mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 09:28:40 +02:00
Device: Add GetComponentVersions and GetSupportedFeatures commands
Driver: Fix re-open and failed open cases for TCP Also enforces even length packets for the RED2, FIRE3, and FIRE3 FlexRay devices.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
#include "icsneo/communication/packet/componentversionpacket.h"
|
||||
#include "icsneo/communication/message/componentversionsmessage.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
#pragma pack(push, 2)
|
||||
struct PackedComponentVersion {
|
||||
uint8_t valid;
|
||||
uint8_t expansionSlot;
|
||||
uint8_t componentInfo; // Component specific data (e.g. Linux: boot device)
|
||||
uint8_t reserved;
|
||||
uint32_t identifier;
|
||||
uint32_t dotVersion; // Represents a.b.c.d, a.b.c, or a.b, depending on leading zeros.
|
||||
uint32_t commitHash;
|
||||
};
|
||||
|
||||
static constexpr size_t MaxReportedVersions = 16;
|
||||
struct ComponentVersionsResponse {
|
||||
ExtendedResponseMessage::ResponseHeader header;
|
||||
uint16_t numVersions;
|
||||
PackedComponentVersion versions[MaxReportedVersions];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::shared_ptr<ComponentVersionsMessage> ComponentVersionPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
|
||||
auto msg = std::make_shared<ComponentVersionsMessage>();
|
||||
// Length checks: At least a header and numVersions field.
|
||||
if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 2) {
|
||||
return msg; // Empty
|
||||
}
|
||||
// Get a reference to the payload to fully validate the length
|
||||
const auto& response = *reinterpret_cast<const ComponentVersionsResponse*>(bytes.data());
|
||||
// Expected size is the header, numVersions field, and numVersions ComponentVersion objects.
|
||||
auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 2 + (response.numVersions * sizeof(ComponentVersion));
|
||||
// If the response is malformed (too small), return an empty message.
|
||||
if(bytes.size() < expectedSize) {
|
||||
return msg; // Empty
|
||||
}
|
||||
// Unpack into the portable class
|
||||
for(unsigned int i = 0; i < response.numVersions; ++i) {
|
||||
const auto& packedVersion = response.versions[i];
|
||||
msg->versions.emplace_back(packedVersion.valid, packedVersion.componentInfo, packedVersion.identifier, packedVersion.dotVersion, packedVersion.commitHash);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "icsneo/communication/packet/supportedfeaturespacket.h"
|
||||
#include "icsneo/communication/message/supportedfeaturesmessage.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr uint16_t SupportedFeaturesCommandVersion = 1;
|
||||
static constexpr size_t NumSupportedFeaturesFields =
|
||||
(static_cast<size_t>(SupportedFeature::numSupportedFeatures) + 31) / 32;
|
||||
#pragma pack(push, 2)
|
||||
struct SupportedFeaturesResponse {
|
||||
ExtendedResponseMessage::ResponseHeader header;
|
||||
uint16_t cmdVersion;
|
||||
uint16_t numValidBits;
|
||||
uint32_t featuresFields[NumSupportedFeaturesFields];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::shared_ptr<SupportedFeaturesMessage> SupportedFeaturesPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
|
||||
auto msg = std::make_shared<SupportedFeaturesMessage>();
|
||||
// Length check: At least a header, a 2-byte cmdVersion field, and a 2-byte numValidBits field.
|
||||
if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 4) {
|
||||
return msg; // Empty
|
||||
}
|
||||
// Get a reference to the payload to fully validate the length
|
||||
const auto& response = *reinterpret_cast<const SupportedFeaturesResponse*>(bytes.data());
|
||||
// Expected size is the header, cmdVersion and numValidBits fields, plus the number of 32-bit bitfields in the response based on numValidBits
|
||||
auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 4 + ((response.numValidBits + 31) / 32) * 4;
|
||||
// If the response is malformed (too small), return an empty message
|
||||
if(bytes.size() < expectedSize) {
|
||||
return msg; // Empty
|
||||
}
|
||||
unsigned int loopLimit = std::min<unsigned int>(response.numValidBits, NumSupportedFeaturesFields);
|
||||
for(unsigned int i = 0; i < loopLimit; ++i) {
|
||||
uint32_t wordOffset = i / 32;
|
||||
uint32_t bitOffset = i % 32;
|
||||
if((response.featuresFields[wordOffset] >> bitOffset) & 1) {
|
||||
msg->features.insert(static_cast<SupportedFeature>(i));
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
Reference in New Issue
Block a user