├── .clang-format ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── CompilerChecks.cmake ├── ConfigureChecks.cmake ├── LICENSE-APACHE ├── README.md ├── cmake ├── Modules │ ├── AddCCompilerFlag.cmake │ ├── AddCMockaTest.cmake │ ├── COPYING-CMAKE-SCRIPTS │ ├── CheckCCompilerFlagSSP.cmake │ ├── DefineCMakeDefaults.cmake │ ├── DefineCompilerFlags.cmake │ ├── DefinePlatformDefaults.cmake │ ├── FindNSIS.cmake │ └── MacroEnsureOutOfSourceBuild.cmake ├── Toolchain-cross-arm-none-eabi.cmake └── tms570-toolchain.cmake ├── config.h.cmake ├── example ├── config-pcan0.sh ├── j1939_socketcan.c ├── j1939_tp_client.c ├── j1939_tp_server.c ├── linux_socketcan.c └── make-vcan0.sh ├── include └── j1939.h └── src ├── atomic.h ├── compat.h ├── compiler.h ├── hasht.c ├── hasht.h ├── j1939.c ├── j1939_ecu.c ├── j1939_time.h ├── pgn.h ├── pgn_pool.c ├── pgn_pool.h ├── session.h ├── sessions.c └── time.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | #AlignEscapedNewlines: Left # Unknown to clang-format-4.0 7 | AlignOperands: true 8 | AlignTrailingComments: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: None 13 | AllowShortIfStatementsOnASingleLine: false 14 | AllowShortLoopsOnASingleLine: false 15 | AlwaysBreakAfterDefinitionReturnType: None 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakBeforeMultilineStrings: false 18 | AlwaysBreakTemplateDeclarations: false 19 | BinPackArguments: true 20 | BinPackParameters: true 21 | BraceWrapping: 22 | AfterClass: false 23 | AfterControlStatement: false 24 | AfterEnum: false 25 | AfterFunction: true 26 | AfterNamespace: true 27 | AfterObjCDeclaration: false 28 | AfterStruct: false 29 | AfterUnion: false 30 | AfterExternBlock: false 31 | BeforeCatch: false 32 | BeforeElse: false 33 | IndentBraces: false 34 | SplitEmptyFunction: true 35 | SplitEmptyRecord: true 36 | #plitEmptyNamespace: true 37 | BreakBeforeBinaryOperators: None 38 | BreakBeforeBraces: Custom 39 | BreakBeforeInheritanceComma: false 40 | BreakBeforeTernaryOperators: false 41 | BreakConstructorInitializersBeforeComma: false 42 | BreakConstructorInitializers: BeforeComma 43 | BreakAfterJavaFieldAnnotations: false 44 | BreakStringLiterals: false 45 | ColumnLimit: 80 46 | CommentPragmas: '^ IWYU pragma:' 47 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 48 | ConstructorInitializerIndentWidth: 8 49 | ContinuationIndentWidth: 8 50 | Cpp11BracedListStyle: false 51 | DerivePointerAlignment: false 52 | DisableFormat: false 53 | ExperimentalAutoDetectBinPacking: false 54 | 55 | 56 | IncludeBlocks: Preserve 57 | IncludeCategories: 58 | - Regex: '.*' 59 | Priority: 1 60 | IncludeIsMainRegex: '(Test)?$' 61 | IndentCaseLabels: false 62 | IndentWidth: 8 63 | IndentWrappedFunctionNames: false 64 | JavaScriptQuotes: Leave 65 | JavaScriptWrapImports: true 66 | KeepEmptyLinesAtTheStartOfBlocks: false 67 | MacroBlockBegin: '' 68 | MacroBlockEnd: '' 69 | MaxEmptyLinesToKeep: 1 70 | NamespaceIndentation: Inner 71 | ObjCBinPackProtocolList: Auto 72 | ObjCBlockIndentWidth: 8 73 | ObjCSpaceAfterProperty: true 74 | ObjCSpaceBeforeProtocolList: true 75 | 76 | PenaltyBreakAssignment: 10 77 | PenaltyBreakBeforeFirstCallParameter: 30 78 | PenaltyBreakComment: 10 79 | PenaltyBreakFirstLessLess: 0 80 | PenaltyBreakString: 10 81 | PenaltyExcessCharacter: 100 82 | PenaltyReturnTypeOnItsOwnLine: 60 83 | 84 | PointerAlignment: Right 85 | ReflowComments: false 86 | SortIncludes: false 87 | SortUsingDeclarations: false 88 | SpaceAfterCStyleCast: false 89 | SpaceAfterTemplateKeyword: true 90 | SpaceBeforeAssignmentOperators: true 91 | SpaceBeforeParens: ControlStatements 92 | SpaceInEmptyParentheses: false 93 | SpacesBeforeTrailingComments: 1 94 | SpacesInAngles: false 95 | SpacesInContainerLiterals: false 96 | SpacesInCStyleCastParentheses: false 97 | SpacesInParentheses: false 98 | SpacesInSquareBrackets: false 99 | Standard: Cpp03 100 | TabWidth: 8 101 | UseTab: Always 102 | ... 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.elf 2 | *.o 3 | *.d 4 | *.map 5 | *.bin 6 | *.srec 7 | 8 | # IDE/Editor 9 | .vscode 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Code Coverage (GCOV) 15 | *.gcno 16 | *.gcda 17 | *.gcov 18 | 19 | # cmake build 20 | build/ 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | os: linux 3 | dist: bionic 4 | 5 | jobs: 6 | include: 7 | - os: linux 8 | compiler: "gcc-7" 9 | env: BUILD='Debug' CC=gcc-7 CXX=g++-7 OPT=-DLIBJ1939_BUILD_EXAMPLE=1 10 | dist: bionic 11 | addons: *gcc7 12 | 13 | - os: linux 14 | compiler: "gcc-7" 15 | env: BUILD='Release' CC=gcc-7 CXX=g++-7 OPT=-DLIBJ1939_BUILD_EXAMPLE=1 16 | dist: bionic 17 | addons: *gcc7 18 | 19 | - os: linux 20 | arch: arm64 21 | compiler: "gcc" 22 | env: BUILD='Release' OPT=-DLIBJ1939_BUILD_EXAMPLE=1 23 | dist: bionic 24 | addons: *gcc7 25 | 26 | - os: linux 27 | compiler: "gcc" 28 | env: BUILD='Release' 29 | TOOLCHAIN=-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-arm-none-eabi.cmake 30 | dist: bionic 31 | addons: 32 | apt: 33 | sources: 34 | - sourceline: 'ppa:team-gcc-arm-embedded/ppa' 35 | packages: 36 | - gcc-arm-embedded 37 | 38 | before_install: 39 | - sudo apt-get -y install linux-headers-generic 40 | 41 | script: 42 | - cmake --version 43 | - ${CC} --version 44 | - mkdir build 45 | - cd build 46 | - cmake -DCMAKE_BUILD_TYPE=${BUILD} ${TOOLCHAIN} ${OPT} .. 47 | - VERBOSE=1 cmake --build . 48 | 49 | notifications: 50 | email: 51 | on_success: never 52 | on_failure: never 53 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -*- mode:cmake -*- 2 | cmake_minimum_required(VERSION 3.10 FATAL_ERROR) 3 | set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) 4 | 5 | set(CMAKE_C_COMPILER_WORKS 1) 6 | set(CMAKE_CXX_COMPILER_WORKS 1) 7 | 8 | set(CMAKE_C_STANDARD 99) 9 | 10 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") 11 | 12 | set(TARGET j1939) 13 | project(${TARGET} VERSION 0.0.1) 14 | 15 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 16 | 17 | include(DefineCMakeDefaults) 18 | include(DefineCompilerFlags) 19 | include(DefinePlatformDefaults) 20 | include(CompilerChecks.cmake) 21 | 22 | set(PGN_POOL_SIZE 16 CACHE STRING "PGN Pool size") 23 | set(MAX_J1939_SESSIONS 12 CACHE STRING "Max number of parallel sessions") 24 | 25 | 26 | # config.h checks 27 | include(ConfigureChecks.cmake) 28 | configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) 29 | 30 | set(J1939_DIR ${PROJECT_SOURCE_DIR}/src) 31 | set(J1939_INC_DIR ${PROJECT_SOURCE_DIR}/include) 32 | 33 | set(J1939_EXAMPLE_DIR ${PROJECT_SOURCE_DIR}/example) 34 | 35 | set(J1939_SRC 36 | ${J1939_DIR}/j1939.c 37 | ${J1939_DIR}/j1939_ecu.c 38 | ${J1939_DIR}/hasht.c 39 | ${J1939_DIR}/pgn_pool.c 40 | ${J1939_DIR}/time.c 41 | ${J1939_DIR}/sessions.c 42 | ) 43 | 44 | include_directories( 45 | ${J1939_DIR} 46 | ${J1939_INC_DIR} 47 | ) 48 | 49 | add_library(${TARGET} STATIC ${J1939_SRC}) 50 | 51 | add_definitions(-DHAVE_CONFIG_H) 52 | 53 | target_compile_options(${TARGET} 54 | PRIVATE 55 | ${DEFAULT_C_COMPILE_FLAGS}) 56 | set_property(TARGET 57 | ${TARGET} 58 | PROPERTY 59 | LINK_FLAGS 60 | "${DEFAULT_LINK_FLAGS}") 61 | 62 | if(LIBJ1939_BUILD_EXAMPLE AND UNIX) 63 | add_definitions(-DTP_TASK_YIELD=1) 64 | add_definitions(-D_GNU_SOURCE) 65 | 66 | set(EXAMPLE_COMMON ${J1939_EXAMPLE_DIR}/linux_socketcan.c) 67 | 68 | add_executable(j1939_socketcan 69 | ${J1939_EXAMPLE_DIR}/j1939_socketcan.c 70 | ${EXAMPLE_COMMON} 71 | ) 72 | set_property(TARGET j1939_socketcan PROPERTY LINK_FLAGS "${DEFAULT_LINK_FLAGS}") 73 | target_link_libraries(j1939_socketcan ${TARGET} rt pthread) 74 | target_compile_options(j1939_socketcan PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) 75 | 76 | add_executable(j1939_tp_client 77 | ${J1939_EXAMPLE_DIR}/j1939_tp_client.c 78 | ${EXAMPLE_COMMON} 79 | ) 80 | set_property(TARGET j1939_tp_client PROPERTY LINK_FLAGS "${DEFAULT_LINK_FLAGS}") 81 | target_link_libraries(j1939_tp_client ${TARGET} rt pthread) 82 | target_compile_options(j1939_tp_client PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) 83 | 84 | add_executable(j1939_tp_server 85 | ${J1939_EXAMPLE_DIR}/j1939_tp_server.c 86 | ${EXAMPLE_COMMON} 87 | ) 88 | set_property(TARGET j1939_tp_server PROPERTY LINK_FLAGS "${DEFAULT_LINK_FLAGS}") 89 | target_link_libraries(j1939_tp_server ${TARGET} rt pthread) 90 | target_compile_options(j1939_tp_server PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) 91 | endif() 92 | 93 | # 94 | # Doxygen 95 | # 96 | if (GENERATE_DOC) 97 | find_package(Doxygen 98 | REQUIRED dot 99 | OPTIONAL_COMPONENTS mscgen dia) 100 | 101 | set(DOXYGEN_GENERATE_HTML YES) 102 | set(DOXYGEN_GENERATE_MAN NO) 103 | set(DOXYGEN_GENERATE_LATEX NO) 104 | set(DOXYGEN_PROJECT_NAME "Lib J1939") 105 | 106 | doxygen_add_docs( 107 | doxygen 108 | ${PROJECT_SOURCE_DIR} 109 | COMMENT "Generate html pages" 110 | ) 111 | endif() 112 | 113 | -------------------------------------------------------------------------------- /CompilerChecks.cmake: -------------------------------------------------------------------------------- 1 | include(AddCCompilerFlag) 2 | include(CheckCCompilerFlagSSP) 3 | 4 | if (UNIX) 5 | # 6 | # Check for -Werror turned on if possible 7 | # 8 | # This will prevent that compiler flags are detected incorrectly. 9 | # 10 | check_c_compiler_flag("-Werror" REQUIRED_FLAGS_WERROR) 11 | if (REQUIRED_FLAGS_WERROR) 12 | set(CMAKE_REQUIRED_FLAGS "-Werror") 13 | 14 | if (PICKY_DEVELOPER) 15 | list(APPEND SUPPORTED_COMPILER_FLAGS "-Werror") 16 | endif() 17 | endif() 18 | 19 | add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS) 20 | #add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS) 21 | add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS) 22 | add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS) 23 | add_c_compiler_flag("-Wmissing-prototypes" SUPPORTED_COMPILER_FLAGS) 24 | add_c_compiler_flag("-Wcast-align" SUPPORTED_COMPILER_FLAGS) 25 | #add_c_compiler_flag("-Wcast-qual" SUPPORTED_COMPILER_FLAGS) 26 | add_c_compiler_flag("-Werror=address" SUPPORTED_COMPILER_FLAGS) 27 | add_c_compiler_flag("-Wstrict-prototypes" SUPPORTED_COMPILER_FLAGS) 28 | add_c_compiler_flag("-Werror=strict-prototypes" SUPPORTED_COMPILER_FLAGS) 29 | add_c_compiler_flag("-Wwrite-strings" SUPPORTED_COMPILER_FLAGS) 30 | add_c_compiler_flag("-Werror=write-strings" SUPPORTED_COMPILER_FLAGS) 31 | add_c_compiler_flag("-Werror-implicit-function-declaration" SUPPORTED_COMPILER_FLAGS) 32 | add_c_compiler_flag("-Wpointer-arith" SUPPORTED_COMPILER_FLAGS) 33 | add_c_compiler_flag("-Werror=pointer-arith" SUPPORTED_COMPILER_FLAGS) 34 | #add_c_compiler_flag("-Wdeclaration-after-statement" SUPPORTED_COMPILER_FLAGS) 35 | #add_c_compiler_flag("-Werror=declaration-after-statement" SUPPORTED_COMPILER_FLAGS) 36 | add_c_compiler_flag("-Wreturn-type" SUPPORTED_COMPILER_FLAGS) 37 | add_c_compiler_flag("-Werror=return-type" SUPPORTED_COMPILER_FLAGS) 38 | add_c_compiler_flag("-Wuninitialized" SUPPORTED_COMPILER_FLAGS) 39 | add_c_compiler_flag("-Werror=uninitialized" SUPPORTED_COMPILER_FLAGS) 40 | add_c_compiler_flag("-Wimplicit-fallthrough" SUPPORTED_COMPILER_FLAGS) 41 | add_c_compiler_flag("-Werror=strict-overflow" SUPPORTED_COMPILER_FLAGS) 42 | add_c_compiler_flag("-Wstrict-overflow=2" SUPPORTED_COMPILER_FLAGS) 43 | add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS) 44 | add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS) 45 | 46 | check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT) 47 | if (REQUIRED_FLAGS_WFORMAT) 48 | list(APPEND SUPPORTED_COMPILER_FLAGS "-Wformat") 49 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Wformat") 50 | endif() 51 | add_c_compiler_flag("-Wformat-security" SUPPORTED_COMPILER_FLAGS) 52 | add_c_compiler_flag("-Werror=format-security" SUPPORTED_COMPILER_FLAGS) 53 | 54 | # Allow zero for a variadic macro argument 55 | string(TOLOWER "${CMAKE_C_COMPILER_ID}" _C_COMPILER_ID) 56 | if ("${_C_COMPILER_ID}" STREQUAL "clang") 57 | add_c_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" SUPPORTED_COMPILER_FLAGS) 58 | endif() 59 | 60 | add_c_compiler_flag("-fno-common" SUPPORTED_COMPILER_FLAGS) 61 | 62 | if (CMAKE_BUILD_TYPE) 63 | string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) 64 | if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) 65 | add_c_compiler_flag("-Wp,-D_FORTIFY_SOURCE=2" SUPPORTED_COMPILER_FLAGS) 66 | endif() 67 | endif() 68 | 69 | check_c_compiler_flag_ssp("-fstack-protector-strong" WITH_STACK_PROTECTOR_STRONG) 70 | if (WITH_STACK_PROTECTOR_STRONG) 71 | list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector-strong") 72 | # This is needed as Solaris has a seperate libssp 73 | if (SOLARIS) 74 | list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector-strong") 75 | endif() 76 | else (WITH_STACK_PROTECTOR_STRONG) 77 | check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR) 78 | if (WITH_STACK_PROTECTOR) 79 | list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector") 80 | # This is needed as Solaris has a seperate libssp 81 | if (SOLARIS) 82 | list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector") 83 | endif() 84 | endif() 85 | endif (WITH_STACK_PROTECTOR_STRONG) 86 | 87 | check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION) 88 | if (WITH_STACK_CLASH_PROTECTION) 89 | list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection") 90 | endif() 91 | 92 | add_c_compiler_flag("-fstack-usage" SUPPORTED_COMPILER_FLAGS) 93 | 94 | if (PICKY_DEVELOPER) 95 | add_c_compiler_flag("-Wno-error=deprecated-declarations" SUPPORTED_COMPILER_FLAGS) 96 | add_c_compiler_flag("-Wno-error=tautological-compare" SUPPORTED_COMPILER_FLAGS) 97 | endif() 98 | 99 | # Unset CMAKE_REQUIRED_FLAGS 100 | unset(CMAKE_REQUIRED_FLAGS) 101 | endif() 102 | 103 | if (MSVC) 104 | add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" SUPPORTED_COMPILER_FLAGS) 105 | add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1" SUPPORTED_COMPILER_FLAGS) 106 | add_c_compiler_flag("/D _CRT_NONSTDC_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) 107 | add_c_compiler_flag("/D _CRT_SECURE_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) 108 | endif() 109 | 110 | set(DEFAULT_C_COMPILE_FLAGS ${SUPPORTED_COMPILER_FLAGS} CACHE INTERNAL "Default C Compiler Flags" FORCE) 111 | set(DEFAULT_LINK_FLAGS ${SUPPORTED_LINKER_FLAGS} CACHE INTERNAL "Default C Linker Flags" FORCE) 112 | -------------------------------------------------------------------------------- /ConfigureChecks.cmake: -------------------------------------------------------------------------------- 1 | include(CheckIncludeFile) 2 | include(CheckSymbolExists) 3 | include(CheckFunctionExists) 4 | include(CheckLibraryExists) 5 | include(CheckTypeSize) 6 | include(CheckCXXSourceCompiles) 7 | include(CheckStructHasMember) 8 | 9 | set(PACKAGE ${PROJECT_NAME}) 10 | set(VERSION ${PROJECT_VERSION}) 11 | set(DATADIR ${DATA_INSTALL_DIR}) 12 | set(LIBDIR ${CMAKE_INSTALL_LIBDIR}) 13 | set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}") 14 | set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) 15 | 16 | set(BINARYDIR ${CMAKE_BINARY_DIR}) 17 | set(SOURCEDIR ${CMAKE_SOURCE_DIR}) 18 | 19 | set(PGN_POOL_SIZE ${PGN_POOL_SIZE}) 20 | set(MAX_J1939_SESSIONS ${MAX_J1939_SESSIONS}) 21 | 22 | function(COMPILER_DUMPVERSION _OUTPUT_VERSION) 23 | # Remove whitespaces from the argument. 24 | # This is needed for CC="ccache gcc" cmake .. 25 | string(REPLACE " " "" _C_COMPILER_ARG "${CMAKE_C_COMPILER_ARG1}") 26 | 27 | execute_process( 28 | COMMAND 29 | ${CMAKE_C_COMPILER} ${_C_COMPILER_ARG} -dumpversion 30 | OUTPUT_VARIABLE _COMPILER_VERSION 31 | ) 32 | 33 | string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" 34 | _COMPILER_VERSION ${_COMPILER_VERSION}) 35 | 36 | set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE) 37 | endfunction() 38 | 39 | if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) 40 | compiler_dumpversion(GNUCC_VERSION) 41 | if (NOT GNUCC_VERSION EQUAL 34) 42 | check_c_compiler_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN) 43 | endif (NOT GNUCC_VERSION EQUAL 34) 44 | endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) 45 | 46 | # DEFINITIONS 47 | if (SOLARIS) 48 | add_definitions(-D__EXTENSIONS__) 49 | endif (SOLARIS) 50 | 51 | # HEADER FILES 52 | check_include_file(assert.h HAVE_ASSERT_H) 53 | check_include_file(inttypes.h HAVE_INTTYPES_H) 54 | check_include_file(io.h HAVE_IO_H) 55 | check_include_file(malloc.h HAVE_MALLOC_H) 56 | check_include_file(memory.h HAVE_MEMORY_H) 57 | check_include_file(setjmp.h HAVE_SETJMP_H) 58 | check_include_file(signal.h HAVE_SIGNAL_H) 59 | check_include_file(stdarg.h HAVE_STDARG_H) 60 | check_include_file(stddef.h HAVE_STDDEF_H) 61 | check_include_file(stdint.h HAVE_STDINT_H) 62 | check_include_file(stdio.h HAVE_STDIO_H) 63 | check_include_file(stdlib.h HAVE_STDLIB_H) 64 | check_include_file(string.h HAVE_STRING_H) 65 | check_include_file(strings.h HAVE_STRINGS_H) 66 | check_include_file(sys/stat.h HAVE_SYS_STAT_H) 67 | check_include_file(sys/types.h HAVE_SYS_TYPES_H) 68 | check_include_file(time.h HAVE_TIME_H) 69 | check_include_file(unistd.h HAVE_UNISTD_H) 70 | check_include_file(stdatomic.h HAVE_STDATOMIC_H) 71 | 72 | if (HAVE_TIME_H) 73 | check_struct_has_member("struct timespec" tv_sec "time.h" HAVE_STRUCT_TIMESPEC) 74 | endif (HAVE_TIME_H) 75 | 76 | # TYPES 77 | check_type_size(uintptr_t UINTPTR_T) 78 | 79 | # FUNCTIONS 80 | check_function_exists(calloc HAVE_CALLOC) 81 | check_function_exists(exit HAVE_EXIT) 82 | check_function_exists(fprintf HAVE_FPRINTF) 83 | check_function_exists(free HAVE_FREE) 84 | check_function_exists(longjmp HAVE_LONGJMP) 85 | check_function_exists(siglongjmp HAVE_SIGLONGJMP) 86 | check_function_exists(malloc HAVE_MALLOC) 87 | check_function_exists(memcpy HAVE_MEMCPY) 88 | check_function_exists(memset HAVE_MEMSET) 89 | check_function_exists(printf HAVE_PRINTF) 90 | check_function_exists(setjmp HAVE_SETJMP) 91 | check_function_exists(signal HAVE_SIGNAL) 92 | check_function_exists(strsignal HAVE_STRSIGNAL) 93 | check_function_exists(strcmp HAVE_STRCMP) 94 | check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) 95 | 96 | if (WIN32) 97 | check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S) 98 | check_function_exists(_vsnprintf HAVE__VSNPRINTF) 99 | check_function_exists(_snprintf HAVE__SNPRINTF) 100 | check_function_exists(_snprintf_s HAVE__SNPRINTF_S) 101 | check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF) 102 | check_symbol_exists(vsnprintf stdio.h HAVE_VSNPRINTF) 103 | else (WIN32) 104 | check_function_exists(sprintf HAVE_SNPRINTF) 105 | check_function_exists(vsnprintf HAVE_VSNPRINTF) 106 | endif (WIN32) 107 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/paoloteti/libj1939.svg?branch=master)](https://travis-ci.com/paoloteti/libj1939) 2 | 3 | # J1939 Library 4 | 5 | Library to work with J1939 Frames used in CAN bus in car and trucks industries. 6 | `libj1939` is intended to be used in microcontrollers. 7 | 8 | ## Coding style 9 | 10 | The whole software is programmed using the Linux kernel coding style, see 11 | https://www.kernel.org/doc/html/v5.9/process/coding-style.html for details. 12 | 13 | ## Amendments to the Linux kernel coding style 14 | 15 | 1. Use stdint types. 16 | 17 | 2. Always add brackets around bodies of if, while and for statements, even 18 | if the body contains only one expression. It is dangerous to not have them 19 | as it easily happens that one adds a second expression and is hunting for 20 | hours why the code is not working just because of a missing bracket pair. 21 | 22 | 3. Use `size_t` for array indexes, for length values and similar. 23 | 24 | 4. Use C99 index declaration inside for loop body where possible. This will ensure 25 | that index will live within the loop scope and not outside. 26 | 27 | ## Semantic versioning 28 | 29 | Software is numbered according to [Semantic versioning 2.0.0](https://semver.org) rules. 30 | Semantic versioning uses a sequence of three digits (Major.Minor.Patch), 31 | an optional prerelease tag and optional build meta tag. 32 | 33 | ## Documentation 34 | 35 | Doxygen is used to generate API docs so it is mandatory to follow that 36 | style for function and definition commentary where possible. 37 | 38 | ## WARNING 39 | 40 | WARNING: Currently this project is in alpha-state! Some of the features are 41 | not completely working! 42 | 43 | ## License 44 | 45 | Licensed under Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or 46 | http://www.apache.org/licenses/LICENSE-2.0) 47 | 48 | 49 | ### Contribution 50 | 51 | Unless you explicitly state otherwise, any contribution intentionally submitted for 52 | inclusion in the work by you, as defined in the Apache-2.0 license, without any 53 | additional terms or conditions. 54 | 55 | Please do not ask for features, but send a Pull Request instead. 56 | -------------------------------------------------------------------------------- /cmake/Modules/AddCCompilerFlag.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # add_c_compiler_flag("-Werror" SUPPORTED_CFLAGS) 3 | # 4 | # Copyright (c) 2018 Andreas Schneider 5 | # 6 | # Redistribution and use is allowed according to the terms of the BSD license. 7 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 8 | 9 | include(CheckCCompilerFlag) 10 | 11 | macro(add_c_compiler_flag _COMPILER_FLAG _OUTPUT_VARIABLE) 12 | string(TOUPPER ${_COMPILER_FLAG} _COMPILER_FLAG_NAME) 13 | string(REGEX REPLACE "^-" "" _COMPILER_FLAG_NAME "${_COMPILER_FLAG_NAME}") 14 | string(REGEX REPLACE "(-|=|\ )" "_" _COMPILER_FLAG_NAME "${_COMPILER_FLAG_NAME}") 15 | 16 | check_c_compiler_flag("${_COMPILER_FLAG}" WITH_${_COMPILER_FLAG_NAME}_FLAG) 17 | if (WITH_${_COMPILER_FLAG_NAME}_FLAG) 18 | #string(APPEND ${_OUTPUT_VARIABLE} "${_COMPILER_FLAG} ") 19 | list(APPEND ${_OUTPUT_VARIABLE} ${_COMPILER_FLAG}) 20 | endif() 21 | endmacro() 22 | -------------------------------------------------------------------------------- /cmake/Modules/AddCMockaTest.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2007 Daniel Gollub 3 | # Copyright (c) 2007-2018 Andreas Schneider 4 | # Copyright (c) 2018 Anderson Toshiyuki Sasaki 5 | # 6 | # Redistribution and use is allowed according to the terms of the BSD license. 7 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 8 | 9 | #.rst: 10 | # AddCMockaTest 11 | # ------------- 12 | # 13 | # This file provides a function to add a test 14 | # 15 | # Functions provided 16 | # ------------------ 17 | # 18 | # :: 19 | # 20 | # add_cmocka_test(target_name 21 | # SOURCES src1 src2 ... srcN 22 | # [COMPILE_OPTIONS opt1 opt2 ... optN] 23 | # [LINK_LIBRARIES lib1 lib2 ... libN] 24 | # [LINK_OPTIONS lopt1 lop2 .. loptN] 25 | # ) 26 | # 27 | # ``target_name``: 28 | # Required, expects the name of the test which will be used to define a target 29 | # 30 | # ``SOURCES``: 31 | # Required, expects one or more source files names 32 | # 33 | # ``COMPILE_OPTIONS``: 34 | # Optional, expects one or more options to be passed to the compiler 35 | # 36 | # ``LINK_LIBRARIES``: 37 | # Optional, expects one or more libraries to be linked with the test 38 | # executable. 39 | # 40 | # ``LINK_OPTIONS``: 41 | # Optional, expects one or more options to be passed to the linker 42 | # 43 | # 44 | # Example: 45 | # 46 | # .. code-block:: cmake 47 | # 48 | # add_cmocka_test(my_test 49 | # SOURCES my_test.c other_source.c 50 | # COMPILE_OPTIONS -g -Wall 51 | # LINK_LIBRARIES mylib 52 | # LINK_OPTIONS -Wl,--enable-syscall-fixup 53 | # ) 54 | # 55 | # Where ``my_test`` is the name of the test, ``my_test.c`` and 56 | # ``other_source.c`` are sources for the binary, ``-g -Wall`` are compiler 57 | # options to be used, ``mylib`` is a target of a library to be linked, and 58 | # ``-Wl,--enable-syscall-fixup`` is an option passed to the linker. 59 | # 60 | 61 | enable_testing() 62 | include(CTest) 63 | 64 | if (CMAKE_CROSSCOMPILING) 65 | if (WIN32) 66 | find_program(WINE_EXECUTABLE 67 | NAMES wine) 68 | set(TARGET_SYSTEM_EMULATOR ${WINE_EXECUTABLE} CACHE INTERNAL "") 69 | endif() 70 | endif() 71 | 72 | function(ADD_CMOCKA_TEST _TARGET_NAME) 73 | 74 | set(one_value_arguments 75 | ) 76 | 77 | set(multi_value_arguments 78 | SOURCES 79 | COMPILE_OPTIONS 80 | LINK_LIBRARIES 81 | LINK_OPTIONS 82 | ) 83 | 84 | cmake_parse_arguments(_add_cmocka_test 85 | "" 86 | "${one_value_arguments}" 87 | "${multi_value_arguments}" 88 | ${ARGN} 89 | ) 90 | 91 | if (NOT DEFINED _add_cmocka_test_SOURCES) 92 | message(FATAL_ERROR "No sources provided for target ${_TARGET_NAME}") 93 | endif() 94 | 95 | add_executable(${_TARGET_NAME} ${_add_cmocka_test_SOURCES}) 96 | 97 | if (DEFINED _add_cmocka_test_COMPILE_OPTIONS) 98 | target_compile_options(${_TARGET_NAME} 99 | PRIVATE ${_add_cmocka_test_COMPILE_OPTIONS} 100 | ) 101 | endif() 102 | 103 | if (DEFINED _add_cmocka_test_LINK_LIBRARIES) 104 | target_link_libraries(${_TARGET_NAME} 105 | PRIVATE ${_add_cmocka_test_LINK_LIBRARIES} 106 | ) 107 | endif() 108 | 109 | if (DEFINED _add_cmocka_test_LINK_OPTIONS) 110 | set_target_properties(${_TARGET_NAME} 111 | PROPERTIES LINK_FLAGS 112 | ${_add_cmocka_test_LINK_OPTIONS} 113 | ) 114 | endif() 115 | 116 | add_test(${_TARGET_NAME} 117 | ${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME} 118 | ) 119 | 120 | endfunction (ADD_CMOCKA_TEST) 121 | 122 | function(ADD_CMOCKA_TEST_ENVIRONMENT _TARGET_NAME) 123 | if (WIN32 OR CYGWIN OR MINGW OR MSVC) 124 | file(TO_NATIVE_PATH "${cmocka-library_BINARY_DIR}" CMOCKA_DLL_PATH) 125 | 126 | if (TARGET_SYSTEM_EMULATOR) 127 | set(DLL_PATH_ENV "WINEPATH=${CMOCKA_DLL_PATH};$ENV{WINEPATH}") 128 | else() 129 | set(DLL_PATH_ENV "PATH=${CMOCKA_DLL_PATH};$ENV{PATH}") 130 | endif() 131 | # 132 | # IMPORTANT NOTE: The set_tests_properties(), below, internally 133 | # stores its name/value pairs with a semicolon delimiter. 134 | # because of this we must protect the semicolons in the path 135 | # 136 | string(REPLACE ";" "\\;" DLL_PATH_ENV "${DLL_PATH_ENV}") 137 | 138 | set_tests_properties(${_TARGET_NAME} 139 | PROPERTIES 140 | ENVIRONMENT 141 | "${DLL_PATH_ENV}") 142 | endif() 143 | endfunction() 144 | -------------------------------------------------------------------------------- /cmake/Modules/COPYING-CMAKE-SCRIPTS: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions 3 | are met: 4 | 5 | 1. Redistributions of source code must retain the copyright 6 | notice, this list of conditions and the following disclaimer. 7 | 2. Redistributions in binary form must reproduce the copyright 8 | notice, this list of conditions and the following disclaimer in the 9 | documentation and/or other materials provided with the distribution. 10 | 3. The name of the author may not be used to endorse or promote products 11 | derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /cmake/Modules/CheckCCompilerFlagSSP.cmake: -------------------------------------------------------------------------------- 1 | # - Check whether the C compiler supports a given flag in the 2 | # context of a stack checking compiler option. 3 | 4 | # CHECK_C_COMPILER_FLAG_SSP(FLAG VARIABLE) 5 | # 6 | # FLAG - the compiler flag 7 | # VARIABLE - variable to store the result 8 | # 9 | # This actually calls check_c_source_compiles. 10 | # See help for CheckCSourceCompiles for a listing of variables 11 | # that can modify the build. 12 | 13 | # Copyright (c) 2006, Alexander Neundorf, 14 | # 15 | # Redistribution and use is allowed according to the terms of the BSD license. 16 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 17 | 18 | # Requires cmake 3.10 19 | #include_guard(GLOBAL) 20 | include(CheckCSourceCompiles) 21 | include(CMakeCheckCompilerFlagCommonPatterns) 22 | 23 | macro(CHECK_C_COMPILER_FLAG_SSP _FLAG _RESULT) 24 | set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") 25 | set(CMAKE_REQUIRED_FLAGS "${_FLAG}") 26 | 27 | # Normalize locale during test compilation. 28 | set(_CheckCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) 29 | foreach(v ${_CheckCCompilerFlag_LOCALE_VARS}) 30 | set(_CheckCCompilerFlag_SAVED_${v} "$ENV{${v}}") 31 | set(ENV{${v}} C) 32 | endforeach() 33 | 34 | CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS) 35 | check_c_source_compiles("int main(int argc, char **argv) { char buffer[256]; return buffer[argc]=0;}" 36 | ${_RESULT} 37 | # Some compilers do not fail with a bad flag 38 | FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU 39 | ${_CheckCCompilerFlag_COMMON_PATTERNS}) 40 | foreach(v ${_CheckCCompilerFlag_LOCALE_VARS}) 41 | set(ENV{${v}} ${_CheckCCompilerFlag_SAVED_${v}}) 42 | unset(_CheckCCompilerFlag_SAVED_${v}) 43 | endforeach() 44 | unset(_CheckCCompilerFlag_LOCALE_VARS) 45 | unset(_CheckCCompilerFlag_COMMON_PATTERNS) 46 | 47 | set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}") 48 | endmacro(CHECK_C_COMPILER_FLAG_SSP) 49 | -------------------------------------------------------------------------------- /cmake/Modules/DefineCMakeDefaults.cmake: -------------------------------------------------------------------------------- 1 | # Always include srcdir and builddir in include path 2 | # This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in 3 | # about every subdir 4 | # since cmake 2.4.0 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | # Put the include dirs which are in the source or build tree 8 | # before all other include dirs, so the headers in the sources 9 | # are prefered over the already installed ones 10 | # since cmake 2.4.1 11 | set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) 12 | 13 | # Use colored output 14 | # since cmake 2.4.0 15 | set(CMAKE_COLOR_MAKEFILE ON) 16 | 17 | # Create the compile command database for clang by default 18 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 19 | 20 | # Always build with -fPIC 21 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 22 | 23 | # Avoid source tree pollution 24 | set(CMAKE_DISABLE_SOURCE_CHANGES ON) 25 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 26 | -------------------------------------------------------------------------------- /cmake/Modules/DefineCompilerFlags.cmake: -------------------------------------------------------------------------------- 1 | if (UNIX AND NOT WIN32) 2 | # Activate with: -DCMAKE_BUILD_TYPE=Profiling 3 | set(CMAKE_C_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" 4 | CACHE STRING "Flags used by the C compiler during PROFILING builds.") 5 | set(CMAKE_CXX_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" 6 | CACHE STRING "Flags used by the CXX compiler during PROFILING builds.") 7 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" 8 | CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") 9 | set(CMAKE_MODULE_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" 10 | CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") 11 | set(CMAKE_EXEC_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" 12 | CACHE STRING "Flags used by the linker during PROFILING builds.") 13 | 14 | # Activate with: -DCMAKE_BUILD_TYPE=AddressSanitizer 15 | set(CMAKE_C_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" 16 | CACHE STRING "Flags used by the C compiler during ADDRESSSANITIZER builds.") 17 | set(CMAKE_CXX_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" 18 | CACHE STRING "Flags used by the CXX compiler during ADDRESSSANITIZER builds.") 19 | set(CMAKE_SHARED_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" 20 | CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") 21 | set(CMAKE_MODULE_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" 22 | CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") 23 | set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" 24 | CACHE STRING "Flags used by the linker during ADDRESSSANITIZER builds.") 25 | 26 | # Activate with: -DCMAKE_BUILD_TYPE=MemorySanitizer 27 | set(CMAKE_C_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" 28 | CACHE STRING "Flags used by the C compiler during MEMORYSANITIZER builds.") 29 | set(CMAKE_CXX_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" 30 | CACHE STRING "Flags used by the CXX compiler during MEMORYSANITIZER builds.") 31 | set(CMAKE_SHARED_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory" 32 | CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.") 33 | set(CMAKE_MODULE_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory" 34 | CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.") 35 | set(CMAKE_EXEC_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory" 36 | CACHE STRING "Flags used by the linker during MEMORYSANITIZER builds.") 37 | 38 | # Activate with: -DCMAKE_BUILD_TYPE=UndefinedSanitizer 39 | set(CMAKE_C_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover" 40 | CACHE STRING "Flags used by the C compiler during UNDEFINEDSANITIZER builds.") 41 | set(CMAKE_CXX_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover" 42 | CACHE STRING "Flags used by the CXX compiler during UNDEFINEDSANITIZER builds.") 43 | set(CMAKE_SHARED_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" 44 | CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.") 45 | set(CMAKE_MODULE_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" 46 | CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.") 47 | set(CMAKE_EXEC_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" 48 | CACHE STRING "Flags used by the linker during UNDEFINEDSANITIZER builds.") 49 | endif() 50 | -------------------------------------------------------------------------------- /cmake/Modules/DefinePlatformDefaults.cmake: -------------------------------------------------------------------------------- 1 | # Set system vars 2 | 3 | if (CMAKE_SYSTEM_NAME MATCHES "Linux") 4 | set(LINUX TRUE) 5 | endif(CMAKE_SYSTEM_NAME MATCHES "Linux") 6 | 7 | if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") 8 | set(FREEBSD TRUE) 9 | endif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") 10 | 11 | if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") 12 | set(OPENBSD TRUE) 13 | endif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") 14 | 15 | if (CMAKE_SYSTEM_NAME MATCHES "NetBSD") 16 | set(NETBSD TRUE) 17 | endif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") 18 | 19 | if (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") 20 | set(SOLARIS TRUE) 21 | endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") 22 | -------------------------------------------------------------------------------- /cmake/Modules/FindNSIS.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find NSIS 2 | # Once done this will define 3 | # 4 | # NSIS_ROOT_PATH - Set this variable to the root installation of NSIS 5 | # 6 | # Read-Only variables: 7 | # 8 | # NSIS_FOUND - system has NSIS 9 | # NSIS_MAKE - NSIS creator executable 10 | # 11 | #============================================================================= 12 | # Copyright (c) 2010-2013 Andreas Schneider 13 | # 14 | # Distributed under the OSI-approved BSD License (the "License"); 15 | # see accompanying file Copyright.txt for details. 16 | # 17 | # This software is distributed WITHOUT ANY WARRANTY; without even the 18 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 19 | # See the License for more information. 20 | #============================================================================= 21 | # 22 | 23 | if (WIN32) 24 | set(_x86 "(x86)") 25 | 26 | set(_NSIS_ROOT_PATHS 27 | "$ENV{ProgramFiles}/NSIS" 28 | "$ENV{ProgramFiles${_x86}}/NSIS" 29 | "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS;Default]") 30 | 31 | find_path(NSIS_ROOT_PATH 32 | NAMES 33 | Include/Library.nsh 34 | PATHS 35 | ${_NSIS_ROOT_PATHS} 36 | ) 37 | mark_as_advanced(NSIS_ROOT_PATH) 38 | endif (WIN32) 39 | 40 | find_program(NSIS_MAKE 41 | NAMES 42 | makensis 43 | PATHS 44 | ${NSIS_ROOT_PATH} 45 | ) 46 | 47 | include(FindPackageHandleStandardArgs) 48 | find_package_handle_standard_args(NSIS DEFAULT_MSG NSIS_MAKE) 49 | 50 | if (NSIS_MAKE) 51 | set(NSIS_FOUND TRUE) 52 | endif (NSIS_MAKE) 53 | 54 | mark_as_advanced(NSIS_MAKE) 55 | -------------------------------------------------------------------------------- /cmake/Modules/MacroEnsureOutOfSourceBuild.cmake: -------------------------------------------------------------------------------- 1 | # - MACRO_ENSURE_OUT_OF_SOURCE_BUILD() 2 | # MACRO_ENSURE_OUT_OF_SOURCE_BUILD() 3 | 4 | # Copyright (c) 2006, Alexander Neundorf, 5 | # 6 | # Redistribution and use is allowed according to the terms of the BSD license. 7 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 8 | 9 | macro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage) 10 | 11 | string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource) 12 | if (_insource) 13 | message(SEND_ERROR "${_errorMessage}") 14 | message(FATAL_ERROR "Remove the file CMakeCache.txt in ${CMAKE_SOURCE_DIR} first.") 15 | endif (_insource) 16 | 17 | endmacro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD) 18 | -------------------------------------------------------------------------------- /cmake/Toolchain-cross-arm-none-eabi.cmake: -------------------------------------------------------------------------------- 1 | SET(CMAKE_C_COMPILER_WORKS 1) 2 | SET(CMAKE_CXX_COMPILER_WORKS 1) 3 | 4 | set(CMAKE_SYSTEM_NAME Generic) 5 | set(CMAKE_SYSTEM_PROCESSOR arm) 6 | set(CMAKE_CROSSCOMPILING 1) 7 | 8 | set(TOOLCHAIN_TRIPLE "arm-none-eabi-" CACHE STRING "Triple prefix for arm crosscompiling tools") 9 | if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") 10 | set(TOOLCHAIN_SUFFIX ".exe" CACHE STRING "Toolchain executable file extension") 11 | else() 12 | set(TOOLCHAIN_SUFFIX "" CACHE STRING "Toolchain executable file extension") 13 | endif() 14 | 15 | # Search default paths for the GNU ARM Embedded Toolchain 16 | # This will need to be changed if you have it in a different directory. 17 | find_path(TOOLCHAIN_BIN_PATH "${TOOLCHAIN_TRIPLE}gcc${TOOLCHAIN_SUFFIX}" 18 | PATHS "/usr/bin" # Linux, Mac 19 | PATHS "C:/Program Files (x86)/GNU Tools ARM Embedded/*/bin" # Default on Windows 20 | DOC "Toolchain binaries directory") 21 | 22 | if(NOT TOOLCHAIN_BIN_PATH) 23 | message(FATAL_ERROR "GNU ARM Embedded Toolchain not found. \ 24 | Please install it and provide its directory as a \ 25 | TOOLCHAIN_BIN_PATH variable.") 26 | endif() 27 | 28 | set(CMAKE_C_COMPILER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}gcc${TOOLCHAIN_SUFFIX}") 29 | set(CMAKE_CXX_COMPILER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}g++${TOOLCHAIN_SUFFIX}") 30 | set(CMAKE_ASM_COMPILER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}gcc${TOOLCHAIN_SUFFIX}") 31 | # 32 | # cmake issue: CMAKE_AR seems to require CACHE on some cmake versions 33 | # 34 | set(CMAKE_AR "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}ar${TOOLCHAIN_SUFFIX}" CACHE FILEPATH "") 35 | set(CMAKE_LINKER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}ld${TOOLCHAIN_SUFFIX}") 36 | set(CMAKE_NM "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}nm${TOOLCHAIN_SUFFIX}") 37 | set(CMAKE_OBJCOPY "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}objcopy${TOOLCHAIN_SUFFIX}") 38 | set(CMAKE_OBJDUMP "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}objdump${TOOLCHAIN_SUFFIX}") 39 | set(CMAKE_STRIP "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}strip${TOOLCHAIN_SUFFIX}") 40 | set(CMAKE_PRINT_SIZE "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}size${TOOLCHAIN_SUFFIX}") 41 | set(CMAKE_RANLIB "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}ranlib${TOOLCHAIN_SUFFIX}") 42 | 43 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 44 | set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS) # remove -Wl,-Bdynamic 45 | set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) # remove -rdynamic 46 | set(BUILD_SHARED_LIBRARIES OFF) 47 | 48 | set(CMAKE_EXE_LINKER_FLAGS "-static -nostartfiles -Wl,--gc-sections --specs=nosys.specs") 49 | set(CMAKE_C_FLAGS "-fno-strict-aliasing -ffunction-sections -fdata-sections") 50 | set(CMAKE_ASM_FLAGS "-x assembler-with-cpp") 51 | -------------------------------------------------------------------------------- /cmake/tms570-toolchain.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # TMS570 big-endian toolchain (GNU Tools ARM Embedded) 3 | # 4 | set(CMAKE_SYSTEM_NAME Generic) 5 | set(CMAKE_SYSTEM_PROCESSOR arm) 6 | set(CMAKE_CROSSCOMPILING 1) 7 | 8 | set(TOOLCHAIN_TRIPLE "armeb-none-eabi-" CACHE STRING "Triple prefix for arm crosscompiling tools") 9 | if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") 10 | set(TOOLCHAIN_SUFFIX ".exe" CACHE STRING "Toolchain executable file extension") 11 | else() 12 | set(TOOLCHAIN_SUFFIX "" CACHE STRING "Toolchain executable file extension") 13 | endif() 14 | 15 | # Search default paths for the GNU ARM Embedded Toolchain 16 | # This will need to be changed if you have it in a different directory. 17 | find_path(TOOLCHAIN_BIN_PATH "${TOOLCHAIN_TRIPLE}gcc${TOOLCHAIN_SUFFIX}" 18 | PATHS "/usr/local/bin" # Linux, Mac 19 | PATHS "C:/Program Files (x86)/GNU Tools ARM Embedded/*/bin" # Default on Windows 20 | DOC "Toolchain binaries directory") 21 | 22 | if(NOT TOOLCHAIN_BIN_PATH) 23 | message(FATAL_ERROR "GNU ARM Embedded Toolchain not found. \ 24 | Please install it and provide its directory as a \ 25 | TOOLCHAIN_BIN_PATH variable.") 26 | endif() 27 | 28 | set(CMAKE_C_COMPILER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}gcc${TOOLCHAIN_SUFFIX}") 29 | set(CMAKE_CXX_COMPILER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}g++${TOOLCHAIN_SUFFIX}") 30 | set(CMAKE_ASM_COMPILER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}gcc${TOOLCHAIN_SUFFIX}") 31 | # 32 | # cmake issue: CMAKE_AR seems to require CACHE on some cmake versions 33 | # 34 | set(CMAKE_AR "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}ar${TOOLCHAIN_SUFFIX}" CACHE FILEPATH "") 35 | set(CMAKE_LINKER "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}ld${TOOLCHAIN_SUFFIX}") 36 | set(CMAKE_NM "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}nm${TOOLCHAIN_SUFFIX}") 37 | set(CMAKE_OBJCOPY "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}objcopy${TOOLCHAIN_SUFFIX}") 38 | set(CMAKE_OBJDUMP "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}objdump${TOOLCHAIN_SUFFIX}") 39 | set(CMAKE_STRIP "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}strip${TOOLCHAIN_SUFFIX}") 40 | set(CMAKE_PRINT_SIZE "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}size${TOOLCHAIN_SUFFIX}") 41 | set(CMAKE_RANLIB "${TOOLCHAIN_BIN_PATH}/${TOOLCHAIN_TRIPLE}ranlib${TOOLCHAIN_SUFFIX}") 42 | 43 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 44 | set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS) # remove -Wl,-Bdynamic 45 | set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) # remove -rdynamic 46 | set(BUILD_SHARED_LIBRARIES OFF) 47 | 48 | set(TARGET_FLAGS "-march=armv7-r -mtune=cortex-r4 -mfloat-abi=hard -mfpu=vfpv3-d16") 49 | set(CMAKE_EXE_LINKER_FLAGS "-mbe32 -static -nostartfiles -Wl,--gc-sections --specs=nosys.specs") 50 | 51 | set(CMAKE_C_FLAGS "-fno-strict-aliasing ${TARGET_FLAGS} -ffunction-sections -fdata-sections") 52 | set(CMAKE_ASM_FLAGS "${TARGET_FLAGS} -x assembler-with-cpp") 53 | -------------------------------------------------------------------------------- /config.h.cmake: -------------------------------------------------------------------------------- 1 | /* Name of package */ 2 | #cmakedefine PACKAGE "${PROJECT_NAME}" 3 | 4 | /* Version number of package */ 5 | #cmakedefine VERSION "${PROJECT_VERSION}" 6 | 7 | /************************** HEADER FILES *************************/ 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #cmakedefine HAVE_ASSERT_H 1 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #cmakedefine HAVE_DLFCN_H 1 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #cmakedefine HAVE_INTTYPES_H 1 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #cmakedefine HAVE_IO_H 1 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #cmakedefine HAVE_MALLOC_H 1 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #cmakedefine HAVE_MEMORY_H 1 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #cmakedefine HAVE_SETJMP_H 1 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #cmakedefine HAVE_SIGNAL_H 1 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #cmakedefine HAVE_STDARG_H 1 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #cmakedefine HAVE_STDDEF_H 1 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #cmakedefine HAVE_STDINT_H 1 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #cmakedefine HAVE_STDIO_H 1 44 | 45 | /* Define to 1 if you have the header file. */ 46 | #cmakedefine HAVE_STDLIB_H 1 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #cmakedefine HAVE_STRINGS_H 1 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #cmakedefine HAVE_STRING_H 1 53 | 54 | /* Define to 1 if you have the header file. */ 55 | #cmakedefine HAVE_SYS_STAT_H 1 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #cmakedefine HAVE_SYS_TYPES_H 1 59 | 60 | /* Define to 1 if you have the header file. */ 61 | #cmakedefine HAVE_TIME_H 1 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #cmakedefine HAVE_UNISTD_H 1 65 | 66 | /* Define to 1 if you have the header file. */ 67 | #cmakedefine HAVE_STDATOMIC_H 1 68 | 69 | 70 | /**************************** STRUCTS ****************************/ 71 | 72 | #cmakedefine HAVE_STRUCT_TIMESPEC 1 73 | 74 | /***************************** TYPES *****************************/ 75 | 76 | #cmakedefine HAVE_UINTPTR_T 1 77 | 78 | /*************************** FUNCTIONS ***************************/ 79 | 80 | /* Define to 1 if you have the `calloc' function. */ 81 | #cmakedefine HAVE_CALLOC 1 82 | 83 | /* Define to 1 if you have the `exit' function. */ 84 | #cmakedefine HAVE_EXIT 1 85 | 86 | /* Define to 1 if you have the `fprintf' function. */ 87 | #cmakedefine HAVE_FPRINTF 1 88 | 89 | /* Define to 1 if you have the `snprintf' function. */ 90 | #cmakedefine HAVE_SNPRINTF 1 91 | 92 | /* Define to 1 if you have the `_snprintf' function. */ 93 | #cmakedefine HAVE__SNPRINTF 1 94 | 95 | /* Define to 1 if you have the `_snprintf_s' function. */ 96 | #cmakedefine HAVE__SNPRINTF_S 1 97 | 98 | /* Define to 1 if you have the `vsnprintf' function. */ 99 | #cmakedefine HAVE_VSNPRINTF 1 100 | 101 | /* Define to 1 if you have the `_vsnprintf' function. */ 102 | #cmakedefine HAVE__VSNPRINTF 1 103 | 104 | /* Define to 1 if you have the `_vsnprintf_s' function. */ 105 | #cmakedefine HAVE__VSNPRINTF_S 1 106 | 107 | /* Define to 1 if you have the `free' function. */ 108 | #cmakedefine HAVE_FREE 1 109 | 110 | /* Define to 1 if you have the `longjmp' function. */ 111 | #cmakedefine HAVE_LONGJMP 1 112 | 113 | /* Define to 1 if you have the `siglongjmp' function. */ 114 | #cmakedefine HAVE_SIGLONGJMP 1 115 | 116 | /* Define to 1 if you have the `malloc' function. */ 117 | #cmakedefine HAVE_MALLOC 1 118 | 119 | /* Define to 1 if you have the `memcpy' function. */ 120 | #cmakedefine HAVE_MEMCPY 1 121 | 122 | /* Define to 1 if you have the `memset' function. */ 123 | #cmakedefine HAVE_MEMSET 1 124 | 125 | /* Define to 1 if you have the `printf' function. */ 126 | #cmakedefine HAVE_PRINTF 1 127 | 128 | /* Define to 1 if you have the `setjmp' function. */ 129 | #cmakedefine HAVE_SETJMP 1 130 | 131 | /* Define to 1 if you have the `signal' function. */ 132 | #cmakedefine HAVE_SIGNAL 1 133 | 134 | /* Define to 1 if you have the `snprintf' function. */ 135 | #cmakedefine HAVE_SNPRINTF 1 136 | 137 | /* Define to 1 if you have the `strcmp' function. */ 138 | #cmakedefine HAVE_STRCMP 1 139 | 140 | /* Define to 1 if you have the `strcpy' function. */ 141 | #cmakedefine HAVE_STRCPY 1 142 | 143 | /* Define to 1 if you have the `vsnprintf' function. */ 144 | #cmakedefine HAVE_VSNPRINTF 1 145 | 146 | /* Define to 1 if you have the `strsignal' function. */ 147 | #cmakedefine HAVE_STRSIGNAL 1 148 | 149 | /*************************** ENDIAN *****************************/ 150 | 151 | #cmakedefine WORDS_SIZEOF_VOID_P ${WORDS_SIZEOF_VOID_P} 152 | 153 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most 154 | significant byte first (like Motorola and SPARC, unlike Intel). */ 155 | #cmakedefine WORDS_BIGENDIAN 1 156 | 157 | #cmakedefine PGN_POOL_SIZE ${PGN_POOL_SIZE} 158 | 159 | /* Max number of active session (i.e different source address) */ 160 | #cmakedefine MAX_J1939_SESSIONS ${MAX_J1939_SESSIONS} 161 | -------------------------------------------------------------------------------- /example/config-pcan0.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # configure PEAK PCAN-USB Pro 4 | 5 | ip link set can0 down 6 | ip link set can0 type can bitrate 500000 7 | ip link set can0 up 8 | 9 | ip link set can1 down 10 | ip link set can1 type can bitrate 500000 11 | ip link set can1 up 12 | -------------------------------------------------------------------------------- /example/j1939_socketcan.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | /* 4 | * NOTE: This is just an example. 5 | * 6 | * Linux has its own J1939 kernel module, so there is no need to use 7 | * this library. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "j1939.h" 20 | 21 | extern int connect_canbus(const char *can_ifname); 22 | extern void disconnect_canbus(void); 23 | 24 | int main(void) 25 | { 26 | int ret, ntimes = 5; 27 | const uint8_t src = 0x80; 28 | const uint8_t dest = 0x20; 29 | j1939_pgn_t pgn = J1939_INIT_PGN(0x0, 0xFE, 0xF6); 30 | uint8_t bam_data[18]; 31 | 32 | uint8_t data[8] = { 33 | J1930_NA_8, /* Particulate Trap Inlet Pressure (SPN 81) */ 34 | J1930_NA_8, /* Boost Pressure (SPN 102) */ 35 | 0x46, /* Intake Manifold 1 Temperature (SPN 105) */ 36 | J1930_NA_8, /* Air Inlet Pressure (SPN 106) */ 37 | J1930_NA_8, /* Air Filter 1 Differential. Pressure (SPN 107) */ 38 | J1930_NA_16_MSB, /* Exhaust Gas Temperature (SPN 173) - MSB */ 39 | J1930_NA_16_LSB, /* Exhaust Gas Temperature (SPN 173) - LSB */ 40 | J1930_NA_8, /* Coolant Filter Differ. Pressure 112) */ 41 | }; 42 | 43 | ecu_name_t name = { 44 | .fields.arbitrary_address_capable = J1939_NO_ADDRESS_CAPABLE, 45 | .fields.industry_group = J1939_INDUSTRY_GROUP_INDUSTRIAL, 46 | .fields.vehicle_system_instance = 1, 47 | .fields.vehicle_system = 1, 48 | .fields.function = 1, 49 | .fields.reserved = 0, 50 | .fields.function_instance = 1, 51 | .fields.ecu_instance = 1, 52 | .fields.manufacturer_code = 1, 53 | .fields.identity_number = 1, 54 | }; 55 | 56 | if (connect_canbus("vcan0") < 0) { 57 | perror("Opening CANbus vcan0"); 58 | return 1; 59 | } 60 | 61 | ret = j1939_address_claim(src, name); 62 | if (ret < 0) { 63 | printf("J1939 AC returns with code %d\n", ret); 64 | } 65 | 66 | j1939_address_claimed(src, name); 67 | 68 | do { 69 | ret = j1939_tp(pgn, 6, src, dest, data, 8); 70 | if (ret < 0) { 71 | printf("J1939 TP returns with code %d\n", ret); 72 | } 73 | data[2]++; 74 | } while (ntimes-- && ret >= 0); 75 | 76 | memset(bam_data, 0xAA, sizeof(bam_data)); 77 | 78 | ret = send_tp_bam(6, src, bam_data, sizeof(bam_data)); 79 | if (ret < 0) { 80 | printf("J1939 BAM returns with code %d\n", ret); 81 | } 82 | 83 | disconnect_canbus(); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /example/j1939_tp_client.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | /* 4 | * NOTE: This is just an example. 5 | * 6 | * Linux has its own J1939 kernel module, so there is no need to use 7 | * this library. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "j1939.h" 27 | 28 | #define DEST 0x80u 29 | 30 | extern int pgn_pool_receive(void); 31 | extern void j1939_task_yield(void); 32 | extern int connect_canbus(const char *can_ifname); 33 | extern void disconnect_canbus(void); 34 | extern uint32_t j1939_get_time(void); 35 | 36 | static j1939_pgn_t PGN = J1939_INIT_PGN(0x0, 0xFE, 0xF6); 37 | 38 | static void *pgn_rx(void *x) 39 | { 40 | while (1) { 41 | pgn_pool_receive(); 42 | } 43 | return NULL; 44 | } 45 | 46 | static void dump_payload(uint8_t *data, const uint8_t len) 47 | { 48 | for (uint8_t i = 0; i < len; i++) { 49 | printf("%02x ", data[i]); 50 | } 51 | printf("\n"); 52 | } 53 | 54 | static int rcv_tp_dt(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 55 | uint8_t dest, uint8_t *data, uint8_t len) 56 | { 57 | dump_payload(data, len); 58 | return 0; 59 | } 60 | 61 | static void error_handler(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 62 | uint8_t dest, int err) 63 | { 64 | printf("[%02x %02x] ERROR: %d\n", src, dest, err); 65 | } 66 | 67 | static void *sender(void *x) 68 | { 69 | uint8_t sess = 0; 70 | uint8_t data[32]; 71 | int ret, ntimes = 32; 72 | uint8_t src = *((uint8_t *)x); 73 | 74 | do { 75 | memset(data, sess, sizeof(data)); 76 | sess++; 77 | retry: 78 | ret = j1939_tp(PGN, 6, src, DEST, data, sizeof(data)); 79 | if (ret < 0) { 80 | if (ret == -J1939_EBUSY) { 81 | usleep(500000); 82 | goto retry; 83 | } 84 | printf("J1939 TP returns with code %d\n", ret); 85 | } 86 | 87 | /* Add src to have different periods */ 88 | usleep(1000000 + src); 89 | } while (ntimes-- && ret >= 0); 90 | pthread_exit(NULL); 91 | } 92 | 93 | int main(void) 94 | { 95 | uint8_t src1 = 0x10; 96 | uint8_t src2 = 0x20; 97 | uint8_t src3 = 0x30; 98 | pthread_t tid, s1, s2, s3; 99 | 100 | if (connect_canbus("vcan0") < 0) { 101 | perror("Opening CANbus vcan0"); 102 | return 1; 103 | } 104 | 105 | j1939_setup(rcv_tp_dt, error_handler); 106 | 107 | pthread_create(&tid, NULL, pgn_rx, NULL); 108 | pthread_detach(tid); 109 | 110 | pthread_create(&s1, NULL, sender, &src1); 111 | pthread_create(&s2, NULL, sender, &src2); 112 | pthread_create(&s3, NULL, sender, &src3); 113 | 114 | pthread_join(s1, NULL); 115 | pthread_join(s2, NULL); 116 | pthread_join(s3, NULL); 117 | 118 | disconnect_canbus(); 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /example/j1939_tp_server.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | /* 4 | * NOTE: This is just an example. 5 | * 6 | * Linux has its own J1939 kernel module, so there is no need to use 7 | * this library. 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "j1939.h" 21 | 22 | extern int pgn_pool_receive(void); 23 | extern int connect_canbus(const char *can_ifname); 24 | extern void disconnect_canbus(void); 25 | extern uint32_t j1939_get_time(void); 26 | 27 | static int stop = 0; 28 | 29 | static void *pgn_rx(void *x) 30 | { 31 | while (!stop) { 32 | pgn_pool_receive(); 33 | } 34 | return NULL; 35 | } 36 | 37 | static void dump_payload(uint8_t *data, const uint8_t len) 38 | { 39 | for (uint8_t i = 0; i < len; i++) { 40 | printf("%02x ", data[i]); 41 | } 42 | printf("\n"); 43 | } 44 | 45 | static int rcv_tp_dt(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 46 | uint8_t dest, uint8_t *data, uint8_t len) 47 | { 48 | printf("[%02x %02x]: ", src, dest); 49 | dump_payload(data, len); 50 | return 0; 51 | } 52 | 53 | static void error_handler(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 54 | uint8_t dest, int err) 55 | { 56 | printf("[%02x %02x] ERROR: %d\n", src, dest, err); 57 | #ifdef STOP_ON_ERROR 58 | stop = 1; 59 | #endif 60 | } 61 | 62 | int main(void) 63 | { 64 | pthread_t tid; 65 | 66 | if (connect_canbus("vcan0") < 0) { 67 | perror("Opening CANbus vcan0"); 68 | return 1; 69 | } 70 | 71 | j1939_setup(rcv_tp_dt, error_handler); 72 | 73 | pthread_create(&tid, NULL, pgn_rx, NULL); 74 | 75 | pthread_join(tid, NULL); 76 | 77 | disconnect_canbus(); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /example/linux_socketcan.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "j1939.h" 17 | 18 | extern void j1939_task_yield(void); 19 | 20 | static int cansock = -1; 21 | 22 | int connect_canbus(const char *can_ifname); 23 | int disconnect_canbus(void); 24 | 25 | static inline ssize_t xread(int fd, void *buf, size_t len) 26 | { 27 | ssize_t nr; 28 | while (1) { 29 | nr = read(fd, buf, len); 30 | if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) 31 | continue; 32 | return nr; 33 | } 34 | } 35 | 36 | static inline ssize_t xwrite(int fd, const void *buf, size_t len) 37 | { 38 | ssize_t nr; 39 | while (1) { 40 | nr = write(fd, buf, len); 41 | if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) 42 | continue; 43 | return nr; 44 | } 45 | } 46 | 47 | int connect_canbus(const char *can_ifname) 48 | { 49 | int ret, sock; 50 | struct ifreq ifr; 51 | struct sockaddr_can addr; 52 | 53 | sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); 54 | if (sock < 0) { 55 | return sock; 56 | } 57 | 58 | memset(&ifr, 0, sizeof(ifr)); 59 | strncpy(ifr.ifr_name, can_ifname, IFNAMSIZ - 1); 60 | ioctl(sock, SIOCGIFINDEX, &ifr); 61 | 62 | memset(&addr, 0, sizeof(addr)); 63 | addr.can_family = AF_CAN; 64 | addr.can_ifindex = ifr.ifr_ifindex; 65 | 66 | ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); 67 | if (ret < 0) { 68 | return ret; 69 | } 70 | cansock = sock; 71 | return 0; 72 | } 73 | 74 | int disconnect_canbus(void) 75 | { 76 | return close(cansock); 77 | } 78 | 79 | int j1939_filter(struct j1939_pgn_filter *filter, uint32_t num_filters) 80 | { 81 | struct can_filter rfilter[num_filters]; 82 | uint32_t id; 83 | 84 | for (size_t i = 0; i < num_filters; i++) { 85 | id = j1939_pgn2id(filter[i].pgn, filter[i].priority, 86 | filter[i].addr); 87 | rfilter[i].can_id = id | CAN_EFF_FLAG; 88 | rfilter[i].can_mask = filter[i].pgn_mask; 89 | } 90 | return setsockopt(cansock, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, 91 | sizeof(rfilter)); 92 | } 93 | 94 | int j1939_cansend(uint32_t id, uint8_t *data, uint8_t len) 95 | { 96 | int ret; 97 | struct can_frame frame; 98 | 99 | frame.can_id = id | CAN_EFF_FLAG; 100 | frame.can_dlc = len; 101 | memcpy(frame.data, data, frame.can_dlc); 102 | 103 | ret = xwrite(cansock, &frame, sizeof(frame)); 104 | if (ret != sizeof(frame)) { 105 | return -1; 106 | } 107 | return frame.can_dlc; 108 | } 109 | 110 | int j1939_canrcv(uint32_t *id, uint8_t *data) 111 | { 112 | int ret; 113 | struct can_frame frame; 114 | 115 | ret = xread(cansock, &frame, sizeof(frame)); 116 | if (ret != sizeof(frame)) { 117 | return -1; 118 | } 119 | 120 | memcpy(data, frame.data, frame.can_dlc); 121 | *id = frame.can_id; 122 | return frame.can_dlc; 123 | } 124 | 125 | uint32_t j1939_get_time(void) 126 | { 127 | struct timespec tv; 128 | clock_gettime(CLOCK_MONOTONIC_RAW, &tv); 129 | return tv.tv_sec * 1000 + tv.tv_nsec / 1000000; 130 | } 131 | 132 | void j1939_task_yield(void) 133 | { 134 | pthread_yield(); 135 | } 136 | -------------------------------------------------------------------------------- /example/make-vcan0.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # create a virtual CAN port driver 4 | 5 | modprobe vcan 6 | ip link add dev vcan0 type vcan 7 | ip link set up vcan0 8 | -------------------------------------------------------------------------------- /include/j1939.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #ifndef __J1939_H__ 4 | #define __J1939_H__ 5 | 6 | #define J1939_MAX_DATA_LEN 1785 /*> 8) 30 | #define J1930_NA_16_LSB (J1930_NOT_AVAILABLE_16 & 0xFF) 31 | 32 | /** @brief indicates that the parameter is "not valid" or "in error" */ 33 | #define J1930_NOT_VALID_8 0xFEu 34 | #define J1930_NV_8 J1930_NOT_VALID_8 35 | #define J1930_NOT_VALID_16 0xFE00u 36 | #define J1930_NV_16 J1930_NOT_VALID_16 37 | 38 | /** @brief raw parameter values must not exceed the following values */ 39 | #define J1930_MAX_8 0xFAu 40 | #define J1930_MAX_16 0xFAFFu 41 | 42 | #define J1939_INDUSTRY_GROUP_GLOBAL 0u 43 | #define J1939_INDUSTRY_GROUP_ON_HIGHWAY 1u 44 | #define J1939_INDUSTRY_GROUP_AGRICULTURAL 2u 45 | #define J1939_INDUSTRY_GROUP_CONSTRUCTION 3u 46 | #define J1939_INDUSTRY_GROUP_MARINE 4u 47 | #define J1939_INDUSTRY_GROUP_INDUSTRIAL 5u 48 | 49 | #define J1939_NO_ADDRESS_CAPABLE 0u 50 | #define J1939_ADDRESS_CAPABLE 1u 51 | 52 | typedef union { 53 | struct { 54 | /* 55 | * 21-bit Identity Number 56 | * A unique number which identifies the particular device in a 57 | * manufacturer specific way. 58 | */ 59 | uint64_t identity_number : 21; 60 | /* 61 | * 11-bit Manufacturer Code 62 | * One of the predefined J1939 manufacturer codes. 63 | */ 64 | uint64_t manufacturer_code : 11; 65 | /* 66 | * 3-bit ECU Instance 67 | * Identify the ECU instance if multiple ECUs are involved in 68 | * performing a single function. Normally set to 0. 69 | */ 70 | uint64_t ecu_instance : 3; 71 | /* 72 | * 5-bit Function Instance 73 | * Instance number of a function to distinguish two or more 74 | * devices with the same function number. 75 | * The first instance is assigned to the instance number 0. 76 | */ 77 | uint64_t function_instance : 5; 78 | /* 79 | * 8-bit Function 80 | * One of the predefined J1939 functions. The same function value 81 | * (upper 128 only) may mean different things for different 82 | * Industry Groups or Vehicle Systems. 83 | */ 84 | uint64_t function : 8; 85 | /* 86 | * 1-bit Reserved 87 | * This field is reserved for future use by SAE. 88 | */ 89 | uint64_t reserved : 1; 90 | /* 91 | * 7-bit Vehicle System 92 | * A subcomponent of a vehicle, that includes one or more J1939 93 | * segments and may be connected from the vehicle. 94 | * A Vehicle System may be made of one or more functions. 95 | * The Vehicle System depends on the Industry Group definition. 96 | */ 97 | uint64_t vehicle_system : 7; 98 | /* 99 | * 4-bit Vehicle System Instance 100 | * Instance number of a vehicle system to distinguish two or 101 | * more device with the same Vehicle System number in the same 102 | * J1939 network. 103 | * The first instance is assigned to the instance number 0. 104 | */ 105 | uint64_t vehicle_system_instance : 4; 106 | /* 107 | * 3-bit Industry Group 108 | * One of the predefined J1939 industry groups. 109 | */ 110 | uint64_t industry_group : 3; 111 | /* 112 | * 1-bit Arbitrary Address Capable 113 | * Indicate the capability to solve address conflicts. 114 | * Set to 1 if the device is Arbitrary Address Capable, 115 | * set to 0 if it's Single Address Capable. 116 | */ 117 | uint64_t arbitrary_address_capable : 1; 118 | } fields; 119 | uint64_t value; 120 | } ecu_name_t; 121 | 122 | /** @brief J1939 PGN according to SAE J1939/21 */ 123 | typedef uint32_t j1939_pgn_t; 124 | 125 | struct j1939_pgn_filter { 126 | j1939_pgn_t pgn; 127 | j1939_pgn_t pgn_mask; 128 | uint8_t priority; 129 | uint8_t addr; 130 | uint8_t addr_mask; 131 | }; 132 | 133 | #define SEND_PERIOD 50 /* 5 | #include "config.h" 6 | 7 | typedef int atomic_t; 8 | 9 | #define ATOMIC_INIT(_v) (_v) 10 | 11 | #define ATOMIC_BITS (sizeof(atomic_t) * 8) 12 | #define ATOMIC_MASK(bit) (1 << ((uint32_t)(bit) & (ATOMIC_BITS - 1))) 13 | #define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS)) 14 | 15 | #ifdef HAVE_STDATOMIC_H 16 | static inline atomic_t atomic_get(const atomic_t *target) 17 | { 18 | return __atomic_load_n(target, __ATOMIC_SEQ_CST); 19 | } 20 | 21 | static inline atomic_t atomic_or(atomic_t *target, atomic_t value) 22 | { 23 | return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST); 24 | } 25 | 26 | static inline atomic_t atomic_and(atomic_t *target, atomic_t value) 27 | { 28 | return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST); 29 | } 30 | 31 | static inline void atomic_set(atomic_t *target, atomic_t x) 32 | { 33 | __atomic_store_n(target, x, __ATOMIC_SEQ_CST); 34 | } 35 | 36 | static inline bool atomic_test_and_set_bit(atomic_t *target, int bit) 37 | { 38 | atomic_t mask = ATOMIC_MASK(bit); 39 | atomic_t old; 40 | 41 | old = atomic_or(ATOMIC_ELEM(target, bit), mask); 42 | 43 | return (old & mask) != 0; 44 | } 45 | 46 | static inline void atomic_clear_bit(atomic_t *target, int bit) 47 | { 48 | atomic_t mask = ATOMIC_MASK(bit); 49 | 50 | (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask); 51 | } 52 | 53 | #else 54 | extern atomic_t atomic_get(const atomic_t *target); 55 | extern atomic_t atomic_or(atomic_t *target, atomic_t value); 56 | extern atomic_t atomic_and(atomic_t *target, atomic_t value); 57 | extern void atomic_set(atomic_t *target, atomic_t x); 58 | extern bool atomic_test_and_set_bit(atomic_t *target, int bit); 59 | extern void atomic_clear_bit(atomic_t *target, int bit); 60 | #endif 61 | 62 | #endif /* __ATOMIC_H__ */ 63 | -------------------------------------------------------------------------------- /src/compat.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #ifndef __COMPAT_H__ 4 | #define __COMPAT_H__ 5 | 6 | #if defined(__linux__) 7 | #include 8 | #elif defined(_WIN32) || defined(_WIN64) 9 | #include 10 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 11 | #if defined(_MSC_VER) 12 | #include 13 | #define htobe64(x) _byteswap_uint64(x) 14 | #define htobe16(x) _byteswap_uint16(x) 15 | #elif defined(__GNUC__) || defined(__clang__) 16 | #define htobe64(x) __builtin_bswap64(x) 17 | #define htobe16(x) __builtin_bswap16(x) 18 | #endif 19 | #endif 20 | #else 21 | #include 22 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 23 | #define htobe64 __bswap64 24 | #define htobe16 __bswap16 25 | #else 26 | #define htobe64 27 | #define htobe16 28 | #endif 29 | #endif 30 | 31 | #endif /* __COMPAT_H__ */ 32 | -------------------------------------------------------------------------------- /src/compiler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #ifndef __COMPILER_H__ 4 | #define __COMPILER_H__ 5 | 6 | 7 | #if defined(__GNUC__) 8 | 9 | #define __arg_unused __attribute__((unused)) 10 | #define __weak __attribute__((weak)) 11 | #define __naked __attribute__((naked)) 12 | #define __noreturn __attribute__((noreturn)) 13 | #define likely(x) __builtin_expect(!!(x), 1) 14 | #define unlikely(x) __builtin_expect(!!(x), 0) 15 | 16 | #else 17 | 18 | #define __arg_unused 19 | #define __weak 20 | #define __naked 21 | #define __noreturn 22 | #define likely(x) (x) 23 | #define unlikely(x) (x) 24 | 25 | #endif /* __GNUC__ */ 26 | 27 | 28 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 29 | 30 | #ifdef MISRAC 31 | #define IS_NULL(p) ((p) == NULL) 32 | #else 33 | #define IS_NULL(p) (!p) 34 | #endif /* MISRAC */ 35 | 36 | #define NOT_NULL(p) !IS_NULL(p) 37 | 38 | #endif /* __COMPILER_H__ */ 39 | -------------------------------------------------------------------------------- /src/hasht.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include "hasht.h" 7 | 8 | 9 | #define KEY_UNDEF_VAL (0x1u << 31) 10 | #define KEY_MASK(_k) ((_k) & 0x7FFFFFFFu) /* 30 bits keys */ 11 | 12 | static inline uint32_t next_hash(struct hasht *ht, const uint32_t hash) 13 | { 14 | return (hash + 1u) % ht->max_size; 15 | } 16 | 17 | static inline uint32_t hash_code(struct hasht *ht, const uint32_t key) 18 | { 19 | return key % ht->max_size; 20 | } 21 | 22 | void hasht_clear(struct hasht *ht) 23 | { 24 | ht->size = 0; 25 | } 26 | 27 | int hasht_delete(struct hasht *ht, const uint32_t key) 28 | { 29 | size_t nitems = ht->size; 30 | const uint32_t k = KEY_MASK(key); 31 | uint32_t hash = hash_code(ht, k); 32 | 33 | if (ht->size > 0) { 34 | while (nitems-- != 0) { 35 | if (ht->items[hash].key == k) { 36 | ht->items[hash].item = NULL; 37 | ht->items[hash].key = KEY_UNDEF_VAL; 38 | ht->size--; 39 | return 0; 40 | } 41 | hash = next_hash(ht, hash); 42 | } 43 | } 44 | return -EHASHT_NFOUND; 45 | } 46 | 47 | struct hasht_entry *hasht_search(struct hasht *ht, const uint32_t key) 48 | { 49 | const uint32_t k = KEY_MASK(key); 50 | uint32_t hash = hash_code(ht, k); 51 | size_t nitems = ht->size; 52 | while (nitems-- != 0) { 53 | if (ht->items[hash].key == k) { 54 | return &ht->items[hash]; 55 | } 56 | hash = next_hash(ht, hash); 57 | } 58 | return NULL; 59 | } 60 | 61 | int hasht_insert(struct hasht *ht, const uint32_t key, void *data) 62 | { 63 | const uint32_t k = KEY_MASK(key); 64 | uint32_t hash = hash_code(ht, k); 65 | 66 | if (ht->size == ht->max_size) { 67 | return -EHASHT_FULL; 68 | } 69 | 70 | if (hasht_search(ht, key) == NULL) { 71 | while (ht->items[hash].item != NULL) { 72 | hash = next_hash(ht, hash); 73 | } 74 | ht->items[hash].key = k; 75 | ht->items[hash].item = data; 76 | ht->size++; 77 | return key; 78 | } 79 | return -EHASHT_DUP; 80 | } 81 | 82 | void hasht_init(struct hasht *ht) 83 | { 84 | for (size_t i = 0; i < ht->max_size; i++) { 85 | ht->items[i].key = KEY_UNDEF_VAL; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/hasht.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #ifndef __HASHT_H__ 4 | #define __HASHT_H__ 5 | 6 | #define EHASHT_EMPTY 1 7 | #define EHASHT_FULL 2 8 | #define EHASHT_NFOUND 3 9 | #define EHASHT_DUP 4 10 | 11 | #define HASHT_INIT(_items, maxsize) \ 12 | { \ 13 | .items = _items, .max_size = maxsize, .size = 0, \ 14 | } 15 | 16 | struct hasht_entry { 17 | uint32_t key; 18 | void *item; 19 | }; 20 | 21 | struct hasht { 22 | struct hasht_entry *items; 23 | size_t max_size; 24 | size_t size; 25 | }; 26 | 27 | int hasht_insert(struct hasht *ht, const uint32_t key, void *data); 28 | struct hasht_entry *hasht_search(struct hasht *ht, const uint32_t key); 29 | int hasht_delete(struct hasht *ht, const uint32_t key); 30 | void hasht_clear(struct hasht *ht); 31 | void hasht_init(struct hasht *ht); 32 | 33 | #endif /* __HASHT_H__ */ 34 | -------------------------------------------------------------------------------- /src/j1939.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | /* 4 | * J1939 Message Construction 5 | * 6 | * J1939 messages are built on top of CAN 2.0b and make specific use of 7 | * extended frames. Extended frames use a 29-bit identifier instead of the 8 | * common 11-bit identifier. 9 | * 10 | * |======================= CAN IDENTIFIER (29 bit) =======================| 11 | * | Priority [3] | Parameter Group Number (PGN) [18] | Source Address [8] | 12 | * |-----------------------------------------------------------------------| 13 | * | EDP [1] | DP [1] | PDU Format [8] | PDU Specific / Destination [8] | 14 | * |=======================================================================| 15 | * 16 | * The first three bits are the priority field. 17 | * This field sets the message’s priority on the network and helps ensure 18 | * messages with higher importance are sent/received before lower priority 19 | * messages. Zero is the highest priority. 20 | * 21 | * Using the Extended Data Page bit (EDP) and the Data Page bit (DP), 22 | * four different "Data pages" for J1939 messages (Parameter Group) can be 23 | * selected: 24 | * 25 | * EDP | DP | Description 26 | * ======================================= 27 | * 0 | 0 | SAE J1939 Parameter Groups 28 | * 0 | 1 | NMEA2000 defined 29 | * 1 | 0 | SAE J1939 reserved 30 | * 1 | 1 | ISO 15765-3 defined 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include "j1939.h" 37 | #include "compiler.h" 38 | #include "pgn.h" 39 | 40 | uint32_t j1939_pgn2id(const j1939_pgn_t pgn, const uint8_t priority, 41 | const uint8_t src) 42 | { 43 | return (((uint32_t)priority & PRGN_PRIORITY_MASK) << 26) | 44 | ((pgn & PGN_MASK) << 8) | (uint32_t)src; 45 | } 46 | 47 | int j1939_send(const j1939_pgn_t pgn, const uint8_t priority, const uint8_t src, 48 | const uint8_t dst, uint8_t *data, const uint32_t len) 49 | { 50 | uint32_t id; 51 | 52 | if (unlikely(!j1939_valid_priority(priority))) { 53 | return -1; 54 | } 55 | 56 | id = j1939_pgn2id(pgn, priority, src); 57 | 58 | /* If PGN is peer-to-peer, add destination address to the ID */ 59 | if (j1939_pdu_is_p2p(pgn)) { 60 | id = (id & 0xFFFF00FFu) | ((uint32_t)dst << 8); 61 | } 62 | 63 | return j1939_cansend(id, data, len); 64 | } 65 | 66 | int j1939_receive(j1939_pgn_t *pgn, uint8_t *priority, uint8_t *src, 67 | uint8_t *dst, uint8_t *data, uint32_t *len) 68 | { 69 | uint32_t id; 70 | int received; 71 | 72 | if (unlikely(!pgn || !priority || !src || !dst || !data || !len)) { 73 | return -1; 74 | } 75 | 76 | received = j1939_canrcv(&id, data); 77 | 78 | if (received >= 0) { 79 | *len = received; 80 | *priority = (id & 0x1C000000u) >> 26; 81 | *pgn = id; 82 | *src = id & 0x000000FFu; 83 | 84 | /* 85 | * if PGN is peer-to-peer, remove destination from 86 | * PGN itself and calculate destination address 87 | */ 88 | if (j1939_pdu_is_p2p(*pgn)) { 89 | *pgn = id & 0xFFFF00FFu; 90 | *dst = (id >> 8) & 0x000000FFu; 91 | } else { 92 | *dst = ADDRESS_NULL; 93 | } 94 | *pgn = (*pgn >> 8) & PGN_MASK; 95 | } 96 | 97 | return received; 98 | } 99 | -------------------------------------------------------------------------------- /src/j1939_ecu.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | /** 4 | * J1939: Electronic Control Unit (ECU) holding one or more 5 | * Controller Applications (CAs). 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include "atomic.h" 11 | #include "compat.h" 12 | #include "compiler.h" 13 | #include "j1939.h" 14 | #include "pgn.h" 15 | #include "pgn_pool.h" 16 | #include "j1939_time.h" 17 | #include "session.h" 18 | 19 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) 20 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 21 | 22 | #define DLC_MAX 8u /*> 8, 55 | num_packets, 56 | 0xFF, 57 | PGN_SPECIFIC(TP_CM), 58 | PGN_FORMAT(TP_CM), 59 | PGN_DATA_PAGE(TP_CM), 60 | }; 61 | 62 | return j1939_send(TP_CM, priority, src, dst, data, ARRAY_SIZE(data)); 63 | } 64 | 65 | static int defrag_send(uint16_t size, const uint8_t priority, const uint8_t src, 66 | const uint8_t dest, uint8_t *data) 67 | { 68 | int ret; 69 | uint8_t seqno = 1; 70 | uint8_t frame[DLC_MAX]; 71 | 72 | while (size > 0) { 73 | frame[0] = seqno; 74 | seqno++; 75 | 76 | if (size >= DEFRAG_DLC_MAX) { 77 | memcpy(&frame[1], data, DEFRAG_DLC_MAX); 78 | size -= DEFRAG_DLC_MAX; 79 | data += DEFRAG_DLC_MAX; 80 | } else { 81 | memcpy(&frame[1], data, size); 82 | memset(&frame[1 + size], J1930_NA_8, 83 | DEFRAG_DLC_MAX - size); 84 | size = 0; 85 | } 86 | 87 | ret = j1939_send(TP_DT, priority, src, dest, frame, 88 | ARRAY_SIZE(frame)); 89 | if (ret < 0) { 90 | return ret; 91 | } 92 | 93 | uint32_t now = j1939_get_time(); 94 | while (!elapsed(now, SEND_PERIOD)) { 95 | #if defined(TP_TASK_YIELD) 96 | j1939_task_yield(); 97 | #endif 98 | } 99 | } 100 | return 0; 101 | } 102 | 103 | int send_tp_bam(const uint8_t priority, const uint8_t src, uint8_t *data, 104 | const uint16_t len) 105 | { 106 | int ret; 107 | uint8_t num_packets = num_packet_from_size(len); 108 | uint8_t bam[DLC_MAX] = { 109 | CONN_MODE_BAM, 110 | len & 0x00FF, 111 | len >> 8, 112 | num_packets, 113 | 0xFF, 114 | PGN_SPECIFIC(BAM), 115 | PGN_FORMAT(BAM), 116 | PGN_DATA_PAGE(BAM), 117 | }; 118 | 119 | if (unlikely(len > J1939_MAX_DATA_LEN)) { 120 | return -J1939_EARGS; 121 | } 122 | 123 | ret = j1939_send(TP_CM, priority, src, ADDRESS_GLOBAL, bam, DLC_MAX); 124 | if (ret < 0) { 125 | return ret; 126 | } 127 | 128 | return defrag_send(len, priority, src, ADDRESS_GLOBAL, data); 129 | } 130 | 131 | static int send_abort(const uint8_t src, const uint8_t dst, 132 | const uint8_t reason) 133 | { 134 | uint8_t data[DLC_MAX] = { 135 | CONN_MODE_ABORT, 136 | reason, 137 | 0xFF, 138 | 0xFF, 139 | 0xFF, 140 | PGN_SPECIFIC(TP_CM), 141 | PGN_FORMAT(TP_CM), 142 | PGN_DATA_PAGE(TP_CM), 143 | }; 144 | return j1939_send(TP_DT, J1939_PRIORITY_LOW, src, dst, data, 145 | ARRAY_SIZE(data)); 146 | } 147 | 148 | static int tp_cts_received(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 149 | uint8_t dest, uint8_t *data, uint8_t len) 150 | { 151 | struct j1939_session *sess = j1939_session_search_addr(dest, src); 152 | if (sess == NULL) { 153 | return -1; 154 | } 155 | 156 | sess->cts_num_packets = data[1]; 157 | sess->cts_next_packet = data[2]; 158 | atomic_set(&sess->cts_done, 1); 159 | return 1; 160 | } 161 | 162 | static uint8_t wait_tp_cts(const j1939_pgn_t pgn, const uint8_t src, 163 | const uint8_t dst) 164 | { 165 | uint8_t ret; 166 | struct j1939_session *sess = j1939_session_search_addr(src, dst); 167 | if (sess == NULL) { 168 | return REASON_NO_RESOURCE; 169 | } 170 | 171 | sess->timeout = j1939_get_time(); 172 | while (!elapsed(sess->timeout, T3) && !atomic_get(&sess->cts_done)) { 173 | #if defined(TP_TASK_YIELD) 174 | j1939_task_yield(); 175 | #endif 176 | } 177 | 178 | ret = atomic_get(&sess->cts_done) ? REASON_NONE : REASON_TIMEOUT; 179 | atomic_set(&sess->cts_done, 0); 180 | return ret; 181 | } 182 | 183 | static int tp_eom_ack_received(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 184 | uint8_t dest, uint8_t *data, uint8_t len) 185 | { 186 | int ret = 0; 187 | struct j1939_session *sess = j1939_session_search_addr(dest, src); 188 | if (sess == NULL) { 189 | ret = -J1939_ENO_RESOURCE; 190 | goto err; 191 | } 192 | 193 | if (elapsed(sess->timeout, T3)) { 194 | ret = -J1939_ETIMEOUT; 195 | goto err; 196 | } 197 | 198 | atomic_set(&sess->eom_ack, 1); 199 | uint16_t eom_ack_size = htobe16((data[1] << 8) | data[2]); 200 | uint8_t eom_ack_num_packets = data[3]; 201 | 202 | if (sess->eom_ack_size != eom_ack_size || 203 | sess->eom_ack_num_packets != eom_ack_num_packets) { 204 | ret = -J1939_EINCOMPLETE; 205 | goto err; 206 | } 207 | 208 | j1939_session_close(dest, src); 209 | return 0; 210 | 211 | err: 212 | if (user_error_cb) { 213 | user_error_cb(pgn, priority, src, dest, ret); 214 | } 215 | return ret; 216 | } 217 | 218 | static int send_tp_eom_ack(const uint8_t src, const uint8_t dst, 219 | const uint16_t size, const uint8_t num_packets) 220 | { 221 | uint8_t data[DLC_MAX] = { 222 | CONN_MODE_EOM_ACK, 223 | size & 0x00FF, 224 | (size >> 8), 225 | num_packets, 226 | 0xFF, 227 | PGN_SPECIFIC(TP_CM), 228 | PGN_FORMAT(TP_CM), 229 | PGN_DATA_PAGE(TP_CM), 230 | }; 231 | return j1939_send(TP_CM, J1939_PRIORITY_LOW, dst, src, data, 232 | ARRAY_SIZE(data)); 233 | } 234 | 235 | int j1939_tp(j1939_pgn_t pgn, const uint8_t priority, const uint8_t src, 236 | const uint8_t dst, uint8_t *data, const uint16_t len) 237 | { 238 | bool initiated = false; 239 | int ret; 240 | struct j1939_session *sess; 241 | uint8_t num_packets, reason; 242 | uint16_t size; 243 | 244 | if (unlikely(len > J1939_MAX_DATA_LEN)) { 245 | return -J1939_EWRONG_DATA_LEN; 246 | } 247 | 248 | /* single frame, send directly */ 249 | if (len <= DLC_MAX) { 250 | return j1939_send(pgn, priority, src, dst, data, len); 251 | } 252 | 253 | sess = j1939_session_open(src, dst); 254 | if (sess == NULL) { 255 | return -J1939_ENO_RESOURCE; 256 | } 257 | 258 | num_packets = num_packet_from_size(len); 259 | 260 | sess->eom_ack_num_packets = num_packets; 261 | sess->eom_ack_size = len; 262 | 263 | /* Send Request To Send (RTS) */ 264 | ret = send_tp_rts(priority, src, dst, len, num_packets); 265 | if (unlikely(ret < 0)) { 266 | goto out; 267 | } 268 | 269 | uint8_t np = num_packets; 270 | while (np > 0) { 271 | /* Wait Clear To Send (CTS) */ 272 | reason = wait_tp_cts(TP_CM, src, dst); 273 | if (unlikely(reason != REASON_NONE)) { 274 | if (initiated) { 275 | ret = send_abort(src, dst, reason); 276 | } else { 277 | ret = -J1939_EBUSY; 278 | } 279 | goto out; 280 | } else { 281 | initiated = true; 282 | } 283 | 284 | np -= sess->cts_num_packets; 285 | size = MIN(sess->cts_num_packets * DEFRAG_DLC_MAX, len); 286 | ret = defrag_send(size, J1939_PRIORITY_LOW, src, dst, data); 287 | if (unlikely(ret < 0)) { 288 | goto out; 289 | } 290 | } 291 | ret = send_tp_eom_ack(src, dst, len, num_packets); 292 | 293 | out: 294 | j1939_session_close(src, dst); 295 | return ret; 296 | } 297 | 298 | int j1939_address_claimed(uint8_t src, ecu_name_t name) 299 | { 300 | const uint8_t dest = 0xFE; 301 | uint64_t n = htobe64(name.value); 302 | return j1939_send(AC, J1939_PRIORITY_HIGH, src, dest, (uint8_t *)&n, 303 | DLC_MAX); 304 | } 305 | 306 | int j1939_cannot_claim_address(ecu_name_t name) 307 | { 308 | uint64_t n = htobe64(name.value); 309 | return j1939_send(AC, J1939_PRIORITY_DEFAULT, ADDRESS_NOT_CLAIMED, 310 | ADDRESS_GLOBAL, (uint8_t *)&n, 8); 311 | } 312 | 313 | int j1939_address_claim(const uint8_t src, ecu_name_t name) 314 | { 315 | int ret; 316 | uint32_t ac = AC; 317 | 318 | /* Send Request for Address Claimed */ 319 | ret = j1939_send(RAC, J1939_PRIORITY_DEFAULT, src, ADDRESS_GLOBAL, 320 | (uint8_t *)&ac, 3); 321 | if (unlikely(ret < 0)) { 322 | return ret; 323 | } 324 | 325 | uint64_t n = htobe64(name.value); 326 | return j1939_send(AC, J1939_PRIORITY_DEFAULT, src, ADDRESS_GLOBAL, 327 | (uint8_t *)&n, DLC_MAX); 328 | } 329 | 330 | int j1939_send_tp_cts(const uint8_t src, const uint8_t dst, 331 | const uint8_t num_packets, const uint8_t next_packet) 332 | { 333 | uint8_t data[DLC_MAX] = { 334 | CONN_MODE_CTS, 335 | num_packets, 336 | next_packet, 337 | 0xFF, 338 | 0xFF, 339 | PGN_SPECIFIC(TP_CM), 340 | PGN_FORMAT(TP_CM), 341 | PGN_DATA_PAGE(TP_CM), 342 | }; 343 | return j1939_send(TP_CM, J1939_PRIORITY_LOW, src, dst, data, 344 | ARRAY_SIZE(data)); 345 | } 346 | 347 | static int pgn_abort(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 348 | uint8_t dest, uint8_t *data, uint8_t len) 349 | { 350 | if (user_error_cb) { 351 | user_error_cb(pgn, priority, src, dest, data[1]); 352 | } 353 | return 0; 354 | } 355 | 356 | static int request_to_send(j1939_pgn_t pgn, uint8_t priority, uint8_t src, 357 | uint8_t dest, uint8_t *data, uint8_t len) 358 | { 359 | struct j1939_session *sess = j1939_session_open(src, dest); 360 | if (sess == NULL) { 361 | return -1; 362 | } 363 | 364 | sess->tp_tot_size = htobe16((data[1] << 8) | data[2]); 365 | sess->tp_num_packets = num_packet_from_size(sess->tp_tot_size); 366 | sess->eom_ack_num_packets = sess->tp_num_packets; 367 | sess->eom_ack_size = sess->tp_tot_size; 368 | return j1939_send_tp_cts(dest, src, sess->tp_num_packets, 0); 369 | } 370 | 371 | static int _rcv_tp(j1939_pgn_t pgn, uint8_t priority, uint8_t src, uint8_t dest, 372 | uint8_t *data, uint8_t len) 373 | { 374 | struct j1939_session *sess = j1939_session_search_addr(src, dest); 375 | 376 | if (sess == NULL) { 377 | return -1; 378 | } 379 | 380 | if (sess->tp_num_packets == 1) { 381 | /* Next packet expected to be EOM ACK */ 382 | atomic_set(&sess->eom_ack, 0); 383 | sess->timeout = j1939_get_time(); 384 | } 385 | sess->tp_num_packets--; 386 | 387 | if (user_rcv_tp_callback) { 388 | user_rcv_tp_callback(pgn, priority, src, dest, data, len); 389 | } 390 | 391 | return 0; 392 | } 393 | 394 | int j1939_setup(pgn_callback_t rcv_tp, pgn_error_cb_t err_cb) 395 | { 396 | user_rcv_tp_callback = rcv_tp; 397 | user_error_cb = err_cb; 398 | 399 | pgn_pool_init(); 400 | pgn_register(TP_CM, CONN_MODE_CTS, tp_cts_received); 401 | pgn_register(TP_CM, CONN_MODE_ABORT, pgn_abort); 402 | pgn_register(TP_CM, CONN_MODE_RTS, request_to_send); 403 | pgn_register(TP_CM, CONN_MODE_EOM_ACK, tp_eom_ack_received); 404 | pgn_register(TP_DT, 0, _rcv_tp); 405 | 406 | j1939_session_init(); 407 | return 0; 408 | } 409 | 410 | int j1939_dispose(void) 411 | { 412 | pgn_deregister_all(); 413 | return 0; 414 | } 415 | 416 | __weak void j1939_task_yield(void) 417 | { 418 | } 419 | -------------------------------------------------------------------------------- /src/j1939_time.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __TIME_H__ 3 | #define __TIME_H__ 4 | 5 | bool elapsed(const uint32_t t, const uint32_t timeout); 6 | 7 | #endif /* __TIME_H__ */ 8 | -------------------------------------------------------------------------------- /src/pgn.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #ifndef __PGN_H__ 4 | #define __PGN_H__ 5 | 6 | #define PGN_FORMAT(_x) (((_x) >> 8) & 0xffu) 7 | #define PGN_SPECIFIC(_x) ((_x) & 0xffu) 8 | #define PGN_DATA_PAGE(_x) (((_x) >> 17) & 0x1u) 9 | 10 | #define PRGN_PRIORITY_MASK 0x3u 11 | #define PGN_MASK 0x3FFFFu 12 | #define PGN_FROM(_f, _s, _dp) \ 13 | (((_dp) & 0x1u) << 17) | (((_f) & 0xffu) << 8) | ((_s) & 0xffu) 14 | 15 | #define BAM 0x00FEECu 16 | #define TP_CM 0x00EC00u 17 | #define TP_DT 0x00EB00u 18 | /** @brief Address Claimed */ 19 | #define AC 0x00EE00u 20 | /** @brief Request for Address Claimed */ 21 | #define RAC 0x00EA00u 22 | 23 | /** @brief Check if PDU format < 240 (peer-to-peer) */ 24 | static inline bool j1939_pdu_is_p2p(const j1939_pgn_t pgn) 25 | { 26 | return PGN_FORMAT(pgn) < 240u; 27 | } 28 | 29 | /** @brief Check if PDU format >= 240 (broadcast) */ 30 | static inline bool j1939_pdu_is_broadcast(const j1939_pgn_t pgn) 31 | { 32 | return !j1939_pdu_is_p2p(pgn); 33 | } 34 | 35 | #endif /* __PGN_H__ */ 36 | -------------------------------------------------------------------------------- /src/pgn_pool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "pgn_pool.h" 5 | #include "pgn.h" 6 | #include "config.h" 7 | #include "hasht.h" 8 | 9 | #if !defined(PGN_POOL_SIZE) 10 | #error "PGN_POOL_SIZE not defined" 11 | #endif 12 | 13 | static struct hasht_entry entries[PGN_POOL_SIZE]; 14 | static struct hasht pgn_pool = HASHT_INIT(entries, PGN_POOL_SIZE); 15 | 16 | static inline uint32_t make_key(uint32_t pgn, uint8_t code) 17 | { 18 | return pgn | (code << 24); 19 | } 20 | 21 | void pgn_pool_init(void) 22 | { 23 | hasht_init(&pgn_pool); 24 | } 25 | 26 | int pgn_register(const uint32_t pgn, const uint8_t code, 27 | const pgn_callback_t cb) 28 | { 29 | return hasht_insert(&pgn_pool, make_key(pgn, code), cb); 30 | } 31 | 32 | int pgn_deregister(const uint32_t pgn, const uint8_t code) 33 | { 34 | return hasht_delete(&pgn_pool, make_key(pgn, code)); 35 | } 36 | 37 | void pgn_deregister_all(void) 38 | { 39 | hasht_clear(&pgn_pool); 40 | } 41 | 42 | int pgn_pool_receive(void) 43 | { 44 | struct hasht_entry *entry; 45 | j1939_pgn_t pgn; 46 | uint8_t code, src, priority, dest; 47 | uint32_t len; 48 | uint8_t data[8]; 49 | int ret; 50 | 51 | ret = j1939_receive(&pgn, &priority, &src, &dest, data, &len); 52 | if (ret > 0) { 53 | code = (pgn == TP_CM) ? data[0] : 0; 54 | entry = hasht_search(&pgn_pool, make_key(pgn, code)); 55 | if (entry && entry->item) { 56 | pgn_callback_t cb = (pgn_callback_t)entry->item; 57 | return (*cb)(pgn, priority, src, dest, data, len); 58 | } 59 | } 60 | return ret; 61 | } -------------------------------------------------------------------------------- /src/pgn_pool.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __PGN_POOL_H__ 3 | #define __PGN_POOL_H__ 4 | 5 | #include "j1939.h" 6 | 7 | #define ERR_NONE 0 8 | #define ERR_TOO_MANY_PGN 1 9 | #define ERR_PGN_UNKNOWN 2 10 | #define ERR_DUPLICATE_PGN 3 11 | 12 | void pgn_pool_init(void); 13 | int pgn_register(const uint32_t pgn, uint8_t code, pgn_callback_t cb); 14 | int pgn_deregister(const uint32_t pgn, uint8_t code); 15 | void pgn_deregister_all(void); 16 | int pgn_pool_receive(void); 17 | 18 | #endif /* __PGN_POOL_H__ */ 19 | -------------------------------------------------------------------------------- /src/session.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #ifndef __SESSION_H__ 4 | #define __SESSION_H__ 5 | 6 | struct j1939_session { 7 | int8_t id; 8 | uint8_t cts_num_packets; 9 | uint8_t cts_next_packet; 10 | uint16_t eom_ack_size; 11 | uint8_t eom_ack_num_packets; 12 | uint8_t tp_num_packets; 13 | uint16_t tp_tot_size; 14 | atomic_t cts_done; 15 | atomic_t eom_ack; 16 | uint32_t timeout; 17 | }; 18 | 19 | void j1939_session_init(void); 20 | uint16_t j1939_session_hash(const uint8_t s, const uint8_t d); 21 | struct j1939_session *j1939_session_open(const uint8_t src, const uint8_t dest); 22 | int j1939_session_close(const uint8_t src, const uint8_t dest); 23 | struct j1939_session *j1939_session_search(const uint16_t id); 24 | struct j1939_session *j1939_session_search_addr(const uint16_t src, 25 | const uint16_t dst); 26 | 27 | #endif /* __SESSION_H__ */ 28 | -------------------------------------------------------------------------------- /src/sessions.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include "atomic.h" 7 | #include "hasht.h" 8 | #include "session.h" 9 | 10 | #define SESSION_UNDEF (-1) 11 | #if !defined(MAX_J1939_SESSIONS) 12 | #error "MAX_J1939_SESSIONS not defined" 13 | #endif 14 | 15 | static struct j1939_session session_dict[MAX_J1939_SESSIONS]; 16 | static struct hasht_entry entries[MAX_J1939_SESSIONS]; 17 | static struct hasht sessions = HASHT_INIT(entries, MAX_J1939_SESSIONS); 18 | 19 | uint16_t j1939_session_hash(const uint8_t s, const uint8_t d) 20 | { 21 | return (s << 8) | d; 22 | } 23 | 24 | void j1939_session_init(void) 25 | { 26 | hasht_init(&sessions); 27 | for (size_t i = 0; i < MAX_J1939_SESSIONS; i++) { 28 | session_dict[i].id = SESSION_UNDEF; 29 | } 30 | } 31 | 32 | static struct j1939_session *assign_session(void) 33 | { 34 | for (size_t i = 0; i < MAX_J1939_SESSIONS; i++) { 35 | if (session_dict[i].id < 0) { 36 | memset(&session_dict[i], 0, 37 | sizeof(struct j1939_session)); 38 | session_dict[i].id = i; 39 | return &session_dict[i]; 40 | } 41 | } 42 | return NULL; 43 | } 44 | 45 | struct j1939_session *j1939_session_open(const uint8_t src, const uint8_t dest) 46 | { 47 | struct j1939_session *sess; 48 | uint16_t key = j1939_session_hash(src, dest); 49 | if (j1939_session_search(key) == NULL) { 50 | sess = assign_session(); 51 | if (sess) { 52 | hasht_insert(&sessions, key, sess); 53 | return sess; 54 | } 55 | } 56 | return NULL; 57 | } 58 | 59 | struct j1939_session *j1939_session_search_addr(const uint16_t src, 60 | const uint16_t dst) 61 | { 62 | uint16_t key = j1939_session_hash(src, dst); 63 | return j1939_session_search(key); 64 | } 65 | 66 | struct j1939_session *j1939_session_search(const uint16_t id) 67 | { 68 | struct hasht_entry *s; 69 | s = hasht_search(&sessions, id); 70 | return s != NULL ? (struct j1939_session *)s->item : NULL; 71 | } 72 | 73 | int j1939_session_close(const uint8_t src, const uint8_t dest) 74 | { 75 | struct j1939_session *sess; 76 | uint16_t key = j1939_session_hash(src, dest); 77 | sess = j1939_session_search(key); 78 | if (sess) { 79 | sess->id = SESSION_UNDEF; 80 | return hasht_delete(&sessions, key); 81 | } 82 | return -1; 83 | } 84 | -------------------------------------------------------------------------------- /src/time.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "j1939_time.h" 5 | #include "j1939.h" 6 | 7 | bool elapsed(const uint32_t t, const uint32_t timeout) 8 | { 9 | uint32_t delta; 10 | uint32_t now = j1939_get_time(); 11 | 12 | if (now >= t) { 13 | delta = now - t; 14 | } else { 15 | delta = UINT32_MAX - t + now; 16 | } 17 | 18 | return delta > timeout; 19 | } 20 | --------------------------------------------------------------------------------