Monitoring and simulating different Bus messages basing on C++
Explore the docs »
Table of Contents
A C/C++ program that can simulate CAN/CANFD/LIN signals and send those messages on real bus. Mainly there are two libs needed, one is db_Parser, which can parse dbc/ldf files and provide decode and encode functions. The other one is TsAPI, which can send real time messages using Vector's hardware interfaces. Besides, there is another lib using to combine TsAPI and db_Parser, and implement real time Cntr & Chks of sending messages together with some real time message display & signals input functions etc.
Functions available:
- Parse the database file(dbc & ldf files), simulate ECU node.
- Send messages on different Vector's hardware interfaces(CAN/CANFD/LIN/DAIO).
- Real-time counter & cheksum.
- Pre-defined config file to pass some valuables(overwrite some dbc default signal values during simulation)
- Availablility to change simulated signal's value at any time.
- Real-time decode(real-time signal monitoring).
I personly use VSCode + CMAKE + MinGW64(x86_64-12.2.0-release-posix-seh-ucrt-rt_v10-rev2), and you can use my CMakeLists.txt to easily build this project.
This is an example of how you may give instructions on setting up your project locally. To get a local copy up and running follow these simple example steps.
- MinGW-w64
- CMake
- VSCode + CMake extensions
- libTsAPI.a, libdb_Parser.a, libSendFunc.a, vxlapi64
After you have prepared the environment, you just need to clone the repo and start to build. Make sure you got libTsAPI.a, libdb_Parser.a, libSendFunc.a, vxlapi64.lib under <$workforder>/lib/static.
- You can design your own program with those APIs, here is an example about how to use config.ini file for pre-defined parameters inputs.
#include "sendFunctions.hpp"
#include "readConfig.hpp"
// global variables
DbcParser dbcFile;
SendFunc* monitorCAN = new SendFunc();
std::thread sendThreadCAN;
std::thread inputThread;
Payloads_CAN encodedPayloadsCAN;
std::shared_ptr<CANFD> canfd;
std::shared_ptr<CAN> can;
Config test_config;
int main() {
if (!readIniValue(test_config)) {
std::cerr << "Error reading config.ini file." << std::endl;
return 1;
}
if (!test_config.dbc_file.empty()) {
// parse the dbcfile
dbcFile.parse(test_config.dbc_file);
monitorCAN->setDB(&dbcFile);
if (dbcFile.databaseBusType == BusType::CAN_FD) {
if (!test_config.dbc_node.empty()) {
// generate Node signals default value
dbcFile.NodeMsgGenerator(test_config.dbc_node, encodedPayloadsCAN);
if (!test_config.can_signals.empty()) {
// apply overwrite signal values in config.ini
for (auto& signal : test_config.can_signals) {
dbcFile.updateSignalValue(std::get<0>(signal), std::get<1>(signal), std::get<2>(signal), encodedPayloadsCAN);
}
}
}
// initialize hardware, go on bus
canfd = std::make_shared<CANFD>(dbcFile.Baudrate, dbcFile.BaudRateCANFD);
// enable real time decode
canfd->attach(monitorCAN);
// start Node simulation
sendThreadCAN = std::thread(SendCANFDEncodedPayloadsThread, canfd, std::ref(encodedPayloadsCAN));
}
else if (dbcFile.databaseBusType == BusType::CAN) {
if (!test_config.dbc_node.empty()) {
dbcFile.NodeMsgGenerator(test_config.dbc_node, encodedPayloadsCAN);
if (!test_config.can_signals.empty()) {
for (auto& signal : test_config.can_signals) {
dbcFile.updateSignalValue(std::get<0>(signal), std::get<1>(signal), std::get<2>(signal), encodedPayloadsCAN);
}
}
}
can = std::make_shared<CAN>(dbcFile.Baudrate);
can->attach(monitorCAN);
sendThreadCAN = std::thread(SendCANEncodedPayloadsThread, can, std::ref(encodedPayloadsCAN));
}
else {
std::cout << "Invalid bus type." << std::endl;
return 1;
}
}
else {
std::cout << "No dbc file provided!" << std::endl;
return 1;
}
// enable cmd interactive function
if (!test_config.dbc_file.empty() && test_config.ldf_file.empty() && dbcFile.databaseBusType == BusType::CAN_FD) {
inputThread = std::thread(CinInputThreadCAN<std::shared_ptr<CANFD>>, canfd, std::ref(dbcFile), std::ref(encodedPayloadsCAN), monitorCAN);
}
else if (!test_config.dbc_file.empty() && test_config.ldf_file.empty() && dbcFile.databaseBusType == BusType::CAN) {
inputThread = std::thread(CinInputThreadCAN<std::shared_ptr<CAN>>, can, std::ref(dbcFile), std::ref(encodedPayloadsCAN), monitorCAN);
}
if (sendThreadCAN.joinable()) {
sendThreadCAN.join();
}
if (inputThread.joinable()) {
inputThread.join();
}
system("pause");
return 0;
}
For more examples, please refer to the Documentation
- CAN, CANFD, LIN support
- Real time ECU simulation (Cntr, Chks)
- Real time payload decode
- Pre-defines paramters in config.ini
- Support cmd input to change signal values
- Logging & replay
- User interface
Distributed under the Apache-2.0 License. See LICENSE.txt
for more information.