From b45cbaefca266e77704f41687fa1d55e36511780 Mon Sep 17 00:00:00 2001 From: Viktor Kopp Date: Sun, 24 Nov 2024 21:35:22 +0100 Subject: [PATCH] Control message payload parsing use ctrlmsg parsing function add test Signed-off-by: Viktor Kopp --- qdlt/CMakeLists.txt | 2 + qdlt/qdltctrlmsg.cpp | 151 ++++++++++++++++++++++ qdlt/qdltctrlmsg.h | 71 +++++++++++ qdlt/tests/CMakeLists.txt | 2 + qdlt/tests/test_dltctrlmsg.cpp | 28 ++++ src/mainwindow.cpp | 226 +++++++++------------------------ 6 files changed, 313 insertions(+), 167 deletions(-) create mode 100644 qdlt/qdltctrlmsg.cpp create mode 100644 qdlt/qdltctrlmsg.h create mode 100644 qdlt/tests/test_dltctrlmsg.cpp diff --git a/qdlt/CMakeLists.txt b/qdlt/CMakeLists.txt index de850cfa..163f9b00 100644 --- a/qdlt/CMakeLists.txt +++ b/qdlt/CMakeLists.txt @@ -45,6 +45,8 @@ add_library(qdlt SHARED qdltlrucache.hpp export_c_rules.h export_rules.h + qdltctrlmsg.cpp + qdltctrlmsg.h ) target_compile_definitions(qdlt PRIVATE diff --git a/qdlt/qdltctrlmsg.cpp b/qdlt/qdltctrlmsg.cpp new file mode 100644 index 00000000..8d4fb332 --- /dev/null +++ b/qdlt/qdltctrlmsg.cpp @@ -0,0 +1,151 @@ +#include "qdltctrlmsg.h" + +#include "dlt_common.h" + +#include +#include +#include + +#include + +namespace qdlt::msg::payload { + +namespace { +using IdType = std::array; + +QString asQString(IdType&& id) { + QString str; + for (size_t i = 0; i < id.size() && id[i] != '\0'; i++) { + str.append(id[i]); + } + return str; +} + +template +T dltPayloadRead(const char *&dataPtr, int32_t &length, bool isBigEndian) +{ + if (sizeof(T) > static_cast(length)) { + throw std::runtime_error("Invalid data length"); + } + + T value{}; + std::memcpy(&value, dataPtr, sizeof(T)); + dataPtr += sizeof(T); + length -= sizeof(T); + + if constexpr (sizeof(T) == sizeof(uint32_t)) { + value = DLT_ENDIAN_GET_32((isBigEndian ? DLT_HTYP_MSBF : 0), value); + } + + if constexpr (sizeof(T) == sizeof(uint16_t)) { + value = DLT_ENDIAN_GET_16((isBigEndian ? DLT_HTYP_MSBF : 0), value); + } + + return value; +} + +IdType dltPayloadReadId(const char *&dataPtr, int32_t &length) +{ + if (DLT_ID_SIZE > length) { + throw std::runtime_error("Invalid ID length"); + } + IdType id{}; + std::copy(dataPtr, dataPtr + DLT_ID_SIZE, id.begin()); + dataPtr += DLT_ID_SIZE; + length -= DLT_ID_SIZE; + + return id; +} + +std::string dltPayloadReadString(const char *&dataPtr, int32_t &length, bool isBigEndian) +{ + uint16_t strLength = dltPayloadRead(dataPtr, length, isBigEndian); + if (strLength > length) { + throw std::runtime_error("Invalid string length"); + } + std::string str; + str.assign(dataPtr, strLength); + dataPtr += strLength; + length -= strLength; + + return str; +} +} + +Type parse(const QByteArray& data, bool isBigEndian) +{ + int32_t length = data.length(); + const char *dataPtr = data.data(); + + auto service_id = dltPayloadRead(dataPtr, length, isBigEndian); + + switch (service_id) { + case DLT_SERVICE_ID_GET_LOG_INFO: + { + GetLogInfo msg; + msg.status = dltPayloadRead(dataPtr, length, isBigEndian); + if ((msg.status != 6) && (msg.status != 7)) { + return msg; + } + + const auto numApps = dltPayloadRead(dataPtr, length, isBigEndian); + for (uint16_t i = 0; i < numApps; i++) { + GetLogInfo::App app; + app.id = asQString(dltPayloadReadId(dataPtr, length)); + const uint16_t numCtx = dltPayloadRead(dataPtr, length, isBigEndian); + for (uint16_t j = 0; j < numCtx; j++) { + GetLogInfo::App::Ctx ctx; + ctx.id = asQString(dltPayloadReadId(dataPtr, length)); + ctx.logLevel = dltPayloadRead(dataPtr, length, isBigEndian); + ctx.traceStatus = dltPayloadRead(dataPtr, length, isBigEndian); + ctx.description = QString::fromStdString(dltPayloadReadString(dataPtr, length, isBigEndian)); + app.ctxs.push_back(std::move(ctx)); + } + if (msg.status == 7) { + app.description = QString::fromStdString(dltPayloadReadString(dataPtr, length, isBigEndian)); + } + msg.apps.push_back(std::move(app)); + } + return msg; + } + case DLT_SERVICE_ID_GET_SOFTWARE_VERSION: + { + GetSoftwareVersion msg; + msg.version = dltPayloadReadString(dataPtr, length, isBigEndian); + return msg; + } + case DLT_SERVICE_ID_GET_DEFAULT_LOG_LEVEL: + { + GetDefaultLogLevel msg; + msg.logLevel = dltPayloadRead(dataPtr, length, isBigEndian); + msg.status = dltPayloadRead(dataPtr, length, isBigEndian); + return msg; + } + case DLT_SERVICE_ID_SET_LOG_LEVEL: + { + SetLogLevel msg; + msg.status = dltPayloadRead(dataPtr, length, isBigEndian); + return msg; + } + case DLT_SERVICE_ID_TIMEZONE: + { + Timezone msg; + msg.status = dltPayloadRead(dataPtr, length, isBigEndian); + msg.timezone = dltPayloadRead(dataPtr, length, isBigEndian); + msg.isDst = dltPayloadRead(dataPtr, length, isBigEndian); + return msg; + } + case DLT_SERVICE_ID_UNREGISTER_CONTEXT: + { + UnregisterContext msg; + msg.status = dltPayloadRead(dataPtr, length, isBigEndian); + msg.appid = asQString(dltPayloadReadId(dataPtr, length)); + msg.ctxid = asQString(dltPayloadReadId(dataPtr, length)); + return msg; + } + } + + throw std::runtime_error("Unknown service type"); +} + +} diff --git a/qdlt/qdltctrlmsg.h b/qdlt/qdltctrlmsg.h new file mode 100644 index 00000000..c9fe634b --- /dev/null +++ b/qdlt/qdltctrlmsg.h @@ -0,0 +1,71 @@ +#ifndef QDLTCTRLMSG_H +#define QDLTCTRLMSG_H + +#include +#include + +#include +#include + + +namespace qdlt::msg::payload { + +struct GetLogInfo { + struct App { + struct Ctx { + QString id; + int8_t logLevel; + int8_t traceStatus; + QString description; + }; + + QString id; + QString description; + std::vector ctxs; + }; + + uint8_t status; + std::vector apps; +}; + +struct GetSoftwareVersion { + std::string version; +}; + +struct GetDefaultLogLevel +{ + uint8_t logLevel; + uint8_t status; +}; + +struct SetLogLevel { + uint8_t status; +}; + +struct Timezone { + uint8_t status; + int32_t timezone; + uint8_t isDst; +}; + +struct UnregisterContext { + uint8_t status; + QString appid; + QString ctxid; +}; + +using Type = std::variant; + +Type parse(const QByteArray&, bool isBigEndian); + +} // namespace qdlt::msg::payload + +// helper type for the visitor +template +struct overloaded : Ts... { using Ts::operator()...; }; +// explicit deduction guide (not needed as of C++20) +template +overloaded(Ts...) -> overloaded; + +#endif // QDLTCTRLMSG_H diff --git a/qdlt/tests/CMakeLists.txt b/qdlt/tests/CMakeLists.txt index 7b65fda1..d0cd6863 100644 --- a/qdlt/tests/CMakeLists.txt +++ b/qdlt/tests/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(test_dltmessagematcher test_dltmessagematcher.cpp + test_dltctrlmsg.cpp ) target_link_libraries( test_dltmessagematcher @@ -16,6 +17,7 @@ add_test( add_executable(test_dltoptmanager test_dltoptmanager.cpp + test_dltctrlmsg.cpp ) target_link_libraries( diff --git a/qdlt/tests/test_dltctrlmsg.cpp b/qdlt/tests/test_dltctrlmsg.cpp new file mode 100644 index 00000000..f698f52c --- /dev/null +++ b/qdlt/tests/test_dltctrlmsg.cpp @@ -0,0 +1,28 @@ +#include + +#include + +#include + +TEST(CtrlPayload, parse) { + // this is real payload of a dlt control message which collect from dlt-daemon + const auto data = QByteArray::fromHex("030000000701005359530001004d475200ffff2200436f6e74657874206f66206d61696e20646c742073797374656d206d616e616765721200444c542053797374656d204d616e6167657272656d6f"); + + auto payload = qdlt::msg::payload::parse(data, false); + + ASSERT_TRUE(std::holds_alternative(payload)); + auto getLogInfo = std::get(payload); + EXPECT_EQ(getLogInfo.status, 7); + ASSERT_EQ(getLogInfo.apps.size(), 1); + + auto app = getLogInfo.apps[0]; + EXPECT_EQ(app.id, "SYS"); + EXPECT_EQ(app.description, "DLT System Manager"); + ASSERT_EQ(app.ctxs.size(), 1); + + auto ctx = app.ctxs[0]; + EXPECT_EQ(ctx.id, "MGR"); + EXPECT_EQ(ctx.logLevel, '\xff'); + EXPECT_EQ(ctx.traceStatus, '\xff'); + EXPECT_EQ(ctx.description, "Context of main dlt system manager"); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5f2a5ec6..d3c911ec 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -87,6 +87,7 @@ extern "C" { #include "tablemodel.h" #include "sortfilterproxymodel.h" #include "qdltoptmanager.h" +#include "qdltctrlmsg.h" MainWindow::MainWindow(QWidget *parent) : @@ -2064,8 +2065,9 @@ void MainWindow::reloadLogFileFinishFilter() // FIXME: this is slow operation running in the main loop QDltMsg msg; for (const auto msgIndex : msgIndexList) { - if (qfile.getMsg(msgIndex, msg)) + if (qfile.getMsg(msgIndex, msg)) { contextLoadingFile(msg); + } } } @@ -4455,172 +4457,62 @@ void MainWindow::onSearchresultsTableSelectionChanged(const QItemSelection & sel void MainWindow::controlMessage_ReceiveControlMessage(EcuItem *ecuitem, const QDltMsg &msg) { - const char *ptr; - int32_t length; - - QByteArray payload = msg.getPayload(); - ptr = payload.constData(); - length = payload.size(); - - /* control message was received */ - uint32_t service_id_tmp=0; - DLT_MSG_READ_VALUE(service_id_tmp,ptr,length,uint32_t); - uint32_t service_id=DLT_ENDIAN_GET_32( ((msg.getEndianness()==QDlt::DltEndiannessBigEndian)?DLT_HTYP_MSBF:0), service_id_tmp); - - switch (service_id) - { - case DLT_SERVICE_ID_GET_SOFTWARE_VERSION: - { - // check if plugin autoload enabled and version string not already parsed - if(!autoloadPluginsVersionEcus.contains(msg.getEcuid())) - { - versionString(msg); - autoloadPluginsVersionEcus.append(msg.getEcuid()); - } - break; - } - case DLT_SERVICE_ID_GET_LOG_INFO: - { - /* Only status 1,2,6,7,8 is supported yet! */ - - uint8_t status=0; - DLT_MSG_READ_VALUE(status,ptr,length,uint8_t); /* No endian conversion necessary */ - - /* Support for status=8 */ - if (status==8) - { - ecuitem->InvalidAll(); - } - - /* Support for status=6 and status=7 */ - if ((status==6) || (status==7)) - { - uint16_t count_app_ids=0,count_app_ids_tmp=0; - DLT_MSG_READ_VALUE(count_app_ids_tmp,ptr,length,uint16_t); - count_app_ids=DLT_ENDIAN_GET_16(((msg.getEndianness()==QDlt::DltEndiannessBigEndian)?DLT_HTYP_MSBF:0), count_app_ids_tmp); - for (int32_t num=0;numloglevel = loglevel; - ecuitem->status = EcuItem::valid; - } - break; - case 1: /* NOT_SUPPORTED */ - { - ecuitem->status = EcuItem::unknown; - } - break; - case 2: /* ERROR */ - { - ecuitem->status = EcuItem::invalid; - } - break; - } - /* update status */ - ecuitem->update(); - - break; - } - case DLT_SERVICE_ID_SET_LOG_LEVEL: - { - break; - } - case DLT_SERVICE_ID_TIMEZONE: - { - if(payload.size() == sizeof(DltServiceTimezone)) - { - DltServiceTimezone *service; - service = (DltServiceTimezone*) payload.constData(); - - if(msg.getEndianness() == QDlt::DltEndiannessLittleEndian) - controlMessage_Timezone(service->timezone, service->isdst); - else - controlMessage_Timezone(DLT_SWAP_32(service->timezone), service->isdst); - } - break; - } - case DLT_SERVICE_ID_UNREGISTER_CONTEXT: - { - if(payload.size() == sizeof(DltServiceUnregisterContext)) - { - DltServiceUnregisterContext *service; - service = (DltServiceUnregisterContext*) payload.constData(); - - controlMessage_UnregisterContext(msg.getEcuid(),QDltMsg::getStringFromId(service->apid),QDltMsg::getStringFromId(service->ctid)); - } - break; - } - } // switch + auto ctrlMsg = qdlt::msg::payload::parse(msg.getPayload(), msg.getEndianness() == QDlt::DltEndiannessBigEndian); + std::visit(overloaded{[&](const qdlt::msg::payload::GetSoftwareVersion &) { + // TODO: use parsed payload + // check if plugin autoload enabled and version string not already parsed + if(!autoloadPluginsVersionEcus.contains(msg.getEcuid())) + { + versionString(msg); + autoloadPluginsVersionEcus.append(msg.getEcuid()); + } + }, + [&](const qdlt::msg::payload::GetLogInfo &payload) { + if (payload.status == 8) + { + ecuitem->InvalidAll(); + } + + if (payload.status == 6 || payload.status == 7) { + for (const auto &app : payload.apps) { + for (const auto& ctx : app.ctxs) { + controlMessage_SetContext(ecuitem, app.id, ctx.id, + ctx.description, ctx.logLevel, + ctx.traceStatus); + } + if (payload.status == 7) { + controlMessage_SetApplication(ecuitem, app.id, + app.description); + } + } + } + }, + [&](const qdlt::msg::payload::GetDefaultLogLevel &payload) { + switch (payload.status) { + case 0: /* OK */ + ecuitem->loglevel = payload.logLevel; + ecuitem->status = EcuItem::valid; + break; + case 1: /* NOT_SUPPORTED */ + ecuitem->status = EcuItem::unknown; + break; + case 2: /* ERROR */ + ecuitem->status = EcuItem::invalid; + break; + } + ecuitem->update(); + }, + [&](const qdlt::msg::payload::Timezone &payload) { + controlMessage_Timezone(payload.timezone, payload.isDst); + }, + [&](const qdlt::msg::payload::UnregisterContext &payload) { + controlMessage_UnregisterContext(msg.getEcuid(), payload.appid, + payload.ctxid); + }, + [&](const qdlt::msg::payload::SetLogLevel &) { + // nothing to do + }}, + ctrlMsg); } void MainWindow::controlMessage_SendControlMessage(EcuItem* ecuitem,DltMessage &msg, QString appid, QString contid)