From 889522069f447e949b72e666b47f3c0d08e12563 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 7 Jan 2023 18:38:42 +0100 Subject: [PATCH 01/30] Update dbc.cpp and test_dbc.cpp --- src/dbc.cpp | 2 +- test/test_dbc.cpp | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/dbc.cpp b/src/dbc.cpp index bb21845..905f237 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -147,7 +147,7 @@ namespace libdbc { bool is_multiplexed = false; // No support yet uint32_t start_bit = std::stoul(match.str(3)); uint32_t size = std::stoul(match.str(4)); - bool is_bigendian = (std::stoul(match.str(5)) == 1); + 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)); diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index 4ad0c8e..83bc3d7 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -44,7 +44,7 @@ TEST_CASE("Testing dbc file loading", "[fileio]") { libdbc::Message msg(500, "IO_DEBUG", 4, "IO"); std::vector receivers{"DBG"}; - libdbc::Signal sig("IO_DEBUG_test_unsigned", false, 0, 8, true, false, 1, 0, 0, 0, "", receivers); + libdbc::Signal sig("IO_DEBUG_test_unsigned", false, 0, 8, false, false, 1, 0, 0, 0, "", receivers); msg.signals.push_back(sig); std::vector msgs = {msg}; @@ -62,6 +62,35 @@ TEST_CASE("Testing dbc file loading", "[fileio]") { } +TEST_CASE("Testing big endian, little endian") { + const auto* filename = std::tmpnam(NULL); + + auto* file = std::fopen(filename, "w"); + CHECK(file); + + std::fputs(PRIMITIVE_DBC.c_str(), file); + // first big endian + // second little endian + std::fputs(R"(BO_ 234 MSG1: 8 Vector__XXX + SG_ Sig1 : 55|16@0- (0.1,0) [-3276.8|-3276.7] "C" Vector__XXX + SG_ Sig2 : 39|16@1- (0.1,0) [-3276.8|-3276.7] "C" Vector__XXX)", file); + std::fclose(file); + + auto parser = libdbc::DbcParser(); + parser.parse_file(filename); + + REQUIRE(parser.get_messages().size() == 1); + REQUIRE(parser.get_messages().at(0).signals.size() == 2); + { + const auto signal = parser.get_messages().at(0).signals.at(0); + REQUIRE(signal.is_bigendian == true); + } + { + const auto signal = parser.get_messages().at(0).signals.at(1); + REQUIRE(signal.is_bigendian == false); + } +} + TEST_CASE("Testing negative values") { const auto* filename = std::tmpnam(NULL); From 55ff2d2dae8ac3d6ad74b089a284c9257716ee33 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 7 Jan 2023 19:09:58 +0100 Subject: [PATCH 02/30] implement < operator for signal to be able to sort them --- include/libdbc/signal.hpp | 1 + src/signal.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/libdbc/signal.hpp b/include/libdbc/signal.hpp index 085994e..2252700 100644 --- a/include/libdbc/signal.hpp +++ b/include/libdbc/signal.hpp @@ -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 recievers); virtual bool operator==(const Signal& rhs) const; + bool operator< (const Signal& rhs) const; }; std::ostream& operator<< (std::ostream &out, const Signal& sig); diff --git a/src/signal.cpp b/src/signal.cpp index 1124fc3..0aa79e9 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -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 << ", "; From 079a46b1314a0448e45da6ecacb1e075736ce3a0 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 7 Jan 2023 19:14:10 +0100 Subject: [PATCH 03/30] initial commit to parse Messages --- CMakeLists.txt | 3 + include/libdbc/dbc.hpp | 6 +- include/libdbc/message.hpp | 21 +- src/dbc.cpp | 18 +- src/message.cpp | 149 ++++++- test/test_dbc.cpp | 62 ++- third_party/bitstream/CMakeLists.txt | 10 + third_party/bitstream/Readme.md | 2 + third_party/bitstream/bitstream.c | 608 +++++++++++++++++++++++++++ third_party/bitstream/bitstream.h | 178 ++++++++ 10 files changed, 1048 insertions(+), 9 deletions(-) create mode 100644 third_party/bitstream/CMakeLists.txt create mode 100644 third_party/bitstream/Readme.md create mode 100644 third_party/bitstream/bitstream.c create mode 100644 third_party/bitstream/bitstream.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 40b1f8c..a4c4068 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,8 @@ list(APPEND SOURCE ${PROJECT_SOURCE_DIR}/src/utils.cpp ${PROJECT_SOURCE_DIR}/src/signal.cpp ${PROJECT_SOURCE_DIR}/src/dbc.cpp) +add_subdirectory(third_party/bitstream) + include_directories(src) include_directories(include) @@ -40,6 +42,7 @@ endif() add_subdirectory(doc) add_library(${PROJECT_NAME} STATIC ${SOURCE}) +target_link_libraries(${PROJECT_NAME} bitstream) add_custom_target(release WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} diff --git a/include/libdbc/dbc.hpp b/include/libdbc/dbc.hpp index 8b3c0cf..8a34ed6 100644 --- a/include/libdbc/dbc.hpp +++ b/include/libdbc/dbc.hpp @@ -24,7 +24,7 @@ namespace libdbc { class DbcParser : public Parser { public: - DbcParser(); + DbcParser(bool sortSignals = false); virtual ~DbcParser() = default; @@ -34,6 +34,8 @@ namespace libdbc { std::vector get_nodes() const; std::vector get_messages() const; + bool parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values); + private: std::string version; std::vector nodes; @@ -46,6 +48,8 @@ namespace libdbc { const std::regex message_re; const std::regex signal_re; + bool sortSignals{false}; + void parse_dbc_header(std::istream& file_stream); void parse_dbc_nodes(std::istream& file_stream); void parse_dbc_messages(const std::vector& lines); diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index 37d021b..872ecf5 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -17,7 +17,26 @@ namespace libdbc { 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; + bool parseSignals(const std::vector data, std::vector &values) const; + + /*! + * \brief prepareMessage + * Preparing message to be able to parse signals afterwards. This speeds up parsing + */ + void prepareMessage(); + + virtual bool operator==(const Message& rhs) const; + + private: + bool prepared{false}; // indicates if the message is prepared for parsing signals + struct BitStruct { + BitStruct(const std::string& name, uint32_t size, bool padding): name(name), size(size), padding(padding) {} + BitStruct() = delete; + std::string name; + uint32_t size; + bool padding; + }; + std::vector bitstruct; }; std::ostream& operator<< (std::ostream &out, const Message& msg); diff --git a/src/dbc.cpp b/src/dbc.cpp index 905f237..2711d19 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -28,7 +28,7 @@ const auto whiteSpace = "\\s"; namespace libdbc { - DbcParser::DbcParser() : version(""), nodes(), + DbcParser::DbcParser(bool sortSignals) : 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)"), @@ -53,7 +53,8 @@ namespace libdbc { whiteSpace + unitPattern + whiteSpace + - receiverPattern) { + receiverPattern), + sortSignals(sortSignals) { } @@ -73,6 +74,11 @@ namespace libdbc { parse_dbc_messages(lines); + if (sortSignals) { + for (auto& message: messages) { + message.prepareMessage(); + } + } } std::string DbcParser::get_version() const { @@ -87,6 +93,14 @@ namespace libdbc { return messages; } + bool DbcParser::parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values) { + for (const auto& message: messages) { + if (message.id == id) + return message.parseSignals(data, out_values); + } + return false; + } + void DbcParser::parse_dbc_header(std::istream& file_stream) { std::string line; diff --git a/src/message.cpp b/src/message.cpp index 35956f6..9e5e3aa 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -1,5 +1,8 @@ +#include #include +#include + 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) {} @@ -7,7 +10,149 @@ namespace libdbc { bool Message::operator==(const Message& rhs) const { return (this->id == rhs.id) && (this->name == rhs.name) && (this->size == rhs.size) && (this->node == rhs.node); - } + } + + bool Message::parseSignals(const std::vector data, std::vector& values) const { + if (!prepared) + return false; + + bitstream_reader_t reader; + bitstream_reader_init(&reader, data.data()); + + double v; + for (const auto& bs: bitstruct) { + if (bs.padding) { + for (uint32_t i=0; i < bs.size; i++) + bitstream_reader_read_bit(&reader); + } else { + for(const auto& signal: signals) { + if (bs.name.compare(signal.name) != 0) { + continue; + } + + if (signal.is_bigendian) { + + switch (bs.size) { + case 1: v = static_cast(bitstream_reader_read_bit(&reader)); break; + case 8: v = static_cast(bitstream_reader_read_u8(&reader)); break; + case 16: { + uint16_t tmp = bitstream_reader_read_u8(&reader); + tmp |= (uint16_t)bitstream_reader_read_u8(&reader) << 8; + if (signal.is_signed) + v = static_cast(static_cast(tmp)); + else + v = static_cast(tmp); + break; + } + case 32: { + uint32_t tmp = bitstream_reader_read_u8(&reader); + tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 8; + tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 16; + tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 24; + if (signal.is_signed) + v = static_cast(static_cast(tmp)); + else + v = static_cast(tmp); + break; + } + case 64: { + uint64_t tmp = bitstream_reader_read_u8(&reader); + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 8; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 16; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 24; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 32; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 40; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 48; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 56; + if (signal.is_signed) + v = static_cast(static_cast(tmp)); + else + v = static_cast(tmp); + break; + } + default: { + // TODO: implement sign? + // TODO: implement big endian + uint64_t value = 0; + for (uint32_t i=0; i < bs.size; i++) { + value |= bitstream_reader_read_bit(&reader) << i; + } + v = static_cast(value); + break; + } + } + } else { + // little endian + switch (bs.size) { + case 1: + v = static_cast(bitstream_reader_read_bit(&reader)); break; + case 8: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u8(&reader))); + else + v = static_cast(bitstream_reader_read_u8(&reader)); + break; + case 16: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u16(&reader))); + else + v = static_cast(bitstream_reader_read_u16(&reader)); + break; + case 32: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u32(&reader))); + else + v = static_cast(bitstream_reader_read_u32(&reader)); + break; + case 64: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u64(&reader))); + else + v = static_cast(bitstream_reader_read_u64(&reader)); + break; + default: { + // TODO: implement sign? + // TODO: implement big endian + uint64_t value = 0; + for (uint32_t i=0; i < bs.size; i++) { + value |= bitstream_reader_read_bit(&reader) << i; + } + v = static_cast(value); + break; + } + } + } + + values.push_back(v * signal.factor + signal.offset); + break; + } + } + } + return true; + } + + void Message::prepareMessage() { + prepared = false; + std::sort(signals.begin(), signals.end()); + + uint32_t curr_bit = 0; + for (const auto& signal: signals) { + if (signal.is_multiplexed /*|| signal.is_bigendian*/) + break; // Not supported yet + + if (curr_bit < signal.start_bit) { + // padding needed + bitstruct.push_back(BitStruct("", signal.start_bit - curr_bit, true)); + } + bitstruct.push_back(BitStruct(signal.name, signal.size, false)); + curr_bit = signal.start_bit + signal.size; + } + if (curr_bit > size * 8) + return; + + prepared = true; + + } std::ostream& operator<< (std::ostream &out, const Message& msg) { out << "Message: {id: " << msg.id << ", "; @@ -16,4 +161,4 @@ namespace libdbc { out << "node: " << msg.node << "}"; return out; } -} \ No newline at end of file +} diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index 83bc3d7..9692179 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "defines.hpp" #include @@ -101,7 +103,7 @@ TEST_CASE("Testing negative values") { SG_ Sig4 : 7|16@0- (1,-10) [0|32767] "" Vector__XXX)"); auto parser = libdbc::DbcParser(); - parser.parse_file(std::string(filename)); + parser.parse_file(filename); REQUIRE(parser.get_messages().size() == 1); REQUIRE(parser.get_messages().at(0).signals.size() == 4); @@ -136,7 +138,6 @@ TEST_CASE("Testing negative values") { } } - TEST_CASE("Special characters in unit") { const auto* filename = std::tmpnam(NULL); @@ -145,7 +146,7 @@ TEST_CASE("Special characters in unit") { auto parser = libdbc::DbcParser(); - parser.parse_file(std::string(filename)); + parser.parse_file(filename); REQUIRE(parser.get_messages().size() == 1); REQUIRE(parser.get_messages().at(0).signals.size() == 1); @@ -154,3 +155,58 @@ TEST_CASE("Special characters in unit") { REQUIRE(signal.unit.compare("Km/h") == 0); } } + +TEST_CASE("Parse Message little endian") { + const auto* filename = std::tmpnam(NULL); + + auto* file = std::fopen(filename, "w"); + CHECK(file); + + std::fputs(PRIMITIVE_DBC.c_str(), file); + std::fputs(R"(BO_ 541 STATUS: 8 DEVICE1 + SG_ Temperature : 48|16@1+ (0.01,-40) [-40|125] "C" DEVICE1 + SG_ SOH : 0|16@1+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOE : 32|16@1+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOC : 16|16@1+ (0.01,0) [0|100] "%" DEVICE1)", file); + std::fclose(file); + + libdbc::DbcParser p(true); + p.parse_file(filename); + + std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // little endian + std::vector result_values; + REQUIRE(p.parseMessage(0x21d, data, result_values) == true); + REQUIRE(result_values.size() == 4); + REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); + REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); + REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); + REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); + +} + +TEST_CASE("Parse Message big endian") { + const auto* filename = std::tmpnam(NULL); + + auto* file = std::fopen(filename, "w"); + CHECK(file); + + std::fputs(PRIMITIVE_DBC.c_str(), file); + std::fputs(R"(BO_ 541 STATUS: 8 DEVICE1 + SG_ Temperature : 48|16@0+ (0.01,-40) [-40|125] "C" DEVICE1 + SG_ SOH : 0|16@0+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOE : 32|16@0+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOC : 16|16@0+ (0.01,0) [0|100] "%" DEVICE1)", file); + std::fclose(file); + + libdbc::DbcParser p(true); + p.parse_file(filename); + + std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // big endian + std::vector result_values; + REQUIRE(p.parseMessage(0x21d, data, result_values) == true); + REQUIRE(result_values.size() == 4); + REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); + REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); + REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); + REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); +} diff --git a/third_party/bitstream/CMakeLists.txt b/third_party/bitstream/CMakeLists.txt new file mode 100644 index 0000000..87416d6 --- /dev/null +++ b/third_party/bitstream/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.23) +# FILE_SET needs cmake 3.23 + +project(bitstream) + +add_library(${PROJECT_NAME} STATIC bitstream.c) +target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS + TYPE HEADERS + BASE_DIRS ${PROJECT_SOURCE_DIR} + FILES bitstream.h) diff --git a/third_party/bitstream/Readme.md b/third_party/bitstream/Readme.md new file mode 100644 index 0000000..3704131 --- /dev/null +++ b/third_party/bitstream/Readme.md @@ -0,0 +1,2 @@ +Bitstream reader. +Files copied from https://github.com/eerimoq/bitstruct/tree/master/bitstruct diff --git a/third_party/bitstream/bitstream.c b/third_party/bitstream/bitstream.c new file mode 100644 index 0000000..cc68ed8 --- /dev/null +++ b/third_party/bitstream/bitstream.c @@ -0,0 +1,608 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2019 Erik Moqvist + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "bitstream.h" + +void bitstream_writer_init(struct bitstream_writer_t *self_p, + uint8_t *buf_p) +{ + self_p->buf_p = buf_p; + self_p->byte_offset = 0; + self_p->bit_offset = 0; +} + +int bitstream_writer_size_in_bits(struct bitstream_writer_t *self_p) +{ + return (8 * self_p->byte_offset + self_p->bit_offset); +} + +int bitstream_writer_size_in_bytes(struct bitstream_writer_t *self_p) +{ + return (self_p->byte_offset + (self_p->bit_offset + 7) / 8); +} + +void bitstream_writer_write_bit(struct bitstream_writer_t *self_p, + int value) +{ + if (self_p->bit_offset == 0) { + self_p->buf_p[self_p->byte_offset] = (value << 7); + self_p->bit_offset = 1; + } else { + self_p->buf_p[self_p->byte_offset] |= (value << (8 - self_p->bit_offset - 1)); + + if (self_p->bit_offset == 7) { + self_p->bit_offset = 0; + self_p->byte_offset++; + } else { + self_p->bit_offset++; + } + } +} + +void bitstream_writer_write_bytes(struct bitstream_writer_t *self_p, + const uint8_t *buf_p, + int length) +{ + int i; + uint8_t *dst_p; + + dst_p = &self_p->buf_p[self_p->byte_offset]; + + if (self_p->bit_offset == 0) { + memcpy(dst_p, buf_p, sizeof(uint8_t) * length); + } else { + for (i = 0; i < length; i++) { + dst_p[i] |= (buf_p[i] >> self_p->bit_offset); + dst_p[i + 1] = (uint8_t)(buf_p[i] << (8 - self_p->bit_offset)); + } + } + + self_p->byte_offset += length; +} + +void bitstream_writer_write_u8(struct bitstream_writer_t *self_p, + uint8_t value) +{ + if (self_p->bit_offset == 0) { + self_p->buf_p[self_p->byte_offset] = value; + } else { + self_p->buf_p[self_p->byte_offset] |= (value >> self_p->bit_offset); + self_p->buf_p[self_p->byte_offset + 1] = + (uint8_t)(value << (8 - self_p->bit_offset)); + } + + self_p->byte_offset++; +} + +void bitstream_writer_write_u16(struct bitstream_writer_t *self_p, + uint16_t value) +{ + if (self_p->bit_offset == 0) { + self_p->buf_p[self_p->byte_offset] = (value >> 8); + } else { + self_p->buf_p[self_p->byte_offset] |= (value >> (8 + self_p->bit_offset)); + self_p->buf_p[self_p->byte_offset + 2] = + (uint8_t)(value << (8 - self_p->bit_offset)); + value >>= self_p->bit_offset; + } + + self_p->buf_p[self_p->byte_offset + 1] = (uint8_t)value; + self_p->byte_offset += 2; +} + +void bitstream_writer_write_u32(struct bitstream_writer_t *self_p, + uint32_t value) +{ + int i; + + if (self_p->bit_offset == 0) { + self_p->buf_p[self_p->byte_offset] = (value >> 24); + } else { + self_p->buf_p[self_p->byte_offset] |= (value >> (24 + self_p->bit_offset)); + self_p->buf_p[self_p->byte_offset + 4] = + (uint8_t)(value << (8 - self_p->bit_offset)); + value >>= self_p->bit_offset; + } + + for (i = 3; i > 0; i--) { + self_p->buf_p[self_p->byte_offset + i] = value; + value >>= 8; + } + + self_p->byte_offset += 4; +} + +void bitstream_writer_write_u64(struct bitstream_writer_t *self_p, + uint64_t value) +{ + int i; + + + if (self_p->bit_offset == 0) { + self_p->buf_p[self_p->byte_offset] = (value >> 56); + } else { + self_p->buf_p[self_p->byte_offset] |= (value >> (56 + self_p->bit_offset)); + self_p->buf_p[self_p->byte_offset + 8] = + (uint8_t)(value << (8 - self_p->bit_offset)); + value >>= self_p->bit_offset; + } + + for (i = 7; i > 0; i--) { + self_p->buf_p[self_p->byte_offset + i] = (uint8_t)value; + value >>= 8; + } + + self_p->byte_offset += 8; +} + +void bitstream_writer_write_u64_bits(struct bitstream_writer_t *self_p, + uint64_t value, + int number_of_bits) +{ + int i; + int first_byte_bits; + int last_byte_bits; + int full_bytes; + + if (number_of_bits == 0) { + return; + } + + /* Align beginning. */ + first_byte_bits = (8 - self_p->bit_offset); + + if (first_byte_bits != 8) { + if (number_of_bits < first_byte_bits) { + self_p->buf_p[self_p->byte_offset] |= + (uint8_t)(value << (first_byte_bits - number_of_bits)); + self_p->bit_offset += number_of_bits; + } else { + self_p->buf_p[self_p->byte_offset] |= (value >> (number_of_bits + - first_byte_bits)); + self_p->byte_offset++; + self_p->bit_offset = 0; + } + + number_of_bits -= first_byte_bits; + + if (number_of_bits <= 0) { + return; + } + } + + /* Align end. */ + last_byte_bits = (number_of_bits % 8); + full_bytes = (number_of_bits / 8); + + if (last_byte_bits != 0) { + self_p->buf_p[self_p->byte_offset + full_bytes] = + (uint8_t)(value << (8 - last_byte_bits)); + value >>= last_byte_bits; + self_p->bit_offset = last_byte_bits; + } + + /* Copy middle bytes. */ + for (i = full_bytes; i > 0; i--) { + self_p->buf_p[self_p->byte_offset + i - 1] = (uint8_t)value; + value >>= 8; + } + + self_p->byte_offset += full_bytes; +} + +void bitstream_writer_write_repeated_bit(struct bitstream_writer_t *self_p, + int value, + int length) +{ + int rest; + + if (value != 0) { + value = 0xff; + } + + rest = (length % 8); + bitstream_writer_write_u64_bits(self_p, value & ((1 << rest) - 1), rest); + bitstream_writer_write_repeated_u8(self_p, value, length / 8); +} + +void bitstream_writer_write_repeated_u8(struct bitstream_writer_t *self_p, + uint8_t value, + int length) +{ + int i; + + for (i = 0; i < length; i++) { + bitstream_writer_write_u8(self_p, value); + } +} + +void bitstream_writer_insert_bit(struct bitstream_writer_t *self_p, + int value) +{ + struct bitstream_writer_bounds_t bounds; + + bitstream_writer_bounds_save(&bounds, + self_p, + (8 * self_p->byte_offset) + self_p->bit_offset, + 1); + bitstream_writer_write_bit(self_p, value); + bitstream_writer_bounds_restore(&bounds); +} + +void bitstream_writer_insert_bytes(struct bitstream_writer_t *self_p, + const uint8_t *buf_p, + int length) +{ + struct bitstream_writer_bounds_t bounds; + + bitstream_writer_bounds_save(&bounds, + self_p, + (8 * self_p->byte_offset) + self_p->bit_offset, + 8 * length); + bitstream_writer_write_bytes(self_p, buf_p, length); + bitstream_writer_bounds_restore(&bounds); +} + +void bitstream_writer_insert_u8(struct bitstream_writer_t *self_p, + uint8_t value) +{ + struct bitstream_writer_bounds_t bounds; + + bitstream_writer_bounds_save(&bounds, + self_p, + (8 * self_p->byte_offset) + self_p->bit_offset, + 8); + bitstream_writer_write_u8(self_p, value); + bitstream_writer_bounds_restore(&bounds); +} + +void bitstream_writer_insert_u16(struct bitstream_writer_t *self_p, + uint16_t value) +{ + struct bitstream_writer_bounds_t bounds; + + bitstream_writer_bounds_save(&bounds, + self_p, + (8 * self_p->byte_offset) + self_p->bit_offset, + 16); + bitstream_writer_write_u16(self_p, value); + bitstream_writer_bounds_restore(&bounds); +} + +void bitstream_writer_insert_u32(struct bitstream_writer_t *self_p, + uint32_t value) +{ + struct bitstream_writer_bounds_t bounds; + + bitstream_writer_bounds_save(&bounds, + self_p, + (8 * self_p->byte_offset) + self_p->bit_offset, + 32); + bitstream_writer_write_u32(self_p, value); + bitstream_writer_bounds_restore(&bounds); +} + +void bitstream_writer_insert_u64(struct bitstream_writer_t *self_p, + uint64_t value) +{ + struct bitstream_writer_bounds_t bounds; + + bitstream_writer_bounds_save(&bounds, + self_p, + (8 * self_p->byte_offset) + self_p->bit_offset, + 64); + bitstream_writer_write_u64(self_p, value); + bitstream_writer_bounds_restore(&bounds); +} + +void bitstream_writer_insert_u64_bits(struct bitstream_writer_t *self_p, + uint64_t value, + int number_of_bits) +{ + struct bitstream_writer_bounds_t bounds; + + bitstream_writer_bounds_save(&bounds, + self_p, + (8 * self_p->byte_offset) + self_p->bit_offset, + number_of_bits); + bitstream_writer_write_u64_bits(self_p, value, number_of_bits); + bitstream_writer_bounds_restore(&bounds); +} + +void bitstream_writer_seek(struct bitstream_writer_t *self_p, + int offset) +{ + offset += ((8 * self_p->byte_offset) + self_p->bit_offset); + self_p->byte_offset = (offset / 8); + self_p->bit_offset = (offset % 8); +} + +void bitstream_writer_bounds_save(struct bitstream_writer_bounds_t *self_p, + struct bitstream_writer_t *writer_p, + int bit_offset, + int length) +{ + int number_of_bits; + + self_p->writer_p = writer_p; + number_of_bits = (bit_offset % 8); + + if (number_of_bits == 0) { + self_p->first_byte_offset = -1; + } else { + self_p->first_byte_offset = (bit_offset / 8); + self_p->first_byte = writer_p->buf_p[self_p->first_byte_offset]; + self_p->first_byte &= (0xff00 >> number_of_bits); + } + + number_of_bits = ((bit_offset + length) % 8); + + if (number_of_bits == 0) { + self_p->last_byte_offset = -1; + } else { + self_p->last_byte_offset = ((bit_offset + length) / 8); + self_p->last_byte = writer_p->buf_p[self_p->last_byte_offset]; + self_p->last_byte &= ~(0xff00 >> number_of_bits); + writer_p->buf_p[self_p->last_byte_offset] = 0; + } + + if (self_p->first_byte_offset != -1) { + writer_p->buf_p[self_p->first_byte_offset] = 0; + } +} + +void bitstream_writer_bounds_restore(struct bitstream_writer_bounds_t *self_p) +{ + if (self_p->first_byte_offset != -1) { + self_p->writer_p->buf_p[self_p->first_byte_offset] |= self_p->first_byte; + } + + if (self_p->last_byte_offset != -1) { + self_p->writer_p->buf_p[self_p->last_byte_offset] |= self_p->last_byte; + } +} + +void bitstream_reader_init(struct bitstream_reader_t *self_p, + const uint8_t *buf_p) +{ + self_p->buf_p = buf_p; + self_p->byte_offset = 0; + self_p->bit_offset = 0; +} + +int bitstream_reader_read_bit(struct bitstream_reader_t *self_p) +{ + int value; + + if (self_p->bit_offset == 0) { + value = (self_p->buf_p[self_p->byte_offset] >> 7); + self_p->bit_offset = 1; + } else { + value = ((self_p->buf_p[self_p->byte_offset] >> (7 - self_p->bit_offset)) & 0x1); + + if (self_p->bit_offset == 7) { + self_p->bit_offset = 0; + self_p->byte_offset++; + } else { + self_p->bit_offset++; + } + } + + return (value); +} + +void bitstream_reader_read_bytes(struct bitstream_reader_t *self_p, + uint8_t *buf_p, + int length) +{ + int i; + const uint8_t *src_p; + + src_p = &self_p->buf_p[self_p->byte_offset]; + + if (self_p->bit_offset == 0) { + memcpy(buf_p, src_p, sizeof(uint8_t) * length); + } else { + for (i = 0; i < length; i++) { + buf_p[i] = (src_p[i] << self_p->bit_offset); + buf_p[i] |= (src_p[i + 1] >> (8 - self_p->bit_offset)); + } + } + + self_p->byte_offset += length; +} + +uint8_t bitstream_reader_read_u8(struct bitstream_reader_t *self_p) +{ + uint8_t value; + + value = (self_p->buf_p[self_p->byte_offset] << self_p->bit_offset); + self_p->byte_offset++; + + if (self_p->bit_offset != 0) { + value |= (self_p->buf_p[self_p->byte_offset] >> (8 - self_p->bit_offset)); + } + + return (value); +} + +uint16_t bitstream_reader_read_u16(struct bitstream_reader_t *self_p) +{ + uint16_t value; + int i; + int offset; + const uint8_t *src_p; + + src_p = &self_p->buf_p[self_p->byte_offset]; + offset = (16 + self_p->bit_offset); + value = 0; + + for (i = 0; i < 2; i++) { + offset -= 8; + value |= ((uint16_t)src_p[i] << offset); + } + + if (offset != 0) { + value |= (src_p[2] >> (8 - offset)); + } + + self_p->byte_offset += 2; + + return (value); +} + +uint32_t bitstream_reader_read_u32(struct bitstream_reader_t *self_p) +{ + uint32_t value; + int i; + int offset; + const uint8_t *src_p; + + src_p = &self_p->buf_p[self_p->byte_offset]; + offset = (32 + self_p->bit_offset); + value = 0; + + for (i = 0; i < 4; i++) { + offset -= 8; + value |= ((uint32_t)src_p[i] << offset); + } + + if (offset != 0) { + value |= (src_p[4] >> (8 - offset)); + } + + self_p->byte_offset += 4; + + return (value); +} + +uint64_t bitstream_reader_read_u64(struct bitstream_reader_t *self_p) +{ + uint64_t value; + int i; + int offset; + const uint8_t *src_p; + + src_p = &self_p->buf_p[self_p->byte_offset]; + offset = (64 + self_p->bit_offset); + value = 0; + + for (i = 0; i < 8; i++) { + offset -= 8; + value |= ((uint64_t)src_p[i] << offset); + } + + if (offset != 0) { + value |= ((uint64_t)src_p[8] >> (8 - offset)); + } + + self_p->byte_offset += 8; + + return (value); +} + +uint64_t bitstream_reader_read_u64_bits(struct bitstream_reader_t *self_p, + int number_of_bits) +{ + uint64_t value; + int i; + int first_byte_bits; + int last_byte_bits; + int full_bytes; + + if (number_of_bits == 0) { + return (0); + } + + /* Align beginning. */ + first_byte_bits = (8 - self_p->bit_offset); + + if (first_byte_bits != 8) { + if (number_of_bits < first_byte_bits) { + value = (self_p->buf_p[self_p->byte_offset] >> (first_byte_bits + - number_of_bits)); + value &= ((1 << number_of_bits) - 1); + self_p->bit_offset += number_of_bits; + } else { + value = self_p->buf_p[self_p->byte_offset]; + value &= ((1 << first_byte_bits) - 1); + self_p->byte_offset++; + self_p->bit_offset = 0; + } + + number_of_bits -= first_byte_bits; + + if (number_of_bits <= 0) { + return (value); + } + } else { + value = 0; + } + + /* Copy middle bytes. */ + full_bytes = (number_of_bits / 8); + + for (i = 0; i < full_bytes; i++) { + value <<= 8; + value |= self_p->buf_p[self_p->byte_offset + i]; + } + + /* Last byte. */ + last_byte_bits = (number_of_bits % 8); + + if (last_byte_bits != 0) { + value <<= last_byte_bits; + value |= (self_p->buf_p[self_p->byte_offset + full_bytes] + >> (8 - last_byte_bits)); + self_p->bit_offset = last_byte_bits; + } + + self_p->byte_offset += full_bytes; + + return (value); +} + +void bitstream_reader_seek(struct bitstream_reader_t *self_p, + int offset) +{ + offset += ((8 * self_p->byte_offset) + self_p->bit_offset); + self_p->byte_offset = (offset / 8); + self_p->bit_offset = (offset % 8); +} + +int bitstream_reader_tell(struct bitstream_reader_t *self_p) +{ + return ((8 * self_p->byte_offset) + self_p->bit_offset); +} + +#ifdef __cplusplus +} +#endif diff --git a/third_party/bitstream/bitstream.h b/third_party/bitstream/bitstream.h new file mode 100644 index 0000000..9ced7b9 --- /dev/null +++ b/third_party/bitstream/bitstream.h @@ -0,0 +1,178 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2019 Erik Moqvist + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BITSTREAM_H +#define BITSTREAM_H + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include + +#define BITSTREAM_VERSION "0.8.0" + +struct bitstream_writer_t { + uint8_t *buf_p; + int byte_offset; + int bit_offset; +}; + +struct bitstream_writer_bounds_t { + struct bitstream_writer_t *writer_p; + int first_byte_offset; + uint8_t first_byte; + int last_byte_offset; + uint8_t last_byte; +}; + +struct bitstream_reader_t { + const uint8_t *buf_p; + int byte_offset; + int bit_offset; +}; + +/* + * The writer. + */ + +void bitstream_writer_init(struct bitstream_writer_t *self_p, + uint8_t *buf_p); + +int bitstream_writer_size_in_bits(struct bitstream_writer_t *self_p); + +int bitstream_writer_size_in_bytes(struct bitstream_writer_t *self_p); + +/* Write bits to the stream. Clears each byte before bits are + written. */ +void bitstream_writer_write_bit(struct bitstream_writer_t *self_p, + int value); + +void bitstream_writer_write_bytes(struct bitstream_writer_t *self_p, + const uint8_t *buf_p, + int length); + +void bitstream_writer_write_u8(struct bitstream_writer_t *self_p, + uint8_t value); + +void bitstream_writer_write_u16(struct bitstream_writer_t *self_p, + uint16_t value); + +void bitstream_writer_write_u32(struct bitstream_writer_t *self_p, + uint32_t value); + +void bitstream_writer_write_u64(struct bitstream_writer_t *self_p, + uint64_t value); + +/* Upper unused bits must be zero. */ +void bitstream_writer_write_u64_bits(struct bitstream_writer_t *self_p, + uint64_t value, + int number_of_bits); + +void bitstream_writer_write_repeated_bit(struct bitstream_writer_t *self_p, + int value, + int length); + +void bitstream_writer_write_repeated_u8(struct bitstream_writer_t *self_p, + uint8_t value, + int length); + +/* Insert bits into the stream. Leaves all other bits unmodified. */ +void bitstream_writer_insert_bit(struct bitstream_writer_t *self_p, + int value); + +void bitstream_writer_insert_bytes(struct bitstream_writer_t *self_p, + const uint8_t *buf_p, + int length); + +void bitstream_writer_insert_u8(struct bitstream_writer_t *self_p, + uint8_t value); + +void bitstream_writer_insert_u16(struct bitstream_writer_t *self_p, + uint16_t value); + +void bitstream_writer_insert_u32(struct bitstream_writer_t *self_p, + uint32_t value); + +void bitstream_writer_insert_u64(struct bitstream_writer_t *self_p, + uint64_t value); + +void bitstream_writer_insert_u64_bits(struct bitstream_writer_t *self_p, + uint64_t value, + int number_of_bits); + +/* Move write position. Seeking backwards makes the written size + smaller. Use write with care after seek, as seek does not clear + bytes. */ +void bitstream_writer_seek(struct bitstream_writer_t *self_p, + int offset); + +/* Save-restore first and last bytes in given range, so write can be + used in given range. */ +void bitstream_writer_bounds_save(struct bitstream_writer_bounds_t *self_p, + struct bitstream_writer_t *writer_p, + int bit_offset, + int length); + +void bitstream_writer_bounds_restore(struct bitstream_writer_bounds_t *self_p); + +/* + * The reader. + */ + +void bitstream_reader_init(struct bitstream_reader_t *self_p, + const uint8_t *buf_p); + +/* Read bits from the stream. */ +int bitstream_reader_read_bit(struct bitstream_reader_t *self_p); + +void bitstream_reader_read_bytes(struct bitstream_reader_t *self_p, + uint8_t *buf_p, + int length); + +uint8_t bitstream_reader_read_u8(struct bitstream_reader_t *self_p); + +uint16_t bitstream_reader_read_u16(struct bitstream_reader_t *self_p); + +uint32_t bitstream_reader_read_u32(struct bitstream_reader_t *self_p); + +uint64_t bitstream_reader_read_u64(struct bitstream_reader_t *self_p); + +uint64_t bitstream_reader_read_u64_bits(struct bitstream_reader_t *self_p, + int number_of_bits); + +/* Move read position. */ +void bitstream_reader_seek(struct bitstream_reader_t *self_p, + int offset); + +/* Get read position. */ +int bitstream_reader_tell(struct bitstream_reader_t *self_p); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // BITSTREAM_H From 339d42776806f348fe2b84aac29db6f89e46a053 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 7 Jan 2023 19:39:07 +0100 Subject: [PATCH 04/30] Update message.hpp, dbc.cpp, and 2 more files... --- include/libdbc/message.hpp | 26 ++-- src/dbc.cpp | 4 +- src/message.cpp | 235 +++++++++++++++++++------------------ test/test_dbc.cpp | 25 ++-- 4 files changed, 152 insertions(+), 138 deletions(-) diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index 872ecf5..d6b61dc 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -8,17 +8,15 @@ namespace libdbc { struct Message { - uint32_t id; - std::string name; - uint8_t size; - std::string node; - std::vector signals; - Message() = delete; explicit Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node); bool parseSignals(const std::vector data, std::vector &values) const; + void appendSignal(const Signal& signal); + const std::vector signals() const; + uint32_t id() const; + /*! * \brief prepareMessage * Preparing message to be able to parse signals afterwards. This speeds up parsing @@ -28,15 +26,25 @@ namespace libdbc { virtual bool operator==(const Message& rhs) const; private: - bool prepared{false}; // indicates if the message is prepared for parsing signals + uint32_t m_id; + std::string m_name; + uint8_t m_size; + std::string m_node; + std::vector m_signals; // when changing this vector m_prepared must be set to false! + + + bool m_prepared{false}; // indicates if the message is prepared for parsing signals struct BitStruct { - BitStruct(const std::string& name, uint32_t size, bool padding): name(name), size(size), padding(padding) {} + BitStruct(uint32_t size): size(size), padding(true) {} + BitStruct(int index, uint32_t size): index(index), size(size), padding(false) {} BitStruct() = delete; - std::string name; + int index; uint32_t size; bool padding; }; std::vector bitstruct; + + friend std::ostream& operator<<(std::ostream& os, const Message& dt); }; std::ostream& operator<< (std::ostream &out, const Message& msg); diff --git a/src/dbc.cpp b/src/dbc.cpp index 2711d19..c52e6bb 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -95,7 +95,7 @@ namespace libdbc { bool DbcParser::parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values) { for (const auto& message: messages) { - if (message.id == id) + if (message.id() == id) return message.parseSignals(data, out_values); } return false; @@ -174,7 +174,7 @@ namespace libdbc { 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); } } diff --git a/src/message.cpp b/src/message.cpp index 9e5e3aa..624b082 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -5,15 +5,15 @@ 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); } bool Message::parseSignals(const std::vector data, std::vector& values) const { - if (!prepared) + if (!m_prepared) return false; bitstream_reader_t reader; @@ -25,140 +25,147 @@ namespace libdbc { for (uint32_t i=0; i < bs.size; i++) bitstream_reader_read_bit(&reader); } else { - for(const auto& signal: signals) { - if (bs.name.compare(signal.name) != 0) { - continue; - } + const auto& signal = m_signals.at(bs.index); + if (signal.is_bigendian) { - if (signal.is_bigendian) { - - switch (bs.size) { - case 1: v = static_cast(bitstream_reader_read_bit(&reader)); break; - case 8: v = static_cast(bitstream_reader_read_u8(&reader)); break; - case 16: { - uint16_t tmp = bitstream_reader_read_u8(&reader); - tmp |= (uint16_t)bitstream_reader_read_u8(&reader) << 8; - if (signal.is_signed) - v = static_cast(static_cast(tmp)); - else - v = static_cast(tmp); - break; - } - case 32: { - uint32_t tmp = bitstream_reader_read_u8(&reader); - tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 8; - tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 16; - tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 24; - if (signal.is_signed) - v = static_cast(static_cast(tmp)); - else - v = static_cast(tmp); - break; - } - case 64: { - uint64_t tmp = bitstream_reader_read_u8(&reader); - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 8; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 16; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 24; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 32; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 40; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 48; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 56; - if (signal.is_signed) - v = static_cast(static_cast(tmp)); - else - v = static_cast(tmp); - break; - } - default: { - // TODO: implement sign? - // TODO: implement big endian - uint64_t value = 0; - for (uint32_t i=0; i < bs.size; i++) { - value |= bitstream_reader_read_bit(&reader) << i; - } - v = static_cast(value); - break; - } - } - } else { - // little endian - switch (bs.size) { - case 1: - v = static_cast(bitstream_reader_read_bit(&reader)); break; - case 8: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u8(&reader))); - else - v = static_cast(bitstream_reader_read_u8(&reader)); - break; - case 16: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u16(&reader))); - else - v = static_cast(bitstream_reader_read_u16(&reader)); - break; - case 32: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u32(&reader))); - else - v = static_cast(bitstream_reader_read_u32(&reader)); - break; - case 64: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u64(&reader))); - else - v = static_cast(bitstream_reader_read_u64(&reader)); - break; - default: { - // TODO: implement sign? - // TODO: implement big endian - uint64_t value = 0; - for (uint32_t i=0; i < bs.size; i++) { - value |= bitstream_reader_read_bit(&reader) << i; - } - v = static_cast(value); - break; + switch (bs.size) { + case 1: v = static_cast(bitstream_reader_read_bit(&reader)); break; + case 8: v = static_cast(bitstream_reader_read_u8(&reader)); break; + case 16: { + uint16_t tmp = bitstream_reader_read_u8(&reader); + tmp |= (uint16_t)bitstream_reader_read_u8(&reader) << 8; + if (signal.is_signed) + v = static_cast(static_cast(tmp)); + else + v = static_cast(tmp); + break; + } + case 32: { + uint32_t tmp = bitstream_reader_read_u8(&reader); + tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 8; + tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 16; + tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 24; + if (signal.is_signed) + v = static_cast(static_cast(tmp)); + else + v = static_cast(tmp); + break; + } + case 64: { + uint64_t tmp = bitstream_reader_read_u8(&reader); + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 8; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 16; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 24; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 32; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 40; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 48; + tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 56; + if (signal.is_signed) + v = static_cast(static_cast(tmp)); + else + v = static_cast(tmp); + break; + } + default: { + // TODO: possible to implement bigendian and sign? + uint64_t value = 0; + for (uint32_t i=0; i < bs.size; i++) { + value |= bitstream_reader_read_bit(&reader) << i; } + v = static_cast(value); + break; + } + } + } else { + // little endian + switch (bs.size) { + case 1: + v = static_cast(bitstream_reader_read_bit(&reader)); break; + case 8: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u8(&reader))); + else + v = static_cast(bitstream_reader_read_u8(&reader)); + break; + case 16: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u16(&reader))); + else + v = static_cast(bitstream_reader_read_u16(&reader)); + break; + case 32: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u32(&reader))); + else + v = static_cast(bitstream_reader_read_u32(&reader)); + break; + case 64: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u64(&reader))); + else + v = static_cast(bitstream_reader_read_u64(&reader)); + break; + default: { + // TODO: possible to implement bigendian and sign? + uint64_t value = 0; + for (uint32_t i=0; i < bs.size; i++) { + value |= bitstream_reader_read_bit(&reader) << i; } + v = static_cast(value); + break; + } } - - values.push_back(v * signal.factor + signal.offset); - break; } + + values.push_back(v * signal.factor + signal.offset); } } return true; } + void Message::appendSignal(const Signal& signal) { + m_prepared = false; + m_signals.push_back(signal); + } + + const std::vector Message::signals() const { + return m_signals; + } + + uint32_t Message::id() const { + return m_id; + } + void Message::prepareMessage() { - prepared = false; - std::sort(signals.begin(), signals.end()); + m_prepared = false; + // sort signals so that the signals are ordered by the startbit + std::sort(m_signals.begin(), m_signals.end()); uint32_t curr_bit = 0; - for (const auto& signal: signals) { - if (signal.is_multiplexed /*|| signal.is_bigendian*/) + for (int i=0; i < m_signals.size(); i++) { + const auto& signal = m_signals.at(i); + if (signal.is_multiplexed) break; // Not supported yet if (curr_bit < signal.start_bit) { // padding needed - bitstruct.push_back(BitStruct("", signal.start_bit - curr_bit, true)); + bitstruct.push_back(BitStruct(signal.start_bit - curr_bit)); } - bitstruct.push_back(BitStruct(signal.name, signal.size, false)); + bitstruct.push_back(BitStruct(i, signal.size)); curr_bit = signal.start_bit + signal.size; } - if (curr_bit > size * 8) + // Check if correct + if (curr_bit > m_size * 8) return; - prepared = true; - + m_prepared = true; } - 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; } } diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index 9692179..d034321 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -47,7 +47,7 @@ TEST_CASE("Testing dbc file loading", "[fileio]") { std::vector receivers{"DBG"}; libdbc::Signal sig("IO_DEBUG_test_unsigned", false, 0, 8, false, false, 1, 0, 0, 0, "", receivers); - msg.signals.push_back(sig); + msg.appendSignal(sig); std::vector msgs = {msg}; @@ -59,7 +59,7 @@ TEST_CASE("Testing dbc file loading", "[fileio]") { REQUIRE(parser->get_messages() == msgs); - REQUIRE(parser->get_messages().front().signals == msg.signals); + REQUIRE(parser->get_messages().front().signals() == msg.signals()); } } @@ -82,13 +82,13 @@ TEST_CASE("Testing big endian, little endian") { parser.parse_file(filename); REQUIRE(parser.get_messages().size() == 1); - REQUIRE(parser.get_messages().at(0).signals.size() == 2); + REQUIRE(parser.get_messages().at(0).signals().size() == 2); { - const auto signal = parser.get_messages().at(0).signals.at(0); + const auto signal = parser.get_messages().at(0).signals().at(0); REQUIRE(signal.is_bigendian == true); } { - const auto signal = parser.get_messages().at(0).signals.at(1); + const auto signal = parser.get_messages().at(0).signals().at(1); REQUIRE(signal.is_bigendian == false); } } @@ -106,31 +106,31 @@ TEST_CASE("Testing negative values") { parser.parse_file(filename); REQUIRE(parser.get_messages().size() == 1); - REQUIRE(parser.get_messages().at(0).signals.size() == 4); + REQUIRE(parser.get_messages().at(0).signals().size() == 4); SECTION("Evaluating first message") { - const auto signal = parser.get_messages().at(0).signals.at(0); + const auto signal = parser.get_messages().at(0).signals().at(0); REQUIRE(signal.factor == 0.1); REQUIRE(signal.offset == 0); REQUIRE(signal.min == -3276.8); REQUIRE(signal.max == -3276.7); } SECTION("Evaluating second message") { - const auto signal = parser.get_messages().at(0).signals.at(1); + const auto signal = parser.get_messages().at(0).signals().at(1); REQUIRE(signal.factor == 0.1); REQUIRE(signal.offset == 0); REQUIRE(signal.min == -3276.8); REQUIRE(signal.max == -3276.7); } SECTION("Evaluating third message"){ - const auto signal = parser.get_messages().at(0).signals.at(2); + const auto signal = parser.get_messages().at(0).signals().at(2); REQUIRE(signal.factor == 10); REQUIRE(signal.offset == 0); REQUIRE(signal.min == -3276.8); REQUIRE(signal.max == -3276.7); } SECTION("Evaluating fourth message"){ - const auto signal = parser.get_messages().at(0).signals.at(3); + const auto signal = parser.get_messages().at(0).signals().at(3); REQUIRE(signal.factor == 1); REQUIRE(signal.offset == -10); REQUIRE(signal.min == 0); @@ -149,9 +149,9 @@ TEST_CASE("Special characters in unit") { parser.parse_file(filename); REQUIRE(parser.get_messages().size() == 1); - REQUIRE(parser.get_messages().at(0).signals.size() == 1); + REQUIRE(parser.get_messages().at(0).signals().size() == 1); SECTION("Checking that signal with special characters as unit is parsed correctly") { - const auto signal = parser.get_messages().at(0).signals.at(0); + const auto signal = parser.get_messages().at(0).signals().at(0); REQUIRE(signal.unit.compare("Km/h") == 0); } } @@ -181,7 +181,6 @@ TEST_CASE("Parse Message little endian") { REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); - } TEST_CASE("Parse Message big endian") { From ed4285198bc8c0a6b4a8ca4c7a5154a0adb35289 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sun, 8 Jan 2023 12:44:52 +0100 Subject: [PATCH 05/30] clear messages, otherwise when reading a second time the messages are dublicate --- src/dbc.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dbc.cpp b/src/dbc.cpp index c52e6bb..1c11c01 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -58,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 lines; + messages.clear(); + parse_dbc_header(s); parse_dbc_nodes(s); From f031db600c08ed3e61ec75314dbc948aa1423acf Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sun, 8 Jan 2023 12:45:21 +0100 Subject: [PATCH 06/30] add comment and fix type to remove warning --- include/libdbc/message.hpp | 6 ++++++ src/message.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index d6b61dc..3c706f8 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -11,6 +11,12 @@ namespace libdbc { Message() = delete; explicit Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node); + /*! + * \brief parseSignals + * \param data + * \param values + * \return + */ bool parseSignals(const std::vector data, std::vector &values) const; void appendSignal(const Signal& signal); diff --git a/src/message.cpp b/src/message.cpp index 624b082..75f56b5 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -142,7 +142,7 @@ namespace libdbc { std::sort(m_signals.begin(), m_signals.end()); uint32_t curr_bit = 0; - for (int i=0; i < m_signals.size(); i++) { + for (std::vector::size_type i=0; i < m_signals.size(); i++) { const auto& signal = m_signals.at(i); if (signal.is_multiplexed) break; // Not supported yet From 6d26e815d4b65a8e8e1eed698ffcba43dd1e48bd Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sun, 8 Jan 2023 13:44:36 +0100 Subject: [PATCH 07/30] use fast_float instead of std::stod, because std::stod uses locale to parse the value which might be wrong. --- CMakeLists.txt | 2 ++ src/dbc.cpp | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a4c4068..336eaf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,8 @@ option(ENABLE_TESTS "Enable Unittests" ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) +find_package(FastFloat REQUIRED) + 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 \ diff --git a/src/dbc.cpp b/src/dbc.cpp index 1c11c01..66a1f7a 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -166,10 +167,14 @@ 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); + 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 receivers; From ea8404c553e3be1ba9c547bd74d9ca494ee043c4 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 11 Jan 2023 07:53:07 +0100 Subject: [PATCH 08/30] due to the error in 19caeeca4ccebadb974fe4cbaddc881c47160518 the assumption in the test was wrong. It has to be changed --- src/message.cpp | 79 +++++++++++++++++++++++------------------------ test/test_dbc.cpp | 4 +-- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/message.cpp b/src/message.cpp index 75f56b5..9bbccd2 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -27,7 +27,45 @@ namespace libdbc { } else { const auto& signal = m_signals.at(bs.index); if (signal.is_bigendian) { - + switch (bs.size) { + case 1: + v = static_cast(bitstream_reader_read_bit(&reader)); break; + case 8: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u8(&reader))); + else + v = static_cast(bitstream_reader_read_u8(&reader)); + break; + case 16: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u16(&reader))); + else + v = static_cast(bitstream_reader_read_u16(&reader)); + break; + case 32: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u32(&reader))); + else + v = static_cast(bitstream_reader_read_u32(&reader)); + break; + case 64: + if (signal.is_signed) + v = static_cast(static_cast(bitstream_reader_read_u64(&reader))); + else + v = static_cast(bitstream_reader_read_u64(&reader)); + break; + default: { + // TODO: possible to implement bigendian and sign? + uint64_t value = 0; + for (uint32_t i=0; i < bs.size; i++) { + value |= bitstream_reader_read_bit(&reader) << i; + } + v = static_cast(value); + break; + } + } + } else { + // little endian switch (bs.size) { case 1: v = static_cast(bitstream_reader_read_bit(&reader)); break; case 8: v = static_cast(bitstream_reader_read_u8(&reader)); break; @@ -76,45 +114,6 @@ namespace libdbc { break; } } - } else { - // little endian - switch (bs.size) { - case 1: - v = static_cast(bitstream_reader_read_bit(&reader)); break; - case 8: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u8(&reader))); - else - v = static_cast(bitstream_reader_read_u8(&reader)); - break; - case 16: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u16(&reader))); - else - v = static_cast(bitstream_reader_read_u16(&reader)); - break; - case 32: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u32(&reader))); - else - v = static_cast(bitstream_reader_read_u32(&reader)); - break; - case 64: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u64(&reader))); - else - v = static_cast(bitstream_reader_read_u64(&reader)); - break; - default: { - // TODO: possible to implement bigendian and sign? - uint64_t value = 0; - for (uint32_t i=0; i < bs.size; i++) { - value |= bitstream_reader_read_bit(&reader) << i; - } - v = static_cast(value); - break; - } - } } values.push_back(v * signal.factor + signal.offset); diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index d034321..edcd3b3 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -173,7 +173,7 @@ TEST_CASE("Parse Message little endian") { libdbc::DbcParser p(true); p.parse_file(filename); - std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // little endian + std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // little endian std::vector result_values; REQUIRE(p.parseMessage(0x21d, data, result_values) == true); REQUIRE(result_values.size() == 4); @@ -200,7 +200,7 @@ TEST_CASE("Parse Message big endian") { libdbc::DbcParser p(true); p.parse_file(filename); - std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // big endian + std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // big endian std::vector result_values; REQUIRE(p.parseMessage(0x21d, data, result_values) == true); REQUIRE(result_values.size() == 4); From e09a41c56a0c4eedf12623e01a431afe1f7ecac3 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 12 Jan 2023 09:00:16 +0100 Subject: [PATCH 09/30] implement parsing also std::array, because the blf library outputs this for CANMessages --- include/libdbc/dbc.hpp | 1 + include/libdbc/message.hpp | 5 ++++- src/dbc.cpp | 8 ++++++++ src/message.cpp | 12 ++++++++++-- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/libdbc/dbc.hpp b/include/libdbc/dbc.hpp index 8a34ed6..da82623 100644 --- a/include/libdbc/dbc.hpp +++ b/include/libdbc/dbc.hpp @@ -35,6 +35,7 @@ namespace libdbc { std::vector get_messages() const; bool parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values); + bool parseMessage(const uint32_t id, const std::array& data, std::vector& out_values); private: std::string version; diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index 3c706f8..9d66ac4 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -17,7 +18,9 @@ namespace libdbc { * \param values * \return */ - bool parseSignals(const std::vector data, std::vector &values) const; + bool parseSignals(const std::vector& data, std::vector &values) const; + bool parseSignals(const std::array& data, std::vector& values) const; + bool parseSignals(const uint8_t* data, std::vector& values) const; void appendSignal(const Signal& signal); const std::vector signals() const; diff --git a/src/dbc.cpp b/src/dbc.cpp index 66a1f7a..9f25987 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -104,6 +104,14 @@ namespace libdbc { return false; } + bool DbcParser::parseMessage(const uint32_t id, const std::array& data, std::vector& out_values) { + for (const auto& message: messages) { + if (message.id() == id) + return message.parseSignals(data, out_values); + } + return false; + } + void DbcParser::parse_dbc_header(std::istream& file_stream) { std::string line; diff --git a/src/message.cpp b/src/message.cpp index 9bbccd2..4b0ac67 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -12,12 +12,12 @@ namespace libdbc { (m_size == rhs.m_size) && (m_node == rhs.m_node); } - bool Message::parseSignals(const std::vector data, std::vector& values) const { + bool Message::parseSignals(const uint8_t* data, std::vector& values) const { if (!m_prepared) return false; bitstream_reader_t reader; - bitstream_reader_init(&reader, data.data()); + bitstream_reader_init(&reader, data); double v; for (const auto& bs: bitstruct) { @@ -122,6 +122,14 @@ namespace libdbc { return true; } + bool Message::parseSignals(const std::array& data, std::vector& values) const { + return parseSignals(data.data(), values); + } + + bool Message::parseSignals(const std::vector &data, std::vector& values) const { + return parseSignals(data.data(), values); + } + void Message::appendSignal(const Signal& signal) { m_prepared = false; m_signals.push_back(signal); From 39f8f90db7d25aa7edda798448550d482e7e2f64 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 12 Jan 2023 18:36:45 +0100 Subject: [PATCH 10/30] install fast_float --- .github/workflows/tests.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 20dcf3f..1b81835 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -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: | From 80f60f43f3065e1d917187bbe7d12b982ce5145f Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 12 Jan 2023 18:41:16 +0100 Subject: [PATCH 11/30] FastFloat target must be linked so that dbc finds the headers --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9382d9..347ce69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ endif() add_subdirectory(doc) add_library(${PROJECT_NAME} STATIC ${SOURCE}) -target_link_libraries(${PROJECT_NAME} bitstream) +target_link_libraries(${PROJECT_NAME} bitstream FastFloat::fast_float) target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS TYPE HEADERS BASE_DIRS ${PROJECT_SOURCE_DIR}/include/libdbc From a7b9a7595bdeb6fc680128c41b17baf4c7d20b52 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Mon, 16 Jan 2023 18:11:06 +0100 Subject: [PATCH 12/30] download FastFloat if it was not found --- CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 347ce69..2110d4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,16 @@ include(GNUInstallDirs) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) -find_package(FastFloat REQUIRED) +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 \ From 26bb4839adb0894f2de8030caf4ad669c4b88720 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 18 Jan 2023 08:04:48 +0100 Subject: [PATCH 13/30] make compatible with 3.16, because labplot uses 3.16 --- CMakeLists.txt | 28 +++++++++++++++++----------- test/CMakeLists.txt | 10 ++++++---- third_party/bitstream/CMakeLists.txt | 15 ++++++++++----- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2110d4c..a309217 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") @@ -74,10 +73,13 @@ add_subdirectory(doc) add_library(${PROJECT_NAME} STATIC ${SOURCE}) target_link_libraries(${PROJECT_NAME} bitstream FastFloat::fast_float) -target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS - TYPE HEADERS - BASE_DIRS ${PROJECT_SOURCE_DIR}/include/libdbc - FILES ${HEADER_FILES}) + +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} @@ -90,11 +92,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) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b76812e..39b3382 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,8 +17,10 @@ list(APPEND TEST_SOURCES add_executable(tests ${TEST_SOURCES}) target_compile_definitions(tests PRIVATE TESTDBCFILES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs") target_link_libraries(tests PRIVATE dbc Catch2::Catch2WithMain) -target_sources(tests INTERFACE FILE_SET HEADERS - TYPE HEADERS - BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} - FILES defines.hpp) +if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23) + target_sources(tests INTERFACE FILE_SET HEADERS + TYPE HEADERS + BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} + FILES defines.hpp) +endif() catch_discover_tests(tests) diff --git a/third_party/bitstream/CMakeLists.txt b/third_party/bitstream/CMakeLists.txt index 87416d6..043d10f 100644 --- a/third_party/bitstream/CMakeLists.txt +++ b/third_party/bitstream/CMakeLists.txt @@ -1,10 +1,15 @@ -cmake_minimum_required(VERSION 3.23) +cmake_minimum_required(VERSION 3.16) # FILE_SET needs cmake 3.23 project(bitstream) add_library(${PROJECT_NAME} STATIC bitstream.c) -target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS - TYPE HEADERS - BASE_DIRS ${PROJECT_SOURCE_DIR} - FILES bitstream.h) + +if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23) + target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS + TYPE HEADERS + BASE_DIRS ${PROJECT_SOURCE_DIR} + FILES bitstream.h) +else() + target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +endif() From eb123512855d829e5b268e834b6c3a492c0733d2 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 18 Jan 2023 08:24:54 +0100 Subject: [PATCH 14/30] include current source dir --- test/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 39b3382..75ce17a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,9 +18,11 @@ add_executable(tests ${TEST_SOURCES}) target_compile_definitions(tests PRIVATE TESTDBCFILES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs") target_link_libraries(tests PRIVATE dbc Catch2::Catch2WithMain) if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23) - target_sources(tests INTERFACE FILE_SET HEADERS + target_sources(tests PRIVATE FILE_SET HEADERS TYPE HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES defines.hpp) +else() + target_include_directories(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) endif() catch_discover_tests(tests) From e2ec1ded789f54a8e1e8e23ac37f17a36ca1c22f Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 18 Jan 2023 13:02:34 +0100 Subject: [PATCH 15/30] rename test --- test/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 75ce17a..8ae1fc4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,15 +14,15 @@ list(APPEND TEST_SOURCES test_dbc.cpp test_utils.cpp) -add_executable(tests ${TEST_SOURCES}) -target_compile_definitions(tests PRIVATE TESTDBCFILES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs") -target_link_libraries(tests PRIVATE dbc Catch2::Catch2WithMain) +add_executable(dbcParserTests ${TEST_SOURCES}) +target_compile_definitions(dbcParserTests PRIVATE TESTDBCFILES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs") +target_link_libraries(dbcParserTests PRIVATE dbc Catch2::Catch2WithMain) if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23) - target_sources(tests PRIVATE FILE_SET HEADERS + target_sources(dbcParserTests PRIVATE FILE_SET HEADERS TYPE HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES defines.hpp) else() - target_include_directories(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_include_directories(dbcParserTests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) endif() -catch_discover_tests(tests) +catch_discover_tests(dbcParserTests) From 25f17ce124c044c0b343ada88db14f0f5e6f273b Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 18 Jan 2023 14:13:54 +0100 Subject: [PATCH 16/30] execute docker everytime --- doc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 666f5b7..1827d5d 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -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" From 3af2c0cdefeecaa91a59e766d64dd7cba08e5d7f Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 19 Jan 2023 17:08:04 +0100 Subject: [PATCH 17/30] hack --- include/libdbc/message.hpp | 2 +- src/message.cpp | 131 ++++++++----------------------------- 2 files changed, 27 insertions(+), 106 deletions(-) diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index 9d66ac4..5f957c9 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -20,7 +20,7 @@ namespace libdbc { */ bool parseSignals(const std::vector& data, std::vector &values) const; bool parseSignals(const std::array& data, std::vector& values) const; - bool parseSignals(const uint8_t* data, std::vector& values) const; + bool parseSignals(const uint8_t* data, int size, std::vector& values) const; void appendSignal(const Signal& signal); const std::vector signals() const; diff --git a/src/message.cpp b/src/message.cpp index 4b0ac67..9ac0f3a 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -12,122 +12,43 @@ namespace libdbc { (m_size == rhs.m_size) && (m_node == rhs.m_node); } - bool Message::parseSignals(const uint8_t* data, std::vector& values) const { + bool Message::parseSignals(const uint8_t* data, int size, std::vector& values) const { if (!m_prepared) return false; - bitstream_reader_t reader; - bitstream_reader_init(&reader, data); - - double v; - for (const auto& bs: bitstruct) { - if (bs.padding) { - for (uint32_t i=0; i < bs.size; i++) - bitstream_reader_read_bit(&reader); - } else { - const auto& signal = m_signals.at(bs.index); - if (signal.is_bigendian) { - switch (bs.size) { - case 1: - v = static_cast(bitstream_reader_read_bit(&reader)); break; - case 8: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u8(&reader))); - else - v = static_cast(bitstream_reader_read_u8(&reader)); - break; - case 16: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u16(&reader))); - else - v = static_cast(bitstream_reader_read_u16(&reader)); - break; - case 32: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u32(&reader))); - else - v = static_cast(bitstream_reader_read_u32(&reader)); - break; - case 64: - if (signal.is_signed) - v = static_cast(static_cast(bitstream_reader_read_u64(&reader))); - else - v = static_cast(bitstream_reader_read_u64(&reader)); - break; - default: { - // TODO: possible to implement bigendian and sign? - uint64_t value = 0; - for (uint32_t i=0; i < bs.size; i++) { - value |= bitstream_reader_read_bit(&reader) << i; - } - v = static_cast(value); - break; - } - } - } else { - // little endian - switch (bs.size) { - case 1: v = static_cast(bitstream_reader_read_bit(&reader)); break; - case 8: v = static_cast(bitstream_reader_read_u8(&reader)); break; - case 16: { - uint16_t tmp = bitstream_reader_read_u8(&reader); - tmp |= (uint16_t)bitstream_reader_read_u8(&reader) << 8; - if (signal.is_signed) - v = static_cast(static_cast(tmp)); - else - v = static_cast(tmp); - break; - } - case 32: { - uint32_t tmp = bitstream_reader_read_u8(&reader); - tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 8; - tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 16; - tmp |= (uint32_t)bitstream_reader_read_u8(&reader) << 24; - if (signal.is_signed) - v = static_cast(static_cast(tmp)); - else - v = static_cast(tmp); - break; - } - case 64: { - uint64_t tmp = bitstream_reader_read_u8(&reader); - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 8; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 16; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 24; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 32; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 40; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 48; - tmp |= (uint64_t)bitstream_reader_read_u8(&reader) << 56; - if (signal.is_signed) - v = static_cast(static_cast(tmp)); - else - v = static_cast(tmp); - break; - } - default: { - // TODO: possible to implement bigendian and sign? - uint64_t value = 0; - for (uint32_t i=0; i < bs.size; i++) { - value |= bitstream_reader_read_bit(&reader) << i; - } - v = static_cast(value); - break; - } - } - } - - values.push_back(v * signal.factor + signal.offset); - } + if (size > 8) + return false; // not supported yet + + // Only little endian supported yet! + // All signals must be little endian + for (const auto& signal: m_signals) { + if (signal.is_bigendian) + return false; + } + + const uint32_t len = size * 8; + + uint64_t d = 0; + for (int i=0; i < size; i++) { + d |= ((uint64_t)data[i]) << i * 8; + } + + uint64_t v = 0; + for (const auto& signal: m_signals) { + const uint32_t shiftLeft = (len - (signal.size + signal.start_bit)); + v = d << shiftLeft; + v = v >> (shiftLeft + signal.start_bit); + values.push_back(v * signal.factor + signal.offset); } return true; } bool Message::parseSignals(const std::array& data, std::vector& values) const { - return parseSignals(data.data(), values); + return parseSignals(data.data(), data.size(), values); } bool Message::parseSignals(const std::vector &data, std::vector& values) const { - return parseSignals(data.data(), values); + return parseSignals(data.data(), data.size(), values); } void Message::appendSignal(const Signal& signal) { From d00599c7d09eb34a4fc10a3c61e547ae3267da51 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Fri, 20 Jan 2023 17:14:50 +0100 Subject: [PATCH 18/30] add tests --- src/message.cpp | 30 +++++----- test/CMakeLists.txt | 19 ++++-- test/common.cpp | 16 +++++ test/common.hpp | 6 ++ test/test_dbc.cpp | 11 +--- test/test_parseMessage.cpp | 119 +++++++++++++++++++++++++++++++++++++ 6 files changed, 172 insertions(+), 29 deletions(-) create mode 100644 test/common.cpp create mode 100644 test/common.hpp create mode 100644 test/test_parseMessage.cpp diff --git a/src/message.cpp b/src/message.cpp index 9ac0f3a..c952f21 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -19,25 +19,27 @@ namespace libdbc { if (size > 8) return false; // not supported yet - // Only little endian supported yet! - // All signals must be little endian - for (const auto& signal: m_signals) { - if (signal.is_bigendian) - return false; - } - - const uint32_t len = size * 8; - - uint64_t d = 0; + uint64_t data_little_endian = 0; + uint64_t data_big_endian = 0; for (int i=0; i < size; i++) { - d |= ((uint64_t)data[i]) << i * 8; + data_little_endian |= ((uint64_t)data[i]) << i * 8; + data_big_endian |= (uint64_t)data[i] << (size - 1 - 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) { - const uint32_t shiftLeft = (len - (signal.size + signal.start_bit)); - v = d << shiftLeft; - v = v >> (shiftLeft + signal.start_bit); + if (signal.is_bigendian) { + const uint32_t shiftLeft = signal.start_bit; + v = data_big_endian << shiftLeft; + v = v >> (shiftLeft + signal.start_bit); + } else { + const uint32_t shiftLeft = (len - (signal.size + signal.start_bit)); + v = data_little_endian << shiftLeft; + v = v >> (shiftLeft + signal.start_bit); + } values.push_back(v * signal.factor + signal.offset); } return true; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8ae1fc4..d856c08 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,11 +10,7 @@ FetchContent_Declare( FetchContent_MakeAvailable(Catch2) include(Catch) -list(APPEND TEST_SOURCES - test_dbc.cpp - test_utils.cpp) - -add_executable(dbcParserTests ${TEST_SOURCES}) +add_executable(dbcParserTests test_dbc.cpp test_utils.cpp common.cpp) target_compile_definitions(dbcParserTests PRIVATE TESTDBCFILES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs") target_link_libraries(dbcParserTests PRIVATE dbc Catch2::Catch2WithMain) if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23) @@ -26,3 +22,16 @@ else() target_include_directories(dbcParserTests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) endif() catch_discover_tests(dbcParserTests) + +add_executable(dbcParserParsemessageTests test_parseMessage.cpp common.cpp) +target_compile_definitions(dbcParserParsemessageTests PRIVATE TESTDBCFILES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs") +target_link_libraries(dbcParserParsemessageTests PRIVATE dbc Catch2::Catch2WithMain) +if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23) + target_sources(dbcParserParsemessageTests PRIVATE FILE_SET HEADERS + TYPE HEADERS + BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} + FILES defines.hpp) +else() + target_include_directories(dbcParserParsemessageTests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +endif() +catch_discover_tests(dbcParserParsemessageTests) diff --git a/test/common.cpp b/test/common.cpp new file mode 100644 index 0000000..9459242 --- /dev/null +++ b/test/common.cpp @@ -0,0 +1,16 @@ +#include "common.hpp" +#include "defines.hpp" + + +bool create_tmp_dbc_with(const char* filename, const char* content) +{ + auto* file = std::fopen(filename, "w"); + if (!file) { + return false; + } + + std::fputs(PRIMITIVE_DBC.c_str(), file); + std::fputs(content, file); + std::fclose(file); + return true; +} diff --git a/test/common.hpp b/test/common.hpp new file mode 100644 index 0000000..074fc25 --- /dev/null +++ b/test/common.hpp @@ -0,0 +1,6 @@ +#ifndef COMMON_H +#define COMMON_H + +bool create_tmp_dbc_with(const char* filename, const char* content); + +#endif // COMMON_H diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index 4d30e66..a9454f9 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -3,16 +3,7 @@ #include #include "defines.hpp" #include - -void create_tmp_dbc_with(const char* filename, const char* content) -{ - auto* file = std::fopen(filename, "w"); - CHECK(file); - - std::fputs(PRIMITIVE_DBC.c_str(), file); - std::fputs(content, file); - std::fclose(file); -} +#include "common.hpp" TEST_CASE("Testing dbc file loading error issues", "[fileio][error]") { diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp new file mode 100644 index 0000000..a325634 --- /dev/null +++ b/test/test_parseMessage.cpp @@ -0,0 +1,119 @@ +#include +#include +#include + +#include + +#include "common.hpp" + +// Testing of parsing messages + +TEST_CASE("Parse Message 1 Big Endian") { + libdbc::DbcParser parser(true); + + const auto dbcContent = R"(BO_ 234 MSG1: 8 Vector__XXX + SG_ Sig1 : 0|8@0- (0.1,-3) [-3276.8|-3276.7] "C" Vector__XXX + SG_ Sig2 : 8|8@0- (0.15,7) [-3276.8|-3276.7] "C" Vector__XXX +)"; + + const auto* filename = std::tmpnam(NULL); + CHECK(create_tmp_dbc_with(filename, dbcContent)); + + parser.parse_file(filename); + + SECTION("Evaluating first message") { + std::vector out_values; + CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == true); + CHECK(out_values.size() == 2); + CHECK(out_values.at(0) == 0x01 * 0.1 - 3); + CHECK(out_values.at(1) == 0x02 * 0.15 + 7); + } + +} + +TEST_CASE("Parse Message 2 Big Endian") { + libdbc::DbcParser parser(true); + + const auto dbcContent = R"(BO_ 234 MSG1: 8 Vector__XXX + SG_ Msg1Sig1 : 0|8@0+ (1,0) [-3276.8|-3276.7] "C" Vector__XXX + SG_ MsgSig2 : 8|8@0+ (1,0) [-3276.8|-3276.7] "C" Vector__XXX +BO_ 123 MSG2: 8 Vector__XXX + SG_ Msg2Sig1 : 0|8@0+ (1,0) [-3276.8|-3276.7] "C" Vector__XXX + SG_ Msg2Sig1 : 8|8@0+ (1,0) [-3276.8|-3276.7] "C" Vector__XXX +)"; + + const auto* filename = std::tmpnam(NULL); + CHECK(create_tmp_dbc_with(filename, dbcContent)); + + parser.parse_file(filename); + + SECTION("Evaluating first message") { + std::vector out_values; + CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == true); + std::vector refData{0x01, 0x02}; + CHECK(refData.size() == 2); + CHECK(out_values.size() == refData.size()); + for (int i=0; i < refData.size(); i++) { + CHECK(out_values.at(i) == refData.at(i)); + } + } + + SECTION("Evaluating unknown message id") { + std::vector out_values; + CHECK(parser.parseMessage(578, std::vector({0xFF, 0xA2}), out_values) == false); + } +} + +TEST_CASE("Parse Message Big Number not aligned little endian") { + libdbc::DbcParser parser(true); + + const auto dbcContent = R"(BO_ 337 STATUS: 8 Vector__XXX + SG_ Value6 : 27|3@1+ (1,0) [0|7] "" Vector__XXX + SG_ Value5 : 16|11@1+ (0.1,-102) [-102|102] "%" Vector__XXX + SG_ Value2 : 8|2@1+ (1,0) [0|2] "" Vector__XXX + SG_ Value3 : 10|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ Value7 : 30|2@1+ (1,0) [0|3] "" Vector__XXX + SG_ Value4 : 11|4@1+ (1,0) [0|3] "" Vector__XXX + SG_ Value1 : 0|8@1+ (1,0) [0|204] "Km/h" Vector__XXX +)"; + + const auto* filename = std::tmpnam(NULL); + CHECK(create_tmp_dbc_with(filename, dbcContent)); + + parser.parse_file(filename); + + SECTION("Evaluating first message") { + std::vector out_values; + CHECK(parser.parseMessage(337, std::vector({0, 4, 252, 19, 0, 0, 0, 0}), out_values) == true); + std::vector refData{0, 0, 1, 0, 0, 2, 0}; + CHECK(refData.size() == 7); + CHECK(out_values.size() == refData.size()); + for (int i=0; i < refData.size(); i++) { + CHECK(out_values.at(i) == refData.at(i)); + } + } + + SECTION("Evaluating second message") { + std::vector out_values; + CHECK(parser.parseMessage(337, std::vector({47, 4, 60, 29, 0, 0, 0, 0}), out_values) == true); + std::vector refData{47, 0, 1, 0, 32, 3, 0}; + CHECK(refData.size() == 7); + CHECK(out_values.size() == refData.size()); + for (int i=0; i < refData.size(); i++) { + CHECK(out_values.at(i) == refData.at(i)); + } + } + + SECTION("Evaluating third message") { + std::vector out_values; + CHECK(parser.parseMessage(337, std::vector({57, 4, 250, 29, 0, 0, 0, 0}), out_values) == true); + std::vector refData{57, 0, 1, 0, 51, 3, 0}; + CHECK(refData.size() == 7); + CHECK(out_values.size() == refData.size()); + for (int i=0; i < refData.size(); i++) { + CHECK(out_values.at(i) == refData.at(i)); + } + } +} + +// TODO: create also for big endian! From 2fd90e049114fb9fd45680139636c46da5ae431d Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 25 Jan 2023 17:51:53 +0100 Subject: [PATCH 19/30] only little endian support right now --- src/message.cpp | 8 ++++++++ src/utils.cpp | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/message.cpp b/src/message.cpp index c952f21..3079d09 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -19,6 +19,14 @@ namespace libdbc { if (size > 8) return false; // not supported yet + // Currently only little endian will be supported, because + // The code below was not tested with bigendian! + // All signals must be little endian + for (const auto& signal: m_signals) { + if (signal.is_bigendian) + return false; + } + uint64_t data_little_endian = 0; uint64_t data_big_endian = 0; for (int i=0; i < size; i++) { diff --git a/src/utils.cpp b/src/utils.cpp index 773b802..824e041 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -72,4 +72,4 @@ namespace utils { return start == end ? std::string() : line.substr(start, end - start + 1); } -} // Namespace Utils \ No newline at end of file +} // Namespace Utils From deba3daf51fec83707d3fd18e83448d2b9fea6d5 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 25 Jan 2023 18:26:41 +0100 Subject: [PATCH 20/30] do not pass a flag to the Contructor, but create a dedicated function --- include/libdbc/dbc.hpp | 6 +++--- src/dbc.cpp | 17 ++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/libdbc/dbc.hpp b/include/libdbc/dbc.hpp index da82623..d2df18d 100644 --- a/include/libdbc/dbc.hpp +++ b/include/libdbc/dbc.hpp @@ -24,7 +24,7 @@ namespace libdbc { class DbcParser : public Parser { public: - DbcParser(bool sortSignals = false); + DbcParser(); virtual ~DbcParser() = default; @@ -37,6 +37,8 @@ namespace libdbc { bool parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values); bool parseMessage(const uint32_t id, const std::array& data, std::vector& out_values); + void sortSignals(); + private: std::string version; std::vector nodes; @@ -49,8 +51,6 @@ namespace libdbc { const std::regex message_re; const std::regex signal_re; - bool sortSignals{false}; - void parse_dbc_header(std::istream& file_stream); void parse_dbc_nodes(std::istream& file_stream); void parse_dbc_messages(const std::vector& lines); diff --git a/src/dbc.cpp b/src/dbc.cpp index 9f25987..fdc7421 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -29,7 +29,7 @@ const auto whiteSpace = "\\s"; namespace libdbc { - DbcParser::DbcParser(bool sortSignals) : 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)"), @@ -54,8 +54,7 @@ namespace libdbc { whiteSpace + unitPattern + whiteSpace + - receiverPattern), - sortSignals(sortSignals) { + receiverPattern) { } @@ -75,14 +74,14 @@ namespace libdbc { lines.push_back(line); } - parse_dbc_messages(lines); + parse_dbc_messages(lines); + } - if (sortSignals) { - for (auto& message: messages) { - message.prepareMessage(); - } + void DbcParser::sortSignals() { + for (auto& message: messages) { + message.prepareMessage(); } - } + } std::string DbcParser::get_version() const { return version; From c883074aedbd52e6a2280971c9c34c0fbc58dad6 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 25 Jan 2023 18:26:59 +0100 Subject: [PATCH 21/30] comment not needed stuff out for now --- src/message.cpp | 50 +++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/message.cpp b/src/message.cpp index 3079d09..60e26d8 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -13,8 +13,9 @@ namespace libdbc { } bool Message::parseSignals(const uint8_t* data, int size, std::vector& values) const { - if (!m_prepared) - return false; + // With the current approach it is not needed to prepare the message by sorting the signals +// if (!m_prepared) +// return false; if (size > 8) return false; // not supported yet @@ -31,7 +32,7 @@ namespace libdbc { 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 |= (uint64_t)data[i] << (size - 1 - i); + //data_big_endian |= (uint64_t)data[i] << (size - 1 - i); } // TODO: does this also work on a big endian machine? @@ -40,9 +41,10 @@ namespace libdbc { uint64_t v = 0; for (const auto& signal: m_signals) { if (signal.is_bigendian) { - const uint32_t shiftLeft = signal.start_bit; - v = data_big_endian << shiftLeft; - v = v >> (shiftLeft + signal.start_bit); + // Not tested! + // const uint32_t shiftLeft = signal.start_bit; + // v = data_big_endian << shiftLeft; + // v = v >> (shiftLeft + signal.start_bit); } else { const uint32_t shiftLeft = (len - (signal.size + signal.start_bit)); v = data_little_endian << shiftLeft; @@ -75,26 +77,26 @@ namespace libdbc { } void Message::prepareMessage() { - m_prepared = false; - // sort signals so that the signals are ordered by the startbit +// m_prepared = false; +// // sort signals so that the signals are ordered by the startbit std::sort(m_signals.begin(), m_signals.end()); - uint32_t curr_bit = 0; - for (std::vector::size_type i=0; i < m_signals.size(); i++) { - const auto& signal = m_signals.at(i); - if (signal.is_multiplexed) - break; // Not supported yet - - if (curr_bit < signal.start_bit) { - // padding needed - bitstruct.push_back(BitStruct(signal.start_bit - curr_bit)); - } - bitstruct.push_back(BitStruct(i, signal.size)); - curr_bit = signal.start_bit + signal.size; - } - // Check if correct - if (curr_bit > m_size * 8) - return; +// uint32_t curr_bit = 0; +// for (std::vector::size_type i=0; i < m_signals.size(); i++) { +// const auto& signal = m_signals.at(i); +// if (signal.is_multiplexed) +// break; // Not supported yet + +// if (curr_bit < signal.start_bit) { +// // padding needed +// bitstruct.push_back(BitStruct(signal.start_bit - curr_bit)); +// } +// bitstruct.push_back(BitStruct(i, signal.size)); +// curr_bit = signal.start_bit + signal.size; +// } +// // Check if correct +// if (curr_bit > m_size * 8) +// return; m_prepared = true; } From 876bab965c1ebf3d9fa4887e926a31459c95057f Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 25 Jan 2023 18:27:21 +0100 Subject: [PATCH 22/30] fix tests --- test/test_dbc.cpp | 36 +++++++++++++----------------------- test/test_parseMessage.cpp | 31 +++++++++++++++++-------------- 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index a9454f9..7aed660 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -159,18 +159,13 @@ TEST_CASE("Special characters in unit") { TEST_CASE("Parse Message little endian") { const auto* filename = std::tmpnam(NULL); - auto* file = std::fopen(filename, "w"); - CHECK(file); - - std::fputs(PRIMITIVE_DBC.c_str(), file); - std::fputs(R"(BO_ 541 STATUS: 8 DEVICE1 + create_tmp_dbc_with(filename, R"(BO_ 541 STATUS: 8 DEVICE1 SG_ Temperature : 48|16@1+ (0.01,-40) [-40|125] "C" DEVICE1 SG_ SOH : 0|16@1+ (0.01,0) [0|100] "%" DEVICE1 SG_ SOE : 32|16@1+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOC : 16|16@1+ (0.01,0) [0|100] "%" DEVICE1)", file); - std::fclose(file); + SG_ SOC : 16|16@1+ (0.01,0) [0|100] "%" DEVICE1)"); - libdbc::DbcParser p(true); + libdbc::DbcParser p; p.parse_file(filename); std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // little endian @@ -185,27 +180,22 @@ TEST_CASE("Parse Message little endian") { TEST_CASE("Parse Message big endian") { const auto* filename = std::tmpnam(NULL); - - auto* file = std::fopen(filename, "w"); - CHECK(file); - - std::fputs(PRIMITIVE_DBC.c_str(), file); - std::fputs(R"(BO_ 541 STATUS: 8 DEVICE1 + create_tmp_dbc_with(filename, R"(BO_ 541 STATUS: 8 DEVICE1 SG_ Temperature : 48|16@0+ (0.01,-40) [-40|125] "C" DEVICE1 SG_ SOH : 0|16@0+ (0.01,0) [0|100] "%" DEVICE1 SG_ SOE : 32|16@0+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOC : 16|16@0+ (0.01,0) [0|100] "%" DEVICE1)", file); - std::fclose(file); + SG_ SOC : 16|16@0+ (0.01,0) [0|100] "%" DEVICE1)"); - libdbc::DbcParser p(true); + libdbc::DbcParser p; p.parse_file(filename); std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // big endian std::vector result_values; - REQUIRE(p.parseMessage(0x21d, data, result_values) == true); - REQUIRE(result_values.size() == 4); - REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); - REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); - REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); - REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); + REQUIRE(p.parseMessage(0x21d, data, result_values) == false); + // Big endian not yet supported +// REQUIRE(result_values.size() == 4); +// REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); +// REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); +// REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); +// REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); } diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp index a325634..5747e26 100644 --- a/test/test_parseMessage.cpp +++ b/test/test_parseMessage.cpp @@ -9,7 +9,7 @@ // Testing of parsing messages TEST_CASE("Parse Message 1 Big Endian") { - libdbc::DbcParser parser(true); + libdbc::DbcParser parser; const auto dbcContent = R"(BO_ 234 MSG1: 8 Vector__XXX SG_ Sig1 : 0|8@0- (0.1,-3) [-3276.8|-3276.7] "C" Vector__XXX @@ -23,16 +23,17 @@ TEST_CASE("Parse Message 1 Big Endian") { SECTION("Evaluating first message") { std::vector out_values; - CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == true); - CHECK(out_values.size() == 2); - CHECK(out_values.at(0) == 0x01 * 0.1 - 3); - CHECK(out_values.at(1) == 0x02 * 0.15 + 7); + CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == false); + // Big endian not supported +// CHECK(out_values.size() == 2); +// CHECK(out_values.at(0) == 0x01 * 0.1 - 3); +// CHECK(out_values.at(1) == 0x02 * 0.15 + 7); } } TEST_CASE("Parse Message 2 Big Endian") { - libdbc::DbcParser parser(true); + libdbc::DbcParser parser; const auto dbcContent = R"(BO_ 234 MSG1: 8 Vector__XXX SG_ Msg1Sig1 : 0|8@0+ (1,0) [-3276.8|-3276.7] "C" Vector__XXX @@ -49,13 +50,14 @@ BO_ 123 MSG2: 8 Vector__XXX SECTION("Evaluating first message") { std::vector out_values; - CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == true); - std::vector refData{0x01, 0x02}; - CHECK(refData.size() == 2); - CHECK(out_values.size() == refData.size()); - for (int i=0; i < refData.size(); i++) { - CHECK(out_values.at(i) == refData.at(i)); - } + CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == false); + // Big endian not supported +// std::vector refData{0x01, 0x02}; +// CHECK(refData.size() == 2); +// CHECK(out_values.size() == refData.size()); +// for (int i=0; i < refData.size(); i++) { +// CHECK(out_values.at(i) == refData.at(i)); +// } } SECTION("Evaluating unknown message id") { @@ -65,7 +67,7 @@ BO_ 123 MSG2: 8 Vector__XXX } TEST_CASE("Parse Message Big Number not aligned little endian") { - libdbc::DbcParser parser(true); + libdbc::DbcParser parser; const auto dbcContent = R"(BO_ 337 STATUS: 8 Vector__XXX SG_ Value6 : 27|3@1+ (1,0) [0|7] "" Vector__XXX @@ -81,6 +83,7 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { CHECK(create_tmp_dbc_with(filename, dbcContent)); parser.parse_file(filename); + parser.sortSignals(); SECTION("Evaluating first message") { std::vector out_values; From ca34f2435a1b5d8d902316783fffc6d87fc38f00 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 25 Jan 2023 18:36:12 +0100 Subject: [PATCH 23/30] add status flag to show which error occured --- include/libdbc/dbc.hpp | 4 ++-- include/libdbc/message.hpp | 13 ++++++++++--- src/dbc.cpp | 8 ++++---- src/message.cpp | 12 ++++++------ test/test_dbc.cpp | 4 ++-- test/test_parseMessage.cpp | 12 ++++++------ 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/include/libdbc/dbc.hpp b/include/libdbc/dbc.hpp index d2df18d..2c62f58 100644 --- a/include/libdbc/dbc.hpp +++ b/include/libdbc/dbc.hpp @@ -34,8 +34,8 @@ namespace libdbc { std::vector get_nodes() const; std::vector get_messages() const; - bool parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values); - bool parseMessage(const uint32_t id, const std::array& data, std::vector& out_values); + Message::ParseSignalsStatus parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values); + Message::ParseSignalsStatus parseMessage(const uint32_t id, const std::array& data, std::vector& out_values); void sortSignals(); diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index 5f957c9..2e607c7 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -12,15 +12,22 @@ namespace libdbc { Message() = delete; explicit Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node); + enum class ParseSignalsStatus { + Success = 0, + ErrorMessageToLong = -1, + ErrorBigEndian = -2, + ErrorUnknownID = -3, + }; + /*! * \brief parseSignals * \param data * \param values * \return */ - bool parseSignals(const std::vector& data, std::vector &values) const; - bool parseSignals(const std::array& data, std::vector& values) const; - bool parseSignals(const uint8_t* data, int size, std::vector& values) const; + ParseSignalsStatus parseSignals(const std::vector& data, std::vector &values) const; + ParseSignalsStatus parseSignals(const std::array& data, std::vector& values) const; + ParseSignalsStatus parseSignals(const uint8_t* data, int size, std::vector& values) const; void appendSignal(const Signal& signal); const std::vector signals() const; diff --git a/src/dbc.cpp b/src/dbc.cpp index fdc7421..e21e302 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -95,20 +95,20 @@ namespace libdbc { return messages; } - bool DbcParser::parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values) { + Message::ParseSignalsStatus DbcParser::parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values) { for (const auto& message: messages) { if (message.id() == id) return message.parseSignals(data, out_values); } - return false; + return Message::ParseSignalsStatus::ErrorUnknownID; } - bool DbcParser::parseMessage(const uint32_t id, const std::array& data, std::vector& out_values) { + Message::ParseSignalsStatus DbcParser::parseMessage(const uint32_t id, const std::array& data, std::vector& out_values) { for (const auto& message: messages) { if (message.id() == id) return message.parseSignals(data, out_values); } - return false; + return Message::ParseSignalsStatus::ErrorUnknownID; } diff --git a/src/message.cpp b/src/message.cpp index 60e26d8..67be25e 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -12,20 +12,20 @@ namespace libdbc { (m_size == rhs.m_size) && (m_node == rhs.m_node); } - bool Message::parseSignals(const uint8_t* data, int size, std::vector& values) const { + Message::ParseSignalsStatus Message::parseSignals(const uint8_t* data, int size, std::vector& values) const { // With the current approach it is not needed to prepare the message by sorting the signals // if (!m_prepared) // return false; if (size > 8) - return false; // not supported yet + return ParseSignalsStatus::ErrorMessageToLong; // not supported yet // Currently only little endian will be supported, because // The code below was not tested with bigendian! // All signals must be little endian for (const auto& signal: m_signals) { if (signal.is_bigendian) - return false; + return ParseSignalsStatus::ErrorBigEndian; } uint64_t data_little_endian = 0; @@ -52,14 +52,14 @@ namespace libdbc { } values.push_back(v * signal.factor + signal.offset); } - return true; + return ParseSignalsStatus::Success; } - bool Message::parseSignals(const std::array& data, std::vector& values) const { + Message::ParseSignalsStatus Message::parseSignals(const std::array& data, std::vector& values) const { return parseSignals(data.data(), data.size(), values); } - bool Message::parseSignals(const std::vector &data, std::vector& values) const { + Message::ParseSignalsStatus Message::parseSignals(const std::vector &data, std::vector& values) const { return parseSignals(data.data(), data.size(), values); } diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index 7aed660..2b9cd11 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -170,7 +170,7 @@ TEST_CASE("Parse Message little endian") { std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // little endian std::vector result_values; - REQUIRE(p.parseMessage(0x21d, data, result_values) == true); + REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::Success); REQUIRE(result_values.size() == 4); REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); @@ -191,7 +191,7 @@ TEST_CASE("Parse Message big endian") { std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // big endian std::vector result_values; - REQUIRE(p.parseMessage(0x21d, data, result_values) == false); + REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); // Big endian not yet supported // REQUIRE(result_values.size() == 4); // REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp index 5747e26..1a9380d 100644 --- a/test/test_parseMessage.cpp +++ b/test/test_parseMessage.cpp @@ -23,7 +23,7 @@ TEST_CASE("Parse Message 1 Big Endian") { SECTION("Evaluating first message") { std::vector out_values; - CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == false); + CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); // Big endian not supported // CHECK(out_values.size() == 2); // CHECK(out_values.at(0) == 0x01 * 0.1 - 3); @@ -50,7 +50,7 @@ BO_ 123 MSG2: 8 Vector__XXX SECTION("Evaluating first message") { std::vector out_values; - CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == false); + CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); // Big endian not supported // std::vector refData{0x01, 0x02}; // CHECK(refData.size() == 2); @@ -62,7 +62,7 @@ BO_ 123 MSG2: 8 Vector__XXX SECTION("Evaluating unknown message id") { std::vector out_values; - CHECK(parser.parseMessage(578, std::vector({0xFF, 0xA2}), out_values) == false); + CHECK(parser.parseMessage(578, std::vector({0xFF, 0xA2}), out_values) == libdbc::Message::ParseSignalsStatus::ErrorUnknownID); } } @@ -87,7 +87,7 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { SECTION("Evaluating first message") { std::vector out_values; - CHECK(parser.parseMessage(337, std::vector({0, 4, 252, 19, 0, 0, 0, 0}), out_values) == true); + CHECK(parser.parseMessage(337, std::vector({0, 4, 252, 19, 0, 0, 0, 0}), out_values) == libdbc::Message::ParseSignalsStatus::Success); std::vector refData{0, 0, 1, 0, 0, 2, 0}; CHECK(refData.size() == 7); CHECK(out_values.size() == refData.size()); @@ -98,7 +98,7 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { SECTION("Evaluating second message") { std::vector out_values; - CHECK(parser.parseMessage(337, std::vector({47, 4, 60, 29, 0, 0, 0, 0}), out_values) == true); + CHECK(parser.parseMessage(337, std::vector({47, 4, 60, 29, 0, 0, 0, 0}), out_values) == libdbc::Message::ParseSignalsStatus::Success); std::vector refData{47, 0, 1, 0, 32, 3, 0}; CHECK(refData.size() == 7); CHECK(out_values.size() == refData.size()); @@ -109,7 +109,7 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { SECTION("Evaluating third message") { std::vector out_values; - CHECK(parser.parseMessage(337, std::vector({57, 4, 250, 29, 0, 0, 0, 0}), out_values) == true); + CHECK(parser.parseMessage(337, std::vector({57, 4, 250, 29, 0, 0, 0, 0}), out_values) == libdbc::Message::ParseSignalsStatus::Success); std::vector refData{57, 0, 1, 0, 51, 3, 0}; CHECK(refData.size() == 7); CHECK(out_values.size() == refData.size()); From 4dc7dfe1d139eac201a6aa3499aaf013bcbb5fb3 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 28 Jan 2023 20:35:57 +0100 Subject: [PATCH 24/30] move parsing tests to test_parseMessage.cpp --- test/test_dbc.cpp | 44 -------------------------------------- test/test_parseMessage.cpp | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/test/test_dbc.cpp b/test/test_dbc.cpp index 2b9cd11..dd519eb 100644 --- a/test/test_dbc.cpp +++ b/test/test_dbc.cpp @@ -155,47 +155,3 @@ TEST_CASE("Special characters in unit") { REQUIRE(signal.unit.compare("Km/h") == 0); } } - -TEST_CASE("Parse Message little endian") { - const auto* filename = std::tmpnam(NULL); - - create_tmp_dbc_with(filename, R"(BO_ 541 STATUS: 8 DEVICE1 - SG_ Temperature : 48|16@1+ (0.01,-40) [-40|125] "C" DEVICE1 - SG_ SOH : 0|16@1+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOE : 32|16@1+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOC : 16|16@1+ (0.01,0) [0|100] "%" DEVICE1)"); - - libdbc::DbcParser p; - p.parse_file(filename); - - std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // little endian - std::vector result_values; - REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::Success); - REQUIRE(result_values.size() == 4); - REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); - REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); - REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); - REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); -} - -TEST_CASE("Parse Message big endian") { - const auto* filename = std::tmpnam(NULL); - create_tmp_dbc_with(filename, R"(BO_ 541 STATUS: 8 DEVICE1 - SG_ Temperature : 48|16@0+ (0.01,-40) [-40|125] "C" DEVICE1 - SG_ SOH : 0|16@0+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOE : 32|16@0+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOC : 16|16@0+ (0.01,0) [0|100] "%" DEVICE1)"); - - libdbc::DbcParser p; - p.parse_file(filename); - - std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // big endian - std::vector result_values; - REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); - // Big endian not yet supported -// REQUIRE(result_values.size() == 4); -// REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); -// REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); -// REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); -// REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); -} diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp index 1a9380d..26ed784 100644 --- a/test/test_parseMessage.cpp +++ b/test/test_parseMessage.cpp @@ -119,4 +119,48 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { } } +TEST_CASE("Parse Message little endian") { + const auto* filename = std::tmpnam(NULL); + + create_tmp_dbc_with(filename, R"(BO_ 541 STATUS: 8 DEVICE1 + SG_ Temperature : 48|16@1+ (0.01,-40) [-40|125] "C" DEVICE1 + SG_ SOH : 0|16@1+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOE : 32|16@1+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOC : 16|16@1+ (0.01,0) [0|100] "%" DEVICE1)"); + + libdbc::DbcParser p; + p.parse_file(filename); + + std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // little endian + std::vector result_values; + REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::Success); + REQUIRE(result_values.size() == 4); + REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); + REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); + REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); + REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); +} + +TEST_CASE("Parse Message big endian") { + const auto* filename = std::tmpnam(NULL); + create_tmp_dbc_with(filename, R"(BO_ 541 STATUS: 8 DEVICE1 + SG_ Temperature : 48|16@0+ (0.01,-40) [-40|125] "C" DEVICE1 + SG_ SOH : 0|16@0+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOE : 32|16@0+ (0.01,0) [0|100] "%" DEVICE1 + SG_ SOC : 16|16@0+ (0.01,0) [0|100] "%" DEVICE1)"); + + libdbc::DbcParser p; + p.parse_file(filename); + + std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // big endian + std::vector result_values; + REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); + // Big endian not yet supported +// REQUIRE(result_values.size() == 4); +// REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); +// REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); +// REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); +// REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); +} + // TODO: create also for big endian! From e9e307e8901e21ee8255b0a7b40ae295a4a33e58 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sat, 28 Jan 2023 20:37:38 +0100 Subject: [PATCH 25/30] sort signals otherwise they do not match with the test results --- test/test_parseMessage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp index 26ed784..8a16a75 100644 --- a/test/test_parseMessage.cpp +++ b/test/test_parseMessage.cpp @@ -130,6 +130,7 @@ TEST_CASE("Parse Message little endian") { libdbc::DbcParser p; p.parse_file(filename); + p.sortSignals(); std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // little endian std::vector result_values; From c4d55afc04fce12535b26d406122083559d7f580 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 8 Feb 2023 14:48:43 +0100 Subject: [PATCH 26/30] add support for big endian --- include/libdbc/dbc.hpp | 2 - include/libdbc/message.hpp | 25 +++-------- src/dbc.cpp | 9 ---- src/message.cpp | 66 +++++++-------------------- test/test_parseMessage.cpp | 91 ++++++++++++++------------------------ 5 files changed, 57 insertions(+), 136 deletions(-) diff --git a/include/libdbc/dbc.hpp b/include/libdbc/dbc.hpp index 2c62f58..3b23147 100644 --- a/include/libdbc/dbc.hpp +++ b/include/libdbc/dbc.hpp @@ -35,8 +35,6 @@ namespace libdbc { std::vector get_messages() const; Message::ParseSignalsStatus parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values); - Message::ParseSignalsStatus parseMessage(const uint32_t id, const std::array& data, std::vector& out_values); - void sortSignals(); private: diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index 2e607c7..69e0cbd 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -13,10 +13,11 @@ namespace libdbc { explicit Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node); enum class ParseSignalsStatus { - Success = 0, - ErrorMessageToLong = -1, - ErrorBigEndian = -2, - ErrorUnknownID = -3, + Success, + ErrorMessageToLong, + ErrorBigEndian, + ErrorUnknownID, + ErrorInvalidConversion, }; /*! @@ -26,8 +27,6 @@ namespace libdbc { * \return */ ParseSignalsStatus parseSignals(const std::vector& data, std::vector &values) const; - ParseSignalsStatus parseSignals(const std::array& data, std::vector& values) const; - ParseSignalsStatus parseSignals(const uint8_t* data, int size, std::vector& values) const; void appendSignal(const Signal& signal); const std::vector signals() const; @@ -46,19 +45,7 @@ namespace libdbc { std::string m_name; uint8_t m_size; std::string m_node; - std::vector m_signals; // when changing this vector m_prepared must be set to false! - - - bool m_prepared{false}; // indicates if the message is prepared for parsing signals - struct BitStruct { - BitStruct(uint32_t size): size(size), padding(true) {} - BitStruct(int index, uint32_t size): index(index), size(size), padding(false) {} - BitStruct() = delete; - int index; - uint32_t size; - bool padding; - }; - std::vector bitstruct; + std::vector m_signals; friend std::ostream& operator<<(std::ostream& os, const Message& dt); }; diff --git a/src/dbc.cpp b/src/dbc.cpp index e21e302..f382dfe 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -103,15 +103,6 @@ namespace libdbc { return Message::ParseSignalsStatus::ErrorUnknownID; } - Message::ParseSignalsStatus DbcParser::parseMessage(const uint32_t id, const std::array& data, std::vector& 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; std::smatch match; diff --git a/src/message.cpp b/src/message.cpp index 67be25e..8953cb9 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -12,27 +12,16 @@ namespace libdbc { (m_size == rhs.m_size) && (m_node == rhs.m_node); } - Message::ParseSignalsStatus Message::parseSignals(const uint8_t* data, int size, std::vector& values) const { - // With the current approach it is not needed to prepare the message by sorting the signals -// if (!m_prepared) -// return false; - + Message::ParseSignalsStatus Message::parseSignals(const std::vector& data, std::vector& values) const { + int size = data.size(); if (size > 8) return ParseSignalsStatus::ErrorMessageToLong; // not supported yet - // Currently only little endian will be supported, because - // The code below was not tested with bigendian! - // All signals must be little endian - for (const auto& signal: m_signals) { - if (signal.is_bigendian) - return ParseSignalsStatus::ErrorBigEndian; - } - 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 |= (uint64_t)data[i] << (size - 1 - i); + data_big_endian = (data_big_endian << 8) | (uint64_t)data[i]; } // TODO: does this also work on a big endian machine? @@ -41,30 +30,30 @@ namespace libdbc { uint64_t v = 0; for (const auto& signal: m_signals) { if (signal.is_bigendian) { - // Not tested! - // const uint32_t shiftLeft = signal.start_bit; - // v = data_big_endian << shiftLeft; - // v = v >> (shiftLeft + signal.start_bit); + 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); } - values.push_back(v * signal.factor + signal.offset); + + 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; } - Message::ParseSignalsStatus Message::parseSignals(const std::array& data, std::vector& values) const { - return parseSignals(data.data(), data.size(), values); - } - - Message::ParseSignalsStatus Message::parseSignals(const std::vector &data, std::vector& values) const { - return parseSignals(data.data(), data.size(), values); - } - void Message::appendSignal(const Signal& signal) { - m_prepared = false; m_signals.push_back(signal); } @@ -77,28 +66,7 @@ namespace libdbc { } void Message::prepareMessage() { -// m_prepared = false; -// // sort signals so that the signals are ordered by the startbit std::sort(m_signals.begin(), m_signals.end()); - -// uint32_t curr_bit = 0; -// for (std::vector::size_type i=0; i < m_signals.size(); i++) { -// const auto& signal = m_signals.at(i); -// if (signal.is_multiplexed) -// break; // Not supported yet - -// if (curr_bit < signal.start_bit) { -// // padding needed -// bitstruct.push_back(BitStruct(signal.start_bit - curr_bit)); -// } -// bitstruct.push_back(BitStruct(i, signal.size)); -// curr_bit = signal.start_bit + signal.size; -// } -// // Check if correct -// if (curr_bit > m_size * 8) -// return; - - m_prepared = true; } std::ostream& operator<< (std::ostream &out, const Message& msg) { diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp index 8a16a75..33a2ae6 100644 --- a/test/test_parseMessage.cpp +++ b/test/test_parseMessage.cpp @@ -8,31 +8,7 @@ // Testing of parsing messages -TEST_CASE("Parse Message 1 Big Endian") { - libdbc::DbcParser parser; - - const auto dbcContent = R"(BO_ 234 MSG1: 8 Vector__XXX - SG_ Sig1 : 0|8@0- (0.1,-3) [-3276.8|-3276.7] "C" Vector__XXX - SG_ Sig2 : 8|8@0- (0.15,7) [-3276.8|-3276.7] "C" Vector__XXX -)"; - - const auto* filename = std::tmpnam(NULL); - CHECK(create_tmp_dbc_with(filename, dbcContent)); - - parser.parse_file(filename); - - SECTION("Evaluating first message") { - std::vector out_values; - CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); - // Big endian not supported -// CHECK(out_values.size() == 2); -// CHECK(out_values.at(0) == 0x01 * 0.1 - 3); -// CHECK(out_values.at(1) == 0x02 * 0.15 + 7); - } - -} - -TEST_CASE("Parse Message 2 Big Endian") { +TEST_CASE("Parse Message Unknown ID") { libdbc::DbcParser parser; const auto dbcContent = R"(BO_ 234 MSG1: 8 Vector__XXX @@ -48,18 +24,6 @@ BO_ 123 MSG2: 8 Vector__XXX parser.parse_file(filename); - SECTION("Evaluating first message") { - std::vector out_values; - CHECK(parser.parseMessage(234, std::vector({0x01, 0x02}), out_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); - // Big endian not supported -// std::vector refData{0x01, 0x02}; -// CHECK(refData.size() == 2); -// CHECK(out_values.size() == refData.size()); -// for (int i=0; i < refData.size(); i++) { -// CHECK(out_values.at(i) == refData.at(i)); -// } - } - SECTION("Evaluating unknown message id") { std::vector out_values; CHECK(parser.parseMessage(578, std::vector({0xFF, 0xA2}), out_values) == libdbc::Message::ParseSignalsStatus::ErrorUnknownID); @@ -130,38 +94,51 @@ TEST_CASE("Parse Message little endian") { libdbc::DbcParser p; p.parse_file(filename); - p.sortSignals(); std::vector data{0x08, 0x27, 0xa3, 0x22, 0xe5, 0x1f, 0x45, 0x14}; // little endian std::vector result_values; REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::Success); REQUIRE(result_values.size() == 4); - REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); - REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); + + REQUIRE(Catch::Approx(result_values.at(0)) == 11.89); + REQUIRE(Catch::Approx(result_values.at(1)) == 99.92); REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); - REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); + REQUIRE(Catch::Approx(result_values.at(3)) == 88.67); } -TEST_CASE("Parse Message big endian") { +TEST_CASE("Parse Message big endian signed values") { const auto* filename = std::tmpnam(NULL); - create_tmp_dbc_with(filename, R"(BO_ 541 STATUS: 8 DEVICE1 - SG_ Temperature : 48|16@0+ (0.01,-40) [-40|125] "C" DEVICE1 - SG_ SOH : 0|16@0+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOE : 32|16@0+ (0.01,0) [0|100] "%" DEVICE1 - SG_ SOC : 16|16@0+ (0.01,0) [0|100] "%" DEVICE1)"); + create_tmp_dbc_with(filename, R"(BO_ 545 MSG: 8 BMS2 + SG_ Sig1 : 62|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig2 : 49|2@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig3 : 39|16@0- (0.1,0) [0|0] "A" Vector__XXX + SG_ Sig4 : 60|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig5 : 55|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig6 : 58|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig7 : 59|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig8 : 57|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig9 : 56|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig10 : 61|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ Sig11 : 7|16@0+ (0.001,0) [0|65.535] "V" Vector__XXX + SG_ Sig12 : 23|16@0+ (0.1,0) [0|6553.5] "A" Vector__XXX)"); libdbc::DbcParser p; p.parse_file(filename); - std::vector data{0x27, 0x08, 0x22, 0xa3, 0x1f, 0xe5, 0x14, 0x45}; // big endian + std::vector data{13, 177, 0, 216, 251, 180, 0, 31}; // big endian std::vector result_values; - REQUIRE(p.parseMessage(0x21d, data, result_values) == libdbc::Message::ParseSignalsStatus::ErrorBigEndian); - // Big endian not yet supported -// REQUIRE(result_values.size() == 4); -// REQUIRE(Catch::Approx(result_values.at(0)) == 99.92); -// REQUIRE(Catch::Approx(result_values.at(1)) == 88.67); -// REQUIRE(Catch::Approx(result_values.at(2)) == 81.65); -// REQUIRE(Catch::Approx(result_values.at(3)) == 11.89); + REQUIRE(p.parseMessage(545, data, result_values) == libdbc::Message::ParseSignalsStatus::Success); + REQUIRE(result_values.size() == 12); + REQUIRE(Catch::Approx(result_values.at(0)) == 0); + REQUIRE(Catch::Approx(result_values.at(1)) == 0); + REQUIRE(Catch::Approx(result_values.at(2)) == -110); + REQUIRE(Catch::Approx(result_values.at(3)) == 1); + REQUIRE(Catch::Approx(result_values.at(4)) == 0); + REQUIRE(Catch::Approx(result_values.at(5)) == 1); + REQUIRE(Catch::Approx(result_values.at(6)) == 1); + REQUIRE(Catch::Approx(result_values.at(7)) == 1); + REQUIRE(Catch::Approx(result_values.at(8)) == 1); + REQUIRE(Catch::Approx(result_values.at(9)) == 0); + REQUIRE(Catch::Approx(result_values.at(10)) == 3.5050); + REQUIRE(Catch::Approx(result_values.at(11)) == 21.6); } - -// TODO: create also for big endian! From f65b85be5e79ce8bc040ebacbd118d0be1eb3e80 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 8 Feb 2023 14:55:44 +0100 Subject: [PATCH 27/30] sorting not needed anymore --- include/libdbc/dbc.hpp | 1 - include/libdbc/message.hpp | 6 ------ src/dbc.cpp | 6 ------ src/message.cpp | 4 ---- test/test_parseMessage.cpp | 8 ++++---- 5 files changed, 4 insertions(+), 21 deletions(-) diff --git a/include/libdbc/dbc.hpp b/include/libdbc/dbc.hpp index 3b23147..7fd3200 100644 --- a/include/libdbc/dbc.hpp +++ b/include/libdbc/dbc.hpp @@ -35,7 +35,6 @@ namespace libdbc { std::vector get_messages() const; Message::ParseSignalsStatus parseMessage(const uint32_t id, const std::vector& data, std::vector& out_values); - void sortSignals(); private: std::string version; diff --git a/include/libdbc/message.hpp b/include/libdbc/message.hpp index 69e0cbd..12ab43c 100644 --- a/include/libdbc/message.hpp +++ b/include/libdbc/message.hpp @@ -32,12 +32,6 @@ namespace libdbc { const std::vector signals() const; uint32_t id() const; - /*! - * \brief prepareMessage - * Preparing message to be able to parse signals afterwards. This speeds up parsing - */ - void prepareMessage(); - virtual bool operator==(const Message& rhs) const; private: diff --git a/src/dbc.cpp b/src/dbc.cpp index f382dfe..0097aae 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -77,12 +77,6 @@ namespace libdbc { parse_dbc_messages(lines); } - void DbcParser::sortSignals() { - for (auto& message: messages) { - message.prepareMessage(); - } - } - std::string DbcParser::get_version() const { return version; } diff --git a/src/message.cpp b/src/message.cpp index 8953cb9..d4dee8f 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -65,10 +65,6 @@ namespace libdbc { return m_id; } - void Message::prepareMessage() { - std::sort(m_signals.begin(), m_signals.end()); - } - std::ostream& operator<< (std::ostream &out, const Message& msg) { out << "Message: {id: " << msg.id() << ", "; out << "name: " << msg.m_name << ", "; diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp index 33a2ae6..15da258 100644 --- a/test/test_parseMessage.cpp +++ b/test/test_parseMessage.cpp @@ -47,12 +47,12 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { CHECK(create_tmp_dbc_with(filename, dbcContent)); parser.parse_file(filename); - parser.sortSignals(); SECTION("Evaluating first message") { std::vector out_values; CHECK(parser.parseMessage(337, std::vector({0, 4, 252, 19, 0, 0, 0, 0}), out_values) == libdbc::Message::ParseSignalsStatus::Success); - std::vector refData{0, 0, 1, 0, 0, 2, 0}; + //std::vector refData{0, 0, 1, 0, 0, 2, 0}; + std::vector refData{2, 0, 0, 1, 0, 0, 0}; CHECK(refData.size() == 7); CHECK(out_values.size() == refData.size()); for (int i=0; i < refData.size(); i++) { @@ -63,7 +63,7 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { SECTION("Evaluating second message") { std::vector out_values; CHECK(parser.parseMessage(337, std::vector({47, 4, 60, 29, 0, 0, 0, 0}), out_values) == libdbc::Message::ParseSignalsStatus::Success); - std::vector refData{47, 0, 1, 0, 32, 3, 0}; + std::vector refData{3, 32, 0, 1, 0, 0, 47}; CHECK(refData.size() == 7); CHECK(out_values.size() == refData.size()); for (int i=0; i < refData.size(); i++) { @@ -74,7 +74,7 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { SECTION("Evaluating third message") { std::vector out_values; CHECK(parser.parseMessage(337, std::vector({57, 4, 250, 29, 0, 0, 0, 0}), out_values) == libdbc::Message::ParseSignalsStatus::Success); - std::vector refData{57, 0, 1, 0, 51, 3, 0}; + std::vector refData{3, 51, 0, 1, 0, 0, 57}; CHECK(refData.size() == 7); CHECK(out_values.size() == refData.size()); for (int i=0; i < refData.size(); i++) { From 70d8510f0b6e06e69dc1a16ed375f83ace929545 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 8 Feb 2023 15:37:08 +0100 Subject: [PATCH 28/30] remove comment --- test/test_parseMessage.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_parseMessage.cpp b/test/test_parseMessage.cpp index 15da258..5543578 100644 --- a/test/test_parseMessage.cpp +++ b/test/test_parseMessage.cpp @@ -51,7 +51,6 @@ TEST_CASE("Parse Message Big Number not aligned little endian") { SECTION("Evaluating first message") { std::vector out_values; CHECK(parser.parseMessage(337, std::vector({0, 4, 252, 19, 0, 0, 0, 0}), out_values) == libdbc::Message::ParseSignalsStatus::Success); - //std::vector refData{0, 0, 1, 0, 0, 2, 0}; std::vector refData{2, 0, 0, 1, 0, 0, 0}; CHECK(refData.size() == 7); CHECK(out_values.size() == refData.size()); From 117deb6710bee8944c2ad37c425be5447585c4fa Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 8 Feb 2023 18:28:54 +0100 Subject: [PATCH 29/30] bitstream not needed anymore --- CMakeLists.txt | 4 +--- src/message.cpp | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a309217..0522203 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,8 +44,6 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}") -add_subdirectory(third_party/bitstream) - # add where to find the source files # file(GLOB_RECURSE SOURCE ${PROJECT_SOURCE_DIR}/src/ *.cpp) list(APPEND SOURCE ${PROJECT_SOURCE_DIR}/src/utils.cpp @@ -72,7 +70,7 @@ endif() add_subdirectory(doc) add_library(${PROJECT_NAME} STATIC ${SOURCE}) -target_link_libraries(${PROJECT_NAME} bitstream FastFloat::fast_float) +target_link_libraries(${PROJECT_NAME} FastFloat::fast_float) if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23) target_sources(${PROJECT_NAME} INTERFACE FILE_SET HEADERS diff --git a/src/message.cpp b/src/message.cpp index d4dee8f..73abf8e 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -1,8 +1,6 @@ #include #include -#include - namespace libdbc { Message::Message(uint32_t id, const std::string& name, uint8_t size, const std::string& node) : m_id(id), m_name(name), m_size(size), m_node(node) {} From b7d7585939743c24a074ed2f75d39d9496772c31 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 9 Feb 2023 19:24:45 +0100 Subject: [PATCH 30/30] Description: add missing from start, so it only searches from there Reason: otherwise it might search through the complete string to find a match Files: dbc.cpp --- src/dbc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbc.cpp b/src/dbc.cpp index 0097aae..d0646c8 100644 --- a/src/dbc.cpp +++ b/src/dbc.cpp @@ -34,7 +34,7 @@ namespace libdbc { 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 +