Skip to content

Commit 676da12

Browse files
authored
Merge pull request #12 from Murmele/parsingMessage
Parsing message
2 parents ffa6ac9 + b7d7585 commit 676da12

File tree

19 files changed

+1175
-77
lines changed

19 files changed

+1175
-77
lines changed

.github/workflows/tests.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,20 @@ jobs:
1616
steps:
1717
- uses: actions/checkout@v3
1818

19+
- name: install fast_float dependency
20+
run: |
21+
cd ${{github.workspace}}
22+
git clone https://github.com/fastfloat/fast_float.git
23+
mkdir fast_float/build
24+
cd fast_float/build
25+
cmake -DCMAKE_INSTALL_PREFIX="${{github.workspace}}/installation" ..
26+
make install
27+
1928
- name: Configure CMake
2029
run: |
2130
mkdir build
2231
cd build
23-
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
32+
cmake -DFastFloat_DIR="${{github.workspace}}/installation/share/cmake/FastFloat" -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
2433
2534
- name: Build
2635
run: |

CMakeLists.txt

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
cmake_minimum_required(VERSION 3.23)
2-
# FILE_SET needs cmake 3.23
1+
cmake_minimum_required(VERSION 3.16)
32

43
project(dbc VERSION 0.1.1 DESCRIPTION "C++ DBC Parser")
54

@@ -21,6 +20,17 @@ include(GNUInstallDirs)
2120
set(CMAKE_CXX_STANDARD 11)
2221
set(CMAKE_CXX_STANDARD_REQUIRED True)
2322

23+
find_package(FastFloat QUIET)
24+
if (NOT ${FastFloat_FOUND})
25+
include(FetchContent)
26+
FetchContent_Declare(
27+
FastFloat
28+
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
29+
GIT_TAG 1ea4f27b2aeee2859a1354a3c24cff52a116cad1
30+
)
31+
FetchContent_MakeAvailable(FastFloat)
32+
endif()
33+
2434
set(GCC_COMPILE_FLAGS "-Wextra -Wall -Wfloat-equal -Wundef -Wshadow \
2535
-Wpointer-arith -Wcast-align -Wstrict-prototypes -Wwrite-strings \
2636
-Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion \
@@ -60,10 +70,14 @@ endif()
6070
add_subdirectory(doc)
6171

6272
add_library(${PROJECT_NAME} STATIC ${SOURCE})
63-
target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS
64-
TYPE HEADERS
65-
BASE_DIRS ${PROJECT_SOURCE_DIR}/include/libdbc
66-
FILES ${HEADER_FILES})
73+
target_link_libraries(${PROJECT_NAME} FastFloat::fast_float)
74+
75+
if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23)
76+
target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS
77+
TYPE HEADERS
78+
BASE_DIRS ${PROJECT_SOURCE_DIR}/include/libdbc
79+
FILES ${HEADER_FILES})
80+
endif()
6781

6882
add_custom_target(release
6983
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
@@ -76,11 +90,15 @@ install(TARGETS ${PROJECT_NAME}
7690
DESTINATION ${CMAKE_INSTALL_LIBDIR})
7791

7892
# install headers
79-
install(TARGETS ${PROJECT_NAME}
80-
FILE_SET HEADERS
81-
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lib${PROJECT_NAME}
82-
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
83-
)
93+
if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23)
94+
install(TARGETS ${PROJECT_NAME}
95+
FILE_SET HEADERS
96+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lib${PROJECT_NAME}
97+
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
98+
)
99+
else()
100+
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/libdbc DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
101+
endif()
84102

85103
# Generate pkg-config file
86104
configure_file(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)

doc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ if(BUILD_DOCUMENTATION)
1313
configure_file(${doxyfile_in} ${doxyfile} @ONLY)
1414

