Skip to content

Parsing message #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8895220
Update dbc.cpp and test_dbc.cpp
Murmele Jan 7, 2023
55ff2d2
implement < operator for signal to be able to sort them
Murmele Jan 7, 2023
079a46b
initial commit to parse Messages
Murmele Jan 7, 2023
339d427
Update message.hpp, dbc.cpp, and 2 more files...
Murmele Jan 7, 2023
ed42851
clear messages, otherwise when reading a second time the messages are…
Murmele Jan 8, 2023
f031db6
add comment and fix type to remove warning
Murmele Jan 8, 2023
6d26e81
use fast_float instead of std::stod, because std::stod uses locale to…
Murmele Jan 8, 2023
ea8404c
due to the error in 19caeeca4ccebadb974fe4cbaddc881c47160518 the assu…
Murmele Jan 11, 2023
e09a41c
implement parsing also std::array, because the blf library outputs th…
Murmele Jan 12, 2023
baca5f7
Merge branch 'master' into parsingMessage
Murmele Jan 12, 2023
39f8f90
install fast_float
Murmele Jan 12, 2023
80f60f4
FastFloat target must be linked so that dbc finds the headers
Murmele Jan 12, 2023
a7b9a75
download FastFloat if it was not found
Murmele Jan 16, 2023
26bb483
make compatible with 3.16, because labplot uses 3.16
Murmele Jan 18, 2023
eb12351
include current source dir
Murmele Jan 18, 2023
e2ec1de
rename test
Murmele Jan 18, 2023
25f17ce
execute docker everytime
Murmele Jan 18, 2023
3af2c0c
hack
Murmele Jan 19, 2023
d00599c
add tests
Murmele Jan 20, 2023
2fd90e0
only little endian support right now
Murmele Jan 25, 2023
deba3da
do not pass a flag to the Contructor, but create a dedicated function
Murmele Jan 25, 2023
c883074
comment not needed stuff out for now
Murmele Jan 25, 2023
876bab9
fix tests
Murmele Jan 25, 2023
ca34f24
add status flag to show which error occured
Murmele Jan 25, 2023
f7f5741
Merge remote-tracking branch 'refs/remotes/upstream/master'
Murmele Jan 28, 2023
4dc7dfe
move parsing tests to test_parseMessage.cpp
Murmele Jan 28, 2023
e9e307e
sort signals otherwise they do not match with the test results
Murmele Jan 28, 2023
c4d55af
add support for big endian
Murmele Feb 8, 2023
f65b85b
sorting not needed anymore
Murmele Feb 8, 2023
70d8510
remove comment
Murmele Feb 8, 2023
117deb6
bitstream not needed anymore
Murmele Feb 8, 2023
b7d7585
Description: add missing from start, so it only searches from there
Murmele Feb 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: install fast_float dependency
run: |
cd ${{github.workspace}}
git clone https://github.com/fastfloat/fast_float.git
mkdir fast_float/build
cd fast_float/build
cmake -DCMAKE_INSTALL_PREFIX="${{github.workspace}}/installation" ..
make install

- name: Configure CMake
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake -DFastFloat_DIR="${{github.workspace}}/installation/share/cmake/FastFloat" -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..

- name: Build
run: |
Expand Down
40 changes: 29 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
cmake_minimum_required(VERSION 3.23)
# FILE_SET needs cmake 3.23
cmake_minimum_required(VERSION 3.16)

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

Expand All @@ -21,6 +20,17 @@ include(GNUInstallDirs)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

find_package(FastFloat QUIET)
if (NOT ${FastFloat_FOUND})
include(FetchContent)
FetchContent_Declare(
FastFloat
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
GIT_TAG 1ea4f27b2aeee2859a1354a3c24cff52a116cad1
)
FetchContent_MakeAvailable(FastFloat)
endif()

set(GCC_COMPILE_FLAGS "-Wextra -Wall -Wfloat-equal -Wundef -Wshadow \
-Wpointer-arith -Wcast-align -Wstrict-prototypes -Wwrite-strings \
-Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion \
Expand Down Expand Up @@ -60,10 +70,14 @@ endif()
add_subdirectory(doc)

add_library(${PROJECT_NAME} STATIC ${SOURCE})
target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS
TYPE HEADERS
BASE_DIRS ${PROJECT_SOURCE_DIR}/include/libdbc
FILES ${HEADER_FILES})
target_link_libraries(${PROJECT_NAME} FastFloat::fast_float)

if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23)
target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS
TYPE HEADERS
BASE_DIRS ${PROJECT_SOURCE_DIR}/include/libdbc
FILES ${HEADER_FILES})
endif()

