├── .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 | --------------------------------------------------------------------------------