Device: Add network mutex support

This commit is contained in:
Jonathan Schwartz
2025-10-24 12:12:36 -04:00
committed by Kyle Schwarz
parent bf311ebe30
commit c2f1022858
29 changed files with 1146 additions and 47 deletions
+35
View File
@@ -14,6 +14,12 @@
#include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/versionmessage.h"
#include "icsneo/communication/message/componentversionsmessage.h"
#include "icsneo/communication/message/filter/extendedresponsefilter.h"
#include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/icspb.h"
#include <commands/generic/v1/client_id.pb.h>
#include <commands/network/v1/mutex.pb.h>
using namespace icsneo;
@@ -313,3 +319,32 @@ std::optional< std::vector<ComponentVersion> > Communication::getComponentVersio
return std::make_optional< std::vector<ComponentVersion> >(std::move(ver->versions));
}
std::optional<uint32_t> Communication::getClientIDSync() {
constexpr auto timeout = std::chrono::milliseconds(250);
commands::generic::v1::ClientId msg;
msg.Clear();
std::vector<uint8_t> payload = protoapi::getPayload(protoapi::Command::GET, msg);
std::shared_ptr<Message> response = waitForMessageSync(
[this, payload](){
return sendCommand(ExtendedCommand::ProtobufAPI, payload);
},
std::make_shared<MessageFilter>(Message::Type::ClientId),
timeout
);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return std::nullopt;
}
auto clientIdMessage = std::dynamic_pointer_cast<ClientIdMessage>(response);
if(!clientIdMessage) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return std::nullopt;
}
return clientIdMessage->clientId;
}
+23
View File
@@ -23,6 +23,8 @@
#include "icsneo/communication/message/gptpstatusmessage.h"
#include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h"
@@ -44,6 +46,8 @@
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/packet/hardwareinfopacket.h"
#include "icsneo/communication/packet/spipacket.h"
#include "icsneo/communication/icspb.h"
#include <iostream>
@@ -338,6 +342,25 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = GPTPStatus::DecodeToMessage(packet->data, report);
return true;
}
case ExtendedCommand::ProtobufAPI: {
// get the proto id
std::vector<uint8_t> responseBody(
packet->data.begin() + sizeof(ExtendedResponseMessage::ResponseHeader),
packet->data.end()
);
protoapi::Id protoId = protoapi::getProtoId(responseBody.data(), responseBody.size());
switch(protoId) {
case protoapi::Id::NetworkMutex:
result = NetworkMutexMessage::DecodeToMessage(responseBody);
return true;
case protoapi::Id::ClientId:
result = ClientIdMessage::DecodeToMessage(responseBody);
return true;
default:
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
}
case ExtendedCommand::GetDiskDetails:
case ExtendedCommand::DiskFormatProgress: {
std::vector<uint8_t> responseBody(
+21
View File
@@ -0,0 +1,21 @@
#include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/icspb.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
using namespace icsneo;
std::shared_ptr<ClientIdMessage> ClientIdMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
ClientIdMessage decoded;
commands::generic::v1::ClientId msg;
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
return nullptr;
}
if(msg.has_client_id()) {
decoded.clientId.emplace(msg.client_id());
}
return std::make_shared<ClientIdMessage>(decoded);
}
@@ -0,0 +1,89 @@
#include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/icspb.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
using namespace icsneo;
std::shared_ptr<NetworkMutexMessage> NetworkMutexMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
NetworkMutexMessage decoded;
commands::network::v1::NetworkMutex msg;
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
return nullptr;
}
if(msg.has_client_id()) {
decoded.owner_id.emplace(msg.client_id());
}
if(msg.has_type()) {
decoded.type.emplace(static_cast<NetworkMutexType>(msg.type()));
}
if(msg.has_priority()) {
decoded.priority.emplace(msg.priority());
}
if(msg.has_ttl()){
decoded.ttlMs.emplace(msg.ttl());
}
if(msg.has_event()){
decoded.event.emplace(static_cast<NetworkMutexEvent>(msg.event()));
}
for(int i = 0 ; i < msg.network_ids_size(); ++i){
decoded.networks.emplace(static_cast<Network::NetID>(msg.network_ids(i)));
}
return std::make_shared<NetworkMutexMessage>(decoded);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForLock(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const std::set<Network::NetID>& networks, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
for(auto&& network_id : networks) {
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network_id));
}
msg.set_client_id(client_id);
msg.set_priority(priority);
msg.set_ttl(ttlMs);
msg.set_type(static_cast<commands::network::v1::MutexType>(type));
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForLockAll(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.set_client_id(client_id);
msg.set_priority(priority);
msg.set_ttl(ttlMs);
msg.set_type(static_cast<commands::network::v1::MutexType>(type));
msg.set_global(true);
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForUnlock(uint32_t client_id, const std::set<Network::NetID>& networks, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.Clear();
for(auto&& network_id : networks)
{
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network_id));
}
msg.set_client_id(client_id);
msg.set_release(true);
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForUnlockAll(uint32_t client_id, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.Clear();
msg.set_client_id(client_id);
msg.set_release(true);
msg.set_global(true);
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForStatus(Network::NetID network, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network));
return protoapi::getPayload(protoapi::Command::GET, msg);
}
+160
View File
@@ -0,0 +1,160 @@
#include "icsneo/communication/message/transmitmessage.h"
// packet defs
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/linpacket.h"
using namespace icsneo;
// copied.. TODO
static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd) {
if(dataLength <= 8)
return uint8_t(dataLength);
if(fd) {
if(dataLength <= 12)
return uint8_t(0x9);
if(dataLength <= 16)
return uint8_t(0xA);
if(dataLength <= 20)
return uint8_t(0xB);
if(dataLength <= 24)
return uint8_t(0xC);
if(dataLength <= 32)
return uint8_t(0xD);
if(dataLength <= 48)
return uint8_t(0xE);
if(dataLength <= 64)
return uint8_t(0xF);
}
return std::nullopt;
}
static std::vector<uint8_t> EncodeFromMessageEthernet(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(frame);
if(!ethmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return {};
}
std::vector<uint8_t> encoded;
size_t messageLen = ethmsg->data.size();
encoded.resize(sizeof(TransmitMessage) + messageLen);
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
HardwareEthernetPacket* const ethpacket = (HardwareEthernetPacket*)(msg->commonHeader);
uint8_t* const payload = encoded.data() + sizeof(TransmitMessage);
ethpacket->header.ENABLE_PADDING = ethmsg->noPadding ? 0 : 1;
ethpacket->header.FCS_OVERRIDE = ethmsg->fcs ? 1 : 0;
ethpacket->eid.txlen = static_cast<uint16_t>(messageLen);
ethpacket->Length = static_cast<uint16_t>(messageLen);
ethpacket->stats = ethmsg->description;
ethpacket->NetworkID = static_cast<uint16_t>(ethmsg->network.getNetID());
std::copy(ethmsg->data.begin(), ethmsg->data.end(), payload);
return encoded;
}
static std::vector<uint8_t> EncodeFromMessageCAN(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(frame);
if(!canmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return {};
}
if(canmsg->isCANFD && canmsg->isRemote) {
report(APIEvent::Type::RTRNotSupported, APIEvent::Severity::Error);
return {}; // RTR frames can not be used with CAN FD
}
std::vector<uint8_t> encoded;
size_t messageLen = canmsg->data.size();
size_t extraLen = 0;
if(messageLen > 8) {
extraLen = messageLen - 8;
}
encoded.resize(sizeof(TransmitMessage) + extraLen);
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
HardwareCANPacket* const canpacket = (HardwareCANPacket*)(msg->commonHeader);
uint8_t* const extra_payload = encoded.data() + sizeof(TransmitMessage);
const size_t dataSize = canmsg->data.size();
std::optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, canmsg->isCANFD);
if(!dlc.has_value()) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return {}; // Too much data for the protocol
}
// arb id
if(canmsg->isExtended) {
canpacket->header.IDE = 1;
canpacket->header.SID = (canmsg->arbid >> 18) & 0x7FF;
canpacket->eid.EID = (canmsg->arbid >> 6) & 0xfff;
canpacket->dlc.EID2 = canmsg->arbid & 0x3f;
} else {
canpacket->header.IDE = 0;
canpacket->header.SID = canmsg->arbid & 0x7FF;
}
// DLC
canpacket->dlc.DLC = dlc.value();
// FDF/BRS or remote frames
if(canmsg->isCANFD) {
canpacket->header.EDL = 1;
canpacket->header.BRS = canmsg->baudrateSwitch ? 1 : 0;
canpacket->header.ESI = canmsg->errorStateIndicator ? 1 : 0;
canpacket->dlc.RTR = 0;
} else {
canpacket->header.EDL = 0;
canpacket->header.BRS = 0;
canpacket->header.ESI = 0;
canpacket->dlc.RTR = canmsg->isRemote ? 1 : 0;
}
// network
canpacket->NetworkID = static_cast<uint16_t>(canmsg->network.getNetID());
canpacket->Length = static_cast<uint16_t>(extraLen);
// description id
canpacket->stats = canmsg->description;
// first 8 bytes
std::copy(canmsg->data.begin(), canmsg->data.begin() + (messageLen > 8 ? 8 : messageLen), canpacket->data);
// extra bytes
if(extraLen > 0) {
// copy extra data after the can packet
std::copy(canmsg->data.begin() + 8, canmsg->data.end(), extra_payload);
}
return encoded;
}
static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> /* frame */, const device_eventhandler_t& report) {
// TODO
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
return {};
}
std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> frame, uint32_t client_id, const device_eventhandler_t& report) {
std::vector<uint8_t> result;
switch(frame->network.getType()) {
case Network::Type::Ethernet:
result = EncodeFromMessageEthernet(frame, report);
break;
case Network::Type::CAN:
result = EncodeFromMessageCAN(frame, report);
break;
case Network::Type::LIN:
result = EncodeFromMessageLIN(frame, report);
break;
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return result;
}
// common fields
TransmitMessage* const msg = (TransmitMessage*)result.data();
msg->options.clientId = client_id;
msg->options.networkId = static_cast<uint32_t>(frame->network.getNetID());
msg->options.reserved[0] = 0;
msg->options.reserved[1] = 0;
msg->options.reserved[2] = 0;
return result;
}
+1 -1
View File
@@ -114,7 +114,7 @@ std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<ui
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket);
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
}
}