Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Do not block UI when building ECUs tree #606

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 2 additions & 0 deletions qdlt/qdlt.pro
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ SOURCES += \
fieldnames.cpp \
qdltimporter.cpp \
dltmessagematcher.cpp \
qdltctrlmsg.cpp \

HEADERS += qdlt.h \
export_rules.h \
Expand Down Expand Up @@ -101,6 +102,7 @@ HEADERS += qdlt.h \
fieldnames.h \
qdltimporter.h \
dltmessagematcher.h \
qdltctrlmsg.h \

unix:VERSION = 1.0.0

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");
}

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

#include "export_rules.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>;

QDLT_EXPORT 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");
}
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ add_executable(dlt-viewer
searchform.cpp
${UI_RESOURCES_RCC}
resources/dlt_viewer.rc
)
ecutree.h
ecutree.cpp
)

target_link_libraries(dlt-viewer
qdlt
Expand Down
17 changes: 17 additions & 0 deletions src/ecutree.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "ecutree.h"

void EcuTree::add(const QString& ecuId, const qdlt::msg::payload::GetLogInfo& info)
{
for (const auto& app : info.apps) {
App appData;
appData.description = app.description;
for (const auto& ctx : app.ctxs) {
Ctx ctxData;
ctxData.description = ctx.description;
ctxData.logLevel = ctx.logLevel;
ctxData.traceStatus = ctx.traceStatus;
appData.contexts[ctx.id] = std::move(ctxData);
}
ecus[ecuId][app.id] = std::move(appData);
}
}
27 changes: 27 additions & 0 deletions src/ecutree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef ECUTREEBUILDER_H
#define ECUTREEBUILDER_H

#include <qdltctrlmsg.h>

#include <map>

struct EcuTree
{
void add(const QString& ecuId, const qdlt::msg::payload::GetLogInfo&);

using EcuId = QString;
using AppId = QString;
using CtxId = QString;
struct Ctx {
QString description;
int8_t logLevel;
int8_t traceStatus;
};
struct App {
QString description;
std::map<CtxId, Ctx> contexts;
};
std::map<EcuId, std::map<AppId, App>> ecus;
};

#endif // ECUTREEBUILDER_H
Loading