#include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../include/sdv_test_macro.h" #include "../../../global/process_watchdog.h" #include "../global/ascformat/ascreader.cpp" #include "../global/ascformat/ascwriter.cpp" #include "../global/exec_dir_helper.h" #define CDataLink CAscReaderDataLink #define SObjectClassInstance_CDataLink SObjectClassInstance_CAscReaderDataLink #define g_CDataLink g_CAscReaderDataLink #undef CDataLink #undef SObjectClassInstance_CDataLink #undef g_CDataLink #define CDataLink CDbcStructDataLink #define SObjectClassInstance_CDataLink SObjectClassInstance_CDbcStructDataLink #define g_CDataLink g_CSbcStructDataLink #include "generated/dbc_struct_test/can_dl/datalink.cpp" #undef CDataLink #undef SObjectClassInstance_CDataLink #undef g_CDataLink #if defined(_WIN32) && defined(_UNICODE) extern "C" int wmain(int argc, wchar_t* argv[]) #else extern "C" int main(int argc, char* argv[]) #endif { CProcessWatchdog watchdog; testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } TEST(DbcUtilCanDLTest, Prerequisitives) { try { std::filesystem::remove(GetExecDirectory() / "asc_writer_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "asc_writer_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_asc.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); sdv::TInterfaceAccessPtr ptrDispatchService = sdv::core::GetObject("DataDispatchService"); EXPECT_TRUE(ptrDispatchService); sdv::TInterfaceAccessPtr ptrCanComObj = sdv::core::GetObject("CAN_Communication_Object"); EXPECT_TRUE(ptrCanComObj); appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, SpontaneousTransmitBigEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalBE1 = dispatch.AddPublisher("TestBE.SignalBE1"); EXPECT_TRUE(signalBE1); sdv::core::CSignal signalBE2 = dispatch.AddPublisher("TestBE.SignalBE2"); EXPECT_TRUE(signalBE2); sdv::core::CSignal signalBE3 = dispatch.AddPublisher("TestBE.SignalBE3"); EXPECT_TRUE(signalBE3); sdv::core::CSignal signalBE4 = dispatch.AddPublisher("TestBE.SignalBE4"); EXPECT_TRUE(signalBE4); sdv::core::CSignal signalBE5 = dispatch.AddPublisher("TestBE.SignalBE5"); EXPECT_TRUE(signalBE5); sdv::core::CSignal signalBE6 = dispatch.AddPublisher("TestBE.SignalBE6"); EXPECT_TRUE(signalBE6); appcontrol.SetRunningMode(); EXPECT_NO_THROW(signalBE1.Write(0xa)); EXPECT_NO_THROW(signalBE2.Write(0x5d)); EXPECT_NO_THROW(signalBE3.Write(0x31)); EXPECT_NO_THROW(signalBE4.Write(0x2d)); EXPECT_NO_THROW(signalBE5.Write(0x96)); EXPECT_NO_THROW(signalBE6.Write(0x33cc55aa)); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalBE1.Reset(); signalBE2.Reset(); signalBE3.Reset(); signalBE4.Reset(); signalBE5.Reset(); signalBE6.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0x6, {0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x6D, 0x96, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x6D, 0x96, 0x33, 0xCC, 0x55, 0xAA}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); EXPECT_EQ(prMsg.first.rguiData[7], sData.rguiData[7]); } } TEST(DbcUtilCanDLTest, SpontaneousTransmit64BitBigEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalInt64BE = dispatch.AddPublisher("TestInt64BE.SignalInt64BE"); EXPECT_TRUE(signalInt64BE); sdv::core::CSignal signalUint64BE = dispatch.AddPublisher("TestUint64BE.SignalUint64BE"); EXPECT_TRUE(signalUint64BE); sdv::core::CSignal signalScaleInt64BE = dispatch.AddPublisher("TestScale64BE.SignalScaleInt64BE"); EXPECT_TRUE(signalScaleInt64BE); appcontrol.SetRunningMode(); EXPECT_NO_THROW(signalInt64BE.Write(-6144092013047381999ll)); // 0xaabbccddeeff0011 EXPECT_NO_THROW(signalUint64BE.Write(0xaabbccddeeff0011)); EXPECT_NO_THROW(signalScaleInt64BE.Write(987.654321012)); // 0xE5F4C8F374 // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalInt64BE.Reset(); signalUint64BE.Reset(); signalScaleInt64BE.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xCB, {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11}}, { 0x67, {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11}}, { 0x1F7, {0x00, 0x00, 0x00, 0xE5, 0xF4, 0xC8, 0xF3, 0x74}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); EXPECT_EQ(prMsg.first.rguiData[7], sData.rguiData[7]); } } TEST(DbcUtilCanDLTest, ReceiveBigEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0x6, {0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x6D, 0x96, 0x00, 0x00, 0x00, 0x00}}, { 0x6, {0xA5, 0xDC, 0x6D, 0x96, 0x33, 0xCC, 0x55, 0xAA}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 8ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; sMsg.rguiData[7] = sData.rguiData[7]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; uint32_t rguiVal[6] = {}; size_t nCnt = 0; sdv::core::CSignal signalBE1 = dispatch.Subscribe("TestBE.SignalBE1", [&](sdv::any_t tVal) {rguiVal[0] = tVal; nCnt++; }); EXPECT_TRUE(signalBE1); sdv::core::CSignal signalBE2 = dispatch.Subscribe("TestBE.SignalBE2", [&](sdv::any_t tVal) {rguiVal[1] = tVal; nCnt++; }); EXPECT_TRUE(signalBE2); sdv::core::CSignal signalBE3 = dispatch.Subscribe("TestBE.SignalBE3", [&](sdv::any_t tVal) {rguiVal[2] = tVal; nCnt++; }); EXPECT_TRUE(signalBE3); sdv::core::CSignal signalBE4 = dispatch.Subscribe("TestBE.SignalBE4", [&](sdv::any_t tVal) {rguiVal[3] = tVal; nCnt++; }); EXPECT_TRUE(signalBE4); sdv::core::CSignal signalBE5 = dispatch.Subscribe("TestBE.SignalBE5", [&](sdv::any_t tVal) {rguiVal[4] = tVal; nCnt++; }); EXPECT_TRUE(signalBE5); sdv::core::CSignal signalBE6 = dispatch.Subscribe("TestBE.SignalBE6", [&](sdv::any_t tVal) {rguiVal[5] = tVal; nCnt++; }); EXPECT_TRUE(signalBE6); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); EXPECT_EQ(nCnt, 36u); EXPECT_EQ(rguiVal[0], 0xau); EXPECT_EQ(rguiVal[1], 0x5du); EXPECT_EQ(rguiVal[2], 0x31u); EXPECT_EQ(rguiVal[3], 0x2du); EXPECT_EQ(rguiVal[4], 0x96u); EXPECT_EQ(rguiVal[5], 0x33cc55aau); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalBE1.Reset(); signalBE2.Reset(); signalBE3.Reset(); signalBE4.Reset(); signalBE5.Reset(); signalBE6.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, Receive64BitBigEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xCB, {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11}}, { 0x67, {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11}}, { 0x1F7, {0x00, 0x00, 0x00, 0xE5, 0xF4, 0xC8, 0xF3, 0x74}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 8ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; sMsg.rguiData[7] = sData.rguiData[7]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; int64_t iInt64Val = 0; uint64_t uiUint64Val = 0u; double dScaleInt64Val = 0; sdv::core::CSignal signalInt64BE = dispatch.Subscribe("TestInt64BE.SignalInt64BE", [&](sdv::any_t tVal) {iInt64Val = tVal; }); EXPECT_TRUE(signalInt64BE); sdv::core::CSignal signalUint64BE = dispatch.Subscribe("TestUint64BE.SignalUint64BE", [&](sdv::any_t tVal) {uiUint64Val = tVal; }); EXPECT_TRUE(signalUint64BE); sdv::core::CSignal signalScaleInt64BE = dispatch.Subscribe("TestScale64BE.SignalScaleInt64BE", [&](sdv::any_t tVal) {dScaleInt64Val = tVal; }); EXPECT_TRUE(signalScaleInt64BE); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); EXPECT_EQ(iInt64Val, -6144092013047381999ll); EXPECT_EQ(uiUint64Val, 0xaabbccddeeff0011); EXPECT_EQ(round(dScaleInt64Val * 1e8), round(987.654321012 * 1e8)); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalInt64BE.Reset(); signalUint64BE.Reset(); signalScaleInt64BE.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, SpontaneousTransmitLittleEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalLE1 = dispatch.AddPublisher("TestLE.SignalLE1"); EXPECT_TRUE(signalLE1); sdv::core::CSignal signalLE2 = dispatch.AddPublisher("TestLE.SignalLE2"); EXPECT_TRUE(signalLE2); sdv::core::CSignal signalLE3 = dispatch.AddPublisher("TestLE.SignalLE3"); EXPECT_TRUE(signalLE3); sdv::core::CSignal signalLE4 = dispatch.AddPublisher("TestLE.SignalLE4"); EXPECT_TRUE(signalLE4); sdv::core::CSignal signalLE5 = dispatch.AddPublisher("TestLE.SignalLE5"); EXPECT_TRUE(signalLE5); sdv::core::CSignal signalLE6 = dispatch.AddPublisher("TestLE.SignalLE6"); EXPECT_TRUE(signalLE6); appcontrol.SetRunningMode(); EXPECT_NO_THROW(signalLE1.Write(0xa)); EXPECT_NO_THROW(signalLE2.Write(0x5d)); EXPECT_NO_THROW(signalLE3.Write(0x31)); EXPECT_NO_THROW(signalLE4.Write(0x2d)); EXPECT_NO_THROW(signalLE5.Write(0x96)); EXPECT_NO_THROW(signalLE6.Write(0x33cc55aa)); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalLE1.Reset(); signalLE2.Reset(); signalLE3.Reset(); signalLE4.Reset(); signalLE5.Reset(); signalLE6.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0x7, {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0xB7, 0x96, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0xB7, 0x96, 0xAA, 0x55, 0xCC, 0x33}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); EXPECT_EQ(prMsg.first.rguiData[7], sData.rguiData[7]); } } TEST(DbcUtilCanDLTest, SpontaneousTransmit64BitLittleEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalInt64LE = dispatch.AddPublisher("TestInt64LE.SignalInt64LE"); EXPECT_TRUE(signalInt64LE); sdv::core::CSignal signalUint64LE = dispatch.AddPublisher("TestUint64LE.SignalUint64LE"); EXPECT_TRUE(signalUint64LE); sdv::core::CSignal signalScaleInt64LE = dispatch.AddPublisher("TestScale64LE.SignalScaleInt64LE"); EXPECT_TRUE(signalScaleInt64LE); appcontrol.SetRunningMode(); EXPECT_NO_THROW(signalInt64LE.Write(-6144092013047381999ll)); // 0xaabbccddeeff0011 EXPECT_NO_THROW(signalUint64LE.Write(0xaabbccddeeff0011)); EXPECT_NO_THROW(signalScaleInt64LE.Write(987.654321012)); // 0xE5F4C8F374 // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalInt64LE.Reset(); signalUint64LE.Reset(); signalScaleInt64LE.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xCA, {0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA}}, { 0x66, {0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA}}, { 0x1F6, {0x74, 0xF3, 0xC8, 0xF4, 0xE5, 0x00, 0x00, 0x00}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); EXPECT_EQ(prMsg.first.rguiData[7], sData.rguiData[7]); } } TEST(DbcUtilCanDLTest, ReceiveLittleEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0x7, {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0xB7, 0x96, 0x00, 0x00, 0x00, 0x00}}, { 0x7, {0xDA, 0x15, 0xB7, 0x96, 0xAA, 0x55, 0xCC, 0x33}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 8ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; sMsg.rguiData[7] = sData.rguiData[7]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; uint32_t rguiVal[6] = {}; size_t nCnt = 0; sdv::core::CSignal signalLE1 = dispatch.Subscribe("TestLE.SignalLE1", [&](sdv::any_t tVal) {rguiVal[0] = tVal; nCnt++; }); EXPECT_TRUE(signalLE1); sdv::core::CSignal signalLE2 = dispatch.Subscribe("TestLE.SignalLE2", [&](sdv::any_t tVal) {rguiVal[1] = tVal; nCnt++; }); EXPECT_TRUE(signalLE2); sdv::core::CSignal signalLE3 = dispatch.Subscribe("TestLE.SignalLE3", [&](sdv::any_t tVal) {rguiVal[2] = tVal; nCnt++; }); EXPECT_TRUE(signalLE3); sdv::core::CSignal signalLE4 = dispatch.Subscribe("TestLE.SignalLE4", [&](sdv::any_t tVal) {rguiVal[3] = tVal; nCnt++; }); EXPECT_TRUE(signalLE4); sdv::core::CSignal signalLE5 = dispatch.Subscribe("TestLE.SignalLE5", [&](sdv::any_t tVal) {rguiVal[4] = tVal; nCnt++; }); EXPECT_TRUE(signalLE5); sdv::core::CSignal signalLE6 = dispatch.Subscribe("TestLE.SignalLE6", [&](sdv::any_t tVal) {rguiVal[5] = tVal; nCnt++; }); EXPECT_TRUE(signalLE6); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); EXPECT_EQ(nCnt, 36u); EXPECT_EQ(rguiVal[0], 0xau); EXPECT_EQ(rguiVal[1], 0x5du); EXPECT_EQ(rguiVal[2], 0x31u); EXPECT_EQ(rguiVal[3], 0x2du); EXPECT_EQ(rguiVal[4], 0x96u); EXPECT_EQ(rguiVal[5], 0x33cc55aau); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalLE1.Reset(); signalLE2.Reset(); signalLE3.Reset(); signalLE4.Reset(); signalLE5.Reset(); signalLE6.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, Receive64BitLittleEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xCA, {0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA}}, { 0x66, {0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA}}, { 0x1F6, {0x74, 0xF3, 0xC8, 0xF4, 0xE5, 0x00, 0x00, 0x00}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 8ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; sMsg.rguiData[7] = sData.rguiData[7]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; int64_t iInt64Val = 0; uint64_t uiUint64Val = 0u; double dScaleInt64Val = 0; sdv::core::CSignal signalInt64LE = dispatch.Subscribe("TestInt64LE.SignalInt64LE", [&](sdv::any_t tVal) {iInt64Val = tVal; }); EXPECT_TRUE(signalInt64LE); sdv::core::CSignal signalUint64LE = dispatch.Subscribe("TestUint64LE.SignalUint64LE", [&](sdv::any_t tVal) {uiUint64Val = tVal; }); EXPECT_TRUE(signalUint64LE); sdv::core::CSignal signalScaleInt64LE = dispatch.Subscribe("TestScale64LE.SignalScaleInt64LE", [&](sdv::any_t tVal) {dScaleInt64Val = tVal; }); EXPECT_TRUE(signalScaleInt64LE); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); EXPECT_EQ(iInt64Val, -6144092013047381999ll); EXPECT_EQ(uiUint64Val, 0xaabbccddeeff0011); EXPECT_EQ(round(dScaleInt64Val * 1e8), round(987.654321012 * 1e8)); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalInt64LE.Reset(); signalUint64LE.Reset(); signalScaleInt64LE.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, SpontaneousTransactionalTransmitBigEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalBE1 = dispatch.AddPublisher("TestBE.SignalBE1"); EXPECT_TRUE(signalBE1); sdv::core::CSignal signalBE2 = dispatch.AddPublisher("TestBE.SignalBE2"); EXPECT_TRUE(signalBE2); sdv::core::CSignal signalBE3 = dispatch.AddPublisher("TestBE.SignalBE3"); EXPECT_TRUE(signalBE3); sdv::core::CSignal signalBE4 = dispatch.AddPublisher("TestBE.SignalBE4"); EXPECT_TRUE(signalBE4); sdv::core::CSignal signalBE5 = dispatch.AddPublisher("TestBE.SignalBE5"); EXPECT_TRUE(signalBE5); sdv::core::CSignal signalBE6 = dispatch.AddPublisher("TestBE.SignalBE6"); EXPECT_TRUE(signalBE6); appcontrol.SetRunningMode(); sdv::core::CTransaction transaction = dispatch.CreateTransaction(); EXPECT_TRUE(transaction); EXPECT_NO_THROW(signalBE1.Write(0xa, transaction)); EXPECT_NO_THROW(signalBE2.Write(0x5d, transaction)); EXPECT_NO_THROW(signalBE3.Write(0x31, transaction)); EXPECT_NO_THROW(signalBE4.Write(0x2d, transaction)); EXPECT_NO_THROW(signalBE5.Write(0x96, transaction)); EXPECT_NO_THROW(signalBE6.Write(0x33cc55aa, transaction)); transaction.Finish(); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalBE1.Reset(); signalBE2.Reset(); signalBE3.Reset(); signalBE4.Reset(); signalBE5.Reset(); signalBE6.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); // Get first message std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, 6ul); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.rguiData[0], 0xa5); EXPECT_EQ(prMsg.first.rguiData[1], 0xdC); EXPECT_EQ(prMsg.first.rguiData[2], 0x6d); EXPECT_EQ(prMsg.first.rguiData[3], 0x96); EXPECT_EQ(prMsg.first.rguiData[4], 0x33); EXPECT_EQ(prMsg.first.rguiData[5], 0xcc); EXPECT_EQ(prMsg.first.rguiData[6], 0x55); EXPECT_EQ(prMsg.first.rguiData[7], 0xaa); } TEST(DbcUtilCanDLTest, SpontaneousTransactionalTransmitLittleEndian) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalLE1 = dispatch.AddPublisher("TestLE.SignalLE1"); EXPECT_TRUE(signalLE1); sdv::core::CSignal signalLE2 = dispatch.AddPublisher("TestLE.SignalLE2"); EXPECT_TRUE(signalLE2); sdv::core::CSignal signalLE3 = dispatch.AddPublisher("TestLE.SignalLE3"); EXPECT_TRUE(signalLE3); sdv::core::CSignal signalLE4 = dispatch.AddPublisher("TestLE.SignalLE4"); EXPECT_TRUE(signalLE4); sdv::core::CSignal signalLE5 = dispatch.AddPublisher("TestLE.SignalLE5"); EXPECT_TRUE(signalLE5); sdv::core::CSignal signalLE6 = dispatch.AddPublisher("TestLE.SignalLE6"); EXPECT_TRUE(signalLE6); appcontrol.SetRunningMode(); sdv::core::CTransaction transaction = dispatch.CreateTransaction(); EXPECT_TRUE(transaction); EXPECT_NO_THROW(signalLE1.Write(0xa, transaction)); EXPECT_NO_THROW(signalLE2.Write(0x5d, transaction)); EXPECT_NO_THROW(signalLE3.Write(0x31, transaction)); EXPECT_NO_THROW(signalLE4.Write(0x2d, transaction)); EXPECT_NO_THROW(signalLE5.Write(0x96, transaction)); EXPECT_NO_THROW(signalLE6.Write(0x33cc55aa, transaction)); transaction.Finish(); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalLE1.Reset(); signalLE2.Reset(); signalLE3.Reset(); signalLE4.Reset(); signalLE5.Reset(); signalLE6.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); // Get first message std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, 7ul); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.rguiData[0], 0xda); EXPECT_EQ(prMsg.first.rguiData[1], 0x15); EXPECT_EQ(prMsg.first.rguiData[2], 0xb7); EXPECT_EQ(prMsg.first.rguiData[3], 0x96); EXPECT_EQ(prMsg.first.rguiData[4], 0xaa); EXPECT_EQ(prMsg.first.rguiData[5], 0x55); EXPECT_EQ(prMsg.first.rguiData[6], 0xcc); EXPECT_EQ(prMsg.first.rguiData[7], 0x33); } TEST(DbcUtilCanDLTest, SpontaneousTransmitBigEndianAllDataTypes) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to integer based signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalIntBE1 = dispatch.AddPublisher("TestIntBE.SignalIntBE1"); EXPECT_TRUE(signalIntBE1); sdv::core::CSignal signalIntBE2 = dispatch.AddPublisher("TestIntBE.SignalIntBE2"); EXPECT_TRUE(signalIntBE2); sdv::core::CSignal signalIntBE3 = dispatch.AddPublisher("TestIntBE.SignalIntBE3"); EXPECT_TRUE(signalIntBE3); sdv::core::CSignal signalIntBE4 = dispatch.AddPublisher("TestIntBE.SignalIntBE4"); EXPECT_TRUE(signalIntBE4); sdv::core::CSignal signalIntBE5 = dispatch.AddPublisher("TestIntBE.SignalIntBE5"); EXPECT_TRUE(signalIntBE5); sdv::core::CSignal signalIntBE6 = dispatch.AddPublisher("TestIntBE.SignalIntBE6"); EXPECT_TRUE(signalIntBE6); // Subscribe to unsigned integer based signals sdv::core::CSignal signalUintBE1 = dispatch.AddPublisher("TestUintBE.SignalUintBE1"); EXPECT_TRUE(signalUintBE1); sdv::core::CSignal signalUintBE2 = dispatch.AddPublisher("TestUintBE.SignalUintBE2"); EXPECT_TRUE(signalUintBE2); sdv::core::CSignal signalUintBE3 = dispatch.AddPublisher("TestUintBE.SignalUintBE3"); EXPECT_TRUE(signalUintBE3); sdv::core::CSignal signalUintBE4 = dispatch.AddPublisher("TestUintBE.SignalUintBE4"); EXPECT_TRUE(signalUintBE4); sdv::core::CSignal signalUintBE5 = dispatch.AddPublisher("TestUintBE.SignalUintBE5"); EXPECT_TRUE(signalUintBE5); sdv::core::CSignal signalUintBE6 = dispatch.AddPublisher("TestUintBE.SignalUintBE6"); EXPECT_TRUE(signalUintBE6); // Subscribe to floating point based signals sdv::core::CSignal signalFloatBE1 = dispatch.AddPublisher("TestFloatBE.SignalFloatBE1"); EXPECT_TRUE(signalFloatBE1); sdv::core::CSignal signalFloatBE2 = dispatch.AddPublisher("TestFloatBE.SignalFloatBE2"); EXPECT_TRUE(signalFloatBE2); // Subscribe to double precision floating point based signals sdv::core::CSignal signalDoubleBE1 = dispatch.AddPublisher("TestDoubleBE.SignalDoubleBE1"); EXPECT_TRUE(signalDoubleBE1); appcontrol.SetRunningMode(); for (size_t n = 10; n < 20; n++) { sdv::core::CTransaction transaction = dispatch.CreateTransaction(); signalIntBE1.Write((static_cast(n) & 0b1) * (n & 1 ? -1 : 1), transaction); // 2 bits incl. sign signalIntBE2.Write((static_cast(n) & 0b1111) * (n & 1 ? -1 : 1), transaction); // 5 bits incl. sign signalIntBE3.Write((static_cast(n) & 0b11111) * (n & 1 ? -1 : 1), transaction); // 6 bits incl. sign signalIntBE4.Write((static_cast(n) & 0b11) * (n & 1 ? -1 : 1), transaction); // 3 bits incl. sign signalIntBE5.Write((static_cast(n)) * (n & 1 ? -1 : 1), transaction); // 18 bits incl. sign signalIntBE6.Write((static_cast(n)) * (n & 1 ? -1 : 1), transaction); // 30 bits incl. sign transaction.Finish(); transaction = dispatch.CreateTransaction(); signalUintBE1.Write(static_cast(n) & 0b1, transaction); // 1 bit signalUintBE2.Write(static_cast(n) & 0b11, transaction); // 2 bits signalUintBE3.Write(static_cast(n) & 0b111111, transaction); // 6 bits signalUintBE4.Write(static_cast(n) & 0b1111111, transaction); // 7 bits signalUintBE5.Write(static_cast(n), transaction); // 18 bits signalUintBE6.Write(static_cast(n), transaction); // 30 bits transaction.Finish(); transaction = dispatch.CreateTransaction(); signalFloatBE1.Write(static_cast(n) * 1.111f, transaction); signalFloatBE2.Write(static_cast(n) * 2.222f, transaction); transaction.Finish(); transaction = dispatch.CreateTransaction(); signalDoubleBE1.Write(static_cast(n) * 3.333, transaction); transaction.Finish(); } // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalIntBE1.Reset(); signalIntBE2.Reset(); signalIntBE3.Reset(); signalIntBE4.Reset(); signalIntBE5.Reset(); signalIntBE6.Reset(); signalUintBE1.Reset(); signalUintBE2.Reset(); signalUintBE3.Reset(); signalUintBE4.Reset(); signalUintBE5.Reset(); signalUintBE6.Reset(); signalFloatBE1.Reset(); signalFloatBE2.Reset(); signalDoubleBE1.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xC9 , {0x14, 0x52, 0x00, 0x02, 0x80, 0x00, 0x00, 0x0A}}, { 0x65 , {0x45, 0x0A, 0x00, 0x02, 0x80, 0x00, 0x00, 0x0A}}, { 0x12D, {0x41, 0x31, 0xC2, 0x8F, 0x41, 0xB1, 0xC2, 0x8F}}, { 0x191, {0x40, 0x40, 0xAA, 0x3D, 0x70, 0xA3, 0xD7, 0x0A}}, { 0xC9 , {0xEB, 0xAD, 0xFF, 0xFD, 0x7F, 0xFF, 0xFF, 0xF5}}, { 0x65 , {0xE5, 0x8B, 0x00, 0x02, 0xC0, 0x00, 0x00, 0x0B}}, { 0x12D, {0x41, 0x43, 0x89, 0x37, 0x41, 0xC3, 0x89, 0x37}}, { 0x191, {0x40, 0x42, 0x54, 0xDD, 0x2F, 0x1A, 0x9F, 0xBF}}, { 0xC9 , {0x18, 0x60, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C}}, { 0x65 , {0x06, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C}}, { 0x12D, {0x41, 0x55, 0x4F, 0xDE, 0x41, 0xD5, 0x4F, 0xDE}}, { 0x191, {0x40, 0x43, 0xFF, 0x7C, 0xED, 0x91, 0x68, 0x73}}, { 0xC9 , {0xE7, 0x9F, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xF3}}, { 0x65 , {0xA6, 0x8D, 0x00, 0x03, 0x40, 0x00, 0x00, 0x0D}}, { 0x12D, {0x41, 0x67, 0x16, 0x86, 0x41, 0xE7, 0x16, 0x86}}, { 0x191, {0x40, 0x45, 0xAA, 0x1C, 0xAC, 0x08, 0x31, 0x27}}, { 0xC9 , {0x1C, 0x72, 0x00, 0x03, 0x80, 0x00, 0x00, 0x0E}}, { 0x65 , {0x47, 0x0E, 0x00, 0x03, 0x80, 0x00, 0x00, 0x0E}}, { 0x12D, {0x41, 0x78, 0xDD, 0x2E, 0x41, 0xF8, 0xDD, 0x2E}}, { 0x191, {0x40, 0x47, 0x54, 0xBC, 0x6A, 0x7E, 0xF9, 0xDC}}, { 0xC9 , {0xE3, 0x8D, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xF1}}, { 0x65 , {0xE7, 0x8F, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x0F}}, { 0x12D, {0x41, 0x85, 0x51, 0xEB, 0x42, 0x05, 0x51, 0xEB}}, { 0x191, {0x40, 0x48, 0xFF, 0x5C, 0x28, 0xF5, 0xC2, 0x90}}, { 0xC9 , {0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10}}, { 0x65 , {0x08, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10}}, { 0x12D, {0x41, 0x8E, 0x35, 0x3F, 0x42, 0x0E, 0x35, 0x3F}}, { 0x191, {0x40, 0x4A, 0xA9, 0xFB, 0xE7, 0x6C, 0x8B, 0x44}}, { 0xC9 , {0xFF, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xEF}}, { 0x65 , {0xA8, 0x91, 0x00, 0x04, 0x40, 0x00, 0x00, 0x11}}, { 0x12D, {0x41, 0x97, 0x18, 0x93, 0x42, 0x17, 0x18, 0x93}}, { 0x191, {0x40, 0x4C, 0x54, 0x9B, 0xA5, 0xE3, 0x53, 0xF8}}, { 0xC9 , {0x04, 0x92, 0x00, 0x04, 0x80, 0x00, 0x00, 0x12}}, { 0x65 , {0x49, 0x12, 0x00, 0x04, 0x80, 0x00, 0x00, 0x12}}, { 0x12D, {0x41, 0x9F, 0xFB, 0xE7, 0x42, 0x1F, 0xFB, 0xE7}}, { 0x191, {0x40, 0x4D, 0xFF, 0x3B, 0x64, 0x5A, 0x1C, 0xAC}}, { 0xC9 , {0xFB, 0x6D, 0xFF, 0xFB, 0x7F, 0xFF, 0xFF, 0xED}}, { 0x65 , {0xE9, 0x93, 0x00, 0x04, 0xC0, 0x00, 0x00, 0x13}}, { 0x12D, {0x41, 0xA8, 0xDF, 0x3B, 0x42, 0x28, 0xDF, 0x3B}}, { 0x191, {0x40, 0x4F, 0xA9, 0xDB, 0x22, 0xD0, 0xE5, 0x61}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); EXPECT_EQ(prMsg.first.rguiData[7], sData.rguiData[7]); } } TEST(DbcUtilCanDLTest, ReceiveBigEndianAllDataTypes) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xC9 , {0x14, 0x52, 0x00, 0x02, 0x80, 0x00, 0x00, 0x0A}}, { 0x65 , {0x45, 0x0A, 0x00, 0x02, 0x80, 0x00, 0x00, 0x0A}}, { 0x12D, {0x41, 0x31, 0xC2, 0x8F, 0x41, 0xB1, 0xC2, 0x8F}}, { 0x191, {0x40, 0x40, 0xAA, 0x3D, 0x70, 0xA3, 0xD7, 0x0A}}, { 0xC9 , {0xEB, 0xAD, 0xFF, 0xFD, 0x7F, 0xFF, 0xFF, 0xF5}}, { 0x65 , {0xE5, 0x8B, 0x00, 0x02, 0xC0, 0x00, 0x00, 0x0B}}, { 0x12D, {0x41, 0x43, 0x89, 0x37, 0x41, 0xC3, 0x89, 0x37}}, { 0x191, {0x40, 0x42, 0x54, 0xDD, 0x2F, 0x1A, 0x9F, 0xBF}}, { 0xC9 , {0x18, 0x60, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C}}, { 0x65 , {0x06, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C}}, { 0x12D, {0x41, 0x55, 0x4F, 0xDE, 0x41, 0xD5, 0x4F, 0xDE}}, { 0x191, {0x40, 0x43, 0xFF, 0x7C, 0xED, 0x91, 0x68, 0x73}}, { 0xC9 , {0xE7, 0x9F, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xF3}}, { 0x65 , {0xA6, 0x8D, 0x00, 0x03, 0x40, 0x00, 0x00, 0x0D}}, { 0x12D, {0x41, 0x67, 0x16, 0x86, 0x41, 0xE7, 0x16, 0x86}}, { 0x191, {0x40, 0x45, 0xAA, 0x1C, 0xAC, 0x08, 0x31, 0x27}}, { 0xC9 , {0x1C, 0x72, 0x00, 0x03, 0x80, 0x00, 0x00, 0x0E}}, { 0x65 , {0x47, 0x0E, 0x00, 0x03, 0x80, 0x00, 0x00, 0x0E}}, { 0x12D, {0x41, 0x78, 0xDD, 0x2E, 0x41, 0xF8, 0xDD, 0x2E}}, { 0x191, {0x40, 0x47, 0x54, 0xBC, 0x6A, 0x7E, 0xF9, 0xDC}}, { 0xC9 , {0xE3, 0x8D, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xF1}}, { 0x65 , {0xE7, 0x8F, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x0F}}, { 0x12D, {0x41, 0x85, 0x51, 0xEB, 0x42, 0x05, 0x51, 0xEB}}, { 0x191, {0x40, 0x48, 0xFF, 0x5C, 0x28, 0xF5, 0xC2, 0x90}}, { 0xC9 , {0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10}}, { 0x65 , {0x08, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10}}, { 0x12D, {0x41, 0x8E, 0x35, 0x3F, 0x42, 0x0E, 0x35, 0x3F}}, { 0x191, {0x40, 0x4A, 0xA9, 0xFB, 0xE7, 0x6C, 0x8B, 0x44}}, { 0xC9 , {0xFF, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xEF}}, { 0x65 , {0xA8, 0x91, 0x00, 0x04, 0x40, 0x00, 0x00, 0x11}}, { 0x12D, {0x41, 0x97, 0x18, 0x93, 0x42, 0x17, 0x18, 0x93}}, { 0x191, {0x40, 0x4C, 0x54, 0x9B, 0xA5, 0xE3, 0x53, 0xF8}}, { 0xC9 , {0x04, 0x92, 0x00, 0x04, 0x80, 0x00, 0x00, 0x12}}, { 0x65 , {0x49, 0x12, 0x00, 0x04, 0x80, 0x00, 0x00, 0x12}}, { 0x12D, {0x41, 0x9F, 0xFB, 0xE7, 0x42, 0x1F, 0xFB, 0xE7}}, { 0x191, {0x40, 0x4D, 0xFF, 0x3B, 0x64, 0x5A, 0x1C, 0xAC}}, { 0xC9 , {0xFB, 0x6D, 0xFF, 0xFB, 0x7F, 0xFF, 0xFF, 0xED}}, { 0x65 , {0xE9, 0x93, 0x00, 0x04, 0xC0, 0x00, 0x00, 0x13}}, { 0x12D, {0x41, 0xA8, 0xDF, 0x3B, 0x42, 0x28, 0xDF, 0x3B}}, { 0x191, {0x40, 0x4F, 0xA9, 0xDB, 0x22, 0xD0, 0xE5, 0x61}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 8ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; sMsg.rguiData[7] = sData.rguiData[7]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; int32_t rgiIntCnt[6] = {10, 10, 10, 10, 10, 10}; sdv::core::CSignal signalIntBE1 = dispatch.Subscribe("TestIntBE.SignalIntBE1", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[0]++; int32_t iCalculated = (static_cast(i) & 0b1) * (i & 1 ? -1 : 1); // 2 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE1); sdv::core::CSignal signalIntBE2 = dispatch.Subscribe("TestIntBE.SignalIntBE2", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[1]++; int32_t iCalculated = (static_cast(i) & 0b1111) * (i & 1 ? -1 : 1); // 5 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE2); sdv::core::CSignal signalIntBE3 = dispatch.Subscribe("TestIntBE.SignalIntBE3", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[2]++; int32_t iCalculated = (static_cast(i) & 0b11111) * (i & 1 ? -1 : 1); // 6 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE3); sdv::core::CSignal signalIntBE4 = dispatch.Subscribe("TestIntBE.SignalIntBE4", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[3]++; int32_t iCalculated = (static_cast(i) & 0b11) * (i & 1 ? -1 : 1); // 3 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE4); sdv::core::CSignal signalIntBE5 = dispatch.Subscribe("TestIntBE.SignalIntBE5", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[4]++; int32_t iCalculated = (static_cast(i)) * (i & 1 ? -1 : 1); // 18 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE5); sdv::core::CSignal signalIntBE6 = dispatch.Subscribe("TestIntBE.SignalIntBE6", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[5]++; int32_t iCalculated = (static_cast(i)) * (i & 1 ? -1 : 1); // 30 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE6); // Subscribe to unsigned integer based signals uint32_t rguiUintCnt[6] = {10u, 10u, 10u, 10u, 10u, 10u}; sdv::core::CSignal signalUintBE1 = dispatch.Subscribe("TestUintBE.SignalUintBE1", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[0]++; uint32_t uiCalculated = static_cast(ui) & 0b1; // 1 bit EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE1); sdv::core::CSignal signalUintBE2 = dispatch.Subscribe("TestUintBE.SignalUintBE2", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[1]++; uint32_t uiCalculated = static_cast(ui) & 0b11; // 2 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE2); sdv::core::CSignal signalUintBE3 = dispatch.Subscribe("TestUintBE.SignalUintBE3", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[2]++; uint32_t uiCalculated = static_cast(ui) & 0b111111; // 6 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE3); sdv::core::CSignal signalUintBE4 = dispatch.Subscribe("TestUintBE.SignalUintBE4", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[3]++; uint32_t uiCalculated = static_cast(ui) & 0b1111111; // 7 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE4); sdv::core::CSignal signalUintBE5 = dispatch.Subscribe("TestUintBE.SignalUintBE5", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[4]++; uint32_t uiCalculated = static_cast(ui); // 18 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE5); sdv::core::CSignal signalUintBE6 = dispatch.Subscribe("TestUintBE.SignalUintBE6", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[5]++; uint32_t uiCalculated = static_cast(ui); // 30 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE6); // Subscribe to floating point based signals uint32_t rguiFloatCnt[2] = {10u, 10u}; sdv::core::CSignal signalFloatBE1 = dispatch.Subscribe("TestFloatBE.SignalFloatBE1", [&](sdv::any_t tVal) { uint32_t ui = rguiFloatCnt[0]++; float fCalculated = static_cast(ui) * 1.111f; EXPECT_EQ(fCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalFloatBE1); sdv::core::CSignal signalFloatBE2 = dispatch.Subscribe("TestFloatBE.SignalFloatBE2", [&](sdv::any_t tVal) { uint32_t ui = rguiFloatCnt[1]++; float fCalculated = static_cast(ui) * 2.222f; EXPECT_EQ(fCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalFloatBE2); // Subscribe to double precision floating point based signals uint32_t uiDoubleCnt = 10u; sdv::core::CSignal signalDoubleBE1 = dispatch.Subscribe("TestDoubleBE.SignalDoubleBE1", [&](sdv::any_t tVal) { uint32_t ui = uiDoubleCnt++; double dCalculated = static_cast(ui) * 3.333; EXPECT_EQ(dCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalDoubleBE1); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); // Check for correct counters for (int32_t i : rgiIntCnt) EXPECT_EQ(i, 20); for (uint32_t ui : rguiUintCnt) EXPECT_EQ(ui, 20u); for (uint32_t ui : rguiFloatCnt) EXPECT_EQ(ui, 20u); EXPECT_EQ(uiDoubleCnt, 20u); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalIntBE1.Reset(); signalIntBE2.Reset(); signalIntBE3.Reset(); signalIntBE4.Reset(); signalIntBE5.Reset(); signalIntBE6.Reset(); signalUintBE1.Reset(); signalUintBE2.Reset(); signalUintBE3.Reset(); signalUintBE4.Reset(); signalUintBE5.Reset(); signalUintBE6.Reset(); signalFloatBE1.Reset(); signalFloatBE2.Reset(); signalDoubleBE1.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, SpontaneousTransmitLittleEndianAllDataTypes) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to integer based signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalIntLE1 = dispatch.AddPublisher("TestIntLE.SignalIntLE1"); EXPECT_TRUE(signalIntLE1); sdv::core::CSignal signalIntLE2 = dispatch.AddPublisher("TestIntLE.SignalIntLE2"); EXPECT_TRUE(signalIntLE2); sdv::core::CSignal signalIntLE3 = dispatch.AddPublisher("TestIntLE.SignalIntLE3"); EXPECT_TRUE(signalIntLE3); sdv::core::CSignal signalIntLE4 = dispatch.AddPublisher("TestIntLE.SignalIntLE4"); EXPECT_TRUE(signalIntLE4); sdv::core::CSignal signalIntLE5 = dispatch.AddPublisher("TestIntLE.SignalIntLE5"); EXPECT_TRUE(signalIntLE5); sdv::core::CSignal signalIntLE6 = dispatch.AddPublisher("TestIntLE.SignalIntLE6"); EXPECT_TRUE(signalIntLE6); // Subscribe to unsigned integer based signals sdv::core::CSignal signalUintLE1 = dispatch.AddPublisher("TestUintLE.SignalUintLE1"); EXPECT_TRUE(signalUintLE1); sdv::core::CSignal signalUintLE2 = dispatch.AddPublisher("TestUintLE.SignalUintLE2"); EXPECT_TRUE(signalUintLE2); sdv::core::CSignal signalUintLE3 = dispatch.AddPublisher("TestUintLE.SignalUintLE3"); EXPECT_TRUE(signalUintLE3); sdv::core::CSignal signalUintLE4 = dispatch.AddPublisher("TestUintLE.SignalUintLE4"); EXPECT_TRUE(signalUintLE4); sdv::core::CSignal signalUintLE5 = dispatch.AddPublisher("TestUintLE.SignalUintLE5"); EXPECT_TRUE(signalUintLE5); sdv::core::CSignal signalUintLE6 = dispatch.AddPublisher("TestUintLE.SignalUintLE6"); EXPECT_TRUE(signalUintLE6); // Subscribe to floating point based signals sdv::core::CSignal signalFloatLE1 = dispatch.AddPublisher("TestFloatLE.SignalFloatLE1"); EXPECT_TRUE(signalFloatLE1); sdv::core::CSignal signalFloatLE2 = dispatch.AddPublisher("TestFloatLE.SignalFloatLE2"); EXPECT_TRUE(signalFloatLE2); // Subscribe to double precision floating point based signals sdv::core::CSignal signalDoubleLE1 = dispatch.AddPublisher("TestDoubleLE.SignalDoubleLE1"); EXPECT_TRUE(signalDoubleLE1); appcontrol.SetRunningMode(); for (size_t n = 10; n < 20; n++) { sdv::core::CTransaction transaction = dispatch.CreateTransaction(); signalIntLE1.Write((static_cast(n) & 0b1) * (n & 1 ? -1 : 1), transaction); // 2 bits incl. sign signalIntLE2.Write((static_cast(n) & 0b1111) * (n & 1 ? -1 : 1), transaction); // 5 bits incl. sign signalIntLE3.Write((static_cast(n) & 0b11111) * (n & 1 ? -1 : 1), transaction); // 6 bits incl. sign signalIntLE4.Write((static_cast(n) & 0b11) * (n & 1 ? -1 : 1), transaction); // 3 bits incl. sign signalIntLE5.Write((static_cast(n)) * (n & 1 ? -1 : 1), transaction); // 18 bits incl. sign signalIntLE6.Write((static_cast(n)) * (n & 1 ? -1 : 1), transaction); // 30 bits incl. sign transaction.Finish(); transaction = dispatch.CreateTransaction(); signalUintLE1.Write(static_cast(n) & 0b1, transaction); // 1 bit signalUintLE2.Write(static_cast(n) & 0b11, transaction); // 2 bits signalUintLE3.Write(static_cast(n) & 0b111111, transaction); // 6 bits signalUintLE4.Write(static_cast(n) & 0b1111111, transaction); // 7 bits signalUintLE5.Write(static_cast(n), transaction); // 18 bits signalUintLE6.Write(static_cast(n), transaction); // 30 bits transaction.Finish(); transaction = dispatch.CreateTransaction(); signalFloatLE1.Write(static_cast(n) * 1.111f, transaction); signalFloatLE2.Write(static_cast(n) * 2.222f, transaction); transaction.Finish(); transaction = dispatch.CreateTransaction(); signalDoubleLE1.Write(static_cast(n) * 3.333, transaction); transaction.Finish(); } // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalIntLE1.Reset(); signalIntLE2.Reset(); signalIntLE3.Reset(); signalIntLE4.Reset(); signalIntLE5.Reset(); signalIntLE6.Reset(); signalUintLE1.Reset(); signalUintLE2.Reset(); signalUintLE3.Reset(); signalUintLE4.Reset(); signalUintLE5.Reset(); signalUintLE6.Reset(); signalFloatLE1.Reset(); signalFloatLE2.Reset(); signalDoubleLE1.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xC8 , {0x28, 0x45, 0x0A, 0x00, 0x28, 0x00, 0x00, 0x00}}, { 0x64 , {0x54, 0x14, 0x0A, 0x00, 0x28, 0x00, 0x00, 0x00}}, { 0x12C, {0x8F, 0xC2, 0x31, 0x41, 0x8F, 0xC2, 0xB1, 0x41}}, { 0x190, {0x0A, 0xD7, 0xA3, 0x70, 0x3D, 0xAA, 0x40, 0x40}}, { 0xC8 , {0xD7, 0xBA, 0xF5, 0xFF, 0xD7, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x5F, 0x16, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00}}, { 0x12C, {0x37, 0x89, 0x43, 0x41, 0x37, 0x89, 0xC3, 0x41}}, { 0x190, {0xBF, 0x9F, 0x1A, 0x2F, 0xDD, 0x54, 0x42, 0x40}}, { 0xC8 , {0x30, 0x06, 0x0C, 0x00, 0x30, 0x00, 0x00, 0x00}}, { 0x64 , {0x60, 0x18, 0x0C, 0x00, 0x30, 0x00, 0x00, 0x00}}, { 0x12C, {0xDE, 0x4F, 0x55, 0x41, 0xDE, 0x4F, 0xD5, 0x41}}, { 0x190, {0x73, 0x68, 0x91, 0xED, 0x7C, 0xFF, 0x43, 0x40}}, { 0xC8 , {0xCF, 0xF9, 0xF3, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x6B, 0x1A, 0x0D, 0x00, 0x34, 0x00, 0x00, 0x00}}, { 0x12C, {0x86, 0x16, 0x67, 0x41, 0x86, 0x16, 0xE7, 0x41}}, { 0x190, {0x27, 0x31, 0x08, 0xAC, 0x1C, 0xAA, 0x45, 0x40}}, { 0xC8 , {0x38, 0x47, 0x0E, 0x00, 0x38, 0x00, 0x00, 0x00}}, { 0x64 , {0x74, 0x1C, 0x0E, 0x00, 0x38, 0x00, 0x00, 0x00}}, { 0x12C, {0x2E, 0xDD, 0x78, 0x41, 0x2E, 0xDD, 0xF8, 0x41}}, { 0x190, {0xDC, 0xF9, 0x7E, 0x6A, 0xBC, 0x54, 0x47, 0x40}}, { 0xC8 , {0xC7, 0xB8, 0xF1, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x7F, 0x1E, 0x0F, 0x00, 0x3C, 0x00, 0x00, 0x00}}, { 0x12C, {0xEB, 0x51, 0x85, 0x41, 0xEB, 0x51, 0x05, 0x42}}, { 0x190, {0x90, 0xC2, 0xF5, 0x28, 0x5C, 0xFF, 0x48, 0x40}}, { 0xC8 , {0x00, 0x08, 0x10, 0x00, 0x40, 0x00, 0x00, 0x00}}, { 0x64 , {0x80, 0x20, 0x10, 0x00, 0x40, 0x00, 0x00, 0x00}}, { 0x12C, {0x3F, 0x35, 0x8E, 0x41, 0x3F, 0x35, 0x0E, 0x42}}, { 0x190, {0x44, 0x8B, 0x6C, 0xE7, 0xFB, 0xA9, 0x4A, 0x40}}, { 0xC8 , {0xFF, 0xF7, 0xEF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x8B, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00}}, { 0x12C, {0x93, 0x18, 0x97, 0x41, 0x93, 0x18, 0x17, 0x42}}, { 0x190, {0xF8, 0x53, 0xE3, 0xA5, 0x9B, 0x54, 0x4C, 0x40}}, { 0xC8 , {0x08, 0x49, 0x12, 0x00, 0x48, 0x00, 0x00, 0x00}}, { 0x64 , {0x94, 0x24, 0x12, 0x00, 0x48, 0x00, 0x00, 0x00}}, { 0x12C, {0xE7, 0xFB, 0x9F, 0x41, 0xE7, 0xFB, 0x1F, 0x42}}, { 0x190, {0xAC, 0x1C, 0x5A, 0x64, 0x3B, 0xFF, 0x4D, 0x40}}, { 0xC8 , {0xF7, 0xB6, 0xED, 0xFF, 0xB7, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x9F, 0x26, 0x13, 0x00, 0x4C, 0x00, 0x00, 0x00}}, { 0x12C, {0x3B, 0xDF, 0xA8, 0x41, 0x3B, 0xDF, 0x28, 0x42}}, { 0x190, {0x61, 0xE5, 0xD0, 0x22, 0xDB, 0xA9, 0x4F, 0x40}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 8ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); EXPECT_EQ(prMsg.first.rguiData[7], sData.rguiData[7]); } } TEST(DbcUtilCanDLTest, ReceiveLittleEndianAllDataTypes) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[8]; } rgsData[] = { { 0xC8 , {0x28, 0x45, 0x0A, 0x00, 0x28, 0x00, 0x00, 0x00}}, { 0x64 , {0x54, 0x14, 0x0A, 0x00, 0x28, 0x00, 0x00, 0x00}}, { 0x12C, {0x8F, 0xC2, 0x31, 0x41, 0x8F, 0xC2, 0xB1, 0x41}}, { 0x190, {0x0A, 0xD7, 0xA3, 0x70, 0x3D, 0xAA, 0x40, 0x40}}, { 0xC8 , {0xD7, 0xBA, 0xF5, 0xFF, 0xD7, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x5F, 0x16, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00}}, { 0x12C, {0x37, 0x89, 0x43, 0x41, 0x37, 0x89, 0xC3, 0x41}}, { 0x190, {0xBF, 0x9F, 0x1A, 0x2F, 0xDD, 0x54, 0x42, 0x40}}, { 0xC8 , {0x30, 0x06, 0x0C, 0x00, 0x30, 0x00, 0x00, 0x00}}, { 0x64 , {0x60, 0x18, 0x0C, 0x00, 0x30, 0x00, 0x00, 0x00}}, { 0x12C, {0xDE, 0x4F, 0x55, 0x41, 0xDE, 0x4F, 0xD5, 0x41}}, { 0x190, {0x73, 0x68, 0x91, 0xED, 0x7C, 0xFF, 0x43, 0x40}}, { 0xC8 , {0xCF, 0xF9, 0xF3, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x6B, 0x1A, 0x0D, 0x00, 0x34, 0x00, 0x00, 0x00}}, { 0x12C, {0x86, 0x16, 0x67, 0x41, 0x86, 0x16, 0xE7, 0x41}}, { 0x190, {0x27, 0x31, 0x08, 0xAC, 0x1C, 0xAA, 0x45, 0x40}}, { 0xC8 , {0x38, 0x47, 0x0E, 0x00, 0x38, 0x00, 0x00, 0x00}}, { 0x64 , {0x74, 0x1C, 0x0E, 0x00, 0x38, 0x00, 0x00, 0x00}}, { 0x12C, {0x2E, 0xDD, 0x78, 0x41, 0x2E, 0xDD, 0xF8, 0x41}}, { 0x190, {0xDC, 0xF9, 0x7E, 0x6A, 0xBC, 0x54, 0x47, 0x40}}, { 0xC8 , {0xC7, 0xB8, 0xF1, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x7F, 0x1E, 0x0F, 0x00, 0x3C, 0x00, 0x00, 0x00}}, { 0x12C, {0xEB, 0x51, 0x85, 0x41, 0xEB, 0x51, 0x05, 0x42}}, { 0x190, {0x90, 0xC2, 0xF5, 0x28, 0x5C, 0xFF, 0x48, 0x40}}, { 0xC8 , {0x00, 0x08, 0x10, 0x00, 0x40, 0x00, 0x00, 0x00}}, { 0x64 , {0x80, 0x20, 0x10, 0x00, 0x40, 0x00, 0x00, 0x00}}, { 0x12C, {0x3F, 0x35, 0x8E, 0x41, 0x3F, 0x35, 0x0E, 0x42}}, { 0x190, {0x44, 0x8B, 0x6C, 0xE7, 0xFB, 0xA9, 0x4A, 0x40}}, { 0xC8 , {0xFF, 0xF7, 0xEF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x8B, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00}}, { 0x12C, {0x93, 0x18, 0x97, 0x41, 0x93, 0x18, 0x17, 0x42}}, { 0x190, {0xF8, 0x53, 0xE3, 0xA5, 0x9B, 0x54, 0x4C, 0x40}}, { 0xC8 , {0x08, 0x49, 0x12, 0x00, 0x48, 0x00, 0x00, 0x00}}, { 0x64 , {0x94, 0x24, 0x12, 0x00, 0x48, 0x00, 0x00, 0x00}}, { 0x12C, {0xE7, 0xFB, 0x9F, 0x41, 0xE7, 0xFB, 0x1F, 0x42}}, { 0x190, {0xAC, 0x1C, 0x5A, 0x64, 0x3B, 0xFF, 0x4D, 0x40}}, { 0xC8 , {0xF7, 0xB6, 0xED, 0xFF, 0xB7, 0xFF, 0xFF, 0xFF}}, { 0x64 , {0x9F, 0x26, 0x13, 0x00, 0x4C, 0x00, 0x00, 0x00}}, { 0x12C, {0x3B, 0xDF, 0xA8, 0x41, 0x3B, 0xDF, 0x28, 0x42}}, { 0x190, {0x61, 0xE5, 0xD0, 0x22, 0xDB, 0xA9, 0x4F, 0x40}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 8ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; sMsg.rguiData[7] = sData.rguiData[7]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; int32_t rgiIntCnt[6] = {10, 10, 10, 10, 10, 10}; sdv::core::CSignal signalIntLE1 = dispatch.Subscribe("TestIntLE.SignalIntLE1", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[0]++; int32_t iCalculated = (static_cast(i) & 0b1) * (i & 1 ? -1 : 1); // 2 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE1); sdv::core::CSignal signalIntLE2 = dispatch.Subscribe("TestIntLE.SignalIntLE2", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[1]++; int32_t iCalculated = (static_cast(i) & 0b1111) * (i & 1 ? -1 : 1); // 5 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE2); sdv::core::CSignal signalIntLE3 = dispatch.Subscribe("TestIntLE.SignalIntLE3", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[2]++; int32_t iCalculated = (static_cast(i) & 0b11111) * (i & 1 ? -1 : 1); // 6 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE3); sdv::core::CSignal signalIntLE4 = dispatch.Subscribe("TestIntLE.SignalIntLE4", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[3]++; int32_t iCalculated = (static_cast(i) & 0b11) * (i & 1 ? -1 : 1); // 3 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE4); sdv::core::CSignal signalIntLE5 = dispatch.Subscribe("TestIntLE.SignalIntLE5", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[4]++; int32_t iCalculated = (static_cast(i)) * (i & 1 ? -1 : 1); // 18 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE5); sdv::core::CSignal signalIntLE6 = dispatch.Subscribe("TestIntLE.SignalIntLE6", [&](sdv::any_t tVal) { int32_t i = rgiIntCnt[5]++; int32_t iCalculated = (static_cast(i)) * (i & 1 ? -1 : 1); // 30 bits incl. sign EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE6); // Subscribe to unsigned integer based signals uint32_t rguiUintCnt[6] = {10u, 10u, 10u, 10u, 10u, 10u}; sdv::core::CSignal signalUintLE1 = dispatch.Subscribe("TestUintLE.SignalUintLE1", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[0]++; uint32_t uiCalculated = static_cast(ui) & 0b1; // 1 bit EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE1); sdv::core::CSignal signalUintLE2 = dispatch.Subscribe("TestUintLE.SignalUintLE2", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[1]++; uint32_t uiCalculated = static_cast(ui) & 0b11; // 2 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE2); sdv::core::CSignal signalUintLE3 = dispatch.Subscribe("TestUintLE.SignalUintLE3", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[2]++; uint32_t uiCalculated = static_cast(ui) & 0b111111; // 6 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE3); sdv::core::CSignal signalUintLE4 = dispatch.Subscribe("TestUintLE.SignalUintLE4", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[3]++; uint32_t uiCalculated = static_cast(ui) & 0b1111111; // 7 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE4); sdv::core::CSignal signalUintLE5 = dispatch.Subscribe("TestUintLE.SignalUintLE5", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[4]++; uint32_t uiCalculated = static_cast(ui); // 18 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE5); sdv::core::CSignal signalUintLE6 = dispatch.Subscribe("TestUintLE.SignalUintLE6", [&](sdv::any_t tVal) { uint32_t ui = rguiUintCnt[5]++; uint32_t uiCalculated = static_cast(ui); // 30 bits EXPECT_EQ(uiCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE6); // Subscribe to floating point based signals uint32_t rguiFloatCnt[2] = {10u, 10u}; sdv::core::CSignal signalFloatLE1 = dispatch.Subscribe("TestFloatLE.SignalFloatLE1", [&](sdv::any_t tVal) { uint32_t ui = rguiFloatCnt[0]++; float fCalculated = static_cast(ui) * 1.111f; EXPECT_EQ(fCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalFloatLE1); sdv::core::CSignal signalFloatLE2 = dispatch.Subscribe("TestFloatLE.SignalFloatLE2", [&](sdv::any_t tVal) { uint32_t ui = rguiFloatCnt[1]++; float fCalculated = static_cast(ui) * 2.222f; EXPECT_EQ(fCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalFloatLE2); // Subscribe to double precision floating point based signals uint32_t uiDoubleCnt = 10u; sdv::core::CSignal signalDoubleLE1 = dispatch.Subscribe("TestDoubleLE.SignalDoubleLE1", [&](sdv::any_t tVal) { uint32_t ui = uiDoubleCnt++; double dCalculated = static_cast(ui) * 3.333; EXPECT_EQ(dCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalDoubleLE1); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); // Check for correct counters for (int32_t i : rgiIntCnt) EXPECT_EQ(i, 20); for (uint32_t ui : rguiUintCnt) EXPECT_EQ(ui, 20u); for (uint32_t ui : rguiFloatCnt) EXPECT_EQ(ui, 20u); EXPECT_EQ(uiDoubleCnt, 20u); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalIntLE1.Reset(); signalIntLE2.Reset(); signalIntLE3.Reset(); signalIntLE4.Reset(); signalIntLE5.Reset(); signalIntLE6.Reset(); signalUintLE1.Reset(); signalUintLE2.Reset(); signalUintLE3.Reset(); signalUintLE4.Reset(); signalUintLE5.Reset(); signalUintLE6.Reset(); signalFloatLE1.Reset(); signalFloatLE2.Reset(); signalDoubleLE1.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, SpontaneousTransmitBigEndianScaledDataTypes) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to integer based signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalUintBE1 = dispatch.AddPublisher("TestScaleBE.SignalScaleUintBE1"); EXPECT_TRUE(signalUintBE1); sdv::core::CSignal signalUintBE2 = dispatch.AddPublisher("TestScaleBE.SignalScaleUintBE2"); EXPECT_TRUE(signalUintBE2); sdv::core::CSignal signalUintBE3 = dispatch.AddPublisher("TestScaleBE.SignalScaleUintBE3"); EXPECT_TRUE(signalUintBE3); sdv::core::CSignal signalUintBE4 = dispatch.AddPublisher("TestScaleBE.SignalScaleUintBE4"); EXPECT_TRUE(signalUintBE4); sdv::core::CSignal signalIntBE5 = dispatch.AddPublisher("TestScaleBE.SignalScaleIntBE5"); EXPECT_TRUE(signalIntBE5); sdv::core::CSignal signalIntBE6 = dispatch.AddPublisher("TestScaleBE.SignalScaleIntBE6"); EXPECT_TRUE(signalIntBE6); sdv::core::CSignal signalFloatBE7 = dispatch.AddPublisher("TestScaleBE.SignalScaleFloatBE7"); EXPECT_TRUE(signalFloatBE7); appcontrol.SetRunningMode(); for (size_t n = 4; n < 12; n++) { sdv::core::CTransaction transaction = dispatch.CreateTransaction(); signalUintBE1.Write(static_cast(n) / 1000.0, transaction); // 4 bits - factor 0.001 signalUintBE2.Write(static_cast(n) - 5, transaction); // 4 bits - offset -3.5 signalUintBE3.Write(static_cast(n) * -1, transaction); // 4 bits - factor -1 signalUintBE4.Write(static_cast(n) - 1, transaction); // 4 bits - offset -2 signalIntBE5.Write(static_cast(n) / 1000.0f, transaction); // 4 bits incl. sign - factor 0.001, offset 0.008 signalIntBE6.Write(static_cast(n) - 10, transaction); // 4 bits incl. sign - offset -3.5 signalFloatBE7.Write(static_cast(n) / 10000.0f, transaction); // 32 bits - factor 0.001, offset 100 transaction.Finish(); } // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalUintBE1.Reset(); signalUintBE2.Reset(); signalUintBE3.Reset(); signalUintBE4.Reset(); signalIntBE5.Reset(); signalIntBE6.Reset(); signalFloatBE7.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[7]; } rgsData[] = { { 0x1F5, {0x43, 0x45, 0xCD, 0xC7, 0xC3, 0x4F, 0xCD}}, { 0x1F5, {0x54, 0x56, 0xDE, 0xC7, 0xC3, 0x4F, 0xBF}}, { 0x1F5, {0x65, 0x67, 0xEF, 0xC7, 0xC3, 0x4F, 0xB2}}, { 0x1F5, {0x76, 0x78, 0xF1, 0xC7, 0xC3, 0x4F, 0xA6}}, { 0x1F5, {0x87, 0x89, 0x02, 0xC7, 0xC3, 0x4F, 0x99}}, { 0x1F5, {0x98, 0x9A, 0x13, 0xC7, 0xC3, 0x4F, 0x8C}}, { 0x1F5, {0xA9, 0xAB, 0x24, 0xC7, 0xC3, 0x4F, 0x7F}}, { 0x1F5, {0xBA, 0xBC, 0x35, 0xC7, 0xC3, 0x4F, 0x73}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 7ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); } } TEST(DbcUtilCanDLTest, ReceiveBigEndianScaledDataType) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[7]; } rgsData[] = { { 0x1F5, {0x43, 0x45, 0xCD, 0xC7, 0xC3, 0x4F, 0xCD}}, { 0x1F5, {0x54, 0x56, 0xDE, 0xC7, 0xC3, 0x4F, 0xBF}}, { 0x1F5, {0x65, 0x67, 0xEF, 0xC7, 0xC3, 0x4F, 0xB2}}, { 0x1F5, {0x76, 0x78, 0xF1, 0xC7, 0xC3, 0x4F, 0xA6}}, { 0x1F5, {0x87, 0x89, 0x02, 0xC7, 0xC3, 0x4F, 0x99}}, { 0x1F5, {0x98, 0x9A, 0x13, 0xC7, 0xC3, 0x4F, 0x8C}}, { 0x1F5, {0xA9, 0xAB, 0x24, 0xC7, 0xC3, 0x4F, 0x7F}}, { 0x1F5, {0xBA, 0xBC, 0x35, 0xC7, 0xC3, 0x4F, 0x73}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 7ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; uint32_t rguiCnt[7] = {4u, 4u, 4u, 4u, 4u, 4u, 4u}; sdv::core::CSignal signalUintBE1 = dispatch.Subscribe("TestScaleBE.SignalScaleUintBE1", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[0]++; double dCalculated = static_cast(ui) / 1000.0; // 4 bits - factor 0.001 EXPECT_EQ(std::round(dCalculated * 1000.0), std::round(static_cast(tVal) * 1000.0)); }); EXPECT_TRUE(signalUintBE1); sdv::core::CSignal signalUintBE2 = dispatch.Subscribe("TestScaleBE.SignalScaleUintBE2", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[1]++; // Since the offset is a floating point value, but the data type is a unsigned integer, the value is being rounded. double dCalculated = static_cast(std::round(static_cast(ui) - 5.0 + 3.5)) - 3.5; // 4 bits - offset -3.5 EXPECT_EQ(dCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE2); sdv::core::CSignal signalUintBE3 = dispatch.Subscribe("TestScaleBE.SignalScaleUintBE3", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[2]++; int32_t iCalculated = static_cast(ui) * -1; // 4 bits - factor -1 EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE3); sdv::core::CSignal signalUintBE4 = dispatch.Subscribe("TestScaleBE.SignalScaleUintBE4", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[3]++; int32_t iCalculated = static_cast(ui) - 1; // 4 bits - offset -2 EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintBE4); sdv::core::CSignal signalIntBE5 = dispatch.Subscribe("TestScaleBE.SignalScaleIntBE5", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[4]++; float fCalculated = static_cast(ui) / 1000.0f; // 4 bits incl. sign - factor 0.001, offset 0.008 EXPECT_EQ(fCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE5); sdv::core::CSignal signalIntBE6 = dispatch.Subscribe("TestScaleBE.SignalScaleIntBE6", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[5]++; // Since the offset is a floating point value, but the data type is a integer, the value is being rounded. double dCalculated = static_cast(std::round(static_cast(ui) - 10.0 + 3.5)) - 3.5; // 4 bits incl. sign - offset -3.5 EXPECT_EQ(dCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntBE6); sdv::core::CSignal signalFloatBE7 = dispatch.Subscribe("TestScaleBE.SignalScaleFloatBE7", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[6]++; float fCalculated = static_cast(ui) / 10000.0f; // 32 bits - factor 0.001, offset 100 EXPECT_EQ(std::round(fCalculated * 1000.f), std::round(static_cast(tVal) * 1000.f)); }); EXPECT_TRUE(signalFloatBE7); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); // Check for correct counters for (uint32_t ui : rguiCnt) EXPECT_EQ(ui, 12u); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalUintBE1.Reset(); signalUintBE2.Reset(); signalUintBE3.Reset(); signalUintBE4.Reset(); signalIntBE5.Reset(); signalIntBE6.Reset(); signalFloatBE7.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, SpontaneousTransmitLittleEndianScaledDataTypes) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to integer based signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalUintLE1 = dispatch.AddPublisher("TestScaleLE.SignalScaleUintLE1"); EXPECT_TRUE(signalUintLE1); sdv::core::CSignal signalUintLE2 = dispatch.AddPublisher("TestScaleLE.SignalScaleUintLE2"); EXPECT_TRUE(signalUintLE2); sdv::core::CSignal signalUintLE3 = dispatch.AddPublisher("TestScaleLE.SignalScaleUintLE3"); EXPECT_TRUE(signalUintLE3); sdv::core::CSignal signalUintLE4 = dispatch.AddPublisher("TestScaleLE.SignalScaleUintLE4"); EXPECT_TRUE(signalUintLE4); sdv::core::CSignal signalIntLE5 = dispatch.AddPublisher("TestScaleLE.SignalScaleIntLE5"); EXPECT_TRUE(signalIntLE5); sdv::core::CSignal signalIntLE6 = dispatch.AddPublisher("TestScaleLE.SignalScaleIntLE6"); EXPECT_TRUE(signalIntLE6); sdv::core::CSignal signalFloatLE7 = dispatch.AddPublisher("TestScaleLE.SignalScaleFloatLE7"); EXPECT_TRUE(signalFloatLE7); appcontrol.SetRunningMode(); for (size_t n = 4; n < 12; n++) { sdv::core::CTransaction transaction = dispatch.CreateTransaction(); signalUintLE1.Write(static_cast(n) / 1000.0, transaction); // 4 bits - factor 0.001 signalUintLE2.Write(static_cast(n) - 5, transaction); // 4 bits - offset -3.5 signalUintLE3.Write(static_cast(n) * -1, transaction); // 4 bits - factor -1 signalUintLE4.Write(static_cast(n) - 1, transaction); // 4 bits - offset -2 signalIntLE5.Write(static_cast(n) / 1000.0f, transaction); // 4 bits incl. sign - factor 0.001, offset 0.008 signalIntLE6.Write(static_cast(n) - 10, transaction); // 4 bits incl. sign - offset -3.5 signalFloatLE7.Write(static_cast(n) / 10000.0f, transaction); // 32 bits - factor 0.001, offset 100 transaction.Finish(); } // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalUintLE1.Reset(); signalUintLE2.Reset(); signalUintLE3.Reset(); signalUintLE4.Reset(); signalIntLE5.Reset(); signalIntLE6.Reset(); signalFloatLE7.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[7]; } rgsData[] = { { 0x1F4, {0x34, 0x54, 0xDC, 0xCD, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x45, 0x65, 0xED, 0xBF, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x56, 0x76, 0xFE, 0xB2, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x67, 0x87, 0x1F, 0xA6, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x78, 0x98, 0x20, 0x99, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x89, 0xA9, 0x31, 0x8C, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x9A, 0xBA, 0x42, 0x7F, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0xAB, 0xCB, 0x53, 0x73, 0x4F, 0xC3, 0xC7}} }; // Compare with test data. for (const STestData& sData : rgsData) { EXPECT_FALSE(reader.IsEOF()); std::pair prMsg; do { prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; } while (!reader.IsEOF() && prMsg.first.uiId != sData.uiID); // Skip other messages EXPECT_EQ(prMsg.first.uiChannel, 1ul); EXPECT_EQ(prMsg.first.uiId, sData.uiID); EXPECT_FALSE(prMsg.first.bExtended); EXPECT_FALSE(prMsg.first.bCanFd); EXPECT_EQ(prMsg.first.uiLength, 7ul); EXPECT_EQ(prMsg.first.eDirection, asc::SCanMessage::EDirection::tx); EXPECT_EQ(prMsg.first.rguiData[0], sData.rguiData[0]); EXPECT_EQ(prMsg.first.rguiData[1], sData.rguiData[1]); EXPECT_EQ(prMsg.first.rguiData[2], sData.rguiData[2]); EXPECT_EQ(prMsg.first.rguiData[3], sData.rguiData[3]); EXPECT_EQ(prMsg.first.rguiData[4], sData.rguiData[4]); EXPECT_EQ(prMsg.first.rguiData[5], sData.rguiData[5]); EXPECT_EQ(prMsg.first.rguiData[6], sData.rguiData[6]); } } TEST(DbcUtilCanDLTest, ReceiveLittleEndianScaledDataType) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); struct STestData { uint32_t uiID; uint8_t rguiData[7]; } rgsData[] = { { 0x1F4, {0x34, 0x54, 0xDC, 0xCD, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x45, 0x65, 0xED, 0xBF, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x56, 0x76, 0xFE, 0xB2, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x67, 0x87, 0x1F, 0xA6, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x78, 0x98, 0x20, 0x99, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x89, 0xA9, 0x31, 0x8C, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0x9A, 0xBA, 0x42, 0x7F, 0x4F, 0xC3, 0xC7}}, { 0x1F4, {0xAB, 0xCB, 0x53, 0x73, 0x4F, 0xC3, 0xC7}} }; // Create ASC file with a delay of 100 (to allow the system to initialize) asc::CAscWriter writer; double dTimestamp = 0.100; for (const STestData& sData : rgsData) { asc::SCanMessage sMsg{}; sMsg.dTimestamp = dTimestamp; dTimestamp += 0.001; sMsg.uiChannel = 1ul; sMsg.uiId = sData.uiID; sMsg.bExtended = false; sMsg.bCanFd = false; sMsg.uiLength = 7ul; sMsg.eDirection = asc::SCanMessage::EDirection::rx; sMsg.rguiData[0] = sData.rguiData[0]; sMsg.rguiData[1] = sData.rguiData[1]; sMsg.rguiData[2] = sData.rguiData[2]; sMsg.rguiData[3] = sData.rguiData[3]; sMsg.rguiData[4] = sData.rguiData[4]; sMsg.rguiData[5] = sData.rguiData[5]; sMsg.rguiData[6] = sData.rguiData[6]; writer.AddSample(sMsg); } // Add a dummy message with a big timegap to prevent the repetition function to jump in. asc::SCanMessage sMsgDummy{}; sMsgDummy.dTimestamp = 100.0; sMsgDummy.uiChannel = 1ul; sMsgDummy.uiId = 999; writer.AddSample(sMsgDummy); // Write the ASC file EXPECT_TRUE(writer.Write(GetExecDirectory() / "receiver_test.asc")); writer.Clear(); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_rx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; uint32_t rguiCnt[7] = {4u, 4u, 4u, 4u, 4u, 4u, 4u}; sdv::core::CSignal signalUintLE1 = dispatch.Subscribe("TestScaleLE.SignalScaleUintLE1", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[0]++; double dCalculated = static_cast(ui) / 1000.0; // 4 bits - factor 0.001 EXPECT_EQ(std::round(dCalculated * 1000.0), std::round(static_cast(tVal) * 1000.0)); }); EXPECT_TRUE(signalUintLE1); sdv::core::CSignal signalUintLE2 = dispatch.Subscribe("TestScaleLE.SignalScaleUintLE2", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[1]++; // Since the offset is a floating point value, but the data type is a unsigned integer, the value is being rounded. double dCalculated = static_cast(std::round(static_cast(ui) - 5.0 + 3.5)) - 3.5; // 4 bits - offset -3.5 EXPECT_EQ(dCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE2); sdv::core::CSignal signalUintLE3 = dispatch.Subscribe("TestScaleLE.SignalScaleUintLE3", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[2]++; int32_t iCalculated = static_cast(ui) * -1; // 4 bits - factor -1 EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE3); sdv::core::CSignal signalUintLE4 = dispatch.Subscribe("TestScaleLE.SignalScaleUintLE4", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[3]++; int32_t iCalculated = static_cast(ui) - 1; // 4 bits - offset -2 EXPECT_EQ(iCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalUintLE4); sdv::core::CSignal signalIntLE5 = dispatch.Subscribe("TestScaleLE.SignalScaleIntLE5", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[4]++; float fCalculated = static_cast(ui) / 1000.0f; // 4 bits incl. sign - factor 0.001, offset 0.008 EXPECT_EQ(fCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE5); sdv::core::CSignal signalIntLE6 = dispatch.Subscribe("TestScaleLE.SignalScaleIntLE6", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[5]++; // Since the offset is a floating point value, but the data type is a integer, the value is being rounded. double dCalculated = static_cast(std::round(static_cast(ui) - 10.0 + 3.5)) - 3.5; // 4 bits incl. sign - offset -3.5 EXPECT_EQ(dCalculated, static_cast(tVal)); }); EXPECT_TRUE(signalIntLE6); sdv::core::CSignal signalFloatLE7 = dispatch.Subscribe("TestScaleLE.SignalScaleFloatLE7", [&](sdv::any_t tVal) { uint32_t ui = rguiCnt[6]++; float fCalculated = static_cast(ui) / 10000.0f; // 32 bits - factor 0.001, offset 100 EXPECT_EQ(std::round(fCalculated * 1000.f), std::round(static_cast(tVal) * 1000.f)); }); EXPECT_TRUE(signalFloatLE7); appcontrol.SetRunningMode(); std::this_thread::sleep_for(std::chrono::milliseconds(250)); // Check for correct counters for (uint32_t ui : rguiCnt) EXPECT_EQ(ui, 12u); // Shutdown appcontrol.SetConfigMode(); dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalUintLE1.Reset(); signalUintLE2.Reset(); signalUintLE3.Reset(); signalUintLE4.Reset(); signalIntLE5.Reset(); signalIntLE6.Reset(); signalFloatLE7.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); } TEST(DbcUtilCanDLTest, CyclicTransmit) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalCounter = dispatch.AddPublisher("TestCyclic.Counter"); EXPECT_TRUE(signalCounter); // The cycle time is 10 ms. Write the counter 5 times with 50ms difference size_t n = 0; std::mutex mtx; std::condition_variable cv; sdv::core::CTaskTimer timer(50, [&]() { if (n == 5) cv.notify_all(); else signalCounter.Write(n++); }); appcontrol.SetRunningMode(); std::unique_lock lock(mtx); cv.wait(lock); timer.Reset(); lock.unlock(); appcontrol.SetConfigMode(); // Shutdown dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalCounter.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); std::vector vecStat(5); std::vector vecTime(5); int32_t iCnt = -1; size_t nSignalCnt = 0; double dLastTime = 0; while (!reader.IsEOF()) { std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; dLastTime = prMsg.first.dTimestamp; // Only look at the cyclic message if (prMsg.first.uiId != 0x8) continue; nSignalCnt++; int32_t iCntTemp = static_cast(prMsg.first.rguiData[0] >> 5); EXPECT_TRUE(iCntTemp == iCnt || iCntTemp == iCnt + 1); iCnt = iCntTemp; EXPECT_LT(iCnt, 5); if (iCnt < 5) { vecStat[iCnt]++; if (iCnt && !vecTime[iCnt - 1]) vecTime[iCnt - 1] = prMsg.first.dTimestamp; } } if (!vecTime[4]) vecTime[4] = dLastTime; if (iCnt < 4) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_ENABLED); } for (n = 0; n < 5; n++) { if (n != 0) { if (vecStat[n] > 6u) // In the unlucky case, 6 triggers might have occurred (during startup, there might be many more...). { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(vecStat[n], 6u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(vecStat[n], 6u, sdv_test::WARNING_ENABLED); } double dPeriod = std::round((vecTime[n] - vecTime[n - 1]) * 1000.0) / 1000.0; if (dPeriod > 0.051) // Max 51ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_ENABLED); } if (n == 4) { if (dPeriod < 0.019) // Min 19ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_ENABLED); } } else { if (dPeriod < 0.039) // Min 39ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_ENABLED); } } } if (vecStat[n] < 4u) // At least 4 triggers. { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(vecStat[n], 4u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(vecStat[n], 4u, sdv_test::WARNING_ENABLED); } } } TEST(DbcUtilCanDLTest, CyclicIfActiveTransmit) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalCounter = dispatch.AddPublisher("TestCyclicIfActive.Counter"); EXPECT_TRUE(signalCounter); // The counter value 2 is the default value and therefore determines the active state. // The cycle time is 10 ms. Write the counter 5 times with 50ms difference size_t n = 0; std::mutex mtx; std::condition_variable cv; sdv::core::CTaskTimer timer(50, [&]() { if (n == 5) cv.notify_all(); else signalCounter.Write(n++); }); appcontrol.SetRunningMode(); std::unique_lock lock(mtx); cv.wait(lock); appcontrol.SetConfigMode(); timer.Reset(); // Shutdown dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalCounter.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); std::vector vecStat(5); std::vector vecTime(5); int32_t iCnt = -1; size_t nSignalCnt = 0; double dLastTime = 0; bool bInit = false; while (!reader.IsEOF()) { std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; dLastTime = prMsg.first.dTimestamp; // Only look at the cyclic message if (prMsg.first.uiId != 0xa) continue; nSignalCnt++; iCnt = static_cast(prMsg.first.rguiData[0] >> 5); EXPECT_LT(iCnt, 5); if (!bInit) { // Expected iCnt to be the default value... if (iCnt != 0 && iCnt != 2) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_EQ_WARN(iCnt, 0, sdv_test::WARNING_REDUCED); else SDV_EXPECT_EQ_WARN(iCnt, 0, sdv_test::WARNING_ENABLED); } bInit = true; } else if (iCnt < 5) { vecStat[iCnt]++; if (iCnt && !vecTime[iCnt - 1]) vecTime[iCnt - 1] = prMsg.first.dTimestamp; } } if (!vecTime[4]) vecTime[4] = dLastTime; if (iCnt < 4) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_ENABLED); } for (n = 0; n < 5; n++) { if (n != 0) { if (n == 2) { if (vecStat[n] != 1u) // One trigger should have occurred due to default value { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_EQ_WARN(vecStat[n], 1u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_EQ_WARN(vecStat[n], 1u, sdv_test::WARNING_ENABLED); } } else { if (vecStat[n] > 6u) // In the unlucky case, 6 triggers might have occurred (during startup, there might be many more...). { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(vecStat[n], 6u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(vecStat[n], 6u, sdv_test::WARNING_ENABLED); } } double dPeriod = std::round((vecTime[n] - vecTime[n - 1]) * 1000.0) / 1000.0; if (dPeriod > 0.051) // Max 51ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_ENABLED); } if (n == 4) { if (dPeriod < 0.019) // Min 19ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_ENABLED); } } else { if (dPeriod < 0.039) // Min 39ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_ENABLED); } } } } } TEST(DbcUtilCanDLTest, CyclicAndSpontaneousTransmit) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalCounter = dispatch.AddPublisher("TestCyclicAndSpontaneous.Counter"); EXPECT_TRUE(signalCounter); // The cycle time is 50 ms. Write a value every 50ms. This should result in a spontaneous and a cyclic trigger. size_t n = 0; std::mutex mtx; std::condition_variable cv; sdv::core::CTaskTimer timer(50, [&]() { if (n == 5) cv.notify_all(); else signalCounter.Write(n++); }); appcontrol.SetRunningMode(); std::unique_lock lock(mtx); cv.wait(lock); appcontrol.SetConfigMode(); timer.Reset(); // Shutdown dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalCounter.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); std::vector vecStat(5); std::vector vecTime(5); int32_t iCnt = -1; size_t nSignalCnt = 0; double dLastTime = 0; while (!reader.IsEOF()) { std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; dLastTime = prMsg.first.dTimestamp; // Only look at the cyclic message if (prMsg.first.uiId != 0x9) continue; nSignalCnt++; int32_t iCntTemp = static_cast(prMsg.first.rguiData[0] >> 5); EXPECT_TRUE(iCntTemp == iCnt || iCntTemp == iCnt + 1); iCnt = iCntTemp; EXPECT_LT(iCnt, 5); if (iCnt < 5) { vecStat[iCnt]++; if (iCnt && !vecTime[iCnt - 1]) vecTime[iCnt - 1] = prMsg.first.dTimestamp; } } if (!vecTime[4]) vecTime[4] = dLastTime; if (iCnt < 4) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_ENABLED); } for (n = 0; n < 5; n++) { if (n != 0) { if (vecStat[n] != 2u) // One trigger and one cycle. { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_EQ_WARN(vecStat[n], 2u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_EQ_WARN(vecStat[n], 2u, sdv_test::WARNING_ENABLED); } double dPeriod = std::round((vecTime[n] - vecTime[n - 1]) * 1000.0) / 1000.0; if (dPeriod > 0.051) // Max 51ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_ENABLED); } if (n == 4) { if (dPeriod < 0.019) // Min 19ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_ENABLED); } } else { if (dPeriod < 0.039) // Min 39ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_ENABLED); } } } } } TEST(DbcUtilCanDLTest, SpontaneousDelayTransmit) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalCounter = dispatch.AddPublisher("TestSpontaneousDelay.Counter"); EXPECT_TRUE(signalCounter); // The delay is 20ms. Write the counter 5 times every 10ms. size_t n = 0; std::mutex mtx; std::condition_variable cv; size_t nCycle = 0; sdv::core::CTaskTimer timer(10, [&]() { if (n < 5) signalCounter.Write(n); if (nCycle++ == 5) { nCycle = 0; if (n == 5) cv.notify_all(); n++; } }); appcontrol.SetRunningMode(); std::unique_lock lock(mtx); cv.wait(lock); appcontrol.SetConfigMode(); timer.Reset(); // Shutdown dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalCounter.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); std::vector vecStat(5); std::vector vecFirstTime(5); std::vector vecLastTime(5); int32_t iCnt = -1; size_t nSignalCnt = 0; while (!reader.IsEOF()) { std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; // Only look at the cyclic message if (prMsg.first.uiId != 0xc) continue; nSignalCnt++; int32_t iCntTemp = static_cast(prMsg.first.rguiData[0] >> 5); EXPECT_TRUE(iCntTemp == iCnt || iCntTemp == iCnt + 1); iCnt = iCntTemp; EXPECT_LT(iCnt, 5); if (iCnt < 5) { vecStat[iCnt]++; if (!vecFirstTime[iCnt]) vecFirstTime[iCnt] = prMsg.first.dTimestamp; vecLastTime[iCnt] = prMsg.first.dTimestamp; } } if (iCnt < 4) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_ENABLED); } for (n = 0; n < 5; n++) { if (n != 0) { if (vecStat[n] > 4u) // Max 4 times { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(vecStat[n], 4u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(vecStat[n], 4u, sdv_test::WARNING_ENABLED); } if (vecStat[n] < 3u) // Min 3 times { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(vecStat[n], 3u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(vecStat[n], 3u, sdv_test::WARNING_ENABLED); } double dPeriod = std::round((vecLastTime[n] - vecFirstTime[n]) * 1000.0) / 1000.0; if (dPeriod > 0.061) // Max 61ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(dPeriod, 0.061, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(dPeriod, 0.061, sdv_test::WARNING_ENABLED); } if (dPeriod < 0.039) // Min 39ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_ENABLED); } } } } TEST(DbcUtilCanDLTest, CyclicAndSpontaneousDelayTransmit) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalCounter = dispatch.AddPublisher("TestCyclicAndSpontaneousDelay.Counter"); EXPECT_TRUE(signalCounter); // The cycle time is 50ms. The delay is 25ms. Write the counter 2 times every 25ms. size_t n = 0; std::mutex mtx; std::condition_variable cv; sdv::core::CTaskTimer timer(25, [&]() { if (n == 10) cv.notify_all(); else { signalCounter.Write(n / 2); n++; } }); appcontrol.SetRunningMode(); std::unique_lock lock(mtx); cv.wait(lock); appcontrol.SetConfigMode(); timer.Reset(); // Shutdown dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalCounter.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); std::vector vecStat(5); std::vector vecTime(5); int32_t iCnt = -1; size_t nSignalCnt = 0; double dLastTime = 0; while (!reader.IsEOF()) { std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; dLastTime = prMsg.first.dTimestamp; // Only look at the cyclic message if (prMsg.first.uiId != 0xd) continue; nSignalCnt++; int32_t iCntTemp = static_cast(prMsg.first.rguiData[0] >> 5); EXPECT_TRUE(iCntTemp == iCnt || iCntTemp == iCnt + 1); iCnt = iCntTemp; EXPECT_LT(iCnt, 5); if (iCnt < 5) { vecStat[iCnt]++; if (iCnt && !vecTime[iCnt - 1]) vecTime[iCnt - 1] = prMsg.first.dTimestamp; } } if (!vecTime[4]) vecTime[4] = dLastTime; if (iCnt < 4) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_ENABLED); } for (n = 0; n < 5; n++) { if (n != 0) { if (vecStat[n] != 2u) // Two trigger and/or cycle. { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_EQ_WARN(vecStat[n], 2u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_EQ_WARN(vecStat[n], 2u, sdv_test::WARNING_ENABLED); } double dPeriod = std::round((vecTime[n] - vecTime[n - 1]) * 1000.0) / 1000.0; if (dPeriod > 0.051) // Max 51ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_ENABLED); } if (n == 4) { if (dPeriod < 0.019) // Min 19ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_ENABLED); } } else { if (dPeriod < 0.049) // Min 49ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.049, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.049, sdv_test::WARNING_ENABLED); } } } } } TEST(DbcUtilCanDLTest, CyclicIfActiveAndSpontaneousTransmit) { try { std::filesystem::remove(GetExecDirectory() / "receiver_test.asc"); std::filesystem::remove(GetExecDirectory() / "transmitter_test.asc"); } catch (const std::filesystem::filesystem_error&) {} EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "receiver_test.asc")); EXPECT_FALSE(std::filesystem::exists(GetExecDirectory() / "transmitter_test.asc")); std::filesystem::current_path(GetExecDirectory()); sdv::app::CAppControl appcontrol; bool bResult = appcontrol.Startup(""); EXPECT_TRUE(bResult); appcontrol.SetConfigMode(); sdv::core::EConfigProcessResult eResult = appcontrol.LoadConfig("test_dbc_util_config_tx.toml"); EXPECT_EQ(eResult, sdv::core::EConfigProcessResult::successful); // Start the data link CDbcStructDataLink dl; EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialization_pending); dl.Initialize(""); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::initialized); dl.SetOperationMode(sdv::EOperationMode::running); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::running); // Subscribe to several signals sdv::core::CDispatchService dispatch; sdv::core::CSignal signalCounter = dispatch.AddPublisher("TestCyclicIfActiveAndSpontaneous.Counter"); EXPECT_TRUE(signalCounter); // The cycle time is 50 ms. Write a value every 50ms. This should result in a spontaneous and a cyclic trigger. size_t n = 0; std::mutex mtx; std::condition_variable cv; sdv::core::CTaskTimer timer(50, [&]() { if (n == 5) cv.notify_all(); else signalCounter.Write(n++); }); appcontrol.SetRunningMode(); std::unique_lock lock(mtx); cv.wait(lock); appcontrol.SetConfigMode(); timer.Reset(); // Shutdown dl.Shutdown(); EXPECT_EQ(dl.GetStatus(), sdv::EObjectStatus::destruction_pending); signalCounter.Reset(); // Shutdown. This will close the CAN recording. appcontrol.Shutdown(); // Read the CAN recording. asc::CAscReader reader; EXPECT_TRUE(reader.Read(GetExecDirectory() / "transmitter_test.asc")); std::vector vecStat(5); std::vector vecTime(5); int32_t iCnt = -1; size_t nSignalCnt = 0; double dLastTime = 0; bool bInit = false; while (!reader.IsEOF()) { std::pair prMsg = reader.Get(); EXPECT_TRUE(prMsg.second); ++reader; dLastTime = prMsg.first.dTimestamp; // Only look at the cyclic message if (prMsg.first.uiId != 0xb) continue; nSignalCnt++; iCnt = static_cast(prMsg.first.rguiData[0] >> 5); EXPECT_LT(iCnt, 5); if (!bInit) { // Expected iCnt to be the default value... if (iCnt != 0 && iCnt != 2) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_EQ_WARN(iCnt, 0, sdv_test::WARNING_REDUCED); else SDV_EXPECT_EQ_WARN(iCnt, 0, sdv_test::WARNING_ENABLED); } bInit = true; } else if (iCnt < 5) { vecStat[iCnt]++; if (iCnt && !vecTime[iCnt - 1]) vecTime[iCnt - 1] = prMsg.first.dTimestamp; } } if (!vecTime[4]) vecTime[4] = dLastTime; if (iCnt < 4) { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(iCnt, 4, sdv_test::WARNING_ENABLED); } for (n = 0; n < 5; n++) { if (n != 0) { if (n == 2) { if (vecStat[n] != 1u) // One trigger no cycle. { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_EQ_WARN(vecStat[n], 1u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_EQ_WARN(vecStat[n], 1u, sdv_test::WARNING_ENABLED); } } else { if (vecStat[n] != 2u) // One trigger and one cycle. { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_EQ_WARN(vecStat[n], 2u, sdv_test::WARNING_REDUCED); else SDV_EXPECT_EQ_WARN(vecStat[n], 2u, sdv_test::WARNING_ENABLED); } } double dPeriod = std::round((vecTime[n] - vecTime[n - 1]) * 1000.0) / 1000.0; if (dPeriod > 0.051) // Max 51ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_REDUCED); else SDV_EXPECT_LE_WARN(dPeriod, 0.051, sdv_test::WARNING_ENABLED); } if (n == 4) { if (dPeriod < 0.019) // Min 19ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.019, sdv_test::WARNING_ENABLED); } } else { if (dPeriod < 0.039) // Min 39ms { if(SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD) SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_REDUCED); else SDV_EXPECT_GE_WARN(dPeriod, 0.039, sdv_test::WARNING_ENABLED); } } } } }