#include "dbc_decoder.h" #include #include #include struct DecodeCase { const char *name; ByteOrder byteOrder; std::uint32_t startBit; std::uint32_t length; ValueType valueType; std::vector data; bool valid; std::int64_t rawValue; double factor; double offset; double physicalValue; }; int main() { const DecodeCase cases[] = { {"Motorola reproduction", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, {"Motorola within byte", ByteOrder::Motorola, 5U, 4U, ValueType::Unsigned, {0xAC}, true, 11, 1.0, 0.0, 11.0}, {"Motorola unaligned crossing", ByteOrder::Motorola, 3U, 12U, ValueType::Unsigned, {0xAB, 0xCD}, true, 0xBCD, 1.0, 0.0, 3021.0}, {"Motorola starts at bit zero", ByteOrder::Motorola, 0U, 2U, ValueType::Unsigned, {0x01, 0x80}, true, 3, 1.0, 0.0, 3.0}, {"Motorola second byte", ByteOrder::Motorola, 15U, 16U, ValueType::Unsigned, {0xFF, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, {"Motorola signed scaled", ByteOrder::Motorola, 7U, 16U, ValueType::Signed, {0xFF, 0xFE}, true, -2, 0.5, 10.0, 9.0}, {"Motorola 64 bits", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0, 0, 0, 0, 0, 0, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, {"Motorola 64 bits high bit", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0x40, 0, 0, 0, 0, 0, 0, 0}, true, 0x4000000000000000LL, 1.0, 0.0, 4611686018427387904.0}, {"Motorola short payload", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0}, {"Motorola empty payload", ByteOrder::Motorola, 7U, 8U, ValueType::Unsigned, {}, false, 0, 1.0, 0.0, 0.0}, {"Motorola large start", ByteOrder::Motorola, std::numeric_limits::max(), 8U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0}, {"Motorola zero length", ByteOrder::Motorola, 7U, 0U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0}, {"Motorola excessive length", ByteOrder::Motorola, 7U, 65U, ValueType::Unsigned, std::vector(9U, 0xFF), false, 0, 1.0, 0.0, 0.0}, {"Intel regression", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x3412, 1.0, 0.0, 13330.0}, {"Intel signed regression", ByteOrder::Intel, 0U, 16U, ValueType::Signed, {0xFE, 0xFF}, true, -2, 0.5, 10.0, 9.0}, {"Intel short payload", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0}}; int failures = 0; for (const DecodeCase &test: cases) { DecodeSignal signal; signal.name = test.name; signal.byteOrder = test.byteOrder; signal.startBit = test.startBit; signal.length = test.length; signal.valueType = test.valueType; signal.factor = test.factor; signal.offset = test.offset; DecodeFrame definition; definition.canId = 0x123U; definition.dlc = static_cast(test.data.size()); definition.signals.push_back(signal); DecodeDatabase database; database.frames.push_back(definition); database.frameIndexByKey.emplace(FrameKey(definition.canId, false), 0U); RawCanFrame frame; frame.canId = definition.canId; frame.data = test.data; const DecodedFrameValue result = DbcDecoder().Decode(database, frame); const bool passed = result.valid && (result.definition == &database.frames[0]) && (result.signals.size() == 1U) && (result.signals[0].definition == &database.frames[0].signals[0]) && (result.signals[0].valid == test.valid) && (!test.valid || (((test.valueType == ValueType::Signed) ? (std::get_if(&result.signals[0].rawValue) && std::get(result.signals[0].rawValue) == test.rawValue) : (std::get_if(&result.signals[0].rawValue) && std::get(result.signals[0].rawValue) == static_cast(test.rawValue))) && (result.signals[0].physicalValue == test.physicalValue))); if (!passed) { std::cerr << "FAIL: " << test.name << '\n'; ++failures; } } std::size_t boundaryCases = 0U; for (ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) { for (ValueType type: {ValueType::Unsigned, ValueType::Signed}) { for (std::uint64_t bits: {std::uint64_t(0U), std::uint64_t(0x7FFFFFFFFFFFFFFFULL), std::uint64_t(0x8000000000000000ULL), std::uint64_t(0x8000000000000001ULL), std::uint64_t(0xFFFFFFFFFFFFFFFFULL)}) { DecodeDatabase database; DecodeFrame definition; DecodeSignal signal; signal.startBit = order == ByteOrder::Intel ? 0U : 7U; signal.length = 64U; signal.byteOrder = order; signal.valueType = type; signal.factor = 0.5; signal.offset = 10.0; definition.signals.push_back(signal); database.frames.push_back(definition); database.frameIndexByKey.emplace(FrameKey(0U, false), 0U); RawCanFrame frame; for (unsigned byte = 0U; byte < 8U; ++byte) { const unsigned shift = (order == ByteOrder::Intel ? byte : 7U - byte) * 8U; frame.data.push_back(static_cast(bits >> shift)); } const auto result = DbcDecoder().Decode(database, frame); const std::int64_t signedExpected = bits <= 0x7FFFFFFFFFFFFFFFULL ? static_cast(bits) : std::numeric_limits::min() + static_cast(bits - 0x8000000000000000ULL); const auto &decoded = result.signals.at(0U); const auto expected = type == ValueType::Unsigned ? std::variant(bits) : std::variant(signedExpected); const double physical = (type == ValueType::Unsigned ? static_cast(bits) : static_cast(signedExpected)) * 0.5 + 10.0; std::ostringstream actualText; std::ostringstream expectedText; std::visit([&actualText](auto raw) { actualText << raw; }, decoded.rawValue); if (type == ValueType::Unsigned) expectedText << bits; else expectedText << signedExpected; if (!decoded.valid || decoded.rawValue != expected || decoded.physicalValue != physical || actualText.str() != expectedText.str()) { std::cerr << "FAIL: 64-bit boundary " << bits << '\n'; ++failures; } ++boundaryCases; } } } if (failures != 0) return 1; std::cout << "All " << sizeof(cases) / sizeof(cases[0]) + boundaryCases << " decoder cases passed.\n"; return 0; }