A C/C++ DBC file parser based on boost.spirit
. This library is designed for decoding performance.
- very fast decoding
- verbose parser output in error case
- DBC is editable through C/C++ interface exported from the library
- read/write DBC file
- decode functionality for frames of arbitrarily byte length
- cantools like decoding
- KCD file format support
- version
- new_symbols
- bit_timing
- nodes
- value_tables
- messages
- message_transmitters
- environment_variables
- environment_variables_data
- signal_types
- comments
- attribute_definitions
- attribute_defaults
- attribute_values
- value_descriptions
- signal_extended_value_type_list
- sigtype_attr_list
- signal_type_refs
- signal_groups
- boost
- libxml2
git clone https://github.com/xR3b0rn/dbcppp.git
cd dbcppp
mkdir build
cd build
cmake ..
make -j
make RunTests
make install
# generate C source from DBC/KCD
dbcppp dbc2 --dbc=file.dbc --format=C
# beauty or merge DBC/KCD
dbcppp dbc2 --dbc=file1.dbc --dbc=file2.kcd --format=DBC
# print DBC/KCD in human readable format
dbcppp dbc2 --dbc=file1.dbc --dbc=file2.kcd --format=human
cantools like decoding:
candump any | dbcppp decode --bus=vcan0,file1.dbc --bus=vcan1,file2.dbc
- Examples
C++
#include <fstream>
#include <dbcppp/Network.h>
int main()
{
std::ifstream dbc_file{"your_dbc.dbc"};
std::unique_ptr<dbcppp::Network> net = dbcppp::Network::fromDBC(dbc_file);
if (net)
{
can_frame frame;
while (1)
{
receive_can_frame_from_somewhere(&frame);
const Message* msg = net->getMessageById(frame.id);
if (msg)
{
std::cout << "Received message: " << msg->getName() << std::endl;
msg->forEachSignal(
[&](const Signal& signal)
{
uint64_t raw = signal.decode(frame.data);
std::cout << "\t" << signal.getName() << "=" << signal.rawToPhys(raw) << std::endl;
});
}
}
}
}
C
#include <stdio.h>
#include <dbcppp/CApi.h>
int main()
{
const dbcppp_Nework* net = dbcppp_NetworkLoadDBCFromFile("your_dbc.dbc");
if (net)
{
can_frame frame;
while (1)
{
receive_can_frame_from_somewhere(&frame);
const dbcppp_Message* msg = dbcppp_NetworkGetMessageById(net, frame.id);
if (msg)
{
printf("Received message: %s\n", dbcppp_MessageGetName(msg));
void print_signal_data(const dbcppp_Signal* sig, void* data)
{
can_frame* frame = (can_frame*)data;
uint64_t raw = dbcppp_SignalDecode(sig, frame->data);
double phys = dbcppp_SignalRawToPhys(sig, raw);
printf("\t%s=%f\n", dbcppp_SignalGetName(sig), phys);
}
dbcppp_MessageForEachSignal(msg, print_signal_data, &frame);
}
}
}
}
The signals decode function is using prestored masks and fixed offsets to speed up calculation, therefore the decoding-function should be almost as fast as a code generated decode function would be. The assembly of the decode
-function on its critical path (signed and byte swap must happen) looks like this (VS19 10.0.18362.0 compiler):
template <Alignment aAlignment, Signal::ByteOrder aByteOrder, Signal::ValueType aValueType, Signal::ExtendedValueType aExtendedValueType>
double template_decode(const Signal* sig, const void* nbytes) noexcept
00007FF8025BCA73 mov rax,rcx
00007FF8025BCA76 mov rcx,qword ptr [rcx+140h]
00007FF8025BCA7D xorps xmm0,xmm0
00007FF8025BCA80 bswap r8
00007FF8025BCA83 shr r8,cl
00007FF8025BCA86 and r8,qword ptr [rax+130h]
00007FF8025BCA8D mov rcx,qword ptr [rax+138h]
00007FF8025BCA94 mov rax,rcx
00007FF8025BCA97 or rcx,r8
00007FF8025BCA9A and rax,r8
00007FF8025BCA9D cmove rcx,r8
00007FF8025BCAA1 cvtsi2sd xmm0,rcx
00007FF8025BCAA6 ret
On the best path (no byteswap must take place and ExtendedValueType == Double) the decode function only has 5 instructions:
template <Alignment aAlignment, Signal::ByteOrder aByteOrder, Signal::ValueType aValueType, Signal::ExtendedValueType aExtendedValueType>
double template_decode(const Signal* sig, const void* nbytes) noexcept
00007FF8025BCAF0 mov rax,qword ptr [rdx]
00007FF8025BCAF3 mov qword ptr [rsp+8],rcx
00007FF8025BCAF8 mov qword ptr [sig],rax
00007FF8025BCAFD movsd xmm0,mmword ptr [data]
00007FF8025BCB03 ret
- tests for decoding function for float/double is failing on some maschines (currently only confirmed for System/s390x)
- Vector_DBC Does basically the same, the biggest difference is that it uses
bison
instead ofboost::spirit
for grammar parsing - CAN BUS tools in Python 3 (cantools)