add_custom_target(release
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
Expand All @@ -76,11 +90,15 @@ install(TARGETS ${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR})

# install headers
install(TARGETS ${PROJECT_NAME}
FILE_SET HEADERS
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lib${PROJECT_NAME}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23)
install(TARGETS ${PROJECT_NAME}
FILE_SET HEADERS
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lib${PROJECT_NAME}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
else()
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/libdbc DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endif()

# Generate pkg-config file
configure_file(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
Expand Down
1 change: 1 addition & 0 deletions doc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ if(BUILD_DOCUMENTATION)
configure_file(${doxyfile_in} ${doxyfile} @ONLY)

add_custom_target(doc
ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
Expand Down
4 changes: 3 additions & 1 deletion include/libdbc/dbc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace libdbc {

class DbcParser : public Parser {
public:
DbcParser();
DbcParser();

virtual ~DbcParser() = default;

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

Message::ParseSignalsStatus parseMessage(const uint32_t id, const std::vector<uint8_t>& data, std::vector<double>& out_values);

private:
std::string version;
std::vector<std::string> nodes;
Expand Down
38 changes: 31 additions & 7 deletions include/libdbc/message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,45 @@

#include <string>
#include <vector>
#include <array>
#include <iostream>
#include <libdbc/signal.hpp>

namespace libdbc {
struct Message {
uint32_t id;
std::string name;
uint8_t size;
std::string node;
std::vector<Signal> signals;

Message() = delete;
explicit Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node);

virtual bool operator==(const Message& rhs) const;
enum class ParseSignalsStatus {
Success,
ErrorMessageToLong,
ErrorBigEndian,
ErrorUnknownID,
ErrorInvalidConversion,
};

/*!
* \brief parseSignals
* \param data
* \param values
* \return
*/
ParseSignalsStatus parseSignals(const std::vector<uint8_t>& data, std::vector<double> &values) const;

void appendSignal(const Signal& signal);
const std::vector<Signal> signals() const;
uint32_t id() const;

virtual bool operator==(const Message& rhs) const;

private:
uint32_t m_id;
std::string m_name;
uint8_t m_size;
std::string m_node;
std::vector<Signal> m_signals;

friend std::ostream& operator<<(std::ostream& os, const Message& dt);
};

std::ostream& operator<< (std::ostream &out, const Message& msg);
Expand Down
1 change: 1 addition & 0 deletions include/libdbc/signal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace libdbc {
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);

virtual bool operator==(const Signal& rhs) const;
bool operator< (const Signal& rhs) const;
};

std::ostream& operator<< (std::ostream &out, const Signal& sig);
Expand Down
33 changes: 23 additions & 10 deletions src/dbc.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <libdbc/exceptions/error.hpp>
#include <libdbc/utils/utils.hpp>
#include <libdbc/dbc.hpp>
#include <fast_float/fast_float.h>

#include <regex>

Expand Down Expand Up @@ -28,12 +29,12 @@ const auto whiteSpace = "\\s";

namespace libdbc {

DbcParser::DbcParser() : version(""), nodes(),
DbcParser::DbcParser() : version(""), nodes(),
version_re("^(VERSION)\\s\"(.*)\""), bit_timing_re("^(BS_:)"),
name_space_re("^(NS_)\\s\\:"), node_re("^(BU_:)\\s((?:[\\w]+?\\s?)*)"),
message_re("^(BO_)\\s(\\d+)\\s(\\w+)\\:\\s(\\d+)\\s(\\w+|Vector__XXX)"),
// NOTE: No multiplex support yet
signal_re(std::string(whiteSpace) +
signal_re(std::string("^") + whiteSpace +
signalIdentifierPattern +
whiteSpace +
namePattern +
Expand All @@ -57,11 +58,13 @@ namespace libdbc {

}

void DbcParser::parse_file(const std::string& file) {
void DbcParser::parse_file(const std::string& file) {
std::ifstream s(file.c_str());
std::string line;
std::vector<std::string> lines;

messages.clear();

parse_dbc_header(s);

parse_dbc_nodes(s);
Expand All @@ -71,8 +74,7 @@ namespace libdbc {
lines.push_back(line);
}

parse_dbc_messages(lines);

parse_dbc_messages(lines);
}

std::string DbcParser::get_version() const {
Expand All @@ -87,6 +89,13 @@ namespace libdbc {
return messages;
}

Message::ParseSignalsStatus DbcParser::parseMessage(const uint32_t id, const std::vector<uint8_t>& data, std::vector<double>& out_values) {
for (const auto& message: messages) {
if (message.id() == id)
return message.parseSignals(data, out_values);
}
return Message::ParseSignalsStatus::ErrorUnknownID;
}

void DbcParser::parse_dbc_header(std::istream& file_stream) {
std::string line;
Expand Down Expand Up @@ -150,17 +159,21 @@ namespace libdbc {
bool is_bigendian = (std::stoul(match.str(5)) == 0);
bool is_signed = (match.str(6) == "-");
// Alternate groups because a group is for the decimal portion
double factor = std::stod(match.str(7));
double offset = std::stod(match.str(9));
double min = std::stod(match.str(11));
double max = std::stod(match.str(13));
double factor;
fast_float::from_chars(match.str(7).data(), match.str(7).data() + match.str(7).size(), factor);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i commented on the bitstream but do we need this library as well? If this gets you going I am good with it. I might come back and rework it out if the single header fails with the new libraries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the problem is you have to convert the values to a double, but std::stod considers localization. I did not find another way, and this library is way faster than the std lib, and is only a single header

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah gotcha. I didn't realize that #8 mattered with this. Learned something new on that.

double offset;
fast_float::from_chars(match.str(9).data(), match.str(9).data() + match.str(9).size(), offset);
double min;
fast_float::from_chars(match.str(11).data(), match.str(11).data() + match.str(11).size(), min);
double max;
fast_float::from_chars(match.str(13).data(), match.str(13).data() + match.str(13).size(), max);
std::string unit = match.str(15);

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

Signal sig(name, is_multiplexed, start_bit, size, is_bigendian, is_signed, factor, offset, min, max, unit, receivers);
messages.back().signals.push_back(sig);
messages.back().appendSignal(sig);
}
}

Expand Down
74 changes: 64 additions & 10 deletions src/message.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,73 @@
#include <algorithm>
#include <libdbc/message.hpp>

namespace libdbc {
Message::Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node) :
id(id), name(name), size(size), node(node) {}
m_id(id), m_name(name), m_size(size), m_node(node) {}

bool Message::operator==(const Message& rhs) const {
return (this->id == rhs.id) && (this->name == rhs.name) &&
(this->size == rhs.size) && (this->node == rhs.node);
}
return (m_id == rhs.id()) && (m_name == rhs.m_name) &&
(m_size == rhs.m_size) && (m_node == rhs.m_node);
}

Message::ParseSignalsStatus Message::parseSignals(const std::vector<uint8_t>& data, std::vector<double>& values) const {
int size = data.size();
if (size > 8)
return ParseSignalsStatus::ErrorMessageToLong; // not supported yet

uint64_t data_little_endian = 0;
uint64_t data_big_endian = 0;
for (int i=0; i < size; i++) {
data_little_endian |= ((uint64_t)data[i]) << i * 8;
data_big_endian = (data_big_endian << 8) | (uint64_t)data[i];
}

// TODO: does this also work on a big endian machine?

const uint32_t len = size * 8;
uint64_t v = 0;
for (const auto& signal: m_signals) {
if (signal.is_bigendian) {
uint32_t start_bit = 8* (signal.start_bit / 8) + (7 - (signal.start_bit % 8)); // Calculation taken from python CAN
v = data_big_endian << start_bit;
v = v >> (len - signal.size);
} else {
const uint32_t shiftLeft = (len - (signal.size + signal.start_bit));
v = data_little_endian << shiftLeft;
v = v >> (shiftLeft + signal.start_bit);
}

if (signal.is_signed && signal.size > 1) {
switch (signal.size) {
case 8: values.push_back((int8_t)v * signal.factor + signal.offset); break;
case 16: values.push_back((int16_t)v * signal.factor + signal.offset); break;
case 32: values.push_back((int32_t)v * signal.factor + signal.offset); break;
case 64: values.push_back((int64_t)v * signal.factor + signal.offset); break;
default: return ParseSignalsStatus::ErrorInvalidConversion;
}
} else
values.push_back(v * signal.factor + signal.offset);
}
return ParseSignalsStatus::Success;
}

void Message::appendSignal(const Signal& signal) {
m_signals.push_back(signal);
}

const std::vector<Signal> Message::signals() const {
return m_signals;
}

uint32_t Message::id() const {
return m_id;
}

std::ostream& operator<< (std::ostream &out, const Message& msg) {
out << "Message: {id: " << msg.id << ", ";
out << "name: " << msg.name << ", ";
out << "size: " << msg.size << ", ";
out << "node: " << msg.node << "}";
std::ostream& operator<< (std::ostream &out, const Message& msg) {
out << "Message: {id: " << msg.id() << ", ";
out << "name: " << msg.m_name << ", ";
out << "size: " << msg.m_size << ", ";
out << "node: " << msg.m_node << "}";
return out;
}
}
}
3 changes: 3 additions & 0 deletions src/signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ namespace libdbc {
(this->unit == rhs.unit) && (this->receivers == rhs.receivers);
}

bool Signal::operator< (const Signal& rhs) const {
return start_bit < rhs.start_bit;
}

std::ostream& operator<< (std::ostream &out, const Signal& sig) {
out << "Signal {name: " << sig.name << ", ";
Expand Down
2 changes: 1 addition & 1 deletion src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ namespace utils {
return start == end ? std::string() : line.substr(start, end - start + 1);
}

} // Namespace Utils
} // Namespace Utils
Loading