Skip to content

Parse non byte aligned number #17

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Aug 1, 2023
Merged
23 changes: 15 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ include(CPack)

option(DEBUG "use debug flag" NO)
option(ENABLE_TESTS "Enable Unittests" ON)
# Turn OFF, if you are using FetchContent to include it to your project
option(FETCH_CONTENT_INCLUSION "Include project with FetchContent_Declare in another project. In this case the headers and the cmake files are not needed, only the library" OFF)

# defines variables used in the dbc.pc.in
include(GNUInstallDirs)
Expand All @@ -30,7 +32,9 @@ if (NOT ${FastFloat_FOUND})
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
GIT_TAG 1ea4f27b2aeee2859a1354a3c24cff52a116cad1
)
FetchContent_MakeAvailable(FastFloat)
# FetchContent_MakeAvailable(FastFloat)
FetchContent_Populate(FastFloat)
add_subdirectory(${fastfloat_SOURCE_DIR} ${fastfloat_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()

set(GCC_COMPILE_FLAGS "-Wextra -Wall -Wfloat-equal -Wundef -Wshadow \
Expand Down Expand Up @@ -92,18 +96,21 @@ install(TARGETS ${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR})

# install headers
if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23)
if (${CMAKE_MINOR_VERSION} GREATER_EQUAL 23 AND NOT FETCH_CONTENT_INCLUSION)
install(TARGETS ${PROJECT_NAME}
FILE_SET HEADERS
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lib${PROJECT_NAME}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
else()
elseif(NOT FETCH_CONTENT_INCLUSION)
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)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

if (NOT FETCH_CONTENT_INCLUSION)
# Generate pkg-config file
configure_file(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif()
3 changes: 3 additions & 0 deletions include/libdbc/message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ struct Message {
void appendSignal(const Signal& signal);
const std::vector<Signal> getSignals() const;
uint32_t id() const;
const std::string& name() const {
return m_name;
}
void addValueDescription(const std::string& signal_name, const std::vector<Signal::SignalValueDescriptions>&);

virtual bool operator==(const Message& rhs) const;
Expand Down
1 change: 1 addition & 0 deletions include/libdbc/signal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#ifndef __SIGNAL_HPP__
#define __SIGNAL_HPP__

#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
Expand Down
25 changes: 17 additions & 8 deletions src/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,8 @@ Message::ParseSignalsStatus Message::parseSignals(const std::vector<uint8_t>& da
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);
}
} else
v = data_little_endian >> signal.start_bit;

if (signal.is_signed && signal.size > 1) {
switch (signal.size) {
Expand All @@ -54,11 +51,23 @@ Message::ParseSignalsStatus Message::parseSignals(const std::vector<uint8_t>& da
case 64:
values.push_back((int64_t)v * signal.factor + signal.offset);
break;
default:
return ParseSignalsStatus::ErrorInvalidConversion;
default: {
// 2 complement -> decimal
const int negative = (v & (1 << (signal.size - 1))) != 0;
int64_t nativeInt;
if (negative)
nativeInt = v | ~((1 << signal.size) - 1); // invert all bits above signal.size
else
nativeInt = v & ((1 << signal.size) - 1); // masking
values.push_back(nativeInt * signal.factor + signal.offset);
break;
}
} else
}
} else {
// use only the relevant bits
v = v & ((1 << signal.size) - 1); // masking
values.push_back(v * signal.factor + signal.offset);
}
}
return ParseSignalsStatus::Success;
}
Expand Down
10 changes: 9 additions & 1 deletion test/test_dbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ TEST_CASE("Testing big endian, little endian") {
parser.parse_file(filename);

REQUIRE(parser.get_messages().size() == 1);
REQUIRE(parser.get_messages().at(0).name() == "MSG1");
REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);
{
const auto signal = parser.get_messages().at(0).getSignals().at(0);
Expand All @@ -104,6 +105,7 @@ TEST_CASE("Testing negative values") {
parser.parse_file(filename);

REQUIRE(parser.get_messages().size() == 1);
REQUIRE(parser.get_messages().at(0).name() == "MSG1");
REQUIRE(parser.get_messages().at(0).getSignals().size() == 4);

SECTION("Evaluating first message") {
Expand Down Expand Up @@ -146,6 +148,7 @@ TEST_CASE("Special characters in unit") {
parser.parse_file(filename);

REQUIRE(parser.get_messages().size() == 1);
REQUIRE(parser.get_messages().at(0).name() == "MSG1");
REQUIRE(parser.get_messages().at(0).getSignals().size() == 1);
SECTION("Checking that signal with special characters as unit is parsed correctly") {
const auto signal = parser.get_messages().at(0).getSignals().at(0);
Expand All @@ -165,6 +168,7 @@ VAL_ 234 State1 123 "Description 1" 0 "Description 2" 90903489 "Big value and sp
parser.parse_file(filename);

REQUIRE(parser.get_messages().size() == 1);
REQUIRE(parser.get_messages().at(0).name() == "MSG1");
REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);

REQUIRE(parser.get_messages().at(0).getSignals().at(0).svDescriptions.size() == 3);
Expand Down Expand Up @@ -194,6 +198,7 @@ VAL_ 3221225472 State1 123 "Description 1" 0 "Description 2" 4000000000 "Big val
parser.parse_file(filename);

REQUIRE(parser.get_messages().size() == 1);
REQUIRE(parser.get_messages().at(0).name() == "MSG1");
REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);

REQUIRE(parser.get_messages().at(0).getSignals().at(0).svDescriptions.size() == 3);
Expand All @@ -217,7 +222,7 @@ TEST_CASE("Signal Value Multiple VAL_") {
create_tmp_dbc_with(filename, R"(BO_ 3221225472 MSG1: 8 Vector__XXX
SG_ State1 : 0|8@1+ (1,0) [0|200] "Km/h" DEVICE1,DEVICE2,DEVICE3
SG_ State2 : 0|8@1+ (1,0) [0|204] "" DEVICE1,DEVICE2,DEVICE3"
BO_ 123 MSG1: 8 Vector__XXX
BO_ 123 MSG2: 8 Vector__XXX
SG_ State1 : 0|8@1+ (1,0) [0|200] "Km/h" DEVICE1,DEVICE2,DEVICE3
SG_ State2 : 0|8@1+ (1,0) [0|204] "" DEVICE1,DEVICE2,DEVICE3
VAL_ 3221225472 State1 123 "Description 1" 0 "Description 2" ;
Expand All @@ -227,6 +232,9 @@ VAL_ 123 State1 123 "Description 3" 0 "Description 4" ;)");
parser.parse_file(filename);

REQUIRE(parser.get_messages().size() == 2);
REQUIRE(parser.get_messages().at(0).name() == "MSG1");
REQUIRE(parser.get_messages().at(1).name() == "MSG2");

REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);

REQUIRE(parser.get_messages().at(0).getSignals().at(0).svDescriptions.size() == 2);
Expand Down
38 changes: 38 additions & 0 deletions test/test_parseMessage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,41 @@ TEST_CASE("Parse Message big endian signed values") {
REQUIRE(Catch::Approx(result_values.at(10)) == 3.5050);
REQUIRE(Catch::Approx(result_values.at(11)) == 21.6);
}

TEST_CASE("Parse Message with non byte aligned values") {
const auto* filename = std::tmpnam(NULL);
create_tmp_dbc_with(filename, R"(BO_ 403 INFORMATION: 8 Vector__XXX
SG_ Voltage : 30|9@1+ (0.2,0) [0|102.2] "V" Vector__XXX
SG_ Phase_Current : 20|10@1- (1,0) [-512|512] "A" Vector__XXX
SG_ Iq_Current : 10|10@1- (1,0) [-512|512] "A" Vector__XXX
SG_ Id_Current : 0|10@1- (1,0) [-512|512] "A" Vector__XXX)");

libdbc::DbcParser p;
p.parse_file(filename);

std::vector<uint8_t> data{131, 51, 33, 9, 33, 0, 0, 0};
std::vector<double> result_values;
REQUIRE(p.parseMessage(403, data, result_values) == libdbc::Message::ParseSignalsStatus::Success);
REQUIRE(result_values.size() == 4);
REQUIRE(Catch::Approx(result_values.at(0)) == 26.4);
REQUIRE(Catch::Approx(result_values.at(1)) == 146);
REQUIRE(Catch::Approx(result_values.at(2)) == 76);
REQUIRE(Catch::Approx(result_values.at(3)) == -125);
}

TEST_CASE("Parse Message data length < 8 unsigned") {
const auto* filename = std::tmpnam(NULL);
create_tmp_dbc_with(filename, R"(BO_ 234 MSG1: 8 Vector__XXX
SG_ Msg1Sig1 : 7|8@0+ (1,0) [-3276.8|-3276.7] "C" Vector__XXX
SG_ Msg1Sig2 : 15|8@0+ (1,0) [-3276.8|-3276.7] "km/h" Vector__XXX)");

libdbc::DbcParser p;
p.parse_file(filename);

std::vector<uint8_t> data{0x1, 0x2};
std::vector<double> result_values;
REQUIRE(p.parseMessage(234, data, result_values) == libdbc::Message::ParseSignalsStatus::Success);
REQUIRE(result_values.size() == 2);
REQUIRE(Catch::Approx(result_values.at(0)) == 0x1);
REQUIRE(Catch::Approx(result_values.at(1)) == 0x2);
}