├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.md ├── astyle ├── astyle-all.sh ├── conf └── astylerc ├── docs └── RELEASES.md ├── rm-driver.sh ├── run-test-gen.bat ├── run-test-gen.sh ├── src ├── CMakeLists.txt ├── app.cpp ├── app.h ├── codegen │ ├── c-main-generator.cpp │ ├── c-main-generator.h │ ├── c-sigprinter.cpp │ ├── c-sigprinter.h │ ├── c-util-generator.cpp │ ├── c-util-generator.h │ ├── conditional-tree.cpp │ ├── conditional-tree.h │ ├── config-generator.cpp │ ├── config-generator.h │ ├── filewriter.cpp │ ├── filewriter.h │ ├── fs-creator.cpp │ ├── fs-creator.h │ ├── mon-generator.cpp │ ├── mon-generator.h │ └── version.h ├── conf-and-limits.h ├── helpers │ ├── formatter.cpp │ └── formatter.h ├── maincli.cpp ├── options-parser.cpp ├── options-parser.h ├── parser │ ├── dbclineparser.cpp │ ├── dbclineparser.h │ ├── dbcscanner.cpp │ └── dbcscanner.h ├── tests │ ├── args-test.cpp │ ├── bitext-test.cpp │ ├── dbcline-test.cpp │ └── testapi.h └── types │ ├── attributes.h │ ├── c-expr.h │ ├── comment.h │ ├── message.h │ └── outfile.h └── test ├── gencode ├── butl │ ├── bcm_testdb-binutil.c │ ├── bcm_testdb-binutil.h │ ├── bms_testdb-binutil.c │ ├── bms_testdb-binutil.h │ ├── eps_testdb-binutil.c │ ├── eps_testdb-binutil.h │ ├── esp_testdb-binutil.c │ └── esp_testdb-binutil.h ├── conf │ ├── dbccodeconf.h │ └── testdb-config.h ├── inc │ └── canmonitorutil.h ├── lib │ ├── testdb-fmon.h │ ├── testdb.c │ └── testdb.h └── usr │ └── testdb-fmon.c └── testdb.dbc /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/build* 2 | loc-test* 3 | .vscode 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CODERDBC 2 | 3 | Coderdbc is a CLI utility for generating C code from DBC CAN matrix files 4 | 5 | ### Features 6 | - ***Pack*** and ***Unpack*** functions for conversion signals to CAN payload raw data and vice verse 7 | - ***Node based*** Receive function _(each node (ECU) has its own ***Receive*** function according to its DBC configuration)_ 8 | - Automation on monitoring functions: CRC, counter and missing tests 9 | - Optional source code generation _(the generation of readonly and configuration files can be avoided)_ 10 | - Flexible setup via driver configuration _(see comments in source code for details)_ 11 | 12 | ## Build and run 13 | 14 | For building project you need to have cmake and c++ development toolkit in your system 15 | 1 download source code: 16 | ```sh 17 | git clone https://github.com/astand/c-coderdbc.git coderdbc 18 | ``` 19 | Go to the source code directory: 20 | ```sh 21 | cd coderdbc 22 | ``` 23 | Run cmake configuration to 'build' directory: 24 | ```sh 25 | cmake -S src -B build 26 | ``` 27 | Run cmake build: 28 | ```sh 29 | cmake --build build --config release 30 | ``` 31 | Go to the build directory and run: 32 | ```sh 33 | cd build 34 | ./coderdbc --help 35 | ``` 36 | 37 | Help information with main instructions about using the tool will be printed 38 | 39 | ## Driver functionality description 40 | 41 | The source code package includes the following source files (presuming that the dbc driver name is "ecudb"): 42 | 43 | ecudb.c / ecudb.h (1) RO / lib 44 | 45 | Pair of the main driver which contains all dbc frames structs / pack functions / unpack functions declarations. These source files preferably to place in the share/library directory. This part of the package is non-changable and has no any data, so can be used across multi projects. 46 | 47 | ecudb-fmon.h (2) RO / lib 48 | 49 | Fmon header is a readonly part of monitoring part of the package. It contains the list of functions for CAN message validation. Those functions should be defined in the scope of user code and can be optionally used in unpack messages. This file is preferably to place in the share/library directory next to the main driver source files. 50 | 51 | ecudb-fmon.c (3) app 52 | 53 | User specific part of monitoring functionality. If monitoring is fully enabled user code must define all the monitoring functions. This file is a part of the scope of user code. 54 | 55 | ecudb-config.h (4) app / inc* 56 | 57 | An application specific configuration file for enabling features in the main driver. If there are a few projects (applications) which include a single main driver (1,2) then each project has to have its own copy of this configuration. Source code (1,2) includes this configuration. If a few dbc matrix is in use in your application then for each of (1,2) specific configuration file must be presented. 58 | 59 | dbccodeconf.h (5) app / inc 60 | 61 | Application specific configuration file. This file might include "CanFrame" definition, sigfloat_t typedef and binutil macros which enables rx and tx structures allocation inside ecudb-binutil.c. Each project has to have its own copy of this configuration (see template dbccodeconf.h). Source code (4,6) includes this configuration. 62 | 63 | ecudb-binutil.c / ecudb-binutil.h (6) RO / app 64 | 65 | The part which is used for generalization CAN frame flow receiving and unpacking. It also optionally can allocate CAN frame tx/rx structs. 66 | 67 | canmonitorutil.h (7) lib 68 | 69 | General definitions for monitoring feature. The source file can be place to the share/library directory. 70 | 71 | ----------------------------------------------------------------------------------------------- 72 | 73 | *inc - file location have to be added to project include path. 74 | 75 | ## generation options 76 | 77 | There are several available generation option, use '-help' option for details 78 | -------------------------------------------------------------------------------- /astyle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astand/c-coderdbc/04e4c420be51676b075ee90704eb745fa89aa334/astyle -------------------------------------------------------------------------------- /astyle-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OPTIONS="--options=conf/astylerc" 4 | 5 | RETURN=0 6 | ASTYLE='./astyle' 7 | if [ $? -ne 0 ]; then 8 | echo "[!] astyle not installed. Unable to check source file format policy." >&2 9 | exit 1 10 | fi 11 | 12 | FILES=`find . | grep -P "^(.*\/src).*\.(c|cpp|h)$"` 13 | for FILE in $FILES; do 14 | # compare files 15 | # $ASTYLE $OPTIONS < $FILE | cmp -s $FILE - 16 | # if [ $? -ne 0 ]; then 17 | # echo "[!] $FILE does not respect the agreed coding style." >&2 18 | # RETURN=1 19 | # fi 20 | # forcibly format file 21 | $ASTYLE $OPTIONS $FILE 22 | # git add $FILE 23 | echo $FILE 24 | done 25 | 26 | if [ $RETURN -eq 1 ]; then 27 | echo "" >&2 28 | echo "Make sure you have run astyle with the following options:" >&2 29 | echo $OPTIONS >&2 30 | fi 31 | 32 | exit $RETURN 33 | -------------------------------------------------------------------------------- /conf/astylerc: -------------------------------------------------------------------------------- 1 | --suffix=none 2 | --style=allman 3 | --attach-inlines 4 | --indent-switches 5 | --indent-preproc-define 6 | --indent=spaces=2 7 | --min-conditional-indent=2 8 | --break-blocks 9 | --pad-oper 10 | --pad-header 11 | --unpad-paren 12 | --align-pointer=type 13 | --align-reference=type 14 | --indent-modifiers 15 | --attach-classes 16 | --break-after-logical 17 | --keep-one-line-statements 18 | --indent-after-parens 19 | --add-braces 20 | --max-code-length=120 21 | --max-continuation-indent=120 -------------------------------------------------------------------------------- /docs/RELEASES.md: -------------------------------------------------------------------------------- 1 | # C-Coderdbc 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | 7 | ## [Unreleased] 8 | 9 | 10 | ## [v3.1] - 2024-06-30 11 | 12 | ### Added 13 | 14 | - CAN FD frames with max DLC (64 bytes) are supported 15 | - Minor type cast improvements in the sign extension function (\_\_ext_sig\_\_) 16 | - (INFR) Test generation script takes one argument: release/debug to specify particular binary call 17 | - istream handling improved in dbcscanner 18 | - The head information with: coderdbc version, dbc file name ([issue #28](https://github.com/astand/c-coderdbc/issues/28)) 19 | - General source file (not driver related) have only coderdbc version and date if enabled (see next chages) 20 | - The generation date can be added to head information with '-gendate' argument 21 | - The final output directory path is extended by the driver name when '-driverdir' argument is passed 22 | 23 | ### Fixed 24 | - Head part info conversion to source code comments in mon-generator module 25 | - FindVersion function improved 26 | - Missing comments from dbc for signals based on real data types (floating-point variables, denoted by '_ro' and '_phys'). 27 | 28 | ## [v3.0] - 2023-10-09 29 | 30 | ### Added 31 | 32 | - Added explicit type casting on: 33 | * Writing data bytes, IDE, DLC and MsgId on pack step 34 | * Explicit unsigned nature ('U') to message CANID macro value 35 | - ```-Wpedantic``` doesn't complain anymore on generated code (tested on test.dbc only) 36 | - Added 'define' with value for filling initial value in frame's bytes before packing signals. 37 | The value can be set in the user scope configuration file (driver-config) 38 | - Added enhanced DLC handling: 39 | * Added max detected DLC value (as a macro in main driver) 40 | * User can specify its own max DLC value if necessary (by setting corresponding macro in driver-config file) 41 | * Functions use new 'VALIDATE_DLC' test when checks the limit of frame data bytes count 42 | 43 | ### Changed 44 | 45 | - Include files in quotes instead of angle brackets 46 | - This changelog file format has been changed 47 | - Added style option file 48 | - Changed git flow 49 | - README.md changed 50 | 51 | ### Fixed 52 | 53 | - No more struct, pack and unpack for frames with no signals (empty frames). IDs and frame related info is left 54 | - Fixed an issue in 'findversion' function 55 | - Fixed issue on appending new string which is empty 56 | 57 | ## [v2.9] - 2023-01-27 58 | 59 | ### Changed 60 | 61 | - prt_double refactored 62 | 63 | ## [v2.8] - 2023-01-27 64 | 65 | ### Fixed 66 | 67 | - Floating factor/offset values handling (incorrect rounding in some cases). 68 | 69 | ## [v2.7] - 2023-01-15 70 | 71 | ### Fixed 72 | 73 | - Removed signal conversion macroses duplication ([issue #11](https://github.com/astand/c-coderdbc/issues/18)) 74 | - More precise floating factor/offset values handling ([issue #10](https://github.com/astand/c-coderdbc/issues/20)) 75 | 76 | ### Added 77 | 78 | - Better print for floating factor/offset values (removed tailing zeros) 79 | - Signals with too low factor/offset values (less than 0.000000001) are considered as plain integer signals, it is up to client to handle them 80 | 81 | ## [v2.6] - 2022-09-29 82 | 83 | ### Fixed 84 | 85 | - [issue #9](https://github.com/astand/c-coderdbc/issues/16) found by [@DPOH357](https://github.com/DPOH357) 86 | 87 | ## [v2.5] - 2022-07-26 88 | 89 | ### Changed 90 | 91 | - GetSystemTick and GetFrameHash functions became macroses. It makes coupling lighter 92 | and adds more flexibility to configure driver 93 | - bitext_t and ubitext_t defined by default in dbccodeconf.h file 94 | - App version is printed when generator runs (not only in help print case) 95 | 96 | ## [v2.4] - 2022-07-24 97 | 98 | ### Added 99 | 100 | - Three new CLI keys to optionally disable some source code generation (see help) 101 | - Added more tests 102 | 103 | ## [v2.3] - 2022-07-19 104 | 105 | ### Changed 106 | - The gGeneration and the file configurations are splitted to different structs 107 | - Specific generators moved to separated files (fmon, config) 108 | - FileWriter API more simple 109 | 110 | ### Added 111 | - FMon driver can be configured for using MONO function approach or 112 | dedicated function (how it was before) by setting _USE_MONO_FMON macro 113 | 114 | ## [v2.2] - 2022-05-07 115 | 116 | ### Fixed 117 | - "C valid name" check for main driver name and value table descriptions 118 | - Fixed some minor printing artefacts (extra whitespaces, extra lines) 119 | - Very strange issue with wrong naming through all bunch of __***-binutil__ drivers (WTF?) 120 | 121 | 122 | ### Added 123 | - Values from value tables and it's descpriptions are printed as macroses 124 | ([issue#9](https://github.com/astand/c-coderdbc/issues/9) from [@delipl](https://github.com/delipl)) 125 | - Added more information about __\_\_ext_sig\_\___ function 126 | - Added strong check of matching of the versions of secondary dbc source 127 | files to main dbc source file (drvname.h) 128 | - Sources which are presumed to be located in __include__ directory are in square brakets 129 | 130 | ## [v2.1] - 2022-02-19 131 | 132 | ### Fixed 133 | - Some times incorrect _ro and _phys type deduction 134 | 135 | ### Added 136 | - Sign extension for signal which have signed type ([@2Black2](https://github.com/2Black2)) 137 | 138 | ## [v2.0] - 2022-02-02 139 | 140 | ### Added 141 | - '-rw' and '-nodeutils' (renamed '--node-utils') options 142 | 143 | ### Changed 144 | - Argument passing way to view: 'key' - 'value' 145 | 146 | ### Fixed 147 | - Minor warnings 148 | - Bad source files placement for -rw key 149 | 150 | ## [v1.10] - 2021-01-24 151 | 152 | ### Changed 153 | - Source files placed to separated directories 154 | ### Fixed 155 | - Incorrect comments for valuetable's values 156 | - Minor changes 157 | 158 | ## [v1.9] - 2021-11-09 159 | 160 | ### Fixed 161 | - Closing last comment section in -config.h ([@SamFisher940425](https://github.com/SamFisher940425)) 162 | - A few minor style changes in generated code 163 | - All sources of repo processed by code style formatting tool 164 | 165 | ## [v1.8] - 2021-11-01 166 | 167 | ### Fixed 168 | - Issue #6. Incorrect checksum signal assigning. 169 | 170 | ## [v1.7] - 2021-10-10 171 | 172 | ### Fixed 173 | - Potential issue when node is only Receiver (presumably will be skipped in node-util struct) 174 | 175 | ### Added 176 | - Support multiple transmitters on single frame (for --node-utils generation variant) 177 | 178 | ## [v1.6] - 2021-09-09 179 | 180 | ### Added 181 | - 4th CLI param '--node-utils' for generation pairs of binutil for each 182 | network node defined in DBC 183 | 184 | ### Fixed 185 | - Bad *_Receive() function body when there is only 1 frame in RX struct 186 | 187 | ## [v1.5] - 2021-08-26 188 | 189 | ### Fixed 190 | - Fixed 'atoi' with Extended ID on Windows OS ([@shevu](https://github.com/shevu)) 191 | - Fixed issue with parsing value table values ([@shevu](https://github.com/shevu)) 192 | - Fixed issue with frames where signals goes out of DLC range 193 | 194 | ## [v1.4] - 2021-07-13 195 | 196 | ### Fixed 197 | - Removed default into "this is test" 198 | - Edited README.md 199 | 200 | ## [v1.3] - 2021-07-11 201 | 202 | ### Added 203 | - Printing template canmonitorutil.h 204 | - Printing template dbccodeconf.h 205 | - Updated driver-config comment text 206 | 207 | ## [v1.2] - 2021-07-11 208 | 209 | ### Added 210 | - Option for rewriting generated files 211 | - Added README.md (base build and run instruction) 212 | - Added LICENSE.md 213 | 214 | ### Changed 215 | - Lib has become CLI utility "coderdbc" 216 | - Added help to CLI 217 | - Refactored project settings (cmake) to make easy way to build on windows PC 218 | 219 | ### Fixed 220 | - Fixed some warnings 221 | 222 | ## [v1.0] - 2021-05-15 223 | 224 | ### Added 225 | - Added DBC file version ("VERSION "x.x"") tag parsing 226 | - Added dbc version info in: fmon, main and util drivers 227 | - Added codegen lib version file 228 | 229 | ### Changed 230 | - Generate interface takes DbcMessageList instance which has version info 231 | 232 | ### Fixed 233 | - Fixed some warnings 234 | 235 | 236 | [Unreleased]: https://github.com/astand/c-coderdbc/compare/v3.1...HEAD 237 | [v3.1]: https://github.com/astand/c-coderdbc/compare/v3.0...v3.1 238 | [v3.0]: https://github.com/astand/c-coderdbc/compare/v2.9...v3.0 239 | [v2.9]: https://github.com/astand/c-coderdbc/compare/v2.8...v2.9 240 | [v2.8]: https://github.com/astand/c-coderdbc/compare/v2.7...v2.8 241 | [v2.7]: https://github.com/astand/c-coderdbc/compare/v2.6...v2.7 242 | [v2.6]: https://github.com/astand/c-coderdbc/compare/v2.5...v2.6 243 | [v2.5]: https://github.com/astand/c-coderdbc/compare/v2.4...v2.5 244 | [v2.4]: https://github.com/astand/c-coderdbc/compare/v2.3...v2.4 245 | [v2.3]: https://github.com/astand/c-coderdbc/compare/v2.2...v2.3 246 | [v2.2]: https://github.com/astand/c-coderdbc/compare/v2.1...v2.2 247 | [v2.1]: https://github.com/astand/c-coderdbc/compare/v2.0...v2.1 248 | [v2.0]: https://github.com/astand/c-coderdbc/compare/v1.10...v2.0 249 | [v1.10]: https://github.com/astand/c-coderdbc/compare/v1.9...v1.10 250 | [v1.9]: https://github.com/astand/c-coderdbc/compare/v1.8...v1.9 251 | [v1.8]: https://github.com/astand/c-coderdbc/compare/v1.7...v1.8 252 | [v1.7]: https://github.com/astand/c-coderdbc/compare/v1.6...v1.7 253 | [v1.6]: https://github.com/astand/c-coderdbc/compare/v1.5...v1.6 254 | [v1.5]: https://github.com/astand/c-coderdbc/compare/v1.4...v1.5 255 | [v1.4]: https://github.com/astand/c-coderdbc/compare/v1.3...v1.4 256 | [v1.3]: https://github.com/astand/c-coderdbc/compare/v1.2...v1.3 257 | [v1.2]: https://github.com/astand/c-coderdbc/compare/v1.0...v1.2 258 | [v1.0]: https://github.com/astand/c-coderdbc/releases/tag/v1.0 -------------------------------------------------------------------------------- /rm-driver.sh: -------------------------------------------------------------------------------- 1 | (cd test/gencode && rm -r *) -------------------------------------------------------------------------------- /run-test-gen.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem The bat file checks the first passed from the caller scope string argument 4 | rem If the argument length is greater than 0 the argument is used in path to the coderdbc.exe 5 | rem Examples: 6 | 7 | rem ./run-test-gen.bat release 8 | rem build\release\coderdbc.exe 9 | 10 | rem ./run-test-gen.bat debug 11 | rem build\debug\coderdbc.exe 12 | 13 | echo Argument passed: %~1 14 | 15 | rem Check if an argument is provided 16 | if "%~1"=="" ( 17 | rem If no argument is provided, set the path directly to "build\coderdbc.exe" 18 | set "CMD_PATH=build\coderdbc.exe" 19 | ) else ( 20 | rem If an argument is provided, use it to construct the path 21 | set "CMD_PATH=build\%~1\coderdbc.exe" 22 | ) 23 | 24 | rem Output the combined path for debugging 25 | echo Combined path: %CMD_PATH% 26 | 27 | rem Run the program with the constructed path and other options 28 | "%CMD_PATH%" -dbc test\testdb.dbc -out -out test\gencode -drvname testdb -nodeutils -rw 29 | 30 | pause 31 | -------------------------------------------------------------------------------- /run-test-gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The bat file checks the first passed from the caller scope string argument 4 | # If the argument length is greater than 0 the argument is used in path to the coderdbc.exe 5 | # Examples: 6 | 7 | # ./run-test-gen.sh release 8 | # build/release/coderdbc 9 | 10 | # ./run-test-gen.sh debug 11 | # build/debug/coderdbc 12 | 13 | # ATTENTION: this script is not tested in Linux yet!!! 14 | 15 | # Check if an argument is provided 16 | if [ -z "$1" ]; then 17 | # If no argument is provided, set the path directly 18 | CMD_PATH="build/coderdbc" 19 | else 20 | # If an argument is provided, use it to construct the path 21 | CMD_PATH="build/$1/coderdbc" 22 | fi 23 | 24 | # Output the combined path for debugging 25 | echo "Combined path: $CMD_PATH" 26 | 27 | # Run the program with the constructed path and other options 28 | "$CMD_PATH" -dbc test/testdb.dbc -out test/gencode -drvname testdb -nodeutils -rw 29 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(${project} LANGUAGES C CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | set(CMAKE_CXX_STANDARD 17) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | 9 | add_executable(coderdbc 10 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/c-main-generator.cpp 11 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/mon-generator.cpp 12 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/config-generator.cpp 13 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/c-util-generator.cpp 14 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/conditional-tree.cpp 15 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/c-sigprinter.cpp 16 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/filewriter.cpp 17 | ${CMAKE_CURRENT_SOURCE_DIR}/codegen/fs-creator.cpp 18 | ${CMAKE_CURRENT_SOURCE_DIR}/helpers/formatter.cpp 19 | ${CMAKE_CURRENT_SOURCE_DIR}/parser/dbclineparser.cpp 20 | ${CMAKE_CURRENT_SOURCE_DIR}/parser/dbcscanner.cpp 21 | ${CMAKE_CURRENT_SOURCE_DIR}/options-parser.cpp 22 | ${CMAKE_CURRENT_SOURCE_DIR}/app.cpp 23 | ${CMAKE_CURRENT_SOURCE_DIR}/maincli.cpp 24 | ) 25 | 26 | 27 | include(FetchContent) 28 | FetchContent_Declare( 29 | googletest 30 | GIT_REPOSITORY https://github.com/google/googletest.git 31 | GIT_TAG release-1.12.1 32 | ) 33 | # For Windows: Prevent overriding the parent project's compiler/linker settings 34 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 35 | FetchContent_MakeAvailable(googletest) 36 | 37 | enable_testing() 38 | 39 | add_executable( 40 | cctest 41 | ${CMAKE_CURRENT_SOURCE_DIR}/helpers/formatter.cpp 42 | ${CMAKE_CURRENT_SOURCE_DIR}/options-parser.cpp 43 | ${CMAKE_CURRENT_SOURCE_DIR}/parser/dbclineparser.cpp 44 | ${CMAKE_CURRENT_SOURCE_DIR}/tests/args-test.cpp 45 | ${CMAKE_CURRENT_SOURCE_DIR}/tests/bitext-test.cpp 46 | ${CMAKE_CURRENT_SOURCE_DIR}/tests/dbcline-test.cpp 47 | ) 48 | 49 | target_link_libraries( 50 | cctest 51 | GTest::gtest_main 52 | ) 53 | 54 | include(GoogleTest) 55 | gtest_discover_tests(cctest) 56 | 57 | 58 | add_library( 59 | dummy OBJECT 60 | ${CMAKE_CURRENT_SOURCE_DIR}/../test/gencode/usr/testdb-fmon.c 61 | ${CMAKE_CURRENT_SOURCE_DIR}/../test/gencode/lib/testdb.c 62 | ${CMAKE_CURRENT_SOURCE_DIR}/../test/gencode/butl/bms_testdb-binutil.c 63 | ) 64 | 65 | target_include_directories( 66 | dummy PRIVATE 67 | ${CMAKE_CURRENT_SOURCE_DIR}/../test/gencode/conf 68 | ${CMAKE_CURRENT_SOURCE_DIR}/../test/gencode/lib 69 | ${CMAKE_CURRENT_SOURCE_DIR}/../test/gencode/inc 70 | ) 71 | -------------------------------------------------------------------------------- /src/app.cpp: -------------------------------------------------------------------------------- 1 | #include "app.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "app.h" 9 | #include "parser/dbcscanner.h" 10 | #include "codegen/c-main-generator.h" 11 | #include "codegen/c-util-generator.h" 12 | #include "codegen/fs-creator.h" 13 | #include "codegen/version.h" 14 | #include 15 | #include 16 | 17 | /// @brief Function returns filename with extension extracted from full path 18 | /// @param fullfilepath Full file path 19 | /// @return Filename only 20 | std::string ExtractFileName(const std::string& fullfilepath) 21 | { 22 | // find the position of the last path separator 23 | size_t pos = fullfilepath.find_last_of("/\\"); 24 | 25 | // extract the file name from the full path 26 | std::string filename = (pos == std::string::npos) ? fullfilepath : fullfilepath.substr(pos + 1); 27 | 28 | return filename; 29 | } 30 | 31 | /// @brief Combines a directory path and a folder name while handling directory separators 32 | /// @param path The initial directory path 33 | /// @param folderName The folder name to append 34 | /// @return The combined path as a string 35 | std::string CombinePath(const std::string& path, const std::string& folderName) 36 | { 37 | // check if path ends with '/' or '\\' 38 | bool pathEndsWithSeparator = !path.empty() && (path.back() == '/' || path.back() == '\\'); 39 | 40 | // check if folderName starts with '/' or '\\' 41 | bool folderStartsWithSeparator = !folderName.empty() && (folderName.front() == '/' || folderName.front() == '\\'); 42 | 43 | // combine path and folderName based on separators 44 | if (pathEndsWithSeparator && folderStartsWithSeparator) 45 | { 46 | // both have separators, remove one from folderName 47 | return path + folderName.substr(1); 48 | } 49 | else if (!pathEndsWithSeparator && !folderStartsWithSeparator) 50 | { 51 | // neither has a separator, add one 52 | return path + '/' + folderName; 53 | } 54 | else 55 | { 56 | // exactly one has a separator, just concatenate 57 | return path + folderName; 58 | } 59 | } 60 | 61 | void CoderApp::Run() 62 | { 63 | std::cout << "coderdbc v" << CODEGEN_LIB_VERSION_MAJ << "." << CODEGEN_LIB_VERSION_MIN << std::endl << std::endl; 64 | 65 | if (AreParamsValid()) 66 | { 67 | GenerateCode(); 68 | } 69 | else 70 | { 71 | PrintHelp(); 72 | } 73 | } 74 | 75 | /// @brief Main generation process 76 | void CoderApp::GenerateCode() 77 | { 78 | DbcScanner scanner; 79 | CiMainGenerator cigen; 80 | CiUtilGenerator ciugen; 81 | FsCreator fscreator; 82 | 83 | std::ifstream reader; 84 | 85 | std::cout << "dbc file : " << Params.dbc.first << std::endl; 86 | std::cout << "gen path : " << Params.outdir.first << std::endl; 87 | std::cout << "drv name : " << Params.drvname.first << std::endl; 88 | 89 | if (std::filesystem::exists(Params.dbc.first) == false) 90 | { 91 | std::cout << "DBC file is not exists!" << std::endl; 92 | return; 93 | } 94 | 95 | std::ifstream file(Params.dbc.first); 96 | 97 | if (!file.is_open()) 98 | { 99 | // Pass ifstream as istream to processStream function 100 | std::cerr << "Unable to open DBC file" << std::endl; 101 | exit(1); 102 | } 103 | 104 | scanner.TrimDbcText(file); 105 | file.close(); 106 | 107 | auto filename = ExtractFileName(Params.dbc.first); 108 | // get current time 109 | std::time_t now = std::time(nullptr); 110 | // convert to local time 111 | std::tm* loctime = std::localtime(&now); 112 | // create driver related comment block 113 | std::stringstream driversrcinfo; 114 | driversrcinfo << "// DBC filename : " << filename << "\n"; 115 | // create common comment block 116 | std::stringstream commonsrcinfo; 117 | commonsrcinfo << "// Generator version : v" << CODEGEN_LIB_VERSION_MAJ << "." << CODEGEN_LIB_VERSION_MIN << "\n"; 118 | 119 | if (loctime && Params.add_gen_date) 120 | { 121 | // put the date and time inside common comment block 122 | commonsrcinfo << "// Generation time : " << std::put_time(loctime, "%Y.%m.%d %H:%M:%S") << "\n"; 123 | } 124 | 125 | std::string finalpath = Params.outdir.first; 126 | 127 | if (Params.is_driver_dir) 128 | { 129 | // append the folder name to the path 130 | finalpath = CombinePath(Params.outdir.first, Params.drvname.first); 131 | } 132 | 133 | // create main destination directory 134 | fscreator.Configure(Params.drvname.first, finalpath, 135 | commonsrcinfo.str(), 136 | driversrcinfo.str(), 137 | scanner.dblist.ver.hi, 138 | scanner.dblist.ver.low); 139 | 140 | auto ret = fscreator.PrepareDirectory(Params.is_rewrite); 141 | 142 | fscreator.FS.gen.no_config = Params.is_noconfig; 143 | fscreator.FS.gen.no_inc = Params.is_nocanmon; 144 | fscreator.FS.gen.no_fmon = Params.is_nofmon; 145 | 146 | if (ret) 147 | { 148 | cigen.Generate(scanner.dblist, fscreator.FS); 149 | } 150 | else 151 | { 152 | std::cout << "One or both are invalid\n"; 153 | } 154 | 155 | // check if option --node-utils is requested, when requested binutil generation 156 | // wiil be performed on each node from DBC file in accordance to its RX / TX subscription 157 | if (Params.is_nodeutils) 158 | { 159 | std::vector nodes; 160 | 161 | for (size_t num = 0; num < scanner.dblist.msgs.size(); num++) 162 | { 163 | // iterate all messages and collect All nodes assign to at least one message 164 | auto m = scanner.dblist.msgs[num]; 165 | 166 | for (size_t txs = 0; txs < m->TranS.size(); txs++) 167 | { 168 | std::string tx_node_name = m->TranS[txs]; 169 | 170 | if (std::find(nodes.begin(), nodes.end(), tx_node_name) == nodes.end()) 171 | { 172 | // New node name. put it in the node collection 173 | nodes.push_back(tx_node_name); 174 | } 175 | } 176 | 177 | for (size_t recs = 0; recs < m->RecS.size(); recs++) 178 | { 179 | std::string rx_node_name = m->RecS[recs]; 180 | 181 | // test all recs 182 | if (std::find(nodes.begin(), nodes.end(), rx_node_name) == nodes.end()) 183 | { 184 | // New node name, put it in the node collection 185 | nodes.push_back(rx_node_name); 186 | } 187 | } 188 | } 189 | 190 | // for each node in collection perform specific bin-util generation 191 | for (size_t node = 0; node < nodes.size(); node++) 192 | { 193 | std::string util_name = nodes[node] + "_" + Params.drvname.first; 194 | 195 | // set new driver name for current node 196 | fscreator.FS.gen.drvname = str_tolower(util_name); 197 | fscreator.FS.gen.DRVNAME = str_toupper(fscreator.FS.gen.drvname); 198 | fscreator.FS.file.util_c.dir = fscreator.FS.file.utildir; 199 | fscreator.FS.file.util_h.dir = fscreator.FS.file.utildir; 200 | 201 | fscreator.FS.file.util_h.fname = str_tolower(fscreator.FS.gen.drvname + "-binutil.h"); 202 | fscreator.FS.file.util_h.fpath = fscreator.FS.file.utildir + "/" + fscreator.FS.file.util_h.fname; 203 | 204 | fscreator.FS.file.util_c.fname = str_tolower(fscreator.FS.gen.drvname + "-binutil.c"); 205 | fscreator.FS.file.util_c.fpath = fscreator.FS.file.utildir + "/" + fscreator.FS.file.util_c.fname; 206 | 207 | MsgsClassification groups; 208 | 209 | for (size_t i = 0; i < scanner.dblist.msgs.size(); i++) 210 | { 211 | auto m = scanner.dblist.msgs[i]; 212 | 213 | bool found = (std::find(m->TranS.begin(), m->TranS.end(), nodes[node]) != m->TranS.end()); 214 | 215 | if (found) 216 | { 217 | // Message is in Tx array of current node 218 | groups.Tx.push_back(m->MsgID); 219 | } 220 | 221 | found = (std::find(m->RecS.begin(), m->RecS.end(), nodes[node]) != m->RecS.end()); 222 | 223 | if (found) 224 | { 225 | // Message is in Rx array of current node 226 | groups.Rx.push_back(m->MsgID); 227 | } 228 | } 229 | 230 | if (ret) 231 | { 232 | ciugen.Generate(scanner.dblist, fscreator.FS, groups, Params.drvname.first); 233 | } 234 | } 235 | } 236 | else 237 | { 238 | MsgsClassification groups; 239 | 240 | for (size_t i = 0; i < scanner.dblist.msgs.size(); i++) 241 | { 242 | groups.Rx.push_back(scanner.dblist.msgs[i]->MsgID); 243 | } 244 | 245 | if (ret) 246 | { 247 | ciugen.Generate(scanner.dblist, fscreator.FS, groups, Params.drvname.first); 248 | } 249 | } 250 | 251 | std::cout << std::endl << "Source code generation completed." << std::endl; 252 | } 253 | 254 | /// @brief Checks if all mandatory configuration parameters are provided 255 | /// @return TRUE if configuration valid, otherwise FALSE 256 | bool CoderApp::AreParamsValid() 257 | { 258 | return (Params.dbc.second && Params.outdir.second && Params.drvname.second) && (Params.is_help == false); 259 | } 260 | 261 | /// @brief Help message printer 262 | void CoderApp::PrintHelp() 263 | { 264 | std::cout << "project source code:\thttps://github.com/astand/c-coderdbc\t\t" << std::endl; 265 | std::cout << "free web application:\thttps://coderdbc.com" << std::endl; 266 | std::cout << std::endl; 267 | std::cout << "required parameters:" << std::endl; 268 | 269 | std::cout << " -dbc\t\t path to dbc file" << std::endl; 270 | std::cout << " -out\t\t directory for generated source files (must be pre-created)" << std::endl; 271 | std::cout << " -drvname\t driver name - will be used for naming driver parts" << std::endl; 272 | std::cout << std::endl; 273 | std::cout << "optional parameters:" << std::endl; 274 | std::cout << " -nodeutils\t will generate specific pairs of binutils drivers for each node" << std::endl; 275 | std::cout << std::endl; 276 | std::cout << " -rw\t\t by default each new generation with previously used params" << std::endl; 277 | std::cout << " \t\t will create new sud-directory with source files (000, 001, ... etc)" << std::endl; 278 | std::cout << " \t\t '-rw' option enables rewriting: all source files previously generated" << std::endl; 279 | std::cout << " \t\t will be replaced by new ones" << std::endl; 280 | std::cout << std::endl; 281 | std::cout << " -noconfig:\t no {drivername}-config and dbccodeconfig generation" << std::endl; 282 | std::cout << " -noinc:\t no canmonitorutil.h generation" << std::endl; 283 | std::cout << " -nofmon:\t no ***-fmon.c generation" << std::endl; 284 | std::cout << std::endl; 285 | std::cout << " -driverdir\t the output path (-out) will be appended by driver name" << std::endl; 286 | std::cout << " -gendate\t the generation date will be included in the header comment section of the source file." << 287 | std::endl; 288 | std::cout << std::endl; 289 | 290 | std::cout << "examples:" << std::endl; 291 | std::cout << std::endl; 292 | 293 | std::cout << 294 | "./dbccoder -dbc /home/user/docs/driveshaft.dbc -out /home/user/docs/gen/ -drvname drivedb -nodeutils -rw -driverdir -gendate" 295 | << std::endl; 296 | std::cout << "./dbccoder -dbc /home/user/docs/driveshaft.dbc -out /home/user/docs/gen/ -drvname drivedb -nodeutils -rw" 297 | << std::endl; 298 | 299 | std::cout << 300 | "./dbccoder -dbc /home/user/docs/driveshaft.dbc -out /home/user/docs/gen/ -drvname drivedb -nodeutils" << std::endl; 301 | 302 | std::cout << "./dbccoder -dbc /home/user/docs/driveshaft.dbc -out /home/user/docs/gen/ -drvname drivedb" << std::endl; 303 | std::cout << std::endl; 304 | } 305 | -------------------------------------------------------------------------------- /src/app.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /// @brief App wrapper class 9 | class CoderApp { 10 | public: 11 | /// @brief Constructor 12 | /// @param params - general generation configuration 13 | CoderApp(const OptionsParser::GenOptions& params) : Params(params) {} 14 | 15 | /// @brief Main generation process 16 | void Run(); 17 | 18 | private: 19 | bool AreParamsValid(); 20 | void GenerateCode(); 21 | void PrintHelp(); 22 | 23 | const OptionsParser::GenOptions& Params; 24 | }; 25 | -------------------------------------------------------------------------------- /src/codegen/c-main-generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "c-sigprinter.h" 6 | #include "filewriter.h" 7 | #include "../types/message.h" 8 | #include "../types/outfile.h" 9 | #include "fs-creator.h" 10 | 11 | class CiMainGenerator { 12 | public: 13 | void Generate(DbcMessageList_t& dlist, const AppSettings_t& fsd); 14 | 15 | private: 16 | 17 | void Gen_MainHeader(); 18 | void Gen_MainSource(); 19 | void Gen_ConfigHeader(); 20 | void Gen_FMonHeader(); 21 | void Gen_FMonSource(); 22 | void Gen_CanMonUtil(); 23 | void Gen_DbcCodeConf(); 24 | 25 | void WriteSigStructField(const SignalDescriptor_t& sig, bool bitfield, size_t pad); 26 | 27 | void WriteUnpackBody(const CiExpr_t* sgs); 28 | void WritePackStructBody(const CiExpr_t* sgs); 29 | void WritePackArrayBody(const CiExpr_t* sgs); 30 | void PrintPackCommonText(const std::string& arrtxt, const CiExpr_t* sgs); 31 | 32 | private: 33 | CSigPrinter sigprt; 34 | FileWriter fwriter; 35 | // Actual max DLC value from dbc list instance 36 | size_t val_maxDlcValueFromDbcList; 37 | // Macro for default initial frame's data bytes value 38 | std::string prt_initialDataByteValueName; 39 | // Macro for frame DLC validation 40 | std::string prt_dlcValidateMacroName; 41 | const AppSettings_t* fdesc; 42 | }; 43 | -------------------------------------------------------------------------------- /src/codegen/c-sigprinter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "c-sigprinter.h" 4 | #include "helpers/formatter.h" 5 | #include "conf-and-limits.h" 6 | 7 | // work buffer for all snprintf operations 8 | static const size_t WBUFF_LEN = 2048; 9 | static char workbuff[WBUFF_LEN] = { 0 }; 10 | 11 | // additional templates for expression generation 12 | static std::string msk[] = { "0", "0x01U", "0x03U", "0x07U", "0x0FU", "0x1FU", "0x3FU", "0x7FU", "0xFFU" }; 13 | 14 | static inline int32_t ShiftByte(const SignalDescriptor_t* sig, int32_t bn) 15 | { 16 | return (sig->Order == BitLayout::kIntel) ? (bn - 1) : (bn + 1); 17 | } 18 | 19 | CSigPrinter::CSigPrinter() 20 | { 21 | sigs_expr.clear(); 22 | } 23 | 24 | CSigPrinter::~CSigPrinter() 25 | { 26 | sigs_expr.clear(); 27 | } 28 | 29 | void CSigPrinter::LoadMessages(const std::vector message) 30 | { 31 | sigs_expr.clear(); 32 | 33 | for (auto it = message.cbegin(); it != message.cend(); ++it) 34 | { 35 | LoadMessage(*(*it)); 36 | } 37 | } 38 | 39 | void CSigPrinter::LoadMessage(const MessageDescriptor_t& message) 40 | { 41 | CiExpr_t* nexpr = new CiExpr_t; 42 | 43 | nexpr->msg = message; 44 | 45 | // do for this new expr to_byte and to_field expression building, 46 | // add them to dedicated members, set signal stdint type 47 | // and push it to vector 48 | 49 | BuildCConvertExprs(nexpr); 50 | 51 | sigs_expr.push_back(nexpr); 52 | } 53 | 54 | std::string CSigPrinter::PrintPhysicalToRaw(const SignalDescriptor_t* sig, const std::string& drvname) 55 | { 56 | std::string retstr = ""; 57 | 58 | const std::string prtFactor = prt_double(sig->Factor, 9); 59 | const std::string prtOffset = prt_double(sig->Offset, 9); 60 | 61 | retstr = StrPrint("// signal: @%s\n", sig->Name.c_str()); 62 | 63 | if (sig->IsDoubleSig) 64 | { 65 | retstr += StrPrint("#define %s_%s_CovFactor (%s)\n", drvname.c_str(), sig->Name.c_str(), prtFactor.c_str()); 66 | } 67 | else 68 | { 69 | retstr += StrPrint("#define %s_%s_CovFactor (%d)\n", drvname.c_str(), sig->Name.c_str(), (int32_t)sig->Factor); 70 | } 71 | 72 | retstr += StrPrint("#define %s_%s_toS(x) ( (%s) ", drvname.c_str(), sig->Name.c_str(), 73 | PrintType((uint8_t)sig->TypeRo).c_str()); 74 | 75 | if (sig->IsDoubleSig) 76 | { 77 | retstr += StrPrint("(((x) - (%s)) / (%s)) )\n", prtOffset.c_str(), prtFactor.c_str()); 78 | } 79 | else 80 | { 81 | if (sig->Offset == 0) 82 | { 83 | // only factor 84 | retstr += StrPrint("((x) / (%d)) )\n", (int32_t)sig->Factor); 85 | } 86 | else if (sig->Factor == 1) 87 | { 88 | // only offset 89 | retstr += StrPrint("((x) - (%d)) )\n", (int32_t)sig->Offset); 90 | } 91 | else 92 | { 93 | // full expression 94 | retstr += StrPrint("(((x) - (%d)) / (%d)) )\n", (int32_t)sig->Offset, (int32_t)sig->Factor); 95 | } 96 | } 97 | 98 | retstr += StrPrint("#define %s_%s_fromS(x) ( ", drvname.c_str(), sig->Name.c_str()); 99 | 100 | if (sig->IsDoubleSig) 101 | { 102 | retstr += StrPrint("(((x) * (%s)) + (%s)) )\n", prtFactor.c_str(), prtOffset.c_str()); 103 | } 104 | else 105 | { 106 | if (sig->Offset == 0) 107 | { 108 | // only factor 109 | retstr += StrPrint("((x) * (%d)) )\n", (int32_t)sig->Factor); 110 | } 111 | else if (sig->Factor == 1) 112 | { 113 | // only offset 114 | retstr += StrPrint("((x) + (%d)) )\n", (int32_t)sig->Offset); 115 | } 116 | else 117 | { 118 | // full expression 119 | retstr += StrPrint("(((x) * (%d)) + (%d)) )\n", (int32_t)sig->Factor, (int32_t)sig->Offset); 120 | } 121 | } 122 | 123 | return retstr; 124 | } 125 | 126 | int32_t CSigPrinter::BuildCConvertExprs(CiExpr_t* msgprinter) 127 | { 128 | int32_t ret = 0; 129 | std::string tmpstr; 130 | 131 | msgprinter->to_bytes.clear(); 132 | msgprinter->to_signals.clear(); 133 | msgprinter->to_bytes.resize(msgprinter->msg.DLC); 134 | 135 | // for each signal specific to_signal expression must be defined, 136 | // and during all signals processing, for each byte to_byte expression 137 | // must be collected 138 | 139 | for (size_t i = 0; i < msgprinter->msg.Signals.size(); i++) 140 | { 141 | // there are two main goal of this code: 142 | // 1 - to generate bytes to signal C-expression, (_d - name of array). 143 | // For each signal one or more bytes can be referenced. It's generated 144 | // once on each function call for each signal 145 | // 146 | // 2 - to generate signals to each byte expression, (_m - name of struct with 147 | // signals). For each byte a 8 signals can be referenced. It's generated 148 | // consequently signal after signal (by adding chunks of expressions to @to_bytes 149 | // collection) 150 | // 151 | // signal expression is saved to vector @to_signals, which id must be 152 | // fully correlated to id of target signal. the final size of 153 | // @to_signals vector must be equal to size of Signals vector 154 | // 155 | // bytes expression is saved to vector @to_bytes, where id is the 156 | // byte number in frame payload (i.e. to_bytes.size() == frame.DLC) 157 | msgprinter->to_signals.push_back(PrintSignalExpr(&msgprinter->msg.Signals[i], msgprinter->to_bytes)); 158 | } 159 | 160 | if (msgprinter->msg.CsmSig != nullptr) 161 | { 162 | std::vector v(8); 163 | 164 | PrintSignalExpr(msgprinter->msg.CsmSig, v); 165 | 166 | for (uint8_t i = 0; i < v.size() && i < 8; i++) 167 | { 168 | if (v[i].size() > 0) 169 | { 170 | msgprinter->msg.CsmToByteExpr = v[i]; 171 | msgprinter->msg.CsmByteNum = i; 172 | break; 173 | } 174 | } 175 | } 176 | 177 | return ret; 178 | } 179 | 180 | std::string CSigPrinter::PrintSignalExpr(const SignalDescriptor_t* sig, std::vector& to_bytes) 181 | { 182 | // value for collecting expression (to_signal) 183 | std::string tosigexpr; 184 | 185 | if (to_bytes.size() == 0) 186 | { 187 | // return empty line is bytes count somehow equals 0 188 | return "Error in DBC file !!!! Dlc of this message must be greater."; 189 | } 190 | 191 | uint16_t startb = (uint16_t)((sig->Order == BitLayout::kIntel) ? 192 | (sig->StartBit + (sig->LengthBit - 1)) : (sig->StartBit)); 193 | 194 | if (startb > CONF_LIMIT_HIGHEST_BIT_POSITION) 195 | { 196 | startb = CONF_LIMIT_HIGHEST_BIT_POSITION; 197 | } 198 | 199 | uint32_t bn = (startb / 8); 200 | 201 | if (to_bytes.size() <= bn) 202 | { 203 | // DLC from message doesn't fit to signal layout 204 | // make code uncomplilable 205 | to_bytes[0] = "Error in DBC file !!!! Dlc of this message must be greater."; 206 | return to_bytes[0]; 207 | } 208 | 209 | // set valid to_byte prefix 210 | int32_t bbc = (startb % 8) + 1; 211 | int32_t slen = sig->LengthBit; 212 | 213 | if (bbc > slen) 214 | { 215 | snprintf(workbuff, WBUFF_LEN, "((_d[%d] >> %dU) & (%s))", bn, bbc - slen, msk[slen].c_str()); 216 | tosigexpr += workbuff; 217 | 218 | snprintf(workbuff, WBUFF_LEN, "((_m->%s & (%s)) << %dU)", sig->Name.c_str(), msk[slen].c_str(), bbc - slen); 219 | AppendToByteLine(to_bytes[bn], workbuff); 220 | } 221 | else if (bbc == slen) 222 | { 223 | // no rolling bits 224 | snprintf(workbuff, WBUFF_LEN, "(_d[%d] & (%s))", bn, msk[slen].c_str()); 225 | tosigexpr += workbuff; 226 | 227 | snprintf(workbuff, WBUFF_LEN, "(_m->%s & (%s))", sig->Name.c_str(), msk[slen].c_str()); 228 | AppendToByteLine(to_bytes[bn], workbuff); 229 | } 230 | else 231 | { 232 | std::string t64 = ""; 233 | slen -= bbc; 234 | 235 | if (slen > 31) 236 | { 237 | t64 = "(uint64_t)"; 238 | } 239 | 240 | snprintf(workbuff, WBUFF_LEN, "(%s(_d[%d] & (%s)) << %dU)", t64.c_str(), bn, msk[bbc].c_str(), slen); 241 | tosigexpr += workbuff; 242 | 243 | snprintf(workbuff, WBUFF_LEN, "((_m->%s >> %dU) & (%s))", sig->Name.c_str(), slen, msk[bbc].c_str()); 244 | AppendToByteLine(to_bytes[bn], workbuff); 245 | 246 | while ((slen - 8) >= 0) 247 | { 248 | t64.clear(); 249 | 250 | slen -= 8; 251 | 252 | bn = ShiftByte(sig, bn); 253 | 254 | if (to_bytes.size() < bn) 255 | { 256 | // DLC from message doesn't fit to signal layout 257 | // make code uncomplilable 258 | to_bytes[0] = "Error in DBC file !!!! Dlc of this message must be greater."; 259 | return to_bytes[0]; 260 | } 261 | 262 | tosigexpr += " | "; 263 | 264 | if (slen == 0) 265 | { 266 | // last byte is aligned 267 | snprintf(workbuff, WBUFF_LEN, "(_d[%d] & (%s))", bn, msk[8].c_str()); 268 | tosigexpr += workbuff; 269 | 270 | snprintf(workbuff, WBUFF_LEN, "(_m->%s & (%s))", sig->Name.c_str(), msk[8].c_str()); 271 | AppendToByteLine(to_bytes[bn], workbuff); 272 | 273 | } 274 | else 275 | { 276 | if (slen > 31) 277 | { 278 | t64 = "(uint64_t)"; 279 | } 280 | 281 | snprintf(workbuff, WBUFF_LEN, "(%s(_d[%d] & (%s)) << %dU)", t64.c_str(), bn, msk[8].c_str(), slen); 282 | tosigexpr += workbuff; 283 | 284 | snprintf(workbuff, WBUFF_LEN, "((_m->%s >> %dU) & (%s))", sig->Name.c_str(), slen, msk[8].c_str()); 285 | AppendToByteLine(to_bytes[bn], workbuff); 286 | } 287 | } 288 | 289 | if (slen > 0) 290 | { 291 | bn = ShiftByte(sig, bn); 292 | 293 | snprintf(workbuff, WBUFF_LEN, " | ((_d[%d] >> %dU) & (%s))", bn, 8 - slen, msk[slen].c_str()); 294 | tosigexpr += workbuff; 295 | 296 | snprintf(workbuff, WBUFF_LEN, "((_m->%s & (%s)) << %dU)", sig->Name.c_str(), msk[slen].c_str(), 297 | 8 - slen); 298 | AppendToByteLine(to_bytes[bn], workbuff); 299 | } 300 | } 301 | 302 | return tosigexpr; 303 | } 304 | 305 | void CSigPrinter::AppendToByteLine(std::string& expr, std::string str) 306 | { 307 | if (expr.size() > 0) 308 | { 309 | // Not first appendingF 310 | expr += " | " + str; 311 | } 312 | else 313 | { 314 | // First appending 315 | expr = str; 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/codegen/c-sigprinter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../types/c-expr.h" 4 | 5 | class CSigPrinter { 6 | public: 7 | CSigPrinter(); 8 | ~CSigPrinter(); 9 | 10 | void LoadMessage(const MessageDescriptor_t& message); 11 | void LoadMessages(const std::vector message); 12 | 13 | std::string PrintPhysicalToRaw(const SignalDescriptor_t* msg, const std::string& drvname); 14 | 15 | public: 16 | std::vector sigs_expr; 17 | 18 | private: 19 | int32_t BuildCConvertExprs(CiExpr_t* msg); 20 | 21 | std::string PrintSignalExpr(const SignalDescriptor_t* sig, std::vector& to_bytes); 22 | 23 | void AppendToByteLine(std::string& expr, std::string str); 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/codegen/c-util-generator.cpp: -------------------------------------------------------------------------------- 1 | #include "c-util-generator.h" 2 | #include "helpers/formatter.h" 3 | #include 4 | #include 5 | 6 | static const std::string openguard = "#ifdef __cplusplus\n\ 7 | extern \"C\" {\n\ 8 | #endif"; 9 | 10 | static const std::string closeguard = "#ifdef __cplusplus\n\ 11 | }\n\ 12 | #endif"; 13 | 14 | CiUtilGenerator::CiUtilGenerator() 15 | { 16 | Clear(); 17 | } 18 | 19 | void CiUtilGenerator::Clear() 20 | { 21 | // clear all groups of messages 22 | tx.clear(); 23 | rx.clear(); 24 | both.clear(); 25 | } 26 | 27 | 28 | void CiUtilGenerator::Generate(DbcMessageList_t& dlist, const AppSettings_t& fsd, 29 | const MsgsClassification& groups, const std::string& drvname) 30 | { 31 | Clear(); 32 | 33 | p_dlist = &dlist; 34 | 35 | code_drvname = drvname; 36 | file_drvname = str_tolower(drvname); 37 | 38 | // 1 step is to prepare vectors of message's groups 39 | for (auto m : dlist.msgs) 40 | { 41 | if (!m->frameNotEmpty) 42 | { 43 | // skip frame when it is empty 44 | continue; 45 | } 46 | 47 | auto v = std::find_if(groups.Both.begin(), groups.Both.end(), [&](const uint32_t& msgid) 48 | { 49 | return msgid == m->MsgID; 50 | }); 51 | 52 | if (v != std::end(groups.Both)) 53 | { 54 | // message is in Both group, so put it to rx and tx containers 55 | tx.push_back(m); 56 | rx.push_back(m); 57 | continue; 58 | } 59 | 60 | v = std::find_if(groups.Rx.begin(), groups.Rx.end(), [&](const uint32_t& msgid) 61 | { 62 | return msgid == m->MsgID; 63 | }); 64 | 65 | if (v != std::end(groups.Rx)) 66 | { 67 | rx.push_back(m); 68 | } 69 | 70 | v = std::find_if(groups.Tx.begin(), groups.Tx.end(), [&](const uint32_t& msgid) 71 | { 72 | return msgid == m->MsgID; 73 | }); 74 | 75 | if (v != std::end(groups.Tx)) 76 | { 77 | tx.push_back(m); 78 | } 79 | } 80 | 81 | std::sort(rx.begin(), rx.end(), [&](const MessageDescriptor_t* a, const MessageDescriptor_t* b) 82 | { 83 | return a->MsgID < b->MsgID; 84 | }); 85 | 86 | std::sort(tx.begin(), tx.end(), [&](const MessageDescriptor_t* a, const MessageDescriptor_t* b) 87 | { 88 | return a->MsgID < b->MsgID; 89 | }); 90 | 91 | fdesc = &fsd.file; 92 | gdesc = &fsd.gen; 93 | 94 | // print header for util code 95 | PrintHeader(); 96 | 97 | // print main source for util code 98 | PrintSource(); 99 | } 100 | 101 | void CiUtilGenerator::PrintHeader() 102 | { 103 | tof.Flush(); 104 | tof.AppendText(gdesc->start_common_info); 105 | tof.AppendText(gdesc->start_driver_info); 106 | tof.Append("#pragma once"); 107 | tof.Append(); 108 | 109 | tof.Append(openguard); 110 | tof.Append(); 111 | 112 | // include common dbc code config header 113 | tof.Append("#include \"dbccodeconf.h\""); 114 | tof.Append(); 115 | 116 | // include c-main driver header 117 | tof.Append("#include \"%s.h\"", file_drvname.c_str()); 118 | tof.Append(); 119 | 120 | 121 | if (rx.size() == 0) 122 | { 123 | tof.Append("// There is no any RX mapped massage."); 124 | tof.Append(); 125 | } 126 | else 127 | { 128 | // print the typedef 129 | tof.Append("typedef struct\n{"); 130 | 131 | for (auto m : rx) 132 | { 133 | tof.Append(" %s_t %s;", m->Name.c_str(), m->Name.c_str()); 134 | } 135 | 136 | tof.Append("} %s_rx_t;", gdesc->drvname.c_str()); 137 | tof.Append(); 138 | } 139 | 140 | if (tx.size() == 0) 141 | { 142 | tof.Append("// There is no any TX mapped massage."); 143 | tof.Append(); 144 | } 145 | else 146 | { 147 | // print the typedef 148 | tof.Append("typedef struct\n{"); 149 | 150 | for (auto m : tx) 151 | { 152 | tof.Append(" %s_t %s;", m->Name.c_str(), m->Name.c_str()); 153 | } 154 | 155 | tof.Append("} %s_tx_t;", gdesc->drvname.c_str()); 156 | tof.Append(); 157 | } 158 | 159 | if (rx.size() > 0) 160 | { 161 | // receive function necessary only when more than 0 rx messages were mapped 162 | tof.Append("uint32_t %s_Receive(%s_rx_t* m, const uint8_t* d, uint32_t msgid, uint8_t dlc);", 163 | gdesc->drvname.c_str(), gdesc->drvname.c_str()); 164 | tof.Append(); 165 | } 166 | 167 | // print extern for super structs 168 | if (rx.size() > 0 || tx.size() > 0) 169 | { 170 | tof.Append("#ifdef __DEF_%s__", gdesc->DRVNAME.c_str()); 171 | tof.Append(); 172 | 173 | if (rx.size() > 0) 174 | { 175 | tof.Append("extern %s_rx_t %s_rx;", gdesc->drvname.c_str(), gdesc->drvname.c_str()); 176 | tof.Append(); 177 | } 178 | 179 | if (tx.size() > 0) 180 | { 181 | tof.Append("extern %s_tx_t %s_tx;", gdesc->drvname.c_str(), gdesc->drvname.c_str()); 182 | tof.Append(); 183 | } 184 | 185 | tof.Append("#endif // __DEF_%s__", gdesc->DRVNAME.c_str()); 186 | tof.Append(); 187 | } 188 | 189 | tof.Append(closeguard); 190 | 191 | tof.Flush(fdesc->util_h.fpath); 192 | } 193 | 194 | void CiUtilGenerator::PrintSource() 195 | { 196 | tof.AppendText(gdesc->start_common_info); 197 | tof.AppendText(gdesc->start_driver_info); 198 | 199 | tof.Append("#include \"%s\"", fdesc->util_h.fname.c_str()); 200 | tof.Append(); 201 | 202 | tof.Append("// DBC file version"); 203 | tof.Append("#if (%s != (%uU)) || (%s != (%uU))", 204 | gdesc->verhigh_def.c_str(), p_dlist->ver.hi, gdesc->verlow_def.c_str(), p_dlist->ver.low); 205 | 206 | tof.Append("#error The %s binutil source file has inconsistency with core dbc lib!", 207 | gdesc->DRVNAME.c_str()); 208 | tof.Append("#endif"); 209 | tof.Append(); 210 | 211 | // optional RX and TX struct allocations 212 | if (rx.size() > 0 || tx.size() > 0) 213 | { 214 | tof.Append("#ifdef __DEF_%s__", gdesc->DRVNAME.c_str()); 215 | tof.Append(); 216 | 217 | if (rx.size() > 0) 218 | { 219 | tof.Append("%s_rx_t %s_rx;", gdesc->drvname.c_str(), gdesc->drvname.c_str()); 220 | tof.Append(); 221 | } 222 | 223 | if (tx.size() > 0) 224 | { 225 | tof.Append("%s_tx_t %s_tx;", gdesc->drvname.c_str(), gdesc->drvname.c_str()); 226 | tof.Append(); 227 | } 228 | 229 | tof.Append("#endif // __DEF_%s__", gdesc->DRVNAME.c_str()); 230 | tof.Append(); 231 | } 232 | 233 | if (rx.size() > 0) 234 | { 235 | // tree will be created inside (in dynamic memory) so this 236 | // scope is responsible for deletion these resources 237 | // tree is the struct tree-view which is used to execute 238 | // binary search on FrameID for selecting unpacking function 239 | auto tree = FillTreeLevel(rx, 0, static_cast(rx.size())); 240 | 241 | tof.Append("uint32_t %s_Receive(%s_rx_t* _m, const uint8_t* _d, uint32_t _id, uint8_t dlc_)", 242 | gdesc->drvname.c_str(), gdesc->drvname.c_str()); 243 | 244 | tof.Append("{"); 245 | tof.Append(" uint32_t recid = 0;"); 246 | 247 | // put tree-view struct on code (in treestr variable) 248 | std::string treestr; 249 | condtree.Clear(); 250 | tof.Append(condtree.WriteCode(tree, treestr, 1)); 251 | tof.Append(); 252 | tof.Append(" return recid;"); 253 | tof.Append("}"); 254 | tof.Append(); 255 | 256 | // clear tree after using 257 | condtree.DeleteTree(tree); 258 | } 259 | 260 | tof.Flush(fdesc->util_c.fpath); 261 | } 262 | 263 | ConditionalTree_t* CiUtilGenerator::FillTreeLevel(std::vector& list, 264 | int32_t l, 265 | int32_t h, 266 | bool started) 267 | { 268 | int32_t span = h - l; 269 | int32_t lowhalf = span / 2; 270 | 271 | treestarted = started; 272 | 273 | if (h < 1) 274 | { 275 | return nullptr; 276 | } 277 | 278 | ConditionalTree_t* ret = new ConditionalTree_t; 279 | 280 | if (!treestarted && h == 1) 281 | { 282 | ret->Type = ConditionalType::Cond; 283 | auto msg = list[l]; 284 | ret->ConditionExpresion = StrPrint("_id == 0x%XU", msg->MsgID); 285 | ret->High = new ConditionalTree_t; 286 | ret->High->Type = ConditionalType::Single; 287 | ret->High->UtilCodeBody = StrPrint("recid = Unpack_%s_%s(&(_m->%s), _d, dlc_);", 288 | msg->Name.c_str(), code_drvname.c_str(), msg->Name.c_str()); 289 | return ret; 290 | } 291 | 292 | if (span > 1) 293 | { 294 | ret->Type = ConditionalType::Cond; 295 | 296 | if (lowhalf > 1) 297 | { 298 | ret->ConditionExpresion = StrPrint("(_id >= 0x%XU) && (_id < 0x%XU)", list[l]->MsgID, list[(l + lowhalf)]->MsgID); 299 | } 300 | else 301 | { 302 | ret->ConditionExpresion = StrPrint("_id == 0x%XU", list[l]->MsgID); 303 | } 304 | 305 | ret->High = FillTreeLevel(list, l, l + lowhalf, true); 306 | ret->Low = FillTreeLevel(list, l + lowhalf, h, true); 307 | } 308 | else 309 | { 310 | ret->Type = ConditionalType::Express; 311 | auto msg = list[l]; 312 | ret->ConditionExpresion = StrPrint("_id == 0x%XU", msg->MsgID); 313 | ret->UtilCodeBody = StrPrint("recid = Unpack_%s_%s(&(_m->%s), _d, dlc_);", 314 | msg->Name.c_str(), code_drvname.c_str(), msg->Name.c_str()); 315 | } 316 | 317 | return ret; 318 | } 319 | -------------------------------------------------------------------------------- /src/codegen/c-util-generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "types/message.h" 5 | #include "fs-creator.h" 6 | #include "filewriter.h" 7 | #include "conditional-tree.h" 8 | 9 | class CiUtilGenerator { 10 | public: 11 | CiUtilGenerator(); 12 | 13 | void Clear(); 14 | 15 | // msgs - the whole list of messages in CAN matrix 16 | // fsd - file and names descriptor 17 | // groups - collection of msg IDs assigned to available groups (rx, tx, both) 18 | 19 | // the output of this function source files which contain: 20 | // - global TX and RX typedefs message struct 21 | // - function to Unpack incoming frame to dedicated RX message struct field 22 | // - optional (through define in global "dbccodeconf.h") variable allocation in source files 23 | // 24 | void Generate(DbcMessageList_t& dlist, const AppSettings_t& fsd, 25 | const MsgsClassification& groups, const std::string& drvname); 26 | 27 | private: 28 | void PrintHeader(); 29 | void PrintSource(); 30 | ConditionalTree_t* FillTreeLevel(std::vector& msgs, 31 | int32_t l, int32_t h, bool started = false); 32 | 33 | private: 34 | 35 | std::vector tx; 36 | std::vector rx; 37 | std::vector both; 38 | 39 | // to file writer 40 | FileWriter tof; 41 | ConditionalTree condtree; 42 | 43 | std::string code_drvname; 44 | std::string file_drvname; 45 | 46 | const FsDescriptor_t* fdesc; 47 | const GenDescriptor_t* gdesc; 48 | const DbcMessageList_t* p_dlist; 49 | 50 | bool treestarted; 51 | }; 52 | -------------------------------------------------------------------------------- /src/codegen/conditional-tree.cpp: -------------------------------------------------------------------------------- 1 | #include "conditional-tree.h" 2 | #include "helpers/formatter.h" 3 | 4 | ConditionalTree::ConditionalTree() 5 | { 6 | } 7 | 8 | // this method performs printing tree-viewed frames collection 9 | // to proper source code 10 | std::string ConditionalTree::WriteCode(const ConditionalTree_t* tree, std::string& outstr, uint8_t intend) 11 | { 12 | if (tree != nullptr) 13 | { 14 | std::string temp; 15 | 16 | if (tree->Type == ConditionalType::Cond) 17 | { 18 | temp = StrPrint("if (%s) {", tree->ConditionExpresion.c_str()); 19 | PrintCode(temp, intend); 20 | 21 | WriteCode(tree->High, outstr, intend + 1); 22 | 23 | if (tree->Low != nullptr) 24 | { 25 | if (tree->Low->Type == ConditionalType::Express) 26 | { 27 | temp = StrPrint("} else if (%s) {", tree->Low->ConditionExpresion.c_str()); 28 | PrintCode(temp, intend); 29 | } 30 | else 31 | { 32 | temp = "} else {"; 33 | PrintCode(temp, intend); 34 | } 35 | 36 | WriteCode(tree->Low, outstr, intend + 1); 37 | } 38 | else 39 | { 40 | temp = "}"; 41 | PrintCode(temp, intend); 42 | } 43 | 44 | if (tree->Low != nullptr) 45 | { 46 | temp = "}"; 47 | PrintCode(temp, intend); 48 | } 49 | } 50 | else 51 | { 52 | temp = StrPrint("%s", tree->UtilCodeBody.c_str()); 53 | PrintCode(temp, intend); 54 | } 55 | } 56 | 57 | return codestr; 58 | } 59 | 60 | void ConditionalTree::PrintCode(std::string& str, uint8_t indent) 61 | { 62 | while (indent--) 63 | { 64 | codestr += " "; 65 | } 66 | 67 | codestr += str; 68 | codestr += "\n"; 69 | } 70 | 71 | 72 | void ConditionalTree::DeleteTree(ConditionalTree_t* tree) 73 | { 74 | if (tree != nullptr) 75 | { 76 | if (tree->Low != nullptr) 77 | { 78 | DeleteTree(tree->Low); 79 | } 80 | 81 | if (tree->High != nullptr) 82 | { 83 | DeleteTree(tree->High); 84 | } 85 | 86 | delete tree; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/codegen/conditional-tree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | enum class ConditionalType { Cond, Express, Single }; 7 | 8 | struct ConditionalTree_t 9 | { 10 | ConditionalTree_t* High; 11 | 12 | ConditionalTree_t* Low; 13 | 14 | ConditionalType Type; 15 | 16 | std::string ConditionExpresion; 17 | 18 | std::string UtilCodeBody; 19 | 20 | ConditionalTree_t() { 21 | High = nullptr; 22 | Low = nullptr; 23 | Type = ConditionalType::Single; 24 | } 25 | }; 26 | 27 | class ConditionalTree { 28 | public: 29 | ConditionalTree(); 30 | 31 | void Clear() { 32 | codestr.clear(); 33 | } 34 | 35 | std::string WriteCode(const ConditionalTree_t* tree, std::string& outstr, uint8_t intend); 36 | 37 | // deletes all memory allocated to tree members 38 | void DeleteTree(ConditionalTree_t* tree); 39 | 40 | private: 41 | 42 | void PrintCode(std::string& str, uint8_t indent); 43 | 44 | std::string codestr; 45 | }; 46 | -------------------------------------------------------------------------------- /src/codegen/config-generator.cpp: -------------------------------------------------------------------------------- 1 | #include "config-generator.h" 2 | 3 | void ConfigGenerator::FillHeader(FileWriter& wr, const GenDescriptor_t& gsett) 4 | { 5 | wr.Append("#pragma once"); 6 | wr.Append(""); 7 | wr.Append("/* include common dbccode configurations */"); 8 | wr.Append("#include \"dbccodeconf.h\""); 9 | wr.Append(""); 10 | wr.Append(""); 11 | wr.Append("/* ------------------------------------------------------------------------- *"); 12 | wr.Append(" This define enables using CAN message structs with bit-fielded signals"); 13 | wr.Append(" layout."); 14 | wr.Append(""); 15 | wr.Append(" Note(!): bit-feild was not tested properly. */"); 16 | wr.Append(""); 17 | wr.Append("/* #define %s */", gsett.usebits_def.c_str()); 18 | wr.Append(2); 19 | 20 | wr.Append("/* ------------------------------------------------------------------------- *"); 21 | wr.Append(" This macro enables using CAN message descriptive struct packing functions"); 22 | wr.Append(" (by default signature of pack function intakes a few simple typed params"); 23 | wr.Append(" for loading data, len, etc). To compile you need to define the struct"); 24 | wr.Append(" __CoderDbcCanFrame_t__ which must have fields:"); 25 | wr.Append(""); 26 | wr.Append(" u32 MsgId (CAN Frame message ID)"); 27 | wr.Append(" u8 DLC (CAN Frame payload length field)"); 28 | wr.Append(" u8 Data[8] (CAN Frame payload data)"); 29 | wr.Append(" u8 IDE (CAN Frame Extended (1) / Standard (0) ID type)"); 30 | wr.Append(""); 31 | wr.Append(" This struct definition have to be placed (or be included) in dbccodeconf.h */"); 32 | wr.Append(""); 33 | wr.Append("/* #define %s */", gsett.usesruct_def.c_str()); 34 | wr.Append(2); 35 | 36 | wr.Append("/* ------------------------------------------------------------------------- *"); 37 | wr.Append(" All the signals which have values of factor != 1 or offset != 0"); 38 | wr.Append(" will be named in message struct with posfix '_ro'. Pack to payload"); 39 | wr.Append(" operations will be made on this signal value as well as unpack from payload."); 40 | wr.Append(""); 41 | wr.Append(" USE_SIGFLOAT macro makes some difference:"); 42 | wr.Append(""); 43 | wr.Append(" 1. All the '_ro' fields will have a pair field with '_phys' postfix."); 44 | wr.Append(" If only offset != 0 is true then the type of '_phys' signal is the same"); 45 | wr.Append(" as '_ro' signal. In other case the type will be @sigfloat_t which"); 46 | wr.Append(" have to be defined in user dbccodeconf.h"); 47 | wr.Append(""); 48 | wr.Append(" 2. In pack function '_ro' signal will be rewritten by '_phys' signal, which"); 49 | wr.Append(" requires from user to use ONLY '_phys' signal for packing frame"); 50 | wr.Append(""); 51 | wr.Append(" 3. In unpack function '_phys' signal will be written by '_ro' signal."); 52 | wr.Append(" User have to use '_phys' signal to read physical value. */"); 53 | wr.Append(""); 54 | wr.Append("/* #define %s */", gsett.usesigfloat_def.c_str()); 55 | wr.Append(2); 56 | 57 | wr.Append("/* ------------------------------------------------------------------------- *"); 58 | wr.Append(" Note(!) that the \"canmonitorutil.h\" must be accessed in include path:"); 59 | wr.Append(""); 60 | wr.Append(" This macro adds:"); 61 | wr.Append(""); 62 | wr.Append(" - monitor field @mon1 to message struct"); 63 | wr.Append(""); 64 | wr.Append(" - capture system tick in unpack function and save value to mon1 field"); 65 | wr.Append(" to provide to user better missing frame detection code. For this case"); 66 | wr.Append(" user must provide function declared in canmonitorutil.h - GetSysTick()"); 67 | wr.Append(" which may return 1ms uptime."); 68 | wr.Append(""); 69 | wr.Append(" - calling function FMon_*** (from 'fmon' driver) inside unpack function"); 70 | wr.Append(" which is empty by default and have to be filled by user if"); 71 | wr.Append(" tests for DLC, rolling, checksum are necessary */"); 72 | wr.Append(""); 73 | wr.Append("/* #define %s */", gsett.usemon_def.c_str()); 74 | wr.Append(2); 75 | 76 | wr.Append("/* ------------------------------------------------------------------------- *"); 77 | wr.Append(" When monitor using is enabled (%s) and define below", gsett.usemon_def.c_str()); 78 | wr.Append(" uncommented, additional signal will be added to message struct. ***_expt:"); 79 | wr.Append(" expected rolling counter, to perform monitoring rolling counter sequence"); 80 | wr.Append(" automatically (result may be tested in dedicated Fmon_*** function) */"); 81 | wr.Append(""); 82 | wr.Append("/* #define %s */", gsett.useroll_def.c_str()); 83 | wr.Append(2); 84 | 85 | wr.Append("/* ------------------------------------------------------------------------- *"); 86 | wr.Append(" When monitor using is enabled (%s) and define below", gsett.usemon_def.c_str()); 87 | wr.Append(" uncommented, frame checksum signal may be handled automatically."); 88 | wr.Append(""); 89 | wr.Append(" The signal which may be marked as checksum signal must have substring"); 90 | wr.Append(" with next format:"); 91 | wr.Append(" "); 92 | wr.Append(""); 93 | wr.Append(" where:"); 94 | wr.Append(""); 95 | wr.Append(" - \"Checksum\": constant marker word"); 96 | wr.Append(""); 97 | wr.Append(" - \"XOR8\": type of method, this text will be passed to GetFrameHash"); 98 | wr.Append(" (canmonitorutil.h) function as is, the best use case is to define 'enum"); 99 | wr.Append(" DbcCanCrcMethods' in canmonitorutil.h file with all possible"); 100 | wr.Append(" checksum algorithms (e.g. XOR8, XOR4 etc)"); 101 | wr.Append(""); 102 | wr.Append(" - \"3\": optional value that will be passed to GetFrameHash as integer value"); 103 | wr.Append(""); 104 | wr.Append(" Function GetFrameHash have to be implemented by user"); 105 | wr.Append(""); 106 | wr.Append(" In pack function checksum signal will be calculated automatically"); 107 | wr.Append(" and loaded to payload"); 108 | wr.Append(""); 109 | wr.Append(" In unpack function checksum signal is checked with calculated."); 110 | wr.Append(" (result may be tested in dedicated Fmon_*** function). */"); 111 | wr.Append(""); 112 | wr.Append("/* #define %s */", gsett.usecsm_def.c_str()); 113 | wr.Append(2); 114 | wr.Append("/* ------------------------------------------------------------------------- *"); 115 | wr.Append(" FMon handling model can be build in two ways: "); 116 | wr.Append(""); 117 | wr.Append(" 1 - Default. In this case when specific frame unpack is called the "); 118 | wr.Append(" specific FMon_{Frame name}_{driver name} functoin will be called."); 119 | wr.Append(" User's code scope has to define each of these functions. Each function is"); 120 | wr.Append(" responsible for the error handling of one frame"); 121 | wr.Append(""); 122 | wr.Append(" 2 - MONO. In this case there is only one function to perform any frame "); 123 | wr.Append(" monitoring. This function has to be implemented in the user's code scope."); 124 | wr.Append(" This function is named as FMon_MONO_{driver name}. It takes frame id"); 125 | wr.Append(" which can be used for selection of the logic for a frame monitoring."); 126 | wr.Append(" This mode costs a bit more in runtime but when you often edit you DBC and you "); 127 | wr.Append(" have more than one project it could be more maintanable (there is"); 128 | wr.Append(" no necessity to replace source code)"); 129 | wr.Append(""); 130 | wr.Append(" For using MONO way uncomment line below */"); 131 | wr.Append("/* #define %s */", gsett.usemonofmon_def.c_str()); 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/codegen/config-generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "filewriter.h" 5 | #include "c-sigprinter.h" 6 | #include "fs-creator.h" 7 | 8 | class ConfigGenerator { 9 | public: 10 | void FillHeader(FileWriter& wr, const GenDescriptor_t& gsett); 11 | }; 12 | -------------------------------------------------------------------------------- /src/codegen/filewriter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "filewriter.h" 7 | 8 | template 9 | std::string __print_loc__(const char* format, va_list args) 10 | { 11 | char work_buff[N] = {0}; 12 | auto ret = vsnprintf(work_buff, N, format, args); 13 | 14 | if (ret >= N) 15 | { 16 | std::cout << "Attention (!) the line has been shortened : " << std::endl; 17 | std::cout << work_buff << std::endl; 18 | } 19 | 20 | // make string from local array 21 | return work_buff; 22 | } 23 | 24 | void FileWriter::Flush() 25 | { 26 | strm.clear(); 27 | } 28 | 29 | void FileWriter::Flush(const std::string& fpath) 30 | { 31 | std::ofstream wfile; 32 | wfile.open(fpath, std::ios::out); 33 | wfile << strm.rdbuf(); 34 | wfile.close(); 35 | Flush(); 36 | } 37 | 38 | void FileWriter::Append(const char* frmt, ...) 39 | { 40 | va_list args; 41 | va_start(args, frmt); 42 | auto ret = __print_loc__(frmt, args); 43 | va_end(args); 44 | Append(ret); 45 | } 46 | 47 | void FileWriter::AppendText(const char* frmt, ...) 48 | { 49 | va_list args; 50 | va_start(args, frmt); 51 | auto ret = __print_loc__(frmt, args); 52 | va_end(args); 53 | AppendText(ret); 54 | } 55 | 56 | void FileWriter::AppendText(const std::string& str) 57 | { 58 | strm << str; 59 | } 60 | 61 | void FileWriter::Append(const std::string& str) 62 | { 63 | if (str.empty()) 64 | { 65 | // the line is empty, just put 1 new empty line 66 | Append(); 67 | } 68 | else 69 | { 70 | AppendText(str); 71 | NewLine(str.back()); 72 | } 73 | } 74 | 75 | void FileWriter::Append(size_t empty_lines) 76 | { 77 | for (auto i = empty_lines; i != 0; --i) 78 | { 79 | NewLine(); 80 | } 81 | } 82 | 83 | void FileWriter::NewLine(const char c) 84 | { 85 | if (c != '\n') 86 | { 87 | strm << '\n'; 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /src/codegen/filewriter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | class FileWriter { 9 | public: 10 | 11 | void Flush(); 12 | void Flush(const std::string& filename); 13 | 14 | void Append(const char* frmt, ...); 15 | void Append(const std::string& str); 16 | 17 | void AppendText(const char* frmt, ...); 18 | void AppendText(const std::string& str); 19 | 20 | void Append(size_t empty_lines = 1); 21 | 22 | private: 23 | 24 | void NewLine(const char c = ' '); 25 | 26 | std::stringstream strm; 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /src/codegen/fs-creator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "fs-creator.h" 4 | #include "helpers/formatter.h" 5 | 6 | static const int32_t kTmpLen = 1024; 7 | 8 | static char _tmpb[kTmpLen]; 9 | 10 | static const char* kLibDir = "/lib"; 11 | static const char* kUsrDir = "/usr"; 12 | static const char* kIncDir = "/inc"; 13 | static const char* kConfDir = "/conf"; 14 | static const char* kUtilDir = "/butl"; 15 | 16 | FsCreator::FsCreator() 17 | { 18 | } 19 | 20 | 21 | void FsCreator::Configure(const std::string& drvname, 22 | const std::string& outpath, 23 | const std::string& commoninfo, 24 | const std::string& driverinfo, 25 | uint32_t highVer, 26 | uint32_t lowVer) 27 | { 28 | FS.file.libdir = outpath + kLibDir; 29 | FS.file.usrdir = outpath + kUsrDir; 30 | FS.file.incdir = outpath + kIncDir; 31 | FS.file.confdir = outpath + kConfDir; 32 | FS.file.utildir = outpath + kUtilDir; 33 | // directory valid and exists, set all the values 34 | FS.gen.DrvName_orig = drvname; 35 | FS.gen.DRVNAME = str_toupper(drvname); 36 | FS.gen.drvname = str_tolower(drvname); 37 | 38 | FS.file.core_h.dir = outpath; 39 | FS.file.core_h.fname = FS.gen.drvname + ".h"; 40 | FS.file.core_h.fpath = FS.file.libdir + "/" + FS.file.core_h.fname; 41 | 42 | FS.file.core_c.dir = outpath; 43 | FS.file.core_c.fname = FS.gen.drvname + ".c"; 44 | FS.file.core_c.fpath = FS.file.libdir + "/" + FS.file.core_c.fname; 45 | 46 | FS.file.util_h.dir = outpath; 47 | FS.file.util_h.fname = FS.gen.drvname + "-binutil" + ".h"; 48 | FS.file.util_h.fpath = FS.file.utildir + "/" + FS.file.util_h.fname; 49 | 50 | FS.file.util_c.dir = outpath; 51 | FS.file.util_c.fname = FS.gen.drvname + "-binutil" + ".c"; 52 | FS.file.util_c.fpath = FS.file.utildir + "/" + FS.file.util_c.fname; 53 | 54 | FS.file.fmon_h.dir = outpath; 55 | FS.file.fmon_h.fname = FS.gen.drvname + "-fmon.h"; 56 | FS.file.fmon_h.fpath = FS.file.libdir + "/" + FS.file.fmon_h.fname; 57 | 58 | FS.file.fmon_c.dir = outpath; 59 | FS.file.fmon_c.fname = FS.gen.drvname + "-fmon.c"; 60 | FS.file.fmon_c.fpath = FS.file.usrdir + "/" + FS.file.fmon_c.fname; 61 | 62 | snprintf(_tmpb, kTmpLen, "%s_USE_BITS_SIGNAL", FS.gen.DRVNAME.c_str()); 63 | FS.gen.usebits_def = _tmpb; 64 | 65 | snprintf(_tmpb, kTmpLen, "%s_USE_DIAG_MONITORS", FS.gen.DRVNAME.c_str()); 66 | FS.gen.usemon_def = _tmpb; 67 | 68 | snprintf(_tmpb, kTmpLen, "%s_USE_MONO_FMON", FS.gen.DRVNAME.c_str()); 69 | FS.gen.usemonofmon_def = _tmpb; 70 | 71 | snprintf(_tmpb, kTmpLen, "%s_USE_SIGFLOAT", FS.gen.DRVNAME.c_str()); 72 | FS.gen.usesigfloat_def = _tmpb; 73 | 74 | snprintf(_tmpb, kTmpLen, "%s_USE_CANSTRUCT", FS.gen.DRVNAME.c_str()); 75 | FS.gen.usesruct_def = _tmpb; 76 | 77 | snprintf(_tmpb, kTmpLen, "%s_AUTO_ROLL", FS.gen.DRVNAME.c_str()); 78 | FS.gen.useroll_def = _tmpb; 79 | 80 | snprintf(_tmpb, kTmpLen, "%s_AUTO_CSM", FS.gen.DRVNAME.c_str()); 81 | FS.gen.usecsm_def = _tmpb; 82 | 83 | snprintf(_tmpb, kTmpLen, "VER_%s_MAJ", FS.gen.DRVNAME.c_str()); 84 | FS.gen.verhigh_def = _tmpb; 85 | 86 | snprintf(_tmpb, kTmpLen, "VER_%s_MIN", FS.gen.DRVNAME.c_str()); 87 | FS.gen.verlow_def = _tmpb; 88 | 89 | // load start info to fdescriptor 90 | FS.gen.start_driver_info = driverinfo; 91 | FS.gen.start_common_info = commoninfo; 92 | FS.gen.hiver = highVer; 93 | FS.gen.lowver = lowVer; 94 | } 95 | 96 | bool FsCreator::PrepareDirectory(bool rw) 97 | { 98 | bool ret = false; 99 | 100 | // find free directory 101 | struct stat info; 102 | 103 | std::string work_dir_path; 104 | const auto& basepath = FS.file.core_h.dir; 105 | 106 | if (rw) 107 | { 108 | work_dir_path = basepath; 109 | ret = true; 110 | 111 | // for this case check only if directory exists 112 | if (stat(work_dir_path.c_str(), &info) != 0) 113 | { 114 | if (!std::filesystem::create_directory(work_dir_path)) 115 | { 116 | ret = false; 117 | } 118 | } 119 | } 120 | else 121 | { 122 | std::string separator = basepath.back() == '/' ? "" : "/"; 123 | 124 | for (int32_t dirnum = 0; dirnum < 1000; dirnum++) 125 | { 126 | snprintf(_tmpb, kTmpLen, "%03d", dirnum); 127 | work_dir_path = basepath + separator + _tmpb; 128 | 129 | if (stat(work_dir_path.c_str(), &info) != 0) 130 | { 131 | if (std::filesystem::create_directory(work_dir_path)) 132 | { 133 | ret = true; 134 | break; 135 | } 136 | } 137 | else if (info.st_mode & S_IFDIR) 138 | { 139 | // directory exists, try next num 140 | continue; 141 | } 142 | else 143 | { 144 | if (std::filesystem::create_directory(work_dir_path) != 0) 145 | { 146 | ret = false; 147 | break; 148 | } 149 | } 150 | } 151 | } 152 | 153 | std::filesystem::create_directory(FS.file.libdir); 154 | std::filesystem::create_directory(FS.file.usrdir); 155 | std::filesystem::create_directory(FS.file.incdir); 156 | std::filesystem::create_directory(FS.file.confdir); 157 | std::filesystem::create_directory(FS.file.utildir); 158 | 159 | return ret; 160 | } 161 | 162 | std::string FsCreator::CreateSubDir(std::string basepath, std::string sub, bool rw) 163 | { 164 | std::string ret = basepath; 165 | struct stat info; 166 | 167 | if (basepath.size() == 0 || sub.size() == 0) 168 | { 169 | return ""; 170 | } 171 | 172 | if (basepath.back() != '/') 173 | { 174 | basepath.append("/"); 175 | } 176 | 177 | basepath.append(sub); 178 | 179 | bool ok = true; 180 | 181 | if (stat(basepath.c_str(), &info) != 0 && rw) 182 | { 183 | // directory already exists and rewrite option is requested 184 | ok = std::filesystem::remove(basepath); 185 | } 186 | 187 | if (!ok) 188 | { 189 | // error on removing directory 190 | return ""; 191 | } 192 | 193 | if (std::filesystem::create_directory(basepath) != 0) 194 | { 195 | ret = ""; 196 | } 197 | 198 | return basepath; 199 | } 200 | -------------------------------------------------------------------------------- /src/codegen/fs-creator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../types/outfile.h" 6 | 7 | typedef struct 8 | { 9 | std::string libdir; 10 | std::string usrdir; 11 | std::string incdir; 12 | std::string confdir; 13 | std::string utildir; 14 | 15 | OutFileDescriptor_t core_h; 16 | OutFileDescriptor_t core_c; 17 | 18 | OutFileDescriptor_t util_h; 19 | OutFileDescriptor_t util_c; 20 | 21 | OutFileDescriptor_t fmon_h; 22 | OutFileDescriptor_t fmon_c; 23 | } FsDescriptor_t; 24 | 25 | typedef struct 26 | { 27 | // original driver name view 28 | std::string DrvName_orig; 29 | // low case driver name 30 | std::string drvname; 31 | // up case driver name 32 | std::string DRVNAME; 33 | 34 | std::string usebits_def; 35 | std::string usesruct_def; 36 | std::string usemon_def; 37 | std::string usemonofmon_def; 38 | std::string usesigfloat_def; 39 | std::string useroll_def; 40 | std::string usecsm_def; 41 | 42 | // for dbc version info 43 | std::string verhigh_def; 44 | std::string verlow_def; 45 | 46 | // text comment to be placed at the beggining of the driver's related source files 47 | std::string start_driver_info; 48 | // text comment to be placed at the beggining of each source files 49 | std::string start_common_info; 50 | 51 | uint32_t hiver{0}; 52 | uint32_t lowver{0}; 53 | 54 | bool no_fmon{false}; 55 | bool no_inc{false}; 56 | bool no_config{false}; 57 | } GenDescriptor_t; 58 | 59 | typedef struct 60 | { 61 | FsDescriptor_t file; 62 | GenDescriptor_t gen; 63 | } AppSettings_t; 64 | 65 | // This class is used to build all neccessary string -ed 66 | // value that will be required during code generation 67 | // (paths, file names, drvnames, common defines etc) 68 | // if preparation ends with true, the collection of 69 | // values can be used. 70 | class FsCreator { 71 | public: 72 | FsCreator(); 73 | 74 | void Configure(const std::string& drvname, 75 | const std::string& outpath, 76 | const std::string& commoninfo, 77 | const std::string& driverinfo, 78 | uint32_t highVer, 79 | uint32_t lowVer); 80 | bool PrepareDirectory(bool rw); 81 | 82 | std::string CreateSubDir(std::string basepath, std::string subdir, bool rm = true); 83 | 84 | AppSettings_t FS; 85 | 86 | }; 87 | 88 | -------------------------------------------------------------------------------- /src/codegen/mon-generator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mon-generator.h" 4 | #include "helpers/formatter.h" 5 | 6 | uint32_t MonGenerator::FillHeader(FileWriter& wr, std::vector& sigs, 7 | const AppSettings_t& aset) 8 | { 9 | wr.AppendText(aset.gen.start_common_info); 10 | wr.AppendText(aset.gen.start_driver_info); 11 | wr.Append("#pragma once"); 12 | wr.Append(); 13 | 14 | wr.Append("#ifdef __cplusplus\nextern \"C\" {\n#endif"); 15 | wr.Append(); 16 | 17 | wr.Append("// DBC file version"); 18 | wr.Append("#define %s_FMON (%uU)", aset.gen.verhigh_def.c_str(), aset.gen.hiver); 19 | wr.Append("#define %s_FMON (%uU)", aset.gen.verlow_def.c_str(), aset.gen.lowver); 20 | wr.Append(); 21 | 22 | wr.Append("#include \"%s-config.h\"", aset.gen.drvname.c_str()); 23 | wr.Append(); 24 | 25 | // put diagmonitor ifdef selection for including @drv-fmon header 26 | // with FMon_* signatures to call from unpack function 27 | wr.Append("#ifdef %s", aset.gen.usemon_def.c_str()); 28 | wr.Append(); 29 | wr.Append("#include \"canmonitorutil.h\""); 30 | wr.Append("/*\n\ 31 | This file contains the prototypes of all the functions that will be called\n\ 32 | from each Unpack_*name* function to detect DBC related errors\n\ 33 | It is the user responsibility to defined these functions in the\n\ 34 | separated .c file. If it won't be done the linkage error will happen\n*/"); 35 | wr.Append(); 36 | 37 | wr.Append("#ifdef %s_USE_MONO_FMON", aset.gen.DRVNAME.c_str()); 38 | wr.Append(); 39 | 40 | wr.Append("void _FMon_MONO_%s(FrameMonitor_t* _mon, uint32_t msgid);", aset.gen.drvname.c_str()); 41 | wr.Append(); 42 | 43 | for (auto it = sigs.begin(); it != sigs.end(); ++it) 44 | { 45 | 46 | auto msg = &((*it)->msg); 47 | wr.Append("#define FMon_%s_%s(x, y) _FMon_MONO_%s((x), (y))", msg->Name.c_str(), 48 | aset.gen.drvname.c_str(), 49 | aset.gen.drvname.c_str()); 50 | } 51 | 52 | wr.Append(); 53 | wr.Append("#else"); 54 | wr.Append(); 55 | 56 | for (auto it = sigs.begin(); it != sigs.end(); ++it) 57 | { 58 | auto msg = &((*it)->msg); 59 | wr.Append("void _FMon_%s_%s(FrameMonitor_t* _mon, uint32_t msgid);", 60 | msg->Name.c_str(), aset.gen.drvname.c_str()); 61 | } 62 | 63 | wr.Append(); 64 | 65 | for (auto it = sigs.begin(); it != sigs.end(); ++it) 66 | { 67 | auto msg = &((*it)->msg); 68 | wr.Append("#define FMon_%s_%s(x, y) _FMon_%s_%s((x), (y))", 69 | msg->Name.c_str(), aset.gen.drvname.c_str(), 70 | msg->Name.c_str(), aset.gen.drvname.c_str()); 71 | } 72 | 73 | wr.Append(); 74 | wr.Append("#endif"); 75 | wr.Append(); 76 | 77 | wr.Append("#endif // %s", aset.gen.usemon_def.c_str()); 78 | wr.Append(); 79 | 80 | wr.Append("#ifdef __cplusplus\n}\n#endif"); 81 | 82 | return 0; 83 | } 84 | 85 | uint32_t MonGenerator::FillSource(FileWriter& wr, std::vector& sigs, 86 | const AppSettings_t& aset) 87 | { 88 | wr.AppendText(aset.gen.start_common_info); 89 | wr.AppendText(aset.gen.start_driver_info); 90 | wr.Append("#include \"%s\"", aset.file.fmon_h.fname.c_str()); 91 | wr.Append(); 92 | // put diagmonitor ifdef selection for including @drv-fmon header 93 | // with FMon_* signatures to call from unpack function 94 | wr.Append("#ifdef %s", aset.gen.usemon_def.c_str()); 95 | wr.Append(); 96 | 97 | wr.Append("/*\n\ 98 | Put the monitor function content here, keep in mind -\n\ 99 | next generation will completely clear all manually added code (!)\n\ 100 | */\n\n"); 101 | 102 | wr.Append("#ifdef %s_USE_MONO_FMON", aset.gen.DRVNAME.c_str()); 103 | wr.Append(); 104 | wr.Append("void _FMon_MONO_%s(FrameMonitor_t* _mon, uint32_t msgid)", aset.gen.drvname.c_str()); 105 | wr.Append("{"); 106 | wr.Append(" (void)_mon;"); 107 | wr.Append(" (void)msgid;"); 108 | wr.Append("}"); 109 | wr.Append(); 110 | wr.Append("#else"); 111 | wr.Append(); 112 | 113 | for (auto it = sigs.begin(); it != sigs.end(); ++it) 114 | { 115 | auto msg = &((*it)->msg); 116 | wr.Append("void _FMon_%s_%s(FrameMonitor_t* _mon, uint32_t msgid)\n{\n (void)_mon;\n (void)msgid;\n}\n\n", 117 | msg->Name.c_str(), aset.gen.drvname.c_str()); 118 | } 119 | 120 | wr.Append("#endif // %s_USE_MONO_FMON", aset.gen.DRVNAME.c_str()); 121 | wr.Append(); 122 | 123 | wr.Append("#endif // %s", aset.gen.usemon_def.c_str()); 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /src/codegen/mon-generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "filewriter.h" 5 | #include "c-sigprinter.h" 6 | #include "fs-creator.h" 7 | 8 | class MonGenerator { 9 | public: 10 | 11 | MonGenerator() = default; 12 | 13 | uint32_t FillHeader(FileWriter& wr, std::vector& sigs, const AppSettings_t& gsett); 14 | uint32_t FillSource(FileWriter& wr, std::vector& sigs, const AppSettings_t& gsett); 15 | }; 16 | -------------------------------------------------------------------------------- /src/codegen/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define CODEGEN_LIB_VERSION_MAJ (3) 6 | #define CODEGEN_LIB_VERSION_MIN (1) 7 | -------------------------------------------------------------------------------- /src/conf-and-limits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //! Maximum length of CAN frame payload in bytes 6 | #define CONF_LIMIT_MAX_DLC 64u 7 | 8 | //! The highest possible bit position based on MAX Data size 9 | #define CONF_LIMIT_HIGHEST_BIT_POSITION (CONF_LIMIT_MAX_DLC * 8u) - 1u 10 | -------------------------------------------------------------------------------- /src/helpers/formatter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "formatter.h" 6 | 7 | static const size_t kMaxWorkArrLength = 4096; 8 | 9 | static char work_buff[kMaxWorkArrLength] = { 0 }; 10 | 11 | static const std::string __typeprint[8] = 12 | { 13 | "int8_t", 14 | "int16_t", 15 | "int32_t", 16 | "int64_t", 17 | "uint8_t", 18 | "uint16_t", 19 | "uint32_t", 20 | "uint64_t" 21 | }; 22 | 23 | std::string IndentedString(size_t n, const std::string& source, const char c) 24 | { 25 | if (source.length() >= n) 26 | { 27 | return source; 28 | } 29 | else 30 | { 31 | std::string indent(n - source.length(), c); 32 | return source + indent; 33 | } 34 | } 35 | 36 | const char* StrPrint(const char* format, ...) 37 | { 38 | va_list args; 39 | va_start(args, format); 40 | 41 | vsnprintf(work_buff, kMaxWorkArrLength, format, args); 42 | 43 | va_end(args); 44 | return work_buff; 45 | } 46 | 47 | std::string PrintType(uint8_t id) 48 | { 49 | if (id < 8) 50 | { 51 | return __typeprint[id]; 52 | } 53 | 54 | return ""; 55 | } 56 | 57 | std::string str_toupper(std::string s) 58 | { 59 | std::transform(s.begin(), s.end(), s.begin(), 60 | [](unsigned char c) 61 | { 62 | return std::toupper(c); 63 | }); 64 | return s; 65 | } 66 | 67 | std::string str_tolower(std::string s) 68 | { 69 | std::transform(s.begin(), s.end(), s.begin(), 70 | [](unsigned char c) 71 | { 72 | return std::tolower(c); 73 | }); 74 | return s; 75 | } 76 | 77 | std::string str_trim(std::string s) 78 | { 79 | size_t passed = 0; 80 | 81 | if (s.empty()) 82 | { 83 | return s + '\n'; 84 | } 85 | 86 | passed = 0; 87 | 88 | while (passed < s.size()) 89 | { 90 | if (s[s.size() - passed - 1] > ' ') 91 | { 92 | break; 93 | } 94 | 95 | ++passed; 96 | } 97 | 98 | if (passed != 0) 99 | { 100 | // remove tail with non-printable values 101 | s.erase(s.size() - passed, passed); 102 | } 103 | 104 | return s; 105 | } 106 | 107 | template 108 | static inline bool in_range(const char c) 109 | { 110 | return ((c >= L) && (c <= U)); 111 | } 112 | 113 | static bool is_first_valid(const char c) 114 | { 115 | return in_range<'a', 'z'>(c) || in_range<'A', 'Z'>(c) || c == '_'; 116 | } 117 | 118 | static bool is_nonfirst_valid(const char c) 119 | { 120 | return is_first_valid(c) || in_range<'0', '9'>(c); 121 | } 122 | 123 | std::string make_c_name(const std::string& s) 124 | { 125 | std::string ret{}; 126 | 127 | if (s.length() == 0) 128 | { 129 | return ret; 130 | } 131 | 132 | for (auto i = 0; i < s.length(); i++) 133 | { 134 | if ((ret.length() == 0 && is_first_valid(s[i])) || 135 | (ret.length() > 0 && is_nonfirst_valid(s[i]))) 136 | { 137 | // basic C-identifier rule 138 | ret += s[i]; 139 | } 140 | else if (s[i] == ' ') 141 | { 142 | // special case for whitespaces 143 | ret += '_'; 144 | } 145 | } 146 | 147 | return ret; 148 | } 149 | 150 | std::string prt_double(double value, size_t precision, bool usedot) 151 | { 152 | std::stringstream strstrm; 153 | strstrm.imbue(std::locale::classic()); 154 | strstrm << std::fixed << std::setprecision(10) << value; 155 | 156 | std::string s(strstrm.str()); 157 | 158 | size_t dotpos = s.find('.'); 159 | 160 | if (dotpos == std::string::npos) 161 | { 162 | // dot not found 163 | if (usedot) 164 | { 165 | s += ".0"; 166 | } 167 | 168 | return s; 169 | } 170 | 171 | // remove trailing zeros after decimal delimiter (dot char) 172 | size_t tailsize = std::min((s.size() - (dotpos + 1u)), precision); 173 | size_t addtail = 0u; 174 | 175 | for (size_t j = 0; j < tailsize; j++) 176 | { 177 | auto ch = s[dotpos + 1u + j]; 178 | 179 | if (ch > '0' && ch <= '9') 180 | { 181 | addtail = j + 1; 182 | } 183 | } 184 | 185 | if (addtail == 0) 186 | { 187 | // precision == 0 or xxx.0(0) resize cut tail with dot 188 | s.resize(dotpos); 189 | 190 | if (usedot) 191 | { 192 | s += ".0"; 193 | } 194 | } 195 | else 196 | { 197 | // xxx.x(x) 198 | s.resize(dotpos + addtail + 1); 199 | } 200 | 201 | return s; 202 | } 203 | -------------------------------------------------------------------------------- /src/helpers/formatter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::string IndentedString(size_t n, const std::string& source, const char c = ' '); 9 | 10 | const char* StrPrint(const char* format, ...); 11 | 12 | std::string PrintType(uint8_t tid); 13 | 14 | std::string str_toupper(std::string s); 15 | 16 | std::string str_tolower(std::string s); 17 | 18 | std::string str_trim(std::string s); 19 | 20 | /// @brief Function prints double value with dropping tailing zeros 21 | /// @param value value to format 22 | /// @param precision maximal precision length 23 | /// @param usedot true for forcibly print precision 1 (one digit after dot) 24 | /// @return string object fixed formatted value 25 | std::string prt_double(double value, size_t precision, bool usedot = true); 26 | 27 | /** 28 | * @brief Makes input string valid C-identifier 29 | * 30 | * @param s source string 31 | * @return std::string 32 | */ 33 | std::string make_c_name(const std::string& s); 34 | 35 | template 36 | std::string StrPrintLoc(const char* format, ...) 37 | { 38 | va_list args; 39 | va_start(args, format); 40 | 41 | // TODO: make N sanitizing here to prevent memory errors 42 | char work_buff[N] = {0}; 43 | 44 | vsnprintf(work_buff, N, format, args); 45 | 46 | va_end(args); 47 | 48 | // make string from local array 49 | return work_buff; 50 | } 51 | -------------------------------------------------------------------------------- /src/maincli.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "app.h" 5 | #include "options-parser.h" 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | OptionsParser parser; 10 | auto opts = parser.GetOptions(argc, argv); 11 | CoderApp app(opts); 12 | app.Run(); 13 | } 14 | -------------------------------------------------------------------------------- /src/options-parser.cpp: -------------------------------------------------------------------------------- 1 | #include "options-parser.h" 2 | #include "helpers/formatter.h" 3 | 4 | OptionsParser::GenOptions OptionsParser::GetOptions(int argc, char** argv) 5 | { 6 | using onepair_t = std::pair; 7 | 8 | std::vector temppairs{}; 9 | onepair_t pair{}; 10 | GenOptions retpairs{}; 11 | 12 | // collect arguments/values to vector 13 | for (int i = 0; i < argc; i++) 14 | { 15 | // key found (must start with '-' (e.g. '-dbc')) 16 | if (argv[i][0] == '-') 17 | { 18 | pair.first = std::string(argv[i]); 19 | pair.second.clear(); 20 | 21 | size_t valindex = i + 1; 22 | 23 | if ((valindex < argc) && (argv[valindex][0] != '-')) 24 | { 25 | // key param 26 | pair.second = std::string(argv[valindex]); 27 | // shift position to next key 28 | ++i; 29 | } 30 | 31 | temppairs.push_back(pair); 32 | } 33 | } 34 | 35 | for (size_t i = 0; i < temppairs.size(); i++) 36 | { 37 | if (temppairs[i].first.compare("-dbc") == 0) 38 | { 39 | retpairs.dbc.first = temppairs[i].second; 40 | retpairs.dbc.second = true; 41 | } 42 | else if (temppairs[i].first.compare("-out") == 0) 43 | { 44 | retpairs.outdir.first = temppairs[i].second; 45 | retpairs.outdir.second = true; 46 | } 47 | else if (temppairs[i].first.compare("-drvname") == 0) 48 | { 49 | retpairs.drvname.first = make_c_name(temppairs[i].second); 50 | retpairs.drvname.second = true; 51 | 52 | if (retpairs.drvname.first.length() == 0) 53 | { 54 | retpairs.drvname.second = false; 55 | } 56 | } 57 | else if (temppairs[i].first.compare("-rw") == 0) 58 | { 59 | retpairs.is_rewrite = true; 60 | } 61 | else if (temppairs[i].first.compare("-nodeutils") == 0) 62 | { 63 | retpairs.is_nodeutils = true; 64 | } 65 | else if (temppairs[i].first.compare("-help") == 0) 66 | { 67 | retpairs.is_help = true; 68 | } 69 | else if (temppairs[i].first.compare("-noinc") == 0) 70 | { 71 | retpairs.is_nocanmon = true; 72 | } 73 | else if (temppairs[i].first.compare("-noconfig") == 0) 74 | { 75 | retpairs.is_noconfig = true; 76 | } 77 | else if (temppairs[i].first.compare("-nofmon") == 0) 78 | { 79 | retpairs.is_nofmon = true; 80 | } 81 | else if (temppairs[i].first.compare("-driverdir") == 0) 82 | { 83 | retpairs.is_driver_dir = true; 84 | } 85 | else if (temppairs[i].first.compare("-gendate") == 0) 86 | { 87 | retpairs.add_gen_date = true; 88 | } 89 | } 90 | 91 | return retpairs; 92 | } 93 | -------------------------------------------------------------------------------- /src/options-parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /// @brief CLI arguments parser 10 | class OptionsParser { 11 | public: 12 | 13 | /// @brief key/value type wrapper 14 | using dualparam_t = std::pair; 15 | 16 | /// @brief Arguments description struct 17 | struct GenOptions 18 | { 19 | /// @brief dbc file name 20 | dualparam_t dbc; 21 | 22 | /// @brief output directory for generated files 23 | dualparam_t outdir; 24 | 25 | /// @brief main driver name 26 | dualparam_t drvname; 27 | 28 | /// @brief rewrite previously generated files or generate to next subdirectory 29 | bool is_rewrite{false}; 30 | 31 | /// @brief add additional directory named as dbc driver inside generation output directory 32 | bool is_driver_dir{false}; 33 | 34 | /// @brief add generation date at the beggining of the source file 35 | bool add_gen_date{false}; 36 | 37 | /// @brief generate specific utility drivers for each ECU defined in the matrix 38 | bool is_nodeutils{false}; 39 | 40 | /// @brief do not generate configuration file 41 | bool is_noconfig{false}; 42 | 43 | /// @brief do not generate canmonitorutil header 44 | bool is_nocanmon{false}; 45 | 46 | /// @brief do not generate fmon header 47 | bool is_nofmon{false}; 48 | 49 | /// @brief help is requested 50 | bool is_help{false}; 51 | }; 52 | 53 | /// @brief Parses arguments and theirs optional values 54 | /// @param argc arguments number 55 | /// @param argv pointer to array with arguments 56 | /// @return parsed arguments in structured form 57 | GenOptions GetOptions(int argc, char** argv); 58 | 59 | }; 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/parser/dbclineparser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "helpers/formatter.h" 7 | #include "dbclineparser.h" 8 | #include "conf-and-limits.h" 9 | 10 | /// @brief Minimal possible value for Factor/Offset 11 | constexpr double MIN_FAC_OFF = 0.000000001; 12 | 13 | // Message line definitions 14 | static const std::string regMessage = "[^A-Za-z0-9_.-]"; 15 | static const std::string MessageLineStart = "BO_ "; 16 | 17 | // Signal line definitions 18 | static const std::string kRegSigReceivers = "[^A-Za-z0-9_.+-]+"; 19 | static const std::string kRegSigSplit0 = "[^\\w]+"; 20 | static const std::string kRegSigSplit1 = "(\\s+:\\s+)"; 21 | static const std::string kregSigSplit2 = "(\")"; 22 | 23 | // This reg splits line to parts delimited by (") 24 | static const std::string kRegCommMain = "\""; 25 | static const std::string kRegCommMeta = "[ ]+"; 26 | 27 | // This reg splits line to parts (for attributes) 28 | static const std::string kRegAttrMain = "[^A-Za-z0-9_\\.]+"; 29 | static const std::string kTransmittersList = "[^a-zA-Z_0-9]+"; 30 | 31 | // Regex template to split string by spaces BUT NOT what inside quotes OR apostrophes 32 | // [^\s"']+|"([^"]*)"|'([^']*)' 33 | 34 | // Reges template to split string by spaces BUT NOT what inside quotes 35 | // [^\s"]+|"([^"]*)" 36 | 37 | static const std::string kRegValTable = "[^\\s\"]+|\"([^\"]*)\""; 38 | 39 | static uint64_t __maxunsigvalues[] = 40 | { 41 | UCHAR_MAX, 42 | USHRT_MAX, 43 | UINT_MAX, 44 | ULLONG_MAX 45 | }; 46 | 47 | static uint64_t __maxsignedvals[] = 48 | { 49 | CHAR_MAX, 50 | SHRT_MAX, 51 | INT_MAX, 52 | LLONG_MAX 53 | }; 54 | 55 | //* @param __submatch 56 | // - -1 each enumerated subexpression does NOT 57 | // match the regular expression (aka field 58 | // splitting) 59 | // - 0 the entire string matching the 60 | // subexpression is returned for each match 61 | // within the text. 62 | // - >0 enumerates only the indicated 63 | // subexpression from a match within the text. 64 | std::vector resplit(const std::string& s, const std::string& rgx_str, int32_t submatch) 65 | { 66 | std::vector elems; 67 | std::regex rgx(rgx_str); 68 | std::sregex_token_iterator iter(s.begin(), s.end(), rgx, submatch); 69 | std::sregex_token_iterator end; 70 | 71 | while (iter != end) 72 | { 73 | //std::cout << "S43:" << *iter << std::endl; 74 | elems.push_back(*iter); 75 | ++iter; 76 | } 77 | 78 | return elems; 79 | } 80 | 81 | std::string& ltrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") 82 | { 83 | str.erase(0, str.find_first_not_of(chars)); 84 | return str; 85 | } 86 | 87 | std::string& rtrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") 88 | { 89 | str.erase(str.find_last_not_of(chars) + 1); 90 | return str; 91 | } 92 | 93 | std::string& trim(std::string& str, const std::string& chars = "\t\n\v\f\r ") 94 | { 95 | return ltrim(rtrim(str, chars), chars); 96 | } 97 | 98 | static uint32_t clear_msgid(uint32_t messageid) 99 | { 100 | return messageid & 0x1FFFFFFFU; 101 | } 102 | 103 | DbcLineParser::DbcLineParser() 104 | { 105 | } 106 | 107 | bool DbcLineParser::IsMessageLine(const std::string& line) 108 | { 109 | if (line.find(MessageLineStart) == 0) 110 | { 111 | return true; 112 | } 113 | 114 | return false; 115 | } 116 | 117 | bool DbcLineParser::ParseMessageLine(MessageDescriptor_t* msg, const std::string& line) 118 | { 119 | // Parse DBC message line 120 | auto items = resplit(line, regMessage, -1); 121 | 122 | if (items.size() < 5) 123 | { 124 | return false; 125 | } 126 | 127 | std::string txname = (items.size() >= 6) ? (items[5]) : (""); 128 | 129 | if (txname.size() > 1) 130 | { 131 | msg->TranS.push_back(txname); 132 | } 133 | 134 | msg->Name = items[2]; 135 | 136 | msg->MsgID = static_cast(atoll(items[1].c_str())); 137 | 138 | msg->DLC = atoi(items[4].c_str()); 139 | 140 | if ((msg->MsgID & 0x60000000) != 0 || msg->DLC == 0 || msg->DLC > CONF_LIMIT_MAX_DLC) 141 | { 142 | return false; 143 | } 144 | 145 | msg->IsExt = ((uint8_t)(msg->MsgID >> 29) & 0x04) == 0x04 ? 1 : 0; 146 | 147 | msg->MsgID = clear_msgid(msg->MsgID); 148 | 149 | return true; 150 | } 151 | 152 | uint32_t DbcLineParser::ParseMultiTrans(std::vector& outnodes, std::string& line) 153 | { 154 | uint32_t ret = 0; 155 | 156 | auto chunks = resplit(line, kTransmittersList, -1); 157 | 158 | if (chunks.size() >= 3 && chunks[0] == "BO_TX_BU_") 159 | { 160 | ret = clear_msgid(static_cast(atoll(chunks[1].c_str()))); 161 | 162 | if (ret != 0) 163 | { 164 | for (size_t i = 2; i < chunks.size(); i++) 165 | { 166 | outnodes.push_back(chunks[i]); 167 | } 168 | } 169 | } 170 | 171 | return ret; 172 | } 173 | 174 | 175 | bool DbcLineParser::IsSignalLine(const std::string& line) 176 | { 177 | const std::regex sigMatch("\\s+SG_"); 178 | bool ret = std::regex_search(line, sigMatch); 179 | return ret; 180 | } 181 | 182 | bool DbcLineParser::ParseSignalLine(SignalDescriptor_t* sig, const std::string& line) 183 | { 184 | // split line in two parts 185 | auto halfs = resplit(line, kRegSigSplit1, -1); 186 | 187 | if (halfs.size() < 2) 188 | { 189 | return false; 190 | } 191 | 192 | // split tail 193 | auto tailpart = resplit(halfs[1], kregSigSplit2, -1); 194 | 195 | // split middle part on dedicated values 196 | auto valpart = resplit(trim(tailpart[0]), kRegSigReceivers, -1); 197 | 198 | halfs = resplit(halfs[0], kRegValTable, 0); 199 | 200 | if (halfs.size() >= 2) 201 | { 202 | sig->Name = halfs[1]; 203 | sig->Multiplex = MultiplexType::kNone; 204 | 205 | if (halfs.size() == 3) 206 | { 207 | // Multiplex signal, put additional comment 208 | if (halfs[2] == "M") 209 | { 210 | sig->Multiplex = MultiplexType::kMaster; 211 | } 212 | else 213 | { 214 | sig->Multiplex = MultiplexType::kMulValue; 215 | } 216 | } 217 | } 218 | else 219 | { 220 | // TODO: handle wrong split 221 | return false; 222 | } 223 | 224 | if (valpart.size() < 7) 225 | { 226 | return false; 227 | } 228 | else 229 | { 230 | sig->StartBit = atoi(valpart[0].c_str()); 231 | sig->LengthBit = atoi(valpart[1].c_str()); 232 | 233 | // get info about factor or offset double nature 234 | sig->IsDoubleSig = false; 235 | sig->IsSimpleSig = false; 236 | 237 | // for enabling double conversation the factor or offset 238 | // substring must have dot ('.') character 239 | if (valpart[3].find_first_of('.') != std::string::npos 240 | || valpart[4].find_first_of('.') != std::string::npos 241 | || valpart[3].find_first_of('E') != std::string::npos 242 | || valpart[3].find_first_of('e') != std::string::npos 243 | || valpart[4].find_first_of('E') != std::string::npos 244 | || valpart[4].find_first_of('e') != std::string::npos 245 | ) 246 | { 247 | sig->IsDoubleSig = true; 248 | } 249 | 250 | // factor = double; 251 | // offset = double; 252 | // 253 | // The factorand offset define the linear conversion rule to convert the signals raw 254 | // value into the signal's physical value and vice versa: 255 | // physical_value = raw_value * factor + offset 256 | // raw_value = (physical_value - offset) / factor 257 | std::setlocale(LC_ALL, "en_US.UTF-8"); 258 | 259 | sig->Factor = atof(valpart[3].c_str()); 260 | sig->Offset = atof(valpart[4].c_str()); 261 | 262 | if (((std::fabs(sig->Factor) < MIN_FAC_OFF) && (sig->Factor != 0.0)) || 263 | ((std::fabs(sig->Offset) < MIN_FAC_OFF) && (sig->Offset != 0.0))) 264 | { 265 | // this values are not supported, treat this signal as a plain integer 266 | sig->Factor = 1.0; 267 | sig->Offset = 0.0; 268 | sig->IsDoubleSig = false; 269 | } 270 | 271 | sig->RawOffset = sig->Offset / sig->Factor; 272 | 273 | sig->MinValue = atof(valpart[5].c_str()); 274 | sig->MaxValue = atof(valpart[6].c_str()); 275 | 276 | 277 | // Bytes layout 278 | // 0: Big endian (Motorolla) 279 | // 1: Little endian (Intel) 280 | sig->Order = (valpart[2].find('1') == std::string::npos) ? BitLayout::kMotorolla : BitLayout::kIntel; 281 | 282 | // value_type = '+' | '-'; (*+= unsigned, -=signed*) 283 | sig->Signed = (valpart[2].find('-') == std::string::npos) ? 0 : 1; 284 | 285 | GetSigType(sig); 286 | 287 | // mark all simple signals to make using them easier 288 | if (!sig->IsDoubleSig && (sig->Factor == 1) && (sig->Offset == 0)) 289 | { 290 | sig->IsSimpleSig = true; 291 | } 292 | 293 | if (!sig->IsSimpleSig) 294 | { 295 | // For this case the name of signal must be marked specially 296 | // to pay attention that if SIGFLOAT is enabled, this signal 297 | // must behave as ReadOnly (_ro) 298 | sig->NameFloat = sig->Name + "_phys"; 299 | sig->Name += "_ro"; 300 | } 301 | } 302 | 303 | if (tailpart.size() == 3) 304 | { 305 | // part 1 went on valpart 306 | // part 2 is the measure unit 307 | sig->Unit = tailpart[1]; 308 | // part 3 is the list of RX modules 309 | auto recs = resplit(trim(tailpart[2]), kRegSigReceivers, -1); 310 | 311 | for (size_t i = 0; i < recs.size(); i++) 312 | { 313 | sig->RecS.push_back(recs[i]); 314 | } 315 | } 316 | else 317 | { 318 | return false; 319 | } 320 | 321 | return true; 322 | } 323 | 324 | // TODO: refactor algorythm detection type of signal 325 | SigType DbcLineParser::GetSigType(SignalDescriptor_t* sig) 326 | { 327 | SigType ret = SigType::u64; 328 | 329 | uint8_t is_unsigned = 0; 330 | 331 | int64_t roffset = (int64_t)(sig->Offset / sig->Factor); 332 | 333 | uint64_t max_v = 0; 334 | 335 | // 1 step is to detect type of _ro 336 | int64_t max_abs, min_abs; 337 | 338 | int64_t addon = 0; 339 | 340 | if (sig->Signed) 341 | { 342 | addon = 1; 343 | max_abs = static_cast((std::pow(2, sig->LengthBit - 1) - 1)); 344 | min_abs = (max_abs + 1) * -1; 345 | 346 | for (size_t i = 0; i < 4; i++) 347 | { 348 | sig->TypeRo = (SigType)(i); 349 | 350 | if (max_abs <= __maxsignedvals[i]) 351 | { 352 | break; 353 | } 354 | } 355 | } 356 | else 357 | { 358 | max_abs = static_cast((std::pow(2, sig->LengthBit) - 1)); 359 | min_abs = 0; 360 | 361 | for (size_t i = 0; i < 4; i++) 362 | { 363 | sig->TypeRo = (SigType)(i + 4); 364 | 365 | if (max_abs <= __maxunsigvalues[i]) 366 | { 367 | break; 368 | } 369 | } 370 | } 371 | 372 | if (sig->IsSimpleSig) 373 | { 374 | // the most simple case, TypePhys is the same as TypeRo 375 | sig->TypePhys = sig->TypeRo; 376 | } 377 | 378 | else if (sig->IsDoubleSig == false) 379 | { 380 | int64_t i_offset = (int64_t)sig->Offset; 381 | int64_t i_factor = (int64_t)sig->Factor; 382 | 383 | // get max and min values with applied factor and offset (physical values) 384 | max_abs = max_abs * i_factor + i_offset; 385 | min_abs = min_abs * i_factor + i_offset; 386 | 387 | if (sig->Signed || max_abs < 0 || min_abs < 0) 388 | { 389 | // phys value must be signed 390 | uint64_t max_v = std::abs(max_abs); 391 | uint64_t addon = 0; 392 | 393 | if ((max_v + 1) < std::abs(min_abs)) 394 | { 395 | // low part is main 396 | addon = 1; 397 | max_v = std::abs(min_abs); 398 | } 399 | 400 | for (size_t i = 0; i < 4; i++) 401 | { 402 | sig->TypePhys = (SigType)(i); 403 | 404 | if (max_v <= __maxsignedvals[i] + addon) 405 | { 406 | break; 407 | } 408 | } 409 | } 410 | else 411 | { 412 | // phys value must be unsigned 413 | for (uint8_t i = 0; i < 4; i++) 414 | { 415 | if ((uint64_t)max_abs <= __maxunsigvalues[i]) 416 | { 417 | sig->TypePhys = (SigType)(i + 4); 418 | break; 419 | } 420 | } 421 | } 422 | } 423 | else 424 | { 425 | // in this case TypePhys will be (sigfloat_t), so 426 | // there is no necessity to determine physical signal type 427 | } 428 | 429 | return sig->TypeRo; 430 | } 431 | 432 | bool DbcLineParser::ParseCommentLine(Comment_t* cm, const std::string& line) 433 | { 434 | bool ret = false; 435 | 436 | if (line.size() > 0) 437 | { 438 | if (line.find("CM_") == 0) 439 | { 440 | commentline.clear(); 441 | commentline = line; 442 | } 443 | else if (commentline.size() > 0) 444 | { 445 | // next part of comment line, add to previously saved 446 | commentline += '\n' + line; 447 | } 448 | 449 | // check if the current line last 450 | if (commentline.size() > 0 && line.back() == ';') 451 | { 452 | // set invalid target type as default return value 453 | cm->ca_target = CommentTarget::Undefined; 454 | 455 | // comment line must have 3 part: meta, text, semicolon 456 | auto items = resplit(commentline, kRegCommMain, -1); 457 | 458 | if (items.size() == 3) 459 | { 460 | // part 1 (meta) contains service fields 461 | auto meta = resplit(items[0], kRegCommMeta, -1); 462 | 463 | if (meta.size() >= 3) 464 | { 465 | // 1 CM_ marker 466 | // 2 target (message or signal) 467 | // 3 msg id 468 | uint32_t id = static_cast(atoll(meta[2].c_str())); 469 | 470 | // clear message id from high 3 bits 471 | cm->MsgId = clear_msgid(id); 472 | 473 | if (meta[1] == "SG_" && meta.size() == 4) 474 | { 475 | // signal comment 476 | cm->ca_target = CommentTarget::Signal; 477 | cm->SigName = meta[3]; 478 | } 479 | else if (meta[1] == "BO_") 480 | { 481 | // message comment 482 | cm->ca_target = CommentTarget::Message; 483 | } 484 | 485 | // copy comment text 486 | cm->Text = items[1]; 487 | } 488 | 489 | if (cm->Text.size() > 0 && cm->Text.back() == '\n') 490 | { 491 | // remove last '\n' symbol in the string end 492 | cm->Text.pop_back(); 493 | } 494 | 495 | ret = true; 496 | } 497 | 498 | commentline.clear(); 499 | } 500 | } 501 | 502 | return ret; 503 | } 504 | 505 | bool DbcLineParser::ParseAttributeLine(AttributeDescriptor_t* attr, const std::string& line) 506 | { 507 | bool ret = false; 508 | 509 | if (line.size() > 0) 510 | { 511 | if (line.find("BA_ ") == 0) 512 | { 513 | attribline.clear(); 514 | attribline = line; 515 | } 516 | else if (attribline.size() > 0) 517 | { 518 | attribline += line; 519 | } 520 | 521 | // check if the current line is last 522 | if (attribline.size() > 0 && line.back() == ';') 523 | { 524 | attr->Type = AttributeType::Undefined; 525 | // raw line is ready 526 | auto items = resplit(attribline, kRegAttrMain, -1); 527 | 528 | if (items.size() > 4 && items[1] == "GenMsgCycleTime" && items[2] == "BO_") 529 | { 530 | attr->Type = AttributeType::CycleTime; 531 | attr->MsgId = clear_msgid(static_cast(atoll(items[3].c_str()))); 532 | // read value of ms of cycle time for the current message 533 | attr->Value = atoi(items[4].c_str()); 534 | ret = true; 535 | } 536 | 537 | attribline.clear(); 538 | } 539 | } 540 | 541 | return ret; 542 | } 543 | 544 | bool DbcLineParser::ParseValTableLine(Comment_t* comm, const std::string& line, ValTable_t& vtab) 545 | { 546 | bool ret = false; 547 | 548 | if (line.size() > 0) 549 | { 550 | if (line.find("VAL_ ") == 0) 551 | { 552 | valueline.clear(); 553 | valueline = line; 554 | } 555 | else if (valueline.size() > 0) 556 | { 557 | valueline += line; 558 | } 559 | 560 | // check if the current line is last 561 | if (valueline.size() > 0 && line.back() == ';') 562 | { 563 | // split all items by spaces and inside quotes. 564 | // after this step proper value items will have count >= 5 565 | // last item will be ';' and number of items will be even 566 | auto items = resplit(valueline, kRegValTable, 0); 567 | 568 | if ((items.size() >= 3) && (items.back() == ";") && (items.size() % 2 == 0)) 569 | { 570 | comm->MsgId = (clear_msgid(static_cast(atoll(items[1].c_str())))); 571 | comm->SigName = items[2]; 572 | comm->Text = ""; 573 | comm->ca_target = CommentTarget::Signal; 574 | 575 | // prepare value table container 576 | vtab.SigName = items[2]; 577 | vtab.vpairs.clear(); 578 | 579 | for (size_t valpair = 3; valpair < (items.size() - 1); valpair += 2) 580 | { 581 | comm->Text += " " + items[valpair + 0] + " : "; 582 | comm->Text += items[valpair + 1] + '\n'; 583 | 584 | auto valdef = make_c_name(items[valpair + 1]); 585 | vtab.vpairs.push_back({valdef, (uint32_t)atoll((items[valpair + 0]).c_str())}); 586 | } 587 | 588 | if (comm->Text.size() > 0) 589 | { 590 | // remove last '\n' symbol in the string end 591 | comm->Text.pop_back(); 592 | } 593 | 594 | // value table params were parse successfully 595 | ret = true; 596 | } 597 | 598 | valueline.clear(); 599 | } 600 | } 601 | 602 | return ret; 603 | } 604 | -------------------------------------------------------------------------------- /src/parser/dbclineparser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../types/message.h" 5 | 6 | //Information from official vector DBC format spec: 7 | // 8 | //The keywords used in DBC files o identify the type of an object are given in the 9 | //following table : 10 | //Keyword Object Type 11 | // BU_ Network Node 12 | // BO_ Message 13 | // SG_ Signal 14 | // EV_ Environment Variable 15 | // 16 | //The signal_size specifies the size of the signal in bits 17 | //byte_order = '0' | '1'; (*0 = little endian, 1 = big endian*) 18 | // 19 | //The byte_format is 0 if the signal's byte order is Intel (little endian) or 1 if the byte 20 | //order is Motorola(big endian). 21 | //value_type = '+' | '-'; (*+= unsigned, -=signed*) 22 | // 23 | // 24 | //The value_type defines the signal as being of type unsigned(-) or signed(-). 25 | //factor = double; 26 | //offset = double; 27 | //The factorand offset define the linear conversion rule to convert the signals raw 28 | //value into the signal's physical value and vice versa: 29 | //physical_value = raw_value * factor + offset 30 | //raw_value = (physical_value - offset) / factor 31 | //As can be seen in the conversion rule formulas the factor must not be 0. 32 | //minimum = double; 33 | //maximum = double; 34 | 35 | //The comment section contains the object comments.For each object having a 36 | //comment, an entry with the object's type identification is defined in this section. 37 | //comments = { comment }; 38 | //comment = 'CM_' (char_string | 39 | // 'BU_' node_name char_string | 40 | // 'BO_' message_id char_string | 41 | // 'SG_' message_id signal_name char_string | 42 | // 'EV_' env_var_name char_string) 43 | // ';'; 44 | 45 | class DbcLineParser { 46 | public: 47 | DbcLineParser(); 48 | 49 | // checks if the line is message description 50 | bool IsMessageLine(const std::string& line); 51 | // parses message line 52 | bool ParseMessageLine(MessageDescriptor_t* msg, const std::string& line = ""); 53 | 54 | // checks if the line is signal description 55 | bool IsSignalLine(const std::string& line); 56 | // parses signal line 57 | bool ParseSignalLine(SignalDescriptor_t* sig, const std::string& line); 58 | 59 | // tries to parse attribute line (or a few lines) and 60 | // loads result in attr struct, return @true if parsed ok 61 | bool ParseAttributeLine(AttributeDescriptor_t* attr, const std::string& line); 62 | 63 | // tries to parse comment information in line (or a few lines) 64 | // and loads result to cm struct, return @true if parsed ok 65 | bool ParseCommentLine(Comment_t* cm, const std::string& line); 66 | 67 | // tries to parse value table string in line 68 | // saves result as comment text in @cm object, and as 69 | // pairs of items (definition / value) in @vtab 70 | bool ParseValTableLine(Comment_t* cm, const std::string& line, ValTable_t& vtab); 71 | 72 | /** 73 | * @brief tries to find string with information about frame which has 74 | * multiple TX nodes 75 | * @param outnodes vector to load names of TX nodes 76 | * @param str line to parse from DBC file 77 | * @retval MsgId if parsed successfully or zero 78 | */ 79 | uint32_t ParseMultiTrans(std::vector& outnodes, std::string& str); 80 | 81 | private: 82 | // defines the type for the message struct member 83 | SigType GetSigType(SignalDescriptor_t* sig); 84 | 85 | // string to collect comment dbc line 86 | std::string commentline; 87 | 88 | // string to collect attribute dbc line 89 | std::string attribline; 90 | 91 | // strign to collect value line 92 | std::string valueline; 93 | }; 94 | 95 | -------------------------------------------------------------------------------- /src/parser/dbcscanner.cpp: -------------------------------------------------------------------------------- 1 | #include "dbcscanner.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../helpers/formatter.h" 10 | 11 | MessageDescriptor_t* find_message(vector msgs, uint32_t ID) 12 | { 13 | MessageDescriptor_t* ret = nullptr; 14 | 15 | if (msgs.size() == 0) 16 | { 17 | return ret; 18 | } 19 | 20 | for (size_t i = 0; i < msgs.size(); i++) 21 | { 22 | ret = msgs[i]; 23 | 24 | if (ret->MsgID == ID) 25 | { 26 | // Frame found 27 | break; 28 | } 29 | } 30 | 31 | return ret; 32 | } 33 | 34 | DbcScanner::DbcScanner() 35 | { 36 | dblist.maxDlcValue = 0u; 37 | } 38 | 39 | DbcScanner::~DbcScanner() 40 | { 41 | } 42 | 43 | int32_t DbcScanner::TrimDbcText(istream& readstrm) 44 | { 45 | dblist.msgs.clear(); 46 | dblist.ver.hi = dblist.ver.low = 0; 47 | 48 | readstrm.clear(); 49 | readstrm.seekg(0); 50 | // Search each message and signals in dbc source data, 51 | // and fill @msgs collection 52 | ParseMessageInfo(readstrm); 53 | 54 | // all the messages and signals were read from source 55 | // scan it one more time to define all attributes and 56 | // more additional information 57 | readstrm.clear(); 58 | readstrm.seekg(0); 59 | 60 | // Search all attributes and additional information 61 | // and update specific fields in messages 62 | ParseOtherInfo(readstrm); 63 | 64 | return 0; 65 | } 66 | 67 | 68 | void DbcScanner::ParseMessageInfo(istream& readstrm) 69 | { 70 | std::string sline; 71 | 72 | MessageDescriptor_t* pMsg = nullptr; 73 | 74 | while (std::getline(readstrm, sline)) 75 | { 76 | sline = str_trim(sline); 77 | 78 | FindVersion(sline); 79 | 80 | // New message line has been found 81 | if (lparser.IsMessageLine(sline)) 82 | { 83 | // if actual message, check DLC value for being max 84 | if ((pMsg != nullptr) && (pMsg->DLC > dblist.maxDlcValue)) 85 | { 86 | dblist.maxDlcValue = pMsg->DLC; 87 | } 88 | 89 | // the message will be added only if pMsg is not nullptr 90 | AddMessage(pMsg); 91 | 92 | // create instance for the detected message 93 | pMsg = new MessageDescriptor_t; 94 | 95 | SetDefualtMessage(pMsg); 96 | 97 | if (!lparser.ParseMessageLine(pMsg, sline)) 98 | { 99 | // the message has invalid format so drop it and wait next one 100 | delete pMsg; 101 | pMsg = nullptr; 102 | } 103 | } 104 | 105 | if (pMsg != nullptr && lparser.IsSignalLine(sline)) 106 | { 107 | SignalDescriptor_t sig; 108 | 109 | // parse signal line 110 | if (lparser.ParseSignalLine(&sig, sline)) 111 | { 112 | // set non empty flag to true once signal has been found and ready to be added into message 113 | pMsg->frameNotEmpty = true; 114 | 115 | // put successfully parsed signal to the message signals 116 | pMsg->Signals.push_back(sig); 117 | 118 | if (sig.IsDoubleSig || sig.IsSimpleSig != true) 119 | { 120 | pMsg->hasPhys = true; 121 | } 122 | } 123 | } 124 | 125 | std::vector tx_nodes; 126 | tx_nodes.clear(); 127 | 128 | uint32_t msgid = lparser.ParseMultiTrans(tx_nodes, sline); 129 | 130 | if (msgid != 0) 131 | { 132 | // In this place no messages will captured after, 133 | // so put temp pMsg as last message and null it 134 | AddMessage(pMsg); 135 | pMsg = nullptr; 136 | 137 | // Multi TXs line detected, expand information 138 | auto msg = find_message(dblist.msgs, msgid); 139 | 140 | if (msg != nullptr) 141 | { 142 | for (size_t i = 0; i < tx_nodes.size(); i++) 143 | { 144 | if (std::find(msg->TranS.begin(), msg->TranS.end(), tx_nodes[i]) == msg->TranS.end()) 145 | { 146 | // add another one RX node 147 | msg->TranS.push_back(tx_nodes[i]); 148 | } 149 | } 150 | } 151 | } 152 | } 153 | 154 | // check if the pMsg takes previous message 155 | AddMessage(pMsg); 156 | } 157 | 158 | 159 | void DbcScanner::ParseOtherInfo(istream& readstrm) 160 | { 161 | std::string sline; 162 | 163 | Comment_t cmmnt; 164 | 165 | ValTable_t vals; 166 | 167 | AttributeDescriptor_t attr; 168 | 169 | while (std::getline(readstrm, sline)) 170 | { 171 | sline = str_trim(sline); 172 | 173 | if (lparser.ParseCommentLine(&cmmnt, sline)) 174 | { 175 | // update message comment field 176 | auto msg = find_message(dblist.msgs, cmmnt.MsgId); 177 | 178 | if (msg != nullptr) 179 | { 180 | // comment line was found 181 | if (cmmnt.ca_target == CommentTarget::Message) 182 | { 183 | // put comment to message descriptor 184 | msg->CommentText = cmmnt.Text; 185 | } 186 | else if (cmmnt.ca_target == CommentTarget::Signal) 187 | { 188 | for (size_t i = 0; i < msg->Signals.size(); i++) 189 | { 190 | if ((cmmnt.SigName == msg->Signals[i].Name) || ((cmmnt.SigName + "_ro") == msg->Signals[i].Name)) 191 | { 192 | SignalDescriptor_t& sig = msg->Signals[i]; 193 | // signal has been found, update commnet text 194 | msg->Signals[i].CommentText = cmmnt.Text; 195 | 196 | // 1 test if signal is rolling 197 | if (cmmnt.Text.find("") != std::string::npos) 198 | { 199 | // set the RollSig to generate necessary code 200 | msg->RollSig = &msg->Signals[i]; 201 | } 202 | 203 | extern std::vector resplit(const std::string & s, const std::string & rgx_str, int32_t submatch); 204 | 205 | size_t openpos = cmmnt.Text.find('<'); 206 | 207 | if (openpos != std::string::npos) 208 | { 209 | size_t closepos = cmmnt.Text.find('>', openpos); 210 | 211 | if ((closepos != std::string::npos) && (closepos > (openpos + 1))) 212 | { 213 | auto substr = cmmnt.Text.substr(openpos + 1, closepos - 1); 214 | 215 | auto meta = resplit(substr, "(\\:)", -1); 216 | 217 | if (meta.size() == 3 && meta[0] == "Checksum") 218 | { 219 | // the signal can be CSM, but additional settings must be 220 | // checked: size, boundary, signal type 221 | bool boundary_ok = (sig.Order == BitLayout::kIntel) ? 222 | ((sig.StartBit / 8) == ((sig.StartBit + sig.LengthBit - 1) / 8)) : 223 | ((sig.StartBit / 8) == ((sig.StartBit - sig.LengthBit + 1) / 8)); 224 | 225 | if (sig.IsSimpleSig && boundary_ok && sig.Signed == false) 226 | { 227 | msg->CsmSig = &sig; 228 | msg->CsmMethod = meta[1]; 229 | msg->CsmOp = atoi(meta[2].c_str()); 230 | } 231 | } 232 | } 233 | } 234 | } 235 | } 236 | } 237 | } 238 | } 239 | 240 | if (lparser.ParseValTableLine(&cmmnt, sline, vals)) 241 | { 242 | // update message comment field 243 | auto msg = find_message(dblist.msgs, cmmnt.MsgId); 244 | 245 | if (msg != nullptr) 246 | { 247 | // comment line was found 248 | if (cmmnt.ca_target == CommentTarget::Message) 249 | { 250 | // put comment to message descriptor 251 | msg->CommentText = cmmnt.Text; 252 | } 253 | else if (cmmnt.ca_target == CommentTarget::Signal) 254 | { 255 | for (size_t i = 0; i < msg->Signals.size(); i++) 256 | { 257 | if (cmmnt.SigName == msg->Signals[i].Name) 258 | { 259 | // signal has been found, update commnet text 260 | msg->Signals[i].ValueText = cmmnt.Text; 261 | // save collected value table's definitions to signal 262 | msg->Signals[i].ValDefs = vals; 263 | } 264 | } 265 | } 266 | } 267 | } 268 | 269 | if (lparser.ParseAttributeLine(&attr, sline)) 270 | { 271 | auto msg = find_message(dblist.msgs, attr.MsgId); 272 | 273 | if (msg != nullptr) 274 | { 275 | // message was found, set attribute value 276 | if (attr.Type == AttributeType::CycleTime) 277 | { 278 | msg->Cycle = attr.Value; 279 | } 280 | } 281 | } 282 | } 283 | } 284 | 285 | 286 | void DbcScanner::AddMessage(MessageDescriptor_t* message) 287 | { 288 | if (message != nullptr) 289 | { 290 | if (message->Signals.size() > 0) 291 | { 292 | // sort signals by start bit 293 | std::sort(message->Signals.begin(), message->Signals.end(), 294 | [](const SignalDescriptor_t& a, const SignalDescriptor_t& b) -> bool 295 | { 296 | return a.StartBit < b.StartBit; 297 | }); 298 | 299 | for (size_t i = 0; i < message->Signals.size(); i++) 300 | { 301 | for (size_t j = 0; j < message->Signals[i].RecS.size(); j++) 302 | { 303 | string val = message->Signals[i].RecS[j]; 304 | 305 | if (std::find(message->RecS.begin(), message->RecS.end(), val) == message->RecS.end()) 306 | { 307 | // add another one RX node 308 | message->RecS.push_back(val); 309 | } 310 | } 311 | } 312 | } 313 | 314 | // save pointer on message 315 | dblist.msgs.push_back(message); 316 | } 317 | } 318 | 319 | 320 | void DbcScanner::SetDefualtMessage(MessageDescriptor_t* message) 321 | { 322 | message->CommentText = ""; 323 | message->Cycle = 0; 324 | message->DLC = 0; 325 | message->IsExt = false; 326 | message->MsgID = 0; 327 | message->Name = ""; 328 | message->RecS.clear(); 329 | message->Signals.clear(); 330 | message->TranS.clear(); 331 | message->hasPhys = false; 332 | message->frameNotEmpty = false; 333 | message->RollSig = nullptr; 334 | message->CsmSig = nullptr; 335 | message->CsmMethod = ""; 336 | message->CsmOp = 0; 337 | message->CsmToByteExpr = ""; 338 | } 339 | 340 | 341 | /// @brief Parses the line to extract a string and two unsigned integers. 342 | /// @param line The input line to parse. 343 | /// @param str The extracted string. 344 | /// @param num1 The first extracted unsigned integer. 345 | /// @param num2 The second extracted unsigned integer. 346 | /// @return The number of successfully matched parts (0 if the pattern did not match). 347 | static bool ParseVersionLine(const std::string& line, std::string& str, uint32_t& num1, uint32_t& num2) 348 | { 349 | std::regex pattern("([a-zA-Z]+)\\s*\"?(\\d+)\\D+(\\d+)\"?"); 350 | std::smatch matches; 351 | 352 | // try to match the regex pattern to the input line 353 | if (std::regex_match(line, matches, pattern)) 354 | { 355 | if (matches.size() == 4) 356 | { 357 | // 1 for the whole match and 3 for the capture groups 358 | str = matches[1].str(); 359 | num1 = std::stoul(matches[2].str()); 360 | num2 = std::stoul(matches[3].str()); 361 | // successfully matched all three parts 362 | return true; 363 | } 364 | } 365 | 366 | // pattern did not match or some parts were not matched 367 | return false; 368 | } 369 | 370 | void DbcScanner::FindVersion(const std::string& line) 371 | { 372 | std::istringstream stream(line); 373 | std::string versionStr; 374 | uint32_t num1, num2; 375 | 376 | if (ParseVersionLine(line, versionStr, num1, num2) == false) 377 | { 378 | // pattern did not match or not all parts were successfully parsed 379 | return; 380 | } 381 | 382 | // check if the string is composed only of alphabetic characters 383 | if (!std::all_of(versionStr.begin(), versionStr.end(), [](char c) { return std::isalpha(c); })) 384 | { 385 | // the string part is not purely alphabetic 386 | return; 387 | } 388 | 389 | // convert the extracted string to lowercase for case-insensitive comparison 390 | std::string lowerStr = versionStr; 391 | std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower); 392 | 393 | // compare the lowercase string with "version" 394 | if (lowerStr == "version") 395 | { 396 | // versions have been found, save numeric values 397 | dblist.ver.hi = num1; 398 | dblist.ver.low = num2; 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /src/parser/dbcscanner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../types/message.h" 7 | #include "dbclineparser.h" 8 | 9 | using namespace std; 10 | 11 | class DbcScanner { 12 | public: 13 | DbcScanner(); 14 | ~DbcScanner(); 15 | 16 | DbcMessageList_t dblist; 17 | 18 | // Trim makes dbc source data analyze and returns count of 19 | // found CAN messages. 20 | int32_t TrimDbcText(istream& instrm); 21 | 22 | private: 23 | 24 | void ParseMessageInfo(istream& instrm); 25 | void ParseOtherInfo(istream& instrm); 26 | void AddMessage(MessageDescriptor_t* message); 27 | void SetDefualtMessage(MessageDescriptor_t* message); 28 | void FindVersion(const std::string& line); 29 | 30 | private: 31 | 32 | DbcLineParser lparser; 33 | 34 | // this variable is used for gathering value table signal's information 35 | std::pair vpairs; 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /src/tests/args-test.cpp: -------------------------------------------------------------------------------- 1 | #include "testapi.h" 2 | #include 3 | 4 | TEST(ArgParserTest, BasicAssert) 5 | { 6 | static char* testchunks[] = 7 | { 8 | (char*)"appname", 9 | (char*)"-out", 10 | (char*)"path/to/out", 11 | (char*)"-dbc", 12 | (char*)"path/to/test.dbc", 13 | (char*)"-drvname", 14 | (char*)"testdbc", 15 | (char*)"-rw" 16 | }; 17 | 18 | OptionsParser parser; 19 | auto ret = parser.GetOptions(9, testchunks); 20 | 21 | expect_true(ret.dbc.second); 22 | expect_true(ret.dbc.first.compare("path/to/test.dbc") == 0); 23 | 24 | expect_true(ret.outdir.second); 25 | expect_true(ret.outdir.first.compare("path/to/out") == 0); 26 | 27 | expect_true(ret.drvname.second); 28 | expect_true(ret.drvname.first.compare("testdbc") == 0); 29 | 30 | expect_true(ret.is_rewrite); 31 | expect_false(ret.is_help); 32 | expect_false(ret.is_noconfig); 33 | expect_false(ret.is_nodeutils); 34 | expect_false(ret.is_nofmon); 35 | expect_false(ret.is_nocanmon); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/tests/bitext-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "testapi.h" 3 | 4 | template 5 | static iT bitext(uT val, uint8_t bits) 6 | { 7 | uT const m = (uT)(1u << (bits - 1u)); 8 | return ((val ^ m) - m); 9 | } 10 | 11 | TEST(TestBitExt, FullTest) 12 | { 13 | // 1 test: 3 bits signal 14 | static const int32_t cmp[] {0, 1, 2, 3, -4, -3, -2, -1}; 15 | 16 | for (auto val = 0; val < 8; val++) 17 | { 18 | auto ret = bitext(val, 3); 19 | expect_eq(ret, cmp[val]); 20 | } 21 | 22 | static const uint8_t val2[] { 126, 127, 128, 129, 255, 0, 1}; 23 | static const int32_t cmp2[] { 126, 127, -128, -127, -1, 0, 1}; 24 | 25 | for (uint8_t i = 0; i < 7; i++) 26 | { 27 | auto ret = bitext(val2[i], 8); 28 | expect_eq(ret, cmp2[i]); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/tests/dbcline-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "testapi.h" 3 | #include "parser/dbclineparser.h" 4 | #include "helpers/formatter.h" 5 | 6 | 7 | TEST(TestSigLineParsing, test1) 8 | { 9 | DbcLineParser parser; 10 | 11 | const std::string t2 = " SG_ FLT4_TEST_1 : 39|4@0+ (2.01,1E-002) [-0.01|30.14] \"\" BCM"; 12 | 13 | expect_true(parser.IsSignalLine(t2)); 14 | 15 | SignalDescriptor_t dsc; 16 | 17 | parser.ParseSignalLine(&dsc, t2); 18 | 19 | expect_true(dsc.IsDoubleSig); 20 | expect_true(dsc.Offset == 0.01); 21 | 22 | const std::string t3 = " SG_ FLT4_TEST_1 : 39|4@0+ (2, 1) [-0.01|30.14] \"\" BCM"; 23 | 24 | parser.ParseSignalLine(&dsc, t3); 25 | 26 | expect_false(dsc.IsDoubleSig); 27 | expect_true(dsc.Offset == 1.0); 28 | 29 | // last supported double values 30 | const std::string t2_ok_norm = " SG_ FLT4_TEST_1 : 39|4@0+ (2, 0.000000001) [-0.01|30.14] \"\" BCM"; 31 | const std::string t2_ok_scie = " SG_ FLT4_TEST_1 : 39|4@0+ (2, 1e-9) [-0.01|30.14] \"\" BCM"; 32 | // next values (and less than) are not currently supported 33 | const std::string t2_nok_norm = " SG_ FLT4_TEST_1 : 39|4@0+ (2, 0.00000000099) [-0.01|30.14] \"\" BCM"; 34 | const std::string t2_nok_scie = " SG_ FLT4_TEST_1 : 39|4@0+ (2, 1e-10) [-0.01|30.14] \"\" BCM"; 35 | const std::string t3_nok_scie = " SG_ FLT4_TEST_1 : 39|4@0+ (1e-10, 44) [-0.01|30.14] \"\" BCM"; 36 | const std::string t3_nok_norm = " SG_ FLT4_TEST_1 : 39|4@0+ (0.00000000099, 2) [-0.01|30.14] \"\" BCM"; 37 | 38 | parser.ParseSignalLine(&dsc, t2_ok_norm); 39 | 40 | expect_true(dsc.IsDoubleSig); 41 | expect_eq(dsc.Offset, 0.000000001); 42 | expect_eq(dsc.Factor, 2.0); 43 | 44 | parser.ParseSignalLine(&dsc, t2_ok_scie); 45 | 46 | expect_true(dsc.IsDoubleSig); 47 | expect_eq(dsc.Offset, 0.000000001); 48 | expect_eq(dsc.Factor, 2.0); 49 | 50 | parser.ParseSignalLine(&dsc, t3_nok_norm); 51 | 52 | expect_false(dsc.IsDoubleSig); 53 | expect_eq(dsc.Offset, 0.0); 54 | expect_eq(dsc.Factor, 1.0); 55 | 56 | parser.ParseSignalLine(&dsc, t3_nok_scie); 57 | 58 | expect_false(dsc.IsDoubleSig); 59 | expect_eq(dsc.Offset, 0.0); 60 | expect_eq(dsc.Factor, 1.0); 61 | 62 | } 63 | 64 | TEST(TestSigLineParsing, test_02) 65 | { 66 | const std::string t3_ok = " SG_ FLT4_TEST_1 : 39|4@0+ (0.99, 0) [-0.01|30.14] \"\" BCM"; 67 | const std::string t4_ok = " SG_ FLT4_TEST_1 : 39|4@0+ (0, -0.11) [-0.01|30.14] \"\" BCM"; 68 | const std::string t5_notok = " SG_ FLT4_TEST_1 : 39|4@0+ (0.00000000099, 0) [-0.01|30.14] \"\" BCM"; 69 | const std::string t6_ok = " SG_ FLT4_TEST_1 : 39|4@0+ (0, 0.000000000000) [-0.01|30.14] \"\" BCM"; 70 | 71 | DbcLineParser parser; 72 | 73 | SignalDescriptor_t dsc; 74 | 75 | parser.ParseSignalLine(&dsc, t3_ok); 76 | 77 | expect_true(dsc.IsDoubleSig); 78 | 79 | parser.ParseSignalLine(&dsc, t4_ok); 80 | 81 | expect_true(dsc.IsDoubleSig); 82 | expect_eq(dsc.Factor, 0.0); 83 | expect_eq(dsc.Offset, -0.11); 84 | 85 | parser.ParseSignalLine(&dsc, t5_notok); 86 | 87 | expect_false(dsc.IsDoubleSig); 88 | expect_eq(dsc.Factor, 1.0); 89 | expect_eq(dsc.Offset, 0.0); 90 | 91 | parser.ParseSignalLine(&dsc, t6_ok); 92 | 93 | expect_true(dsc.IsDoubleSig); 94 | expect_eq(dsc.Factor, 0.0); 95 | expect_eq(dsc.Offset, 0.0); 96 | 97 | } 98 | 99 | TEST(TestSigLineParsing, test_prt_double) 100 | { 101 | constexpr double v = -124.10001110002220; 102 | 103 | expect_eq(prt_double(v, 0, false), "-124"); 104 | expect_eq(prt_double(v, 1, false), "-124.1"); 105 | expect_eq(prt_double(v, 2, false), "-124.1"); 106 | expect_eq(prt_double(v, 3, false), "-124.1"); 107 | expect_eq(prt_double(v, 4, false), "-124.1"); 108 | expect_eq(prt_double(v, 5, false), "-124.10001"); 109 | expect_eq(prt_double(v, 6, false), "-124.100011"); 110 | expect_eq(prt_double(v, 7, false), "-124.1000111"); 111 | expect_eq(prt_double(v, 8, false), "-124.1000111"); 112 | expect_eq(prt_double(v, 9, false), "-124.1000111"); 113 | 114 | constexpr double vint = 123.0000; 115 | 116 | expect_eq(prt_double(vint, 3), "123.0"); 117 | expect_eq(prt_double(vint, 2), "123.0"); 118 | expect_eq(prt_double(vint, 1), "123.0"); 119 | expect_eq(prt_double(vint, 0), "123.0"); 120 | expect_eq(prt_double(vint, 0, false), "123"); 121 | expect_eq(prt_double(vint, 1, false), "123"); 122 | expect_eq(prt_double(vint, 100), "123.0"); 123 | expect_eq(prt_double(vint, 1000), "123.0"); 124 | 125 | constexpr double v2 = 0.0110022; 126 | 127 | expect_eq(prt_double(v2, 0), "0.0"); 128 | 129 | constexpr double v3 = -20.47; 130 | 131 | expect_eq(prt_double(v3, 2), "-20.47"); 132 | expect_eq(prt_double(v3, 10), "-20.47"); 133 | 134 | constexpr double v4 = 20.4699999999; 135 | 136 | expect_eq(prt_double(v4, 9), "20.469999999"); 137 | expect_eq(prt_double(v4, 8), "20.46999999"); 138 | expect_eq(prt_double(v4, 7), "20.4699999"); 139 | expect_eq(prt_double(v4, 3), "20.469"); 140 | 141 | constexpr double v5 = -20.4699999999; 142 | 143 | expect_eq(prt_double(v5, 8), "-20.46999999"); 144 | expect_eq(prt_double(v5, 7), "-20.4699999"); 145 | expect_eq(prt_double(v5, 3), "-20.469"); 146 | expect_eq(prt_double(v5, 10), "-20.4699999999"); 147 | expect_eq(prt_double(v5, 11), "-20.4699999999"); 148 | expect_eq(prt_double(v5, 15), "-20.4699999999"); 149 | 150 | constexpr double v6 = 123.012345678900000; 151 | expect_eq(prt_double(v6, 10), "123.0123456789"); 152 | expect_eq(prt_double(v6, 11), "123.0123456789"); 153 | expect_eq(prt_double(v6, 15), "123.0123456789"); 154 | } 155 | -------------------------------------------------------------------------------- /src/tests/testapi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define expect_eq EXPECT_EQ 6 | #define expect_true EXPECT_TRUE 7 | #define expect_false EXPECT_FALSE 8 | -------------------------------------------------------------------------------- /src/types/attributes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /// @brief Message attributes 8 | enum class AttributeType 9 | { 10 | /// @brief Message cycle time attribute 11 | CycleTime, 12 | 13 | /// @brief Undefined attribute 14 | Undefined 15 | }; 16 | 17 | struct AttributeDescriptor_t 18 | { 19 | /// @brief Attribute message ID 20 | uint32_t MsgId; 21 | 22 | /// @brief Attribute type 23 | AttributeType Type; 24 | 25 | /// @brief Attribute value 26 | int32_t Value; 27 | }; 28 | -------------------------------------------------------------------------------- /src/types/c-expr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "message.h" 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | 11 | MessageDescriptor_t msg; 12 | 13 | // this field contains all expressions for converting 14 | // data bytes to actual signals 15 | std::vector to_signals; 16 | 17 | // this field contains all expressions for converting 18 | // frame fields to data bytes 19 | std::vector to_bytes; 20 | 21 | } CiExpr_t; -------------------------------------------------------------------------------- /src/types/comment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /// @brief Type of commented value 8 | enum class CommentTarget 9 | { 10 | /// @brief Comment is for CAN message 11 | Message, 12 | /// @brief Comment is for CAN message signal 13 | Signal, 14 | /// @brief Invalid type 15 | Undefined 16 | }; 17 | 18 | 19 | /// @brief Comment descripton 20 | struct Comment_t 21 | { 22 | /// @brief Message ID for which comment is bound 23 | uint32_t MsgId; 24 | 25 | /// @brief Signal name for which comment is bound 26 | std::string SigName; 27 | 28 | /// @brief Comment target type 29 | CommentTarget ca_target; 30 | 31 | /// @brief Comment text 32 | std::string Text; 33 | }; 34 | 35 | 36 | /// @brief Value table inforamtion 37 | struct ValTable_t 38 | { 39 | /// @brief Signal name for which value table is applied 40 | std::string SigName; 41 | 42 | /// @brief Value table names and values pairs 43 | std::vector> vpairs{}; 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /src/types/message.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "attributes.h" 8 | #include "comment.h" 9 | 10 | enum class BitLayout 11 | { 12 | kIntel = 0, 13 | kMotorolla 14 | }; 15 | 16 | enum class MultiplexType 17 | { 18 | kNone, 19 | kMaster, 20 | kMulValue 21 | }; 22 | 23 | enum class SigType 24 | { 25 | i8 = 0, 26 | i16, 27 | i32, 28 | i64, 29 | u8, 30 | u16, 31 | u32, 32 | u64 33 | }; 34 | 35 | 36 | typedef struct 37 | { 38 | // Signal name 39 | std::string Name; 40 | // Signal float name 41 | std::string NameFloat; 42 | // Unit 43 | std::string Unit; 44 | 45 | uint32_t StartBit; 46 | 47 | uint8_t LengthBit; 48 | 49 | // By next two fields any signal can be strictly related to one of 50 | // 3 signal type: 51 | // 1 double based scaled value (IsDoubleSig == true) 52 | // 2 integer based scaled value (IsDoubleSig == false && IsSimpleSig == false) 53 | // 3 simple (IsDoubleSig == false && IsSimpleSig == true) 54 | 55 | // this flag shows when factor (or offset) is double 56 | // it is used when *_from_S and _to_S macros is generated 57 | bool IsDoubleSig; 58 | 59 | // this flag shows if the signal has factor = 1 and offset = 0 60 | // to reject any sigfloat or "toS"/"fromS" operations 61 | // SimpleSig is true when: IsDoubleSig == false && Factor == 1 && Offset == 0 62 | bool IsSimpleSig; 63 | 64 | double Factor; 65 | 66 | double Offset; 67 | 68 | double RawOffset; 69 | 70 | BitLayout Order; 71 | 72 | bool Signed; 73 | 74 | SigType TypeRo; 75 | 76 | SigType TypePhys; 77 | 78 | std::vector SigToByte; 79 | 80 | double MinValue; 81 | 82 | double MaxValue; 83 | 84 | std::vector RecS; 85 | 86 | ValTable_t ValDefs; 87 | 88 | std::string CommentText; 89 | 90 | std::string ValueText; 91 | 92 | MultiplexType Multiplex; 93 | 94 | } SignalDescriptor_t; 95 | 96 | typedef struct 97 | { 98 | 99 | // Pointer on message name 100 | std::string Name; 101 | 102 | // Value of message length in bytes 103 | uint8_t DLC; 104 | 105 | // Message CAN identifier 106 | uint32_t MsgID; 107 | 108 | // Extended frame type mark, if 0 then standart frame 109 | uint8_t IsExt; 110 | 111 | // Frame cycle time im ms 112 | uint32_t Cycle; 113 | 114 | // Name of transmitter ECU 115 | std::vector TranS; 116 | 117 | // List of ECUs to receive frame 118 | std::vector RecS; 119 | 120 | // List of Message signals 121 | std::vector Signals; 122 | 123 | // flag about having sigfloat fields 124 | bool hasPhys; 125 | 126 | // flag if frame has at least one signal (not empty) 127 | bool frameNotEmpty; 128 | 129 | // pointer to rolling counter signal 130 | SignalDescriptor_t* RollSig; 131 | 132 | // pointer to checksum signal 133 | SignalDescriptor_t* CsmSig; 134 | 135 | // keeps the method or crc algorythm (will be passed to CRC calc function) 136 | std::string CsmMethod; 137 | 138 | // option value (will be passed to CRC calc function) 139 | uint32_t CsmOp; 140 | 141 | // expression to load CSM signal to byte 142 | std::string CsmToByteExpr; 143 | 144 | // byte number in payload which keeps CS value 145 | uint8_t CsmByteNum; 146 | 147 | // Message comment 148 | std::string CommentText; 149 | 150 | } MessageDescriptor_t; 151 | 152 | typedef struct 153 | { 154 | std::vector Rx; 155 | 156 | std::vector Tx; 157 | 158 | std::vector Both; 159 | 160 | } MsgsClassification; 161 | 162 | typedef struct 163 | { 164 | uint32_t hi; 165 | uint32_t low; 166 | } DbcFileVersion_t; 167 | 168 | typedef struct 169 | { 170 | // Array of all the parsed messages from DBC file 171 | std::vector msgs; 172 | // The value of maximum DLC value among the parsed messages 173 | size_t maxDlcValue; 174 | // DBC file version values to be printed as macro values inside driver source code 175 | DbcFileVersion_t ver; 176 | } DbcMessageList_t; 177 | -------------------------------------------------------------------------------- /src/types/outfile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | typedef struct 7 | { 8 | std::string dir; 9 | 10 | std::string fpath; 11 | 12 | std::string fname; 13 | 14 | } OutFileDescriptor_t; 15 | -------------------------------------------------------------------------------- /test/gencode/butl/bcm_testdb-binutil.c: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #include "bcm_testdb-binutil.h" 4 | 5 | // DBC file version 6 | #if (VER_TESTDB_MAJ != (1U)) || (VER_TESTDB_MIN != (10U)) 7 | #error The BCM_TESTDB binutil source file has inconsistency with core dbc lib! 8 | #endif 9 | 10 | #ifdef __DEF_BCM_TESTDB__ 11 | 12 | bcm_testdb_rx_t bcm_testdb_rx; 13 | 14 | bcm_testdb_tx_t bcm_testdb_tx; 15 | 16 | #endif // __DEF_BCM_TESTDB__ 17 | 18 | uint32_t bcm_testdb_Receive(bcm_testdb_rx_t* _m, const uint8_t* _d, uint32_t _id, uint8_t dlc_) 19 | { 20 | uint32_t recid = 0; 21 | if (_id == 0x360U) { 22 | recid = Unpack_FLT_TEST_1_testdb(&(_m->FLT_TEST_1), _d, dlc_); 23 | } else { 24 | if (_id == 0x777U) { 25 | recid = Unpack_SIG_TEST_1_testdb(&(_m->SIG_TEST_1), _d, dlc_); 26 | } else if (_id == 0x1FFFFFF6U) { 27 | recid = Unpack_EMPTY_EXT_ID_testdb(&(_m->EMPTY_EXT_ID), _d, dlc_); 28 | } 29 | } 30 | 31 | return recid; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /test/gencode/butl/bcm_testdb-binutil.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #pragma once 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include "dbccodeconf.h" 10 | 11 | #include "testdb.h" 12 | 13 | typedef struct 14 | { 15 | FLT_TEST_1_t FLT_TEST_1; 16 | SIG_TEST_1_t SIG_TEST_1; 17 | EMPTY_EXT_ID_t EMPTY_EXT_ID; 18 | } bcm_testdb_rx_t; 19 | 20 | typedef struct 21 | { 22 | UTEST_2_t UTEST_2; 23 | EMPTY_0_t EMPTY_0; 24 | UTEST_3_t UTEST_3; 25 | EMPTY_EXT_ID_t EMPTY_EXT_ID; 26 | } bcm_testdb_tx_t; 27 | 28 | uint32_t bcm_testdb_Receive(bcm_testdb_rx_t* m, const uint8_t* d, uint32_t msgid, uint8_t dlc); 29 | 30 | #ifdef __DEF_BCM_TESTDB__ 31 | 32 | extern bcm_testdb_rx_t bcm_testdb_rx; 33 | 34 | extern bcm_testdb_tx_t bcm_testdb_tx; 35 | 36 | #endif // __DEF_BCM_TESTDB__ 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /test/gencode/butl/bms_testdb-binutil.c: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #include "bms_testdb-binutil.h" 4 | 5 | // DBC file version 6 | #if (VER_TESTDB_MAJ != (1U)) || (VER_TESTDB_MIN != (10U)) 7 | #error The BMS_TESTDB binutil source file has inconsistency with core dbc lib! 8 | #endif 9 | 10 | #ifdef __DEF_BMS_TESTDB__ 11 | 12 | bms_testdb_rx_t bms_testdb_rx; 13 | 14 | bms_testdb_tx_t bms_testdb_tx; 15 | 16 | #endif // __DEF_BMS_TESTDB__ 17 | 18 | uint32_t bms_testdb_Receive(bms_testdb_rx_t* _m, const uint8_t* _d, uint32_t _id, uint8_t dlc_) 19 | { 20 | uint32_t recid = 0; 21 | if ((_id >= 0x14DU) && (_id < 0x22BU)) { 22 | if (_id == 0x14DU) { 23 | recid = Unpack_UTEST_2_testdb(&(_m->UTEST_2), _d, dlc_); 24 | } else if (_id == 0x160U) { 25 | recid = Unpack_EMPTY_0_testdb(&(_m->EMPTY_0), _d, dlc_); 26 | } 27 | } else { 28 | if (_id == 0x22BU) { 29 | recid = Unpack_UTEST_3_testdb(&(_m->UTEST_3), _d, dlc_); 30 | } else if (_id == 0x1FFFFFF6U) { 31 | recid = Unpack_EMPTY_EXT_ID_testdb(&(_m->EMPTY_EXT_ID), _d, dlc_); 32 | } 33 | } 34 | 35 | return recid; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /test/gencode/butl/bms_testdb-binutil.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #pragma once 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include "dbccodeconf.h" 10 | 11 | #include "testdb.h" 12 | 13 | typedef struct 14 | { 15 | UTEST_2_t UTEST_2; 16 | EMPTY_0_t EMPTY_0; 17 | UTEST_3_t UTEST_3; 18 | EMPTY_EXT_ID_t EMPTY_EXT_ID; 19 | } bms_testdb_rx_t; 20 | 21 | typedef struct 22 | { 23 | EMPTY_0_t EMPTY_0; 24 | FLT_TEST_1_t FLT_TEST_1; 25 | } bms_testdb_tx_t; 26 | 27 | uint32_t bms_testdb_Receive(bms_testdb_rx_t* m, const uint8_t* d, uint32_t msgid, uint8_t dlc); 28 | 29 | #ifdef __DEF_BMS_TESTDB__ 30 | 31 | extern bms_testdb_rx_t bms_testdb_rx; 32 | 33 | extern bms_testdb_tx_t bms_testdb_tx; 34 | 35 | #endif // __DEF_BMS_TESTDB__ 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /test/gencode/butl/eps_testdb-binutil.c: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #include "eps_testdb-binutil.h" 4 | 5 | // DBC file version 6 | #if (VER_TESTDB_MAJ != (1U)) || (VER_TESTDB_MIN != (10U)) 7 | #error The EPS_TESTDB binutil source file has inconsistency with core dbc lib! 8 | #endif 9 | 10 | #ifdef __DEF_EPS_TESTDB__ 11 | 12 | eps_testdb_tx_t eps_testdb_tx; 13 | 14 | #endif // __DEF_EPS_TESTDB__ 15 | 16 | -------------------------------------------------------------------------------- /test/gencode/butl/eps_testdb-binutil.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #pragma once 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include "dbccodeconf.h" 10 | 11 | #include "testdb.h" 12 | 13 | // There is no any RX mapped massage. 14 | 15 | typedef struct 16 | { 17 | SIG_TEST_1_t SIG_TEST_1; 18 | } eps_testdb_tx_t; 19 | 20 | #ifdef __DEF_EPS_TESTDB__ 21 | 22 | extern eps_testdb_tx_t eps_testdb_tx; 23 | 24 | #endif // __DEF_EPS_TESTDB__ 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /test/gencode/butl/esp_testdb-binutil.c: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #include "esp_testdb-binutil.h" 4 | 5 | // DBC file version 6 | #if (VER_TESTDB_MAJ != (1U)) || (VER_TESTDB_MIN != (10U)) 7 | #error The ESP_TESTDB binutil source file has inconsistency with core dbc lib! 8 | #endif 9 | 10 | #ifdef __DEF_ESP_TESTDB__ 11 | 12 | esp_testdb_rx_t esp_testdb_rx; 13 | 14 | esp_testdb_tx_t esp_testdb_tx; 15 | 16 | #endif // __DEF_ESP_TESTDB__ 17 | 18 | uint32_t esp_testdb_Receive(esp_testdb_rx_t* _m, const uint8_t* _d, uint32_t _id, uint8_t dlc_) 19 | { 20 | uint32_t recid = 0; 21 | if (_id == 0x14DU) { 22 | recid = Unpack_UTEST_2_testdb(&(_m->UTEST_2), _d, dlc_); 23 | } else if (_id == 0x1FFFFFF6U) { 24 | recid = Unpack_EMPTY_EXT_ID_testdb(&(_m->EMPTY_EXT_ID), _d, dlc_); 25 | } 26 | 27 | return recid; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /test/gencode/butl/esp_testdb-binutil.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #pragma once 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include "dbccodeconf.h" 10 | 11 | #include "testdb.h" 12 | 13 | typedef struct 14 | { 15 | UTEST_2_t UTEST_2; 16 | EMPTY_EXT_ID_t EMPTY_EXT_ID; 17 | } esp_testdb_rx_t; 18 | 19 | typedef struct 20 | { 21 | EMPTY_0_t EMPTY_0; 22 | } esp_testdb_tx_t; 23 | 24 | uint32_t esp_testdb_Receive(esp_testdb_rx_t* m, const uint8_t* d, uint32_t msgid, uint8_t dlc); 25 | 26 | #ifdef __DEF_ESP_TESTDB__ 27 | 28 | extern esp_testdb_rx_t esp_testdb_rx; 29 | 30 | extern esp_testdb_tx_t esp_testdb_tx; 31 | 32 | #endif // __DEF_ESP_TESTDB__ 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /test/gencode/conf/dbccodeconf.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | #pragma once 3 | 4 | #include 5 | 6 | // when USE_SIGFLOAT enabed the sigfloat_t must be defined 7 | // typedef double sigfloat_t; 8 | 9 | // when USE_CANSTRUCT enabled __CoderDbcCanFrame_t__ must be defined 10 | // #include "{header_with_can_struct}" 11 | // typedef {can_struct} __CoderDbcCanFrame_t__; 12 | 13 | // if you need to allocate rx and tx messages structs put the allocation macro here 14 | // #define __DEF_{your_driver_name}__ 15 | 16 | // defualt @__ext_sig__ help types definition 17 | 18 | typedef uint32_t ubitext_t; 19 | typedef int32_t bitext_t; 20 | 21 | // To provide a way to make missing control correctly you 22 | // have to define macro @GetSystemTick() which has to 23 | // return kind of tick counter (e.g. 1 ms ticker) 24 | 25 | // #define GetSystemTick() __get__tick__() 26 | 27 | // To provide a way to calculate hash (crc) for CAN 28 | // frame's data field you have to define macro @GetFrameHash 29 | 30 | // #define GetFrameHash(a,b,c,d,e) __get_hash__(a,b,c,d,e) 31 | 32 | -------------------------------------------------------------------------------- /test/gencode/conf/testdb-config.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #pragma once 4 | 5 | /* include common dbccode configurations */ 6 | #include "dbccodeconf.h" 7 | 8 | 9 | /* ------------------------------------------------------------------------- * 10 | This define enables using CAN message structs with bit-fielded signals 11 | layout. 12 | 13 | Note(!): bit-feild was not tested properly. */ 14 | 15 | /* #define TESTDB_USE_BITS_SIGNAL */ 16 | 17 | 18 | /* ------------------------------------------------------------------------- * 19 | This macro enables using CAN message descriptive struct packing functions 20 | (by default signature of pack function intakes a few simple typed params 21 | for loading data, len, etc). To compile you need to define the struct 22 | __CoderDbcCanFrame_t__ which must have fields: 23 | 24 | u32 MsgId (CAN Frame message ID) 25 | u8 DLC (CAN Frame payload length field) 26 | u8 Data[8] (CAN Frame payload data) 27 | u8 IDE (CAN Frame Extended (1) / Standard (0) ID type) 28 | 29 | This struct definition have to be placed (or be included) in dbccodeconf.h */ 30 | 31 | /* #define TESTDB_USE_CANSTRUCT */ 32 | 33 | 34 | /* ------------------------------------------------------------------------- * 35 | All the signals which have values of factor != 1 or offset != 0 36 | will be named in message struct with posfix '_ro'. Pack to payload 37 | operations will be made on this signal value as well as unpack from payload. 38 | 39 | USE_SIGFLOAT macro makes some difference: 40 | 41 | 1. All the '_ro' fields will have a pair field with '_phys' postfix. 42 | If only offset != 0 is true then the type of '_phys' signal is the same 43 | as '_ro' signal. In other case the type will be @sigfloat_t which 44 | have to be defined in user dbccodeconf.h 45 | 46 | 2. In pack function '_ro' signal will be rewritten by '_phys' signal, which 47 | requires from user to use ONLY '_phys' signal for packing frame 48 | 49 | 3. In unpack function '_phys' signal will be written by '_ro' signal. 50 | User have to use '_phys' signal to read physical value. */ 51 | 52 | /* #define TESTDB_USE_SIGFLOAT */ 53 | 54 | 55 | /* ------------------------------------------------------------------------- * 56 | Note(!) that the "canmonitorutil.h" must be accessed in include path: 57 | 58 | This macro adds: 59 | 60 | - monitor field @mon1 to message struct 61 | 62 | - capture system tick in unpack function and save value to mon1 field 63 | to provide to user better missing frame detection code. For this case 64 | user must provide function declared in canmonitorutil.h - GetSysTick() 65 | which may return 1ms uptime. 66 | 67 | - calling function FMon_*** (from 'fmon' driver) inside unpack function 68 | which is empty by default and have to be filled by user if 69 | tests for DLC, rolling, checksum are necessary */ 70 | 71 | /* #define TESTDB_USE_DIAG_MONITORS */ 72 | 73 | 74 | /* ------------------------------------------------------------------------- * 75 | When monitor using is enabled (TESTDB_USE_DIAG_MONITORS) and define below 76 | uncommented, additional signal will be added to message struct. ***_expt: 77 | expected rolling counter, to perform monitoring rolling counter sequence 78 | automatically (result may be tested in dedicated Fmon_*** function) */ 79 | 80 | /* #define TESTDB_AUTO_ROLL */ 81 | 82 | 83 | /* ------------------------------------------------------------------------- * 84 | When monitor using is enabled (TESTDB_USE_DIAG_MONITORS) and define below 85 | uncommented, frame checksum signal may be handled automatically. 86 | 87 | The signal which may be marked as checksum signal must have substring 88 | with next format: 89 | 90 | 91 | where: 92 | 93 | - "Checksum": constant marker word 94 | 95 | - "XOR8": type of method, this text will be passed to GetFrameHash 96 | (canmonitorutil.h) function as is, the best use case is to define 'enum 97 | DbcCanCrcMethods' in canmonitorutil.h file with all possible 98 | checksum algorithms (e.g. XOR8, XOR4 etc) 99 | 100 | - "3": optional value that will be passed to GetFrameHash as integer value 101 | 102 | Function GetFrameHash have to be implemented by user 103 | 104 | In pack function checksum signal will be calculated automatically 105 | and loaded to payload 106 | 107 | In unpack function checksum signal is checked with calculated. 108 | (result may be tested in dedicated Fmon_*** function). */ 109 | 110 | /* #define TESTDB_AUTO_CSM */ 111 | 112 | 113 | /* ------------------------------------------------------------------------- * 114 | FMon handling model can be build in two ways: 115 | 116 | 1 - Default. In this case when specific frame unpack is called the 117 | specific FMon_{Frame name}_{driver name} functoin will be called. 118 | User's code scope has to define each of these functions. Each function is 119 | responsible for the error handling of one frame 120 | 121 | 2 - MONO. In this case there is only one function to perform any frame 122 | monitoring. This function has to be implemented in the user's code scope. 123 | This function is named as FMon_MONO_{driver name}. It takes frame id 124 | which can be used for selection of the logic for a frame monitoring. 125 | This mode costs a bit more in runtime but when you often edit you DBC and you 126 | have more than one project it could be more maintanable (there is 127 | no necessity to replace source code) 128 | 129 | For using MONO way uncomment line below */ 130 | /* #define TESTDB_USE_MONO_FMON */ 131 | -------------------------------------------------------------------------------- /test/gencode/inc/canmonitorutil.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | #pragma once 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | // declare here all availible checksum algorithms 11 | typedef enum 12 | { 13 | // XOR8 = 0, 14 | // XOR4 = 1, 15 | // etc 16 | 17 | // it is up to user to have or to skip final enum value - @CRC_ALG_COUNT 18 | CRC_ALG_COUNT 19 | } DbcCanCrcMethods; 20 | 21 | typedef struct 22 | { 23 | // @last_cycle keeps tick-value when last frame was received 24 | uint32_t last_cycle; 25 | 26 | // @timeout_cycle keeps maximum timeout for frame, user responsibility 27 | // to init this field and use it in missing frame monitoring function 28 | uint32_t timeout_cycle; 29 | 30 | // @frame_cnt keeps count of all the received frames 31 | uint32_t frame_cnt; 32 | 33 | // setting up @roll_error bit indicates roll counting fail. 34 | // Bit is not clearing automatically! 35 | uint32_t roll_error : 1; 36 | 37 | // setting up @checksum_error bit indicates checksum checking failure. 38 | // Bit is not clearing automatically! 39 | uint32_t csm_error : 1; 40 | 41 | // setting up @cycle_error bit indicates that time was overrunned. 42 | // Bit is not clearing automatically! 43 | uint32_t cycle_error : 1; 44 | 45 | // setting up @dlc_error bit indicates that the actual length of 46 | // CAN frame is less then defined by CAN matrix! 47 | uint32_t dlc_error : 1; 48 | 49 | } FrameMonitor_t; 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /test/gencode/lib/testdb-fmon.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #pragma once 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | // DBC file version 10 | #define VER_TESTDB_MAJ_FMON (1U) 11 | #define VER_TESTDB_MIN_FMON (10U) 12 | 13 | #include "testdb-config.h" 14 | 15 | #ifdef TESTDB_USE_DIAG_MONITORS 16 | 17 | #include "canmonitorutil.h" 18 | /* 19 | This file contains the prototypes of all the functions that will be called 20 | from each Unpack_*name* function to detect DBC related errors 21 | It is the user responsibility to defined these functions in the 22 | separated .c file. If it won't be done the linkage error will happen 23 | */ 24 | 25 | #ifdef TESTDB_USE_MONO_FMON 26 | 27 | void _FMon_MONO_testdb(FrameMonitor_t* _mon, uint32_t msgid); 28 | 29 | #define FMon_NO_SIGS_MSG_testdb(x, y) _FMon_MONO_testdb((x), (y)) 30 | #define FMon_UTEST_2_testdb(x, y) _FMon_MONO_testdb((x), (y)) 31 | #define FMon_EMPTY_0_testdb(x, y) _FMon_MONO_testdb((x), (y)) 32 | #define FMon_UTEST_3_testdb(x, y) _FMon_MONO_testdb((x), (y)) 33 | #define FMon_FLT_TEST_1_testdb(x, y) _FMon_MONO_testdb((x), (y)) 34 | #define FMon_SIG_TEST_1_testdb(x, y) _FMon_MONO_testdb((x), (y)) 35 | #define FMon_EMPTY_EXT_ID_testdb(x, y) _FMon_MONO_testdb((x), (y)) 36 | 37 | #else 38 | 39 | void _FMon_NO_SIGS_MSG_testdb(FrameMonitor_t* _mon, uint32_t msgid); 40 | void _FMon_UTEST_2_testdb(FrameMonitor_t* _mon, uint32_t msgid); 41 | void _FMon_EMPTY_0_testdb(FrameMonitor_t* _mon, uint32_t msgid); 42 | void _FMon_UTEST_3_testdb(FrameMonitor_t* _mon, uint32_t msgid); 43 | void _FMon_FLT_TEST_1_testdb(FrameMonitor_t* _mon, uint32_t msgid); 44 | void _FMon_SIG_TEST_1_testdb(FrameMonitor_t* _mon, uint32_t msgid); 45 | void _FMon_EMPTY_EXT_ID_testdb(FrameMonitor_t* _mon, uint32_t msgid); 46 | 47 | #define FMon_NO_SIGS_MSG_testdb(x, y) _FMon_NO_SIGS_MSG_testdb((x), (y)) 48 | #define FMon_UTEST_2_testdb(x, y) _FMon_UTEST_2_testdb((x), (y)) 49 | #define FMon_EMPTY_0_testdb(x, y) _FMon_EMPTY_0_testdb((x), (y)) 50 | #define FMon_UTEST_3_testdb(x, y) _FMon_UTEST_3_testdb((x), (y)) 51 | #define FMon_FLT_TEST_1_testdb(x, y) _FMon_FLT_TEST_1_testdb((x), (y)) 52 | #define FMon_SIG_TEST_1_testdb(x, y) _FMon_SIG_TEST_1_testdb((x), (y)) 53 | #define FMon_EMPTY_EXT_ID_testdb(x, y) _FMon_EMPTY_EXT_ID_testdb((x), (y)) 54 | 55 | #endif 56 | 57 | #endif // TESTDB_USE_DIAG_MONITORS 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | -------------------------------------------------------------------------------- /test/gencode/lib/testdb.c: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #include "testdb.h" 4 | 5 | 6 | // DBC file version 7 | #if (VER_TESTDB_MAJ != (1U)) || (VER_TESTDB_MIN != (10U)) 8 | #error The TESTDB dbc source files have different versions 9 | #endif 10 | 11 | #ifdef TESTDB_USE_DIAG_MONITORS 12 | // Function prototypes to be called each time CAN frame is unpacked 13 | // FMon function may detect RC, CRC or DLC violation 14 | #include "testdb-fmon.h" 15 | 16 | #endif // TESTDB_USE_DIAG_MONITORS 17 | 18 | // This macro guard for the case when you need to enable 19 | // using diag monitors but there is no necessity in proper 20 | // SysTick provider. For providing one you need define macro 21 | // before this line - in dbccodeconf.h 22 | 23 | #ifndef GetSystemTick 24 | #define GetSystemTick() (0u) 25 | #endif 26 | 27 | // This macro guard is for the case when you want to build 28 | // app with enabled optoin auto CSM, but don't yet have 29 | // proper getframehash implementation 30 | 31 | #ifndef GetFrameHash 32 | #define GetFrameHash(a,b,c,d,e) (0u) 33 | #endif 34 | 35 | // This function performs extension of sign for the signals 36 | // whose bit width value is not aligned to one of power of 2 or less than 8. 37 | // The types 'bitext_t' and 'ubitext_t' define the biggest bit width which 38 | // can be correctly handled. You need to select type which can contain 39 | // n+1 bits where n is the largest signed signal width. For example if 40 | // the most wide signed signal has a width of 31 bits you need to set 41 | // bitext_t as int32_t and ubitext_t as uint32_t 42 | // Defined these typedefs in @dbccodeconf.h or locally in 'dbcdrvname'-config.h 43 | static bitext_t __ext_sig__(ubitext_t val, uint8_t bits) 44 | { 45 | ubitext_t const m = (ubitext_t) (1u << (bits - 1u)); 46 | return ((val ^ m) - m); 47 | } 48 | 49 | uint32_t Unpack_UTEST_2_testdb(UTEST_2_t* _m, const uint8_t* _d, uint8_t dlc_) 50 | { 51 | (void)dlc_; 52 | _m->U28_TEST_1 = (uint32_t) ( ((_d[3] & (0x0FU)) << 24U) | ((_d[2] & (0xFFU)) << 16U) | ((_d[1] & (0xFFU)) << 8U) | (_d[0] & (0xFFU)) ); 53 | _m->ValTest = (uint8_t) ( ((_d[3] >> 5U) & (0x03U)) ); 54 | _m->U8_TEST_1 = (uint8_t) ( (_d[4] & (0xFFU)) ); 55 | _m->U7_TEST_1_ro = (uint8_t) ( ((_d[5] >> 1U) & (0x7FU)) ); 56 | #ifdef TESTDB_USE_SIGFLOAT 57 | _m->U7_TEST_1_phys = (int16_t) TESTDB_U7_TEST_1_ro_fromS(_m->U7_TEST_1_ro); 58 | #endif // TESTDB_USE_SIGFLOAT 59 | 60 | #ifdef TESTDB_USE_DIAG_MONITORS 61 | _m->mon1.dlc_error = (dlc_ < UTEST_2_DLC); 62 | _m->mon1.last_cycle = GetSystemTick(); 63 | _m->mon1.frame_cnt++; 64 | 65 | FMon_UTEST_2_testdb(&_m->mon1, UTEST_2_CANID); 66 | #endif // TESTDB_USE_DIAG_MONITORS 67 | 68 | return UTEST_2_CANID; 69 | } 70 | 71 | #ifdef TESTDB_USE_CANSTRUCT 72 | 73 | uint32_t Pack_UTEST_2_testdb(UTEST_2_t* _m, __CoderDbcCanFrame_t__* cframe) 74 | { 75 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(UTEST_2_DLC); cframe->Data[i++] = TESTDB_INITIAL_BYTE_VALUE); 76 | 77 | #ifdef TESTDB_USE_SIGFLOAT 78 | _m->U7_TEST_1_ro = (uint8_t) TESTDB_U7_TEST_1_ro_toS(_m->U7_TEST_1_phys); 79 | #endif // TESTDB_USE_SIGFLOAT 80 | 81 | cframe->Data[0] |= (uint8_t) ( (_m->U28_TEST_1 & (0xFFU)) ); 82 | cframe->Data[1] |= (uint8_t) ( ((_m->U28_TEST_1 >> 8U) & (0xFFU)) ); 83 | cframe->Data[2] |= (uint8_t) ( ((_m->U28_TEST_1 >> 16U) & (0xFFU)) ); 84 | cframe->Data[3] |= (uint8_t) ( ((_m->U28_TEST_1 >> 24U) & (0x0FU)) | ((_m->ValTest & (0x03U)) << 5U) ); 85 | cframe->Data[4] |= (uint8_t) ( (_m->U8_TEST_1 & (0xFFU)) ); 86 | cframe->Data[5] |= (uint8_t) ( ((_m->U7_TEST_1_ro & (0x7FU)) << 1U) ); 87 | 88 | cframe->MsgId = (uint32_t) UTEST_2_CANID; 89 | cframe->DLC = (uint8_t) UTEST_2_DLC; 90 | cframe->IDE = (uint8_t) UTEST_2_IDE; 91 | return UTEST_2_CANID; 92 | } 93 | 94 | #else 95 | 96 | uint32_t Pack_UTEST_2_testdb(UTEST_2_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide) 97 | { 98 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(UTEST_2_DLC); _d[i++] = TESTDB_INITIAL_BYTE_VALUE); 99 | 100 | #ifdef TESTDB_USE_SIGFLOAT 101 | _m->U7_TEST_1_ro = (uint8_t) TESTDB_U7_TEST_1_ro_toS(_m->U7_TEST_1_phys); 102 | #endif // TESTDB_USE_SIGFLOAT 103 | 104 | _d[0] |= (uint8_t) ( (_m->U28_TEST_1 & (0xFFU)) ); 105 | _d[1] |= (uint8_t) ( ((_m->U28_TEST_1 >> 8U) & (0xFFU)) ); 106 | _d[2] |= (uint8_t) ( ((_m->U28_TEST_1 >> 16U) & (0xFFU)) ); 107 | _d[3] |= (uint8_t) ( ((_m->U28_TEST_1 >> 24U) & (0x0FU)) | ((_m->ValTest & (0x03U)) << 5U) ); 108 | _d[4] |= (uint8_t) ( (_m->U8_TEST_1 & (0xFFU)) ); 109 | _d[5] |= (uint8_t) ( ((_m->U7_TEST_1_ro & (0x7FU)) << 1U) ); 110 | 111 | *_len = (uint8_t) UTEST_2_DLC; 112 | *_ide = (uint8_t) UTEST_2_IDE; 113 | return UTEST_2_CANID; 114 | } 115 | 116 | #endif // TESTDB_USE_CANSTRUCT 117 | 118 | uint32_t Unpack_EMPTY_0_testdb(EMPTY_0_t* _m, const uint8_t* _d, uint8_t dlc_) 119 | { 120 | (void)dlc_; 121 | _m->CS = (uint8_t) ( ((_d[4] >> 1U) & (0x3FU)) ); 122 | _m->RC = (uint8_t) ( ((_d[6] & (0x07U)) << 1U) | ((_d[5] >> 7U) & (0x01U)) ); 123 | 124 | #ifdef TESTDB_USE_DIAG_MONITORS 125 | _m->mon1.dlc_error = (dlc_ < EMPTY_0_DLC); 126 | _m->mon1.last_cycle = GetSystemTick(); 127 | _m->mon1.frame_cnt++; 128 | 129 | #ifdef TESTDB_AUTO_ROLL 130 | _m->mon1.roll_error = (_m->RC != _m->RC_expt); 131 | _m->RC_expt = (_m->RC + 1) & (0x0FU); 132 | #endif // TESTDB_AUTO_ROLL 133 | 134 | #ifdef TESTDB_AUTO_CSM 135 | _m->mon1.csm_error = (((uint8_t)GetFrameHash(_d, EMPTY_0_DLC, EMPTY_0_CANID, kXor8, 1)) != (_m->CS)); 136 | #endif // TESTDB_AUTO_CSM 137 | 138 | FMon_EMPTY_0_testdb(&_m->mon1, EMPTY_0_CANID); 139 | #endif // TESTDB_USE_DIAG_MONITORS 140 | 141 | return EMPTY_0_CANID; 142 | } 143 | 144 | #ifdef TESTDB_USE_CANSTRUCT 145 | 146 | uint32_t Pack_EMPTY_0_testdb(EMPTY_0_t* _m, __CoderDbcCanFrame_t__* cframe) 147 | { 148 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(EMPTY_0_DLC); cframe->Data[i++] = TESTDB_INITIAL_BYTE_VALUE); 149 | 150 | #ifdef TESTDB_AUTO_ROLL 151 | _m->RC = (_m->RC + 1) & (0x0FU); 152 | #endif // TESTDB_AUTO_ROLL 153 | 154 | #ifdef TESTDB_AUTO_CSM 155 | _m->CS = (uint8_t) 0; 156 | #endif // TESTDB_AUTO_CSM 157 | 158 | cframe->Data[4] |= (uint8_t) ( ((_m->CS & (0x3FU)) << 1U) ); 159 | cframe->Data[5] |= (uint8_t) ( ((_m->RC & (0x01U)) << 7U) ); 160 | cframe->Data[6] |= (uint8_t) ( ((_m->RC >> 1U) & (0x07U)) ); 161 | 162 | #ifdef TESTDB_AUTO_CSM 163 | _m->CS = ((uint8_t)GetFrameHash(cframe->Data, EMPTY_0_DLC, EMPTY_0_CANID, kXor8, 1)); 164 | cframe->Data[4] |= (uint8_t) ( ((_m->CS & (0x3FU)) << 1U) ); 165 | #endif // TESTDB_AUTO_CSM 166 | 167 | cframe->MsgId = (uint32_t) EMPTY_0_CANID; 168 | cframe->DLC = (uint8_t) EMPTY_0_DLC; 169 | cframe->IDE = (uint8_t) EMPTY_0_IDE; 170 | return EMPTY_0_CANID; 171 | } 172 | 173 | #else 174 | 175 | uint32_t Pack_EMPTY_0_testdb(EMPTY_0_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide) 176 | { 177 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(EMPTY_0_DLC); _d[i++] = TESTDB_INITIAL_BYTE_VALUE); 178 | 179 | #ifdef TESTDB_AUTO_ROLL 180 | _m->RC = (_m->RC + 1) & (0x0FU); 181 | #endif // TESTDB_AUTO_ROLL 182 | 183 | #ifdef TESTDB_AUTO_CSM 184 | _m->CS = (uint8_t) 0; 185 | #endif // TESTDB_AUTO_CSM 186 | 187 | _d[4] |= (uint8_t) ( ((_m->CS & (0x3FU)) << 1U) ); 188 | _d[5] |= (uint8_t) ( ((_m->RC & (0x01U)) << 7U) ); 189 | _d[6] |= (uint8_t) ( ((_m->RC >> 1U) & (0x07U)) ); 190 | 191 | #ifdef TESTDB_AUTO_CSM 192 | _m->CS = ((uint8_t)GetFrameHash(_d, EMPTY_0_DLC, EMPTY_0_CANID, kXor8, 1)); 193 | _d[4] |= (uint8_t) ( ((_m->CS & (0x3FU)) << 1U) ); 194 | #endif // TESTDB_AUTO_CSM 195 | 196 | *_len = (uint8_t) EMPTY_0_DLC; 197 | *_ide = (uint8_t) EMPTY_0_IDE; 198 | return EMPTY_0_CANID; 199 | } 200 | 201 | #endif // TESTDB_USE_CANSTRUCT 202 | 203 | uint32_t Unpack_UTEST_3_testdb(UTEST_3_t* _m, const uint8_t* _d, uint8_t dlc_) 204 | { 205 | (void)dlc_; 206 | _m->U32_TEST_1 = (uint32_t) ( ((_d[3] & (0xFFU)) << 24U) | ((_d[2] & (0xFFU)) << 16U) | ((_d[1] & (0xFFU)) << 8U) | (_d[0] & (0xFFU)) ); 207 | _m->TestValTableID = (uint8_t) ( (_d[4] & (0x07U)) ); 208 | 209 | #ifdef TESTDB_USE_DIAG_MONITORS 210 | _m->mon1.dlc_error = (dlc_ < UTEST_3_DLC); 211 | _m->mon1.last_cycle = GetSystemTick(); 212 | _m->mon1.frame_cnt++; 213 | 214 | FMon_UTEST_3_testdb(&_m->mon1, UTEST_3_CANID); 215 | #endif // TESTDB_USE_DIAG_MONITORS 216 | 217 | return UTEST_3_CANID; 218 | } 219 | 220 | #ifdef TESTDB_USE_CANSTRUCT 221 | 222 | uint32_t Pack_UTEST_3_testdb(UTEST_3_t* _m, __CoderDbcCanFrame_t__* cframe) 223 | { 224 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(UTEST_3_DLC); cframe->Data[i++] = TESTDB_INITIAL_BYTE_VALUE); 225 | 226 | cframe->Data[0] |= (uint8_t) ( (_m->U32_TEST_1 & (0xFFU)) ); 227 | cframe->Data[1] |= (uint8_t) ( ((_m->U32_TEST_1 >> 8U) & (0xFFU)) ); 228 | cframe->Data[2] |= (uint8_t) ( ((_m->U32_TEST_1 >> 16U) & (0xFFU)) ); 229 | cframe->Data[3] |= (uint8_t) ( ((_m->U32_TEST_1 >> 24U) & (0xFFU)) ); 230 | cframe->Data[4] |= (uint8_t) ( (_m->TestValTableID & (0x07U)) ); 231 | 232 | cframe->MsgId = (uint32_t) UTEST_3_CANID; 233 | cframe->DLC = (uint8_t) UTEST_3_DLC; 234 | cframe->IDE = (uint8_t) UTEST_3_IDE; 235 | return UTEST_3_CANID; 236 | } 237 | 238 | #else 239 | 240 | uint32_t Pack_UTEST_3_testdb(UTEST_3_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide) 241 | { 242 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(UTEST_3_DLC); _d[i++] = TESTDB_INITIAL_BYTE_VALUE); 243 | 244 | _d[0] |= (uint8_t) ( (_m->U32_TEST_1 & (0xFFU)) ); 245 | _d[1] |= (uint8_t) ( ((_m->U32_TEST_1 >> 8U) & (0xFFU)) ); 246 | _d[2] |= (uint8_t) ( ((_m->U32_TEST_1 >> 16U) & (0xFFU)) ); 247 | _d[3] |= (uint8_t) ( ((_m->U32_TEST_1 >> 24U) & (0xFFU)) ); 248 | _d[4] |= (uint8_t) ( (_m->TestValTableID & (0x07U)) ); 249 | 250 | *_len = (uint8_t) UTEST_3_DLC; 251 | *_ide = (uint8_t) UTEST_3_IDE; 252 | return UTEST_3_CANID; 253 | } 254 | 255 | #endif // TESTDB_USE_CANSTRUCT 256 | 257 | uint32_t Unpack_FLT_TEST_1_testdb(FLT_TEST_1_t* _m, const uint8_t* _d, uint8_t dlc_) 258 | { 259 | (void)dlc_; 260 | _m->ValTable = (uint8_t) ( (_d[0] & (0x03U)) ); 261 | _m->Position = (uint8_t) ( ((_d[0] >> 4U) & (0x0FU)) ); 262 | _m->INT_TEST_2_ro = (int8_t) __ext_sig__(( ((_d[1] >> 1U) & (0x7FU)) ), 7); 263 | #ifdef TESTDB_USE_SIGFLOAT 264 | _m->INT_TEST_2_phys = (int16_t) TESTDB_INT_TEST_2_ro_fromS(_m->INT_TEST_2_ro); 265 | #endif // TESTDB_USE_SIGFLOAT 266 | 267 | _m->RC = (uint8_t) ( (_d[2] & (0x0FU)) ); 268 | _m->CS = (uint8_t) ( ((_d[2] >> 4U) & (0x0FU)) ); 269 | _m->Accel_ro = (uint16_t) ( ((_d[4] & (0x0FU)) << 8U) | (_d[3] & (0xFFU)) ); 270 | #ifdef TESTDB_USE_SIGFLOAT 271 | _m->Accel_phys = (sigfloat_t)(TESTDB_Accel_ro_fromS(_m->Accel_ro)); 272 | #endif // TESTDB_USE_SIGFLOAT 273 | 274 | _m->FLT4_TEST_1_ro = (uint8_t) ( ((_d[4] >> 4U) & (0x0FU)) ); 275 | #ifdef TESTDB_USE_SIGFLOAT 276 | _m->FLT4_TEST_1_phys = (sigfloat_t)(TESTDB_FLT4_TEST_1_ro_fromS(_m->FLT4_TEST_1_ro)); 277 | #endif // TESTDB_USE_SIGFLOAT 278 | 279 | _m->FLT4_TEST_2_ro = (uint8_t) ( (_d[5] & (0x0FU)) ); 280 | #ifdef TESTDB_USE_SIGFLOAT 281 | _m->FLT4_TEST_2_phys = (sigfloat_t)(TESTDB_FLT4_TEST_2_ro_fromS(_m->FLT4_TEST_2_ro)); 282 | #endif // TESTDB_USE_SIGFLOAT 283 | 284 | _m->FLT4_TEST_3_ro = (uint8_t) ( ((_d[5] >> 4U) & (0x0FU)) ); 285 | #ifdef TESTDB_USE_SIGFLOAT 286 | _m->FLT4_TEST_3_phys = (sigfloat_t)(TESTDB_FLT4_TEST_3_ro_fromS(_m->FLT4_TEST_3_ro)); 287 | #endif // TESTDB_USE_SIGFLOAT 288 | 289 | _m->INT_TEST_1_ro = (uint8_t) ( ((_d[6] >> 2U) & (0x0FU)) ); 290 | #ifdef TESTDB_USE_SIGFLOAT 291 | _m->INT_TEST_1_phys = (int8_t) TESTDB_INT_TEST_1_ro_fromS(_m->INT_TEST_1_ro); 292 | #endif // TESTDB_USE_SIGFLOAT 293 | 294 | #ifdef TESTDB_USE_DIAG_MONITORS 295 | _m->mon1.dlc_error = (dlc_ < FLT_TEST_1_DLC); 296 | _m->mon1.last_cycle = GetSystemTick(); 297 | _m->mon1.frame_cnt++; 298 | 299 | #ifdef TESTDB_AUTO_ROLL 300 | _m->mon1.roll_error = (_m->RC != _m->RC_expt); 301 | _m->RC_expt = (_m->RC + 1) & (0x0FU); 302 | #endif // TESTDB_AUTO_ROLL 303 | 304 | #ifdef TESTDB_AUTO_CSM 305 | _m->mon1.csm_error = (((uint8_t)GetFrameHash(_d, FLT_TEST_1_DLC, FLT_TEST_1_CANID, kXor4, 1)) != (_m->CS)); 306 | #endif // TESTDB_AUTO_CSM 307 | 308 | FMon_FLT_TEST_1_testdb(&_m->mon1, FLT_TEST_1_CANID); 309 | #endif // TESTDB_USE_DIAG_MONITORS 310 | 311 | return FLT_TEST_1_CANID; 312 | } 313 | 314 | #ifdef TESTDB_USE_CANSTRUCT 315 | 316 | uint32_t Pack_FLT_TEST_1_testdb(FLT_TEST_1_t* _m, __CoderDbcCanFrame_t__* cframe) 317 | { 318 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(FLT_TEST_1_DLC); cframe->Data[i++] = TESTDB_INITIAL_BYTE_VALUE); 319 | 320 | #ifdef TESTDB_AUTO_ROLL 321 | _m->RC = (_m->RC + 1) & (0x0FU); 322 | #endif // TESTDB_AUTO_ROLL 323 | 324 | #ifdef TESTDB_AUTO_CSM 325 | _m->CS = (uint8_t) 0; 326 | #endif // TESTDB_AUTO_CSM 327 | 328 | #ifdef TESTDB_USE_SIGFLOAT 329 | _m->INT_TEST_2_ro = (int8_t) TESTDB_INT_TEST_2_ro_toS(_m->INT_TEST_2_phys); 330 | _m->Accel_ro = (uint16_t) TESTDB_Accel_ro_toS(_m->Accel_phys); 331 | _m->FLT4_TEST_1_ro = (uint8_t) TESTDB_FLT4_TEST_1_ro_toS(_m->FLT4_TEST_1_phys); 332 | _m->FLT4_TEST_2_ro = (uint8_t) TESTDB_FLT4_TEST_2_ro_toS(_m->FLT4_TEST_2_phys); 333 | _m->FLT4_TEST_3_ro = (uint8_t) TESTDB_FLT4_TEST_3_ro_toS(_m->FLT4_TEST_3_phys); 334 | _m->INT_TEST_1_ro = (uint8_t) TESTDB_INT_TEST_1_ro_toS(_m->INT_TEST_1_phys); 335 | #endif // TESTDB_USE_SIGFLOAT 336 | 337 | cframe->Data[0] |= (uint8_t) ( (_m->ValTable & (0x03U)) | ((_m->Position & (0x0FU)) << 4U) ); 338 | cframe->Data[1] |= (uint8_t) ( ((_m->INT_TEST_2_ro & (0x7FU)) << 1U) ); 339 | cframe->Data[2] |= (uint8_t) ( (_m->RC & (0x0FU)) | ((_m->CS & (0x0FU)) << 4U) ); 340 | cframe->Data[3] |= (uint8_t) ( (_m->Accel_ro & (0xFFU)) ); 341 | cframe->Data[4] |= (uint8_t) ( ((_m->Accel_ro >> 8U) & (0x0FU)) | ((_m->FLT4_TEST_1_ro & (0x0FU)) << 4U) ); 342 | cframe->Data[5] |= (uint8_t) ( (_m->FLT4_TEST_2_ro & (0x0FU)) | ((_m->FLT4_TEST_3_ro & (0x0FU)) << 4U) ); 343 | cframe->Data[6] |= (uint8_t) ( ((_m->INT_TEST_1_ro & (0x0FU)) << 2U) ); 344 | 345 | #ifdef TESTDB_AUTO_CSM 346 | _m->CS = ((uint8_t)GetFrameHash(cframe->Data, FLT_TEST_1_DLC, FLT_TEST_1_CANID, kXor4, 1)); 347 | cframe->Data[2] |= (uint8_t) ( ((_m->CS & (0x0FU)) << 4U) ); 348 | #endif // TESTDB_AUTO_CSM 349 | 350 | cframe->MsgId = (uint32_t) FLT_TEST_1_CANID; 351 | cframe->DLC = (uint8_t) FLT_TEST_1_DLC; 352 | cframe->IDE = (uint8_t) FLT_TEST_1_IDE; 353 | return FLT_TEST_1_CANID; 354 | } 355 | 356 | #else 357 | 358 | uint32_t Pack_FLT_TEST_1_testdb(FLT_TEST_1_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide) 359 | { 360 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(FLT_TEST_1_DLC); _d[i++] = TESTDB_INITIAL_BYTE_VALUE); 361 | 362 | #ifdef TESTDB_AUTO_ROLL 363 | _m->RC = (_m->RC + 1) & (0x0FU); 364 | #endif // TESTDB_AUTO_ROLL 365 | 366 | #ifdef TESTDB_AUTO_CSM 367 | _m->CS = (uint8_t) 0; 368 | #endif // TESTDB_AUTO_CSM 369 | 370 | #ifdef TESTDB_USE_SIGFLOAT 371 | _m->INT_TEST_2_ro = (int8_t) TESTDB_INT_TEST_2_ro_toS(_m->INT_TEST_2_phys); 372 | _m->Accel_ro = (uint16_t) TESTDB_Accel_ro_toS(_m->Accel_phys); 373 | _m->FLT4_TEST_1_ro = (uint8_t) TESTDB_FLT4_TEST_1_ro_toS(_m->FLT4_TEST_1_phys); 374 | _m->FLT4_TEST_2_ro = (uint8_t) TESTDB_FLT4_TEST_2_ro_toS(_m->FLT4_TEST_2_phys); 375 | _m->FLT4_TEST_3_ro = (uint8_t) TESTDB_FLT4_TEST_3_ro_toS(_m->FLT4_TEST_3_phys); 376 | _m->INT_TEST_1_ro = (uint8_t) TESTDB_INT_TEST_1_ro_toS(_m->INT_TEST_1_phys); 377 | #endif // TESTDB_USE_SIGFLOAT 378 | 379 | _d[0] |= (uint8_t) ( (_m->ValTable & (0x03U)) | ((_m->Position & (0x0FU)) << 4U) ); 380 | _d[1] |= (uint8_t) ( ((_m->INT_TEST_2_ro & (0x7FU)) << 1U) ); 381 | _d[2] |= (uint8_t) ( (_m->RC & (0x0FU)) | ((_m->CS & (0x0FU)) << 4U) ); 382 | _d[3] |= (uint8_t) ( (_m->Accel_ro & (0xFFU)) ); 383 | _d[4] |= (uint8_t) ( ((_m->Accel_ro >> 8U) & (0x0FU)) | ((_m->FLT4_TEST_1_ro & (0x0FU)) << 4U) ); 384 | _d[5] |= (uint8_t) ( (_m->FLT4_TEST_2_ro & (0x0FU)) | ((_m->FLT4_TEST_3_ro & (0x0FU)) << 4U) ); 385 | _d[6] |= (uint8_t) ( ((_m->INT_TEST_1_ro & (0x0FU)) << 2U) ); 386 | 387 | #ifdef TESTDB_AUTO_CSM 388 | _m->CS = ((uint8_t)GetFrameHash(_d, FLT_TEST_1_DLC, FLT_TEST_1_CANID, kXor4, 1)); 389 | _d[2] |= (uint8_t) ( ((_m->CS & (0x0FU)) << 4U) ); 390 | #endif // TESTDB_AUTO_CSM 391 | 392 | *_len = (uint8_t) FLT_TEST_1_DLC; 393 | *_ide = (uint8_t) FLT_TEST_1_IDE; 394 | return FLT_TEST_1_CANID; 395 | } 396 | 397 | #endif // TESTDB_USE_CANSTRUCT 398 | 399 | uint32_t Unpack_SIG_TEST_1_testdb(SIG_TEST_1_t* _m, const uint8_t* _d, uint8_t dlc_) 400 | { 401 | (void)dlc_; 402 | _m->sig15_ro = (int16_t) __ext_sig__(( ((_d[1] & (0x7FU)) << 8U) | (_d[0] & (0xFFU)) ), 15); 403 | #ifdef TESTDB_USE_SIGFLOAT 404 | _m->sig15_phys = (int32_t) TESTDB_sig15_ro_fromS(_m->sig15_ro); 405 | #endif // TESTDB_USE_SIGFLOAT 406 | 407 | _m->sig15_2_ro = (int16_t) __ext_sig__(( ((_d[3] & (0x7FU)) << 8U) | (_d[2] & (0xFFU)) ), 15); 408 | #ifdef TESTDB_USE_SIGFLOAT 409 | _m->sig15_2_phys = (sigfloat_t)(TESTDB_sig15_2_ro_fromS(_m->sig15_2_ro)); 410 | #endif // TESTDB_USE_SIGFLOAT 411 | 412 | _m->sig8_ro = (int8_t) __ext_sig__(( (_d[4] & (0xFFU)) ), 8); 413 | #ifdef TESTDB_USE_SIGFLOAT 414 | _m->sig8_phys = (int16_t) TESTDB_sig8_ro_fromS(_m->sig8_ro); 415 | #endif // TESTDB_USE_SIGFLOAT 416 | 417 | _m->sig_7_ro = (int8_t) __ext_sig__(( (_d[5] & (0x7FU)) ), 7); 418 | #ifdef TESTDB_USE_SIGFLOAT 419 | _m->sig_7_phys = (sigfloat_t)(TESTDB_sig_7_ro_fromS(_m->sig_7_ro)); 420 | #endif // TESTDB_USE_SIGFLOAT 421 | 422 | _m->U7_TEST_1_ro = (uint8_t) ( ((_d[6] >> 1U) & (0x7FU)) ); 423 | #ifdef TESTDB_USE_SIGFLOAT 424 | _m->U7_TEST_1_phys = (int16_t) TESTDB_U7_TEST_1_ro_fromS(_m->U7_TEST_1_ro); 425 | #endif // TESTDB_USE_SIGFLOAT 426 | 427 | #ifdef TESTDB_USE_DIAG_MONITORS 428 | _m->mon1.dlc_error = (dlc_ < SIG_TEST_1_DLC); 429 | _m->mon1.last_cycle = GetSystemTick(); 430 | _m->mon1.frame_cnt++; 431 | 432 | FMon_SIG_TEST_1_testdb(&_m->mon1, SIG_TEST_1_CANID); 433 | #endif // TESTDB_USE_DIAG_MONITORS 434 | 435 | return SIG_TEST_1_CANID; 436 | } 437 | 438 | #ifdef TESTDB_USE_CANSTRUCT 439 | 440 | uint32_t Pack_SIG_TEST_1_testdb(SIG_TEST_1_t* _m, __CoderDbcCanFrame_t__* cframe) 441 | { 442 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(SIG_TEST_1_DLC); cframe->Data[i++] = TESTDB_INITIAL_BYTE_VALUE); 443 | 444 | #ifdef TESTDB_USE_SIGFLOAT 445 | _m->sig15_ro = (int16_t) TESTDB_sig15_ro_toS(_m->sig15_phys); 446 | _m->sig15_2_ro = (int16_t) TESTDB_sig15_2_ro_toS(_m->sig15_2_phys); 447 | _m->sig8_ro = (int8_t) TESTDB_sig8_ro_toS(_m->sig8_phys); 448 | _m->sig_7_ro = (int8_t) TESTDB_sig_7_ro_toS(_m->sig_7_phys); 449 | _m->U7_TEST_1_ro = (uint8_t) TESTDB_U7_TEST_1_ro_toS(_m->U7_TEST_1_phys); 450 | #endif // TESTDB_USE_SIGFLOAT 451 | 452 | cframe->Data[0] |= (uint8_t) ( (_m->sig15_ro & (0xFFU)) ); 453 | cframe->Data[1] |= (uint8_t) ( ((_m->sig15_ro >> 8U) & (0x7FU)) ); 454 | cframe->Data[2] |= (uint8_t) ( (_m->sig15_2_ro & (0xFFU)) ); 455 | cframe->Data[3] |= (uint8_t) ( ((_m->sig15_2_ro >> 8U) & (0x7FU)) ); 456 | cframe->Data[4] |= (uint8_t) ( (_m->sig8_ro & (0xFFU)) ); 457 | cframe->Data[5] |= (uint8_t) ( (_m->sig_7_ro & (0x7FU)) ); 458 | cframe->Data[6] |= (uint8_t) ( ((_m->U7_TEST_1_ro & (0x7FU)) << 1U) ); 459 | 460 | cframe->MsgId = (uint32_t) SIG_TEST_1_CANID; 461 | cframe->DLC = (uint8_t) SIG_TEST_1_DLC; 462 | cframe->IDE = (uint8_t) SIG_TEST_1_IDE; 463 | return SIG_TEST_1_CANID; 464 | } 465 | 466 | #else 467 | 468 | uint32_t Pack_SIG_TEST_1_testdb(SIG_TEST_1_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide) 469 | { 470 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(SIG_TEST_1_DLC); _d[i++] = TESTDB_INITIAL_BYTE_VALUE); 471 | 472 | #ifdef TESTDB_USE_SIGFLOAT 473 | _m->sig15_ro = (int16_t) TESTDB_sig15_ro_toS(_m->sig15_phys); 474 | _m->sig15_2_ro = (int16_t) TESTDB_sig15_2_ro_toS(_m->sig15_2_phys); 475 | _m->sig8_ro = (int8_t) TESTDB_sig8_ro_toS(_m->sig8_phys); 476 | _m->sig_7_ro = (int8_t) TESTDB_sig_7_ro_toS(_m->sig_7_phys); 477 | _m->U7_TEST_1_ro = (uint8_t) TESTDB_U7_TEST_1_ro_toS(_m->U7_TEST_1_phys); 478 | #endif // TESTDB_USE_SIGFLOAT 479 | 480 | _d[0] |= (uint8_t) ( (_m->sig15_ro & (0xFFU)) ); 481 | _d[1] |= (uint8_t) ( ((_m->sig15_ro >> 8U) & (0x7FU)) ); 482 | _d[2] |= (uint8_t) ( (_m->sig15_2_ro & (0xFFU)) ); 483 | _d[3] |= (uint8_t) ( ((_m->sig15_2_ro >> 8U) & (0x7FU)) ); 484 | _d[4] |= (uint8_t) ( (_m->sig8_ro & (0xFFU)) ); 485 | _d[5] |= (uint8_t) ( (_m->sig_7_ro & (0x7FU)) ); 486 | _d[6] |= (uint8_t) ( ((_m->U7_TEST_1_ro & (0x7FU)) << 1U) ); 487 | 488 | *_len = (uint8_t) SIG_TEST_1_DLC; 489 | *_ide = (uint8_t) SIG_TEST_1_IDE; 490 | return SIG_TEST_1_CANID; 491 | } 492 | 493 | #endif // TESTDB_USE_CANSTRUCT 494 | 495 | uint32_t Unpack_EMPTY_EXT_ID_testdb(EMPTY_EXT_ID_t* _m, const uint8_t* _d, uint8_t dlc_) 496 | { 497 | (void)dlc_; 498 | _m->ValTest = (uint8_t) ( ((_d[0] >> 6U) & (0x03U)) ); 499 | _m->CS = (uint8_t) ( (_d[1] & (0x3FU)) ); 500 | 501 | #ifdef TESTDB_USE_DIAG_MONITORS 502 | _m->mon1.dlc_error = (dlc_ < EMPTY_EXT_ID_DLC); 503 | _m->mon1.last_cycle = GetSystemTick(); 504 | _m->mon1.frame_cnt++; 505 | 506 | #ifdef TESTDB_AUTO_CSM 507 | _m->mon1.csm_error = (((uint8_t)GetFrameHash(_d, EMPTY_EXT_ID_DLC, EMPTY_EXT_ID_CANID, kXor8, 1)) != (_m->CS)); 508 | #endif // TESTDB_AUTO_CSM 509 | 510 | FMon_EMPTY_EXT_ID_testdb(&_m->mon1, EMPTY_EXT_ID_CANID); 511 | #endif // TESTDB_USE_DIAG_MONITORS 512 | 513 | return EMPTY_EXT_ID_CANID; 514 | } 515 | 516 | #ifdef TESTDB_USE_CANSTRUCT 517 | 518 | uint32_t Pack_EMPTY_EXT_ID_testdb(EMPTY_EXT_ID_t* _m, __CoderDbcCanFrame_t__* cframe) 519 | { 520 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(EMPTY_EXT_ID_DLC); cframe->Data[i++] = TESTDB_INITIAL_BYTE_VALUE); 521 | 522 | #ifdef TESTDB_AUTO_CSM 523 | _m->CS = (uint8_t) 0; 524 | #endif // TESTDB_AUTO_CSM 525 | 526 | cframe->Data[0] |= (uint8_t) ( ((_m->ValTest & (0x03U)) << 6U) ); 527 | cframe->Data[1] |= (uint8_t) ( (_m->CS & (0x3FU)) ); 528 | 529 | #ifdef TESTDB_AUTO_CSM 530 | _m->CS = ((uint8_t)GetFrameHash(cframe->Data, EMPTY_EXT_ID_DLC, EMPTY_EXT_ID_CANID, kXor8, 1)); 531 | cframe->Data[1] |= (uint8_t) ( (_m->CS & (0x3FU)) ); 532 | #endif // TESTDB_AUTO_CSM 533 | 534 | cframe->MsgId = (uint32_t) EMPTY_EXT_ID_CANID; 535 | cframe->DLC = (uint8_t) EMPTY_EXT_ID_DLC; 536 | cframe->IDE = (uint8_t) EMPTY_EXT_ID_IDE; 537 | return EMPTY_EXT_ID_CANID; 538 | } 539 | 540 | #else 541 | 542 | uint32_t Pack_EMPTY_EXT_ID_testdb(EMPTY_EXT_ID_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide) 543 | { 544 | uint8_t i; for (i = 0u; i < TESTDB_VALIDATE_DLC(EMPTY_EXT_ID_DLC); _d[i++] = TESTDB_INITIAL_BYTE_VALUE); 545 | 546 | #ifdef TESTDB_AUTO_CSM 547 | _m->CS = (uint8_t) 0; 548 | #endif // TESTDB_AUTO_CSM 549 | 550 | _d[0] |= (uint8_t) ( ((_m->ValTest & (0x03U)) << 6U) ); 551 | _d[1] |= (uint8_t) ( (_m->CS & (0x3FU)) ); 552 | 553 | #ifdef TESTDB_AUTO_CSM 554 | _m->CS = ((uint8_t)GetFrameHash(_d, EMPTY_EXT_ID_DLC, EMPTY_EXT_ID_CANID, kXor8, 1)); 555 | _d[1] |= (uint8_t) ( (_m->CS & (0x3FU)) ); 556 | #endif // TESTDB_AUTO_CSM 557 | 558 | *_len = (uint8_t) EMPTY_EXT_ID_DLC; 559 | *_ide = (uint8_t) EMPTY_EXT_ID_IDE; 560 | return EMPTY_EXT_ID_CANID; 561 | } 562 | 563 | #endif // TESTDB_USE_CANSTRUCT 564 | 565 | -------------------------------------------------------------------------------- /test/gencode/lib/testdb.h: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #pragma once 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | // DBC file version 12 | #define VER_TESTDB_MAJ (1U) 13 | #define VER_TESTDB_MIN (10U) 14 | 15 | // include current dbc-driver compilation config 16 | #include "testdb-config.h" 17 | 18 | #ifdef TESTDB_USE_DIAG_MONITORS 19 | // This file must define: 20 | // base monitor struct 21 | #include "canmonitorutil.h" 22 | 23 | #endif // TESTDB_USE_DIAG_MONITORS 24 | 25 | 26 | // DLC maximum value which is used as the limit for frame's data buffer size. 27 | // Client can set its own value (not sure why) in driver-config 28 | // or can test it on some limit specified by application 29 | // e.g.: static_assert(TESTDB_MAX_DLC_VALUE <= APPLICATION_FRAME_DATA_SIZE, "Max DLC value in the driver is too big") 30 | #ifndef TESTDB_MAX_DLC_VALUE 31 | // The value which was found out by generator (real max value) 32 | #define TESTDB_MAX_DLC_VALUE 8U 33 | #endif 34 | 35 | // The limit is used for setting frame's data bytes 36 | #define TESTDB_VALIDATE_DLC(msgDlc) (((msgDlc) <= (TESTDB_MAX_DLC_VALUE)) ? (msgDlc) : (TESTDB_MAX_DLC_VALUE)) 37 | 38 | // Initial byte value to be filles in data bytes of the frame before pack signals 39 | // User can define its own custom value in driver-config file 40 | #ifndef TESTDB_INITIAL_BYTE_VALUE 41 | #define TESTDB_INITIAL_BYTE_VALUE 0U 42 | #endif 43 | 44 | 45 | // def @NO_SIGS_MSG CAN Message (273 0x111) 46 | #define NO_SIGS_MSG_IDE (0U) 47 | #define NO_SIGS_MSG_DLC (8U) 48 | #define NO_SIGS_MSG_CANID (0x111U) 49 | 50 | // def @UTEST_2 CAN Message (333 0x14d) 51 | #define UTEST_2_IDE (0U) 52 | #define UTEST_2_DLC (8U) 53 | #define UTEST_2_CANID (0x14dU) 54 | 55 | // Value tables for @ValTest signal 56 | 57 | #ifndef ValTest_UTEST_2_Unsupported 58 | #define ValTest_UTEST_2_Unsupported (3) 59 | #endif 60 | 61 | #ifndef ValTest_UTEST_2_Fail 62 | #define ValTest_UTEST_2_Fail (2) 63 | #endif 64 | 65 | #ifndef ValTest_UTEST_2_OK 66 | #define ValTest_UTEST_2_OK (1) 67 | #endif 68 | 69 | #ifndef ValTest_UTEST_2_Undefined 70 | #define ValTest_UTEST_2_Undefined (0) 71 | #endif 72 | 73 | // signal: @U7_TEST_1_ro 74 | #define TESTDB_U7_TEST_1_ro_CovFactor (1) 75 | #define TESTDB_U7_TEST_1_ro_toS(x) ( (uint8_t) ((x) - (-255)) ) 76 | #define TESTDB_U7_TEST_1_ro_fromS(x) ( ((x) + (-255)) ) 77 | 78 | typedef struct 79 | { 80 | #ifdef TESTDB_USE_BITS_SIGNAL 81 | 82 | uint32_t U28_TEST_1; // Bits=28 83 | 84 | // This is test signal for Value Table 85 | // 86 | // 87 | // 88 | // 89 | // 90 | // 91 | // 3 : "Unsupported" 92 | // 2 : "Fail" 93 | // 1 : "OK" 94 | // 0 : "Undefined" 95 | uint8_t ValTest : 2; // Bits= 2 Unit:'c' 96 | 97 | uint8_t U8_TEST_1; // Bits= 8 98 | 99 | uint8_t U7_TEST_1_ro : 7; // Bits= 7 Offset= -255 100 | 101 | #ifdef TESTDB_USE_SIGFLOAT 102 | int16_t U7_TEST_1_phys; 103 | #endif // TESTDB_USE_SIGFLOAT 104 | 105 | #else 106 | 107 | uint32_t U28_TEST_1; // Bits=28 108 | 109 | // This is test signal for Value Table 110 | // 111 | // 112 | // 113 | // 114 | // 115 | // 116 | // 3 : "Unsupported" 117 | // 2 : "Fail" 118 | // 1 : "OK" 119 | // 0 : "Undefined" 120 | uint8_t ValTest; // Bits= 2 Unit:'c' 121 | 122 | uint8_t U8_TEST_1; // Bits= 8 123 | 124 | uint8_t U7_TEST_1_ro; // Bits= 7 Offset= -255 125 | 126 | #ifdef TESTDB_USE_SIGFLOAT 127 | int16_t U7_TEST_1_phys; 128 | #endif // TESTDB_USE_SIGFLOAT 129 | 130 | #endif // TESTDB_USE_BITS_SIGNAL 131 | 132 | #ifdef TESTDB_USE_DIAG_MONITORS 133 | 134 | FrameMonitor_t mon1; 135 | 136 | #endif // TESTDB_USE_DIAG_MONITORS 137 | 138 | } UTEST_2_t; 139 | 140 | // def @EMPTY_0 CAN Message (352 0x160) 141 | #define EMPTY_0_IDE (0U) 142 | #define EMPTY_0_DLC (8U) 143 | #define EMPTY_0_CANID (0x160U) 144 | #define EMPTY_0_CYC (101U) 145 | 146 | typedef struct 147 | { 148 | #ifdef TESTDB_USE_BITS_SIGNAL 149 | 150 | // test pattern 151 | uint8_t CS : 6; // Bits= 6 152 | 153 | // 154 | uint8_t RC : 4; // Bits= 4 155 | 156 | #ifdef TESTDB_AUTO_ROLL 157 | 158 | uint8_t RC_expt : 4; // Bits= 4 159 | 160 | #endif // TESTDB_AUTO_ROLL 161 | 162 | #else 163 | 164 | // test pattern 165 | uint8_t CS; // Bits= 6 166 | 167 | // 168 | uint8_t RC; // Bits= 4 169 | 170 | #ifdef TESTDB_AUTO_ROLL 171 | 172 | uint8_t RC_expt; // Bits= 4 173 | 174 | #endif // TESTDB_AUTO_ROLL 175 | 176 | #endif // TESTDB_USE_BITS_SIGNAL 177 | 178 | #ifdef TESTDB_USE_DIAG_MONITORS 179 | 180 | FrameMonitor_t mon1; 181 | 182 | #endif // TESTDB_USE_DIAG_MONITORS 183 | 184 | } EMPTY_0_t; 185 | 186 | // def @UTEST_3 CAN Message (555 0x22b) 187 | #define UTEST_3_IDE (0U) 188 | #define UTEST_3_DLC (8U) 189 | #define UTEST_3_CANID (0x22bU) 190 | 191 | // Value tables for @TestValTableID signal 192 | 193 | #ifndef TestValTableID_UTEST_3_Description_for_the_value_0x7 194 | #define TestValTableID_UTEST_3_Description_for_the_value_0x7 (-2) 195 | #endif 196 | 197 | #ifndef TestValTableID_UTEST_3_Udef 198 | #define TestValTableID_UTEST_3_Udef (-1) 199 | #endif 200 | 201 | #ifndef TestValTableID_UTEST_3_Udef 202 | #define TestValTableID_UTEST_3_Udef (6) 203 | #endif 204 | 205 | #ifndef TestValTableID_UTEST_3_Udef 206 | #define TestValTableID_UTEST_3_Udef (5) 207 | #endif 208 | 209 | #ifndef TestValTableID_UTEST_3_Udef 210 | #define TestValTableID_UTEST_3_Udef (4) 211 | #endif 212 | 213 | #ifndef TestValTableID_UTEST_3_Error 214 | #define TestValTableID_UTEST_3_Error (3) 215 | #endif 216 | 217 | #ifndef TestValTableID_UTEST_3_Ok 218 | #define TestValTableID_UTEST_3_Ok (2) 219 | #endif 220 | 221 | #ifndef TestValTableID_UTEST_3_State_one 222 | #define TestValTableID_UTEST_3_State_one (1) 223 | #endif 224 | 225 | #ifndef TestValTableID_UTEST_3_State_1 226 | #define TestValTableID_UTEST_3_State_1 (0) 227 | #endif 228 | 229 | 230 | typedef struct 231 | { 232 | #ifdef TESTDB_USE_BITS_SIGNAL 233 | 234 | uint32_t U32_TEST_1; // Bits=32 235 | 236 | // -2 : "Description for the value '0x7'" 237 | // -1 : "Udef" 238 | // 6 : "Udef" 239 | // 5 : "Udef" 240 | // 4 : "Udef" 241 | // 3 : "Error" 242 | // 2 : "Ok" 243 | // 1 : "State one" 244 | // 0 : "State 1" 245 | uint8_t TestValTableID : 3; // Bits= 3 246 | 247 | #else 248 | 249 | uint32_t U32_TEST_1; // Bits=32 250 | 251 | // -2 : "Description for the value '0x7'" 252 | // -1 : "Udef" 253 | // 6 : "Udef" 254 | // 5 : "Udef" 255 | // 4 : "Udef" 256 | // 3 : "Error" 257 | // 2 : "Ok" 258 | // 1 : "State one" 259 | // 0 : "State 1" 260 | uint8_t TestValTableID; // Bits= 3 261 | 262 | #endif // TESTDB_USE_BITS_SIGNAL 263 | 264 | #ifdef TESTDB_USE_DIAG_MONITORS 265 | 266 | FrameMonitor_t mon1; 267 | 268 | #endif // TESTDB_USE_DIAG_MONITORS 269 | 270 | } UTEST_3_t; 271 | 272 | // def @FLT_TEST_1 CAN Message (864 0x360) 273 | #define FLT_TEST_1_IDE (0U) 274 | #define FLT_TEST_1_DLC (8U) 275 | #define FLT_TEST_1_CANID (0x360U) 276 | #define FLT_TEST_1_CYC (101U) 277 | 278 | // Value tables for @ValTable signal 279 | 280 | #ifndef ValTable_FLT_TEST_1_Unsupported 281 | #define ValTable_FLT_TEST_1_Unsupported (3) 282 | #endif 283 | 284 | #ifndef ValTable_FLT_TEST_1_Fail 285 | #define ValTable_FLT_TEST_1_Fail (2) 286 | #endif 287 | 288 | #ifndef ValTable_FLT_TEST_1_OK 289 | #define ValTable_FLT_TEST_1_OK (1) 290 | #endif 291 | 292 | #ifndef ValTable_FLT_TEST_1_Undefined 293 | #define ValTable_FLT_TEST_1_Undefined (0) 294 | #endif 295 | 296 | // signal: @INT_TEST_2_ro 297 | #define TESTDB_INT_TEST_2_ro_CovFactor (5) 298 | #define TESTDB_INT_TEST_2_ro_toS(x) ( (int8_t) ((x) / (5)) ) 299 | #define TESTDB_INT_TEST_2_ro_fromS(x) ( ((x) * (5)) ) 300 | // signal: @Accel_ro 301 | #define TESTDB_Accel_ro_CovFactor (0.1) 302 | #define TESTDB_Accel_ro_toS(x) ( (uint16_t) (((x) - (-100.0)) / (0.1)) ) 303 | #define TESTDB_Accel_ro_fromS(x) ( (((x) * (0.1)) + (-100.0)) ) 304 | // signal: @FLT4_TEST_1_ro 305 | #define TESTDB_FLT4_TEST_1_ro_CovFactor (2.01) 306 | #define TESTDB_FLT4_TEST_1_ro_toS(x) ( (uint8_t) (((x) - (-0.01)) / (2.01)) ) 307 | #define TESTDB_FLT4_TEST_1_ro_fromS(x) ( (((x) * (2.01)) + (-0.01)) ) 308 | // signal: @FLT4_TEST_2_ro 309 | #define TESTDB_FLT4_TEST_2_ro_CovFactor (2.01) 310 | #define TESTDB_FLT4_TEST_2_ro_toS(x) ( (uint8_t) (((x) - (-5.0)) / (2.01)) ) 311 | #define TESTDB_FLT4_TEST_2_ro_fromS(x) ( (((x) * (2.01)) + (-5.0)) ) 312 | // signal: @FLT4_TEST_3_ro 313 | #define TESTDB_FLT4_TEST_3_ro_CovFactor (2.0) 314 | #define TESTDB_FLT4_TEST_3_ro_toS(x) ( (uint8_t) (((x) - (-10.1)) / (2.0)) ) 315 | #define TESTDB_FLT4_TEST_3_ro_fromS(x) ( (((x) * (2.0)) + (-10.1)) ) 316 | // signal: @INT_TEST_1_ro 317 | #define TESTDB_INT_TEST_1_ro_CovFactor (9) 318 | #define TESTDB_INT_TEST_1_ro_toS(x) ( (uint8_t) (((x) - (-11)) / (9)) ) 319 | #define TESTDB_INT_TEST_1_ro_fromS(x) ( (((x) * (9)) + (-11)) ) 320 | 321 | typedef struct 322 | { 323 | #ifdef TESTDB_USE_BITS_SIGNAL 324 | 325 | // This is just comment. 326 | // Next line. 327 | // 3 : "Unsupported" 328 | // 2 : "Fail" 329 | // 1 : "OK" 330 | // 0 : "Undefined" 331 | uint8_t ValTable : 2; // Bits= 2 Unit:'e' 332 | 333 | uint8_t Position : 4; // Bits= 4 334 | 335 | int8_t INT_TEST_2_ro : 7; // [-] Bits= 7 Factor= 5 336 | 337 | #ifdef TESTDB_USE_SIGFLOAT 338 | int16_t INT_TEST_2_phys; 339 | #endif // TESTDB_USE_SIGFLOAT 340 | 341 | // 342 | uint8_t RC : 4; // Bits= 4 343 | 344 | // 345 | uint8_t CS : 4; // Bits= 4 346 | 347 | // Test floating point value. 348 | uint16_t Accel_ro; // Bits=12 Offset= -100.0 Factor= 0.1 Unit:'m/s' 349 | 350 | #ifdef TESTDB_USE_SIGFLOAT 351 | sigfloat_t Accel_phys; 352 | #endif // TESTDB_USE_SIGFLOAT 353 | 354 | uint8_t FLT4_TEST_1_ro : 4; // Bits= 4 Offset= -0.01 Factor= 2.01 355 | 356 | #ifdef TESTDB_USE_SIGFLOAT 357 | sigfloat_t FLT4_TEST_1_phys; 358 | #endif // TESTDB_USE_SIGFLOAT 359 | 360 | uint8_t FLT4_TEST_2_ro : 4; // Bits= 4 Offset= -5.0 Factor= 2.01 361 | 362 | #ifdef TESTDB_USE_SIGFLOAT 363 | sigfloat_t FLT4_TEST_2_phys; 364 | #endif // TESTDB_USE_SIGFLOAT 365 | 366 | uint8_t FLT4_TEST_3_ro : 4; // Bits= 4 Offset= -10.1 Factor= 2.0 367 | 368 | #ifdef TESTDB_USE_SIGFLOAT 369 | sigfloat_t FLT4_TEST_3_phys; 370 | #endif // TESTDB_USE_SIGFLOAT 371 | 372 | uint8_t INT_TEST_1_ro : 4; // Bits= 4 Offset= -11 Factor= 9 373 | 374 | #ifdef TESTDB_USE_SIGFLOAT 375 | int8_t INT_TEST_1_phys; 376 | #endif // TESTDB_USE_SIGFLOAT 377 | 378 | #ifdef TESTDB_AUTO_ROLL 379 | 380 | uint8_t RC_expt : 4; // Bits= 4 381 | 382 | #endif // TESTDB_AUTO_ROLL 383 | 384 | #else 385 | 386 | // This is just comment. 387 | // Next line. 388 | // 3 : "Unsupported" 389 | // 2 : "Fail" 390 | // 1 : "OK" 391 | // 0 : "Undefined" 392 | uint8_t ValTable; // Bits= 2 Unit:'e' 393 | 394 | uint8_t Position; // Bits= 4 395 | 396 | int8_t INT_TEST_2_ro; // [-] Bits= 7 Factor= 5 397 | 398 | #ifdef TESTDB_USE_SIGFLOAT 399 | int16_t INT_TEST_2_phys; 400 | #endif // TESTDB_USE_SIGFLOAT 401 | 402 | // 403 | uint8_t RC; // Bits= 4 404 | 405 | // 406 | uint8_t CS; // Bits= 4 407 | 408 | // Test floating point value. 409 | uint16_t Accel_ro; // Bits=12 Offset= -100.0 Factor= 0.1 Unit:'m/s' 410 | 411 | #ifdef TESTDB_USE_SIGFLOAT 412 | sigfloat_t Accel_phys; 413 | #endif // TESTDB_USE_SIGFLOAT 414 | 415 | uint8_t FLT4_TEST_1_ro; // Bits= 4 Offset= -0.01 Factor= 2.01 416 | 417 | #ifdef TESTDB_USE_SIGFLOAT 418 | sigfloat_t FLT4_TEST_1_phys; 419 | #endif // TESTDB_USE_SIGFLOAT 420 | 421 | uint8_t FLT4_TEST_2_ro; // Bits= 4 Offset= -5.0 Factor= 2.01 422 | 423 | #ifdef TESTDB_USE_SIGFLOAT 424 | sigfloat_t FLT4_TEST_2_phys; 425 | #endif // TESTDB_USE_SIGFLOAT 426 | 427 | uint8_t FLT4_TEST_3_ro; // Bits= 4 Offset= -10.1 Factor= 2.0 428 | 429 | #ifdef TESTDB_USE_SIGFLOAT 430 | sigfloat_t FLT4_TEST_3_phys; 431 | #endif // TESTDB_USE_SIGFLOAT 432 | 433 | uint8_t INT_TEST_1_ro; // Bits= 4 Offset= -11 Factor= 9 434 | 435 | #ifdef TESTDB_USE_SIGFLOAT 436 | int8_t INT_TEST_1_phys; 437 | #endif // TESTDB_USE_SIGFLOAT 438 | 439 | #ifdef TESTDB_AUTO_ROLL 440 | 441 | uint8_t RC_expt; // Bits= 4 442 | 443 | #endif // TESTDB_AUTO_ROLL 444 | 445 | #endif // TESTDB_USE_BITS_SIGNAL 446 | 447 | #ifdef TESTDB_USE_DIAG_MONITORS 448 | 449 | FrameMonitor_t mon1; 450 | 451 | #endif // TESTDB_USE_DIAG_MONITORS 452 | 453 | } FLT_TEST_1_t; 454 | 455 | // def @SIG_TEST_1 CAN Message (1911 0x777) 456 | #define SIG_TEST_1_IDE (0U) 457 | #define SIG_TEST_1_DLC (8U) 458 | #define SIG_TEST_1_CANID (0x777U) 459 | // signal: @sig15_ro 460 | #define TESTDB_sig15_ro_CovFactor (3) 461 | #define TESTDB_sig15_ro_toS(x) ( (int16_t) (((x) - (-1024)) / (3)) ) 462 | #define TESTDB_sig15_ro_fromS(x) ( (((x) * (3)) + (-1024)) ) 463 | // signal: @sig15_2_ro 464 | #define TESTDB_sig15_2_ro_CovFactor (1.9) 465 | #define TESTDB_sig15_2_ro_toS(x) ( (int16_t) (((x) - (-2500.0)) / (1.9)) ) 466 | #define TESTDB_sig15_2_ro_fromS(x) ( (((x) * (1.9)) + (-2500.0)) ) 467 | // signal: @sig8_ro 468 | #define TESTDB_sig8_ro_CovFactor (5) 469 | #define TESTDB_sig8_ro_toS(x) ( (int8_t) ((x) / (5)) ) 470 | #define TESTDB_sig8_ro_fromS(x) ( ((x) * (5)) ) 471 | // signal: @sig_7_ro 472 | #define TESTDB_sig_7_ro_CovFactor (1.2) 473 | #define TESTDB_sig_7_ro_toS(x) ( (int8_t) (((x) - (0.0)) / (1.2)) ) 474 | #define TESTDB_sig_7_ro_fromS(x) ( (((x) * (1.2)) + (0.0)) ) 475 | 476 | typedef struct 477 | { 478 | #ifdef TESTDB_USE_BITS_SIGNAL 479 | 480 | int16_t sig15_ro; // [-] Bits=15 Offset= -1024 Factor= 3 481 | 482 | #ifdef TESTDB_USE_SIGFLOAT 483 | int32_t sig15_phys; 484 | #endif // TESTDB_USE_SIGFLOAT 485 | 486 | int16_t sig15_2_ro; // [-] Bits=15 Offset= -2500.0 Factor= 1.9 487 | 488 | #ifdef TESTDB_USE_SIGFLOAT 489 | sigfloat_t sig15_2_phys; 490 | #endif // TESTDB_USE_SIGFLOAT 491 | 492 | int8_t sig8_ro; // [-] Bits= 8 Factor= 5 493 | 494 | #ifdef TESTDB_USE_SIGFLOAT 495 | int16_t sig8_phys; 496 | #endif // TESTDB_USE_SIGFLOAT 497 | 498 | int8_t sig_7_ro : 7; // [-] Bits= 7 Factor= 1.2 499 | 500 | #ifdef TESTDB_USE_SIGFLOAT 501 | sigfloat_t sig_7_phys; 502 | #endif // TESTDB_USE_SIGFLOAT 503 | 504 | uint8_t U7_TEST_1_ro : 7; // Bits= 7 Offset= -255 505 | 506 | #ifdef TESTDB_USE_SIGFLOAT 507 | int16_t U7_TEST_1_phys; 508 | #endif // TESTDB_USE_SIGFLOAT 509 | 510 | #else 511 | 512 | int16_t sig15_ro; // [-] Bits=15 Offset= -1024 Factor= 3 513 | 514 | #ifdef TESTDB_USE_SIGFLOAT 515 | int32_t sig15_phys; 516 | #endif // TESTDB_USE_SIGFLOAT 517 | 518 | int16_t sig15_2_ro; // [-] Bits=15 Offset= -2500.0 Factor= 1.9 519 | 520 | #ifdef TESTDB_USE_SIGFLOAT 521 | sigfloat_t sig15_2_phys; 522 | #endif // TESTDB_USE_SIGFLOAT 523 | 524 | int8_t sig8_ro; // [-] Bits= 8 Factor= 5 525 | 526 | #ifdef TESTDB_USE_SIGFLOAT 527 | int16_t sig8_phys; 528 | #endif // TESTDB_USE_SIGFLOAT 529 | 530 | int8_t sig_7_ro; // [-] Bits= 7 Factor= 1.2 531 | 532 | #ifdef TESTDB_USE_SIGFLOAT 533 | sigfloat_t sig_7_phys; 534 | #endif // TESTDB_USE_SIGFLOAT 535 | 536 | uint8_t U7_TEST_1_ro; // Bits= 7 Offset= -255 537 | 538 | #ifdef TESTDB_USE_SIGFLOAT 539 | int16_t U7_TEST_1_phys; 540 | #endif // TESTDB_USE_SIGFLOAT 541 | 542 | #endif // TESTDB_USE_BITS_SIGNAL 543 | 544 | #ifdef TESTDB_USE_DIAG_MONITORS 545 | 546 | FrameMonitor_t mon1; 547 | 548 | #endif // TESTDB_USE_DIAG_MONITORS 549 | 550 | } SIG_TEST_1_t; 551 | 552 | // def @EMPTY_EXT_ID CAN Message (536870902 0x1ffffff6) 553 | #define EMPTY_EXT_ID_IDE (1U) 554 | #define EMPTY_EXT_ID_DLC (8U) 555 | #define EMPTY_EXT_ID_CANID (0x1ffffff6U) 556 | 557 | // Value tables for @ValTest signal 558 | 559 | #ifndef ValTest_EMPTY_EXT_ID_Unsupported 560 | #define ValTest_EMPTY_EXT_ID_Unsupported (3) 561 | #endif 562 | 563 | #ifndef ValTest_EMPTY_EXT_ID_Fail 564 | #define ValTest_EMPTY_EXT_ID_Fail (2) 565 | #endif 566 | 567 | #ifndef ValTest_EMPTY_EXT_ID_OK 568 | #define ValTest_EMPTY_EXT_ID_OK (1) 569 | #endif 570 | 571 | #ifndef ValTest_EMPTY_EXT_ID_Undefined 572 | #define ValTest_EMPTY_EXT_ID_Undefined (0) 573 | #endif 574 | 575 | 576 | typedef struct 577 | { 578 | #ifdef TESTDB_USE_BITS_SIGNAL 579 | 580 | // This is test signal for Value Table 581 | // 582 | // 583 | // 584 | // 585 | // 586 | // 587 | // 3 : "Unsupported" 588 | // 2 : "Fail" 589 | // 1 : "OK" 590 | // 0 : "Undefined" 591 | uint8_t ValTest : 2; // Bits= 2 Unit:'c' 592 | 593 | // test pattern 594 | uint8_t CS : 6; // Bits= 6 595 | 596 | #else 597 | 598 | // This is test signal for Value Table 599 | // 600 | // 601 | // 602 | // 603 | // 604 | // 605 | // 3 : "Unsupported" 606 | // 2 : "Fail" 607 | // 1 : "OK" 608 | // 0 : "Undefined" 609 | uint8_t ValTest; // Bits= 2 Unit:'c' 610 | 611 | // test pattern 612 | uint8_t CS; // Bits= 6 613 | 614 | #endif // TESTDB_USE_BITS_SIGNAL 615 | 616 | #ifdef TESTDB_USE_DIAG_MONITORS 617 | 618 | FrameMonitor_t mon1; 619 | 620 | #endif // TESTDB_USE_DIAG_MONITORS 621 | 622 | } EMPTY_EXT_ID_t; 623 | 624 | // Function signatures 625 | 626 | uint32_t Unpack_UTEST_2_testdb(UTEST_2_t* _m, const uint8_t* _d, uint8_t dlc_); 627 | #ifdef TESTDB_USE_CANSTRUCT 628 | uint32_t Pack_UTEST_2_testdb(UTEST_2_t* _m, __CoderDbcCanFrame_t__* cframe); 629 | #else 630 | uint32_t Pack_UTEST_2_testdb(UTEST_2_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide); 631 | #endif // TESTDB_USE_CANSTRUCT 632 | 633 | uint32_t Unpack_EMPTY_0_testdb(EMPTY_0_t* _m, const uint8_t* _d, uint8_t dlc_); 634 | #ifdef TESTDB_USE_CANSTRUCT 635 | uint32_t Pack_EMPTY_0_testdb(EMPTY_0_t* _m, __CoderDbcCanFrame_t__* cframe); 636 | #else 637 | uint32_t Pack_EMPTY_0_testdb(EMPTY_0_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide); 638 | #endif // TESTDB_USE_CANSTRUCT 639 | 640 | uint32_t Unpack_UTEST_3_testdb(UTEST_3_t* _m, const uint8_t* _d, uint8_t dlc_); 641 | #ifdef TESTDB_USE_CANSTRUCT 642 | uint32_t Pack_UTEST_3_testdb(UTEST_3_t* _m, __CoderDbcCanFrame_t__* cframe); 643 | #else 644 | uint32_t Pack_UTEST_3_testdb(UTEST_3_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide); 645 | #endif // TESTDB_USE_CANSTRUCT 646 | 647 | uint32_t Unpack_FLT_TEST_1_testdb(FLT_TEST_1_t* _m, const uint8_t* _d, uint8_t dlc_); 648 | #ifdef TESTDB_USE_CANSTRUCT 649 | uint32_t Pack_FLT_TEST_1_testdb(FLT_TEST_1_t* _m, __CoderDbcCanFrame_t__* cframe); 650 | #else 651 | uint32_t Pack_FLT_TEST_1_testdb(FLT_TEST_1_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide); 652 | #endif // TESTDB_USE_CANSTRUCT 653 | 654 | uint32_t Unpack_SIG_TEST_1_testdb(SIG_TEST_1_t* _m, const uint8_t* _d, uint8_t dlc_); 655 | #ifdef TESTDB_USE_CANSTRUCT 656 | uint32_t Pack_SIG_TEST_1_testdb(SIG_TEST_1_t* _m, __CoderDbcCanFrame_t__* cframe); 657 | #else 658 | uint32_t Pack_SIG_TEST_1_testdb(SIG_TEST_1_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide); 659 | #endif // TESTDB_USE_CANSTRUCT 660 | 661 | uint32_t Unpack_EMPTY_EXT_ID_testdb(EMPTY_EXT_ID_t* _m, const uint8_t* _d, uint8_t dlc_); 662 | #ifdef TESTDB_USE_CANSTRUCT 663 | uint32_t Pack_EMPTY_EXT_ID_testdb(EMPTY_EXT_ID_t* _m, __CoderDbcCanFrame_t__* cframe); 664 | #else 665 | uint32_t Pack_EMPTY_EXT_ID_testdb(EMPTY_EXT_ID_t* _m, uint8_t* _d, uint8_t* _len, uint8_t* _ide); 666 | #endif // TESTDB_USE_CANSTRUCT 667 | 668 | #ifdef __cplusplus 669 | } 670 | #endif 671 | -------------------------------------------------------------------------------- /test/gencode/usr/testdb-fmon.c: -------------------------------------------------------------------------------- 1 | // Generator version : v3.1 2 | // DBC filename : testdb.dbc 3 | #include "testdb-fmon.h" 4 | 5 | #ifdef TESTDB_USE_DIAG_MONITORS 6 | 7 | /* 8 | Put the monitor function content here, keep in mind - 9 | next generation will completely clear all manually added code (!) 10 | */ 11 | 12 | #ifdef TESTDB_USE_MONO_FMON 13 | 14 | void _FMon_MONO_testdb(FrameMonitor_t* _mon, uint32_t msgid) 15 | { 16 | (void)_mon; 17 | (void)msgid; 18 | } 19 | 20 | #else 21 | 22 | void _FMon_NO_SIGS_MSG_testdb(FrameMonitor_t* _mon, uint32_t msgid) 23 | { 24 | (void)_mon; 25 | (void)msgid; 26 | } 27 | 28 | void _FMon_UTEST_2_testdb(FrameMonitor_t* _mon, uint32_t msgid) 29 | { 30 | (void)_mon; 31 | (void)msgid; 32 | } 33 | 34 | void _FMon_EMPTY_0_testdb(FrameMonitor_t* _mon, uint32_t msgid) 35 | { 36 | (void)_mon; 37 | (void)msgid; 38 | } 39 | 40 | void _FMon_UTEST_3_testdb(FrameMonitor_t* _mon, uint32_t msgid) 41 | { 42 | (void)_mon; 43 | (void)msgid; 44 | } 45 | 46 | void _FMon_FLT_TEST_1_testdb(FrameMonitor_t* _mon, uint32_t msgid) 47 | { 48 | (void)_mon; 49 | (void)msgid; 50 | } 51 | 52 | void _FMon_SIG_TEST_1_testdb(FrameMonitor_t* _mon, uint32_t msgid) 53 | { 54 | (void)_mon; 55 | (void)msgid; 56 | } 57 | 58 | void _FMon_EMPTY_EXT_ID_testdb(FrameMonitor_t* _mon, uint32_t msgid) 59 | { 60 | (void)_mon; 61 | (void)msgid; 62 | } 63 | 64 | #endif // TESTDB_USE_MONO_FMON 65 | 66 | #endif // TESTDB_USE_DIAG_MONITORS 67 | -------------------------------------------------------------------------------- /test/testdb.dbc: -------------------------------------------------------------------------------- 1 | VERSION "1.10" 2 | 3 | 4 | NS_ : 5 | NS_DESC_ 6 | CM_ 7 | BA_DEF_ 8 | BA_ 9 | VAL_ 10 | CAT_DEF_ 11 | CAT_ 12 | FILTER 13 | BA_DEF_DEF_ 14 | EV_DATA_ 15 | ENVVAR_DATA_ 16 | SGTYPE_ 17 | SGTYPE_VAL_ 18 | BA_DEF_SGTYPE_ 19 | BA_SGTYPE_ 20 | SIG_TYPE_REF_ 21 | VAL_TABLE_ 22 | SIG_GROUP_ 23 | SIG_VALTYPE_ 24 | SIGTYPE_VALTYPE_ 25 | BO_TX_BU_ 26 | BA_DEF_REL_ 27 | BA_REL_ 28 | BA_DEF_DEF_REL_ 29 | BU_SG_REL_ 30 | BU_EV_REL_ 31 | BU_BO_REL_ 32 | SG_MUL_VAL_ 33 | 34 | BS_: 35 | 36 | BU_: EPS ESP BMS BCM 37 | VAL_TABLE_ VtTestSig -2 "Description for the value '0x7'" -1 "Udef" 6 "Udef" 5 "Udef" 4 "Udef" 3 "Error" 2 "Ok" 1 "State one" 0 "State 1" ; 38 | 39 | 40 | BO_ 273 NO_SIGS_MSG: 8 BCM 41 | 42 | BO_ 1911 SIG_TEST_1: 8 EPS 43 | SG_ U7_TEST_1 : 55|7@0+ (1,-255) [-255|-128] "" BCM 44 | SG_ sig_7 : 40|7@1- (1.2,0) [-76.8|75.6] "" BCM 45 | SG_ sig8 : 32|8@1- (5,0) [-640|635] "" BCM 46 | SG_ sig15_2 : 16|15@1- (1.9,-2500) [-33629.6|28627.7] "" BCM 47 | SG_ sig15 : 0|15@1- (3,-1024) [-50176|48125] "" BCM 48 | 49 | BO_ 2684354550 EMPTY_EXT_ID: 8 BCM 50 | SG_ CS : 13|6@0+ (1,0) [0|255] "" BCM,ESP,BMS 51 | SG_ ValTest : 7|2@0+ (1,0) [0|0] "c" BCM,ESP,BMS 52 | 53 | BO_ 555 UTEST_3: 8 BCM 54 | SG_ TestValTableID : 32|3@1+ (1,0) [0|7] "" BMS 55 | SG_ U32_TEST_1 : 0|32@1+ (1,0) [0|4294967295] "" BMS 56 | 57 | BO_ 333 UTEST_2: 8 BCM 58 | SG_ U8_TEST_1 : 39|8@0+ (1,0) [0|255] "" BMS 59 | SG_ U7_TEST_1 : 47|7@0+ (1,-255) [-255|-128] "" BMS 60 | SG_ ValTest : 30|2@0+ (1,0) [0|3] "c" ESP,BMS 61 | SG_ U28_TEST_1 : 0|28@1+ (1,0) [0|4294967295] "" ESP,BMS 62 | 63 | BO_ 864 FLT_TEST_1: 8 BMS 64 | SG_ INT_TEST_2 : 15|7@0- (5,0) [-320|315] "" BCM 65 | SG_ INT_TEST_1 : 53|4@0+ (9,-11) [-11|124] "" BCM 66 | SG_ FLT4_TEST_2 : 43|4@0+ (2.01,-5) [-5|25.15] "" BCM 67 | SG_ FLT4_TEST_1 : 39|4@0+ (2.01,-0.01) [-0.01|30.14] "" BCM 68 | SG_ FLT4_TEST_3 : 47|4@0+ (2,-10.1) [-10.1|19.9] "" BCM 69 | SG_ Accel : 24|12@1+ (0.1,-100) [-100|309.5] "m/s" BCM 70 | SG_ ValTable : 1|2@0+ (1,0) [0|3] "e" BCM 71 | SG_ Position : 7|4@0+ (1,0) [0|15] "" BCM 72 | SG_ RC : 16|4@1+ (1,0) [0|15] "" BCM 73 | SG_ CS : 20|4@1+ (1,0) [0|15] "" BCM 74 | 75 | BO_ 352 EMPTY_0: 8 BCM 76 | SG_ CS : 38|6@0+ (1,0) [0|63] "" BMS 77 | SG_ RC : 47|4@1+ (1,0) [0|15] "" BMS 78 | 79 | BO_TX_BU_ 352 : BMS,ESP,BCM; 80 | 81 | 82 | CM_ BU_ BMS "Selector ECU info block 83 | "; 84 | CM_ BU_ BCM "ESP ECU information"; 85 | CM_ SG_ 2684354550 CS " test pattern"; 86 | CM_ SG_ 2684354550 ValTest "This is test signal for Value Table 87 | 88 | 89 | 90 | "; 91 | CM_ SG_ 333 ValTest "This is test signal for Value Table 92 | 93 | 94 | 95 | "; 96 | CM_ SG_ 864 Accel "Test floating point value."; 97 | CM_ SG_ 864 ValTable "This is just comment. 98 | Next line."; 99 | CM_ SG_ 864 RC ""; 100 | CM_ SG_ 864 CS ""; 101 | CM_ SG_ 352 CS " test pattern"; 102 | CM_ SG_ 352 RC ""; 103 | BA_DEF_ SG_ "GenSigSendType" ENUM "Cyclic","OnWrite","OnWriteWithRepetition","OnChange","OnChangeWithRepetition","IfActive","IfActiveWithRepetition","NoSigSendType"; 104 | BA_DEF_ BO_ "GenMsgSendType " ENUM "Cyclic","not_used","not_used","not_used","not_used","Cyclic","not_used","IfActive","NoMsgSendType"; 105 | BA_DEF_ BU_ "NmStationAddress" HEX 0 0; 106 | BA_DEF_ "BusType" STRING ; 107 | BA_DEF_ "DBName" STRING ; 108 | BA_DEF_ BO_ "GenMsgCycleTime" INT 2 50000; 109 | BA_DEF_ BO_ "GenMsgDelayTime" INT 1 1000; 110 | BA_DEF_ BO_ "GenMsgNrOfRepetitions" INT 1 999999; 111 | BA_DEF_ BO_ "GenMsgSendType" ENUM "cyclic","spontaneous","cyclicIfActive","spontaneousWithDelay","cyclicAndSpontaneous","cyclicAndSpontaneousWithDelay","spontaneousWithRepetition","cyclicIfActiveAndSpontaneousWD"; 112 | BA_DEF_ SG_ "GenSigInactiveValue" INT 0 100000; 113 | BA_DEF_ SG_ "GenSigStartValue" FLOAT 0 100000000000; 114 | BA_DEF_DEF_ "GenSigSendType" "Cyclic"; 115 | BA_DEF_DEF_ "GenMsgSendType " "NoMsgSendType"; 116 | BA_DEF_DEF_ "NmStationAddress" 0; 117 | BA_DEF_DEF_ "BusType" ""; 118 | BA_DEF_DEF_ "DBName" ""; 119 | BA_DEF_DEF_ "GenMsgCycleTime" 100; 120 | BA_DEF_DEF_ "GenMsgDelayTime" 1; 121 | BA_DEF_DEF_ "GenMsgNrOfRepetitions" 1; 122 | BA_DEF_DEF_ "GenMsgSendType" "spontaneous"; 123 | BA_DEF_DEF_ "GenSigInactiveValue" 0; 124 | BA_DEF_DEF_ "GenSigStartValue" 0; 125 | BA_ "DBName" "ceedselector"; 126 | BA_ "GenMsgSendType" BO_ 2684354550 0; 127 | BA_ "GenMsgCycleTime" BO_ 864 101; 128 | BA_ "GenMsgSendType" BO_ 864 0; 129 | BA_ "GenMsgCycleTime" BO_ 352 101; 130 | BA_ "GenMsgSendType" BO_ 352 0; 131 | BA_ "GenSigStartValue" SG_ 1911 sig15_2 1315.78947368421; 132 | BA_ "GenSigStartValue" SG_ 1911 sig15 341.333333333333; 133 | BA_ "GenSigStartValue" SG_ 864 INT_TEST_2 0.6; 134 | BA_ "GenSigStartValue" SG_ 864 INT_TEST_1 0; 135 | BA_ "GenSigStartValue" SG_ 864 FLT4_TEST_2 0; 136 | BA_ "GenSigStartValue" SG_ 864 FLT4_TEST_1 0; 137 | BA_ "GenSigStartValue" SG_ 864 FLT4_TEST_3 5.05; 138 | BA_ "GenSigStartValue" SG_ 864 Accel 1000; 139 | VAL_ 2684354550 ValTest 3 "Unsupported" 2 "Fail" 1 "OK" 0 "Undefined" ; 140 | VAL_ 555 TestValTableID -2 "Description for the value '0x7'" -1 "Udef" 6 "Udef" 5 "Udef" 4 "Udef" 3 "Error" 2 "Ok" 1 "State one" 0 "State 1" ; 141 | VAL_ 333 ValTest 3 "Unsupported" 2 "Fail" 1 "OK" 0 "Undefined" ; 142 | VAL_ 864 ValTable 3 "Unsupported" 2 "Fail" 1 "OK" 0 "Undefined" ; 143 | 144 | --------------------------------------------------------------------------------