1515
add_custom_target(doc
16+
ALL
1617
COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
1718
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
1819
COMMENT "Generating API documentation with Doxygen"

include/libdbc/dbc.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace libdbc {
2424

2525
class DbcParser : public Parser {
2626
public:
27-
DbcParser();
27+
DbcParser();
2828

2929
virtual ~DbcParser() = default;
3030

@@ -34,6 +34,8 @@ namespace libdbc {
3434
std::vector<std::string> get_nodes() const;
3535
std::vector<libdbc::Message> get_messages() const;
3636

37+
Message::ParseSignalsStatus parseMessage(const uint32_t id, const std::vector<uint8_t>& data, std::vector<double>& out_values);
38+
3739
private:
3840
std::string version;
3941
std::vector<std::string> nodes;

include/libdbc/message.hpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,45 @@
33

44
#include <string>
55
#include <vector>
6+
#include <array>
67
#include <iostream>
78
#include <libdbc/signal.hpp>
89

910
namespace libdbc {
1011
struct Message {
11-
uint32_t id;
12-
std::string name;
13-
uint8_t size;
14-
std::string node;
15-
std::vector<Signal> signals;
16-
1712
Message() = delete;
1813
explicit Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node);
1914

20-
virtual bool operator==(const Message& rhs) const;
15+
enum class ParseSignalsStatus {
16+
Success,
17+
ErrorMessageToLong,
18+
ErrorBigEndian,
19+
ErrorUnknownID,
20+
ErrorInvalidConversion,
21+
};
22+
23+
/*!
24+
* \brief parseSignals
25+
* \param data
26+
* \param values
27+
* \return
28+
*/
29+
ParseSignalsStatus parseSignals(const std::vector<uint8_t>& data, std::vector<double> &values) const;
30+
31+
void appendSignal(const Signal& signal);
32+
const std::vector<Signal> signals() const;
33+
uint32_t id() const;
34+
35+
virtual bool operator==(const Message& rhs) const;
36+
37+
private:
38+
uint32_t m_id;
39+
std::string m_name;
40+
uint8_t m_size;
41+
std::string m_node;
42+
std::vector<Signal> m_signals;
43+
44+
friend std::ostream& operator<<(std::ostream& os, const Message& dt);
2145
};
2246

2347
std::ostream& operator<< (std::ostream &out, const Message& msg);

include/libdbc/signal.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace libdbc {
2525
explicit Signal(std::string name, bool is_multiplexed, uint32_t start_bit, uint32_t size, bool is_bigendian, bool is_signed, double factor, double offset, double min, double max, std::string unit, std::vector<std::string> recievers);
2626

2727
virtual bool operator==(const Signal& rhs) const;
28+
bool operator< (const Signal& rhs) const;
2829
};
2930

3031
std::ostream& operator<< (std::ostream &out, const Signal& sig);

src/dbc.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <libdbc/exceptions/error.hpp>
22
#include <libdbc/utils/utils.hpp>
33
#include <libdbc/dbc.hpp>
4+
#include <fast_float/fast_float.h>
45

56
#include <regex>
67

@@ -28,12 +29,12 @@ const auto whiteSpace = "\\s";
2829

2930
namespace libdbc {
3031

31-
DbcParser::DbcParser() : version(""), nodes(),
32+
DbcParser::DbcParser() : version(""), nodes(),
3233
version_re("^(VERSION)\\s\"(.*)\""), bit_timing_re("^(BS_:)"),
3334
name_space_re("^(NS_)\\s\\:"), node_re("^(BU_:)\\s((?:[\\w]+?\\s?)*)"),
3435
message_re("^(BO_)\\s(\\d+)\\s(\\w+)\\:\\s(\\d+)\\s(\\w+|Vector__XXX)"),
3536
// NOTE: No multiplex support yet
36-
signal_re(std::string(whiteSpace) +
37+
signal_re(std::string("^") + whiteSpace +
3738
signalIdentifierPattern +
3839
whiteSpace +
3940
namePattern +
@@ -57,11 +58,13 @@ namespace libdbc {
5758

5859
}
5960

60-
void DbcParser::parse_file(const std::string& file) {
61+
void DbcParser::parse_file(const std::string& file) {
6162
std::ifstream s(file.c_str());
6263
std::string line;
6364
std::vector<std::string> lines;
6465

66+
messages.clear();
67+
6568
parse_dbc_header(s);
6669

6770
parse_dbc_nodes(s);
@@ -71,8 +74,7 @@ namespace libdbc {
7174
lines.push_back(line);
7275
}
7376

74-
parse_dbc_messages(lines);
75-
77+
parse_dbc_messages(lines);
7678
}
7779

7880
std::string DbcParser::get_version() const {
@@ -87,6 +89,13 @@ namespace libdbc {
8789
return messages;
8890
}
8991

92+
Message::ParseSignalsStatus DbcParser::parseMessage(const uint32_t id, const std::vector<uint8_t>& data, std::vector<double>& out_values) {
93+
for (const auto& message: messages) {
94+
if (message.id() == id)
95+
return message.parseSignals(data, out_values);
96+
}
97+
return Message::ParseSignalsStatus::ErrorUnknownID;
98+
}
9099

91100
void DbcParser::parse_dbc_header(std::istream& file_stream) {
92101
std::string line;
@@ -150,17 +159,21 @@ namespace libdbc {
150159
bool is_bigendian = (std::stoul(match.str(5)) == 0);
151160
bool is_signed = (match.str(6) == "-");
152161
// Alternate groups because a group is for the decimal portion
153-
double factor = std::stod(match.str(7));
154-
double offset = std::stod(match.str(9));
155-
double min = std::stod(match.str(11));
156-
double max = std::stod(match.str(13));
162+
double factor;
163+
fast_float::from_chars(match.str(7).data(), match.str(7).data() + match.str(7).size(), factor);
164+
double offset;
165+
fast_float::from_chars(match.str(9).data(), match.str(9).data() + match.str(9).size(), offset);
166+
double min;
167+
fast_float::from_chars(match.str(11).data(), match.str(11).data() + match.str(11).size(), min);
168+
double max;
169+
fast_float::from_chars(match.str(13).data(), match.str(13).data() + match.str(13).size(), max);
157170
std::string unit = match.str(15);
158171

159172
std::vector<std::string> receivers;
160173
utils::String::split(match.str(16), receivers, ',');
161174

162175
Signal sig(name, is_multiplexed, start_bit, size, is_bigendian, is_signed, factor, offset, min, max, unit, receivers);
163-
messages.back().signals.push_back(sig);
176+
messages.back().appendSignal(sig);
164177
}
165178
}
166179

src/message.cpp

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,73 @@
1+
#include <algorithm>
12
#include <libdbc/message.hpp>
23

34
namespace libdbc {
45
Message::Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node) :
5-
id(id), name(name), size(size), node(node) {}
6+
m_id(id), m_name(name), m_size(size), m_node(node) {}
67

78
bool Message::operator==(const Message& rhs) const {
8-
return (this->id == rhs.id) && (this->name == rhs.name) &&
9-
(this->size == rhs.size) && (this->node == rhs.node);
10-
}
9+
return (m_id == rhs.id()) && (m_name == rhs.m_name) &&
10+
(m_size == rhs.m_size) && (m_node == rhs.m_node);
11+
}
12+
13+
Message::ParseSignalsStatus Message::parseSignals(const std::vector<uint8_t>& data, std::vector<double>& values) const {
14+
int size = data.size();
15+
if (size > 8)
16+
return ParseSignalsStatus::ErrorMessageToLong; // not supported yet
17+
18+
uint64_t data_little_endian = 0;
19+
uint64_t data_big_endian = 0;
20+
for (int i=0; i < size; i++) {
21+
data_little_endian |= ((uint64_t)data[i]) << i * 8;
22+
data_big_endian = (data_big_endian << 8) | (uint64_t)data[i];
23+
}
24+
25+
// TODO: does this also work on a big endian machine?
26+
27+
const uint32_t len = size * 8;
28+
uint64_t v = 0;
29+
for (const auto& signal: m_signals) {
30+
if (signal.is_bigendian) {
31+
uint32_t start_bit = 8* (signal.start_bit / 8) + (7 - (signal.start_bit % 8)); // Calculation taken from python CAN
32+
v = data_big_endian << start_bit;
33+
v = v >> (len - signal.size);
34+
} else {
35+
const uint32_t shiftLeft = (len - (signal.size + signal.start_bit));
36+
v = data_little_endian << shiftLeft;
37+
v = v >> (shiftLeft + signal.start_bit);
38+
}
39+
40+
if (signal.is_signed && signal.size > 1) {
41+
switch (signal.size) {
42+
case 8: values.push_back((int8_t)v * signal.factor + signal.offset); break;
43+
case 16: values.push_back((int16_t)v * signal.factor + signal.offset); break;
44+
case 32: values.push_back((int32_t)v * signal.factor + signal.offset); break;
45+
case 64: values.push_back((int64_t)v * signal.factor + signal.offset); break;
46+
default: return ParseSignalsStatus::ErrorInvalidConversion;
47+
}
48+
} else
49+
values.push_back(v * signal.factor + signal.offset);
50+
}
51+
return ParseSignalsStatus::Success;
52+
}
53+
54+
void Message::appendSignal(const Signal& signal) {
55+
m_signals.push_back(signal);
56+
}
57+
58+
const std::vector<Signal> Message::signals() const {
59+
return m_signals;
60+
}
61+
62+
uint32_t Message::id() const {
63+
return m_id;
64+
}
1165

12-
std::ostream& operator<< (std::ostream &out, const Message& msg) {
13-
out << "Message: {id: " << msg.id << ", ";
14-
out << "name: " << msg.name << ", ";
15-
out << "size: " << msg.size << ", ";
16-
out << "node: " << msg.node << "}";
66+
std::ostream& operator<< (std::ostream &out, const Message& msg) {
67+
out << "Message: {id: " << msg.id() << ", ";
68+
out << "name: " << msg.m_name << ", ";
69+
out << "size: " << msg.m_size << ", ";
70+
out << "node: " << msg.m_node << "}";
1771
return out;
1872
}
19-
}
73+
}

src/signal.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ namespace libdbc {
1212
(this->unit == rhs.unit) && (this->receivers == rhs.receivers);
1313
}
1414

15+
bool Signal::operator< (const Signal& rhs) const {
16+
return start_bit < rhs.start_bit;
17+
}
1518

1619
std::ostream& operator<< (std::ostream &out, const Signal& sig) {
1720
out << "Signal {name: " << sig.name << ", ";

src/utils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@ namespace utils {
7272
return start == end ? std::string() : line.substr(start, end - start + 1);
7373
}
7474

75-
} // Namespace Utils
75+
} // Namespace Utils

0 commit comments

Comments
 (0)