mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 09:28:40 +02:00
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:
@@ -0,0 +1,39 @@
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
#include "icsneo/communication/packet/ethernetpacket.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
// VSA Base Class Functions
|
||||
|
||||
// VSAMessage Class Functions
|
||||
std::shared_ptr<Packet> VSAMessage::getPacket() const
|
||||
{
|
||||
auto packet = std::make_shared<Packet>();
|
||||
packet->network = network;
|
||||
reservePacketData(packet);
|
||||
packet->data.insert(packet->data.end(), payload.begin(), payload.end());
|
||||
return packet;
|
||||
}
|
||||
|
||||
// VSAExtendedMessage Class Functions
|
||||
|
||||
void VSAExtendedMessage::appendPacket(std::shared_ptr<Packet> packet) const
|
||||
{
|
||||
packet->data.insert(packet->data.end(), payload.begin(), payload.end());
|
||||
// Set the network if not already set (Happens in AA0F records)
|
||||
if(packet->network.getNetID() == Network::NetID::Invalid) {
|
||||
packet->network = network;
|
||||
}
|
||||
}
|
||||
|
||||
void VSAExtendedMessage::truncatePacket(std::shared_ptr<Packet> packet)
|
||||
{
|
||||
static constexpr auto EthernetLengthOffset = 26u;
|
||||
switch(packet->network.getType()) {
|
||||
case Network::Type::Ethernet:
|
||||
const auto& packetLength = *reinterpret_cast<uint16_t*>(packet->data.data() + EthernetLengthOffset);
|
||||
const size_t ethernetFrameSize = packetLength - (sizeof(uint16_t) * 2);
|
||||
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + ethernetFrameSize;
|
||||
packet->data.resize(bytestreamExpectedSize);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "icsneo/disk/vsa/vsa02.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA02::VSA02(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA02);
|
||||
constantIndex = *reinterpret_cast<uint16_t*>(recordBytes + 2);
|
||||
flags = *reinterpret_cast<Flags*>(recordBytes + 4);
|
||||
pieceCount = recordBytes[5];
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
samples.insert(samples.end(), recordBytes + 14, recordBytes + 30);
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA02::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "icsneo/disk/vsa/vsa03.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA03::VSA03(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA03);
|
||||
eventType = static_cast<EventType>(*reinterpret_cast<uint16_t*>(recordBytes + 2));
|
||||
eventData = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA03::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "icsneo/disk/vsa/vsa04.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA04::VSA04(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA04);
|
||||
flags = *reinterpret_cast<Flags*>(recordBytes + 2);
|
||||
partitionIndex = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA04::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "icsneo/disk/vsa/vsa05.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA05::VSA05(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA05);
|
||||
errorType = static_cast<ErrorType>(*reinterpret_cast<uint16_t*>(recordBytes + 2));
|
||||
errorNetwork = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
|
||||
}
|
||||
|
||||
void VSA05::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "icsneo/disk/vsa/vsa06.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA06::VSA06(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA06);
|
||||
savedSectors.insert(savedSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 2), reinterpret_cast<uint32_t*>(recordBytes + 18));
|
||||
error = *reinterpret_cast<uint16_t*>(recordBytes + 18);
|
||||
savedSectorsHigh = *reinterpret_cast<uint16_t*>(recordBytes + 20);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA06::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "icsneo/disk/vsa/vsa07.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA07::VSA07(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA07);
|
||||
lastSector = *reinterpret_cast<uint32_t*>(recordBytes + 2);
|
||||
currentSector = *reinterpret_cast<uint32_t*>(recordBytes + 6);
|
||||
reserved.insert(reserved.end(), recordBytes + 10, recordBytes + 22);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA07::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "icsneo/disk/vsa/vsa08.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA08::VSA08(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA08);
|
||||
troubleSramCount.insert(troubleSramCount.end(), recordBytes + 2, recordBytes + 6);
|
||||
troubleSectors.insert(troubleSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 6), reinterpret_cast<uint32_t*>(recordBytes + 20));
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA08::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "icsneo/disk/vsa/vsa09.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA09::VSA09(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA09);
|
||||
serialNumber = *reinterpret_cast<uint32_t*>(recordBytes + 2);
|
||||
firmwareMajorVersion = recordBytes[6];
|
||||
firmwareMinorVersion = recordBytes[7];
|
||||
manufactureMajorRevision = recordBytes[8];
|
||||
manufactureMinorRevision = recordBytes[9];
|
||||
bootloaderMajorVersion = recordBytes[10];
|
||||
bootloaderMinorVersion = recordBytes[11];
|
||||
reserved0.insert(reserved0.end(), recordBytes + 12, recordBytes + 18);
|
||||
hardwareID = static_cast<HardwareID>(recordBytes[18]);
|
||||
reserved1.insert(reserved1.end(), recordBytes + 19, recordBytes + 22);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA09::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "icsneo/disk/vsa/vsa0b.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto PayloadOffset = 4;
|
||||
|
||||
VSA0B::VSA0B(uint8_t* const recordBytes)
|
||||
: VSAMessage(recordBytes + PayloadOffset, CoreMiniPayloadSize, static_cast<Network::CoreMini>(recordBytes[29]))
|
||||
{
|
||||
setType(VSA::Type::AA0B);
|
||||
captureBitfield = reinterpret_cast<uint16_t*>(recordBytes)[1];
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
reserved = recordBytes[28];
|
||||
checksum = reinterpret_cast<uint16_t*>(recordBytes)[15];
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA0B::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
bool VSA0B::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if((filter->captureBitfield != captureBitfield && filter->captureBitfield != UINT16_MAX) ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "icsneo/disk/vsa/vsa0c.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA0C::VSA0C(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA0C);
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 2);
|
||||
audioPreamble = recordBytes[4];
|
||||
audioHeader = recordBytes[5];
|
||||
pcmData.insert(pcmData.end(), recordBytes + 6, recordBytes + 20);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
vNetBitfield = *reinterpret_cast<VSA0C::VNet*>(recordBytes + 28);
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA0C::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#include "icsneo/disk/vsa/vsa0d.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto FirstPayloadOffset = 8;
|
||||
static constexpr auto FirstPayloadSize = 12;
|
||||
static constexpr auto ConsecutivePayloadOffset = 4;
|
||||
static constexpr auto LastPayloadSize = 24;
|
||||
static constexpr auto OtherPayloadSize = 28;
|
||||
|
||||
// Parent class functions
|
||||
|
||||
VSA0D::VSA0D(uint8_t* const recordBytes, uint8_t* const messageBytes, size_t numBytes, uint32_t& runningChecksum, Network::CoreMini networkId)
|
||||
: VSAExtendedMessage(messageBytes, numBytes, networkId)
|
||||
{
|
||||
static constexpr auto DWordSize = 4;
|
||||
setType(VSA::Type::AA0D);
|
||||
setIndex(*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0x01FFu);
|
||||
setSequenceNum((*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0xFE00u) >> 9);
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data());
|
||||
for(size_t i = 0; i < payload.size() / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
}
|
||||
|
||||
// First Record Functions
|
||||
|
||||
VSA0DFirst::VSA0DFirst(uint8_t* const recordBytes, uint32_t& runningChecksum)
|
||||
: VSA0D(recordBytes, recordBytes + FirstPayloadOffset, FirstPayloadSize, runningChecksum, static_cast<Network::CoreMini>(recordBytes[29]))
|
||||
{
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
setRecordCount(*reinterpret_cast<uint16_t*>(recordBytes + 6));
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
vNetInfo = *reinterpret_cast<VNet*>(recordBytes + 28);
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
uint32_t* const timestampDWords = reinterpret_cast<uint32_t*>(timestamp);
|
||||
runningChecksum += timestampDWords[0];
|
||||
runningChecksum += timestampDWords[1];
|
||||
}
|
||||
|
||||
void VSA0DFirst::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
void VSA0DFirst::reservePacketData(std::shared_ptr<Packet>& packet) const
|
||||
{
|
||||
uint32_t numMessageBytes = (getRecordCount() - 2) * OtherPayloadSize + FirstPayloadSize + LastPayloadSize;
|
||||
packet->data.reserve(numMessageBytes);
|
||||
}
|
||||
|
||||
void VSA0DFirst::reorderPayload(std::vector<uint8_t>& secondPayload)
|
||||
{
|
||||
std::vector<uint8_t> tempPayload;
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin(), secondPayload.begin() + 4);
|
||||
uint8_t* timestampBytes = reinterpret_cast<uint8_t*>(×tamp);
|
||||
tempPayload.insert(tempPayload.end(), timestampBytes, timestampBytes + 8);
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin() + 4, secondPayload.end());
|
||||
payload.clear();
|
||||
secondPayload.clear();
|
||||
payload.insert(payload.end(), tempPayload.begin(), tempPayload.begin() + 12); // This is done because the capacity of payload is already 12
|
||||
secondPayload.insert(secondPayload.end(), tempPayload.begin() + 12, tempPayload.end());
|
||||
}
|
||||
|
||||
bool VSA0DFirst::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if((filter->captureBitfield != captureBitfield && filter->captureBitfield != UINT16_MAX) ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Consecutive Record Functions
|
||||
|
||||
VSA0DConsecutive::VSA0DConsecutive(uint8_t* const recordBytes, uint32_t& runningChecksum, std::shared_ptr<VSA0DFirst> first, bool isLastRecord)
|
||||
: VSA0D(recordBytes, recordBytes + ConsecutivePayloadOffset, isLastRecord ? LastPayloadSize : OtherPayloadSize, runningChecksum)
|
||||
{
|
||||
this->first = first;
|
||||
calculatedChecksum = runningChecksum;
|
||||
if(getIndex() == 1) {
|
||||
first->reorderPayload(payload);
|
||||
} else if(isLastRecord) {
|
||||
recordChecksum = *reinterpret_cast<uint32_t*>(recordBytes + 28);
|
||||
doChecksum(recordBytes);
|
||||
} else {
|
||||
setChecksumFailed(first->getChecksumFailed());
|
||||
}
|
||||
setRecordCount(first->getRecordCount());
|
||||
}
|
||||
|
||||
void VSA0DConsecutive::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
setChecksumFailed(recordBytes && calculatedChecksum != recordChecksum);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
#include "icsneo/disk/vsa/vsa0e.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto FirstPayloadOffset = 10;
|
||||
static constexpr auto FirstPayloadSize = 10;
|
||||
static constexpr auto ConsecutivePayloadOffset = 4;
|
||||
static constexpr auto LastPayloadSize = 24;
|
||||
static constexpr auto OtherPayloadSize = 28;
|
||||
|
||||
// Parent class functions
|
||||
|
||||
VSA0E::VSA0E(uint8_t* const recordBytes, uint8_t* const messageBytes, size_t numBytes, uint32_t& runningChecksum, Network::CoreMini networkId)
|
||||
: VSAExtendedMessage(messageBytes, numBytes, networkId)
|
||||
{
|
||||
static constexpr auto DWordSize = 4;
|
||||
setType(VSA::Type::AA0E);
|
||||
setIndex(static_cast<uint16_t>(recordBytes[2]));
|
||||
setSequenceNum(static_cast<uint16_t>(recordBytes[3]));
|
||||
if(getIndex() == 0) {
|
||||
runningChecksum = (static_cast<uint32_t>(payload[0]) << 16) | (static_cast<uint32_t>(payload[1]) << 24);
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data() + 2);
|
||||
for(size_t i = 0; i < (payload.size() - 2) / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
} else {
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data());
|
||||
for(size_t i = 0; i < payload.size() / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First Record Functions
|
||||
|
||||
VSA0EFirst::VSA0EFirst(uint8_t* const recordBytes, uint32_t& runningChecksum)
|
||||
: VSA0E(recordBytes, recordBytes + FirstPayloadOffset, FirstPayloadSize, runningChecksum,
|
||||
static_cast<Network::CoreMini>(*reinterpret_cast<uint16_t*>(recordBytes + 28)))
|
||||
{
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
setRecordCount(*reinterpret_cast<uint32_t*>(recordBytes + 6));
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA0EFirst::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
void VSA0EFirst::reservePacketData(std::shared_ptr<Packet>& packet) const
|
||||
{
|
||||
uint32_t numMessageBytes = (getRecordCount() - 2) * OtherPayloadSize + FirstPayloadSize + LastPayloadSize;
|
||||
packet->data.reserve(numMessageBytes);
|
||||
}
|
||||
|
||||
bool VSA0EFirst::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if((filter->captureBitfield != captureBitfield && filter->captureBitfield != UINT16_MAX) ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VSA0EFirst::reorderPayload(std::vector<uint8_t>& secondPayload)
|
||||
{
|
||||
std::vector<uint8_t> tempPayload;
|
||||
tempPayload.insert(tempPayload.end(), { 0, 0 }); // Leaving this in here temporarily to figure out checksum stuff
|
||||
tempPayload.insert(tempPayload.end(), payload.begin(), payload.end());
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin(), secondPayload.begin() + 6);
|
||||
uint8_t* timestampBytes = reinterpret_cast<uint8_t*>(×tamp);
|
||||
tempPayload.insert(tempPayload.end(), timestampBytes, timestampBytes + 8);
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin() + 6, secondPayload.end());
|
||||
payload.clear();
|
||||
secondPayload.clear();
|
||||
payload.insert(payload.end(), tempPayload.begin(), tempPayload.begin() + 10); // This is done because the capacity of payload is already 10
|
||||
secondPayload.insert(secondPayload.end(), tempPayload.begin() + 12, tempPayload.end());
|
||||
}
|
||||
|
||||
// Consecutive Record Functions
|
||||
|
||||
VSA0EConsecutive::VSA0EConsecutive(uint8_t* const recordBytes, uint32_t& runningChecksum, std::shared_ptr<VSA0EFirst> first, bool isLastRecord)
|
||||
: VSA0E(recordBytes, recordBytes + ConsecutivePayloadOffset, isLastRecord ? LastPayloadSize : OtherPayloadSize, runningChecksum)
|
||||
{
|
||||
this->first = first;
|
||||
calculatedChecksum = runningChecksum;
|
||||
if(getIndex() == 1) {
|
||||
first->reorderPayload(payload);
|
||||
} else if(isLastRecord) {
|
||||
recordChecksum = *reinterpret_cast<uint32_t*>(recordBytes + 28);
|
||||
doChecksum(recordBytes);
|
||||
} else {
|
||||
setChecksumFailed(first->getChecksumFailed());
|
||||
}
|
||||
setRecordCount(first->getRecordCount());
|
||||
}
|
||||
|
||||
void VSA0EConsecutive::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
setChecksumFailed(recordBytes && calculatedChecksum != recordChecksum);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "icsneo/disk/vsa/vsa0f.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto FirstPayloadOffset = 18;
|
||||
static constexpr auto FirstPayloadSize = 14;
|
||||
static constexpr auto LastPayloadSize = 24;
|
||||
static constexpr auto OtherPayloadSize = 28;
|
||||
|
||||
// Parent class functions
|
||||
|
||||
VSA0F::VSA0F(uint8_t* const recordBytes, uint8_t* const messageBytes, size_t numBytes, uint32_t& runningChecksum, Network::CoreMini networkId)
|
||||
: VSAExtendedMessage(messageBytes, numBytes, networkId)
|
||||
{
|
||||
static constexpr auto DWordSize = 4;
|
||||
setType(VSA::Type::AA0F);
|
||||
setIndex(*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0x01FFu);
|
||||
setSequenceNum((*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0xFE00u) >> 9);
|
||||
if(getIndex() == 0) {
|
||||
runningChecksum = (static_cast<uint32_t>(payload[0]) << 16) | (static_cast<uint32_t>(payload[1]) << 24);
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data() + 2);
|
||||
for (size_t i = 0; i < (payload.size() - 2) / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
} else {
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(recordBytes);
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First Record Functions
|
||||
|
||||
VSA0FFirst::VSA0FFirst(uint8_t* const recordBytes, uint32_t& runningChecksum)
|
||||
: VSA0F(recordBytes, recordBytes + FirstPayloadOffset, FirstPayloadSize, runningChecksum)
|
||||
{
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
uint16_t byteCount = *reinterpret_cast<uint16_t*>(recordBytes + 6);
|
||||
uint16_t recordCount;
|
||||
if(byteCount <= FirstPayloadSize) {
|
||||
recordCount = 1;
|
||||
} else if(byteCount <= FirstPayloadSize + LastPayloadSize) {
|
||||
recordCount = 2;
|
||||
} else {
|
||||
byteCount -= FirstPayloadSize + LastPayloadSize;
|
||||
recordCount = 2 + byteCount / OtherPayloadSize;
|
||||
if (byteCount % OtherPayloadSize != 0) {
|
||||
recordCount += 1;
|
||||
}
|
||||
}
|
||||
setRecordCount(recordCount);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 8) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 16);
|
||||
doChecksum(recordBytes);
|
||||
// Network ID is not found in first record for AA0F
|
||||
// Only the subsequent records have the Network ID in the payload
|
||||
}
|
||||
|
||||
void VSA0FFirst::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for (size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
void VSA0FFirst::reservePacketData(std::shared_ptr<Packet>& packet) const
|
||||
{
|
||||
uint32_t numMessageBytes = (getRecordCount() - 2) * OtherPayloadSize + FirstPayloadSize + LastPayloadSize;
|
||||
packet->data.reserve(numMessageBytes);
|
||||
}
|
||||
|
||||
bool VSA0FFirst::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if(filter->captureBitfield != captureBitfield ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Consecutive Record Functions
|
||||
|
||||
VSA0FConsecutive::VSA0FConsecutive(uint8_t* const recordBytes, uint32_t& runningChecksum, std::shared_ptr<VSA0FFirst> first, bool isLastRecord)
|
||||
: VSA0F(recordBytes, recordBytes + 4, isLastRecord ? LastPayloadSize : OtherPayloadSize, runningChecksum)
|
||||
{
|
||||
this->first = first;
|
||||
calculatedChecksum = runningChecksum;
|
||||
if(isLastRecord) {
|
||||
doChecksum(recordBytes);
|
||||
} else {
|
||||
network = Network(static_cast<Network::CoreMini>(*reinterpret_cast<uint16_t*>(recordBytes + 28))); // Network ID is stored in 25th and 26th recordBytes of payload
|
||||
}
|
||||
setRecordCount(first->getRecordCount());
|
||||
}
|
||||
|
||||
void VSA0FConsecutive::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
setChecksumFailed(recordBytes && calculatedChecksum != 0);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "icsneo/disk/vsa/vsa6a.h"
|
||||
#include "icsneo/disk/diskdriver.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto PayloadOffset = 56;
|
||||
static constexpr auto PayloadSize = 452;
|
||||
static constexpr auto TimestampOffset = 48;
|
||||
static constexpr auto TimestampSize = 8;
|
||||
|
||||
VSA6A::VSA6A(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA6A);
|
||||
|
||||
sequenceNum = *reinterpret_cast<uint32_t*>(recordBytes + 34);
|
||||
totalSectors = *reinterpret_cast<uint32_t*>(recordBytes + 38);
|
||||
reserved = *reinterpret_cast<uint32_t*>(recordBytes + 42);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 46) & UINT63_MAX;
|
||||
timestampSum = *reinterpret_cast<uint16_t*>(recordBytes + 54);
|
||||
data.insert(data.end(), recordBytes + 56, recordBytes + 508);
|
||||
checksum = *reinterpret_cast<uint32_t*>(recordBytes + 508);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA6A::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
for(size_t i = PayloadOffset; i < PayloadOffset+ PayloadSize; i++) {
|
||||
sum += recordBytes[i];
|
||||
}
|
||||
uint16_t tSum = 0;
|
||||
for(size_t i = TimestampOffset; i < TimestampOffset + TimestampSize; i++) {
|
||||
tSum += recordBytes[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum || tSum != timestampSum);
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
#include "icsneo/disk/vsa/vsaparser.h"
|
||||
#include "icsneo/disk/vsa/vsa02.h"
|
||||
#include "icsneo/disk/vsa/vsa03.h"
|
||||
#include "icsneo/disk/vsa/vsa04.h"
|
||||
#include "icsneo/disk/vsa/vsa05.h"
|
||||
#include "icsneo/disk/vsa/vsa06.h"
|
||||
#include "icsneo/disk/vsa/vsa07.h"
|
||||
#include "icsneo/disk/vsa/vsa08.h"
|
||||
#include "icsneo/disk/vsa/vsa09.h"
|
||||
#include "icsneo/disk/vsa/vsa0b.h"
|
||||
#include "icsneo/disk/vsa/vsa0c.h"
|
||||
#include "icsneo/disk/vsa/vsa0d.h"
|
||||
#include "icsneo/disk/vsa/vsa0e.h"
|
||||
#include "icsneo/disk/vsa/vsa0f.h"
|
||||
#include "icsneo/disk/vsa/vsa6a.h"
|
||||
#include "icsneo/disk/diskdriver.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
bool VSAParser::parseBytes(uint8_t* const bytes, uint64_t arrLen)
|
||||
{
|
||||
uint64_t bytesOffset = 0;
|
||||
while(bytesOffset + VSA::StandardRecordSize <= arrLen) { // Enough bytes to read for Standard Record
|
||||
if(bytes[bytesOffset] != 0xAAu) {
|
||||
// Invalid Input
|
||||
return false;
|
||||
}
|
||||
switch(bytes[bytesOffset + 1]) {
|
||||
case 0x00u: // Pad Record
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x01u: // Message Data (Deprecated)
|
||||
hasDeprecatedRecords = true;
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x02u: // Logdata Record
|
||||
if(settings.extractAA02) {
|
||||
vsaRecords.push_back(std::make_shared<VSA02>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x03u: // Event Record
|
||||
if(settings.extractAA03) {
|
||||
vsaRecords.push_back(std::make_shared<VSA03>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x04u: // Partition Info Record
|
||||
if(settings.extractAA04) {
|
||||
vsaRecords.push_back(std::make_shared<VSA04>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x05u: // Application Error Record
|
||||
if(settings.extractAA05) {
|
||||
vsaRecords.push_back(std::make_shared<VSA05>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x06u: // Debug/Internal
|
||||
if(settings.extractAA06) {
|
||||
vsaRecords.push_back(std::make_shared<VSA06>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x07u: // Debug/Internal
|
||||
if(settings.extractAA07) {
|
||||
vsaRecords.push_back(std::make_shared<VSA07>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x08u: // Buffer Info Record
|
||||
if(settings.extractAA08) {
|
||||
vsaRecords.push_back(std::make_shared<VSA08>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x09u: // Device Info Record
|
||||
if(settings.extractAA09) {
|
||||
vsaRecords.push_back(std::make_shared<VSA09>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Au: // Logger Info Configuration (Deprecated)
|
||||
hasDeprecatedRecords = true;
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Bu: // Message Data
|
||||
if(settings.extractAA0B) {
|
||||
auto record = std::make_shared<VSA0B>(bytes + bytesOffset);
|
||||
vsaRecords.push_back(record);
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Cu: // PCM Audio Data
|
||||
if(settings.extractAA0C) {
|
||||
vsaRecords.push_back(std::make_shared<VSA0C>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Du: // Message Data (Extended)
|
||||
if(settings.extractAA0D) {
|
||||
if(!handleExtendedRecord(bytes, bytesOffset, VSA::Type::AA0D)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Eu: // Message Data (Extended)
|
||||
if(settings.extractAA0E) {
|
||||
if(!handleExtendedRecord(bytes, bytesOffset, VSA::Type::AA0E)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Fu: // Message Data (Extended)
|
||||
if(settings.extractAA0F) {
|
||||
if(!handleExtendedRecord(bytes, bytesOffset, VSA::Type::AA0F)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x6Au: // Logger Configuration Backup
|
||||
if(bytesOffset + Disk::SectorSize <= arrLen) {
|
||||
if(settings.extractAA6A) {
|
||||
vsaRecords.push_back(std::make_shared<VSA6A>(bytes + bytesOffset));
|
||||
}
|
||||
}
|
||||
bytesOffset += Disk::SectorSize;
|
||||
break;
|
||||
default:
|
||||
// Unhandled VSA Record Type
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VSAParser::handleExtendedRecord(uint8_t* const bytes, uint64_t& bytesOffset, VSA::Type type)
|
||||
{
|
||||
// Gather info about the extended record sequence of the record contained in bytes
|
||||
std::shared_ptr<VSAExtendedMessage> first;
|
||||
uint16_t seqNum;
|
||||
ExtendedMessageState::ExtendedRecordSeqInfo* seqInfo;
|
||||
uint32_t runningChecksum = 0;
|
||||
switch(type) {
|
||||
case VSA::Type::AA0D:
|
||||
first = std::make_shared<VSA0DFirst>(bytes + bytesOffset, runningChecksum);
|
||||
seqNum = first->getSequenceNum();
|
||||
seqInfo = &state.vsa0DSeqInfo[seqNum];
|
||||
break;
|
||||
case VSA::Type::AA0E:
|
||||
first = std::make_shared<VSA0EFirst>(bytes + bytesOffset, runningChecksum);
|
||||
seqNum = first->getSequenceNum();
|
||||
seqInfo = &state.vsa0ESeqInfo[seqNum];
|
||||
break;
|
||||
case VSA::Type::AA0F:
|
||||
first = std::make_shared<VSA0FFirst>(bytes + bytesOffset, runningChecksum);
|
||||
seqNum = first->getSequenceNum();
|
||||
seqInfo = &state.vsa0FSeqInfo[seqNum];
|
||||
break;
|
||||
default:
|
||||
return false; // Invalid type was passed
|
||||
}
|
||||
|
||||
if(seqInfo->nextIndex == 0 && seqInfo->records.size() == 0) { // This is the first record in the sequence
|
||||
if(first->getIndex() != 0) {
|
||||
seqInfo->clear();
|
||||
report(APIEvent::Type::VSAExtendedMessageError, APIEvent::Severity::EventWarning);
|
||||
return true; // This is not actually the first record
|
||||
}
|
||||
seqInfo->records.push_back(first);
|
||||
seqInfo->totalRecordCount = first->getRecordCount();
|
||||
seqInfo->nextIndex++;
|
||||
seqInfo->runningChecksum = runningChecksum;
|
||||
} else if(seqInfo->nextIndex < seqInfo->totalRecordCount && seqInfo->records.size() > 0) { // Consecutive Record
|
||||
std::shared_ptr<VSAExtendedMessage> consecutive;
|
||||
bool isLast = seqInfo->nextIndex == seqInfo->totalRecordCount - 1;
|
||||
|
||||
// Construct the consecutive record from bytes
|
||||
switch(type) {
|
||||
case VSA::Type::AA0D:
|
||||
consecutive = std::make_shared<VSA0DConsecutive>(
|
||||
bytes + bytesOffset,
|
||||
seqInfo->runningChecksum,
|
||||
std::dynamic_pointer_cast<VSA0DFirst>(seqInfo->records[0]),
|
||||
isLast
|
||||
);
|
||||
break;
|
||||
case VSA::Type::AA0E:
|
||||
consecutive = std::make_shared<VSA0EConsecutive>(
|
||||
bytes + bytesOffset,
|
||||
seqInfo->runningChecksum,
|
||||
std::dynamic_pointer_cast<VSA0EFirst>(seqInfo->records[0]),
|
||||
isLast
|
||||
);
|
||||
break;
|
||||
case VSA::Type::AA0F:
|
||||
consecutive = std::make_shared<VSA0FConsecutive>(
|
||||
bytes + bytesOffset,
|
||||
seqInfo->runningChecksum,
|
||||
std::dynamic_pointer_cast<VSA0FFirst>(seqInfo->records[0]),
|
||||
isLast
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if(consecutive->getIndex() == seqInfo->nextIndex && consecutive->getSequenceNum() == seqNum) { // This record is valid in the sequence
|
||||
seqInfo->records.push_back(consecutive);
|
||||
seqInfo->nextIndex++;
|
||||
} else { // Sequence is out of order/invalid
|
||||
// Throw away incomplete sequence and report warning
|
||||
seqInfo->clear();
|
||||
report(APIEvent::Type::VSAExtendedMessageError, APIEvent::Severity::EventWarning);
|
||||
// Save data for new sequence
|
||||
if(first->getIndex() == 0) {
|
||||
seqInfo->records.push_back(first);
|
||||
seqInfo->totalRecordCount = first->getRecordCount();
|
||||
seqInfo->nextIndex++;
|
||||
seqInfo->runningChecksum = runningChecksum;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(seqInfo->nextIndex == seqInfo->totalRecordCount) { // This is the last record in the sequence
|
||||
if(consecutive->getChecksumFailed()) {
|
||||
// Fail out if checksum fails
|
||||
seqInfo->clear();
|
||||
return false;
|
||||
}
|
||||
vsaRecords.insert(vsaRecords.end(), seqInfo->records.begin(), seqInfo->records.end());
|
||||
seqInfo->clear();
|
||||
}
|
||||
} else {
|
||||
return false; // Undefined behavior
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VSAParser::RecordParseStatus VSAParser::getRecordFromBytes(uint8_t* const bytes, size_t arrLen, std::shared_ptr<VSA>& record)
|
||||
{
|
||||
record = nullptr;
|
||||
if(arrLen < VSA::StandardRecordSize) {
|
||||
// Not enough bytes
|
||||
return VSAParser::RecordParseStatus::InsufficientData;
|
||||
} else if(bytes[0] != 0xAAu) {
|
||||
return VSAParser::RecordParseStatus::NotARecordStart;
|
||||
} else {
|
||||
switch(bytes[1]) {
|
||||
case 0x00u: // Pad Record
|
||||
return VSAParser::RecordParseStatus::Pad;
|
||||
case 0x01u: // Message Data (Deprecated)
|
||||
return VSAParser::RecordParseStatus::Deprecated;
|
||||
case 0x02u: // Logdata Record
|
||||
if(settings.extractAA02) {
|
||||
record = std::make_shared<VSA02>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x03u: // Event Record
|
||||
if(settings.extractAA03) {
|
||||
record = std::make_shared<VSA03>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x04u: // Partition Info Record
|
||||
if(settings.extractAA04) {
|
||||
record = std::make_shared<VSA04>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x05u: // Application Error Record
|
||||
if(settings.extractAA05) {
|
||||
record = std::make_shared<VSA05>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x06u: // Debug/Internal
|
||||
if(settings.extractAA06) {
|
||||
record = std::make_shared<VSA06>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x07u: // Debug/Internal
|
||||
if(settings.extractAA07) {
|
||||
record = std::make_shared<VSA07>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x08u: // Buffer Info Record
|
||||
if(settings.extractAA08) {
|
||||
record = std::make_shared<VSA08>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x09u: // Device Info Record
|
||||
if(settings.extractAA09) {
|
||||
record = std::make_shared<VSA09>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x0Au:
|
||||
return VSAParser::RecordParseStatus::Deprecated;
|
||||
case 0x0Bu: // Message Data
|
||||
if(settings.extractAA0B) {
|
||||
record = std::make_shared<VSA0B>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x0Cu: // PCM Audio Data
|
||||
if(settings.extractAA0C) {
|
||||
record = std::make_shared<VSA0C>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x0Du: // Message Data (Extended)
|
||||
if(settings.extractAA0D) {
|
||||
uint32_t payloadChecksum = 0;
|
||||
const auto& vsa = std::make_shared<VSA0DFirst>(bytes, payloadChecksum);
|
||||
record = vsa;
|
||||
if(vsa->getIndex() == 0) {
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
// This returns the consecutive record as a first record
|
||||
return VSAParser::RecordParseStatus::ConsecutiveExtended;
|
||||
}
|
||||
break;
|
||||
case 0x0Eu: // Message Data (Extended)
|
||||
if(settings.extractAA0E) {
|
||||
uint32_t payloadChecksum = 0;
|
||||
const auto& vsa = std::make_shared<VSA0EFirst>(bytes, payloadChecksum);
|
||||
record = vsa;
|
||||
if(vsa->getIndex() == 0) {
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
// This returns the consecutive record as a first record
|
||||
return VSAParser::RecordParseStatus::ConsecutiveExtended;
|
||||
}
|
||||
break;
|
||||
case 0x0Fu: // Message Data (Extended)
|
||||
if(settings.extractAA0F) {
|
||||
uint32_t payloadChecksum = 0;
|
||||
const auto& vsa = std::make_shared<VSA0FFirst>(bytes, payloadChecksum);
|
||||
record = vsa;
|
||||
if(vsa->getIndex() == 0) {
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
// This returns the consecutive record as a first record
|
||||
return VSAParser::RecordParseStatus::ConsecutiveExtended;
|
||||
}
|
||||
break;
|
||||
case 0x6Au: // Logger Configuration Backup
|
||||
if(settings.extractAA6A) {
|
||||
if(arrLen < Disk::SectorSize) {
|
||||
return VSAParser::RecordParseStatus::InsufficientData;
|
||||
}
|
||||
record = std::make_shared<VSA6A>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Unhandled VSA Record Type
|
||||
return VSAParser::RecordParseStatus::UnknownRecordType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return VSAParser::RecordParseStatus::FilteredOut;
|
||||
}
|
||||
|
||||
void VSAParser::clearParseState()
|
||||
{
|
||||
for(size_t i = 0; i < state.vsa0DSeqInfo.size(); i++) {
|
||||
state.vsa0DSeqInfo[i].clear();
|
||||
}
|
||||
for(size_t i = 0; i < state.vsa0ESeqInfo.size(); i++) {
|
||||
state.vsa0ESeqInfo[i].clear();
|
||||
}
|
||||
for(size_t i = 0; i < state.vsa0DSeqInfo.size(); i++) {
|
||||
state.vsa0ESeqInfo[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool VSAParser::extractMessagePackets(std::vector<std::shared_ptr<Packet>>& packets)
|
||||
{
|
||||
if(settings != Settings::messageRecords()) {
|
||||
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||
return false; // We do not have exclusively message records
|
||||
}
|
||||
std::shared_ptr<Packet> packet;
|
||||
bool activeExtendedMessage = false;
|
||||
VSA::Type previousRecordType = VSA::Type::Invalid;
|
||||
for(const auto& record : vsaRecords) {
|
||||
VSA::Type activeRecordType = record->getType();
|
||||
switch(activeRecordType) {
|
||||
// Handle standard message records
|
||||
case VSA::Type::AA0B: {
|
||||
if(activeExtendedMessage) {
|
||||
// Non-terminated extended message record
|
||||
// There was a failure/unexpected behavior in the parsing process
|
||||
report(APIEvent::Type::VSAExtendedMessageError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<VSAMessage> messageRecord = std::dynamic_pointer_cast<VSAMessage>(record);
|
||||
if(!settings.messageFilter || messageRecord->filter(settings.messageFilter)) {
|
||||
packet = messageRecord->getPacket();
|
||||
packets.push_back(packet);
|
||||
}
|
||||
packet = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle extended message records
|
||||
case VSA::Type::AA0D:
|
||||
case VSA::Type::AA0E:
|
||||
case VSA::Type::AA0F: {
|
||||
std::shared_ptr<VSAExtendedMessage> extendedMessageRecord = std::dynamic_pointer_cast<VSAExtendedMessage>(record);
|
||||
|
||||
if(!activeExtendedMessage) { // Start new extended message packet
|
||||
packet = extendedMessageRecord->getPacket();
|
||||
activeExtendedMessage = true;
|
||||
previousRecordType = extendedMessageRecord->getType();
|
||||
} else if(previousRecordType == activeRecordType) { // Continue existing extended message packet
|
||||
extendedMessageRecord->appendPacket(packet);
|
||||
if(extendedMessageRecord->getRecordCount() == static_cast<uint32_t>(extendedMessageRecord->getIndex() + 1)) { // Last record in sequence
|
||||
if(!settings.messageFilter || extendedMessageRecord->filter(settings.messageFilter)) {
|
||||
VSAExtendedMessage::truncatePacket(packet);
|
||||
packets.push_back(packet);
|
||||
}
|
||||
activeExtendedMessage = false;
|
||||
packet = nullptr;
|
||||
previousRecordType = activeRecordType;
|
||||
}
|
||||
} else {
|
||||
// Non-terminated extended message record
|
||||
// There was a failure/unexpected behavior in the parsing process
|
||||
activeExtendedMessage = false;
|
||||
packet = nullptr;
|
||||
previousRecordType = VSA::Type::Invalid;
|
||||
report(APIEvent::Type::VSAOtherError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Non-message record discovered
|
||||
report(APIEvent::Type::VSAOtherError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
vsaRecords.clear();
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user