Skip to content

Commit

Permalink
Control message payload parsing
Browse files Browse the repository at this point in the history
use ctrlmsg parsing function

add test

Signed-off-by: Viktor Kopp <[email protected]>
  • Loading branch information
vifactor committed Jan 7, 2025
1 parent 5a66b24 commit b45cbae
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 167 deletions.
2 changes: 2 additions & 0 deletions qdlt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
151 changes: 151 additions & 0 deletions qdlt/qdltctrlmsg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#include "qdltctrlmsg.h"

#include "dlt_common.h"

#include <stdexcept>
#include <cstring>
#include <array>

#include <QByteArray>

namespace qdlt::msg::payload {

namespace {
using IdType = std::array<char, DLT_ID_SIZE>;

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 <typename T>
T dltPayloadRead(const char *&dataPtr, int32_t &length, bool isBigEndian)
{
if (sizeof(T) > static_cast<uint32_t>(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<uint16_t>(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<uint32_t>(dataPtr, length, isBigEndian);

switch (service_id) {
case DLT_SERVICE_ID_GET_LOG_INFO:
{
GetLogInfo msg;
msg.status = dltPayloadRead<uint8_t>(dataPtr, length, isBigEndian);
if ((msg.status != 6) && (msg.status != 7)) {
return msg;
}

const auto numApps = dltPayloadRead<uint16_t>(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<uint16_t>(dataPtr, length, isBigEndian);
for (uint16_t j = 0; j < numCtx; j++) {
GetLogInfo::App::Ctx ctx;
ctx.id = asQString(dltPayloadReadId(dataPtr, length));
ctx.logLevel = dltPayloadRead<int8_t>(dataPtr, length, isBigEndian);
ctx.traceStatus = dltPayloadRead<int8_t>(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<int8_t>(dataPtr, length, isBigEndian);
msg.status = dltPayloadRead<uint8_t>(dataPtr, length, isBigEndian);
return msg;
}
case DLT_SERVICE_ID_SET_LOG_LEVEL:
{
SetLogLevel msg;
msg.status = dltPayloadRead<uint8_t>(dataPtr, length, isBigEndian);
return msg;
}
case DLT_SERVICE_ID_TIMEZONE:
{
Timezone msg;
msg.status = dltPayloadRead<uint8_t>(dataPtr, length, isBigEndian);
msg.timezone = dltPayloadRead<int32_t>(dataPtr, length, isBigEndian);
msg.isDst = dltPayloadRead<uint8_t>(dataPtr, length, isBigEndian);
return msg;
}
case DLT_SERVICE_ID_UNREGISTER_CONTEXT:
{
UnregisterContext msg;
msg.status = dltPayloadRead<uint8_t>(dataPtr, length, isBigEndian);
msg.appid = asQString(dltPayloadReadId(dataPtr, length));
msg.ctxid = asQString(dltPayloadReadId(dataPtr, length));
return msg;
}
}

throw std::runtime_error("Unknown service type");
}

}
71 changes: 71 additions & 0 deletions qdlt/qdltctrlmsg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#ifndef QDLTCTRLMSG_H
#define QDLTCTRLMSG_H

#include <vector>
#include <variant>

#include <QByteArray>
#include <QString>


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<Ctx> ctxs;
};

uint8_t status;
std::vector<App> 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<GetLogInfo, GetSoftwareVersion, GetDefaultLogLevel, SetLogLevel, Timezone,
UnregisterContext>;

Type parse(const QByteArray&, bool isBigEndian);

} // namespace qdlt::msg::payload

// helper type for the visitor
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

#endif // QDLTCTRLMSG_H
2 changes: 2 additions & 0 deletions qdlt/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_executable(test_dltmessagematcher
test_dltmessagematcher.cpp
test_dltctrlmsg.cpp
)
target_link_libraries(
test_dltmessagematcher
Expand All @@ -16,6 +17,7 @@ add_test(

add_executable(test_dltoptmanager
test_dltoptmanager.cpp
test_dltctrlmsg.cpp
)

target_link_libraries(
Expand Down
28 changes: 28 additions & 0 deletions qdlt/tests/test_dltctrlmsg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <gtest/gtest.h>

#include <qdltctrlmsg.h>

#include <QByteArray>

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<qdlt::msg::payload::GetLogInfo>(payload));
auto getLogInfo = std::get<qdlt::msg::payload::GetLogInfo>(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");
}
Loading

0 comments on commit b45cbae

Please sign in to comment.