Device/Disk: Add VSA read and parse functionality

Implement ability to extract network traffic (CAN, LIN, Ethernet, etc.) from VSA message records on disk. Add a method to Device class that uses the VSAParser and the individual record types to extract messages from the VSA message records and pass them back to the communication system. This routes messages such that it appears as if they were discovered live instead of read from disk. The parse process (in Device) requires determination of metadata about the VSA file system on a device before it can begin extracting messages. This currently only handles data captured from the current coremini script on a device.
This commit is contained in:
Max Brombach
2023-11-15 16:02:47 +00:00
parent 4248c1a538
commit 02f1b4592e
43 changed files with 4122 additions and 20 deletions
+5
View File
@@ -8,6 +8,7 @@ option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON)
option(LIBICSNEO_BUILD_CPP_LIVEDATA_EXAMPLE "Build the Live Data example." ON)
option(LIBICSNEO_BUILD_CPP_COREMINI_EXAMPLE "Build the Coremini example." ON)
option(LIBICSNEO_BUILD_CPP_MDIO_EXAMPLE "Build the MDIO example." ON)
option(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE "Build the VSA example." ON)
# Disabled until we properly build these in-tree
# option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF)
@@ -53,6 +54,10 @@ if(LIBICSNEO_BUILD_CPP_MDIO_EXAMPLE)
add_subdirectory(cpp/mdio)
endif()
if(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE)
add_subdirectory(cpp/vsa)
endif()
# if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE)
# add_subdirectory(csharp)
# endif()
+27
View File
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.2)
project(libicsneocpp-vsa-example VERSION 0.1.0)
set(CMAKE_CXX_STANDARD_REQUIRED 11)
include(GNUInstallDirs)
# Add an include directory like so if desired
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
# Enable Warnings
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
endif()
# Add libicsneo, usually a git submodule within your project works well
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
add_executable(libicsneocpp-vsa-example src/VSAExample.cpp)
target_link_libraries(libicsneocpp-vsa-example icsneocpp)
+94
View File
@@ -0,0 +1,94 @@
#include <iostream>
#include <random>
#include "icsneo/icsneocpp.h"
void onEvent(std::shared_ptr<icsneo::APIEvent> event) {
std::cout << event->describe() << std::endl;
}
int main(int argc, char* argv[]) {
if(argc != 2) {
std::cout << "Usage: libicsneocpp-vsa-example <device serial>" << std::endl;
return -1;
}
std::string deviceSerial = argv[1];
// register an event callback so we can see all logged events
icsneo::EventManager::GetInstance().addEventCallback(icsneo::EventCallback(onEvent));
auto devices = icsneo::FindAllDevices();
if(devices.empty()) {
std::cout << "error: no devices found" << std::endl;
return -1;
}
std::shared_ptr<icsneo::Device> device;
for(auto&& d : devices) {
if(deviceSerial == d->getSerial()) {
device = d;
}
}
if(!device) {
std::cout << "error: failed to find a device with serial number: " << deviceSerial << std::endl;
return -1;
}
std::cout << "info: found " << device->describe() << std::endl;
if(!device->open()) {
std::cout << "error: unable to open device" << std::endl;
}
device->stopScript();
uint64_t firstOffset;
std::shared_ptr<icsneo::VSA> firstRecord;
if(!device->findFirstVSARecord(firstOffset, firstRecord)) {
std::cout << "error: unable to find first VSA record" << std::endl;
return -1;
}
std::cout << "info: found first VSA record at " << firstOffset << std::endl;
uint64_t origLastOffset;
std::shared_ptr<icsneo::VSA> origLastRecord;
if(!device->findLastVSARecord(origLastOffset, origLastRecord)) {
std::cout << "error: unable to find last VSA record" << std::endl;
return -1;
}
std::cout << "info: found last VSA record at " << origLastOffset << std::endl;
uint64_t canFrameCount = 0;
uint64_t ethFrameCount = 0;
device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
if(msg->type != icsneo::Message::Type::Frame) {
return;
}
const auto frame = std::static_pointer_cast<icsneo::Frame>(msg);
if(frame->network.getType() == icsneo::Network::Type::CAN) {
++canFrameCount;
} else if(frame->network.getType() == icsneo::Network::Type::Ethernet) {
++ethFrameCount;
}
}));
icsneo::VSAExtractionSettings settings;
{
auto& filter = settings.filters.emplace_back();
filter.readRange.first = origLastRecord->getTimestampICSClock() - std::chrono::seconds(20);
filter.readRange.second = origLastRecord->getTimestampICSClock() - std::chrono::seconds(10);
}
{
auto& filter = settings.filters.emplace_back();
filter.readRange.first = firstRecord->getTimestampICSClock() + std::chrono::seconds(0);
filter.readRange.second = firstRecord->getTimestampICSClock() + std::chrono::seconds(10);
}
std::cout << "info: reading two blocks of VSA, 10s from the start and 10s from the end..." << std::endl;
if(!device->readVSA(settings)) {
std::cout << "error: unable to read VSA" << std::endl;
return -1;
}
std::cout << "info: processed " << canFrameCount << " CAN frames and " << ethFrameCount << " Ethernet frames" << std::endl;
return 0;
}