├── .cproject
├── .gitattributes
├── .gitignore
├── .project
├── .settings
├── language.settings.xml
├── org.eclipse.cdt.core.prefs
└── org.eclipse.cdt.managedbuilder.core.prefs
├── CMakeLists.txt
├── ECUINFO.TXT
├── LICENSE
├── Open-SAE-J1939.sln
├── README.md
└── Src
├── Documentation
├── Map DM14 - DM15 - DM16.odg
├── Map SAE J1939.odg
├── Open SAE J1939.odt
├── Open SAE J1939.pdf
└── Pictures
│ ├── Project structure.png
│ └── SAE J1939 Resources
│ ├── 3J Series VDC Module.pdf
│ ├── 80525_KHC_J1939_ManUtente_10-2018_ENG.pdf
│ ├── BWM_0000842_99.pdf
│ ├── CAN Table.PDF
│ ├── CAN protocol (J1939 ISOBUS) for Sense42.pdf
│ ├── PB_ETS4000J1939_E_2021-01-14_670052.pdf
│ ├── PVED-CC_Series5_ISObus_Technical_Information_2017.pdf
│ ├── TCI SENSE 42 Version 3.0-25-108.pdf
│ ├── WP29-140-06e.pdf
│ ├── avr-d550-canbus-interface-installation-and-maintenance-en-iss202205-f-5806.pdf
│ ├── iVec.Protocol.pdf
│ ├── mv5ar.pdf
│ └── sw01358_56V_X6T IDD.pdf
├── ECUINFO.TXT
├── Examples
├── Hardware
│ ├── CAN_STM32.txt
│ ├── QT_USB.txt
│ └── SD_Card.txt
├── ISO 11783
│ ├── Auxiliary Valve Command.txt
│ ├── Auxiliary Valve Estimated Flow.txt
│ ├── Auxiliary Valve Measured Position.txt
│ ├── General Purpose Valve Command.txt
│ └── General Purpose Valve Estimated Flow.txt
├── Open SAE J1939
│ ├── CAN Traffic.txt
│ ├── Internal callback.txt
│ └── Main.txt
└── SAE J1939
│ ├── Acknowledgement.txt
│ ├── Address Claimed.txt
│ ├── Address Not Claimed.txt
│ ├── Commanded Address.txt
│ ├── Component Identification.txt
│ ├── DM1.txt
│ ├── DM14.txt
│ ├── DM16.txt
│ ├── DM2.txt
│ ├── DM3.txt
│ ├── ECU Identification.txt
│ ├── Proprietary A.txt
│ ├── Proprietary B.txt
│ └── Software Identification.txt
├── Hardware
├── CAN_Transmit_Receive.c
├── FLASH_EEPROM_RAM_Memory.c
├── Hardware.h
└── Save_Load_Struct.c
├── ISO_11783
├── ISO_11783-7_Application_Layer
│ ├── Application_Layer.h
│ ├── Auxiliary_Valve_Command.c
│ ├── Auxiliary_Valve_Estimated_Flow.c
│ ├── Auxiliary_Valve_Measured_Position.c
│ ├── General_Purpose_Valve_Command.c
│ └── General_Purpose_Valve_Estimated_Flow.c
└── ISO_11783_Enums
│ └── Enum_Valves.h
├── Main.c
├── Open-SAE-J1939.vcxproj
├── Open_SAE_J1939
├── C89_Library.h
├── Closedown_ECU.c
├── Listen_For_Messages.c
├── Open_SAE_J1939.h
├── Startup_ECU.c
└── Structs.h
├── SAE_J1939
├── SAE_J1939-21_Transport_Layer
│ ├── Acknowledgement.c
│ ├── Request.c
│ ├── Transport_Layer.h
│ ├── Transport_Protocol_Connection_Management.c
│ └── Transport_Protocol_Data_Transfer.c
├── SAE_J1939-71_Application_Layer
│ ├── Application_Layer.h
│ ├── Request_Component_Identification.c
│ ├── Request_ECU_Identification.c
│ ├── Request_Proprietary.c
│ ├── Request_Proprietary_B.c
│ └── Request_Software_Identification.c
├── SAE_J1939-73_Diagnostics_Layer
│ ├── DM1.c
│ ├── DM14.c
│ ├── DM15.c
│ ├── DM16.c
│ ├── DM2.c
│ ├── DM3.c
│ └── Diagnostics_Layer.h
├── SAE_J1939-81_Network_Management_Layer
│ ├── Address_Claimed.c
│ ├── Address_Delete.c
│ ├── Address_Not_Claimed.c
│ ├── Commanded_Address.c
│ └── Network_Management_Layer.h
└── SAE_J1939_Enums
│ ├── Enum_Control_Byte.h
│ ├── Enum_DM14_DM15.h
│ ├── Enum_DM1_DM2.h
│ ├── Enum_Group_Function_Value.h
│ ├── Enum_NAME.h
│ ├── Enum_PGN.h
│ └── Enum_Send_Status.h
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.c linguist-language=C
2 | *.h linguist-language=C
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | setup/deploy/
141 | setup/PK-Sim*
142 | setup/*.zip
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | *.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.pfx
196 | *.publishsettings
197 | node_modules/
198 | orleans.codegen.cs
199 |
200 | # Since there are multiple workflows, uncomment next line to ignore bower_components
201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
202 | #bower_components/
203 |
204 | # RIA/Silverlight projects
205 | Generated_Code/
206 |
207 | # Backup & report files from converting an old project file
208 | # to a newer Visual Studio version. Backup files are not needed,
209 | # because we have git ;-)
210 | _UpgradeReport_Files/
211 | Backup*/
212 | UpgradeLog*.XML
213 | UpgradeLog*.htm
214 |
215 | # SQL Server files
216 | *.mdf
217 | *.ldf
218 |
219 | # Business Intelligence projects
220 | *.rdl.data
221 | *.bim.layout
222 | *.bim_*.settings
223 |
224 | # Microsoft Fakes
225 | FakesAssemblies/
226 |
227 | # GhostDoc plugin setting file
228 | *.GhostDoc.xml
229 |
230 | # Node.js Tools for Visual Studio
231 | .ntvs_analysis.dat
232 |
233 | # Visual Studio 6 build log
234 | *.plg
235 |
236 | # Visual Studio 6 workspace options file
237 | *.opt
238 |
239 | # Visual Studio LightSwitch build output
240 | **/*.HTMLClient/GeneratedArtifacts
241 | **/*.DesktopClient/GeneratedArtifacts
242 | **/*.DesktopClient/ModelManifest.xml
243 | **/*.Server/GeneratedArtifacts
244 | **/*.Server/ModelManifest.xml
245 | _Pvt_Extensions
246 |
247 | # Paket dependency manager
248 | .paket/paket.exe
249 | paket-files/
250 |
251 | # FAKE - F# Make
252 | .fake/
253 |
254 | # CMake
255 | CMake
256 | CMakeFiles
257 | .vscode
258 | CMakeCache.txt
259 | cmake_install.cmake
260 | Makefile
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Open-SAE-J1939
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
10 | clean,full,incremental,
11 |
12 |
13 |
14 |
15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
16 | full,incremental,
17 |
18 |
19 |
20 |
21 |
22 | org.eclipse.cdt.core.cnature
23 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
24 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.settings/language.settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.cdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | environment/project/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/append=true
3 | environment/project/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/appendContributed=true
4 | environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1306552510/MINGW_HOME/delimiter=;
5 | environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1306552510/MINGW_HOME/operation=replace
6 | environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1306552510/MINGW_HOME/value=C\:\\minGW\\mingw64
7 | environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1306552510/append=true
8 | environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1306552510/appendContributed=true
9 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.cdt.managedbuilder.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/CPATH/delimiter=;
3 | environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/CPATH/operation=remove
4 | environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/C_INCLUDE_PATH/delimiter=;
5 | environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/C_INCLUDE_PATH/operation=remove
6 | environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/append=true
7 | environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/appendContributed=true
8 | environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/LIBRARY_PATH/delimiter=;
9 | environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/LIBRARY_PATH/operation=remove
10 | environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/append=true
11 | environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.280892246/appendContributed=true
12 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16.0)
2 |
3 | project(Open-SAE-J1939 C)
4 |
5 | FILE(GLOB_RECURSE SOURCE_FILES_LIST "Src/*.c" "Src/*.c")
6 |
7 | add_executable(main ${SOURCE_FILES_LIST})
--------------------------------------------------------------------------------
/ECUINFO.TXT:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/ECUINFO.TXT
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Daniel Mårtensson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Open-SAE-J1939.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32929.385
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Open-SAE-J1939", "src\Open-SAE-J1939.vcxproj", "{64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Debug|x64.ActiveCfg = Debug|x64
17 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Debug|x64.Build.0 = Debug|x64
18 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Debug|x86.ActiveCfg = Debug|Win32
19 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Debug|x86.Build.0 = Debug|Win32
20 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Release|x64.ActiveCfg = Release|x64
21 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Release|x64.Build.0 = Release|x64
22 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Release|x86.ActiveCfg = Release|Win32
23 | {64CDD89D-0D0D-451E-8554-3D68F4EBBFD3}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {AE023F7B-A4A7-49BE-8C07-B0C4E4CF29CB}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/Src/Documentation/Map DM14 - DM15 - DM16.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Map DM14 - DM15 - DM16.odg
--------------------------------------------------------------------------------
/Src/Documentation/Map SAE J1939.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Map SAE J1939.odg
--------------------------------------------------------------------------------
/Src/Documentation/Open SAE J1939.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Open SAE J1939.odt
--------------------------------------------------------------------------------
/Src/Documentation/Open SAE J1939.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Open SAE J1939.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/Project structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/Project structure.png
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/3J Series VDC Module.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/3J Series VDC Module.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/80525_KHC_J1939_ManUtente_10-2018_ENG.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/80525_KHC_J1939_ManUtente_10-2018_ENG.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/BWM_0000842_99.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/BWM_0000842_99.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/CAN Table.PDF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/CAN Table.PDF
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/CAN protocol (J1939 ISOBUS) for Sense42.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/CAN protocol (J1939 ISOBUS) for Sense42.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/PB_ETS4000J1939_E_2021-01-14_670052.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/PB_ETS4000J1939_E_2021-01-14_670052.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/PVED-CC_Series5_ISObus_Technical_Information_2017.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/PVED-CC_Series5_ISObus_Technical_Information_2017.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/TCI SENSE 42 Version 3.0-25-108.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/TCI SENSE 42 Version 3.0-25-108.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/WP29-140-06e.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/WP29-140-06e.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/avr-d550-canbus-interface-installation-and-maintenance-en-iss202205-f-5806.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/avr-d550-canbus-interface-installation-and-maintenance-en-iss202205-f-5806.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/iVec.Protocol.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/iVec.Protocol.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/mv5ar.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/mv5ar.pdf
--------------------------------------------------------------------------------
/Src/Documentation/Pictures/SAE J1939 Resources/sw01358_56V_X6T IDD.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Documentation/Pictures/SAE J1939 Resources/sw01358_56V_X6T IDD.pdf
--------------------------------------------------------------------------------
/Src/ECUINFO.TXT:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/ECUINFO.TXT
--------------------------------------------------------------------------------
/Src/Examples/Hardware/CAN_STM32.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * CAN.c
3 | *
4 | * Created on: Jun 14, 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Functions.h"
9 |
10 | static CAN_HandleTypeDef *can_handler;
11 | static J1939 *j1939_handler;
12 | static void Create_CAN_Filter(CAN_HandleTypeDef *hcan);
13 | static void Create_CAN_Interrupt(CAN_HandleTypeDef *hcan);
14 |
15 | void STM32_PLC_Start_CAN(CAN_HandleTypeDef *hcan, J1939 *j1939) {
16 | can_handler = hcan;
17 | j1939_handler = j1939;
18 | Create_CAN_Filter(hcan);
19 | if (HAL_CAN_Start(hcan) != HAL_OK)
20 | Error_Handler();
21 | Create_CAN_Interrupt(hcan);
22 | }
23 |
24 | HAL_StatusTypeDef STM32_PLC_CAN_Transmit(uint8_t TxData[], CAN_TxHeaderTypeDef *TxHeader) {
25 | uint32_t TxMailbox;
26 | return HAL_CAN_AddTxMessage(can_handler, TxHeader, TxData, &TxMailbox);
27 | }
28 |
29 | /* Returns true if the message data is new */
30 | void STM32_PLC_CAN_Get_ID_Data(uint32_t* ID, uint8_t data[], bool* is_new_message) {
31 | CAN_RxHeaderTypeDef RxHeader = {0};
32 | uint8_t RxData[8] = {0};
33 | HAL_StatusTypeDef status = HAL_CAN_GetRxMessage(can_handler, CAN_RX_FIFO0, &RxHeader, RxData);
34 | if (status != HAL_OK)
35 | Error_Handler();
36 |
37 | /* Check the length of the data */
38 | if(RxHeader.DLC == 0){
39 | *is_new_message = false;
40 | return;
41 | }
42 |
43 | /* Read ID */
44 | if(RxHeader.IDE == CAN_ID_STD)
45 | *ID = RxHeader.StdId;
46 | else
47 | *ID = RxHeader.ExtId;
48 |
49 | /* Read data */
50 | memcpy(data, RxData, 8);
51 |
52 | /* Leave the function by saying that the message is new */
53 | *is_new_message = true;
54 | }
55 |
56 | /* Interrupt handler that read message */
57 | void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
58 | Open_SAE_J1939_Listen_For_Messages(j1939_handler);
59 | }
60 |
61 |
62 | static void Create_CAN_Interrupt(CAN_HandleTypeDef *hcan) {
63 | /* Don't forget to check NVIC in CAN -> NVIC Settings -> CAN RX0 interrupt */
64 | if (HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
65 | Error_Handler();
66 | }
67 |
68 |
69 | static void Create_CAN_Filter(CAN_HandleTypeDef *hcan) {
70 | CAN_FilterTypeDef sFilterConfig;
71 | sFilterConfig.FilterBank = 0;
72 | sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
73 | sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
74 | sFilterConfig.FilterIdHigh = 0x0000;
75 | sFilterConfig.FilterIdLow = 0x0000;
76 | sFilterConfig.FilterMaskIdHigh = 0x0000;
77 | sFilterConfig.FilterMaskIdLow = 0x0000;
78 | sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
79 | sFilterConfig.FilterActivation = ENABLE;
80 | sFilterConfig.SlaveStartFilterBank = 14;
81 |
82 | if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
83 | Error_Handler();
84 | }
85 |
--------------------------------------------------------------------------------
/Src/Examples/Hardware/QT_USB.txt:
--------------------------------------------------------------------------------
1 | #include "can_to_usb.h"
2 |
3 | /* Private include */
4 | #include "../../../../USB/usb_message_defines.h"
5 |
6 | static QSerialPort* this_serial_port;
7 |
8 | void QT_USB_set_serial_handler(QSerialPort* serial_port){
9 | this_serial_port = serial_port;
10 | }
11 |
12 | ENUM_J1939_STATUS_CODES QT_USB_Transmit(uint32_t ID, uint8_t data[], uint8_t DLC){
13 | uint8_t send_data_array[14] = {0}; /* We cannot send more than 14 bytes */
14 | send_data_array[0] = J1939_MESSAGE_TYPE;
15 | send_data_array[1] = ID >> 24; /* Most significant bit */
16 | send_data_array[2] = ID >> 16;
17 | send_data_array[3] = ID >> 8;
18 | send_data_array[4] = ID; /* Least significant bit */
19 | send_data_array[5] = DLC; /* Data length */
20 | for(uint8_t i = 0; i < DLC; i++)
21 | send_data_array[6+i] = data[i];
22 | this_serial_port->write((char*)send_data_array, 6+DLC);
23 | return STATUS_SEND_OK;
24 | }
25 |
26 | void QT_USB_Get_ID_Data(uint32_t *ID, uint8_t data[], bool* is_new_message){
27 | uint8_t receive_buf[13] = {0}; /* From STM32 PLC, we have send 14 bytes, but byte 0 is the message type, which we have already read */
28 | this_serial_port->read((char*)receive_buf, 13);
29 | *ID = (receive_buf[0] << 24) | (receive_buf[1] << 16) | (receive_buf[2] << 8) | receive_buf[3];
30 | uint8_t DLC = receive_buf[4];
31 | if(DLC == 0){
32 | *is_new_message = false;
33 | }else{
34 | for(uint8_t i = 0; i < 8; i++)
35 | if(i < DLC)
36 | data[i] = receive_buf[5+i];
37 | else
38 | data[i] = 0;
39 | *is_new_message = true;
40 | }
41 | }
42 |
43 |
44 |
45 | ////////////////////////////////////////////////////////////////////////////////////////////
46 |
47 | #ifndef CAN_BUS_H
48 | #define CAN_BUS_H
49 |
50 | #include "../../../../J1939/SAE_J1939/SAE_J1939_Enums/Enum_Send_Status.h"
51 | #include
52 | #include
53 |
54 | #ifdef __cplusplus
55 | #include
56 | void QT_USB_set_serial_handler(QSerialPort* serial_port);
57 | extern "C" {
58 | #endif
59 |
60 | ENUM_J1939_STATUS_CODES QT_USB_Transmit(uint32_t ID, uint8_t data[], uint8_t DLC);
61 | void QT_USB_Get_ID_Data(uint32_t *ID, uint8_t data[], bool* is_new_message);
62 |
63 | #ifdef __cplusplus
64 | }
65 |
66 | #endif
67 |
68 | #endif // CAN_BUS_H
69 |
70 |
71 |
72 | ///////////////////////////////////////////////////////////////////////////////////////////
73 |
74 | #ifndef USB_MESSAGE_DEFINES_H
75 | #define USB_MESSAGE_DEFINES_H
76 |
77 | /* Message length from STM32 PLC */
78 | #define J1939_MESSAGE_FROM_STM32_PLC 14
79 | #define MEASUREMENT_MESSAGE_FROM_STM32_PLC 51
80 |
81 | /* Message types for STM32 PLC */
82 | #define J1939_MESSAGE_TYPE 0
83 | #define CAN_BUS_MESSAGE_TYPE 1
84 | #define PWM_MESSAGE_TYPE 2
85 | #define ANALOG_OUTPUT_MESSAGE_TYPE 3
86 | #define SEND_BACK_MEASUREMENT_MESSAGE_TYPE 4
87 |
88 | #endif // USB_MESSAGE_DEFINES_H
89 |
--------------------------------------------------------------------------------
/Src/Examples/Hardware/SD_Card.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * SD_Card.c
3 | *
4 | * Created on: Jun 15, 2021
5 | * Author: Daniel Mårtensson
6 | */
7 | #include "Functions.h"
8 | #include "user_diskio_spi.h"
9 | #include "fatfs.h"
10 |
11 | /* These are extern inside fatfs.h */
12 | FATFS USERFatFS;
13 | FIL USERFile;
14 |
15 | void STM32_PLC_SD(SPI_HandleTypeDef *hspi, GPIO_TypeDef *SD_CS_PORT, uint16_t SD_CS_PIN) {
16 | SD_init(hspi, SD_CS_PORT, SD_CS_PIN);
17 | }
18 |
19 | FRESULT STM32_PLC_SD_Mont_Card() {
20 | FRESULT status;
21 | uint8_t attempt = 0;
22 | while(attempt < 255) {
23 | MX_FATFS_Init();
24 | status = f_mount(&USERFatFS, "", 1);
25 | if(status == FR_OK){
26 | break;
27 | } else {
28 | STM32_PLC_SD_Unmount_Card();
29 | attempt++;
30 | }
31 | }
32 | return status;
33 | }
34 |
35 | FRESULT STM32_PLC_SD_Unmount_Card() {
36 | FRESULT status = f_mount(NULL, "", 0);
37 | MX_FATFS_DeInit();
38 | return status;
39 | }
40 |
41 | FRESULT STM32_PLC_SD_Open_File_With_Read(char filename[]) {
42 | return f_open(&USERFile, filename, FA_OPEN_ALWAYS | FA_READ); /* Posix "r" */
43 | }
44 |
45 | FRESULT STM32_PLC_SD_Create_File_With_Write(char filename[]) {
46 | return f_open(&USERFile, filename, FA_CREATE_ALWAYS | FA_WRITE); /* Posix "w" */
47 | }
48 |
49 | FRESULT STM32_PLC_SD_Close_File() {
50 | return f_close(&USERFile);
51 | }
52 |
53 | FRESULT STM32_PLC_SD_Check_Space(uint32_t *total_space, uint32_t *free_space) {
54 | FATFS *pfs;
55 | DWORD fre_clust;
56 | FRESULT status = f_getfree("", &fre_clust, &pfs);
57 | *total_space = (uint32_t) ((pfs->n_fatent - 2) * pfs->csize * 0.5);
58 | *free_space = (uint32_t) (fre_clust * pfs->csize * 0.5);
59 | return status;
60 | }
61 |
62 | /* Return text "error" or "eof" if it's end of file (eof) */
63 | char* STM32_PLC_SD_Read_File(char text[], int len) {
64 | return f_gets(text, len, &USERFile);
65 | }
66 |
67 | /* Return -1 with End of File (EOF) */
68 | int STM32_PLC_SD_Write_File(char text[]) {
69 | return f_puts(text, &USERFile);
70 | }
71 |
72 | /* Write data instead of text */
73 | FRESULT STM32_PLC_SD_Write_Data(uint8_t buff[], uint32_t btw){
74 | unsigned int bw;
75 | return f_write(&USERFile, buff, btw, &bw);
76 | }
77 |
78 | /* Read data instead of text */
79 | FRESULT STM32_PLC_SD_Read_Data(uint8_t buff[], uint32_t btr){
80 | unsigned int br;
81 | return f_read(&USERFile, buff, btr, &br);
82 | }
83 |
--------------------------------------------------------------------------------
/Src/Examples/ISO 11783/Auxiliary Valve Command.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | /* Include ISO 11783 */
14 | #include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
15 |
16 | int main() {
17 |
18 | /* Create our J1939 structure with two ECU */
19 | J1939 j1939_1 = {0};
20 | J1939 j1939_2 = {0};
21 |
22 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
23 | uint8_t i;
24 | for(i = 0; i < 255; i++){
25 | j1939_1.other_ECU_address[i] = 0xFF;
26 | j1939_2.other_ECU_address[i] = 0xFF;
27 | }
28 |
29 | /* Set the ECU address */
30 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
31 | j1939_2.information_this_ECU.this_ECU_address = 0xFD;
32 |
33 | /* Broadcast a command from ECU 1 */
34 | uint8_t valve_number = 1;
35 | ISO_11783_Send_Auxiliary_Valve_Command(&j1939_1, valve_number, 100, FAIL_SAFE_MODE_ACTIVATED, VALVE_STATE_INITIALISATION);
36 |
37 | /* Read the command for ECU 2 */
38 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
39 |
40 | /* Display what we got */
41 | printf("Standard flow = %i\nValve state = %i\nFail safe mode = %i\nFrom ECU address = 0x%X"
42 | ,j1939_2.from_other_ecu_auxiliary_valve_command[valve_number].standard_flow
43 | ,j1939_2.from_other_ecu_auxiliary_valve_command[valve_number].valve_state
44 | ,j1939_2.from_other_ecu_auxiliary_valve_command[valve_number].fail_safe_mode
45 | ,j1939_2.from_other_ecu_auxiliary_valve_command[valve_number].from_ecu_address);
46 |
47 | return 0;
48 | }
49 |
--------------------------------------------------------------------------------
/Src/Examples/ISO 11783/Auxiliary Valve Estimated Flow.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | /* Include ISO 11783 */
14 | #include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
15 |
16 | int main() {
17 |
18 | /* Create our J1939 structure with two ECU */
19 | J1939 j1939_1 = {0};
20 | J1939 j1939_2 = {0};
21 |
22 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
23 | uint8_t i;
24 | for(i = 0; i < 255; i++){
25 | j1939_1.other_ECU_address[i] = 0xFF;
26 | j1939_2.other_ECU_address[i] = 0xFF;
27 | }
28 |
29 | /* Set the ECU address */
30 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
31 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
32 |
33 | /* Set the information about valve 1 for ECU 2 */
34 | uint8_t valve_number = 1;
35 | j1939_2.this_auxiliary_valve_estimated_flow[valve_number].extend_estimated_flow_standard = 100;
36 | j1939_2.this_auxiliary_valve_estimated_flow[valve_number].fail_safe_mode = FAIL_SAFE_MODE_BLOCKED; /* No fail safe mode */
37 | j1939_2.this_auxiliary_valve_estimated_flow[valve_number].limit = LIMIT_NOT_USED;
38 | j1939_2.this_auxiliary_valve_estimated_flow[valve_number].retract_estimated_flow_standard = 50;
39 | j1939_2.this_auxiliary_valve_estimated_flow[valve_number].valve_state = VALVE_STATE_EXTEND;
40 |
41 | /* Send a request from ECU 1 to ECU 2 */
42 | ISO_11783_Send_Request_Auxiliary_Valve_Estimated_Flow(&j1939_1, 0x90, valve_number);
43 |
44 | /* Read the request for ECU 2*/
45 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
46 |
47 | /* Read the response request for ECU 1 */
48 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
49 |
50 | /* Display what we got */
51 | printf("Extend estimated flow standard = %i\nFail safe mode = %i\nLimit = %i\nRetract estimated flow standard = %i\nValve state = %i\nFrom ECU address = 0x%X"
52 | ,j1939_1.from_other_ecu_auxiliary_valve_estimated_flow[valve_number].extend_estimated_flow_standard
53 | ,j1939_1.from_other_ecu_auxiliary_valve_estimated_flow[valve_number].fail_safe_mode
54 | ,j1939_1.from_other_ecu_auxiliary_valve_estimated_flow[valve_number].limit
55 | ,j1939_1.from_other_ecu_auxiliary_valve_estimated_flow[valve_number].retract_estimated_flow_standard
56 | ,j1939_1.from_other_ecu_auxiliary_valve_estimated_flow[valve_number].valve_state
57 | ,j1939_1.from_other_ecu_auxiliary_valve_estimated_flow[valve_number].from_ecu_address);
58 |
59 | return 0;
60 | }
61 |
--------------------------------------------------------------------------------
/Src/Examples/ISO 11783/Auxiliary Valve Measured Position.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | /* Include ISO 11783 */
14 | #include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
15 |
16 | int main() {
17 |
18 | /* Create our J1939 structure with two ECU */
19 | J1939 j1939_1 = {0};
20 | J1939 j1939_2 = {0};
21 |
22 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
23 | uint8_t i;
24 | for(i = 0; i < 255; i++){
25 | j1939_1.other_ECU_address[i] = 0xFF;
26 | j1939_2.other_ECU_address[i] = 0xFF;
27 | }
28 |
29 | /* Set the ECU address */
30 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
31 | j1939_2.information_this_ECU.this_ECU_address = 0xFD;
32 |
33 | /* Set the information about valve 1 for ECU 2 */
34 | uint8_t valve_number = 1;
35 | j1939_2.this_auxiliary_valve_measured_position[valve_number].measured_position_percent = 100;
36 | j1939_2.this_auxiliary_valve_measured_position[valve_number].measured_position_micrometer = 50000; /* 5 mm */
37 | j1939_2.this_auxiliary_valve_measured_position[valve_number].valve_state = VALVE_STATE_RETRACT; /* Spool in reverse */
38 |
39 | /* Send a request from ECU 1 to ECU 2 */
40 | ISO_11783_Send_Request_Auxiliary_Valve_Measured_Position(&j1939_1, 0xFD, valve_number);
41 |
42 | /* Read the request for ECU 2*/
43 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
44 |
45 | /* Read the response request for ECU 1 */
46 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
47 |
48 | /* Display what we got */
49 | printf("Measured position percent = %i\nMeasured position micrometer = %i\nValve state = %i\nFrom ECU address = 0x%X"
50 | ,j1939_1.from_other_ecu_auxiliary_valve_measured_position[valve_number].measured_position_percent
51 | ,j1939_1.from_other_ecu_auxiliary_valve_measured_position[valve_number].measured_position_micrometer
52 | ,j1939_1.from_other_ecu_auxiliary_valve_measured_position[valve_number].valve_state
53 | ,j1939_1.from_other_ecu_auxiliary_valve_measured_position[valve_number].from_ecu_address);
54 |
55 | return 0;
56 | }
57 |
--------------------------------------------------------------------------------
/Src/Examples/ISO 11783/General Purpose Valve Command.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | /* Include ISO 11783 */
14 | #include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
15 |
16 | int main() {
17 |
18 | /* Create our J1939 structure with two ECU */
19 | J1939 j1939_1 = {0};
20 | J1939 j1939_2 = {0};
21 |
22 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
23 | uint8_t i;
24 | for(i = 0; i < 255; i++){
25 | j1939_1.other_ECU_address[i] = 0xFF;
26 | j1939_2.other_ECU_address[i] = 0xFF;
27 | }
28 |
29 | /* Set the ECU address */
30 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
31 | j1939_2.information_this_ECU.this_ECU_address = 0xFD;
32 |
33 | /* Send a command from ECU 1 to ECU 2 */
34 | ISO_11783_Send_General_Purpose_Valve_Command(&j1939_1, 0xFD, 100, FAIL_SAFE_MODE_ACTIVATED, VALVE_STATE_INITIALISATION, 60000);
35 |
36 | /* Read the command for ECU 2 */
37 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
38 |
39 | /* Display what we got */
40 | printf("Standard flow = %i\nValve state = %i\nFail safe mode = %i\nExtended flow = %i\nFrom ECU address = 0x%X"
41 | ,j1939_2.from_other_ecu_general_purpose_valve_command.standard_flow
42 | ,j1939_2.from_other_ecu_general_purpose_valve_command.valve_state
43 | ,j1939_2.from_other_ecu_general_purpose_valve_command.fail_safe_mode
44 | ,j1939_2.from_other_ecu_general_purpose_valve_command.extended_flow
45 | ,j1939_2.from_other_ecu_general_purpose_valve_command.from_ecu_address);
46 |
47 | return 0;
48 | }
49 |
--------------------------------------------------------------------------------
/Src/Examples/ISO 11783/General Purpose Valve Estimated Flow.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | /* Include ISO 11783 */
14 | #include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
15 |
16 | int main() {
17 |
18 | /* Create our J1939 structure with two ECU */
19 | J1939 j1939_1 = {0};
20 | J1939 j1939_2 = {0};
21 |
22 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
23 | uint8_t i;
24 | for(i = 0; i < 255; i++){
25 | j1939_1.other_ECU_address[i] = 0xFF;
26 | j1939_2.other_ECU_address[i] = 0xFF;
27 | }
28 |
29 | /* Set the ECU address */
30 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
31 | j1939_2.information_this_ECU.this_ECU_address = 0x7A;
32 |
33 | /* Set the information about valve 1 for ECU 2 */
34 | j1939_2.this_general_purpose_valve_estimated_flow.extend_estimated_flow_standard = 150;
35 | j1939_2.this_general_purpose_valve_estimated_flow.fail_safe_mode = FAIL_SAFE_MODE_ACTIVATED; /* Jump to neutral because now the valve is in fail safe mode */
36 | j1939_2.this_general_purpose_valve_estimated_flow.limit = LIMIT_NOT_USED;
37 | j1939_2.this_general_purpose_valve_estimated_flow.retract_estimated_flow_standard = 50;
38 | j1939_2.this_general_purpose_valve_estimated_flow.valve_state = VALVE_STATE_INITIALISATION;
39 | j1939_2.this_general_purpose_valve_estimated_flow.retract_estimated_flow_extended = 1000;
40 | j1939_2.this_general_purpose_valve_estimated_flow.extend_estimated_flow_extended = 65535;
41 |
42 | /* Send a request from ECU 1 to ECU 2 */
43 | ISO_11783_Send_Request_General_Purpose_Valve_Estimated_Flow(&j1939_1, 0x7A);
44 |
45 | /* Read the request for ECU 2*/
46 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
47 |
48 | /* Read the response request for ECU 1 */
49 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
50 |
51 | /* Display what we got */
52 | printf("Extend estimated flow standard = %i\nFail safe mode = %i\nLimit = %i\nRetract estimated flow standard = %i\nValve state = %i\nRetract estimated flow extended = %i\nExtend estimated flow extended = %i\nFrom ECU address = 0x%X"
53 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.extend_estimated_flow_standard
54 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.fail_safe_mode
55 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.limit
56 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.retract_estimated_flow_standard
57 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.valve_state
58 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.retract_estimated_flow_extended
59 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.extend_estimated_flow_extended
60 | ,j1939_1.from_other_ecu_general_purpose_valve_estimated_flow.from_ecu_address);
61 |
62 | return 0;
63 | }
64 |
--------------------------------------------------------------------------------
/Src/Examples/Open SAE J1939/CAN Traffic.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Examples/Open SAE J1939/CAN Traffic.txt
--------------------------------------------------------------------------------
/Src/Examples/Open SAE J1939/Internal callback.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | /* Every time we want to send a CAN message, this function will be called */
14 | void Callback_Function_Send(uint32_t ID, uint8_t DLC, uint8_t data[]) {
15 | printf("Callback_Function_Send called\n");
16 | printf("ID = 0x%X\n", ID);
17 | printf("DLC = %i\n", DLC);
18 | for (uint8_t i = 0; i < DLC; i++) {
19 | printf("data[%i] = 0x%X\n", i, data[i]);
20 | }
21 | printf("\n");
22 | }
23 |
24 | /* Every time we want to read a CAN message, this function will be called */
25 | void Callback_Function_Read(uint32_t* ID, uint8_t data[], bool* is_new_data) {
26 | printf("Callback_Function_Read called\n");
27 | *ID = 0xFF;
28 | for (uint8_t i = 0; i < 8; i++) {
29 | data[i] = 0xFF;
30 | }
31 | *is_new_data = true;
32 | }
33 |
34 | /* Apply your delay here */
35 | void Callback_Function_Delay(uint8_t delay){
36 | /* Place your hardware delay here e.g HAL_Delay(delay); for STM32 */
37 | }
38 |
39 | int main() {
40 |
41 | /* Create our J1939 structure with two ECU */
42 | J1939 j1939_1 = { 0 };
43 |
44 | /* !!!!! DON'T FORGET TO CHANGE THE PROCESSOR_CHOICE to INTERNAL_CALLBACK in Hardware.h !!!!! */
45 |
46 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
47 | uint8_t i;
48 | for (i = 0; i < 255; i++) {
49 | j1939_1.other_ECU_address[i] = 0xFF;
50 | }
51 |
52 | /* Set the ECU address */
53 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
54 |
55 | /* Set the callback functions for the hardware */
56 | CAN_Set_Callback_Functions(Callback_Function_Send, Callback_Function_Read, NULL, Callback_Function_Delay);
57 |
58 | /* Set NAME for ECU 2 by using Commanded Address. Also change the ECU address from 0x90 to 0x91 */
59 | SAE_J1939_Send_Commanded_Address(&j1939_1, 0x90, 0x91, 5000, 500, 30, 5, FUNCTION_AUXILIARY_VALVES_CONTROL, 50, 0, INDUSTRY_GROUP_AGRICULTURAL_AND_FORESTRY, 15);
60 |
61 | /* Send a PGN request */
62 | SAE_J1939_Send_Request(&j1939_1, 0x20, PGN_AUXILIARY_VALVE_COMMAND_0);
63 |
64 | /* Read a SAE J1939 message */
65 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
66 |
67 | return 0;
68 | }
--------------------------------------------------------------------------------
/Src/Examples/Open SAE J1939/Main.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | /* Include ISO 11783 */
14 | #include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
15 |
16 | void Callback_Function_Send(uint32_t ID, uint8_t DLC, uint8_t data[]) {
17 | /* Apply your transmit layer here, e.g:
18 | * uint32_t TxMailbox;
19 | * static CAN_HandleTypeDef can_handler;
20 | * This function transmit ID, DLC and data[] as the CAN-message.
21 | * HardWareLayerCAN_TX(&can_handler, ID, DLC, data, &TxMailbox);
22 | *
23 | * You can use TCP/IP, USB, CAN etc. as hardware layers for SAE J1939
24 | */
25 | }
26 |
27 | void Callback_Function_Read(uint32_t* ID, uint8_t data[], bool* is_new_data) {
28 | /* Apply your receive layer here, e.g:
29 | * CAN_RxHeaderTypeDef rxHeader = {0};
30 | * static CAN_HandleTypeDef can_handler;
31 | * This function read CAN RX and give the data to ID and data[] as the CAN-message.
32 | * if (HardWareLayerCAN_RX(can_handler, &rxHeader, ID, data) == STATUS_OK){
33 | * *is_new_data = true;
34 | * }
35 | *
36 | * You can use TCP/IP, USB, CAN etc. as hardware layers for SAE J1939
37 | */
38 | }
39 |
40 | /* This function reads the CAN traffic */
41 | void Callback_Function_Traffic(uint32_t ID, uint8_t DLC, uint8_t data[], bool is_TX) {
42 | /* Print if it is TX or RX */
43 | printf("%s\t", is_TX ? "TX" : "RX");
44 |
45 | /* Print ID as hex */
46 | printf("%08X\t", ID);
47 |
48 | /* Print the data */
49 | uint8_t i;
50 | for (i = 0U; i < DLC; i++) {
51 | printf("%X\t", data[i]);
52 | }
53 |
54 | /* Print the non-data */
55 | for (i = DLC; i < 8U; i++) {
56 | printf("%X\t", 0U);
57 | }
58 |
59 | /* New line */
60 | printf("\n");
61 | }
62 |
63 | /* Apply your delay here */
64 | void Callback_Function_Delay(uint8_t delay){
65 | /* Place your hardware delay here e.g HAL_Delay(delay); for STM32 */
66 | }
67 |
68 | int main() {
69 |
70 | /* Create our J1939 structure */
71 | J1939 j1939 = { 0 };
72 |
73 | /*
74 | * Callbacks can be used if you want to pass a specific CAN-function into the hardware layer.
75 | * All you need to do is to enable INTERNAL_CALLLBACK inside hardware.h
76 | * If you don't want to have the traffic callback, just set the argument as NULL.
77 | * If you don't want any callback at all, you can write your own hardware layer by selecting a specific processor choice at hardware.h
78 | */
79 | CAN_Set_Callback_Functions(Callback_Function_Send, Callback_Function_Read, Callback_Function_Traffic, Callback_Function_Delay);
80 |
81 | /* Load your ECU information */
82 | Open_SAE_J1939_Startup_ECU(&j1939);
83 |
84 | /* SAE J1939 process */
85 | bool run = true;
86 | while (run) {
87 | /* Read incoming messages */
88 | Open_SAE_J1939_Listen_For_Messages(&j1939);
89 |
90 | /* Your application code here */
91 |
92 | }
93 |
94 | /* Save your ECU information */
95 | Open_SAE_J1939_Closedown_ECU(&j1939);
96 |
97 | return 0;
98 | }
99 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Acknowledgement.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = {0};
17 | J1939 j1939_2 = {0};
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for(i = 0; i < 255; i++){
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Send an acknowledgement from ECU 1 to ECU 2 where we say that the PGN function is busy because of time out */
31 | SAE_J1939_Send_Acknowledgement(&j1939_1, 0x90, CONTROL_BYTE_ACKNOWLEDGEMENT_PGN_BUSY, GROUP_FUNCTION_VALUE_ABORT_TIME_OUT, PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_0);
32 |
33 | /* Read the acknowledgement at ECU 2 */
34 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
35 |
36 | /* Check what acknowledgement we have */
37 | printf("Control byte = %i\nGroup function value = %i\nPGN of requested info = %i\nAddress(Which is the same as the source address of the ECU) = 0x%X\nFrom where came the message = 0x%X"
38 | , j1939_2.from_other_ecu_acknowledgement.control_byte
39 | , j1939_2.from_other_ecu_acknowledgement.group_function_value
40 | , j1939_2.from_other_ecu_acknowledgement.PGN_of_requested_info
41 | , j1939_2.from_other_ecu_acknowledgement.address
42 | , j1939_2.from_other_ecu_acknowledgement.from_ecu_address);
43 |
44 | return 0;
45 | }
46 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Address Claimed.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = {0};
17 | J1939 j1939_2 = {0};
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for(i = 0; i < 255; i++){
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0xA; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Set NAME for ECU 1 */
31 | j1939_1.information_this_ECU.this_name.identity_number = 100; /* From 0 to 2097151 */
32 | j1939_1.information_this_ECU.this_name.manufacturer_code = 300; /* From 0 to 2047 */
33 | j1939_1.information_this_ECU.this_name.function_instance = 10; /* From 0 to 31 */
34 | j1939_1.information_this_ECU.this_name.ECU_instance = 2; /* From 0 to 7 */
35 | j1939_1.information_this_ECU.this_name.function = FUNCTION_VDC_MODULE; /* From 0 to 255 */
36 | j1939_1.information_this_ECU.this_name.vehicle_system = 100; /* From 0 to 127 */
37 | j1939_1.information_this_ECU.this_name.arbitrary_address_capable = 0; /* From 0 to 1 */
38 | j1939_1.information_this_ECU.this_name.industry_group = INDUSTRY_GROUP_CONSTRUCTION; /* From 0 to 7 */
39 | j1939_1.information_this_ECU.this_name.vehicle_system_instance = 10; /* From 0 to 15 */
40 |
41 | /* Set NAME for ECU 2 */
42 | j1939_2.information_this_ECU.this_name.identity_number = 1000; /* From 0 to 2097151 */
43 | j1939_2.information_this_ECU.this_name.manufacturer_code = 400; /* From 0 to 2047 */
44 | j1939_2.information_this_ECU.this_name.function_instance = 20; /* From 0 to 31 */
45 | j1939_2.information_this_ECU.this_name.ECU_instance = 1; /* From 0 to 7 */
46 | j1939_2.information_this_ECU.this_name.function = FUNCTION_AUXILIARY_VALVES_CONTROL; /* From 0 to 255 */
47 | j1939_2.information_this_ECU.this_name.vehicle_system = 50; /* From 0 to 127 */
48 | j1939_2.information_this_ECU.this_name.arbitrary_address_capable = 0; /* From 0 to 1 */
49 | j1939_2.information_this_ECU.this_name.industry_group = INDUSTRY_GROUP_AGRICULTURAL_AND_FORESTRY; /* From 0 to 7 */
50 | j1939_2.information_this_ECU.this_name.vehicle_system_instance = 15; /* From 0 to 15 */
51 |
52 | /* Broadcast request NAME from ECU 1 to all ECU */
53 | SAE_J1939_Send_Request_Address_Claimed(&j1939_1, 0xFF); /* 0xFF means broadcast to all ECU */
54 |
55 | /* Listen for NAME request for ECU 2 from ECU 1 */
56 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
57 |
58 | /* Listen for NAME response request from ECU 2 to ECU 1 */
59 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
60 |
61 | /* Send request NAME from ECU 2 to ECU 1 */
62 | SAE_J1939_Send_Request_Address_Claimed(&j1939_2, 0xA);
63 |
64 | /* Listen for NAME request for ECU 1 from ECU 2 */
65 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
66 |
67 | /* Listen for NAME response request from ECU 1 to ECU 2 */
68 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
69 |
70 | /* Print information */
71 | printf("How many external ECU are connected according to ECU 1: %i and the NAME came from address = 0x%X\n", j1939_1.number_of_other_ECU, j1939_1.from_other_ecu_name.from_ecu_address);
72 | printf("How many external ECU are connected according to ECU 2: %i and the NAME came from address = 0x%X\n", j1939_2.number_of_other_ECU, j1939_2.from_other_ecu_name.from_ecu_address);
73 |
74 | return 0;
75 | }
76 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Address Not Claimed.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = {0};
17 | J1939 j1939_2 = {0};
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for(i = 0; i < 255; i++){
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address - Notice that they are the same address! */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x80;
29 |
30 | /* Set NAME for ECU 1 */
31 | j1939_1.information_this_ECU.this_name.identity_number = 100; /* From 0 to 2097151 */
32 | j1939_1.information_this_ECU.this_name.manufacturer_code = 300; /* From 0 to 2047 */
33 | j1939_1.information_this_ECU.this_name.function_instance = 10; /* From 0 to 31 */
34 | j1939_1.information_this_ECU.this_name.ECU_instance = 2; /* From 0 to 7 */
35 | j1939_1.information_this_ECU.this_name.function = FUNCTION_VDC_MODULE; /* From 0 to 255 */
36 | j1939_1.information_this_ECU.this_name.vehicle_system = 100; /* From 0 to 127 */
37 | j1939_1.information_this_ECU.this_name.arbitrary_address_capable = 0; /* From 0 to 1 */
38 | j1939_1.information_this_ECU.this_name.industry_group = INDUSTRY_GROUP_CONSTRUCTION; /* From 0 to 7 */
39 | j1939_1.information_this_ECU.this_name.vehicle_system_instance = 10; /* From 0 to 15 */
40 |
41 | /* Set NAME for ECU 2 */
42 | j1939_2.information_this_ECU.this_name.identity_number = 1000; /* From 0 to 2097151 */
43 | j1939_2.information_this_ECU.this_name.manufacturer_code = 400; /* From 0 to 2047 */
44 | j1939_2.information_this_ECU.this_name.function_instance = 20; /* From 0 to 31 */
45 | j1939_2.information_this_ECU.this_name.ECU_instance = 1; /* From 0 to 7 */
46 | j1939_2.information_this_ECU.this_name.function = FUNCTION_AUXILIARY_VALVES_CONTROL; /* From 0 to 255 */
47 | j1939_2.information_this_ECU.this_name.vehicle_system = 50; /* From 0 to 127 */
48 | j1939_2.information_this_ECU.this_name.arbitrary_address_capable = 0; /* From 0 to 1 */
49 | j1939_2.information_this_ECU.this_name.industry_group = INDUSTRY_GROUP_AGRICULTURAL_AND_FORESTRY; /* From 0 to 7 */
50 | j1939_2.information_this_ECU.this_name.vehicle_system_instance = 15; /* From 0 to 15 */
51 |
52 | /* Broadcast NAME from ECU 1 to all ECU */
53 | SAE_J1939_Response_Request_Address_Claimed(&j1939_1);
54 |
55 | /* Listen for NAME request for ECU 2 from ECU 1 - What going to happen: ECU 2 is going to send Address Not Claimed to all ECU because it's conflicts with the ECU 1 address */
56 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
57 |
58 | /* To see that Address Not Claimed, ECU 1 need to read that message */
59 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
60 |
61 | /* Print information */
62 | printf("How many external ECU are connected according to ECU 1? %i\n", j1939_1.number_of_other_ECU);
63 | printf("How many external ECU are connected according to ECU 2? %i\n", j1939_2.number_of_other_ECU);
64 |
65 | /* Print information about who cannot claim their own address */
66 | printf("How many ECU cannot claim their address according to ECU 1? %i\n", j1939_1.number_of_cannot_claim_address);
67 | printf("How many ECU cannot claim their address according to ECU 2? %i\n", j1939_2.number_of_cannot_claim_address);
68 |
69 | return 0;
70 | }
71 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Commanded Address.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Set NAME for ECU 1 */
31 | j1939_1.information_this_ECU.this_name.identity_number = 100; /* From 0 to 2097151 */
32 | j1939_1.information_this_ECU.this_name.manufacturer_code = 300; /* From 0 to 2047 */
33 | j1939_1.information_this_ECU.this_name.function_instance = 10; /* From 0 to 31 */
34 | j1939_1.information_this_ECU.this_name.ECU_instance = 2; /* From 0 to 7 */
35 | j1939_1.information_this_ECU.this_name.function = FUNCTION_VDC_MODULE; /* From 0 to 255 */
36 | j1939_1.information_this_ECU.this_name.vehicle_system = 100; /* From 0 to 127 */
37 | j1939_1.information_this_ECU.this_name.arbitrary_address_capable = 0; /* From 0 to 1 */
38 | j1939_1.information_this_ECU.this_name.industry_group = INDUSTRY_GROUP_CONSTRUCTION; /* From 0 to 7 */
39 | j1939_1.information_this_ECU.this_name.vehicle_system_instance = 10; /* From 0 to 15 */
40 |
41 | /* Set NAME for ECU 2 */
42 | j1939_2.information_this_ECU.this_name.identity_number = 1000; /* From 0 to 2097151 */
43 | j1939_2.information_this_ECU.this_name.manufacturer_code = 400; /* From 0 to 2047 */
44 | j1939_2.information_this_ECU.this_name.function_instance = 20; /* From 0 to 31 */
45 | j1939_2.information_this_ECU.this_name.ECU_instance = 1; /* From 0 to 7 */
46 | j1939_2.information_this_ECU.this_name.function = FUNCTION_VDC_MODULE; /* From 0 to 255 */
47 | j1939_2.information_this_ECU.this_name.vehicle_system = 50; /* From 0 to 127 */
48 | j1939_2.information_this_ECU.this_name.arbitrary_address_capable = 0; /* From 0 to 1 */
49 | j1939_2.information_this_ECU.this_name.industry_group = INDUSTRY_GROUP_GLOBAL; /* From 0 to 7 */
50 | j1939_2.information_this_ECU.this_name.vehicle_system_instance = 10; /* From 0 to 15 */
51 |
52 | /* First let ECU 1 and ECU 2 know each other - This should be done at the startup of every ECU */
53 | SAE_J1939_Response_Request_Address_Claimed(&j1939_1);
54 | SAE_J1939_Response_Request_Address_Claimed(&j1939_2);
55 |
56 | /* Let ECU 2 read and then ECU 1 */
57 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
58 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
59 |
60 | /* Print information */
61 | printf("How many external ECU are connected according to ECU 1: %i and the NAME came from address = 0x%x\n", j1939_1.number_of_other_ECU, j1939_1.from_other_ecu_name.from_ecu_address);
62 | printf("How many external ECU are connected according to ECU 2: %i and the NAME came from address = 0x%x\n", j1939_2.number_of_other_ECU, j1939_2.from_other_ecu_name.from_ecu_address);
63 |
64 | /* Set NAME for ECU 2 by using Commanded Address. Also change the ECU address from 0x90 to 0x91 */
65 | uint8_t DA = 0x90; /* Change this to broadcast address 0xFF */
66 | SAE_J1939_Send_Commanded_Address(&j1939_1, DA, 0x91, 5000, 500, 30, 5, FUNCTION_AUXILIARY_VALVES_CONTROL, 50, 0, INDUSTRY_GROUP_AGRICULTURAL_AND_FORESTRY, 15);
67 |
68 | /* Listen for messages - The reason why it looks like this is because ECU 1 and ECU 2 shares the same CAN-bus buffer - In CAN bus application, you don't need this mess */
69 | if (DA == 0xFF) {
70 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
71 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
72 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
73 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
74 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
75 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
76 | }
77 | else {
78 | Open_SAE_J1939_Listen_For_Messages(&j1939_2); /* Read TP CM with control byte RTS from ECU 1 to ECU 2 */
79 | Open_SAE_J1939_Listen_For_Messages(&j1939_1); /* Read control byte CTS response from ECU 2 */
80 | Open_SAE_J1939_Listen_For_Messages(&j1939_2); /* Read TP DT package 1 from ECU 1 */
81 | Open_SAE_J1939_Listen_For_Messages(&j1939_1); /* Read TP DT package 2 from ECU 1 */
82 | Open_SAE_J1939_Listen_For_Messages(&j1939_2); /* Read one more package */
83 | Open_SAE_J1939_Listen_For_Messages(&j1939_1); /* Read the send request of delete address from ECU 2 */
84 | Open_SAE_J1939_Listen_For_Messages(&j1939_2); /* Read the new address from ECU 2 */
85 | Open_SAE_J1939_Listen_For_Messages(&j1939_1); /* Read the send request of delete address from ECU 2 */
86 | Open_SAE_J1939_Listen_For_Messages(&j1939_2); /* Read the new address from ECU 2 */
87 | }
88 | /* Print information */
89 | printf("Identity number = %i\nManufacturer code = %i\nFunction instance = %i\nECU instance = %i\nFunction = %i\nVehicle system = %i\nArbitrary address capable = %i\nIndustry group = %i\nVehicle system instance = %i\nNew ECU address = 0x%X\n"
90 | , j1939_2.information_this_ECU.this_name.identity_number
91 | , j1939_2.information_this_ECU.this_name.manufacturer_code
92 | , j1939_2.information_this_ECU.this_name.function_instance
93 | , j1939_2.information_this_ECU.this_name.ECU_instance
94 | , j1939_2.information_this_ECU.this_name.function
95 | , j1939_2.information_this_ECU.this_name.vehicle_system
96 | , j1939_2.information_this_ECU.this_name.arbitrary_address_capable
97 | , j1939_2.information_this_ECU.this_name.industry_group
98 | , j1939_2.information_this_ECU.this_name.vehicle_system_instance
99 | , j1939_2.information_this_ECU.this_ECU_address);
100 |
101 | printf("How many external ECU are connected according to ECU 1: %i and the NAME came from address = 0x%X\n", j1939_1.number_of_other_ECU, j1939_1.from_other_ecu_name.from_ecu_address);
102 | printf("How many external ECU are connected according to ECU 2: %i and the NAME came from address = 0x%X (0xFE is error address)\n", j1939_2.number_of_other_ECU, j1939_2.from_other_ecu_name.from_ecu_address);
103 |
104 | return 0;
105 | }
106 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Component Identification.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* This is important because length_of_each_field is not a SAE J1939 standard. The software need to know how large field it is from the beginning */
31 | j1939_2.from_other_ecu_identifications.component_identification.length_of_each_field = 30;
32 |
33 | /* Set the Component Identification */
34 | j1939_1.information_this_ECU.this_identifications.component_identification.length_of_each_field = 30;
35 | char component_product_date[20] = "2021-07-20";
36 | char component_model_name[20] = "200X-PPT";
37 | char component_serial_number[20] = "1243-13244-1244";
38 | char component_unit_name[20] = "Unit 4K";
39 | for (i = 0; i < 20; i++) {
40 | j1939_1.information_this_ECU.this_identifications.component_identification.component_product_date[i] = (uint8_t)component_product_date[i];
41 | j1939_1.information_this_ECU.this_identifications.component_identification.component_model_name[i] = (uint8_t)component_model_name[i];
42 | j1939_1.information_this_ECU.this_identifications.component_identification.component_serial_number[i] = (uint8_t)component_serial_number[i];
43 | j1939_1.information_this_ECU.this_identifications.component_identification.component_unit_name[i] = (uint8_t)component_unit_name[i];
44 | }
45 |
46 | /* Request Software Identification from ECU 2 to ECU 1 */
47 | SAE_J1939_Send_Request(&j1939_2, 0x80, PGN_COMPONENT_IDENTIFICATION);
48 |
49 | /* Response request from ECU 1 perspective - Don't worry, in real CAN applications you don't need this mess. */
50 | for (i = 0; i < 16; i++) {
51 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
52 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
53 | }
54 |
55 | /* Display what ECU 2 got */
56 | printf("Length of each field = %i\nComponent product date = %s\nComponent model name = %s\nComponent serial number = %s\nComponent unit name = %s\nFrom ECU address = 0x%X"
57 | , j1939_2.from_other_ecu_identifications.component_identification.length_of_each_field
58 | , j1939_2.from_other_ecu_identifications.component_identification.component_product_date
59 | , j1939_2.from_other_ecu_identifications.component_identification.component_model_name
60 | , j1939_2.from_other_ecu_identifications.component_identification.component_serial_number
61 | , j1939_2.from_other_ecu_identifications.component_identification.component_unit_name
62 | , j1939_2.from_other_ecu_identifications.component_identification.from_ecu_address);
63 |
64 | return 0;
65 | }
66 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/DM1.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Set the DM1 error message - You can have multiple error messages, but only send one at the time */
31 | j1939_1.this_dm.dm1.SAE_lamp_status_malfunction_indicator = 1;
32 | j1939_1.this_dm.dm1.SAE_lamp_status_red_stop = 0;
33 | j1939_1.this_dm.dm1.SAE_lamp_status_amber_warning = 1;
34 | j1939_1.this_dm.dm1.SAE_lamp_status_protect_lamp = 0;
35 | j1939_1.this_dm.dm1.SAE_flash_lamp_malfunction_indicator = 0;
36 | j1939_1.this_dm.dm1.SAE_flash_lamp_red_stop = 1;
37 | j1939_1.this_dm.dm1.SAE_flash_lamp_amber_warning = 0;
38 | j1939_1.this_dm.dm1.SAE_flash_lamp_protect_lamp = 1;
39 |
40 | j1939_1.this_dm.dm1.FMI[0] = FMI_CURRENT_ABOVE_NORMAL; /* If FMI_NOT_AVAILABLE, then errors_dm1_active will become 0 */
41 | j1939_1.this_dm.dm1.SPN[0] = SPN_5_VOLTS_DC_SUPPLY;
42 | j1939_1.this_dm.dm1.SPN_conversion_method[0] = 1;
43 | j1939_1.this_dm.dm1.occurrence_count[0] = 1;
44 |
45 | j1939_1.this_dm.dm1.FMI[1] = FMI_VOLTAGE_BELOW_NORMAL; /* If FMI_NOT_AVAILABLE, then errors_dm1_active will become 0 */
46 | j1939_1.this_dm.dm1.SPN[1] = SPN_SENSOR_SUPPLY_VOLTAGE_1;
47 | j1939_1.this_dm.dm1.SPN_conversion_method[1] = 1;
48 | j1939_1.this_dm.dm1.occurrence_count[1] = 2;
49 |
50 | j1939_1.this_dm.dm1.FMI[2] = FMI_ABOVE_NORMAL_MODERATELY_SEVERE; /* If FMI_NOT_AVAILABLE, then errors_dm1_active will become 0 */
51 | j1939_1.this_dm.dm1.SPN[2] = SPN_ENGINE_COOLANT_LEVEL;
52 | j1939_1.this_dm.dm1.SPN_conversion_method[2] = 1;
53 | j1939_1.this_dm.dm1.occurrence_count[2] = 3;
54 |
55 | j1939_1.this_dm.errors_dm1_active = 3; /* If this is above 1, then this is going to be send as multi-packet */
56 |
57 | /* Request DM1 codes from ECU 2 to ECU 1 */
58 | SAE_J1939_Send_Request(&j1939_2, 0x80, PGN_DM1);
59 |
60 | /* Read */
61 | for (i = 0; i < 10; i++) {
62 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
63 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
64 | }
65 |
66 | /* Display what ECU 2 got */
67 | printf("Active DTCs = %i\n", j1939_2.from_other_ecu_dm.errors_dm1_active);
68 | printf("SAE lamp status malfunction indicator = %i\nSAE lamp status red stop = %i\nSAE lamp status amber warning = %i\nSAE lamp status protect lamp = %i\nSAE flash lamp malfunction indicator = %i\nSAE flash lamp_red stop = %i\nSAE flash lamp amber warning = %i\nSAE flash lamp protect lamp = %i\n",
69 | j1939_2.from_other_ecu_dm.dm1.SAE_lamp_status_malfunction_indicator,
70 | j1939_2.from_other_ecu_dm.dm1.SAE_lamp_status_red_stop,
71 | j1939_2.from_other_ecu_dm.dm1.SAE_lamp_status_amber_warning,
72 | j1939_2.from_other_ecu_dm.dm1.SAE_lamp_status_protect_lamp,
73 | j1939_2.from_other_ecu_dm.dm1.SAE_flash_lamp_malfunction_indicator,
74 | j1939_2.from_other_ecu_dm.dm1.SAE_flash_lamp_red_stop,
75 | j1939_2.from_other_ecu_dm.dm1.SAE_flash_lamp_amber_warning,
76 | j1939_2.from_other_ecu_dm.dm1.SAE_flash_lamp_protect_lamp);
77 |
78 | for (i = 0; i < j1939_2.from_other_ecu_dm.errors_dm1_active; i++) {
79 | printf("\nDTC %i\n FMI = %i\n SPN = %i\n SPN conversion method = %i\n Occurrence_count = %i\n From ECU address 0x%X\n",
80 | i, j1939_2.from_other_ecu_dm.dm1.FMI[i],
81 | j1939_2.from_other_ecu_dm.dm1.SPN[i],
82 | j1939_2.from_other_ecu_dm.dm1.SPN_conversion_method[i],
83 | j1939_2.from_other_ecu_dm.dm1.occurrence_count[i],
84 | j1939_2.from_other_ecu_dm.dm1.from_ecu_address[i]);
85 | }
86 | return 0;
87 | }
88 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/DM14.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x1; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x2;
29 |
30 | /* Send data from ECU 2 to ECU 1 */
31 | uint8_t number_of_occurences = 37; /* How many bytes to transfer */
32 | uint8_t pointer_type = 1; /* User defined */
33 | uint8_t command = 0x7; /* User defined */
34 | uint32_t pointer = 0xFFFFFF; /* User defined */
35 | uint8_t pointer_extension = 0xFF; /* User defined */
36 | uint16_t key = 0xFFFF; /* User defined */
37 |
38 | /* Send binary request to ECU 2 */
39 | SAE_J1939_Send_Request_DM14(&j1939_1, 0x2, number_of_occurences, pointer_type, command, pointer, pointer_extension, key);
40 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
41 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
42 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
43 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
44 |
45 | /* This is only here because we using the internal message buffer - In real CAN applications, this mess is not needed */
46 | for (i = 0; i < 15; i++) {
47 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
48 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
49 | }
50 |
51 | /* Pick up the message */
52 | printf("Message length: %i\n", j1939_1.from_other_ecu_dm.dm16.number_of_occurences);
53 | printf("Message text: %s\n", (char*)j1939_1.from_other_ecu_dm.dm16.raw_binary_data);
54 | printf("From ECU address: 0x%X", j1939_1.from_other_ecu_dm.dm16.from_ecu_address);
55 | return 0;
56 | }
57 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/DM16.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x60; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x6A;
29 |
30 | /* Send data from ECU 1 to ECU 2 */
31 | uint8_t raw_binary_data[13];
32 | uint8_t number_of_occurences = 13;
33 | raw_binary_data[0] = 83; /* 'S' */
34 | raw_binary_data[1] = 65; /* 'A' */
35 | raw_binary_data[2] = 69; /* 'E' */
36 | raw_binary_data[3] = 32; /* ' ' */
37 | raw_binary_data[4] = 74; /* 'J' */
38 | raw_binary_data[5] = 49; /* '1' */
39 | raw_binary_data[6] = 57; /* '9' */
40 | raw_binary_data[7] = 51; /* '3' */
41 | raw_binary_data[8] = 57; /* '9' */
42 | raw_binary_data[9] = 33; /* '!' */
43 | raw_binary_data[10] = 33; /* '!' */
44 | raw_binary_data[11] = 33; /* '!' */
45 | raw_binary_data[12] = 0; /* NULL termination (Important for C-string) */
46 |
47 | /* Send binary data to ECU 2 */
48 | uint8_t DA = 0x6A;
49 | SAE_J1939_Send_Binary_Data_Transfer_DM16(&j1939_1, 0x6A, number_of_occurences, raw_binary_data);
50 |
51 | /* This is only here because we using the internal message buffer - In real CAN applications, this mess is not needed */
52 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
53 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
54 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
55 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
56 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
57 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
58 |
59 | /* Pick up the message */
60 | printf("Message length: %i\n", j1939_2.from_other_ecu_dm.dm16.number_of_occurences);
61 | printf("Message text: %s\n", (char*)j1939_2.from_other_ecu_dm.dm16.raw_binary_data);
62 | printf("From ECU address: 0x%X", j1939_2.from_other_ecu_dm.dm16.from_ecu_address);
63 | return 0;
64 | }
65 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/DM2.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Set the dm2 error message - You can have multiple error messages, but only send one at the time */
31 | j1939_1.this_dm.dm2.SAE_lamp_status_malfunction_indicator = 1;
32 | j1939_1.this_dm.dm2.SAE_lamp_status_red_stop = 0;
33 | j1939_1.this_dm.dm2.SAE_lamp_status_amber_warning = 1;
34 | j1939_1.this_dm.dm2.SAE_lamp_status_protect_lamp = 0;
35 | j1939_1.this_dm.dm2.SAE_flash_lamp_malfunction_indicator = 0;
36 | j1939_1.this_dm.dm2.SAE_flash_lamp_red_stop = 1;
37 | j1939_1.this_dm.dm2.SAE_flash_lamp_amber_warning = 0;
38 | j1939_1.this_dm.dm2.SAE_flash_lamp_protect_lamp = 1;
39 |
40 | j1939_1.this_dm.dm2.FMI[0] = FMI_CURRENT_ABOVE_NORMAL; /* If FMI_NOT_AVAILABLE, then errors_dm2_active will become 0 */
41 | j1939_1.this_dm.dm2.SPN[0] = SPN_5_VOLTS_DC_SUPPLY;
42 | j1939_1.this_dm.dm2.SPN_conversion_method[0] = 1;
43 | j1939_1.this_dm.dm2.occurrence_count[0] = 1;
44 |
45 | j1939_1.this_dm.dm2.FMI[1] = FMI_VOLTAGE_BELOW_NORMAL; /* If FMI_NOT_AVAILABLE, then errors_dm2_active will become 0 */
46 | j1939_1.this_dm.dm2.SPN[1] = SPN_SENSOR_SUPPLY_VOLTAGE_1;
47 | j1939_1.this_dm.dm2.SPN_conversion_method[1] = 1;
48 | j1939_1.this_dm.dm2.occurrence_count[1] = 2;
49 |
50 | j1939_1.this_dm.dm2.FMI[2] = FMI_ABOVE_NORMAL_MODERATELY_SEVERE; /* If FMI_NOT_AVAILABLE, then errors_dm2_active will become 0 */
51 | j1939_1.this_dm.dm2.SPN[2] = SPN_ENGINE_COOLANT_LEVEL;
52 | j1939_1.this_dm.dm2.SPN_conversion_method[2] = 1;
53 | j1939_1.this_dm.dm2.occurrence_count[2] = 3;
54 |
55 | j1939_1.this_dm.errors_dm2_active = 3; /* If this is above 1, then this is going to be send as multi-packet */
56 |
57 | /* Request dm2 codes from ECU 2 to ECU 1 */
58 | SAE_J1939_Send_Request(&j1939_2, 0x80, PGN_DM2);
59 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
60 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
61 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
62 |
63 | /* Read */
64 | for (i = 0; i < 15; i++) {
65 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
66 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
67 | }
68 |
69 | /* Display what ECU 2 got */
70 | printf("Active DTCs = %i\n", j1939_2.from_other_ecu_dm.errors_dm2_active);
71 | printf("SAE lamp status malfunction indicator = %i\nSAE lamp status red stop = %i\nSAE lamp status amber warning = %i\nSAE lamp status protect lamp = %i\nSAE flash lamp malfunction indicator = %i\nSAE flash lamp_red stop = %i\nSAE flash lamp amber warning = %i\nSAE flash lamp protect lamp = %i\n",
72 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_malfunction_indicator,
73 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_red_stop,
74 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_amber_warning,
75 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_protect_lamp,
76 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_malfunction_indicator,
77 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_red_stop,
78 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_amber_warning,
79 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_protect_lamp);
80 |
81 | for (i = 0; i < j1939_2.from_other_ecu_dm.errors_dm2_active; i++) {
82 | printf("\nDTC %i\n FMI = %i\n SPN = %i\n SPN conversion method = %i\n Occurrence_count = %i\n From ECU address 0x%X\n",
83 | i, j1939_2.from_other_ecu_dm.dm2.FMI[i],
84 | j1939_2.from_other_ecu_dm.dm2.SPN[i],
85 | j1939_2.from_other_ecu_dm.dm2.SPN_conversion_method[i],
86 | j1939_2.from_other_ecu_dm.dm2.occurrence_count[i],
87 | j1939_2.from_other_ecu_dm.dm2.from_ecu_address[i]);
88 | }
89 | return 0;
90 | }
91 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/DM3.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Set the dm2 error message - You can have multiple error messages, but only send one at the time */
31 | j1939_1.this_dm.dm2.SAE_lamp_status_malfunction_indicator = 1;
32 | j1939_1.this_dm.dm2.SAE_lamp_status_red_stop = 0;
33 | j1939_1.this_dm.dm2.SAE_lamp_status_amber_warning = 1;
34 | j1939_1.this_dm.dm2.SAE_lamp_status_protect_lamp = 0;
35 | j1939_1.this_dm.dm2.SAE_flash_lamp_malfunction_indicator = 0;
36 | j1939_1.this_dm.dm2.SAE_flash_lamp_red_stop = 1;
37 | j1939_1.this_dm.dm2.SAE_flash_lamp_amber_warning = 0;
38 | j1939_1.this_dm.dm2.SAE_flash_lamp_protect_lamp = 1;
39 |
40 | j1939_1.this_dm.dm2.FMI[0] = FMI_CURRENT_ABOVE_NORMAL; /* If FMI_NOT_AVAILABLE, then errors_dm2_active will become 0 */
41 | j1939_1.this_dm.dm2.SPN[0] = SPN_5_VOLTS_DC_SUPPLY;
42 | j1939_1.this_dm.dm2.SPN_conversion_method[0] = 1;
43 | j1939_1.this_dm.dm2.occurrence_count[0] = 1;
44 |
45 | j1939_1.this_dm.dm2.FMI[1] = FMI_VOLTAGE_BELOW_NORMAL; /* If FMI_NOT_AVAILABLE, then errors_dm2_active will become 0 */
46 | j1939_1.this_dm.dm2.SPN[1] = SPN_SENSOR_SUPPLY_VOLTAGE_1;
47 | j1939_1.this_dm.dm2.SPN_conversion_method[1] = 1;
48 | j1939_1.this_dm.dm2.occurrence_count[1] = 2;
49 |
50 | j1939_1.this_dm.dm2.FMI[2] = FMI_ABOVE_NORMAL_MODERATELY_SEVERE; /* If FMI_NOT_AVAILABLE, then errors_dm2_active will become 0 */
51 | j1939_1.this_dm.dm2.SPN[2] = SPN_ENGINE_COOLANT_LEVEL;
52 | j1939_1.this_dm.dm2.SPN_conversion_method[2] = 1;
53 | j1939_1.this_dm.dm2.occurrence_count[2] = 3;
54 |
55 | j1939_1.this_dm.errors_dm2_active = 3; /* If this is above 1, then this is going to be send as multi-packet */
56 |
57 | /* Request DM3 delete DM2 from ECU 2 to ECU 1 */
58 | SAE_J1939_Send_Request(&j1939_2, 0x80, PGN_DM3);
59 |
60 | /* Response request from ECU 1 perspective - Don't worry, in real CAN applications you don't need this mess. */
61 | for (i = 0; i < 10; i++) {
62 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
63 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
64 | }
65 |
66 | /* Display what ECU 2 got */
67 | printf("Active DTCs = %i\n", j1939_2.from_other_ecu_dm.errors_dm2_active);
68 | printf("SAE lamp status malfunction indicator = %i\nSAE lamp status red stop = %i\nSAE lamp status amber warning = %i\nSAE lamp status protect lamp = %i\nSAE flash lamp malfunction indicator = %i\nSAE flash lamp_red stop = %i\nSAE flash lamp amber warning = %i\nSAE flash lamp protect lamp = %i\n",
69 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_malfunction_indicator,
70 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_red_stop,
71 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_amber_warning,
72 | j1939_2.from_other_ecu_dm.dm2.SAE_lamp_status_protect_lamp,
73 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_malfunction_indicator,
74 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_red_stop,
75 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_amber_warning,
76 | j1939_2.from_other_ecu_dm.dm2.SAE_flash_lamp_protect_lamp);
77 |
78 | for (i = 0; i < j1939_2.from_other_ecu_dm.errors_dm2_active; i++) {
79 | printf("\nDTC %i\n FMI = %i\n SPN = %i\n SPN conversion method = %i\n Occurrence_count = %i\n From ECU address 0x%X\n",
80 | i, j1939_2.from_other_ecu_dm.dm2.FMI[i],
81 | j1939_2.from_other_ecu_dm.dm2.SPN[i],
82 | j1939_2.from_other_ecu_dm.dm2.SPN_conversion_method[i],
83 | j1939_2.from_other_ecu_dm.dm2.occurrence_count[i],
84 | j1939_2.from_other_ecu_dm.dm2.from_ecu_address[i]);
85 | }
86 | return 0;
87 | }
88 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/ECU Identification.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* This is important because length_of_each_field is not a SAE J1939 standard. The software need to know how large field it is from the beginning */
31 | j1939_2.from_other_ecu_identifications.ecu_identification.length_of_each_field = 30;
32 |
33 | /* Set the ECU Identification */
34 | j1939_1.information_this_ECU.this_identifications.ecu_identification.length_of_each_field = 30;
35 | char ecu_part_number[20] = "ABC-1100P-XXXX10";
36 | char ecu_serial_number[20] = "1-200-K-10M";
37 | char ecu_location[20] = "Under bridge";
38 | char ecu_type[20] = "Model G";
39 | for (i = 0; i < 20; i++) {
40 | j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_part_number[i] = (uint8_t)ecu_part_number[i];
41 | j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_serial_number[i] = (uint8_t)ecu_serial_number[i];
42 | j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_location[i] = (uint8_t)ecu_location[i];
43 | j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_type[i] = (uint8_t)ecu_type[i];
44 | }
45 |
46 | /* Request Software Identification from ECU 2 to ECU 1 */
47 | SAE_J1939_Send_Request(&j1939_2, 0x80, PGN_ECU_IDENTIFICATION);
48 |
49 | /* Response request from ECU 1 perspective - Don't worry, in real CAN applications you don't need this mess. */
50 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
51 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
52 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
53 |
54 | /* Read response request from ECU 1 to ECU 2 */
55 | for (i = 0; i < 15; i++) {
56 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
57 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
58 | }
59 |
60 | /* Display what ECU 2 got */
61 | printf("Length of each field = %i\nECU part number = %s\nECU serial number = %s\nECU location = %s\nECU type = %s\nFrom ECU address 0x%X"
62 | , j1939_2.from_other_ecu_identifications.ecu_identification.length_of_each_field
63 | , j1939_2.from_other_ecu_identifications.ecu_identification.ecu_part_number
64 | , j1939_2.from_other_ecu_identifications.ecu_identification.ecu_serial_number
65 | , j1939_2.from_other_ecu_identifications.ecu_identification.ecu_location
66 | , j1939_2.from_other_ecu_identifications.ecu_identification.ecu_type
67 | , j1939_2.from_other_ecu_identifications.ecu_identification.from_ecu_address);
68 |
69 | return 0;
70 | }
71 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Proprietary A.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Examples/SAE J1939/Proprietary A.txt
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Proprietary B.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 03 November 2024
5 | * Author: Guillermo Rodríguez
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 | /* Create our J1939 structure with two ECU */
15 | J1939 j1939_1 = { 0 };
16 | J1939 j1939_2 = { 0 };
17 |
18 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
19 | uint8_t i;
20 | for (i = 0; i < 255; i++) {
21 | j1939_1.other_ECU_address[i] = 0xFF;
22 | j1939_2.other_ECU_address[i] = 0xFF;
23 | }
24 |
25 | /* Set the ECU address */
26 | j1939_1.information_this_ECU.this_ECU_address = 0x80; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
27 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
28 |
29 | /* Set the supported PGNs IDs */
30 | // ECU 0x80 will send PGNs 0xFF00 and 0xFF01 and will receive PGNs 0xFFFE and 0xFFFF
31 | // ECU 0x90 will send PGNs 0xFFFE and 0xFFFF anb will receive PGNs 0xFF00 and 0xFF01
32 | j1939_1.this_proprietary.proprietary_B[0].pgn = 0xFF00;
33 | j1939_1.this_proprietary.proprietary_B[1].pgn = 0xFF01;
34 | j1939_1.from_other_ecu_proprietary.proprietary_B[0].pgn = 0xFFFE;
35 | j1939_1.from_other_ecu_proprietary.proprietary_B[1].pgn = 0xFFFF;
36 | j1939_2.this_proprietary.proprietary_B[0].pgn = 0xFFFE;
37 | j1939_2.this_proprietary.proprietary_B[1].pgn = 0xFFFF;
38 | j1939_2.from_other_ecu_proprietary.proprietary_B[0].pgn = 0xFF00;
39 | j1939_2.from_other_ecu_proprietary.proprietary_B[1].pgn = 0xFF01;
40 |
41 | // Set PGN 0xFF00 data content (< 8 bytes) on ECU 1
42 | char pgn_B_0_content[] = "0xFF00";
43 | memcpy(j1939_1.this_proprietary.proprietary_B[0].data, pgn_B_0_content, sizeof(pgn_B_0_content));
44 | j1939_1.this_proprietary.proprietary_B[0].total_bytes = sizeof(pgn_B_0_content);
45 | j1939_2.from_other_ecu_proprietary.proprietary_B[0].total_bytes = sizeof(pgn_B_0_content); // Don't forget to set expected length of the PGN to receive it
46 | // Set PGN 0xFF01 data content (> 8 bytes) on ECU 1
47 | char pgn_B_1_content[] = "This is PGN 0xFF01 content ...";
48 | memcpy(j1939_1.this_proprietary.proprietary_B[1].data, pgn_B_1_content, sizeof(pgn_B_1_content));
49 | j1939_1.this_proprietary.proprietary_B[1].total_bytes = sizeof(pgn_B_1_content);
50 | j1939_2.from_other_ecu_proprietary.proprietary_B[1].total_bytes = sizeof(pgn_B_1_content); // Don't forget to set expected length of the PGN to receive it
51 |
52 | // Set PGN 0xFFFE data content on ECU 2
53 | char pgn_B_FE_content[] = "This is PGN 0xFFFE content .......";
54 | memcpy(j1939_2.this_proprietary.proprietary_B[0].data, pgn_B_FE_content, sizeof(pgn_B_FE_content));
55 | j1939_2.this_proprietary.proprietary_B[0].total_bytes = sizeof(pgn_B_FE_content);
56 | j1939_1.from_other_ecu_proprietary.proprietary_B[0].total_bytes = sizeof(pgn_B_FE_content); // Don't forget to set expected length of the PGN to receive it
57 | // Set PGN 0xFFFF data content on ECU 2
58 | char pgn_B_FF_content[] = "This is PGN 0xFFFF content ..........";
59 | memcpy(j1939_2.this_proprietary.proprietary_B[1].data, pgn_B_FF_content, sizeof(pgn_B_FF_content));
60 | j1939_2.this_proprietary.proprietary_B[1].total_bytes = sizeof(pgn_B_FF_content);
61 | j1939_1.from_other_ecu_proprietary.proprietary_B[1].total_bytes = sizeof(pgn_B_FF_content); // Don't forget to set expected length of the PGN to receive it
62 |
63 | SAE_J1939_Send_Request(&j1939_2, 0x80, 0xFF00);
64 | // Listen for messages
65 | for (i = 0; i < 100; i++) {
66 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
67 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
68 | }
69 | printf("%s\n", (char*)j1939_2.from_other_ecu_proprietary.proprietary_B[0].data);
70 |
71 | SAE_J1939_Send_Request(&j1939_2, 0x80, 0xFF01);
72 | // Listen for messages
73 | for (i = 0; i < 100; i++) {
74 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
75 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
76 | }
77 | printf("%s\n", (char*)j1939_2.from_other_ecu_proprietary.proprietary_B[1].data);
78 |
79 | SAE_J1939_Send_Request(&j1939_1, 0x90, 0xFFFE);
80 | // Listen for messages
81 | for (i = 0; i < 100; i++) {
82 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
83 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
84 | }
85 | printf("%s\n", (char*)j1939_1.from_other_ecu_proprietary.proprietary_B[0].data);
86 |
87 | SAE_J1939_Send_Request(&j1939_1, 0x90, 0xFFFF);
88 | // Listen for messages
89 | for (i = 0; i < 100; i++) {
90 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
91 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
92 | }
93 | printf("%s\n", (char*)j1939_1.from_other_ecu_proprietary.proprietary_B[1].data);
94 |
95 | return 0;
96 | }
97 |
--------------------------------------------------------------------------------
/Src/Examples/SAE J1939/Software Identification.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0xA2; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Set the Software Identification */
31 | j1939_1.information_this_ECU.this_identifications.software_identification.number_of_fields = 15;
32 | char text[15] = "SAE J1939!!!";
33 | for (i = 0; i < 15; i++) {
34 | j1939_1.information_this_ECU.this_identifications.software_identification.identifications[i] = (uint8_t)text[i];
35 | }
36 | /* Request Software Identification from ECU 2 to ECU 1 */
37 | SAE_J1939_Send_Request(&j1939_2, 0xA2, PGN_SOFTWARE_IDENTIFICATION);
38 |
39 | /* Response request from ECU 1 perspective - Don't worry, in real CAN applications you don't need this mess. */
40 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
41 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
42 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
43 |
44 | /* Read response request from ECU 1 to ECU 2 */
45 | for (i = 0; i < 15; i++) {
46 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
47 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
48 | }
49 |
50 | /* Display what ECU 2 got */
51 | printf("Number of fields = %i\nIdentifications = %s\nFrom ECU address = 0x%X", j1939_2.from_other_ecu_identifications.software_identification.number_of_fields, j1939_2.from_other_ecu_identifications.software_identification.identifications, j1939_2.from_other_ecu_identifications.software_identification.from_ecu_address);
52 |
53 | return 0;
54 | }
55 |
--------------------------------------------------------------------------------
/Src/Hardware/FLASH_EEPROM_RAM_Memory.c:
--------------------------------------------------------------------------------
1 | /*
2 | * FLASH_EEPROM_RAM_Memory.c
3 | *
4 | * Created on: 19 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Hardware.h"
9 |
10 | /*
11 | * This function ask the hardware for memory access with pointers.
12 | * Those pointers are translated to DM15 memory responses after the function exist
13 | * DM14: DM15:
14 | * number_of_requested_bytes -> number_of_allowed_bytes
15 | * command -> status
16 | * pointer -> EDC_parameter
17 | * pointer_extension -> EDCP_extention
18 | * key -> seed
19 | */
20 | void FLASH_EEPROM_RAM_Memory(uint16_t *number_of_requested_bytes, uint8_t pointer_type, uint8_t *command, uint32_t *pointer, uint8_t *pointer_extension, uint16_t *key, uint8_t raw_binary_data[]){
21 | #if PROCESSOR_CHOICE == STM32
22 | /* Implement your memory handler function for the STM32 platform */
23 | #elif PROCESSOR_CHOICE == ARDUINO
24 | /* Implement your memory handler function for the Arduino platform */
25 | #elif PROCESSOR_CHOICE == PIC
26 | /* Implement your memory handler function for the PIC platform */
27 | #elif PROCESSOR_CHOICE == AVR
28 | /* Implement your memory handler function for the AVR platform */
29 | #else
30 | /* If no processor are used, use internal feedback for debugging */
31 | raw_binary_data[0] = 0x4C; /* L */
32 | raw_binary_data[1] = 0x6F; /* o */
33 | raw_binary_data[2] = 0x6F; /* o */
34 | raw_binary_data[3] = 0x6B; /* k */
35 | raw_binary_data[4] = 0x20; /* */
36 | raw_binary_data[5] = 0x61; /* a */
37 | raw_binary_data[6] = 0x74; /* t */
38 | raw_binary_data[7] = 0x20; /* */
39 | raw_binary_data[8] = 0x22; /* " */
40 | raw_binary_data[9] = 0x46; /* F */
41 | raw_binary_data[10] = 0x4C; /* L */
42 | raw_binary_data[11] = 0x41; /* A */
43 | raw_binary_data[12] = 0x53; /* S */
44 | raw_binary_data[13] = 0x48; /* H */
45 | raw_binary_data[14] = 0x5F; /* _ */
46 | raw_binary_data[15] = 0x45; /* E */
47 | raw_binary_data[16] = 0x45; /* E */
48 | raw_binary_data[17] = 0x50; /* P */
49 | raw_binary_data[18] = 0x52; /* R */
50 | raw_binary_data[19] = 0x4F; /* O */
51 | raw_binary_data[20] = 0x4D; /* M */
52 | raw_binary_data[21] = 0x5F; /* */
53 | raw_binary_data[22] = 0x52; /* R */
54 | raw_binary_data[23] = 0x41; /* A */
55 | raw_binary_data[24] = 0x4D; /* M */
56 | raw_binary_data[25] = 0x5F; /* _ */
57 | raw_binary_data[26] = 0x4D; /* M */
58 | raw_binary_data[27] = 0x65; /* e */
59 | raw_binary_data[28] = 0x6D; /* m */
60 | raw_binary_data[29] = 0x6F; /* o */
61 | raw_binary_data[30] = 0x72; /* r */
62 | raw_binary_data[31] = 0x79; /* y */
63 | raw_binary_data[32] = 0x2E; /* . */
64 | raw_binary_data[33] = 0x63; /* c */
65 | raw_binary_data[34] = 0x22; /* " */
66 | raw_binary_data[35] = 0x0; /* Null termination C-string */
67 | *number_of_requested_bytes = 40;
68 | *command = STATUS_DM15_PROCEED;
69 | #endif
70 | }
71 |
72 |
73 |
--------------------------------------------------------------------------------
/Src/Hardware/Hardware.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Hardware.h
3 | *
4 | * Created on: 6 nov. 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef HARDWARE_HARDWARE_H_
9 | #define HARDWARE_HARDWARE_H_
10 |
11 | /* Select your processor choice here */
12 | #define NO_PROCESSOR 0
13 | #define STM32 1
14 | #define ARDUINO 2
15 | #define PIC 3
16 | #define AVR 4
17 | #define QT_USB 5
18 | #define INTERNAL_CALLBACK 6
19 | #define PROCESSOR_CHOICE NO_PROCESSOR
20 |
21 | /* C Standard library */
22 | #include "../Open_SAE_J1939/C89_Library.h"
23 |
24 | /* Enums */
25 | #include "../SAE_J1939/SAE_J1939_Enums/Enum_DM14_DM15.h"
26 | #include "../SAE_J1939/SAE_J1939_Enums/Enum_Send_Status.h"
27 |
28 | #ifdef __cplusplus
29 | extern "C" {
30 | #endif
31 |
32 | ENUM_J1939_STATUS_CODES CAN_Send_Message(uint32_t ID, uint8_t data[]);
33 | ENUM_J1939_STATUS_CODES CAN_Send_Request(uint32_t ID, uint8_t PGN[]);
34 | bool CAN_Read_Message(uint32_t *ID, uint8_t data[]);
35 | void CAN_Delay(uint8_t milliseconds);
36 | void CAN_Set_Callback_Functions(void (*Callback_Function_Send_)(uint32_t, uint8_t, uint8_t[]), void (*Callback_Function_Read_)(uint32_t*, uint8_t[], bool*), void (*Callback_Function_Traffic_)(uint32_t, uint8_t, uint8_t[], bool), void (*Callback_Function_Delay_ms_)(uint8_t));
37 | void FLASH_EEPROM_RAM_Memory(uint16_t *number_of_requested_bytes, uint8_t pointer_type, uint8_t *command, uint32_t *pointer, uint8_t *pointer_extension, uint16_t *key, uint8_t raw_binary_data[]);
38 | bool Save_Struct(uint8_t data[], uint32_t data_length, char file_name[]);
39 | bool Load_Struct(uint8_t data[], uint32_t data_length, char file_name[]);
40 |
41 | #ifdef __cplusplus
42 | }
43 | #endif
44 |
45 | #endif /* HARDWARE_HARDWARE_H_ */
46 |
--------------------------------------------------------------------------------
/Src/Hardware/Save_Load_Struct.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Save_Load_Struct.c
3 | *
4 | * Created on: 22 sep. 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Hardware.h"
9 |
10 | /* Layers */
11 | #include
12 |
13 | bool Save_Struct(uint8_t data[], uint32_t data_length, char file_name[]){
14 | #if PROCESSOR_CHOICE == STM32
15 | /* Save it to SD card */
16 | if(STM32_PLC_SD_Mont_Card() != FR_OK){
17 | return false;
18 | }
19 | STM32_PLC_SD_Create_File_With_Write(file_name);
20 | STM32_PLC_SD_Write_Data(data, data_length);
21 | STM32_PLC_SD_Close_File();
22 | STM32_PLC_SD_Unmount_Card();
23 | return true;
24 | #elif PROCESSOR_CHOICE == ARDUINO
25 | /* Implement your memory handler function for the Arduino platform */
26 | #elif PROCESSOR_CHOICE == PIC
27 | /* Implement your memory handler function for the PIC platform */
28 | #elif PROCESSOR_CHOICE == AVR
29 | /* Implement your memory handler function for the AVR platform */
30 | #else
31 | /* Write a file */
32 | FILE *file = NULL;
33 | file = fopen(file_name, "wb");
34 | if (file == NULL) {
35 | return false;
36 | }
37 | fwrite(data, 1, data_length, file);
38 | fclose(file);
39 | return true;
40 | #endif
41 | }
42 |
43 | bool Load_Struct(uint8_t data[], uint32_t data_length, char file_name[]){
44 | #if PROCESSOR_CHOICE == STM32
45 | /* Load it from SD card */
46 | if(STM32_PLC_SD_Mont_Card() != FR_OK){
47 | return false;
48 | }
49 | STM32_PLC_SD_Open_File_With_Read(file_name);
50 | STM32_PLC_SD_Read_Data(data, data_length);
51 | STM32_PLC_SD_Close_File();
52 | STM32_PLC_SD_Unmount_Card();
53 | return true;
54 | #elif PROCESSOR_CHOICE == ARDUINO
55 | /* Implement your memory handler function for the Arduino platform */
56 | #elif PROCESSOR_CHOICE == PIC
57 | /* Implement your memory handler function for the PIC platform */
58 | #elif PROCESSOR_CHOICE == AVR
59 | /* Implement your memory handler function for the AVR platform */
60 | #else
61 | /* Read a file */
62 | FILE *file = NULL;
63 | file = fopen(file_name, "rb");
64 | if(file == NULL){
65 | file = fopen(file_name, "wb");
66 | if (file == NULL) {
67 | return false;
68 | }
69 | }
70 | fread(data, 1, data_length, file);
71 | fclose(file);
72 | return true;
73 | #endif
74 | }
75 |
--------------------------------------------------------------------------------
/Src/ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Application_Layer.h
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef ISO_11783_ISO_11783_7_APPLICATION_LAYER_ISO_11783_7_APPLICATION_LAYER_H_
9 | #define ISO_11783_ISO_11783_7_APPLICATION_LAYER_ISO_11783_7_APPLICATION_LAYER_H_
10 |
11 | /* Enums and struct */
12 | #include "../../Open_SAE_J1939/Structs.h"
13 | #include "../../SAE_J1939/SAE_J1939_Enums/Enum_PGN.h"
14 | #include "../../SAE_J1939/SAE_J1939_Enums/Enum_Send_Status.h"
15 | #include "../ISO_11783_Enums/Enum_Valves.h"
16 |
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 | /* Auxiliary Valve Command */
22 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Auxiliary_Valve_Command(J1939 *j1939, uint8_t valve_number, uint8_t standard_flow, uint8_t fail_safe_mode, uint8_t valve_state);
23 | void ISO_11783_Read_Auxiliary_Valve_Command(J1939 *j1939, uint8_t SA, uint8_t valve_number, uint8_t data[]);
24 |
25 | /* Auxiliary Valve Estimated Flow */
26 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Request_Auxiliary_Valve_Estimated_Flow(J1939 *j1939, uint8_t DA, uint8_t valve_number);
27 | ENUM_J1939_STATUS_CODES ISO_11783_Response_Request_Auxiliary_Valve_Estimated_Flow(J1939 *j1939, uint8_t valve_number);
28 | void ISO_11783_Read_Response_Request_Auxiliary_Estimated_Flow(J1939 *j1939, uint8_t SA, uint8_t valve_number, uint8_t data[]);
29 |
30 | /* Auxiliary Valve Measured Position */
31 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Request_Auxiliary_Valve_Measured_Position(J1939 *j1939, uint8_t DA, uint8_t valve_number);
32 | ENUM_J1939_STATUS_CODES ISO_11783_Response_Request_Auxiliary_Valve_Measured_Position(J1939 *j1939, uint8_t valve_number);
33 | void ISO_11783_Read_Response_Request_Auxiliary_Valve_Measured_Position(J1939 *j1939, uint8_t SA, uint8_t valve_number, uint8_t data[]);
34 |
35 | /* General Purpose Valve Command */
36 | ENUM_J1939_STATUS_CODES ISO_11783_Send_General_Purpose_Valve_Command(J1939 *j1939, uint8_t DA, uint8_t standard_flow, uint8_t fail_safe_mode, uint8_t valve_state, uint16_t extended_flow);
37 | void ISO_11783_Read_General_Purpose_Valve_Command(J1939 *j1939, uint8_t SA, uint8_t data[]);
38 |
39 | /* General Purpose Valve Estimated Flow */
40 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Request_General_Purpose_Valve_Estimated_Flow(J1939 *j1939, uint8_t DA);
41 | ENUM_J1939_STATUS_CODES ISO_11783_Response_Request_General_Purpose_Valve_Estimated_Flow(J1939 *j1939, uint8_t DA);
42 | void ISO_11783_Read_Response_Request_General_Purpose_Valve_Estimated_Flow(J1939 *j1939, uint8_t SA, uint8_t data[]);
43 |
44 | #ifdef __cplusplus
45 | }
46 | #endif
47 |
48 | #endif /* ISO_11783_ISO_11783_7_APPLICATION_LAYER_ISO_11783_7_APPLICATION_LAYER_H_ */
49 |
--------------------------------------------------------------------------------
/Src/ISO_11783/ISO_11783-7_Application_Layer/Auxiliary_Valve_Command.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Auxiliary_Valve_Command.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../../SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Send an auxiliary valve command to all ECU
16 | * PGN: 0x00FE30 (65072) to 0x00FE3F (65087)
17 | */
18 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Auxiliary_Valve_Command(J1939 *j1939, uint8_t valve_number, uint8_t standard_flow, uint8_t fail_safe_mode, uint8_t valve_state) {
19 | uint32_t ID = (0x0CFE << 16) | ((0x30 + valve_number) << 8) | j1939->information_this_ECU.this_ECU_address;
20 | uint8_t data[8];
21 | data[0] = standard_flow;
22 | data[1] = 0xFF; /* Reserved */
23 | data[2] = (fail_safe_mode << 6) | (0b11 << 4) | valve_state; /* Bit 5 and 6 are reserved */
24 | data[3] = data[4] = data[5] = data[6] = data[7] = 0xFF; /* All reserved */
25 | return CAN_Send_Message(ID, data);
26 | }
27 |
28 | /*
29 | * Read an auxiliary valve command from any ECU - Broadcast in other words
30 | * PGN: 0x00FE30 (65072) to 0x00FE3F (65087)
31 | */
32 | void ISO_11783_Read_Auxiliary_Valve_Command(J1939 *j1939, uint8_t SA, uint8_t valve_number, uint8_t data[]) {
33 | j1939->from_other_ecu_auxiliary_valve_command[valve_number].standard_flow = data[0];
34 | j1939->from_other_ecu_auxiliary_valve_command[valve_number].fail_safe_mode = data[2] >> 6;
35 | j1939->from_other_ecu_auxiliary_valve_command[valve_number].valve_state = data[2] & 0b00001111;
36 | j1939->from_other_ecu_auxiliary_valve_command[valve_number].from_ecu_address = SA;
37 | }
38 |
--------------------------------------------------------------------------------
/Src/ISO_11783/ISO_11783-7_Application_Layer/Auxiliary_Valve_Estimated_Flow.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Auxiliary_Valve_Estimated_Flow.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../../SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request auxiliary valve estimated flow to all ECU
16 | * PGN: 0x00FE10 (65040) to 0x00FE1F (65055)
17 | */
18 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Request_Auxiliary_Valve_Estimated_Flow(J1939 *j1939, uint8_t DA, uint8_t valve_number) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_0 + valve_number); /* valve_number can be 0 to 15 */
20 | }
21 |
22 | /*
23 | * Response the request auxiliary valve estimated flow to all ECU
24 | * PGN: 0x00FE10 (65040) to 0x00FE1F (65055)
25 | */
26 | ENUM_J1939_STATUS_CODES ISO_11783_Response_Request_Auxiliary_Valve_Estimated_Flow(J1939 *j1939, uint8_t valve_number) {
27 | uint32_t ID = (0x0CFE << 16) | ((0x10 + valve_number) << 8) | j1939->information_this_ECU.this_ECU_address;
28 | uint8_t data[8];
29 | data[0] = j1939->this_auxiliary_valve_estimated_flow[valve_number].extend_estimated_flow_standard;
30 | data[1] = j1939->this_auxiliary_valve_estimated_flow[valve_number].retract_estimated_flow_standard;
31 | data[2] = (j1939->this_auxiliary_valve_estimated_flow[valve_number].fail_safe_mode << 6) | (0b11 << 4) | j1939->this_auxiliary_valve_estimated_flow[valve_number].valve_state; /* Bit 5 and 6 are reserved */
32 | data[3] = j1939->this_auxiliary_valve_estimated_flow[valve_number].limit << 5;
33 | data[4] = data[5] = data[6] = data[7] = 0xFF; /* All reserved */
34 | return CAN_Send_Message(ID, data);
35 | }
36 |
37 | /*
38 | * Read a response request auxiliary valve estimated flow from any ECU - Broadcast in other words
39 | * PGN: 0x00FE10 (65040) to 0x00FE1F (65055)
40 | */
41 | void ISO_11783_Read_Response_Request_Auxiliary_Estimated_Flow(J1939 *j1939, uint8_t SA, uint8_t valve_number, uint8_t data[]) {
42 | j1939->from_other_ecu_auxiliary_valve_estimated_flow[valve_number].extend_estimated_flow_standard = data[0];
43 | j1939->from_other_ecu_auxiliary_valve_estimated_flow[valve_number].retract_estimated_flow_standard = data[1];
44 | j1939->from_other_ecu_auxiliary_valve_estimated_flow[valve_number].fail_safe_mode = data[2] >> 6;
45 | j1939->from_other_ecu_auxiliary_valve_estimated_flow[valve_number].valve_state = data[2] & 0b00001111;
46 | j1939->from_other_ecu_auxiliary_valve_estimated_flow[valve_number].limit = data[3] >> 5;
47 | j1939->from_other_ecu_auxiliary_valve_estimated_flow[valve_number].from_ecu_address = SA;
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/Src/ISO_11783/ISO_11783-7_Application_Layer/Auxiliary_Valve_Measured_Position.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Auxiliary_Valve_Measured_Position.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../../SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request auxiliary valve measured position to all ECU
16 | * PGN: 0x00FF20 (65312) to 0x00FF2F (65327)
17 | */
18 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Request_Auxiliary_Valve_Measured_Position(J1939 *j1939, uint8_t DA, uint8_t valve_number) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_AUXILIARY_VALVE_MEASURED_POSITION_0 + valve_number); /* valve_number can be 0 to 15 */
20 | }
21 |
22 | /*
23 | * Response the request auxiliary valve measured position to all ECU
24 | * PGN: 0x00FF20 (65312) to 0x00FF2F (65327)
25 | */
26 | ENUM_J1939_STATUS_CODES ISO_11783_Response_Request_Auxiliary_Valve_Measured_Position(J1939 *j1939, uint8_t valve_number) {
27 | uint32_t ID = (0x0CFF << 16) | ((0x20 + valve_number) << 8) | j1939->information_this_ECU.this_ECU_address;
28 | uint8_t data[8];
29 | data[0] = j1939->this_auxiliary_valve_measured_position[valve_number].measured_position_percent;
30 | data[1] = j1939->this_auxiliary_valve_measured_position[valve_number].measured_position_percent >> 8;
31 | data[2] = 0b11110000 | j1939->this_auxiliary_valve_measured_position[valve_number].valve_state;
32 | data[3] = j1939->this_auxiliary_valve_measured_position[valve_number].measured_position_micrometer;
33 | data[4] = j1939->this_auxiliary_valve_measured_position[valve_number].measured_position_micrometer >> 8;
34 | data[5] = data[6] = data[7] = 0xFF; /* All reserved */
35 | return CAN_Send_Message(ID, data);
36 | }
37 |
38 | /*
39 | * Read a response request auxiliary valve measured position from any ECU - Broadcast in other words
40 | * PGN: 0x00FF20 (65312) to 0x00FF2F (65327)
41 | */
42 | void ISO_11783_Read_Response_Request_Auxiliary_Valve_Measured_Position(J1939 *j1939, uint8_t SA, uint8_t valve_number, uint8_t data[]) {
43 | j1939->from_other_ecu_auxiliary_valve_measured_position[valve_number].measured_position_percent = (data[1] << 8) | data[0];
44 | j1939->from_other_ecu_auxiliary_valve_measured_position[valve_number].valve_state = 0b00001111 & data[2];
45 | j1939->from_other_ecu_auxiliary_valve_measured_position[valve_number].measured_position_micrometer = (data[4] << 8) | data[3];
46 | j1939->from_other_ecu_auxiliary_valve_measured_position[valve_number].from_ecu_address = SA;
47 | }
48 |
--------------------------------------------------------------------------------
/Src/ISO_11783/ISO_11783-7_Application_Layer/General_Purpose_Valve_Command.c:
--------------------------------------------------------------------------------
1 | /*
2 | * General_Purpose_Valve_Command.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../../SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Send a general purpose valve command to an ECU
16 | * PGN: 0x00C400 (50176)
17 | */
18 | ENUM_J1939_STATUS_CODES ISO_11783_Send_General_Purpose_Valve_Command(J1939 *j1939, uint8_t DA, uint8_t standard_flow, uint8_t fail_safe_mode, uint8_t valve_state, uint16_t extended_flow) {
19 | uint32_t ID = (0x0CC4 << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
20 | uint8_t data[8];
21 | data[0] = standard_flow;
22 | data[1] = 0xFF; /* Reserved */
23 | data[2] = (fail_safe_mode << 6) | (0b11 << 4) | valve_state; /* Bit 5 and 6 are reserved */
24 | data[3] = extended_flow;
25 | data[4] = extended_flow >> 8;
26 | data[5] = data[6] = data[7] = 0xFF; /* All reserved */
27 | return CAN_Send_Message(ID, data);
28 | }
29 |
30 | /*
31 | * Read a general purpose valve command from an ECU
32 | * PGN: 0x00C400 (50176)
33 | */
34 | void ISO_11783_Read_General_Purpose_Valve_Command(J1939 *j1939, uint8_t SA, uint8_t data[]) {
35 | j1939->from_other_ecu_general_purpose_valve_command.standard_flow = data[0];
36 | j1939->from_other_ecu_general_purpose_valve_command.fail_safe_mode = data[2] >> 6;
37 | j1939->from_other_ecu_general_purpose_valve_command.valve_state = data[2] & 0b00001111;
38 | j1939->from_other_ecu_general_purpose_valve_command.extended_flow = (data[4] << 8) | data[3];
39 | j1939->from_other_ecu_general_purpose_valve_command.from_ecu_address = SA;
40 | }
41 |
--------------------------------------------------------------------------------
/Src/ISO_11783/ISO_11783-7_Application_Layer/General_Purpose_Valve_Estimated_Flow.c:
--------------------------------------------------------------------------------
1 | /*
2 | * General_Purpose_Valve_Estimated_Flow.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../../SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request general purpose valve estimated flow to an ECU
16 | * PGN: 0x00C600 (50688)
17 | */
18 | ENUM_J1939_STATUS_CODES ISO_11783_Send_Request_General_Purpose_Valve_Estimated_Flow(J1939 *j1939, uint8_t DA) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_GENERAL_PURPOSE_VALVE_ESTIMATED_FLOW);
20 | }
21 |
22 | /*
23 | * Response the request general purpose valve estimated flow to an ECU
24 | * PGN: 0x00C600 (50688)
25 | */
26 | ENUM_J1939_STATUS_CODES ISO_11783_Response_Request_General_Purpose_Valve_Estimated_Flow(J1939 *j1939, uint8_t DA) {
27 | uint32_t ID = (0x0CC6 << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
28 | uint8_t data[8];
29 | data[0] = j1939->this_general_purpose_valve_estimated_flow.extend_estimated_flow_standard;
30 | data[1] = j1939->this_general_purpose_valve_estimated_flow.retract_estimated_flow_standard;
31 | data[2] = (j1939->this_general_purpose_valve_estimated_flow.fail_safe_mode << 6) | (0b11 << 4) | j1939->this_general_purpose_valve_estimated_flow.valve_state; /* Bit 5 and 6 are reserved for further use */
32 | data[3] = j1939->this_general_purpose_valve_estimated_flow.limit << 5;
33 | data[4] = j1939->this_general_purpose_valve_estimated_flow.extend_estimated_flow_extended;
34 | data[5] = j1939->this_general_purpose_valve_estimated_flow.extend_estimated_flow_extended >> 8;
35 | data[6] = j1939->this_general_purpose_valve_estimated_flow.retract_estimated_flow_extended;
36 | data[7] = j1939->this_general_purpose_valve_estimated_flow.retract_estimated_flow_extended >> 8;
37 | return CAN_Send_Message(ID, data);
38 | }
39 |
40 | /*
41 | * Read a response request general purpose valve estimated flow from an ECU
42 | * PGN: 0x00C600 (50688)
43 | */
44 | void ISO_11783_Read_Response_Request_General_Purpose_Valve_Estimated_Flow(J1939 *j1939, uint8_t SA, uint8_t data[]) {
45 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.extend_estimated_flow_standard = data[0];
46 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.retract_estimated_flow_standard = data[1];
47 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.fail_safe_mode = data[2] >> 6;
48 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.valve_state = data[2] & 0b00001111;
49 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.limit = data[3] >> 5;
50 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.extend_estimated_flow_extended = (data[5] << 8) | data[4];
51 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.retract_estimated_flow_extended = (data[7] << 8) | data[6];
52 | j1939->from_other_ecu_general_purpose_valve_estimated_flow.from_ecu_address = SA;
53 | }
54 |
--------------------------------------------------------------------------------
/Src/ISO_11783/ISO_11783_Enums/Enum_Valves.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Enum_Auxiliary_And_General_Purpose_Valves.h
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef ISO_11783_ISO_11783_ENUMS_ISO_11783_ENUM_AUXILIARY_AND_GENERAL_PURPOSE_VALVES_H_
9 | #define ISO_11783_ISO_11783_ENUMS_ISO_11783_ENUM_AUXILIARY_AND_GENERAL_PURPOSE_VALVES_H_
10 |
11 | /* Enums for valve commands */
12 | typedef enum {
13 | VALVE_STATE_NEUTRAL = 0x00U,
14 | VALVE_STATE_EXTEND = 0x1U,
15 | VALVE_STATE_RETRACT = 0x2U,
16 | VALVE_STATE_FLOATING = 0x3U,
17 | VALVE_STATE_INITIALISATION = 0xAU,
18 | VALVE_STATE_ERROR = 0xEU
19 | }ENUM_VALVE_STATE_CODES;
20 |
21 | typedef enum {
22 | EXIT_CODE_NOT_USED = 0x1FU
23 | }ENUM_EXIT_CODE_CODES;
24 |
25 | typedef enum {
26 | FAIL_SAFE_MODE_BLOCKED = 0x0U,
27 | FAIL_SAFE_MODE_ACTIVATED = 0x1U
28 | }ENUM_FAIL_SAFE_MODE_CODES;
29 |
30 | typedef enum {
31 | LIMIT_NOT_USED = 0x7U
32 | }ENUM_LIMIT_CODES;
33 |
34 | #endif /* ISO_11783_ISO_11783_ENUMS_ISO_11783_ENUM_AUXILIARY_AND_GENERAL_PURPOSE_VALVES_H_ */
35 |
--------------------------------------------------------------------------------
/Src/Main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Main.c
3 | *
4 | * Created on: 16 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include
9 |
10 | /* Include Open SAE J1939 */
11 | #include "Open_SAE_J1939/Open_SAE_J1939.h"
12 |
13 | int main() {
14 |
15 | /* Create our J1939 structure with two ECU */
16 | J1939 j1939_1 = { 0 };
17 | J1939 j1939_2 = { 0 };
18 |
19 | /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
20 | uint8_t i;
21 | for (i = 0; i < 255; i++) {
22 | j1939_1.other_ECU_address[i] = 0xFF;
23 | j1939_2.other_ECU_address[i] = 0xFF;
24 | }
25 |
26 | /* Set the ECU address */
27 | j1939_1.information_this_ECU.this_ECU_address = 0xA2; /* From 0 to 253 because 254 = error address and 255 = broadcast address */
28 | j1939_2.information_this_ECU.this_ECU_address = 0x90;
29 |
30 | /* Set the Software Identification */
31 | j1939_1.information_this_ECU.this_identifications.software_identification.number_of_fields = 15;
32 | char text[15] = "SAE J1939!!!";
33 | for (i = 0; i < 15; i++) {
34 | j1939_1.information_this_ECU.this_identifications.software_identification.identifications[i] = (uint8_t)text[i];
35 | }
36 | /* Request Software Identification from ECU 2 to ECU 1 */
37 | SAE_J1939_Send_Request(&j1939_2, 0xA2, PGN_SOFTWARE_IDENTIFICATION);
38 |
39 | /* Response request from ECU 1 perspective - Don't worry, in real CAN applications you don't need this mess. */
40 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
41 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
42 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
43 |
44 | /* Read response request from ECU 1 to ECU 2 */
45 | for (i = 0; i < 15; i++) {
46 | Open_SAE_J1939_Listen_For_Messages(&j1939_2);
47 | Open_SAE_J1939_Listen_For_Messages(&j1939_1);
48 | }
49 |
50 | /* Display what ECU 2 got */
51 | printf("Number of fields = %i\nIdentifications = %s\nFrom ECU address = 0x%X", j1939_2.from_other_ecu_identifications.software_identification.number_of_fields, j1939_2.from_other_ecu_identifications.software_identification.identifications, j1939_2.from_other_ecu_identifications.software_identification.from_ecu_address);
52 |
53 | return 0;
54 | }
55 |
--------------------------------------------------------------------------------
/Src/Open_SAE_J1939/C89_Library.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Clibrary.h
3 | *
4 | * Created on: 28 feb. 2023
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef OPEN_SAE_J1939_C89_LIBRARY_H_
9 | #define OPEN_SAE_J1939_C89_LIBRARY_H_
10 |
11 | /* C standard library */
12 | #include
13 | #include
14 |
15 | #ifndef __cplusplus
16 |
17 | /* In ANSI C (C89), the __STDC_VERSION__ is not defined */
18 | #ifndef __STDC_VERSION__
19 | #define __STDC_VERSION__ 199409L /* STDC version of C89 standard */
20 | #endif
21 |
22 | /* C99 has the __STDC_VERSION 199901L */
23 | #if __STDC_VERSION__ < 199901L
24 | /* Standard signed int and unsigned int */
25 | typedef unsigned char uint8_t;
26 | typedef unsigned short uint16_t;
27 | typedef unsigned int uint32_t;
28 | typedef signed char int8_t;
29 | typedef signed short int16_t;
30 | typedef signed int int32_t;
31 |
32 | /* Standard bool */
33 | typedef uint8_t bool;
34 | #define true 1
35 | #define false 0
36 |
37 | #define SAE_J1939_INLINE
38 |
39 | #else
40 | /* C99 and above */
41 | #include /* For bool datatype */
42 | #include /* For uint8_t, uint16_t and uint32_t */
43 |
44 | #define SAE_J1939_INLINE inline
45 |
46 | #endif
47 | #endif
48 |
49 | #endif /* OPEN_SAE_J1939_C89_LIBRARY_H_ */
50 |
--------------------------------------------------------------------------------
/Src/Open_SAE_J1939/Closedown_ECU.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DanielMartensson/Open-SAE-J1939/e5e5ee62024639dc752538c6dec31a52438d6d85/Src/Open_SAE_J1939/Closedown_ECU.c
--------------------------------------------------------------------------------
/Src/Open_SAE_J1939/Listen_For_Messages.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Listen_For_Messages.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Open_SAE_J1939.h"
9 |
10 | /* Layers */
11 | #include "../ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
12 | #include "../Hardware/Hardware.h"
13 |
14 | /* This function should be called all the time, or be placed inside an interrupt listener */
15 | ENUM_J1939_RX_MSG Open_SAE_J1939_Listen_For_Messages(J1939* j1939) {
16 | uint32_t ID = 0;
17 | uint8_t data[8] = {0};
18 | ENUM_J1939_RX_MSG rx_msg = RX_MSG_NONE;
19 | bool is_new_message = CAN_Read_Message(&ID, data);
20 | if(is_new_message) {
21 | /* Save latest */
22 | j1939->ID = ID;
23 | memcpy(j1939->data, data, 8);
24 | j1939->ID_and_data_is_updated = true;
25 |
26 | uint8_t id0 = ID >> 24;
27 | uint8_t id1 = ID >> 16; /* PDU Format (PF) */
28 | uint8_t DA = ID >> 8; /* PDU Specific (PS) or destination address which is this ECU. if DA = 0xFF = broadcast to all ECU. Sometimes DA can be an ID number too */
29 | uint8_t SA = ID; /* Source address of the ECU that we got the message from */
30 |
31 | uint32_t PGN;
32 |
33 | /* Properly calculate PGN based on PF (id1) */
34 | if (id1 >= 240){
35 | PGN = (ID >> 8) & 0x3FFFFUL; /* Mask for including EDP, DP, PF, and PS in the PGN */
36 | }else{
37 | PGN = (ID >> 8) & 0x3FF00UL; /* Mask for including EDP, DP, and PF only (exclude PS) */
38 | }
39 |
40 | rx_msg = RX_MSG_NOT_SUPPORTED;
41 |
42 | /* Read request from other ECU */
43 | if (id0 == 0x18 && id1 == 0xEA && (DA == j1939->information_this_ECU.this_ECU_address || DA == 0xFF)){
44 | SAE_J1939_Read_Request(j1939, SA, data);
45 | rx_msg = RX_MSG_REQ;
46 | }else if (id0 == 0x18 && id1 == 0xD9 && DA == j1939->information_this_ECU.this_ECU_address){
47 | SAE_J1939_Read_Request_DM14(j1939, SA, data);
48 | rx_msg = RX_MSG_REQ_DM14;
49 |
50 | /* Read status from other ECU */
51 | }else if(id0 == 0x18 && id1 == 0xE8 && DA == j1939->information_this_ECU.this_ECU_address){
52 | SAE_J1939_Read_Acknowledgement(j1939, SA, data);
53 | rx_msg = RX_MSG_ACK;
54 | }else if (id0 == 0x18 && id1 == 0xD8 && DA == j1939->information_this_ECU.this_ECU_address){
55 | SAE_J1939_Read_Response_DM15(j1939, SA, data);
56 | rx_msg = RX_MSG_DM15;
57 | }else if(id0 == 0x18 && id1 == 0xD7 && DA == j1939->information_this_ECU.this_ECU_address){
58 | SAE_J1939_Read_Binary_Data_Transfer_DM16(j1939, SA, data);
59 | rx_msg = RX_MSG_DM16;
60 |
61 | /* Read Transport Protocol information from other ECU */
62 | }else if(id0 == 0x1C && id1 == 0xEC && (DA == j1939->information_this_ECU.this_ECU_address || DA == 0xFF)){
63 | SAE_J1939_Read_Transport_Protocol_Connection_Management(j1939, SA, data);
64 | rx_msg = RX_MSG_TP_CONN_MANAGEMENT;
65 | }else if (id0 == 0x1C && id1 == 0xEB && (DA == j1939->information_this_ECU.this_ECU_address || DA == 0xFF)){
66 | SAE_J1939_Read_Transport_Protocol_Data_Transfer(j1939, SA, data);
67 | rx_msg = RX_MSG_TP_CONN_DATA_TRANSFER;
68 |
69 | /* Read response request from other ECU - This are response request. They are responses from other ECU about request from this ECU */
70 | }else if (id0 == 0x14 && id1 == 0xEF && DA == 0x23) {
71 | SAE_J1939_Read_Response_Request_Proprietary_A(j1939, SA, data); /* Manufacturer specific data */
72 | rx_msg = RX_MSG_RESP_REQ_PROPRIETARY_A;
73 | }else if (((PGN >= PGN_PROPRIETARY_B_START) && (PGN <= PGN_PROPRIETARY_B_END)) ||
74 | ((PGN >= PGN_PROPRIETARY_B2_START) && (PGN <= PGN_PROPRIETARY_B2_END))) {
75 | SAE_J1939_Read_Response_Request_Proprietary_B(j1939, SA, PGN, data); /* Manufacturer specific data (B) */
76 | rx_msg = RX_MSG_RESP_REQ_PROPRIETARY_B;
77 | }else if (id0 == 0x18 && id1 == 0xEE && DA == 0xFF && SA != 0xFE){
78 | SAE_J1939_Read_Response_Request_Address_Claimed(j1939, SA, data); /* This is a broadcast response request */
79 | rx_msg = RX_MSG_RESP_REQ_ADDR_CLAIMED;
80 | }else if (id0 == 0x18 && id1 == 0xEE && DA == 0xFF && SA == 0xFE) {
81 | SAE_J1939_Read_Address_Not_Claimed(j1939, SA, data); /* This is error */
82 | rx_msg = RX_MSG_ADDR_NOT_CLAIMED;
83 |
84 | }else if (id0 == 0x18 && id1 == 0xFE && DA == 0xCA){
85 | SAE_J1939_Read_Response_Request_DM1(j1939, SA, data, 1); /* Assume that errors_dm1_active = 1 */
86 | rx_msg = RX_MSG_RESP_REQ_DM1;
87 | }else if (id0 == 0x18 && id1 == 0xFE && DA == 0xCB){
88 | SAE_J1939_Read_Response_Request_DM2(j1939, SA, data, 1); /* Assume that errors_dm2_active = 1 */
89 | rx_msg = RX_MSG_RESP_REQ_DM2;
90 | }else if (id0 == 0x18 && id1 == 0xFE && DA == 0xDA){
91 | SAE_J1939_Read_Response_Request_Software_Identification(j1939, SA, data);
92 | rx_msg = RX_MSG_RESP_REQ_SOFTWARE_IDENTIFICATION;
93 | }else if (id0 == 0x18 && id1 == 0xFD && DA == 0xC5){
94 | SAE_J1939_Read_Response_Request_ECU_Identification(j1939, SA, data);
95 | rx_msg = RX_MSG_RESP_REQ_ECU_IDENTIFICATION;
96 | }else if (id0 == 0x18 && id1 == 0xFE && DA == 0xEB){
97 | SAE_J1939_Read_Response_Request_Component_Identification(j1939, SA, data);
98 | rx_msg = RX_MSG_RESP_REQ_COMPONENT_IDENTIFICATION;
99 | }else if (id0 == 0x0C && id1 == 0xFE && DA >= 0x10 && DA <= 0x1F){
100 | ISO_11783_Read_Response_Request_Auxiliary_Estimated_Flow(j1939, SA, DA & 0xF, data); /* DA & 0xF = Valve number. Total 16 valves from 0 to 15 */
101 | rx_msg = RX_MSG_RESP_REQ_AUX_ESTIMATED_FLOW;
102 | }else if (id0 == 0x0C && id1 == 0xC6 && DA == j1939->information_this_ECU.this_ECU_address){
103 | ISO_11783_Read_Response_Request_General_Purpose_Valve_Estimated_Flow(j1939, SA, data);
104 | rx_msg = RX_MSG_RESP_REQ_GP_VALVE_ESTIMATED_FLOW;
105 | }else if (id0 == 0x0C && id1 == 0xFF && DA >= 0x20 && DA <= 0x2F) {
106 | ISO_11783_Read_Response_Request_Auxiliary_Valve_Measured_Position(j1939, SA, DA & 0xF, data); /* DA & 0xF = Valve number. Total 16 valves from 0 to 15 */
107 | rx_msg = RX_MSG_RESP_REQ_AUX_VALVE_MEASURED_POSITION;
108 |
109 | /* Read command from other ECU */
110 | }else if (id0 == 0x0C && id1 == 0xFE && DA >= 0x30 && DA <= 0x3F){
111 | ISO_11783_Read_Auxiliary_Valve_Command(j1939, SA, DA & 0xF, data); /* DA & 0xF = Valve number. Total 16 valves from 0 to 15 */
112 | rx_msg = RX_MSG_AUX_VALVE_CMD;
113 | }else if (id0 == 0x0C && id1 == 0xC4 && DA == j1939->information_this_ECU.this_ECU_address){
114 | ISO_11783_Read_General_Purpose_Valve_Command(j1939, SA, data); /* General Purpose Valve Command have only one valve */
115 | rx_msg = RX_MSG_GP_VALVE_CMD;
116 | }else if (id0 == 0x0 && id1 == 0x2 && (DA == j1939->information_this_ECU.this_ECU_address || DA == 0xFF)){
117 | SAE_J1939_Read_Address_Delete(j1939, data); /* Not a SAE J1939 standard */
118 | rx_msg = RX_MSG_NOT_SAE_J1939;
119 | }else{
120 | rx_msg = RX_MSG_UNKNOWN; /* The message was not meant for this ECU */
121 | }
122 | /* Add more else if statement here */
123 | }
124 | return rx_msg;
125 | }
126 |
--------------------------------------------------------------------------------
/Src/Open_SAE_J1939/Open_SAE_J1939.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Open_SAE_J1939.h
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef OPEN_SAE_J1939_OPEN_SAE_J1939_H_
9 | #define OPEN_SAE_J1939_OPEN_SAE_J1939_H_
10 |
11 | /* Enum and structs */
12 | #include "Structs.h"
13 |
14 | /* Layers */
15 | #include "../SAE_J1939/SAE_J1939-71_Application_Layer/Application_Layer.h"
16 | #include "../SAE_J1939/SAE_J1939-73_Diagnostics_Layer/Diagnostics_Layer.h"
17 | #include "../SAE_J1939/SAE_J1939-81_Network_Management_Layer/Network_Management_Layer.h"
18 | #include "../SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Layer.h"
19 |
20 | #ifdef __cplusplus
21 | extern "C" {
22 | #endif
23 |
24 |
25 | /* Enum for the supported functionality */
26 | typedef enum {
27 | RX_MSG_NONE = 0,
28 | RX_MSG_ACK,
29 | RX_MSG_REQ,
30 | RX_MSG_REQ_DM14,
31 | RX_MSG_DM15,
32 | RX_MSG_DM16,
33 | RX_MSG_TP_CONN_MANAGEMENT,
34 | RX_MSG_TP_CONN_DATA_TRANSFER,
35 | RX_MSG_RESP_REQ_PROPRIETARY_A,
36 | RX_MSG_RESP_REQ_PROPRIETARY_B,
37 | RX_MSG_RESP_REQ_ADDR_CLAIMED,
38 | RX_MSG_ADDR_NOT_CLAIMED,
39 | RX_MSG_RESP_REQ_DM1,
40 | RX_MSG_RESP_REQ_DM2,
41 | RX_MSG_RESP_REQ_SOFTWARE_IDENTIFICATION,
42 | RX_MSG_RESP_REQ_ECU_IDENTIFICATION,
43 | RX_MSG_RESP_REQ_COMPONENT_IDENTIFICATION,
44 | RX_MSG_RESP_REQ_AUX_ESTIMATED_FLOW,
45 | RX_MSG_RESP_REQ_GP_VALVE_ESTIMATED_FLOW,
46 | RX_MSG_RESP_REQ_AUX_VALVE_MEASURED_POSITION,
47 | RX_MSG_AUX_VALVE_CMD,
48 | RX_MSG_GP_VALVE_CMD,
49 | RX_MSG_NOT_SUPPORTED,
50 | RX_MSG_NOT_SAE_J1939,
51 | RX_MSG_UNKNOWN
52 | } ENUM_J1939_RX_MSG;
53 |
54 | /* This functions must be called all the time, or be placed inside an interrupt listener */
55 | ENUM_J1939_RX_MSG Open_SAE_J1939_Listen_For_Messages(J1939 *j1939);
56 |
57 | /* This function should ONLY be called at your ECU startup */
58 | bool Open_SAE_J1939_Startup_ECU(J1939* j1939);
59 |
60 | /* This function should ONLY be called at your ECU closedown */
61 | bool Open_SAE_J1939_Closedown_ECU(J1939* j1939);
62 |
63 | #ifdef __cplusplus
64 | }
65 | #endif
66 |
67 | #endif /* OPEN_SAE_J1939_OPEN_SAE_J1939_H_ */
68 |
--------------------------------------------------------------------------------
/Src/Open_SAE_J1939/Startup_ECU.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Startup_ECU.c
3 | *
4 | * Created on: 25 sep. 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Open_SAE_J1939.h"
9 |
10 | /* Layers */
11 | #include "../Hardware/Hardware.h"
12 |
13 | /* Load our ECU parameters into J1939 structure. Very useful if you want your ECU remember its NAME + address + identifications at startup. */
14 | bool Open_SAE_J1939_Startup_ECU(J1939* j1939) {
15 | uint32_t ECU_information_length = sizeof(Information_this_ECU);
16 | uint8_t ECU_information_data[sizeof(Information_this_ECU)];
17 | memset(ECU_information_data, 0, ECU_information_length);
18 | if(!Load_Struct(ECU_information_data, ECU_information_length, (char*)INFORMATION_THIS_ECU)){
19 | return false; /* Problems occurs */
20 | }
21 | memcpy(&j1939->information_this_ECU, (Information_this_ECU*)ECU_information_data, ECU_information_length);
22 |
23 | /* If we are going to send and receive the ECU identification and component identification, we need to specify the size of them */
24 | j1939->information_this_ECU.this_identifications.ecu_identification.length_of_each_field = MAX_IDENTIFICATION;
25 | j1939->information_this_ECU.this_identifications.component_identification.length_of_each_field = MAX_IDENTIFICATION;
26 | j1939->from_other_ecu_identifications.ecu_identification.length_of_each_field = MAX_IDENTIFICATION;
27 | j1939->from_other_ecu_identifications.component_identification.length_of_each_field = MAX_IDENTIFICATION;
28 |
29 | /* If we are going to send and receive Proprietary, we need to specify the size of them */
30 | j1939->this_proprietary.proprietary_A.total_bytes = MAX_PROPRIETARY_A;
31 | j1939->from_other_ecu_proprietary.proprietary_A.total_bytes = MAX_PROPRIETARY_A;
32 | for (int i = 0; i < MAX_PROPRIETARY_B_PGNS; ++i)
33 | {
34 | j1939->this_proprietary.proprietary_B[i].total_bytes = MAX_PROPRIETARY_B;
35 | j1939->from_other_ecu_proprietary.proprietary_B[i].total_bytes = MAX_PROPRIETARY_B;
36 | }
37 |
38 | /* Clear other ECU addresses by setting the broadcast address to them */
39 | memset(j1939->other_ECU_address, 0xFF, 0xFF);
40 | j1939->number_of_cannot_claim_address = 0;
41 | j1939->number_of_other_ECU = 0;
42 |
43 | /* This broadcast out this ECU NAME + address to all other ECU:s */
44 | SAE_J1939_Response_Request_Address_Claimed(j1939);
45 |
46 | /* This asking all ECU about their NAME + address */
47 | SAE_J1939_Send_Request_Address_Claimed(j1939, 0xFF);
48 |
49 | /* OK */
50 | return true;
51 | }
52 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-21_Transport_Layer/Acknowledgement.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Acknowledgement.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Transport_Layer.h"
9 |
10 | /*
11 | * Store acknowledgement information from other ECU about PGN request to other ECU
12 | * PGN: 0x00E800 (59392)
13 | */
14 | void SAE_J1939_Read_Acknowledgement(J1939 *j1939, uint8_t SA, uint8_t data[]) {
15 | j1939->from_other_ecu_acknowledgement.control_byte = data[0];
16 | j1939->from_other_ecu_acknowledgement.group_function_value = data[1]; /* The cause of the control byte */
17 | j1939->from_other_ecu_acknowledgement.address = data[4]; /* The source address from the ECU */
18 | j1939->from_other_ecu_acknowledgement.PGN_of_requested_info = (data[7] << 16) | (data[6] << 8) | data[5];
19 | j1939->from_other_ecu_acknowledgement.from_ecu_address = SA; /* From where came the message */
20 | }
21 |
22 | /*
23 | * Send back a acknowledgement to other ECU about the their PGN request
24 | * PGN: 0x00E800 (59392)
25 | */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Acknowledgement(J1939 *j1939, uint8_t DA, uint8_t control_byte, uint8_t group_function_value, uint32_t PGN_of_requested_info) {
27 | uint32_t ID = (0x18E8 << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
28 | uint8_t data[8];
29 | data[0] = control_byte;
30 | data[1] = group_function_value; /* The cause of the control byte */
31 | data[2] = 0xFF; /* Reserved */
32 | data[3] = 0xFF; /* Reserved */
33 | data[4] = j1939->information_this_ECU.this_ECU_address; /* This source address */
34 | data[5] = PGN_of_requested_info;
35 | data[6] = PGN_of_requested_info >> 8;
36 | data[7] = PGN_of_requested_info >> 16;
37 | return CAN_Send_Message(ID, data);
38 | }
39 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Layer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Transport_Layer.h
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_21_TRANSPORT_LAYER_SAE_J1939_21_TRANSPORT_LAYER_H_
9 | #define SAE_J1939_21_TRANSPORT_LAYER_SAE_J1939_21_TRANSPORT_LAYER_H_
10 |
11 | /* Enums and structs */
12 | #include "../../Open_SAE_J1939/Structs.h"
13 | #include "../SAE_J1939_Enums/Enum_Control_Byte.h"
14 | #include "../SAE_J1939_Enums/Enum_DM1_DM2.h"
15 | #include "../SAE_J1939_Enums/Enum_DM14_DM15.h"
16 | #include "../SAE_J1939_Enums/Enum_Group_Function_Value.h"
17 | #include "../SAE_J1939_Enums/Enum_NAME.h"
18 | #include "../SAE_J1939_Enums/Enum_PGN.h"
19 | #include "../SAE_J1939_Enums/Enum_Send_Status.h"
20 |
21 | /* Layers */
22 | #include "../../Hardware/Hardware.h"
23 |
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 |
29 | /* Acknowledgement */
30 | void SAE_J1939_Read_Acknowledgement(J1939 *j1939, uint8_t SA, uint8_t data[]);
31 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Acknowledgement(J1939 *j1939, uint8_t DA, uint8_t control_byte, uint8_t group_function_value, uint32_t PGN_of_requested_info);
32 |
33 | /* Request */
34 | void SAE_J1939_Read_Request(J1939 *j1939, uint8_t SA, uint8_t data[]);
35 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request(J1939 *j1939, uint8_t DA, uint32_t PGN_code);
36 |
37 | /* Transport Protocol Connection Management */
38 | void SAE_J1939_Read_Transport_Protocol_Connection_Management(J1939 *j1939, uint8_t SA, uint8_t data[]);
39 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Transport_Protocol_Connection_Management(J1939 *j1939, uint8_t DA);
40 |
41 | /* Transport Protocol Data Transfer */
42 | void SAE_J1939_Read_Transport_Protocol_Data_Transfer(J1939 *j1939, uint8_t SA, uint8_t data[]);
43 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Transport_Protocol_Data_Transfer(J1939 *j1939, uint8_t DA);
44 |
45 | static SAE_J1939_INLINE uint8_t SAE_J1939_Transport_Protocol_GetNumberOfPackages(uint16_t total_message_size_being_transmitted) {
46 | return total_message_size_being_transmitted % 7 > 0 ? total_message_size_being_transmitted / 7 + 1 : total_message_size_being_transmitted / 7; /* Rounding up */
47 | }
48 |
49 | #ifdef __cplusplus
50 | }
51 | #endif
52 |
53 | #endif /* SAE_J1939_21_TRANSPORT_LAYER_SAE_J1939_21_TRANSPORT_LAYER_H_ */
54 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Protocol_Connection_Management.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Transport_Protocol_Connection_Management.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Transport_Layer.h"
9 |
10 | /*
11 | * Store information about sequence data packages from other ECU who are going to send to this ECU
12 | * PGN: 0x00EC00 (60416)
13 | */
14 | void SAE_J1939_Read_Transport_Protocol_Connection_Management(J1939 *j1939, uint8_t SA, uint8_t data[]) {
15 | /* Read the control byte */
16 | j1939->from_other_ecu_tp_cm.control_byte = data[0];
17 |
18 | /* PGN */
19 | j1939->from_other_ecu_tp_cm.PGN_of_the_packeted_message = (data[7] << 16) | (data[6] << 8) | data[5];
20 |
21 | /* Source address */
22 | j1939->from_other_ecu_tp_cm.from_ecu_address = SA;
23 |
24 | /* Check the control byte */
25 | switch (data[0]) {
26 | case CONTROL_BYTE_TP_CM_RTS:
27 | /* Set the RTS values */
28 | j1939->from_other_ecu_tp_cm.total_message_size_being_transmitted = (data[2] << 8) | data[1];
29 | j1939->from_other_ecu_tp_cm.number_of_packages_being_transmitted = data[3];
30 |
31 | /* Send CTS */
32 | j1939->this_ecu_tp_cm.control_byte = CONTROL_BYTE_TP_CM_CTS;
33 | j1939->this_ecu_tp_cm.number_of_packets_to_be_transmitted = 1;
34 | j1939->this_ecu_tp_cm.next_packet_number_transmitted = 1;
35 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = (data[7] << 16) | (data[6] << 8) | data[5];
36 | SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, SA);
37 | break;
38 | case CONTROL_BYTE_TP_CM_CTS:
39 | j1939->from_other_ecu_tp_cm.number_of_packets_to_be_transmitted = data[1];
40 | j1939->from_other_ecu_tp_cm.next_packet_number_transmitted = data[2];
41 | SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, SA);
42 | break;
43 | case CONTROL_BYTE_TP_CM_BAM:
44 | j1939->from_other_ecu_tp_cm.total_message_size_being_transmitted = (data[2] << 8) | data[1];
45 | j1939->from_other_ecu_tp_cm.number_of_packages_being_transmitted = data[3];
46 | SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, SA);
47 | break;
48 | case CONTROL_BYTE_TP_CM_EndOfMsgACK:
49 | j1939->from_other_ecu_tp_cm.total_number_of_bytes_received = (data[2] << 8) | data[1];
50 | j1939->from_other_ecu_tp_cm.total_number_of_packages_received = data[3];
51 | }
52 | }
53 |
54 | /*
55 | * Send information to other ECU about how much sequence data packages this ECU is going to send to other ECU
56 | * PGN: 0x00EC00 (60416)
57 | */
58 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Transport_Protocol_Connection_Management(J1939 *j1939, uint8_t DA) {
59 | uint32_t ID = (0x1CEC << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
60 | uint8_t data[8] = { 0 };
61 |
62 | /* Read the control byte */
63 | data[0] = j1939->this_ecu_tp_cm.control_byte;
64 |
65 | /* Check the control byte */
66 | switch (data[0]) {
67 | case CONTROL_BYTE_TP_CM_RTS:
68 | data[1] = j1939->this_ecu_tp_cm.total_message_size_being_transmitted;
69 | data[2] = j1939->this_ecu_tp_cm.total_message_size_being_transmitted >> 8;
70 | data[3] = j1939->this_ecu_tp_cm.number_of_packages_being_transmitted;
71 | data[4] = 0x01; /* Max number of packages to be transmitted at once */
72 | break;
73 | case CONTROL_BYTE_TP_CM_CTS:
74 | data[1] = j1939->this_ecu_tp_cm.number_of_packets_to_be_transmitted;
75 | data[2] = j1939->this_ecu_tp_cm.next_packet_number_transmitted;
76 | data[3] = 0xFF; /* Reserved */
77 | data[4] = 0xFF; /* Reserved */
78 | break;
79 | case CONTROL_BYTE_TP_CM_BAM:
80 | data[1] = j1939->this_ecu_tp_cm.total_message_size_being_transmitted;
81 | data[2] = j1939->this_ecu_tp_cm.total_message_size_being_transmitted >> 8;
82 | data[3] = j1939->this_ecu_tp_cm.number_of_packages_being_transmitted;
83 | data[4] = 0xFF; /* Reserved */
84 | break;
85 | case CONTROL_BYTE_TP_CM_EndOfMsgACK:
86 | data[1] = j1939->this_ecu_tp_cm.total_number_of_bytes_received;
87 | data[2] = j1939->this_ecu_tp_cm.total_number_of_bytes_received >> 8;
88 | data[3] = j1939->this_ecu_tp_cm.total_number_of_packages_received;
89 | data[4] = 0xFF; /* Reserved */
90 | }
91 |
92 | /* PGN */
93 | data[5] = j1939->this_ecu_tp_cm.PGN_of_the_packeted_message;
94 | data[6] = j1939->this_ecu_tp_cm.PGN_of_the_packeted_message >> 8;
95 | data[7] = j1939->this_ecu_tp_cm.PGN_of_the_packeted_message >> 16;
96 |
97 | return CAN_Send_Message(ID, data);
98 | }
99 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-21_Transport_Layer/Transport_Protocol_Data_Transfer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Transport_Protocol_Data_Transfer.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Transport_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-81_Network_Management_Layer/Network_Management_Layer.h"
12 | #include "../SAE_J1939-73_Diagnostics_Layer/Diagnostics_Layer.h"
13 | #include "../SAE_J1939-71_Application_Layer/Application_Layer.h"
14 |
15 | /*
16 | * Store the sequence data packages from other ECU
17 | * PGN: 0x00EB00 (60160)
18 | */
19 | void SAE_J1939_Read_Transport_Protocol_Data_Transfer(J1939 *j1939, uint8_t SA, uint8_t data[]) {
20 | /* Save the sequence data */
21 | j1939->from_other_ecu_tp_dt.sequence_number = data[0];
22 | j1939->from_other_ecu_tp_dt.from_ecu_address = SA;
23 | uint8_t i, j, index = data[0] - 1;
24 | for (i = 1; i < 8; i++){
25 | j1939->from_other_ecu_tp_dt.data[index*7 + i-1] = data[i]; /* For every package, we send 7 bytes of data where the first byte data[0] is the sequence number */
26 | }
27 | /* Check if we have completed our message - Return = Not completed */
28 | if (j1939->from_other_ecu_tp_cm.number_of_packages_being_transmitted != j1939->from_other_ecu_tp_dt.sequence_number || j1939->from_other_ecu_tp_cm.number_of_packages_being_transmitted == 0){
29 | if (j1939->from_other_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_RTS) {
30 | /* Send new CTS */
31 | j1939->this_ecu_tp_cm.control_byte = CONTROL_BYTE_TP_CM_CTS;
32 | j1939->this_ecu_tp_cm.next_packet_number_transmitted++;
33 | SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, SA);
34 | }
35 | return;
36 | }
37 |
38 | /* Our message are complete - Build it and call it complete_data[total_message_size] */
39 | uint32_t PGN = j1939->from_other_ecu_tp_cm.PGN_of_the_packeted_message;
40 | uint16_t total_message_size = j1939->from_other_ecu_tp_cm.total_message_size_being_transmitted;
41 | uint8_t complete_data[MAX_TP_DT];
42 | uint16_t inserted_bytes = 0;
43 | for (i = 0; i < j1939->from_other_ecu_tp_dt.sequence_number; i++){
44 | for (j = 0; j < 7; j++){
45 | if (inserted_bytes < total_message_size){
46 | complete_data[inserted_bytes++] = j1939->from_other_ecu_tp_dt.data[i*7 + j];
47 | }
48 | }
49 | }
50 |
51 | /* Send an end of message ACK back */
52 | if(j1939->from_other_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_RTS){
53 | j1939->this_ecu_tp_cm.control_byte = CONTROL_BYTE_TP_CM_EndOfMsgACK;
54 | j1939->this_ecu_tp_cm.total_number_of_bytes_received = j1939->from_other_ecu_tp_cm.total_message_size_being_transmitted;
55 | j1939->this_ecu_tp_cm.total_number_of_packages_received = j1939->from_other_ecu_tp_dt.sequence_number;
56 | SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, SA);
57 | }
58 | /* Check what type of function that message want this ECU to do */
59 | switch (PGN) {
60 | case PGN_COMMANDED_ADDRESS:
61 | SAE_J1939_Read_Commanded_Address(j1939, complete_data); /* Insert new name and new address to this ECU */
62 | break;
63 | case PGN_DM1:
64 | SAE_J1939_Read_Response_Request_DM1(j1939, SA, complete_data, (total_message_size-2)/4); /* Number of DTCs = 4 bytes per DTC excluding 2 bytes for the lamp */
65 | break;
66 | case PGN_DM2:
67 | SAE_J1939_Read_Response_Request_DM2(j1939, SA, complete_data, (total_message_size-2)/4); /* Number of DTCs = 4 bytes per DTC excluding 2 bytes for the lamp */
68 | break;
69 | case PGN_DM16:
70 | SAE_J1939_Read_Binary_Data_Transfer_DM16(j1939, SA, complete_data);
71 | break;
72 | case PGN_SOFTWARE_IDENTIFICATION:
73 | SAE_J1939_Read_Response_Request_Software_Identification(j1939, SA, complete_data);
74 | break;
75 | case PGN_ECU_IDENTIFICATION:
76 | SAE_J1939_Read_Response_Request_ECU_Identification(j1939, SA, complete_data);
77 | break;
78 | case PGN_COMPONENT_IDENTIFICATION:
79 | SAE_J1939_Read_Response_Request_Component_Identification(j1939, SA, complete_data);
80 | break;
81 | case PGN_PROPRIETARY_A:
82 | SAE_J1939_Read_Response_Request_Proprietary_A(j1939, SA, complete_data);
83 | break;
84 | /* Add more here */
85 | default:
86 | if (((PGN >= PGN_PROPRIETARY_B_START) && (PGN <= PGN_PROPRIETARY_B_END)) ||
87 | ((PGN >= PGN_PROPRIETARY_B2_START) && (PGN <= PGN_PROPRIETARY_B2_END))) {
88 | SAE_J1939_Read_Response_Request_Proprietary_B(j1939, SA, PGN, complete_data);
89 | }
90 | break;
91 | }
92 |
93 | /* Delete TP DT and TP CM */
94 | memset(&j1939->from_other_ecu_tp_dt, 0, sizeof(j1939->from_other_ecu_tp_dt));
95 | memset(&j1939->from_other_ecu_tp_cm, 0, sizeof(j1939->from_other_ecu_tp_cm));
96 | }
97 |
98 | /*
99 | * Send sequence data packages to other ECU that we have loaded
100 | * PGN: 0x00EB00 (60160)
101 | */
102 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Transport_Protocol_Data_Transfer(J1939 *j1939, uint8_t DA){
103 | uint32_t ID = (0x1CEB << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
104 | uint8_t i, j, package[8];
105 | uint16_t bytes_sent = 0;
106 | ENUM_J1939_STATUS_CODES status = STATUS_SEND_OK;
107 | switch (j1939->from_other_ecu_tp_cm.control_byte) {
108 | case CONTROL_BYTE_TP_CM_BAM:
109 | for (i = 1; i <= j1939->this_ecu_tp_cm.number_of_packages_being_transmitted; i++) {
110 | package[0] = i; /* Number of package */
111 | for (j = 0; j < 7; j++) {
112 | if (bytes_sent < j1939->this_ecu_tp_cm.total_message_size_being_transmitted) {
113 | package[j + 1] = j1939->this_ecu_tp_dt.data[bytes_sent++]; /* Data that we have collected */
114 | }
115 | else {
116 | package[j + 1] = 0xFF; /* Reserved */
117 | }
118 | }
119 |
120 | /* Transmitt message */
121 | status = CAN_Send_Message(ID, package);
122 | CAN_Delay(100); /* Important CAN delay according to standard */
123 | if (status != STATUS_SEND_OK) {
124 | break;
125 | }
126 | }
127 | break;
128 | case CONTROL_BYTE_TP_CM_CTS:
129 | package[0] = j1939->from_other_ecu_tp_cm.next_packet_number_transmitted; /* Next number of package */
130 | bytes_sent = (j1939->from_other_ecu_tp_cm.next_packet_number_transmitted -1) * 7;
131 | for (j = 0; j < 7; j++) {
132 | if (bytes_sent < j1939->this_ecu_tp_cm.total_message_size_being_transmitted) {
133 | package[j + 1] = j1939->this_ecu_tp_dt.data[bytes_sent++]; /* Data that we have collected */
134 | }
135 | else {
136 | package[j + 1] = 0xFF; /* Reserved */
137 | }
138 | }
139 |
140 | /* Transmitt message */
141 | status = CAN_Send_Message(ID, package);
142 | break;
143 | }
144 |
145 | return status;
146 | }
147 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-71_Application_Layer/Application_Layer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Application_Layer.h
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_71_APPLICATION_LAYER_SAE_J1939_71_APPLICATION_LAYER_H_
9 | #define SAE_J1939_71_APPLICATION_LAYER_SAE_J1939_71_APPLICATION_LAYER_H_
10 |
11 | /* Enums and structs */
12 | #include "../../Open_SAE_J1939/Structs.h"
13 | #include "../SAE_J1939_Enums/Enum_Control_Byte.h"
14 | #include "../SAE_J1939_Enums/Enum_DM1_DM2.h"
15 | #include "../SAE_J1939_Enums/Enum_DM14_DM15.h"
16 | #include "../SAE_J1939_Enums/Enum_Group_Function_Value.h"
17 | #include "../SAE_J1939_Enums/Enum_NAME.h"
18 | #include "../SAE_J1939_Enums/Enum_PGN.h"
19 | #include "../SAE_J1939_Enums/Enum_Send_Status.h"
20 |
21 | #ifdef __cplusplus
22 | extern "C" {
23 | #endif
24 |
25 | /* Software identification */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Software_Identification(J1939 *j1939, uint8_t DA);
27 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Software_Identification(J1939* j1939, uint8_t DA);
28 | void SAE_J1939_Read_Response_Request_Software_Identification(J1939 *j1939, uint8_t SA, uint8_t data[]);
29 |
30 | /* ECU identification */
31 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_ECU_Identification(J1939 *j1939, uint8_t DA);
32 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_ECU_Identification(J1939* j1939, uint8_t DA);
33 | void SAE_J1939_Read_Response_Request_ECU_Identification(J1939 *j1939, uint8_t SA, uint8_t data[]);
34 |
35 | /* Component identification */
36 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Component_Identification(J1939 *j1939, uint8_t DA);
37 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Component_Identification(J1939* j1939, uint8_t DA);
38 | void SAE_J1939_Read_Response_Request_Component_Identification(J1939 *j1939, uint8_t SA, uint8_t data[]);
39 |
40 | /* Proprietary A */
41 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Proprietary_A(J1939* j1939, uint8_t DA);
42 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Proprietary_A(J1939* j1939, uint8_t DA);
43 | void SAE_J1939_Read_Response_Request_Proprietary_A(J1939* j1939, uint8_t SA, uint8_t data[]);
44 |
45 | /* Proprietary B */
46 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Proprietary_B(J1939* j1939, uint8_t DA, uint32_t PGN);
47 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Proprietary_B(J1939* j1939, uint8_t DA, uint32_t PGN, bool * is_supported);
48 | void SAE_J1939_Read_Response_Request_Proprietary_B(J1939* j1939, uint8_t SA, uint32_t PGN, uint8_t data[]);
49 | struct Proprietary_B * Get_Proprietary_B_By_PGN(struct Proprietary * proprietary, uint32_t PGN);
50 |
51 | #ifdef __cplusplus
52 | }
53 | #endif
54 |
55 | #endif /* SAE_J1939_71_APPLICATION_LAYER_SAE_J1939_71_APPLICATION_LAYER_H_ */
56 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-71_Application_Layer/Request_Component_Identification.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Request_Component_Identification.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request component identification to another ECU
16 | * PGN: 0x00FEEB (65259)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Component_Identification(J1939 *j1939, uint8_t DA) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_COMPONENT_IDENTIFICATION);
20 | }
21 |
22 | /*
23 | * Response the request of the component identification about this ECU
24 | * PGN: 0x00FEEB (65259)
25 | */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Component_Identification(J1939* j1939, uint8_t DA){
27 | /* Find the length of the array fields */
28 | uint8_t length_of_each_field = j1939->information_this_ECU.this_identifications.component_identification.length_of_each_field;
29 | if (length_of_each_field < 2) {
30 | /* If each field have the length 1, then we can send component identification as it was a normal message */
31 | uint32_t ID = (0x18FEEB << 8) | j1939->information_this_ECU.this_ECU_address;
32 | uint8_t data[8];
33 | data[0] = j1939->information_this_ECU.this_identifications.component_identification.component_product_date[0];
34 | data[1] = j1939->information_this_ECU.this_identifications.component_identification.component_model_name[0];
35 | data[2] = j1939->information_this_ECU.this_identifications.component_identification.component_serial_number[0];
36 | data[3] = j1939->information_this_ECU.this_identifications.component_identification.component_unit_name[0];
37 | data[4] = 0xFF; /* Reserved */
38 | data[5] = 0xFF; /* Reserved */
39 | data[6] = 0xFF; /* Reserved */
40 | data[7] = 0xFF; /* Reserved */
41 | return CAN_Send_Message(ID, data);
42 | } else {
43 | /* Multiple messages - Load data */
44 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = 0;
45 | uint8_t i;
46 | for(i = 0; i < length_of_each_field; i++) {
47 | j1939->this_ecu_tp_dt.data[i] = j1939->information_this_ECU.this_identifications.component_identification.component_product_date[i];
48 | j1939->this_ecu_tp_dt.data[length_of_each_field + i] = j1939->information_this_ECU.this_identifications.component_identification.component_model_name[i];
49 | j1939->this_ecu_tp_dt.data[length_of_each_field*2 + i] = j1939->information_this_ECU.this_identifications.component_identification.component_serial_number[i];
50 | j1939->this_ecu_tp_dt.data[length_of_each_field*3 + i] = j1939->information_this_ECU.this_identifications.component_identification.component_unit_name[i];
51 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted += 4;
52 | }
53 |
54 | /* Send TP CM */
55 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = SAE_J1939_Transport_Protocol_GetNumberOfPackages(j1939->this_ecu_tp_cm.total_message_size_being_transmitted);
56 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_COMPONENT_IDENTIFICATION;
57 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
58 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
59 | if(status != STATUS_SEND_OK){
60 | return status;
61 | }
62 |
63 | /* Check if we are going to send it directly (BAM) */
64 | if(j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM){
65 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
66 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
67 | }
68 | return status;
69 | }
70 | }
71 |
72 | /*
73 | * Store the component identification about other ECU
74 | * PGN: 0x00FEEB (65259)
75 | */
76 | void SAE_J1939_Read_Response_Request_Component_Identification(J1939 *j1939, uint8_t SA, uint8_t data[]) {
77 | /* Component identification have 4 fixed fields in the J1939 struct */
78 | uint8_t i, length_of_each_field = j1939->from_other_ecu_identifications.component_identification.length_of_each_field;
79 | for(i = 0; i < length_of_each_field; i++) {
80 | j1939->from_other_ecu_identifications.component_identification.component_product_date[i] = data[i];
81 | j1939->from_other_ecu_identifications.component_identification.component_model_name[i] = data[i + length_of_each_field];
82 | j1939->from_other_ecu_identifications.component_identification.component_serial_number[i] = data[i + length_of_each_field*2];
83 | j1939->from_other_ecu_identifications.component_identification.component_unit_name[i] = data[i + length_of_each_field*3];
84 | }
85 | j1939->from_other_ecu_identifications.component_identification.from_ecu_address = SA;
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-71_Application_Layer/Request_ECU_Identification.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Request_ECU_Identification.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request ECU identification to another ECU
16 | * PGN: 0x00FDC5 (64965)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_ECU_Identification(J1939 *j1939, uint8_t DA) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_ECU_IDENTIFICATION);
20 | }
21 |
22 | /*
23 | * Response the request of the ECU identification about this ECU
24 | * PGN: 0x00FDC5 (64965)
25 | */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_ECU_Identification(J1939* j1939, uint8_t DA) {
27 | /* Find the length of the array fields */
28 | uint8_t length_of_each_field = j1939->information_this_ECU.this_identifications.ecu_identification.length_of_each_field;
29 | if (length_of_each_field < 2) {
30 | /* If each field have the length 1, then we can send ECU identification as it was a normal message */
31 | uint32_t ID = (0x18FDC5 << 8) | j1939->information_this_ECU.this_ECU_address;
32 | uint8_t data[8];
33 | data[0] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_part_number[0];
34 | data[1] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_serial_number[0];
35 | data[2] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_location[0];
36 | data[3] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_type[0];
37 | data[4] = 0xFF; /* Reserved */
38 | data[5] = 0xFF; /* Reserved */
39 | data[6] = 0xFF; /* Reserved */
40 | data[7] = 0xFF; /* Reserved */
41 | return CAN_Send_Message(ID, data);
42 | } else {
43 | /* Multiple messages - Load data */
44 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = 0;
45 | uint8_t i;
46 | for(i = 0; i < length_of_each_field; i++) {
47 | j1939->this_ecu_tp_dt.data[i] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_part_number[i];
48 | j1939->this_ecu_tp_dt.data[length_of_each_field + i] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_serial_number[i];
49 | j1939->this_ecu_tp_dt.data[length_of_each_field*2 + i] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_location[i];
50 | j1939->this_ecu_tp_dt.data[length_of_each_field*3 + i] = j1939->information_this_ECU.this_identifications.ecu_identification.ecu_type[i];
51 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted += 4;
52 | }
53 |
54 | /* Send TP CM */
55 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = SAE_J1939_Transport_Protocol_GetNumberOfPackages(j1939->this_ecu_tp_cm.total_message_size_being_transmitted);
56 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_ECU_IDENTIFICATION;
57 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
58 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
59 | if(status != STATUS_SEND_OK){
60 | return status;
61 | }
62 |
63 | /* Check if we are going to send it directly (BAM) */
64 | if(j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM){
65 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
66 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
67 | }
68 | return status;
69 | }
70 | }
71 |
72 | /*
73 | * Store the ECU identification about other ECU
74 | * PGN: 0x00FDC5 (64965)
75 | */
76 | void SAE_J1939_Read_Response_Request_ECU_Identification(J1939 *j1939, uint8_t SA, uint8_t data[]) {
77 | /* ECU identification have 6 fixed fields in the J1939 struct */
78 | uint8_t i, length_of_each_field = j1939->from_other_ecu_identifications.ecu_identification.length_of_each_field;
79 | for(i = 0; i < length_of_each_field; i++) {
80 | j1939->from_other_ecu_identifications.ecu_identification.ecu_part_number[i] = data[i];
81 | j1939->from_other_ecu_identifications.ecu_identification.ecu_serial_number[i] = data[i + length_of_each_field];
82 | j1939->from_other_ecu_identifications.ecu_identification.ecu_location[i] = data[i + length_of_each_field*2];
83 | j1939->from_other_ecu_identifications.ecu_identification.ecu_type[i] = data[i + length_of_each_field*3];
84 | }
85 | j1939->from_other_ecu_identifications.ecu_identification.from_ecu_address = SA;
86 | }
87 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-71_Application_Layer/Request_Proprietary.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Request_Proprietary.c
3 | *
4 | * Created on: 25 December 2023
5 | * Author: Daniel M�rtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request Proprietary A to another ECU
16 | * PGN: 0x00EF00 (61184)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Proprietary_A(J1939* j1939, uint8_t DA) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_PROPRIETARY_A);
20 | }
21 |
22 | /*
23 | * Response the request Proprietary A about this ECU
24 | * PGN: 0x00EF00 (61184)
25 | */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Proprietary_A(J1939* j1939, uint8_t DA) {
27 | /* Find the length of the array fields */
28 | uint16_t length_of_each_field = j1939->this_proprietary.proprietary_A.total_bytes;
29 | if (length_of_each_field < 9) {
30 | /* If each field have the length 8 or less, then we can send Proprietary A as it was a normal message */
31 | uint32_t ID = (0x14EF23 << 8) | j1939->information_this_ECU.this_ECU_address;
32 | uint8_t data[8];
33 | memcpy(data, j1939->this_proprietary.proprietary_A.data, length_of_each_field);
34 | return CAN_Send_Message(ID, data);
35 | }
36 | else {
37 | /* Multiple messages - Load data */
38 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = length_of_each_field;
39 | memcpy(j1939->this_ecu_tp_dt.data, j1939->this_proprietary.proprietary_A.data, length_of_each_field);
40 |
41 | /* Send TP CM */
42 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = SAE_J1939_Transport_Protocol_GetNumberOfPackages(j1939->this_ecu_tp_cm.total_message_size_being_transmitted);
43 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_PROPRIETARY_A;
44 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
45 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
46 | if (status != STATUS_SEND_OK) {
47 | return status;
48 | }
49 |
50 | /* Check if we are going to send it directly (BAM) */
51 | if (j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM) {
52 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
53 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
54 | }
55 | return status;
56 | }
57 | }
58 |
59 | /*
60 | * Store the Proprietary A about other ECU
61 | * PGN: 0x00EF00 (61184)
62 | */
63 | void SAE_J1939_Read_Response_Request_Proprietary_A(J1939* j1939, uint8_t SA, uint8_t data[]) {
64 | /* Proprietary A have 1 fixed field in the J1939 struct */
65 | uint16_t total_bytes = j1939->from_other_ecu_proprietary.proprietary_A.total_bytes;
66 | memcpy(j1939->from_other_ecu_proprietary.proprietary_A.data, data, total_bytes);
67 | j1939->from_other_ecu_proprietary.proprietary_A.from_ecu_address = SA;
68 | }
69 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-71_Application_Layer/Request_Proprietary_B.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Request_Proprietary_B.c
3 | *
4 | * Created on: 3 November 2024
5 | * Author: Guillermo Rodríguez
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request Proprietary B to another ECU
16 | * PGN: 0x00FF00 <-> 0x00FFFF
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Proprietary_B(J1939* j1939, uint8_t DA, uint32_t PGN) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN);
20 | }
21 |
22 | // IMPORTANT: This function can return NULL if given PGN is not expected in this ECU
23 | struct Proprietary_B * Get_Proprietary_B_By_PGN(struct Proprietary * proprietary, uint32_t PGN)
24 | {
25 | for (int i = 0; i < MAX_PROPRIETARY_B_PGNS; ++i)
26 | {
27 | if (proprietary->proprietary_B[i].pgn == PGN)
28 | {
29 | return &proprietary->proprietary_B[i];
30 | }
31 | }
32 | return NULL;
33 | }
34 |
35 | /*
36 | * Response the request Proprietary B about this ECU
37 | * PGN: 0x00FF00 <-> 0x00FFFF
38 | */
39 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Proprietary_B(J1939* j1939, uint8_t DA, uint32_t PGN, bool * is_supported) {
40 | struct Proprietary_B * proprietary_B = Get_Proprietary_B_By_PGN(&j1939->this_proprietary, PGN);
41 | if (proprietary_B == NULL) /* This PGN is not implemented on this ECU, can't send reply */
42 | {
43 | *is_supported = false;
44 | return STATUS_SEND_ERROR;
45 | }
46 | *is_supported = true;
47 |
48 | /* Find the length of the array fields */
49 | uint16_t length_of_each_field = proprietary_B->total_bytes;
50 | if (length_of_each_field < 9) {
51 | /* If each field have the length 8 or less, then we can send Proprietary B as it was a normal message */
52 | uint32_t ID = (PGN << 8) | j1939->information_this_ECU.this_ECU_address;
53 | uint8_t data[8];
54 | memcpy(data, proprietary_B->data, length_of_each_field);
55 | return CAN_Send_Message(ID, data);
56 | }
57 | else {
58 | /* Multiple messages - Load data */
59 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = length_of_each_field;
60 | memcpy(j1939->this_ecu_tp_dt.data, proprietary_B->data, length_of_each_field);
61 |
62 | /* Send TP CM */
63 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = SAE_J1939_Transport_Protocol_GetNumberOfPackages(j1939->this_ecu_tp_cm.total_message_size_being_transmitted);
64 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN;
65 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
66 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
67 | if (status != STATUS_SEND_OK) {
68 | return status;
69 | }
70 |
71 | /* Check if we are going to send it directly (BAM) */
72 | if (j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM) {
73 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
74 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
75 | }
76 | return status;
77 | }
78 | }
79 |
80 | /*
81 | * Store the Proprietary B about other ECU
82 | * PGN: 0x00FF00 <-> 0x00FFFF
83 | */
84 | void SAE_J1939_Read_Response_Request_Proprietary_B(J1939* j1939, uint8_t SA, uint32_t PGN, uint8_t data[]) {
85 | struct Proprietary_B * proprietary_B = Get_Proprietary_B_By_PGN(&j1939->from_other_ecu_proprietary, PGN);
86 |
87 | if (proprietary_B == NULL) /* Proprietary B is not expected, don't fill the data anywhere */
88 | {
89 | return;
90 | }
91 |
92 | uint16_t total_bytes = proprietary_B->total_bytes;
93 | memcpy(proprietary_B->data, data, total_bytes);
94 | proprietary_B->from_ecu_address = SA;
95 | }
96 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-71_Application_Layer/Request_Software_Identification.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Request_Software_Identification.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Application_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Send request software identification to another ECU
16 | * PGN: 0x00FEDA (65242)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Software_Identification(J1939 *j1939, uint8_t DA) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_SOFTWARE_IDENTIFICATION);
20 | }
21 |
22 | /*
23 | * Response the request of the software identification about this ECU
24 | * PGN: 0x00FEDA (65242)
25 | */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Software_Identification(J1939* j1939, uint8_t DA) {
27 | uint8_t i, number_of_fields = j1939->information_this_ECU.this_identifications.software_identification.number_of_fields;
28 | if (number_of_fields < 9) {
29 | uint32_t ID = (0x18FEDA << 8) | j1939->information_this_ECU.this_ECU_address;
30 | uint8_t data[8];
31 | data[0] = number_of_fields;
32 | for(i = 0; i < 7; i++){
33 | data[i+1] = j1939->information_this_ECU.this_identifications.software_identification.identifications[i];
34 | }
35 | return CAN_Send_Message(ID, data);
36 | } else {
37 | /* Multiple messages - Load data */
38 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = 0;
39 | j1939->this_ecu_tp_dt.data[j1939->this_ecu_tp_cm.total_message_size_being_transmitted++] = number_of_fields;
40 | for(i = 0; i < number_of_fields; i++){
41 | j1939->this_ecu_tp_dt.data[j1939->this_ecu_tp_cm.total_message_size_being_transmitted++] = j1939->information_this_ECU.this_identifications.software_identification.identifications[i];
42 | }
43 | /* Send TP CM */
44 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = SAE_J1939_Transport_Protocol_GetNumberOfPackages(j1939->this_ecu_tp_cm.total_message_size_being_transmitted);
45 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_SOFTWARE_IDENTIFICATION;
46 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
47 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
48 | if(status != STATUS_SEND_OK){
49 | return status;
50 | }
51 |
52 | /* Check if we are going to send it directly (BAM) */
53 | if(j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM){
54 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
55 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
56 | }
57 | return status;
58 | }
59 | }
60 |
61 | /*
62 | * Store the software identification about other ECU
63 | * PGN: 0x00FEDA (65242)
64 | */
65 | void SAE_J1939_Read_Response_Request_Software_Identification(J1939 *j1939, uint8_t SA, uint8_t data[]) {
66 | j1939->from_other_ecu_identifications.software_identification.number_of_fields = data[0]; /* How many fields we have */
67 | j1939->from_other_ecu_identifications.software_identification.from_ecu_address = SA;
68 | uint8_t i;
69 | for(i = 0; i < data[0]; i++){
70 | j1939->from_other_ecu_identifications.software_identification.identifications[i] = data[i+1]; /* 1 for the number of fields */
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-73_Diagnostics_Layer/DM1.c:
--------------------------------------------------------------------------------
1 | /*
2 | * DM1.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Diagnostics_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request DM1 from another ECU
16 | * PGN: 0x00FECA (65226)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM1(J1939 *j1939, uint8_t DA) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_DM1);
20 | }
21 |
22 | /*
23 | * Response the request of DM1 information to other ECU about this ECU
24 | * PGN: 0x00FECA (65226)
25 | */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_DM1(J1939* j1939, uint8_t DA) {
27 | if(j1939->this_dm.errors_dm1_active < 2) {
28 | uint32_t ID = (0x18FECA << 8) | j1939->information_this_ECU.this_ECU_address;
29 | uint8_t data[8];
30 | data[0] = (j1939->this_dm.dm1.SAE_lamp_status_malfunction_indicator << 6) | (j1939->this_dm.dm1.SAE_lamp_status_red_stop << 4) | (j1939->this_dm.dm1.SAE_lamp_status_amber_warning << 2) | (j1939->this_dm.dm1.SAE_lamp_status_protect_lamp);
31 | data[1] = (j1939->this_dm.dm1.SAE_flash_lamp_malfunction_indicator << 6) | (j1939->this_dm.dm1.SAE_flash_lamp_red_stop << 4) | (j1939->this_dm.dm1.SAE_flash_lamp_amber_warning << 2) | (j1939->this_dm.dm1.SAE_flash_lamp_protect_lamp);
32 | data[2] = j1939->this_dm.dm1.SPN[0];
33 | data[3] = j1939->this_dm.dm1.SPN[0] >> 8;
34 | data[4] = ((j1939->this_dm.dm1.SPN[0] >> 11) & 0b11100000) | j1939->this_dm.dm1.FMI[0];
35 | data[5] = (j1939->this_dm.dm1.SPN_conversion_method[0] << 7) | j1939->this_dm.dm1.occurrence_count[0];
36 | data[6] = 0xFF; /* Reserved */
37 | data[7] = 0xFF; /* Reserved */
38 | return CAN_Send_Message(ID, data);
39 | } else {
40 | /* Multiple messages - Load data */
41 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = (j1939->this_dm.errors_dm1_active *4) +2 ; /* set total message size where each DTC is 4 btyes, plus 2 bytes for the lamp code */
42 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = SAE_J1939_Transport_Protocol_GetNumberOfPackages(j1939->this_ecu_tp_cm.total_message_size_being_transmitted);
43 |
44 | /* Load lamp data to first two bytes */
45 | j1939->this_ecu_tp_dt.data[0] = (j1939->this_dm.dm1.SAE_lamp_status_malfunction_indicator << 6) | (j1939->this_dm.dm1.SAE_lamp_status_red_stop << 4) | (j1939->this_dm.dm1.SAE_lamp_status_amber_warning << 2) | (j1939->this_dm.dm1.SAE_lamp_status_protect_lamp);
46 | j1939->this_ecu_tp_dt.data[1] = (j1939->this_dm.dm1.SAE_flash_lamp_malfunction_indicator << 6) | (j1939->this_dm.dm1.SAE_flash_lamp_red_stop << 4) | (j1939->this_dm.dm1.SAE_flash_lamp_amber_warning << 2) | (j1939->this_dm.dm1.SAE_flash_lamp_protect_lamp);
47 | /* Load DTCs into TP data package */
48 | uint8_t i;
49 | for (i = 0; i < j1939->this_ecu_tp_cm.total_message_size_being_transmitted; i++){
50 | j1939->this_ecu_tp_dt.data[i*4 + 2] = j1939->this_dm.dm1.SPN[i];
51 | j1939->this_ecu_tp_dt.data[i*4 + 3] = j1939->this_dm.dm1.SPN[i] >> 8;
52 | j1939->this_ecu_tp_dt.data[i*4 + 4] = ((j1939->this_dm.dm1.SPN[i] >> 11) & 0b11100000) | j1939->this_dm.dm1.FMI[i];
53 | j1939->this_ecu_tp_dt.data[i*4 + 5] = (j1939->this_dm.dm1.SPN_conversion_method[i] << 7) | j1939->this_dm.dm1.occurrence_count[i];
54 | }
55 |
56 | /* Send TP CM */
57 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_DM1;
58 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
59 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
60 | if(status != STATUS_SEND_OK){
61 | return status;
62 | }
63 |
64 | /* Check if we are going to send it directly (BAM) */
65 | if(j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM){
66 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
67 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
68 | }
69 | return status;
70 | }
71 | }
72 |
73 | /*
74 | * Store the last DM1 information about other ECU. At least we know how many errors are active
75 | * PGN: 0x00FECA (65226)
76 | */
77 | void SAE_J1939_Read_Response_Request_DM1(J1939 *j1939, uint8_t SA, uint8_t data[], uint8_t errors_dm1_active) {
78 | /* If there are fewer active DTCs than previous, clear the list so old DTCs do not remain after parsing the new ones*/
79 | if (errors_dm1_active < j1939->from_other_ecu_dm.errors_dm1_active) {
80 | memset(&j1939->from_other_ecu_dm.dm1.SPN, 0, sizeof(j1939->from_other_ecu_dm.dm1.SPN)); /* This set all fields of dm1 to 0 */
81 | }
82 |
83 | /* Decode lamp status */
84 | j1939->from_other_ecu_dm.dm1.SAE_lamp_status_malfunction_indicator = data[0] >> 6;
85 | j1939->from_other_ecu_dm.dm1.SAE_lamp_status_red_stop = (data[0] >> 4) & 0b00000011;
86 | j1939->from_other_ecu_dm.dm1.SAE_lamp_status_amber_warning = (data[0] >> 2) & 0b00000011;
87 | j1939->from_other_ecu_dm.dm1.SAE_lamp_status_protect_lamp = data[0] & 0b00000011;
88 | j1939->from_other_ecu_dm.dm1.SAE_flash_lamp_malfunction_indicator = data[1] >> 6;
89 | j1939->from_other_ecu_dm.dm1.SAE_flash_lamp_red_stop = (data[1] >> 4) & 0b00000011;
90 | j1939->from_other_ecu_dm.dm1.SAE_flash_lamp_amber_warning = (data[1] >> 2) & 0b00000011;
91 | j1939->from_other_ecu_dm.dm1.SAE_flash_lamp_protect_lamp = data[1] & 0b00000011;
92 |
93 | /* Read and Decode DTC info for up to MAX_DM_FIELD active DTCs */
94 | uint8_t i;
95 | for (i = 0; i < errors_dm1_active && i < MAX_DM_FIELD; i++){
96 | j1939->from_other_ecu_dm.dm1.SPN[i] = ((data[(i*4)+4] & 0b11100000) << 11) | (data[(i*4)+3] << 8) | data[(i*4)+2];
97 | j1939->from_other_ecu_dm.dm1.FMI[i] = data[(i*4)+4] & 0b00011111;
98 | j1939->from_other_ecu_dm.dm1.SPN_conversion_method[i] = data[(i*4)+5] >> 7;
99 | j1939->from_other_ecu_dm.dm1.occurrence_count[i] = data[(i*4)+5] & 0b01111111;
100 | j1939->from_other_ecu_dm.dm1.from_ecu_address[i] = SA;
101 | }
102 |
103 | /* Check if we have no fault cause
104 | * When there is a single DM1 code, and the SPN is 0, this signals all DM1 messages have cleared and no active messages are left */
105 | if (errors_dm1_active == 1 && j1939->from_other_ecu_dm.dm1.SPN[0] == 0) {
106 | j1939->from_other_ecu_dm.errors_dm1_active = 0;
107 | } else if (j1939->from_other_ecu_dm.errors_dm1_active < errors_dm1_active) {
108 | j1939->from_other_ecu_dm.errors_dm1_active = errors_dm1_active;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-73_Diagnostics_Layer/DM14.c:
--------------------------------------------------------------------------------
1 | /*
2 | * DM14.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Diagnostics_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request DM14 from another ECU
16 | * PGN: 0x00D900 (55552)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM14(J1939 *j1939, uint8_t DA, uint16_t number_of_requested_bytes, uint8_t pointer_type, uint8_t command, uint32_t pointer, uint8_t pointer_extension, uint16_t key) {
19 | uint32_t ID = (0x18D9 << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
20 | uint8_t data[8];
21 | data[0] = number_of_requested_bytes;
22 | data[1] = ((number_of_requested_bytes >> 3)&0xE0) | (pointer_type << 4) | (command << 1) | 0b1;
23 | data[2] = pointer;
24 | data[3] = pointer >> 8;
25 | data[4] = pointer >> 16;
26 | data[5] = pointer_extension;
27 | data[6] = key;
28 | data[7] = key >> 8;
29 | return CAN_Send_Message(ID, data);
30 | }
31 |
32 | /*
33 | * Read the request of DM14 memory request to other ECU about this ECU
34 | * PGN: 0x00D900 (55552)
35 | */
36 | ENUM_J1939_STATUS_CODES SAE_J1939_Read_Request_DM14(J1939 *j1939, uint8_t DA, uint8_t data[]) {
37 | /* These are information the ECU want to have */
38 | uint16_t number_of_requested_bytes = ((data[1] & 0b11100000) << 3) | data[0];
39 | uint8_t pointer_type = (data[1] >> 4) & 0b0001;
40 | uint8_t command = (data[1] >> 1) & 0b0000111;
41 | uint32_t pointer = (data[4] << 16) | (data[3] << 8) | data[2];
42 | uint8_t pointer_extension = data[5];
43 | uint16_t key = (data[7] << 8) | data[6];
44 |
45 | /* Load up the amount of bytes we want to send via DM16 */
46 | uint8_t raw_binary_data[MAX_TP_DT];
47 |
48 | /* Here we ask the flash, eeprom or ram and use pointers */
49 | FLASH_EEPROM_RAM_Memory(&number_of_requested_bytes, pointer_type, &command, &pointer, &pointer_extension, &key, raw_binary_data);
50 |
51 | /* Prepare a DM15 PGN: 0x00D800 response back to DA */
52 | uint16_t number_of_allowed_bytes = number_of_requested_bytes;
53 | uint8_t status = command;
54 | uint32_t EDC_parameter = pointer;
55 | uint8_t EDCP_extention = pointer_extension;
56 | uint16_t seed = key;
57 | status = SAE_J1939_Send_Response_DM15(j1939, DA, number_of_allowed_bytes, status, EDC_parameter, EDCP_extention, seed);
58 |
59 | /* Check if our message was OK - Send DM16 binary data transfer */
60 | if(status == STATUS_DM15_PROCEED) {
61 | if(SAE_J1939_Send_Binary_Data_Transfer_DM16(j1939, DA, number_of_allowed_bytes, raw_binary_data) == STATUS_SEND_OK){
62 | status = SAE_J1939_Send_Response_DM15(j1939, DA, number_of_allowed_bytes, STATUS_DM15_OPERATION_COMPLETED, EDC_parameter, EDCP_extention, seed);
63 | }else{
64 | status = SAE_J1939_Send_Response_DM15(j1939, DA, number_of_allowed_bytes, STATUS_DM15_OPERATION_FAILED, EDC_parameter, EDCP_extention, seed);
65 | }
66 | }
67 | return status;
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-73_Diagnostics_Layer/DM15.c:
--------------------------------------------------------------------------------
1 | /*
2 | * DM15.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Diagnostics_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Send a memory response. This will be sent after a DM14 memory request
16 | * PGN: 0x00D800 (55296)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Response_DM15(J1939 *j1939, uint8_t DA, uint16_t number_of_allowed_bytes, uint8_t status, uint32_t EDC_parameter, uint8_t EDCP_extention, uint16_t seed) {
19 | uint32_t ID = (0x18D8 << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
20 | uint8_t response_data[8];
21 | response_data[0] = number_of_allowed_bytes;
22 | response_data[1] = ((number_of_allowed_bytes >> 3)&0xE0) | (0b1 << 4) | (status << 1) | 0b1; /* bit 5 and 1 are reserved */
23 | response_data[2] = EDC_parameter;
24 | response_data[3] = EDC_parameter >> 8;
25 | response_data[4] = EDC_parameter >> 16;
26 | response_data[5] = EDCP_extention;
27 | response_data[6] = seed;
28 | response_data[7] = seed >> 8;
29 | return CAN_Send_Message(ID, response_data);
30 | }
31 |
32 | /*
33 | * Store the DM15 information about other ECU (This is actually the response after DM14 request according to J1939 standard)
34 | * PGN: 0x00D800 (55296)
35 | */
36 | void SAE_J1939_Read_Response_DM15(J1939 *j1939, uint8_t SA, uint8_t data[]) {
37 | j1939->from_other_ecu_dm.dm15.number_of_allowed_bytes = ((data[1] & 0b11100000) << 3) | data[0];
38 | j1939->from_other_ecu_dm.dm15.status = (data[1] >> 1) & 0b0000111;
39 | j1939->from_other_ecu_dm.dm15.EDC_parameter = (data[4] << 16) | (data[3] << 8) | data[2];
40 | j1939->from_other_ecu_dm.dm15.EDCP_extention = data[5];
41 | j1939->from_other_ecu_dm.dm15.seed = (data[7] << 8) | data[6];
42 | j1939->from_other_ecu_dm.dm15.from_ecu_address = SA;
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-73_Diagnostics_Layer/DM16.c:
--------------------------------------------------------------------------------
1 | /*
2 | * DM16.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Diagnostics_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Send binary data transfer. This will be sent after DM15 memory response (if DM15 was proceeded)
16 | * PGN: 0x00D700 (55040)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Binary_Data_Transfer_DM16(J1939 *j1939, uint8_t DA, uint8_t number_of_occurences, uint8_t raw_binary_data[]) {
19 | if(number_of_occurences < 8) {
20 | uint32_t ID = (0x18D7 << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
21 | uint8_t data[7 + 1]; /* number_of_occurences must be 7 */
22 | data[0] = number_of_occurences; /* How much binary data we want to send */
23 | uint8_t i;
24 | for(i = 0; i < number_of_occurences; i++){
25 | data[i+1] = raw_binary_data[i];
26 | }
27 | return CAN_Send_Message(ID, data);
28 | }else{
29 | /* Multiple messages - Load data */
30 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = 0;
31 | j1939->this_ecu_tp_dt.data[j1939->this_ecu_tp_cm.total_message_size_being_transmitted++] = number_of_occurences;
32 | uint8_t i;
33 | for(i = 0; i < number_of_occurences; i++){
34 | j1939->this_ecu_tp_dt.data[j1939->this_ecu_tp_cm.total_message_size_being_transmitted++] = raw_binary_data[i]; /* When i = 0, then total_message_size = 1 */
35 | }
36 | /* Send TP CM */
37 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = SAE_J1939_Transport_Protocol_GetNumberOfPackages(j1939->this_ecu_tp_cm.total_message_size_being_transmitted);
38 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_DM16;
39 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
40 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
41 | if(status != STATUS_SEND_OK){
42 | return status;
43 | }
44 |
45 | /* Check if we are going to send it directly (BAM) */
46 | if(j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM){
47 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
48 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
49 | }
50 | return status;
51 | }
52 | }
53 |
54 |
55 | /*
56 | * Read binary data transfer
57 | * PGN: 0x00D700 (55040)
58 | */
59 | void SAE_J1939_Read_Binary_Data_Transfer_DM16(J1939 *j1939, uint8_t SA, uint8_t data[]) {
60 | j1939->from_other_ecu_dm.dm16.number_of_occurences = data[0];
61 | j1939->from_other_ecu_dm.dm16.from_ecu_address = SA;
62 | memset(j1939->from_other_ecu_dm.dm16.raw_binary_data, 0, sizeof(j1939->from_other_ecu_dm.dm16.raw_binary_data));
63 | uint8_t i;
64 | for(i = 0; i < data[0]; i++){
65 | j1939->from_other_ecu_dm.dm16.raw_binary_data[i] = data[i+1];
66 | }
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-73_Diagnostics_Layer/DM2.c:
--------------------------------------------------------------------------------
1 | /*
2 | * DM2.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Diagnostics_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Request DM2 from another ECU
16 | * PGN: 0x00FECB (65227)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM2(J1939 *j1939, uint8_t DA) {
19 | return SAE_J1939_Send_Request(j1939, DA, PGN_DM2);
20 | }
21 |
22 | /*
23 | * Response the request of DM2 information to other ECU about this ECU
24 | * PGN: 0x00FECB (65227)
25 | */
26 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_DM2(J1939 *j1939, uint8_t DA) {
27 | if(j1939->this_dm.errors_dm2_active < 2) {
28 | uint32_t ID = (0x18FECB << 8) | j1939->information_this_ECU.this_ECU_address;
29 | uint8_t data[8];
30 | data[0] = (j1939->this_dm.dm2.SAE_lamp_status_malfunction_indicator << 6) | (j1939->this_dm.dm2.SAE_lamp_status_red_stop << 4) | (j1939->this_dm.dm2.SAE_lamp_status_amber_warning << 2) | (j1939->this_dm.dm2.SAE_lamp_status_protect_lamp);
31 | data[1] = (j1939->this_dm.dm2.SAE_flash_lamp_malfunction_indicator << 6) | (j1939->this_dm.dm2.SAE_flash_lamp_red_stop << 4) | (j1939->this_dm.dm2.SAE_flash_lamp_amber_warning << 2) | (j1939->this_dm.dm2.SAE_flash_lamp_protect_lamp);
32 | data[2] = j1939->this_dm.dm2.SPN[0];
33 | data[3] = j1939->this_dm.dm2.SPN[0] >> 8;
34 | data[4] = ((j1939->this_dm.dm2.SPN[0] >> 11) & 0b11100000) | j1939->this_dm.dm2.FMI[0];
35 | data[5] = (j1939->this_dm.dm2.SPN_conversion_method[0] << 7) | j1939->this_dm.dm2.occurrence_count[0];
36 | data[6] = 0xFF; /* Reserved */
37 | data[7] = 0xFF; /* Reserved */
38 | return CAN_Send_Message(ID, data);
39 | } else {
40 | /* Multiple messages - Load data */
41 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = (j1939->this_dm.errors_dm2_active *4) +2 ; /* set total message size where each DTC is 4 btyes, plus 2 bytes for the lamp code */
42 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = (j1939->this_ecu_tp_cm.total_message_size_being_transmitted)/7; /* set number of packages, where each package will transmit up to 7 bytes */
43 | if (j1939->this_ecu_tp_cm.total_message_size_being_transmitted % 7 > 0) {
44 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted++; /* add extra frame if data rolls over */
45 | }
46 |
47 | /* Load lamp data to first two bytes */
48 | j1939->this_ecu_tp_dt.data[0] = (j1939->this_dm.dm2.SAE_lamp_status_malfunction_indicator << 6) | (j1939->this_dm.dm2.SAE_lamp_status_red_stop << 4) | (j1939->this_dm.dm2.SAE_lamp_status_amber_warning << 2) | (j1939->this_dm.dm2.SAE_lamp_status_protect_lamp);
49 | j1939->this_ecu_tp_dt.data[1] = (j1939->this_dm.dm2.SAE_flash_lamp_malfunction_indicator << 6) | (j1939->this_dm.dm2.SAE_flash_lamp_red_stop << 4) | (j1939->this_dm.dm2.SAE_flash_lamp_amber_warning << 2) | (j1939->this_dm.dm2.SAE_flash_lamp_protect_lamp);
50 | /* Load DTCs into TP data package */
51 | uint8_t i;
52 | for (i = 0; i < j1939->this_ecu_tp_cm.total_message_size_being_transmitted; i++){
53 | j1939->this_ecu_tp_dt.data[i*4 + 2] = j1939->this_dm.dm2.SPN[i];
54 | j1939->this_ecu_tp_dt.data[i*4 + 3] = j1939->this_dm.dm2.SPN[i] >> 8;
55 | j1939->this_ecu_tp_dt.data[i*4 + 4] = ((j1939->this_dm.dm2.SPN[i] >> 11) & 0b11100000) | j1939->this_dm.dm2.FMI[i];
56 | j1939->this_ecu_tp_dt.data[i*4 + 5] = (j1939->this_dm.dm2.SPN_conversion_method[i] << 7) | j1939->this_dm.dm2.occurrence_count[i];
57 | }
58 |
59 | /* Send TP CM */
60 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_DM2;
61 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
62 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
63 | if(status != STATUS_SEND_OK){
64 | return status;
65 | }
66 |
67 | /* Check if we are going to send it directly (BAM) */
68 | if(j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM){
69 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
70 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
71 | }
72 | return status;
73 | }
74 | }
75 |
76 | /*
77 | * Store the last DM2 information about other ECU. At least we know how many errors are active
78 | * PGN: 0x00FECB (65227)
79 | */
80 | void SAE_J1939_Read_Response_Request_DM2(J1939 *j1939, uint8_t SA, uint8_t data[], uint8_t errors_dm2_active) {
81 | /* If there are fewer active DTCs than previous, clear the list so old DTCs do not remain after parsing the new ones */
82 | if (errors_dm2_active < j1939->from_other_ecu_dm.errors_dm2_active) {
83 | memset(&j1939->from_other_ecu_dm.dm2.SPN, 0, sizeof(j1939->from_other_ecu_dm.dm2.SPN)); /* This set all fields of dm1 to 0 */
84 | }
85 |
86 | /* Decode lamp status */
87 | j1939->from_other_ecu_dm.dm2.SAE_lamp_status_malfunction_indicator = data[0] >> 6;
88 | j1939->from_other_ecu_dm.dm2.SAE_lamp_status_red_stop = (data[0] >> 4) & 0b00000011;
89 | j1939->from_other_ecu_dm.dm2.SAE_lamp_status_amber_warning = (data[0] >> 2) & 0b00000011;
90 | j1939->from_other_ecu_dm.dm2.SAE_lamp_status_protect_lamp = data[0] & 0b00000011;
91 | j1939->from_other_ecu_dm.dm2.SAE_flash_lamp_malfunction_indicator = data[1] >> 6;
92 | j1939->from_other_ecu_dm.dm2.SAE_flash_lamp_red_stop = (data[1] >> 4) & 0b00000011;
93 | j1939->from_other_ecu_dm.dm2.SAE_flash_lamp_amber_warning = (data[1] >> 2) & 0b00000011;
94 | j1939->from_other_ecu_dm.dm2.SAE_flash_lamp_protect_lamp = data[1] & 0b00000011;
95 |
96 | /* Read and Decode DTC info for up to MAX_DM_FIELD previously active DTCs */
97 | uint8_t i;
98 | for (i = 0; i < errors_dm2_active && i < MAX_DM_FIELD; i++){
99 | j1939->from_other_ecu_dm.dm2.SPN[i] = ((data[(i*4)+4] & 0b11100000) << 11) | (data[(i*4)+3] << 8) | data[(i*4)+2];
100 | j1939->from_other_ecu_dm.dm2.FMI[i] = data[(i*4)+4] & 0b00011111;
101 | j1939->from_other_ecu_dm.dm2.SPN_conversion_method[i] = data[(i*4)+5] >> 7;
102 | j1939->from_other_ecu_dm.dm2.occurrence_count[i] = data[(i*4)+5] & 0b01111111;
103 | j1939->from_other_ecu_dm.dm2.from_ecu_address[i] = SA;
104 | }
105 |
106 | /* Assign number of DTCs in previously active list */
107 | if (errors_dm2_active == 1 && j1939->from_other_ecu_dm.dm2.SPN[0] == 0) {
108 | j1939->from_other_ecu_dm.errors_dm2_active = 0;
109 | } else if (j1939->from_other_ecu_dm.errors_dm2_active < errors_dm2_active) {
110 | j1939->from_other_ecu_dm.errors_dm2_active = errors_dm2_active;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-73_Diagnostics_Layer/DM3.c:
--------------------------------------------------------------------------------
1 | /*
2 | * DM3.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Diagnostics_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 |
13 | /*
14 | * Request DM3 from another ECU
15 | * PGN: 0x00FECC (65228)
16 | */
17 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM3(J1939 *j1939, uint8_t DA) {
18 | return SAE_J1939_Send_Request(j1939, DA, PGN_DM3);
19 | }
20 |
21 | /*
22 | * Response the request of DM3 (clear DM2, which is previously active errors from DM1 codes) to other ECU about this ECU
23 | * PGN: 0x00FECC (65228)
24 | */
25 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_DM3(J1939* j1939, uint8_t DA) {
26 | memset(&j1939->this_dm.dm2, 0, sizeof(j1939->this_dm.dm2)); /* This set all fields of dm2 to 0 */
27 | j1939->this_dm.errors_dm2_active = 0;
28 | /* Removed assigning FMI to 31. Fixed DMx active message count to not rely on this value*/
29 | return SAE_J1939_Response_Request_DM2(j1939, DA); /* Send DM2 codes to the ECU who send the request */
30 | }
31 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-73_Diagnostics_Layer/Diagnostics_Layer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Diagnostics_Layer.h
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_73_DIAGNOSTICS_LAYER_SAE_J1939_73_DIAGNOSTICS_LAYER_H_
9 | #define SAE_J1939_73_DIAGNOSTICS_LAYER_SAE_J1939_73_DIAGNOSTICS_LAYER_H_
10 |
11 | /* The C standard library */
12 | #include
13 |
14 | /* Enums and structs */
15 | #include "../../Open_SAE_J1939/Structs.h"
16 | #include "../SAE_J1939_Enums/Enum_Control_Byte.h"
17 | #include "../SAE_J1939_Enums/Enum_DM1_DM2.h"
18 | #include "../SAE_J1939_Enums/Enum_DM14_DM15.h"
19 | #include "../SAE_J1939_Enums/Enum_Group_Function_Value.h"
20 | #include "../SAE_J1939_Enums/Enum_NAME.h"
21 | #include "../SAE_J1939_Enums/Enum_PGN.h"
22 | #include "../SAE_J1939_Enums/Enum_Send_Status.h"
23 |
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 | /* DM1 */
29 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM1(J1939 *j1939, uint8_t DA);
30 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_DM1(J1939* j1939, uint8_t DA);
31 | void SAE_J1939_Read_Response_Request_DM1(J1939 *j1939, uint8_t SA, uint8_t data[], uint8_t errors_dm1_active);
32 |
33 | /* DM2 */
34 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM2(J1939 *j1939, uint8_t DA);
35 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_DM2(J1939 *j1939, uint8_t DA);
36 | void SAE_J1939_Read_Response_Request_DM2(J1939 *j1939, uint8_t SA, uint8_t data[], uint8_t errors_dm1_active);
37 |
38 | /* DM3 */
39 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM3(J1939 *j1939, uint8_t DA);
40 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_DM3(J1939 *j1939, uint8_t DA);
41 |
42 | /* DM14 */
43 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_DM14(J1939 *j1939, uint8_t DA, uint16_t number_of_requested_bytes, uint8_t pointer_type, uint8_t command, uint32_t pointer, uint8_t pointer_extension, uint16_t key);
44 | ENUM_J1939_STATUS_CODES SAE_J1939_Read_Request_DM14(J1939 *j1939, uint8_t DA, uint8_t data[]);
45 |
46 | /* DM15 */
47 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Response_DM15(J1939 *j1939, uint8_t DA, uint16_t number_of_allowed_bytes, uint8_t status, uint32_t EDC_parameter, uint8_t EDCP_extention, uint16_t seed);
48 | void SAE_J1939_Read_Response_DM15(J1939 *j1939, uint8_t SA, uint8_t data[]);
49 |
50 | /* DM16 */
51 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Binary_Data_Transfer_DM16(J1939 *j1939, uint8_t DA, const uint8_t number_of_occurences, uint8_t raw_binary_data[]);
52 | void SAE_J1939_Read_Binary_Data_Transfer_DM16(J1939 *j1939, uint8_t SA, uint8_t data[]);
53 |
54 | #ifdef __cplusplus
55 | }
56 | #endif
57 |
58 | #endif /* SAE_J1939_73_DIAGNOSTICS_LAYER_SAE_J1939_73_DIAGNOSTICS_LAYER_H_ */
59 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-81_Network_Management_Layer/Address_Claimed.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Address_Claimed.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Network_Management_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Send request address claimed to other ECU. Every time we asking addresses from other ECU, then we clear our storage of other ECU
16 | * PGN: 0x00EE00 (60928)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Address_Claimed(J1939 *j1939, uint8_t DA) {
19 | /* Delete all addresses by setting them to broadcast address and set the counters to 0 */
20 | memset(j1939->other_ECU_address, 0xFF, 0xFF);
21 | j1939->number_of_cannot_claim_address = 0;
22 | j1939->number_of_other_ECU = 0;
23 | return SAE_J1939_Send_Request(j1939, DA, PGN_ADDRESS_CLAIMED);
24 | }
25 |
26 | /*
27 | * Response the request address claimed about this ECU to all ECU - Broadcast. This function must be called at the ECU start up according to J1939 standard
28 | * PGN: 0x00EE00 (60928)
29 | */
30 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Address_Claimed(J1939 *j1939) {
31 | uint32_t ID = (0x18EEFF << 8) | j1939->information_this_ECU.this_ECU_address;
32 | uint8_t data[8];
33 | data[0] = j1939->information_this_ECU.this_name.identity_number;
34 | data[1] = j1939->information_this_ECU.this_name.identity_number >> 8;
35 | data[2] = (j1939->information_this_ECU.this_name.identity_number >> 16) | (j1939->information_this_ECU.this_name.manufacturer_code << 5);
36 | data[3] = j1939->information_this_ECU.this_name.manufacturer_code >> 3;
37 | data[4] = (j1939->information_this_ECU.this_name.function_instance << 3) | j1939->information_this_ECU.this_name.ECU_instance;
38 | data[5] = j1939->information_this_ECU.this_name.function;
39 | data[6] = j1939->information_this_ECU.this_name.vehicle_system << 1;
40 | data[7] = (j1939->information_this_ECU.this_name.arbitrary_address_capable << 7) | (j1939->information_this_ECU.this_name.industry_group << 4) | j1939->information_this_ECU.this_name.vehicle_system_instance;
41 | return CAN_Send_Message(ID, data);
42 | }
43 |
44 | /*
45 | * Store the address claimed information about other ECU
46 | * PGN: 0x00EE00 (60928)
47 | */
48 | void SAE_J1939_Read_Response_Request_Address_Claimed(J1939 *j1939, uint8_t SA, uint8_t data[]) {
49 | /* Check if it's the same address */
50 | if(j1939->information_this_ECU.this_ECU_address == SA){
51 | SAE_J1939_Send_Address_Not_Claimed(j1939);
52 | }
53 |
54 | /* If not, then store the temporary information */
55 | j1939->from_other_ecu_name.identity_number = ((data[2] & 0b00011111) << 16) | (data[1] << 8) | data[0];
56 | j1939->from_other_ecu_name.manufacturer_code = (data[3] << 3) | (data[2] >> 5);
57 | j1939->from_other_ecu_name.function_instance = data[4] >> 3;
58 | j1939->from_other_ecu_name.ECU_instance = data[4] & 0b00000111;
59 | j1939->from_other_ecu_name.function = data[5];
60 | j1939->from_other_ecu_name.vehicle_system = data[6] >> 1;
61 | j1939->from_other_ecu_name.arbitrary_address_capable = data[7] >> 7;
62 | j1939->from_other_ecu_name.industry_group = (data[7] >> 4) & 0b0111;
63 | j1939->from_other_ecu_name.vehicle_system_instance = data[7] & 0b00001111;
64 | j1939->from_other_ecu_name.from_ecu_address = SA;
65 | /* Remember the source address of the ECU */
66 | bool exist = false;
67 | uint8_t i;
68 | for (i = 0; i < j1939->number_of_other_ECU; i++){
69 | if (j1939->other_ECU_address[i] == SA){
70 | exist = true;
71 | }
72 | }
73 | if (!exist){
74 | j1939->other_ECU_address[j1939->number_of_other_ECU++] = SA; /* For every new ECU address, count how many ECU */
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-81_Network_Management_Layer/Address_Delete.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Address_Delete.c
3 | *
4 | * Created on: 20 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Network_Management_Layer.h"
9 |
10 | /* Layers */
11 | #include "../../Hardware/Hardware.h"
12 |
13 | /*
14 | * This is not a SAE J1939 standard. It's only for deleting the j1939->ECU_address
15 | * PGN: 0x000002 (2)
16 | */
17 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Address_Delete(J1939 *j1939, uint8_t DA, uint8_t old_ECU_address) {
18 | /* Delete other ECU address in this ECU */
19 | uint8_t i;
20 | for(i = 0; i < j1939->number_of_other_ECU; i++){
21 | if(old_ECU_address == j1939->other_ECU_address[i]){
22 | j1939->other_ECU_address[i] = 0xFF;
23 | j1939->number_of_other_ECU--;
24 | }
25 | }
26 |
27 | /* Send delete command to other ECU - Spread the news that the old_ECU_address is not used any more */
28 | uint32_t ID = (0x0002 << 16) | (DA << 8) | j1939->information_this_ECU.this_ECU_address;
29 | uint8_t data[8];
30 | data[0] = old_ECU_address;
31 | data[1] = data[2] = data[3] = data[4] = data[5] = data[6] = data[7] = 0xFF; /*Reserved */
32 | return CAN_Send_Message(ID, data);
33 | }
34 |
35 | /*
36 | * This is not a SAE J1939 standard. It's only for deleting the j1939->ECU_address
37 | * PGN: 0x000002 (2)
38 | */
39 | void SAE_J1939_Read_Address_Delete(J1939 *j1939, uint8_t data[]) {
40 | /* Delete other ECU address in this ECU */
41 | uint8_t i, old_ECU_address = data[0];
42 | for(i = 0; i < j1939->number_of_other_ECU; i++){
43 | if(old_ECU_address == j1939->other_ECU_address[i]){
44 | j1939->other_ECU_address[i] = 0xFF;
45 | j1939->number_of_other_ECU--;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-81_Network_Management_Layer/Address_Not_Claimed.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Address_Not_Claimed.c
3 | *
4 | * Created on: 19 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Network_Management_Layer.h"
9 |
10 | /* Layers */
11 | #include "../../Hardware/Hardware.h"
12 |
13 | /*
14 | * Send Address Not Claimed if the address conflicts with each other
15 | * PGN: 0x00EE00 (60928)
16 | */
17 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Address_Not_Claimed(J1939 *j1939) {
18 | uint32_t ID = 0x18EEFFFE;
19 | uint8_t data[8];
20 | data[0] = j1939->information_this_ECU.this_name.identity_number;
21 | data[1] = j1939->information_this_ECU.this_name.identity_number >> 8;
22 | data[2] = (j1939->information_this_ECU.this_name.identity_number >> 16) | (j1939->information_this_ECU.this_name.manufacturer_code << 5);
23 | data[3] = j1939->information_this_ECU.this_name.manufacturer_code >> 3;
24 | data[4] = (j1939->information_this_ECU.this_name.function_instance << 3) | j1939->information_this_ECU.this_name.ECU_instance;
25 | data[5] = j1939->information_this_ECU.this_name.function;
26 | data[6] = j1939->information_this_ECU.this_name.vehicle_system << 1;
27 | data[7] = (j1939->information_this_ECU.this_name.arbitrary_address_capable << 7) | (j1939->information_this_ECU.this_name.industry_group << 4) | j1939->information_this_ECU.this_name.vehicle_system_instance;
28 | return CAN_Send_Message(ID, data);
29 | }
30 |
31 | /*
32 | * Store the address not claimed information about other ECU. In this case, SA will always be 0xFE = 254
33 | * PGN: 0x00EE00 (60928)
34 | */
35 | void SAE_J1939_Read_Address_Not_Claimed(J1939 *j1939, uint8_t SA, uint8_t data[]) {
36 | j1939->from_other_ecu_name.identity_number = ((data[2] & 0b00011111) << 16) | (data[1] << 8) | data[0];
37 | j1939->from_other_ecu_name.manufacturer_code = (data[3] << 3) | (data[2] >> 5);
38 | j1939->from_other_ecu_name.function_instance = data[4] >> 3;
39 | j1939->from_other_ecu_name.ECU_instance = data[4] & 0b00000111;
40 | j1939->from_other_ecu_name.function = data[5];
41 | j1939->from_other_ecu_name.vehicle_system = data[6] >> 1;
42 | j1939->from_other_ecu_name.arbitrary_address_capable = data[7] >> 7;
43 | j1939->from_other_ecu_name.industry_group = (data[7] >> 4) & 0b0111;
44 | j1939->from_other_ecu_name.vehicle_system_instance = data[7] & 0b00001111;
45 | j1939->from_other_ecu_name.from_ecu_address = SA;
46 | j1939->number_of_cannot_claim_address++;
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-81_Network_Management_Layer/Commanded_Address.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Commanded_Address.c
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #include "Network_Management_Layer.h"
9 |
10 | /* Layers */
11 | #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h"
12 | #include "../../Hardware/Hardware.h"
13 |
14 | /*
15 | * Send commanded address to another ECU
16 | * PGN: 0x00FED8 (65240)
17 | */
18 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Commanded_Address(J1939 *j1939, uint8_t DA, uint8_t new_ECU_address, uint32_t identity_number, uint16_t manufacturer_code, uint8_t function_instance, uint8_t ECU_instance, uint8_t function, uint8_t vehicle_system, uint8_t arbitrary_address_capable, uint8_t industry_group, uint8_t vehicle_system_instance) {
19 | /* Multiple messages - Load data */
20 | j1939->this_ecu_tp_cm.number_of_packages_being_transmitted = 2;
21 | j1939->this_ecu_tp_cm.total_message_size_being_transmitted = 9;
22 | j1939->this_ecu_tp_dt.data[0] = identity_number;
23 | j1939->this_ecu_tp_dt.data[1] = identity_number >> 8;
24 | j1939->this_ecu_tp_dt.data[2] = (identity_number >> 16) | (manufacturer_code << 5);
25 | j1939->this_ecu_tp_dt.data[3] = manufacturer_code >> 3;
26 | j1939->this_ecu_tp_dt.data[4] = (function_instance << 3) | ECU_instance;
27 | j1939->this_ecu_tp_dt.data[5] = function;
28 | j1939->this_ecu_tp_dt.data[6] = vehicle_system << 1;
29 | j1939->this_ecu_tp_dt.data[7] = (arbitrary_address_capable << 7) | (industry_group << 4) | vehicle_system_instance;
30 | j1939->this_ecu_tp_dt.data[8] = new_ECU_address; /* New address of the ECU we are sending to*/
31 |
32 | /* Send TP CM */
33 | j1939->this_ecu_tp_cm.PGN_of_the_packeted_message = PGN_COMMANDED_ADDRESS;
34 | j1939->this_ecu_tp_cm.control_byte = DA == 0xFF ? CONTROL_BYTE_TP_CM_BAM : CONTROL_BYTE_TP_CM_RTS; /* If broadcast, then use BAM control byte */
35 | ENUM_J1939_STATUS_CODES status = SAE_J1939_Send_Transport_Protocol_Connection_Management(j1939, DA);
36 | if(status != STATUS_SEND_OK){
37 | return status;
38 | }
39 |
40 | /* Check if we are going to send it directly (BAM) */
41 | if(j1939->this_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_BAM){
42 | j1939->from_other_ecu_tp_cm.control_byte = j1939->this_ecu_tp_cm.control_byte;
43 | return SAE_J1939_Send_Transport_Protocol_Data_Transfer(j1939, DA);
44 | }
45 | return status;
46 |
47 | }
48 |
49 | /*
50 | * Read the commanded address from another ECU. Will always be called from Transport Protocol Data Transfer due to 9 bytes of data
51 | * PGN: 0x00FED8 (65240)
52 | */
53 | void SAE_J1939_Read_Commanded_Address(J1939 *j1939, uint8_t data[]) {
54 | /* Send to all ECU that the current address is unused */
55 | SAE_J1939_Send_Address_Delete(j1939, 0xFF, j1939->information_this_ECU.this_ECU_address);
56 |
57 | /* Apply new NAME and address for this ECU */
58 | j1939->information_this_ECU.this_name.identity_number = ((data[2] & 0b00011111) << 16) | (data[1] << 8) | data[0];
59 | j1939->information_this_ECU.this_name.manufacturer_code = (data[3] << 3) | (data[2] >> 5);
60 | j1939->information_this_ECU.this_name.function_instance = data[4] >> 3;
61 | j1939->information_this_ECU.this_name.ECU_instance = data[4] & 0b00000111;
62 | j1939->information_this_ECU.this_name.function = data[5];
63 | j1939->information_this_ECU.this_name.vehicle_system = data[6] >> 1;
64 | j1939->information_this_ECU.this_name.arbitrary_address_capable = data[7] >> 7;
65 | j1939->information_this_ECU.this_name.industry_group = (data[7] >> 4) & 0b0111;
66 | j1939->information_this_ECU.this_name.vehicle_system_instance = data[7] & 0b00001111;
67 | j1939->information_this_ECU.this_ECU_address = data[8]; /* New address of this ECU */
68 | Save_Struct((uint8_t*)&j1939->information_this_ECU, sizeof(Information_this_ECU), INFORMATION_THIS_ECU);
69 |
70 | /* Broadcast the new NAME and address of this ECU */
71 | SAE_J1939_Response_Request_Address_Claimed(j1939);
72 | }
73 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939-81_Network_Management_Layer/Network_Management_Layer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Network_Management_Layer.h
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_81_NETWORK_MANAGEMENT_LAYER_SAE_J1939_81_NETWORK_MANAGEMENT_LAYER_H_
9 | #define SAE_J1939_81_NETWORK_MANAGEMENT_LAYER_SAE_J1939_81_NETWORK_MANAGEMENT_LAYER_H_
10 |
11 | /* The C standard library */
12 | #include
13 |
14 | /* Enums and structs */
15 | #include "../../Open_SAE_J1939/Structs.h"
16 | #include "../SAE_J1939_Enums/Enum_Control_Byte.h"
17 | #include "../SAE_J1939_Enums/Enum_DM1_DM2.h"
18 | #include "../SAE_J1939_Enums/Enum_DM14_DM15.h"
19 | #include "../SAE_J1939_Enums/Enum_Group_Function_Value.h"
20 | #include "../SAE_J1939_Enums/Enum_NAME.h"
21 | #include "../SAE_J1939_Enums/Enum_PGN.h"
22 | #include "../SAE_J1939_Enums/Enum_Send_Status.h"
23 |
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 | /* Address claimed */
29 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Request_Address_Claimed(J1939 *j1939, uint8_t DA);
30 | ENUM_J1939_STATUS_CODES SAE_J1939_Response_Request_Address_Claimed(J1939 *j1939);
31 | void SAE_J1939_Read_Response_Request_Address_Claimed(J1939 *j1939, uint8_t SA, uint8_t data[]);
32 |
33 | /* Address not claimed */
34 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Address_Not_Claimed(J1939 *j1939);
35 | void SAE_J1939_Read_Address_Not_Claimed(J1939 *j1939, uint8_t SA, uint8_t data[]);
36 |
37 | /* Commanded address */
38 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Commanded_Address(J1939 *j1939, uint8_t DA, uint8_t new_ECU_address, uint32_t identity_number, uint16_t manufacturer_code, uint8_t function_instance, uint8_t ECU_instance, uint8_t function, uint8_t vehicle_system, uint8_t arbitrary_address_capable, uint8_t industry_group, uint8_t vehicle_system_instance);
39 | void SAE_J1939_Read_Commanded_Address(J1939 *j1939, uint8_t data[]);
40 |
41 | /* Delete address */
42 | ENUM_J1939_STATUS_CODES SAE_J1939_Send_Address_Delete(J1939 *j1939, uint8_t DA, uint8_t old_ECU_address);
43 | void SAE_J1939_Read_Address_Delete(J1939 *j1939, uint8_t data[]);
44 |
45 | #ifdef __cplusplus
46 | }
47 | #endif
48 |
49 | #endif /* SAE_J1939_81_NETWORK_MANAGEMENT_LAYER_SAE_J1939_81_NETWORK_MANAGEMENT_LAYER_H_ */
50 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939_Enums/Enum_Control_Byte.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Enum_Control_Byte.h
3 | *
4 | * Created on: 14 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_SAE_J1939_ENUMS_SAE_J1939_ENUM_CONTROL_BYTE_H_
9 | #define SAE_J1939_SAE_J1939_ENUMS_SAE_J1939_ENUM_CONTROL_BYTE_H_
10 |
11 | /* Control bytes enums */
12 | typedef enum {
13 | CONTROL_BYTE_TP_CM_ABORT = 0xFFU,
14 | CONTROL_BYTE_TP_CM_BAM = 0x20U,
15 | CONTROL_BYTE_TP_CM_EndOfMsgACK = 0x13U,
16 | CONTROL_BYTE_TP_CM_CTS = 0x11U,
17 | CONTROL_BYTE_TP_CM_RTS = 0x10U,
18 | CONTROL_BYTE_ACKNOWLEDGEMENT_PGN_SUPPORTED = 0x0U,
19 | CONTROL_BYTE_ACKNOWLEDGEMENT_PGN_NOT_SUPPORTED = 0x1U,
20 | CONTROL_BYTE_ACKNOWLEDGEMENT_PGN_ACCESS_DENIED = 0x2U,
21 | CONTROL_BYTE_ACKNOWLEDGEMENT_PGN_BUSY = 0x3U
22 | /* Add more control bytes here */
23 | }ENUM_CONTROL_BYTES_CODES;
24 |
25 | #endif /* SAE_J1939_SAE_J1939_ENUMS_SAE_J1939_ENUM_CONTROL_BYTE_H_ */
26 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939_Enums/Enum_DM14_DM15.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Enum_DM14_DM15.h
3 | *
4 | * Created on: 8 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_ENUMS_SAE_J1939_ENUM_DM14_DM15_H_
9 | #define SAE_J1939_ENUMS_SAE_J1939_ENUM_DM14_DM15_H_
10 |
11 | /* DM14 and DM15 enums */
12 | typedef enum {
13 | /* Status */
14 | STATUS_DM15_PROCEED = 0x0U,
15 | STATUS_DM15_BUSY = 0x1U,
16 | STATUS_DM15_OPERATION_COMPLETED = 0x4U,
17 | STATUS_DM15_OPERATION_FAILED = 0x5U,
18 | /* EDCP extesion */
19 | EDCP_EXTENSION_ALL_EDC_PARAMETER_BEEN_SENT = 0x0U,
20 | EDCP_EXTENSION_CONCATENATE_FOLLOWING_DATA_HIGHER_ORDER = 0x2U,
21 | EDCP_EXTENSION_CONCATENATE_FOLLOWING_DATA_LOWER_ORDER = 0x3U,
22 | EDCP_EXTENSION_DATA_IN_EDC_PARAMETER_IS_ERROR_INDICATOR = 0x4U,
23 | EDCP_EXTENSION_DATA_IN_EDC_PARAMETER_IS_ERROR_INDICATOR_SEED_IS_TIME_TO_COMPLETE = 0x7U,
24 | EDCP_EXTENSION_NOT_USED = 0xFFU,
25 | /* EDC parameter */
26 | EDC_PARAMETER_PROCESSING_ERASE_REQUEST = 0x10U,
27 | EDC_PARAMETER_PROCESSING_READ_REQUEST = 0x11U,
28 | EDC_PARAMETER_PROCESSING_WRITE_REQUEST = 0x12U,
29 | EDC_PARAMETER_PROCESSING_STATUS_REQUEST = 0x13U,
30 | EDC_PARAMETER_PROCESSING_BOOT_LOAD_REQUEST = 0x16U,
31 | EDC_PARAMETER_NOT_VERIFY_RAM_WRITE = 0x21U,
32 | EDC_PARAMETER_NOT_VERIFY_FLASH_WRITE = 0x22U,
33 | EDC_PARAMETER_NOT_VERIFY_EEPROM_WRITE = 0x23U,
34 | EDC_PARAMETER_INVALID_KEY = 0x1003U,
35 | /* Seed */
36 | SEED_NO_MORE_KEYS_NEED_FOR_THE_PROCESS = 0x0U,
37 | SEED_USE_LONG_KEY = 0x1U,
38 | SEED_NO_KEY_USED = 0xFFFFU
39 | } ENUM_DM15_CODES;
40 |
41 | typedef enum {
42 | /* Command */
43 | COMMAND_DM14_READ = 0x1U,
44 | COMMAND_DM14_WRITE = 0x2U,
45 | COMMAND_DM14_OPERATION_COMPLETED = 0x4U,
46 | COMMAND_DM14_OPERATION_FAILED = 0x5U,
47 | COMMAND_DM14_BOOT_LOAD = 0x6U,
48 | /* Pointer type */
49 | POINTER_TYPE_JOIN_POINTER_WITH_POINTER_EXTENSION = 0x0U,
50 | POINTER_TYPE_POINTER_EXTENSION_IS_A_COMMAND = 0x1U,
51 | /* Pointer extension */
52 | POINTER_EXTENSION_DM14_FLASH_ACCESS = 0x0U,
53 | POINTER_EXTENSION_DM14_EEPROM_ACCESS = 0x1U,
54 | POINTER_EXTENSION_DM14_VARIABLE_ACCESS = 0x2U,
55 | USER_KEY_LEVEL_DM14_NO_KEY_AVAILABLE = 0xFFFFU
56 | }ENUM_DM14_CODES;
57 |
58 | #endif /* SAE_J1939_ENUMS_SAE_J1939_ENUM_DM14_DM15_H_ */
59 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939_Enums/Enum_Group_Function_Value.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Enum_Group_Function_Value.h
3 | *
4 | * Created on: 15 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_ENUMS_SAE_J1939_ENUM_GROUP_FUNCTION_VALUE_H_
9 | #define SAE_J1939_ENUMS_SAE_J1939_ENUM_GROUP_FUNCTION_VALUE_H_
10 |
11 | /* Enums for the acknowledgements */
12 | typedef enum {
13 | GROUP_FUNCTION_VALUE_NORMAL = 0x0U,
14 | GROUP_FUNCTION_VALUE_CANNOT_MAINTAIN_ANOTHER_CONNECTION = 0x1U,
15 | GROUP_FUNCTION_VALUE_LACKING_NECESSARY_RESOURCES = 0x2U,
16 | GROUP_FUNCTION_VALUE_ABORT_TIME_OUT = 0x3U,
17 | GROUP_FUNCTION_VALUE_NO_CAUSE = 0xFFU
18 | } ENUM_GROUP_FUNCTION_VALUE_CODES;
19 |
20 | #endif /* SAE_J1939_ENUMS_SAE_J1939_ENUM_GROUP_FUNCTION_VALUE_H_ */
21 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939_Enums/Enum_NAME.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Enum_NAME.h
3 | *
4 | * Created on: 15 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_ENUMS_SAE_J1939_ENUM_NAME_H_
9 | #define SAE_J1939_ENUMS_SAE_J1939_ENUM_NAME_H_
10 |
11 | /* NAME fields enums */
12 | typedef enum {
13 | /* Manufacturer code */
14 | MANUFACTURER_CODE_SONCEBOZ = 0x147U,
15 | MANUFACTURER_CODE_GRAYHILL = 0x126U,
16 | /* Industry group */
17 | INDUSTRY_GROUP_GLOBAL = 0x0U,
18 | INDUSTRY_GROUP_ON_HIGHWAY = 0x1U,
19 | INDUSTRY_GROUP_AGRICULTURAL_AND_FORESTRY = 0x2U,
20 | INDUSTRY_GROUP_CONSTRUCTION = 0x3U,
21 | INDUSTRY_GROUP_MARINE = 0x4U,
22 | INDUSTRY_GROUP_INDUSTRIAL_CONTROL_PROCESS = 0x5U,
23 | INDUSTRY_GROUP_RESERVED_6 = 0x6U,
24 | INDUSTRY_GROUP_RESERVED_7 = 0x7U,
25 | /* Function */
26 | FUNCTION_AUXILIARY_VALVES_CONTROL= 0x81U,
27 | FUNCTION_VDC_MODULE = 0x87U,
28 | /* Select of of them if you want the ECU to take own decision to change its own ECU address */
29 | ARBITRARY_ADDRESS_CAPABLE_NOT_CAPABLE = 0x0U,
30 | ARBITRARY_ADDRESS_CAPABLE_CAPABLE = 0x1U
31 | /* Add more here */
32 | }ENUM_NAME_CODES;
33 |
34 | #endif /* SAE_J1939_ENUMS_SAE_J1939_ENUM_NAME_H_ */
35 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939_Enums/Enum_PGN.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Enum_PGN.h
3 | *
4 | * Created on: 9 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_ENUMS_SAE_J1939_ENUM_PGN_H_
9 | #define SAE_J1939_ENUMS_SAE_J1939_ENUM_PGN_H_
10 |
11 | /* PGN enums */
12 | typedef enum {
13 | PGN_ADDRESS_DELETE = 0x000002U, /* NOT SAE J1939 standard. If you find the correct PGN number, please do a pull request */
14 | PGN_REQUEST = 0x00EA00U,
15 | PGN_ACKNOWLEDGEMENT = 0x00E800U,
16 | PGN_TP_CM = 0x00EC00U,
17 | PGN_TP_DT = 0x00EB00U,
18 | PGN_ADDRESS_CLAIMED = 0x00EE00U,
19 | PGN_PROPRIETARY_A = 0x00EF00U,
20 | PGN_COMMANDED_ADDRESS = 0x00FED8U,
21 | PGN_DM1 = 0x00FECAU,
22 | PGN_DM2 = 0x00FECBU,
23 | PGN_DM3 = 0x00FECCU,
24 | PGN_DM14 = 0x00D900U,
25 | PGN_DM15 = 0x00D800U,
26 | PGN_DM16 = 0x00D700U,
27 | PGN_SOFTWARE_IDENTIFICATION = 0x00FEDAU,
28 | PGN_ECU_IDENTIFICATION = 0x00FDC5U,
29 | PGN_COMPONENT_IDENTIFICATION = 0x00FEEBU,
30 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_0 = 0x00FE10U,
31 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_1 = 0x00FE11U,
32 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_2 = 0x00FE12U,
33 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_3 = 0x00FE13U,
34 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_4 = 0x00FE14U,
35 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_5 = 0x00FE15U,
36 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_6 = 0x00FE16U,
37 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_7 = 0x00FE17U,
38 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_8 = 0x00FE18U,
39 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_9 = 0x00FE19U,
40 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_10 = 0x00FE1AU,
41 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_11 = 0x00FE1BU,
42 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_12 = 0x00FE1CU,
43 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_13 = 0x00FE1DU,
44 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_14 = 0x00FE1EU,
45 | PGN_AUXILIARY_VALVE_ESTIMATED_FLOW_15 = 0x00FE1FU,
46 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_0 = 0x00FF20U,
47 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_1 = 0x00FF21U,
48 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_2 = 0x00FF22U,
49 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_3 = 0x00FF23U,
50 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_4 = 0x00FF24U,
51 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_5 = 0x00FF25U,
52 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_6 = 0x00FF26U,
53 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_7 = 0x00FF27U,
54 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_8 = 0x00FF28U,
55 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_9 = 0x00FF29U,
56 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_10 = 0x00FF2AU,
57 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_11 = 0x00FF2BU,
58 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_12 = 0x00FF2CU,
59 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_13 = 0x00FF2DU,
60 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_14 = 0x00FF2EU,
61 | PGN_AUXILIARY_VALVE_MEASURED_POSITION_15 = 0x00FF2FU,
62 | PGN_AUXILIARY_VALVE_COMMAND_0 = 0x00FE30U,
63 | PGN_AUXILIARY_VALVE_COMMAND_1 = 0x00FE31U,
64 | PGN_AUXILIARY_VALVE_COMMAND_2 = 0x00FE32U,
65 | PGN_AUXILIARY_VALVE_COMMAND_3 = 0x00FE33U,
66 | PGN_AUXILIARY_VALVE_COMMAND_4 = 0x00FE34U,
67 | PGN_AUXILIARY_VALVE_COMMAND_5 = 0x00FE35U,
68 | PGN_AUXILIARY_VALVE_COMMAND_6 = 0x00FE36U,
69 | PGN_AUXILIARY_VALVE_COMMAND_7 = 0x00FE37U,
70 | PGN_AUXILIARY_VALVE_COMMAND_8 = 0x00FE38U,
71 | PGN_AUXILIARY_VALVE_COMMAND_9 = 0x00FE39U,
72 | PGN_AUXILIARY_VALVE_COMMAND_10 = 0x00FE3AU,
73 | PGN_AUXILIARY_VALVE_COMMAND_11 = 0x00FE3BU,
74 | PGN_AUXILIARY_VALVE_COMMAND_12 = 0x00FE3CU,
75 | PGN_AUXILIARY_VALVE_COMMAND_13 = 0x00FE3DU,
76 | PGN_AUXILIARY_VALVE_COMMAND_14 = 0x00FE3EU,
77 | PGN_AUXILIARY_VALVE_COMMAND_15 = 0x00FE3FU,
78 | PGN_GENERAL_PURPOSE_VALVE_ESTIMATED_FLOW = 0x00C600U,
79 | PGN_ENGINE_HOURS_65253 = 0x00FE3FU,
80 | PGN_ENGINE_TEMPERATURE_1_65262 = 0x00FEEEU,
81 | PGN_VEHICLE_ELECTRICAL_POWER_1_65271 = 0x00FEF7U,
82 | PGN_ELECTRONIC_ENGINE_CONTROLLER_1_61444 = 0x00F004U,
83 | PGN_COLD_START_AIDS_64966 = 0x00FDC6U,
84 | PGN_FUEL_CONSUMPTION_65257 = 0x00FEE9U,
85 | PGN_FUEL_ECONOMY_65266 = 0x00FEF2U,
86 | PGN_ENGINE_FLUIDS_LEVEL_PRESSURE_1_65263 = 0x00FEEFU,
87 | PGN_ELECTRONIC_ENGINE_CONTROLLER_2_61443 = 0x00F003U,
88 | PGN_AMBIENT_CONDITIONS_65269 = 0x00FEF5U,
89 | PGN_ENGINE_FUEL_LUBE_SYSTEMS_65130 = 0x00FE6AU,
90 | PGN_AUXILIARY_ANALOG_INFORMATION_65164 = 0x00FE8CU,
91 | PGN_AFTERTREATMENT_1_DEF_TANK_1_65110 = 0x00FE56U,
92 | PGN_SHUTDOWN_65252 = 0x00FEE4U,
93 | PGN_ELECTRONIC_ENGINE_CONTROLLER_3_65247 = 0x00FEDFU,
94 | PGN_ENGINE_FLUIDS_LEVEL_PRESSURE_12_64735 = 0x00FCDFU,
95 | PGN_INTAKE_MANIFOLD_INFO_1_65190 = 0x00FEA6U,
96 | PGN_DASH_DISPLAY_65276 = 0x00FEFCU,
97 | PGN_DIRECT_LAMP_CONTROL_COMMAND_1_64775 = 0x00FD07U,
98 | PGN_TORQUE_SPEED_CONTROL_1_0 = 0x000000U,
99 | PGN_ELECTRONIC_BRAKE_CONTROLLER_1_61441 = 0x00F001U,
100 | PGN_PROPRIETARY_B_START= 0x00FF00U,
101 | PGN_PROPRIETARY_B_END= 0x00FFFFU,
102 | // Same as proprietary B but with DP (data page = 1)
103 | PGN_PROPRIETARY_B2_START= 0x01FF00U, /* This range is not officially support by the standard */
104 | PGN_PROPRIETARY_B2_END= 0x01FFFFU /* but it is very commonly used, so it's supported here */
105 |
106 | /* Add more here */
107 | }ENUM_PGN_CODES;
108 |
109 | #endif /* SAE_J1939_ENUMS_SAE_J1939_ENUM_PGN_H_ */
110 |
--------------------------------------------------------------------------------
/Src/SAE_J1939/SAE_J1939_Enums/Enum_Send_Status.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Enum_Send_Status.h
3 | *
4 | * Created on: 15 juli 2021
5 | * Author: Daniel Mårtensson
6 | */
7 |
8 | #ifndef SAE_J1939_ENUMS_SAE_J1939_ENUM_SEND_STATUS_H_
9 | #define SAE_J1939_ENUMS_SAE_J1939_ENUM_SEND_STATUS_H_
10 |
11 | /* Send OK enum */
12 | typedef enum {
13 | STATUS_SEND_OK = 0x00U,
14 | STATUS_SEND_ERROR = 0x01U,
15 | STATUS_SEND_BUSY = 0x02U,
16 | STATUS_SEND_TIMEOUT = 0x03U
17 | } ENUM_J1939_STATUS_CODES;
18 |
19 | #endif /* SAE_J1939_ENUMS_SAE_J1939_ENUM_SEND_STATUS_H_ */
20 |
--------------------------------------------------------------------------------
/Src/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------