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
+2
View File
@@ -62,6 +62,8 @@ enum class ExtendedCommand : uint16_t {
RequestTC10Wake = 0x003D,
RequestTC10Sleep = 0x003E,
GetTC10Status = 0x003F,
ProtobufAPI = 0x0041,
TransmitMessage = 0x0042,
};
enum class ExtendedResponse : int32_t {
@@ -64,6 +64,8 @@ public:
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::optional< std::vector<ComponentVersion> > getComponentVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
std::optional<uint32_t> getClientIDSync();
int addMessageCallback(const std::shared_ptr<MessageCallback>& cb);
bool removeMessageCallback(int id);
+127
View File
@@ -0,0 +1,127 @@
#ifndef COMMUNICATION_PROTO_API_IMPL_H
#define COMMUNICATION_PROTO_API_IMPL_H
#include <cstdint>
#ifdef _WIN32
#pragma warning(push, 0)
#endif
#include <common/v1/proto_header.pb.h>
#include <commands/generic/v1/client_id.pb.h>
#include <commands/network/v1/mutex.pb.h>
#ifdef _WIN32
#pragma warning(pop)
#endif
namespace icsneo {
namespace protoapi {
enum class Command : uint8_t {
Unspecified = 0,
GET = 1,
PUT = 2,
PATCH = 3,
};
enum class Id : uint32_t {
Unspecified = 0,
MfgConfig = 1,
CpuId = 2,
NetworkMutex = 3,
ClientId = 4,
};
template <typename T>
struct IDLookup {
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_UNSPECIFIED;
};
template <>
struct IDLookup<commands::network::v1::NetworkMutex> {
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_NETWORK_MUTEX;
};
template <>
struct IDLookup<commands::generic::v1::ClientId> {
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_GET_CLIENT_ID;
};
inline uint8_t* writeVarint32(uint32_t value, uint8_t* target) {
return google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(value, target);
}
inline const uint8_t* readVarint32(uint32_t& value, const uint8_t* source) {
value = 0;
do {
value <<= 7;
value += *source & 0x7F;
} while(*source++ & 0x80);
return source;
}
template <typename T>
std::vector<uint8_t> getPayload(Command command, const T& msg) {
std::vector<uint8_t> payload;
constexpr uint32_t proto_version = 1;
common::v1::ProtoHeader hdr;
hdr.set_version(proto_version);
hdr.set_api_command(static_cast<common::v1::ApiCommand>(command));
hdr.set_auth_method(common::v1::AuthMethod::PROTO_API_AUTH_NONE); // TODO
hdr.set_proto_id(IDLookup<T>::value);
static constexpr size_t varint_size_max = 5;
size_t header_size = hdr.ByteSizeLong();
size_t msg_size = msg.ByteSizeLong();
size_t payload_size_max = header_size + msg_size + (varint_size_max * 2); // TODO: auth
payload.resize(payload_size_max);
uint8_t* target = payload.data();
target = writeVarint32(static_cast<uint32_t>(header_size), target);
hdr.SerializeToArray(target, static_cast<int>(header_size));
target += header_size;
if(msg_size) {
target = writeVarint32(static_cast<uint32_t>(msg_size), target);
msg.SerializeToArray(target, static_cast<int>(msg_size));
target += msg_size;
}
payload.resize(target - payload.data());
return payload;
}
template <typename T>
bool processResponse(const uint8_t* payload, size_t /* payload_length */, T& msg) {
// TODO: we should probably check payload_length throughout to not go past the end of the supplied buffer
// header
common::v1::ProtoHeader hdr;
uint32_t length;
const uint8_t* serialized = readVarint32(length, payload);
if(!hdr.ParseFromArray(serialized, length)) {
return false;
}
// message payload
serialized = readVarint32(length, serialized + length);
if(!msg.ParseFromArray(serialized, length)) {
return false;
}
return true;
}
inline Id getProtoId(const uint8_t* payload, size_t /* payload_length */) {
// TODO: we should probably check this throughout to not go past the end of the supplied buffer
// header
common::v1::ProtoHeader hdr;
uint32_t length;
const uint8_t* serialized = readVarint32(length, payload);
if(!hdr.ParseFromArray(serialized, length)) {
return Id::Unspecified;
}
return static_cast<Id>(hdr.proto_id());
}
} // namespace protoapi
} // namespace icsneo
#endif
@@ -0,0 +1,21 @@
#ifndef CLIENT_ID_MESSAGE_H_
#define CLIENT_ID_MESSAGE_H_
#include <cstdint>
#include "icsneo/communication/network.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
class ClientIdMessage : public Message {
public:
ClientIdMessage() : Message(Message::Type::ClientId) {}
static std::shared_ptr<ClientIdMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
std::optional<uint32_t> clientId;
};
} // namespace icsneo
#endif
@@ -45,6 +45,8 @@ public:
GPTPStatus = 0x8013,
EthernetStatus = 0x8014,
LogData = 0x8015,
NetworkMutex = 0x8016,
ClientId = 0x8017,
};
Message(Type t) : type(t) {}
@@ -0,0 +1,82 @@
#ifndef __NETWORKMUTEXMESSAGE_H_
#define __NETWORKMUTEXMESSAGE_H_
#include <cstdint>
#include <set>
#include "icsneo/communication/network.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
enum class NetworkMutexType : uint8_t {
Shared = 0,
TxExclusive = 1,
ExternalExclusive = 2,
FullyExclusive = 3,
};
enum class NetworkMutexEvent : uint8_t {
Released = 0,
Expired = 1,
Preempted = 2,
Queued = 3,
Acquired = 4,
};
class NetworkMutexMessage : public Message
{
public:
NetworkMutexMessage() : Message(Message::Type::NetworkMutex) {}
static std::shared_ptr<NetworkMutexMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static std::vector<uint8_t> EncodeArgumentsForLock(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const std::set<Network::NetID>& networks, const device_eventhandler_t& report);
static std::vector<uint8_t> EncodeArgumentsForLockAll(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const device_eventhandler_t& report);
static std::vector<uint8_t> EncodeArgumentsForUnlock(uint32_t client_id, const std::set<Network::NetID>& networks, const device_eventhandler_t& report);
static std::vector<uint8_t> EncodeArgumentsForUnlockAll(uint32_t client_id, const device_eventhandler_t& report);
static std::vector<uint8_t> EncodeArgumentsForStatus(Network::NetID network, const device_eventhandler_t& report);
static const char* GetNetworkMutexTypeString(NetworkMutexType type) {
switch(type) {
case icsneo::NetworkMutexType::Shared:
return "Shared";
case icsneo::NetworkMutexType::TxExclusive:
return "TxExclusive";
case icsneo::NetworkMutexType::ExternalExclusive:
return "ExternalExclusive";
case icsneo::NetworkMutexType::FullyExclusive:
return "FullyExclusive";
default:
return "Unknown";
}
}
static const char* GetNetworkMutexEventString(NetworkMutexEvent event) {
switch(event) {
case icsneo::NetworkMutexEvent::Acquired:
return "Acquired";
case icsneo::NetworkMutexEvent::Released:
return "Released";
case icsneo::NetworkMutexEvent::Preempted:
return "Preempted";
case icsneo::NetworkMutexEvent::Expired:
return "Expired";
case icsneo::NetworkMutexEvent::Queued:
return "Queued";
default:
return "Unknown";
}
}
std::optional<uint32_t> owner_id;
std::optional<NetworkMutexType> type;
std::optional<uint32_t> priority;
std::optional<uint32_t> ttlMs;
std::set<Network::NetID> networks;
std::optional<NetworkMutexEvent> event;
};
} // namespace icsneo
#endif
@@ -0,0 +1,30 @@
#ifndef TRANSMIT_MESSAGE_H_
#define TRANSMIT_MESSAGE_H_
#include <cstdint>
#include "icsneo/communication/message/message.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
struct TransmitMessage {
static std::vector<uint8_t> EncodeFromMessage(std::shared_ptr<Frame> message, uint32_t client_id, const device_eventhandler_t& report);
constexpr static size_t messageOptionsOffset = 0;
constexpr static size_t messageOptionsSize = 20; // todo determine max
constexpr static size_t messageCommonHeaderOffset = messageOptionsOffset + messageOptionsSize;
constexpr static size_t messageCommonHeaderSize = 28; // CoreminiMsgExtendedHdr
#pragma pack(push,1)
struct
{
uint32_t clientId;
uint32_t networkId;
uint32_t reserved[3]; // set to 0
} options;
uint8_t commonHeader[messageCommonHeaderSize];
#pragma pack(pop)
};
} // namespace icsneo
#endif // TRANSMIT_MESSAGE_H_
@@ -50,6 +50,9 @@ struct HardwareCANPacket {
uint64_t : 3; // Reserved for future status bits
uint64_t IsExtended : 1;
} timestamp;
uint16_t NetworkID;
uint16_t Length;
};
struct HardwareCANErrorPacket {
uint8_t error_code;
+16 -1
View File
@@ -57,7 +57,7 @@
#include "icsneo/disk/vsa/vsaparser.h"
#include "icsneo/communication/message/versionmessage.h"
#include "icsneo/communication/message/gptpstatusmessage.h"
#include "icsneo/communication/message/networkmutexmessage.h"
#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \
static constexpr DeviceType::Enum DEVICE_TYPE = type; \
@@ -856,6 +856,14 @@ public:
virtual bool writeMACsecConfig(const MACsecMessage& message, uint16_t binaryIndex);
std::shared_ptr<DeviceExtension> getExtension(const std::string& name) const;
[[nodiscard]] std::optional<int> lockNetworks(const std::set<Network::NetID>& networks, uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event);
[[nodiscard]] std::optional<int> lockAllNetworks(uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event);
bool unlockNetworks(const std::set<Network::NetID>& networks);
bool unlockAllNetworks();
std::shared_ptr<NetworkMutexMessage> getNetworkMutexStatus(Network::NetID network);
virtual bool supportsNetworkMutex() const { return false; }
protected:
bool online = false;
@@ -969,6 +977,8 @@ protected:
};
LEDState ledState;
void updateLEDState();
private:
neodevice_t data;
std::shared_ptr<ResetStatusMessage> latestResetStatus;
@@ -1127,6 +1137,11 @@ private:
// Keeponline (keepalive for online)
std::unique_ptr<Periodic> keeponline;
std::optional<uint32_t> assignedClientId;
std::set<icsneo::Network::NetID> lockedNetworks;
std::optional<int> networkMutexCallbackHandle;
};
}
@@ -123,6 +123,7 @@ protected:
return 2;
}
bool supportsNetworkMutex() const override { return true; }
};
}
@@ -145,6 +145,8 @@ protected:
return ret;
}
bool supportsNetworkMutex() const override { return true; }
};
}
@@ -103,6 +103,8 @@ protected:
size_t getDiskCount() const override {
return 2;
}
bool supportsNetworkMutex() const override { return true; }
};
}