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.pull/56/head
parent
b6d9ef4c7e
commit
32900ae263
|
|
@ -240,6 +240,8 @@ set(SRC_FILES
|
||||||
communication/packet/i2cpacket.cpp
|
communication/packet/i2cpacket.cpp
|
||||||
communication/packet/linpacket.cpp
|
communication/packet/linpacket.cpp
|
||||||
communication/packet/scriptstatuspacket.cpp
|
communication/packet/scriptstatuspacket.cpp
|
||||||
|
communication/packet/componentversionpacket.cpp
|
||||||
|
communication/packet/supportedfeaturespacket.cpp
|
||||||
communication/decoder.cpp
|
communication/decoder.cpp
|
||||||
communication/encoder.cpp
|
communication/encoder.cpp
|
||||||
communication/ethernetpacketizer.cpp
|
communication/ethernetpacketizer.cpp
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI up
|
||||||
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
|
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
|
||||||
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
|
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
|
||||||
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
|
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
|
||||||
|
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
|
||||||
|
|
||||||
// Transport Errors
|
// Transport Errors
|
||||||
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
|
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
|
||||||
|
|
@ -290,6 +291,8 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||||
return COREMINI_UPLOAD_VERSION_MISMATCH;
|
return COREMINI_UPLOAD_VERSION_MISMATCH;
|
||||||
case Type::DiskNotConnected:
|
case Type::DiskNotConnected:
|
||||||
return DISK_NOT_CONNECTED;
|
return DISK_NOT_CONNECTED;
|
||||||
|
case Type::UnexpectedResponse:
|
||||||
|
return UNEXPECTED_RESPONSE;
|
||||||
// Transport Errors
|
// Transport Errors
|
||||||
case Type::FailedToRead:
|
case Type::FailedToRead:
|
||||||
return FAILED_TO_READ;
|
return FAILED_TO_READ;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "icsneo/communication/message/filter/main51messagefilter.h"
|
#include "icsneo/communication/message/filter/main51messagefilter.h"
|
||||||
#include "icsneo/communication/message/readsettingsmessage.h"
|
#include "icsneo/communication/message/readsettingsmessage.h"
|
||||||
#include "icsneo/communication/message/versionmessage.h"
|
#include "icsneo/communication/message/versionmessage.h"
|
||||||
|
#include "icsneo/communication/message/componentversionsmessage.h"
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
|
|
@ -301,3 +302,18 @@ void Communication::handleInput(Packetizer& p, std::vector<uint8_t>& readBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional< std::vector<ComponentVersion> > Communication::getComponentVersionsSync(std::chrono::milliseconds timeout) {
|
||||||
|
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::ComponentVersions);
|
||||||
|
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
||||||
|
return sendCommand(ExtendedCommand::GetComponentVersions, {});
|
||||||
|
}, filter, timeout);
|
||||||
|
if(!msg) // Did not receive a message
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
auto ver = std::dynamic_pointer_cast<ComponentVersionsMessage>(msg);
|
||||||
|
if(!ver) // Could not upcast for some reason
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return std::make_optional< std::vector<ComponentVersion> >(std::move(ver->versions));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#include "icsneo/communication/packet/i2cpacket.h"
|
#include "icsneo/communication/packet/i2cpacket.h"
|
||||||
#include "icsneo/communication/packet/scriptstatuspacket.h"
|
#include "icsneo/communication/packet/scriptstatuspacket.h"
|
||||||
#include "icsneo/communication/packet/linpacket.h"
|
#include "icsneo/communication/packet/linpacket.h"
|
||||||
|
#include "icsneo/communication/packet/componentversionpacket.h"
|
||||||
|
#include "icsneo/communication/packet/supportedfeaturespacket.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
@ -247,13 +249,21 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
break; // Handle as a raw message, might not be a generic response
|
break; // Handle as a raw message, might not be a generic response
|
||||||
|
|
||||||
const auto& resp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data());
|
const auto& resp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data());
|
||||||
if(resp.header.command != ExtendedCommand::GenericReturn)
|
switch(resp.header.command) {
|
||||||
break; // Handle as a raw message
|
case ExtendedCommand::GetComponentVersions:
|
||||||
|
result = ComponentVersionPacket::DecodeToMessage(packet->data);
|
||||||
const auto msg = std::make_shared<ExtendedResponseMessage>(resp.command, resp.returnCode);
|
|
||||||
result = msg;
|
|
||||||
return true;
|
return true;
|
||||||
|
case ExtendedCommand::GetSupportedFeatures:
|
||||||
|
result = SupportedFeaturesPacket::DecodeToMessage(packet->data);
|
||||||
|
return true;
|
||||||
|
case ExtendedCommand::GenericReturn:
|
||||||
|
result = std::make_shared<ExtendedResponseMessage>(resp.command, resp.returnCode);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
// No defined handler, treat this as a RawMessage
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
case Network::NetID::FlexRayControl: {
|
case Network::NetID::FlexRayControl: {
|
||||||
auto frResult = std::make_shared<FlexRayControlMessage>(*packet);
|
auto frResult = std::make_shared<FlexRayControlMessage>(*packet);
|
||||||
if(!frResult->decoded) {
|
if(!frResult->decoded) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -217,6 +217,13 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
|
||||||
if(block) // Extensions say no
|
if(block) // Extensions say no
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Get component versions *after* the extension "onDeviceOpen" hooks (e.g. device reflashes)
|
||||||
|
|
||||||
|
if (auto compVersions = com->getComponentVersionsSync())
|
||||||
|
componentVersions = std::move(*compVersions);
|
||||||
|
else
|
||||||
|
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::EventWarning);
|
||||||
|
|
||||||
if(!settings->disabled) {
|
if(!settings->disabled) {
|
||||||
// Since we will not fail the open if a settings read fails,
|
// Since we will not fail the open if a settings read fails,
|
||||||
// downgrade any errors to warnings. Otherwise the error will
|
// downgrade any errors to warnings. Otherwise the error will
|
||||||
|
|
@ -303,6 +310,10 @@ APIEvent::Type Device::attemptToBeginCommunication() {
|
||||||
return getCommunicationNotEstablishedError();
|
return getCommunicationNotEstablishedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!com->sendCommand(Command::EnableNetworkCommunication, false))
|
||||||
|
return getCommunicationNotEstablishedError();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
auto serial = com->getSerialNumberSync();
|
auto serial = com->getSerialNumberSync();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(!serial) {
|
while(!serial) {
|
||||||
|
|
@ -1752,3 +1763,20 @@ bool Device::setRTC(const std::chrono::time_point<std::chrono::system_clock>& ti
|
||||||
com->sendCommand(Command::SetRTC, bytestream);
|
com->sendCommand(Command::SetRTC, bytestream);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::set<SupportedFeature>> Device::getSupportedFeatures() {
|
||||||
|
auto timeout = std::chrono::milliseconds(100);
|
||||||
|
std::shared_ptr<Message> msg = com->waitForMessageSync(
|
||||||
|
[this](){ return com->sendCommand(ExtendedCommand::GetSupportedFeatures, {}); },
|
||||||
|
std::make_shared<MessageFilter>(Message::Type::SupportedFeatures), timeout);
|
||||||
|
if(!msg) {
|
||||||
|
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const auto& typedResponse = std::dynamic_pointer_cast<SupportedFeaturesMessage>(msg);
|
||||||
|
if(!typedResponse) {
|
||||||
|
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return std::move(typedResponse->features);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ public:
|
||||||
A2BMessageIncompleteFrame = 0x2039,
|
A2BMessageIncompleteFrame = 0x2039,
|
||||||
CoreminiUploadVersionMismatch = 0x2040,
|
CoreminiUploadVersionMismatch = 0x2040,
|
||||||
DiskNotConnected = 0x2041,
|
DiskNotConnected = 0x2041,
|
||||||
|
UnexpectedResponse = 0x2042,
|
||||||
|
|
||||||
// Transport Events
|
// Transport Events
|
||||||
FailedToRead = 0x3000,
|
FailedToRead = 0x3000,
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ enum class ExtendedCommand : uint16_t {
|
||||||
Extract = 0x0015,
|
Extract = 0x0015,
|
||||||
StartDHCPServer = 0x0016,
|
StartDHCPServer = 0x0016,
|
||||||
StopDHCPServer = 0x0017,
|
StopDHCPServer = 0x0017,
|
||||||
|
GetSupportedFeatures = 0x0018,
|
||||||
|
GetComponentVersions = 0x001A,
|
||||||
Reboot = 0x001C,
|
Reboot = 0x001C,
|
||||||
SetUploadedFlag = 0x0027,
|
SetUploadedFlag = 0x0027,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
#include "icsneo/communication/message/callback/messagecallback.h"
|
#include "icsneo/communication/message/callback/messagecallback.h"
|
||||||
#include "icsneo/communication/message/serialnumbermessage.h"
|
#include "icsneo/communication/message/serialnumbermessage.h"
|
||||||
#include "icsneo/communication/message/logicaldiskinfomessage.h"
|
#include "icsneo/communication/message/logicaldiskinfomessage.h"
|
||||||
|
#include "icsneo/communication/message/componentversionsmessage.h"
|
||||||
|
#include "icsneo/communication/message/extendedresponsemessage.h"
|
||||||
#include "icsneo/device/deviceversion.h"
|
#include "icsneo/device/deviceversion.h"
|
||||||
#include "icsneo/api/eventmanager.h"
|
#include "icsneo/api/eventmanager.h"
|
||||||
#include "icsneo/communication/packetizer.h"
|
#include "icsneo/communication/packetizer.h"
|
||||||
|
|
@ -58,6 +60,7 @@ public:
|
||||||
std::shared_ptr<SerialNumberMessage> getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
std::shared_ptr<SerialNumberMessage> getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
std::optional< std::vector< std::optional<DeviceAppVersion> > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
std::optional< std::vector< std::optional<DeviceAppVersion> > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
std::shared_ptr<LogicalDiskInfoMessage> getLogicalDiskInfoSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
std::shared_ptr<LogicalDiskInfoMessage> getLogicalDiskInfoSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
|
std::optional< std::vector<ComponentVersion> > getComponentVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
|
|
||||||
int addMessageCallback(const std::shared_ptr<MessageCallback>& cb);
|
int addMessageCallback(const std::shared_ptr<MessageCallback>& cb);
|
||||||
bool removeMessageCallback(int id);
|
bool removeMessageCallback(int id);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef _EXTENDED_COMPONENT_VERSIONS_RESPONSE_MESSAGE_H_
|
||||||
|
#define _EXTENDED_COMPONENT_VERSIONS_RESPONSE_MESSAGE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include "icsneo/communication/message/extendedresponsemessage.h"
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
class ComponentVersion {
|
||||||
|
public:
|
||||||
|
ComponentVersion(uint8_t valid, uint8_t componentInfo, uint32_t identifier, uint32_t dotVersion, uint32_t commitHash) :
|
||||||
|
valid(valid), componentInfo(componentInfo), identifier(identifier), dotVersion(dotVersion), commitHash(commitHash) {}
|
||||||
|
const bool valid;
|
||||||
|
const uint8_t componentInfo;
|
||||||
|
const uint32_t identifier;
|
||||||
|
const uint32_t dotVersion;
|
||||||
|
const uint32_t commitHash;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ComponentVersionsMessage : public Message {
|
||||||
|
public:
|
||||||
|
ComponentVersionsMessage() : Message(Message::Type::ComponentVersions) {}
|
||||||
|
std::vector<ComponentVersion> versions;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // _EXTENDED_COMPONENT_VERSIONS_RESPONSE_MESSAGE_H_
|
||||||
|
|
@ -34,6 +34,8 @@ public:
|
||||||
ExtendedResponse = 0x8009,
|
ExtendedResponse = 0x8009,
|
||||||
WiVICommandResponse = 0x800a,
|
WiVICommandResponse = 0x800a,
|
||||||
ScriptStatus = 0x800b,
|
ScriptStatus = 0x800b,
|
||||||
|
ComponentVersions = 0x800c,
|
||||||
|
SupportedFeatures = 0x800d,
|
||||||
};
|
};
|
||||||
|
|
||||||
Message(Type t) : type(t) {}
|
Message(Type t) : type(t) {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef _SUPPORTED_FEATURES_RESPONSE_MESSAGE_H_
|
||||||
|
#define _SUPPORTED_FEATURES_RESPONSE_MESSAGE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include "icsneo/communication/message/extendedresponsemessage.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
enum class SupportedFeature : uint16_t {
|
||||||
|
networkDWCAN01 = 0,
|
||||||
|
networkDWCAN02 = 1,
|
||||||
|
networkDWCAN03 = 2,
|
||||||
|
networkDWCAN04 = 3,
|
||||||
|
networkDWCAN05 = 4,
|
||||||
|
networkDWCAN06 = 5,
|
||||||
|
networkDWCAN07 = 6,
|
||||||
|
networkDWCAN08 = 7,
|
||||||
|
networkTerminationDWCAN01 = 8,
|
||||||
|
networkTerminationDWCAN02 = 9,
|
||||||
|
networkTerminationDWCAN03 = 10,
|
||||||
|
networkTerminationDWCAN04 = 11,
|
||||||
|
networkTerminationDWCAN05 = 12,
|
||||||
|
networkTerminationDWCAN06 = 13,
|
||||||
|
networkTerminationDWCAN07 = 14,
|
||||||
|
networkTerminationDWCAN08 = 15,
|
||||||
|
enhancedFlashDriver = 16,
|
||||||
|
rtcCalibration = 17,
|
||||||
|
rtcClosedLoopCalibration = 18,
|
||||||
|
numSupportedFeatures,
|
||||||
|
};
|
||||||
|
|
||||||
|
class SupportedFeaturesMessage : public Message {
|
||||||
|
public:
|
||||||
|
SupportedFeaturesMessage() : Message(Message::Type::SupportedFeatures) {}
|
||||||
|
std::set<SupportedFeature> features;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // _SUPPORTED_FEATURES_RESPONSE_MESSAGE_H_
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef __COMPONENTVERSIONPACKET_H__
|
||||||
|
#define __COMPONENTVERSIONPACKET_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
class ComponentVersionsMessage;
|
||||||
|
|
||||||
|
struct ComponentVersionPacket {
|
||||||
|
static std::shared_ptr<ComponentVersionsMessage> DecodeToMessage(const std::vector<uint8_t>& bytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // __DEVICECOMPONENTVERSIONPACKET_H__
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef __SUPPORTEDFEATURESPACKET_H_
|
||||||
|
#define __SUPPORTEDFEATURESPACKET_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
class SupportedFeaturesMessage;
|
||||||
|
|
||||||
|
struct SupportedFeaturesPacket {
|
||||||
|
static std::shared_ptr<SupportedFeaturesMessage> DecodeToMessage(const std::vector<uint8_t>& bytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // __SUPPORTEDFEATURESPACKET_H_
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <set>
|
||||||
#include "icsneo/api/eventmanager.h"
|
#include "icsneo/api/eventmanager.h"
|
||||||
#include "icsneo/api/lifetime.h"
|
#include "icsneo/api/lifetime.h"
|
||||||
#include "icsneo/device/neodevice.h"
|
#include "icsneo/device/neodevice.h"
|
||||||
|
|
@ -31,6 +32,7 @@
|
||||||
#include "icsneo/communication/message/resetstatusmessage.h"
|
#include "icsneo/communication/message/resetstatusmessage.h"
|
||||||
#include "icsneo/communication/message/wiviresponsemessage.h"
|
#include "icsneo/communication/message/wiviresponsemessage.h"
|
||||||
#include "icsneo/communication/message/scriptstatusmessage.h"
|
#include "icsneo/communication/message/scriptstatusmessage.h"
|
||||||
|
#include "icsneo/communication/message/supportedfeaturesmessage.h"
|
||||||
#include "icsneo/device/extensions/flexray/controller.h"
|
#include "icsneo/device/extensions/flexray/controller.h"
|
||||||
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
||||||
#include "icsneo/communication/message/ethphymessage.h"
|
#include "icsneo/communication/message/ethphymessage.h"
|
||||||
|
|
@ -530,7 +532,7 @@ public:
|
||||||
* For use by extensions only. A more stable API will be provided in the future.
|
* For use by extensions only. A more stable API will be provided in the future.
|
||||||
*/
|
*/
|
||||||
const std::vector<std::optional<DeviceAppVersion>>& getVersions() const { return versions; }
|
const std::vector<std::optional<DeviceAppVersion>>& getVersions() const { return versions; }
|
||||||
|
const std::vector<ComponentVersion>& getComponentVersions() const { return componentVersions; }
|
||||||
/**
|
/**
|
||||||
* Some alternate communication protocols do not support DFU
|
* Some alternate communication protocols do not support DFU
|
||||||
*/
|
*/
|
||||||
|
|
@ -548,6 +550,9 @@ public:
|
||||||
std::optional<std::chrono::time_point<std::chrono::system_clock>> getRTC();
|
std::optional<std::chrono::time_point<std::chrono::system_clock>> getRTC();
|
||||||
bool setRTC(const std::chrono::time_point<std::chrono::system_clock>& time);
|
bool setRTC(const std::chrono::time_point<std::chrono::system_clock>& time);
|
||||||
|
|
||||||
|
// Get a bitfield from the device representing supported networks and features.
|
||||||
|
std::optional<std::set<SupportedFeature>> getSupportedFeatures();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this device supports the Wireless neoVI featureset
|
* Returns true if this device supports the Wireless neoVI featureset
|
||||||
*/
|
*/
|
||||||
|
|
@ -669,6 +674,7 @@ private:
|
||||||
neodevice_t data;
|
neodevice_t data;
|
||||||
std::shared_ptr<ResetStatusMessage> latestResetStatus;
|
std::shared_ptr<ResetStatusMessage> latestResetStatus;
|
||||||
std::vector<std::optional<DeviceAppVersion>> versions;
|
std::vector<std::optional<DeviceAppVersion>> versions;
|
||||||
|
std::vector<ComponentVersion> componentVersions;
|
||||||
|
|
||||||
mutable std::mutex diskLock;
|
mutable std::mutex diskLock;
|
||||||
std::unique_ptr<Disk::ReadDriver> diskReadDriver;
|
std::unique_ptr<Disk::ReadDriver> diskReadDriver;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ protected:
|
||||||
|
|
||||||
void setupPacketizer(Packetizer& packetizer) override {
|
void setupPacketizer(Packetizer& packetizer) override {
|
||||||
Device::setupPacketizer(packetizer);
|
Device::setupPacketizer(packetizer);
|
||||||
packetizer.align16bit = false;
|
packetizer.align16bit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ protected:
|
||||||
|
|
||||||
void setupPacketizer(Packetizer& packetizer) override {
|
void setupPacketizer(Packetizer& packetizer) override {
|
||||||
Device::setupPacketizer(packetizer);
|
Device::setupPacketizer(packetizer);
|
||||||
packetizer.align16bit = false;
|
packetizer.align16bit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ protected:
|
||||||
|
|
||||||
void setupPacketizer(Packetizer& packetizer) override {
|
void setupPacketizer(Packetizer& packetizer) override {
|
||||||
Device::setupPacketizer(packetizer);
|
Device::setupPacketizer(packetizer);
|
||||||
packetizer.align16bit = false;
|
packetizer.align16bit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
#include <optional>
|
#include <memory>
|
||||||
|
|
||||||
#include "icsneo/communication/driver.h"
|
#include "icsneo/communication/driver.h"
|
||||||
#include "icsneo/device/founddevice.h"
|
#include "icsneo/device/founddevice.h"
|
||||||
|
|
@ -45,7 +45,7 @@ private:
|
||||||
NetworkInterface interface;
|
NetworkInterface interface;
|
||||||
uint32_t dstIP;
|
uint32_t dstIP;
|
||||||
uint16_t dstPort;
|
uint16_t dstPort;
|
||||||
std::optional<Socket> socket;
|
std::unique_ptr<Socket> socket;
|
||||||
void readTask() override;
|
void readTask() override;
|
||||||
void writeTask() override;
|
void writeTask() override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ void CDCACM::readTask() {
|
||||||
// We were expecting a disconnect for reenumeration
|
// We were expecting a disconnect for reenumeration
|
||||||
modeChangeThread = std::thread([this] {
|
modeChangeThread = std::thread([this] {
|
||||||
modeChangeCV.notify_all();
|
modeChangeCV.notify_all();
|
||||||
close(); // Which will trigger an open() due to modeChanging
|
// Requesting thread is responsible for calling close. This allows for more flexibility
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
} else if(!closing && !fdIsValid() && !isDisconnected()) {
|
} else if(!closing && !fdIsValid() && !isDisconnected()) {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include "icsneo/platform/tcp.h"
|
#include "icsneo/platform/tcp.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
@ -415,9 +416,10 @@ bool TCP::open() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emplace(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
auto partiallyOpenSocket = std::make_unique<Socket>(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||||
if(::setsockopt(*socket, SOL_SOCKET, SO_BINDTODEVICE, interface.name.c_str(), interface.name.size()) < 0) {
|
if(::setsockopt(*partiallyOpenSocket, SOL_SOCKET, SO_BINDTODEVICE, interface.name.c_str(), interface.name.size()) < 0) {
|
||||||
report(APIEvent::Type::ErrorSettingSocketOption, APIEvent::Severity::Error);
|
report(APIEvent::Type::ErrorSettingSocketOption, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -428,7 +430,7 @@ bool TCP::open() {
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_addr.s_addr = htonl(interface.ip);
|
addr.sin_addr.s_addr = htonl(interface.ip);
|
||||||
APPLE_SIN_LEN(addr);
|
APPLE_SIN_LEN(addr);
|
||||||
if(::bind(*socket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
if(::bind(*partiallyOpenSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||||
report(APIEvent::Type::FailedToBind, APIEvent::Severity::Error);
|
report(APIEvent::Type::FailedToBind, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -442,7 +444,7 @@ bool TCP::open() {
|
||||||
APPLE_SIN_LEN(addr);
|
APPLE_SIN_LEN(addr);
|
||||||
|
|
||||||
// the socket is non-blocking so it's expected that the first connect will fail
|
// the socket is non-blocking so it's expected that the first connect will fail
|
||||||
if(::connect(*socket, (sockaddr*)&addr, sizeof(addr)) == 0) {
|
if(::connect(*partiallyOpenSocket, (sockaddr*)&addr, sizeof(addr)) == 0) {
|
||||||
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
|
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -462,11 +464,11 @@ bool TCP::open() {
|
||||||
timeout.tv_sec = 1;
|
timeout.tv_sec = 1;
|
||||||
fd_set writefs;
|
fd_set writefs;
|
||||||
FD_ZERO(&writefs);
|
FD_ZERO(&writefs);
|
||||||
int nfds = WIN_INT(*socket) + 1;
|
int nfds = WIN_INT(*partiallyOpenSocket) + 1;
|
||||||
FD_SET(*socket, &writefs);
|
FD_SET(*partiallyOpenSocket, &writefs);
|
||||||
::select(nfds, 0, &writefs, 0, &timeout);
|
::select(nfds, 0, &writefs, 0, &timeout);
|
||||||
|
|
||||||
if(::connect(*socket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
if(::connect(*partiallyOpenSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if(::WSAGetLastError() != WSAEISCONN) {
|
if(::WSAGetLastError() != WSAEISCONN) {
|
||||||
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
|
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
|
||||||
|
|
@ -484,13 +486,14 @@ bool TCP::open() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket = std::move(partiallyOpenSocket);
|
||||||
readThread = std::thread(&TCP::readTask, this);
|
readThread = std::thread(&TCP::readTask, this);
|
||||||
writeThread = std::thread(&TCP::writeTask, this);
|
writeThread = std::thread(&TCP::writeTask, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TCP::isOpen() {
|
bool TCP::isOpen() {
|
||||||
return socket.has_value();
|
return socket ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TCP::close() {
|
bool TCP::close() {
|
||||||
|
|
@ -513,6 +516,7 @@ bool TCP::close() {
|
||||||
while(writeQueue.try_dequeue(flushop)) {}
|
while(writeQueue.try_dequeue(flushop)) {}
|
||||||
|
|
||||||
socket.reset();
|
socket.reset();
|
||||||
|
closing = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue