mirror of
https://github.com/BotChain-Robots/rpc.git
synced 2026-03-09 23:12:27 +01:00
Prepare files for public release
This commit is contained in:
53
include/BlockingQueue.h
Normal file
53
include/BlockingQueue.h
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-07-10.
|
||||
//
|
||||
|
||||
#ifndef BLOCKINGQUEUE_H
|
||||
#define BLOCKINGQUEUE_H
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
template <typename T> class BlockingQueue {
|
||||
public:
|
||||
explicit BlockingQueue(const size_t capacity) : m_capacity(capacity) {
|
||||
}
|
||||
|
||||
// Enqueue with timeout. Returns true on success, false on timeout.
|
||||
bool enqueue(T &&item, std::chrono::milliseconds max_wait) {
|
||||
std::unique_lock lock(m_mutex);
|
||||
if (!m_cond_not_full.wait_for(lock, max_wait,
|
||||
[this]() { return m_queue.size() < m_capacity; })) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_queue.push(std::move(item));
|
||||
m_cond_not_empty.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dequeue with timeout. Returns optional<T> (empty on timeout).
|
||||
std::optional<T> dequeue(std::chrono::milliseconds max_wait) {
|
||||
std::unique_lock lock(m_mutex);
|
||||
if (!m_cond_not_empty.wait_for(lock, max_wait, [this]() { return !m_queue.empty(); })) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
T item = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
m_cond_not_full.notify_one();
|
||||
return item;
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<T> m_queue;
|
||||
size_t m_capacity;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cond_not_empty;
|
||||
std::condition_variable m_cond_not_full;
|
||||
};
|
||||
|
||||
#endif // BLOCKINGQUEUE_H
|
||||
15
include/ICommunicationClient.h
Normal file
15
include/ICommunicationClient.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-06-10.
|
||||
//
|
||||
|
||||
#ifndef INETWORKCLIENT_H
|
||||
#define INETWORKCLIENT_H
|
||||
|
||||
class ICommunicationClient {
|
||||
public:
|
||||
virtual ~ICommunicationClient() = default;
|
||||
virtual int init() = 0;
|
||||
virtual int send_msg(void *sendbuff, uint32_t len) = 0;
|
||||
};
|
||||
|
||||
#endif //INETWORKCLIENT_H
|
||||
24
include/IDiscoveryService.h
Normal file
24
include/IDiscoveryService.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-06-10.
|
||||
//
|
||||
|
||||
#ifndef IDISCOVERYSERVICE_H
|
||||
#define IDISCOVERYSERVICE_H
|
||||
#include <unordered_set>
|
||||
|
||||
#include "ICommunicationClient.h"
|
||||
#include "mDNSRobotModule.h"
|
||||
|
||||
class IDiscoveryService {
|
||||
public:
|
||||
virtual ~IDiscoveryService() = default;
|
||||
virtual std::unordered_set<uint8_t> find_modules(std::chrono::duration<double> wait_time) = 0;
|
||||
virtual std::unordered_map<uint8_t, std::shared_ptr<ICommunicationClient>> get_lossy_clients(
|
||||
const std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> &rx_queue,
|
||||
std::vector<uint8_t> &skip_modules) = 0;
|
||||
virtual std::unordered_map<uint8_t, std::shared_ptr<ICommunicationClient>> get_lossless_clients(
|
||||
const std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> &rx_queue,
|
||||
std::vector<uint8_t> &skip_modules) = 0;
|
||||
};
|
||||
|
||||
#endif // IDISCOVERYSERVICE_H
|
||||
54
include/TCPClient.h
Normal file
54
include/TCPClient.h
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-06-10.
|
||||
//
|
||||
|
||||
#ifndef TCPCLIENT_H
|
||||
#define TCPCLIENT_H
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "ICommunicationClient.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#define CLOSE_SOCKET close
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
#include "BlockingQueue.h"
|
||||
|
||||
class TCPClient final : public ICommunicationClient {
|
||||
|
||||
public:
|
||||
TCPClient(std::string ip,
|
||||
const std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> &rx_queue)
|
||||
: port{3000}, m_ip{std::move(ip)}, m_stop_flag(false),
|
||||
m_thread(std::thread(&TCPClient::rx_thread, this)), m_rx_queue(rx_queue) {
|
||||
}
|
||||
~TCPClient() override;
|
||||
int init() override;
|
||||
int send_msg(void *sendbuff, uint32_t len) override;
|
||||
|
||||
private:
|
||||
void deinit();
|
||||
void rx_thread() const;
|
||||
|
||||
socket_t m_socket = -1;
|
||||
int port;
|
||||
bool m_initialized = false;
|
||||
std::string m_ip;
|
||||
std::atomic<bool> m_stop_flag;
|
||||
std::thread m_thread;
|
||||
std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> m_rx_queue;
|
||||
};
|
||||
|
||||
#endif // TCPCLIENT_H
|
||||
53
include/UDPClient.h
Normal file
53
include/UDPClient.h
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-12-27.
|
||||
//
|
||||
|
||||
#ifndef UDPCLIENT_H
|
||||
#define UDPCLIENT_H
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "ICommunicationClient.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#define CLOSE_SOCKET close
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
#include "BlockingQueue.h"
|
||||
|
||||
class UDPClient final : public ICommunicationClient {
|
||||
|
||||
public:
|
||||
UDPClient(std::string /* ip */,
|
||||
const std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> &rx_queue)
|
||||
: m_stop_flag(false), m_thread(std::thread(&UDPClient::rx_thread, this)),
|
||||
m_rx_queue(rx_queue) {
|
||||
}
|
||||
~UDPClient() override;
|
||||
int init() override;
|
||||
int send_msg(void *sendbuff, uint32_t len) override;
|
||||
|
||||
private:
|
||||
void deinit();
|
||||
void rx_thread() const;
|
||||
|
||||
socket_t m_tx_socket = -1;
|
||||
socket_t m_rx_socket = -1;
|
||||
bool m_initialized = false;
|
||||
std::atomic<bool> m_stop_flag;
|
||||
std::thread m_thread;
|
||||
std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> m_rx_queue;
|
||||
};
|
||||
|
||||
#endif // UDPCLIENT_H
|
||||
7
include/constants.h
Normal file
7
include/constants.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef CONSTANTS_H
|
||||
#define CONSTANTS_H
|
||||
|
||||
constexpr auto PC_MODULE_ID = 1;
|
||||
constexpr auto MAX_BUFFER_SIZE = 1024;
|
||||
|
||||
#endif // CONSTANTS_H
|
||||
33
include/flatbuffers/MPIMessageBuilder.h
Normal file
33
include/flatbuffers/MPIMessageBuilder.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-06-30.
|
||||
//
|
||||
|
||||
#ifndef MPIMESSAGEBUILDER_H
|
||||
#define MPIMESSAGEBUILDER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../flatbuffers_generated/MPIMessage_generated.h"
|
||||
#include "SerializedMessage.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
namespace Flatbuffers {
|
||||
class MPIMessageBuilder {
|
||||
public:
|
||||
MPIMessageBuilder() : builder_(1024) {
|
||||
}
|
||||
|
||||
SerializedMessage build_mpi_message(Messaging::MessageType type, uint8_t sender,
|
||||
uint8_t destination, uint16_t sequence_number,
|
||||
bool is_durable, uint8_t tag,
|
||||
const std::vector<uint8_t> &payload);
|
||||
|
||||
static const Messaging::MPIMessage *parse_mpi_message(const uint8_t *buffer);
|
||||
|
||||
private:
|
||||
flatbuffers::FlatBufferBuilder builder_;
|
||||
};
|
||||
} // namespace Flatbuffers
|
||||
|
||||
#endif //MPIMESSAGEBUILDER_H
|
||||
15
include/flatbuffers/SerializedMessage.h
Normal file
15
include/flatbuffers/SerializedMessage.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-07-05.
|
||||
//
|
||||
|
||||
#ifndef SERIALIZEDMESSAGE_H
|
||||
#define SERIALIZEDMESSAGE_H
|
||||
|
||||
namespace Flatbuffers {
|
||||
struct SerializedMessage {
|
||||
void *data;
|
||||
size_t size;
|
||||
};
|
||||
} // namespace Flatbuffers
|
||||
|
||||
#endif //SERIALIZEDMESSAGE_H
|
||||
188
include/flatbuffers_generated/MPIMessage_generated.h
Normal file
188
include/flatbuffers_generated/MPIMessage_generated.h
Normal file
@@ -0,0 +1,188 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_MPIMESSAGE_MESSAGING_H_
|
||||
#define FLATBUFFERS_GENERATED_MPIMESSAGE_MESSAGING_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||
// generated, otherwise it may not be compatible.
|
||||
// static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||
// FLATBUFFERS_VERSION_MINOR == 2 &&
|
||||
// FLATBUFFERS_VERSION_REVISION == 10,
|
||||
// "Non-compatible flatbuffers version included");
|
||||
|
||||
namespace Messaging {
|
||||
|
||||
struct MPIMessage;
|
||||
struct MPIMessageBuilder;
|
||||
|
||||
enum MessageType : int8_t {
|
||||
MessageType_BROADCAST = 0,
|
||||
MessageType_PTP = 1,
|
||||
MessageType_MIN = MessageType_BROADCAST,
|
||||
MessageType_MAX = MessageType_PTP
|
||||
};
|
||||
|
||||
inline const MessageType (&EnumValuesMessageType())[2] {
|
||||
static const MessageType values[] = {MessageType_BROADCAST, MessageType_PTP};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char *const *EnumNamesMessageType() {
|
||||
static const char *const names[3] = {"BROADCAST", "PTP", nullptr};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameMessageType(MessageType e) {
|
||||
if (::flatbuffers::IsOutRange(e, MessageType_BROADCAST, MessageType_PTP))
|
||||
return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesMessageType()[index];
|
||||
}
|
||||
|
||||
struct MPIMessage FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
typedef MPIMessageBuilder Builder;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_TYPE = 4,
|
||||
VT_SENDER = 6,
|
||||
VT_DESTINATION = 8,
|
||||
VT_SEQUENCE_NUMBER = 10,
|
||||
VT_IS_DURABLE = 12,
|
||||
VT_LENGTH = 14,
|
||||
VT_TAG = 16,
|
||||
VT_PAYLOAD = 18
|
||||
};
|
||||
Messaging::MessageType type() const {
|
||||
return static_cast<Messaging::MessageType>(GetField<int8_t>(VT_TYPE, 0));
|
||||
}
|
||||
uint8_t sender() const {
|
||||
return GetField<uint8_t>(VT_SENDER, 0);
|
||||
}
|
||||
uint8_t destination() const {
|
||||
return GetField<uint8_t>(VT_DESTINATION, 0);
|
||||
}
|
||||
uint16_t sequence_number() const {
|
||||
return GetField<uint16_t>(VT_SEQUENCE_NUMBER, 0);
|
||||
}
|
||||
bool is_durable() const {
|
||||
return GetField<uint8_t>(VT_IS_DURABLE, 0) != 0;
|
||||
}
|
||||
uint16_t length() const {
|
||||
return GetField<uint16_t>(VT_LENGTH, 0);
|
||||
}
|
||||
uint8_t tag() const {
|
||||
return GetField<uint8_t>(VT_TAG, 0);
|
||||
}
|
||||
const ::flatbuffers::Vector<uint8_t> *payload() const {
|
||||
return GetPointer<const ::flatbuffers::Vector<uint8_t> *>(VT_PAYLOAD);
|
||||
}
|
||||
bool Verify(::flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_TYPE, 1) &&
|
||||
VerifyField<uint8_t>(verifier, VT_SENDER, 1) &&
|
||||
VerifyField<uint8_t>(verifier, VT_DESTINATION, 1) &&
|
||||
VerifyField<uint16_t>(verifier, VT_SEQUENCE_NUMBER, 2) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_DURABLE, 1) &&
|
||||
VerifyField<uint16_t>(verifier, VT_LENGTH, 2) &&
|
||||
VerifyField<uint8_t>(verifier, VT_TAG, 1) && VerifyOffset(verifier, VT_PAYLOAD) &&
|
||||
verifier.VerifyVector(payload()) && verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct MPIMessageBuilder {
|
||||
typedef MPIMessage Table;
|
||||
::flatbuffers::FlatBufferBuilder &fbb_;
|
||||
::flatbuffers::uoffset_t start_;
|
||||
void add_type(Messaging::MessageType type) {
|
||||
fbb_.AddElement<int8_t>(MPIMessage::VT_TYPE, static_cast<int8_t>(type), 0);
|
||||
}
|
||||
void add_sender(uint8_t sender) {
|
||||
fbb_.AddElement<uint8_t>(MPIMessage::VT_SENDER, sender, 0);
|
||||
}
|
||||
void add_destination(uint8_t destination) {
|
||||
fbb_.AddElement<uint8_t>(MPIMessage::VT_DESTINATION, destination, 0);
|
||||
}
|
||||
void add_sequence_number(uint16_t sequence_number) {
|
||||
fbb_.AddElement<uint16_t>(MPIMessage::VT_SEQUENCE_NUMBER, sequence_number, 0);
|
||||
}
|
||||
void add_is_durable(bool is_durable) {
|
||||
fbb_.AddElement<uint8_t>(MPIMessage::VT_IS_DURABLE, static_cast<uint8_t>(is_durable), 0);
|
||||
}
|
||||
void add_length(uint16_t length) {
|
||||
fbb_.AddElement<uint16_t>(MPIMessage::VT_LENGTH, length, 0);
|
||||
}
|
||||
void add_tag(uint8_t tag) {
|
||||
fbb_.AddElement<uint8_t>(MPIMessage::VT_TAG, tag, 0);
|
||||
}
|
||||
void add_payload(::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload) {
|
||||
fbb_.AddOffset(MPIMessage::VT_PAYLOAD, payload);
|
||||
}
|
||||
explicit MPIMessageBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
::flatbuffers::Offset<MPIMessage> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = ::flatbuffers::Offset<MPIMessage>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline ::flatbuffers::Offset<MPIMessage>
|
||||
CreateMPIMessage(::flatbuffers::FlatBufferBuilder &_fbb,
|
||||
Messaging::MessageType type = Messaging::MessageType_BROADCAST, uint8_t sender = 0,
|
||||
uint8_t destination = 0, uint16_t sequence_number = 0, bool is_durable = false,
|
||||
uint16_t length = 0, uint8_t tag = 0,
|
||||
::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload = 0) {
|
||||
MPIMessageBuilder builder_(_fbb);
|
||||
builder_.add_payload(payload);
|
||||
builder_.add_length(length);
|
||||
builder_.add_sequence_number(sequence_number);
|
||||
builder_.add_tag(tag);
|
||||
builder_.add_is_durable(is_durable);
|
||||
builder_.add_destination(destination);
|
||||
builder_.add_sender(sender);
|
||||
builder_.add_type(type);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline ::flatbuffers::Offset<MPIMessage>
|
||||
CreateMPIMessageDirect(::flatbuffers::FlatBufferBuilder &_fbb,
|
||||
Messaging::MessageType type = Messaging::MessageType_BROADCAST,
|
||||
uint8_t sender = 0, uint8_t destination = 0, uint16_t sequence_number = 0,
|
||||
bool is_durable = false, uint16_t length = 0, uint8_t tag = 0,
|
||||
const std::vector<uint8_t> *payload = nullptr) {
|
||||
auto payload__ = payload ? _fbb.CreateVector<uint8_t>(*payload) : 0;
|
||||
return Messaging::CreateMPIMessage(_fbb, type, sender, destination, sequence_number, is_durable,
|
||||
length, tag, payload__);
|
||||
}
|
||||
|
||||
inline const Messaging::MPIMessage *GetMPIMessage(const void *buf) {
|
||||
return ::flatbuffers::GetRoot<Messaging::MPIMessage>(buf);
|
||||
}
|
||||
|
||||
inline const Messaging::MPIMessage *GetSizePrefixedMPIMessage(const void *buf) {
|
||||
return ::flatbuffers::GetSizePrefixedRoot<Messaging::MPIMessage>(buf);
|
||||
}
|
||||
|
||||
inline bool VerifyMPIMessageBuffer(::flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<Messaging::MPIMessage>(nullptr);
|
||||
}
|
||||
|
||||
inline bool VerifySizePrefixedMPIMessageBuffer(::flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifySizePrefixedBuffer<Messaging::MPIMessage>(nullptr);
|
||||
}
|
||||
|
||||
inline void FinishMPIMessageBuffer(::flatbuffers::FlatBufferBuilder &fbb,
|
||||
::flatbuffers::Offset<Messaging::MPIMessage> root) {
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline void FinishSizePrefixedMPIMessageBuffer(::flatbuffers::FlatBufferBuilder &fbb,
|
||||
::flatbuffers::Offset<Messaging::MPIMessage> root) {
|
||||
fbb.FinishSizePrefixed(root);
|
||||
}
|
||||
|
||||
} // namespace Messaging
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_MPIMESSAGE_MESSAGING_H_
|
||||
286
include/flatbuffers_generated/RobotModule_generated.h
Normal file
286
include/flatbuffers_generated/RobotModule_generated.h
Normal file
@@ -0,0 +1,286 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_ROBOTMODULE_H_
|
||||
#define FLATBUFFERS_GENERATED_ROBOTMODULE_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||
// generated, otherwise it may not be compatible.
|
||||
//static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||
// FLATBUFFERS_VERSION_MINOR == 2 &&
|
||||
// FLATBUFFERS_VERSION_REVISION == 10,
|
||||
// "Non-compatible flatbuffers version included");
|
||||
|
||||
struct MotorState;
|
||||
struct MotorStateBuilder;
|
||||
|
||||
struct RobotModule;
|
||||
struct RobotModuleBuilder;
|
||||
|
||||
enum ModuleType : int8_t {
|
||||
ModuleType_SPLITTER = 0,
|
||||
ModuleType_SERVO_1 = 1,
|
||||
ModuleType_DC_MOTOR = 2,
|
||||
ModuleType_BATTERY = 3,
|
||||
ModuleType_MIN = ModuleType_SPLITTER,
|
||||
ModuleType_MAX = ModuleType_BATTERY
|
||||
};
|
||||
|
||||
inline const ModuleType (&EnumValuesModuleType())[4] {
|
||||
static const ModuleType values[] = {ModuleType_SPLITTER, ModuleType_SERVO_1,
|
||||
ModuleType_DC_MOTOR, ModuleType_BATTERY};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char *const *EnumNamesModuleType() {
|
||||
static const char *const names[5] = {"SPLITTER", "SERVO_1", "DC_MOTOR", "BATTERY", nullptr};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameModuleType(ModuleType e) {
|
||||
if (::flatbuffers::IsOutRange(e, ModuleType_SPLITTER, ModuleType_BATTERY))
|
||||
return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesModuleType()[index];
|
||||
}
|
||||
|
||||
enum Orientation : int8_t {
|
||||
Orientation_Deg0 = 0,
|
||||
Orientation_Deg90 = 1,
|
||||
Orientation_Deg180 = 2,
|
||||
Orientation_Deg270 = 3,
|
||||
Orientation_MIN = Orientation_Deg0,
|
||||
Orientation_MAX = Orientation_Deg270
|
||||
};
|
||||
|
||||
inline const Orientation (&EnumValuesOrientation())[4] {
|
||||
static const Orientation values[] = {Orientation_Deg0, Orientation_Deg90, Orientation_Deg180,
|
||||
Orientation_Deg270};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char *const *EnumNamesOrientation() {
|
||||
static const char *const names[5] = {"Deg0", "Deg90", "Deg180", "Deg270", nullptr};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameOrientation(Orientation e) {
|
||||
if (::flatbuffers::IsOutRange(e, Orientation_Deg0, Orientation_Deg270))
|
||||
return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesOrientation()[index];
|
||||
}
|
||||
|
||||
enum ModuleState : uint8_t {
|
||||
ModuleState_NONE = 0,
|
||||
ModuleState_MotorState = 1,
|
||||
ModuleState_MIN = ModuleState_NONE,
|
||||
ModuleState_MAX = ModuleState_MotorState
|
||||
};
|
||||
|
||||
inline const ModuleState (&EnumValuesModuleState())[2] {
|
||||
static const ModuleState values[] = {ModuleState_NONE, ModuleState_MotorState};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char *const *EnumNamesModuleState() {
|
||||
static const char *const names[3] = {"NONE", "MotorState", nullptr};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameModuleState(ModuleState e) {
|
||||
if (::flatbuffers::IsOutRange(e, ModuleState_NONE, ModuleState_MotorState))
|
||||
return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesModuleState()[index];
|
||||
}
|
||||
|
||||
template <typename T> struct ModuleStateTraits {
|
||||
static const ModuleState enum_value = ModuleState_NONE;
|
||||
};
|
||||
|
||||
template <> struct ModuleStateTraits<MotorState> {
|
||||
static const ModuleState enum_value = ModuleState_MotorState;
|
||||
};
|
||||
|
||||
bool VerifyModuleState(::flatbuffers::Verifier &verifier, const void *obj, ModuleState type);
|
||||
bool VerifyModuleStateVector(::flatbuffers::Verifier &verifier,
|
||||
const ::flatbuffers::Vector<::flatbuffers::Offset<void>> *values,
|
||||
const ::flatbuffers::Vector<uint8_t> *types);
|
||||
|
||||
struct MotorState FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
typedef MotorStateBuilder Builder;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_ANGLE = 4 };
|
||||
int32_t angle() const {
|
||||
return GetField<int32_t>(VT_ANGLE, 0);
|
||||
}
|
||||
bool Verify(::flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_ANGLE, 4) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct MotorStateBuilder {
|
||||
typedef MotorState Table;
|
||||
::flatbuffers::FlatBufferBuilder &fbb_;
|
||||
::flatbuffers::uoffset_t start_;
|
||||
void add_angle(int32_t angle) {
|
||||
fbb_.AddElement<int32_t>(MotorState::VT_ANGLE, angle, 0);
|
||||
}
|
||||
explicit MotorStateBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
::flatbuffers::Offset<MotorState> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = ::flatbuffers::Offset<MotorState>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline ::flatbuffers::Offset<MotorState> CreateMotorState(::flatbuffers::FlatBufferBuilder &_fbb,
|
||||
int32_t angle = 0) {
|
||||
MotorStateBuilder builder_(_fbb);
|
||||
builder_.add_angle(angle);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct RobotModule FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
typedef RobotModuleBuilder Builder;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_ID = 4,
|
||||
VT_MODULE_TYPE = 6,
|
||||
VT_CONFIGURATION_TYPE = 8,
|
||||
VT_CONFIGURATION = 10
|
||||
};
|
||||
uint8_t id() const {
|
||||
return GetField<uint8_t>(VT_ID, 0);
|
||||
}
|
||||
ModuleType module_type() const {
|
||||
return static_cast<ModuleType>(GetField<int8_t>(VT_MODULE_TYPE, 0));
|
||||
}
|
||||
ModuleState configuration_type() const {
|
||||
return static_cast<ModuleState>(GetField<uint8_t>(VT_CONFIGURATION_TYPE, 0));
|
||||
}
|
||||
const void *configuration() const {
|
||||
return GetPointer<const void *>(VT_CONFIGURATION);
|
||||
}
|
||||
template <typename T> const T *configuration_as() const;
|
||||
const MotorState *configuration_as_MotorState() const {
|
||||
return configuration_type() == ModuleState_MotorState
|
||||
? static_cast<const MotorState *>(configuration())
|
||||
: nullptr;
|
||||
}
|
||||
bool Verify(::flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_ID, 1) &&
|
||||
VerifyField<int8_t>(verifier, VT_MODULE_TYPE, 1) &&
|
||||
VerifyField<uint8_t>(verifier, VT_CONFIGURATION_TYPE, 1) &&
|
||||
VerifyOffset(verifier, VT_CONFIGURATION) &&
|
||||
VerifyModuleState(verifier, configuration(), configuration_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
template <> inline const MotorState *RobotModule::configuration_as<MotorState>() const {
|
||||
return configuration_as_MotorState();
|
||||
}
|
||||
|
||||
struct RobotModuleBuilder {
|
||||
typedef RobotModule Table;
|
||||
::flatbuffers::FlatBufferBuilder &fbb_;
|
||||
::flatbuffers::uoffset_t start_;
|
||||
void add_id(uint8_t id) {
|
||||
fbb_.AddElement<uint8_t>(RobotModule::VT_ID, id, 0);
|
||||
}
|
||||
void add_module_type(ModuleType module_type) {
|
||||
fbb_.AddElement<int8_t>(RobotModule::VT_MODULE_TYPE, static_cast<int8_t>(module_type), 0);
|
||||
}
|
||||
void add_configuration_type(ModuleState configuration_type) {
|
||||
fbb_.AddElement<uint8_t>(RobotModule::VT_CONFIGURATION_TYPE,
|
||||
static_cast<uint8_t>(configuration_type), 0);
|
||||
}
|
||||
void add_configuration(::flatbuffers::Offset<void> configuration) {
|
||||
fbb_.AddOffset(RobotModule::VT_CONFIGURATION, configuration);
|
||||
}
|
||||
explicit RobotModuleBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
::flatbuffers::Offset<RobotModule> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = ::flatbuffers::Offset<RobotModule>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline ::flatbuffers::Offset<RobotModule>
|
||||
CreateRobotModule(::flatbuffers::FlatBufferBuilder &_fbb, uint8_t id = 0,
|
||||
ModuleType module_type = ModuleType_SPLITTER,
|
||||
ModuleState configuration_type = ModuleState_NONE,
|
||||
::flatbuffers::Offset<void> configuration = 0) {
|
||||
RobotModuleBuilder builder_(_fbb);
|
||||
builder_.add_configuration(configuration);
|
||||
builder_.add_configuration_type(configuration_type);
|
||||
builder_.add_module_type(module_type);
|
||||
builder_.add_id(id);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline bool VerifyModuleState(::flatbuffers::Verifier &verifier, const void *obj,
|
||||
ModuleState type) {
|
||||
switch (type) {
|
||||
case ModuleState_NONE: {
|
||||
return true;
|
||||
}
|
||||
case ModuleState_MotorState: {
|
||||
auto ptr = reinterpret_cast<const MotorState *>(obj);
|
||||
return verifier.VerifyTable(ptr);
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
VerifyModuleStateVector(::flatbuffers::Verifier &verifier,
|
||||
const ::flatbuffers::Vector<::flatbuffers::Offset<void>> *values,
|
||||
const ::flatbuffers::Vector<uint8_t> *types) {
|
||||
if (!values || !types)
|
||||
return !values && !types;
|
||||
if (values->size() != types->size())
|
||||
return false;
|
||||
for (::flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
|
||||
if (!VerifyModuleState(verifier, values->Get(i), types->GetEnum<ModuleState>(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline const RobotModule *GetRobotModule(const void *buf) {
|
||||
return ::flatbuffers::GetRoot<RobotModule>(buf);
|
||||
}
|
||||
|
||||
inline const RobotModule *GetSizePrefixedRobotModule(const void *buf) {
|
||||
return ::flatbuffers::GetSizePrefixedRoot<RobotModule>(buf);
|
||||
}
|
||||
|
||||
inline bool VerifyRobotModuleBuffer(::flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<RobotModule>(nullptr);
|
||||
}
|
||||
|
||||
inline bool VerifySizePrefixedRobotModuleBuffer(::flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifySizePrefixedBuffer<RobotModule>(nullptr);
|
||||
}
|
||||
|
||||
inline void FinishRobotModuleBuffer(::flatbuffers::FlatBufferBuilder &fbb,
|
||||
::flatbuffers::Offset<RobotModule> root) {
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline void FinishSizePrefixedRobotModuleBuffer(::flatbuffers::FlatBufferBuilder &fbb,
|
||||
::flatbuffers::Offset<RobotModule> root) {
|
||||
fbb.FinishSizePrefixed(root);
|
||||
}
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_ROBOTMODULE_H_
|
||||
59
include/librpc.h
Normal file
59
include/librpc.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef RPC_LIBRARY_H
|
||||
#define RPC_LIBRARY_H
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "BlockingQueue.h"
|
||||
#include "constants.h"
|
||||
#include "mDNSDiscoveryService.h"
|
||||
|
||||
|
||||
constexpr auto RX_QUEUE_SIZE = 100;
|
||||
|
||||
struct SizeAndSource {
|
||||
size_t bytes_written;
|
||||
uint8_t sender;
|
||||
};
|
||||
|
||||
class MessagingInterface {
|
||||
public:
|
||||
MessagingInterface()
|
||||
: m_stop_flag(false), m_rx_thread(std::thread(&MessagingInterface::handle_recv, this)),
|
||||
m_rx_queue(std::make_shared<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>>(
|
||||
RX_QUEUE_SIZE)) {
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
#endif
|
||||
// Initialization must be after call to WSAStartup
|
||||
m_discovery_service = std::make_unique<mDNSDiscoveryService>();
|
||||
}
|
||||
|
||||
~MessagingInterface();
|
||||
int send(uint8_t *buffer, size_t size, uint8_t destination, uint8_t tag, bool durable);
|
||||
int broadcast(uint8_t *buffer, size_t size, bool durable); // todo
|
||||
std::optional<SizeAndSource> recv(uint8_t *buffer, size_t size, uint8_t tag);
|
||||
int sendrecv(uint8_t *send_buffer, size_t send_size, uint8_t dest, uint8_t send_tag,
|
||||
uint8_t *recv_buffer, size_t recv_size, uint8_t recv_tag); // todo
|
||||
std::unordered_set<uint8_t> find_connected_modules(std::chrono::duration<double> scan_duration);
|
||||
|
||||
private:
|
||||
void handle_recv();
|
||||
|
||||
uint16_t m_sequence_number = 0;
|
||||
std::unordered_map<uint8_t, std::shared_ptr<ICommunicationClient>> m_id_to_lossless_client;
|
||||
std::unordered_map<uint8_t, std::shared_ptr<ICommunicationClient>> m_id_to_lossy_client;
|
||||
std::unordered_map<int, std::unique_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>>>
|
||||
m_tag_to_queue_map;
|
||||
std::unique_ptr<IDiscoveryService> m_discovery_service;
|
||||
std::atomic<bool> m_stop_flag;
|
||||
std::thread m_rx_thread;
|
||||
std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> m_rx_queue;
|
||||
std::shared_mutex m_client_mutex;
|
||||
std::shared_mutex m_scan_mutex;
|
||||
};
|
||||
|
||||
#endif // RPC_LIBRARY_H
|
||||
56
include/mDNSDiscoveryService.h
Normal file
56
include/mDNSDiscoveryService.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-06-10.
|
||||
//
|
||||
|
||||
#ifndef MDNSDISCOVERYSERVICE_H
|
||||
#define MDNSDISCOVERYSERVICE_H
|
||||
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "BlockingQueue.h"
|
||||
#include "ICommunicationClient.h"
|
||||
#include "IDiscoveryService.h"
|
||||
#include "mDNSRobotModule.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#define CLOSE_SOCKET close
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
class mDNSDiscoveryService final : public IDiscoveryService {
|
||||
|
||||
public:
|
||||
mDNSDiscoveryService();
|
||||
~mDNSDiscoveryService() override;
|
||||
std::unordered_set<uint8_t> find_modules(std::chrono::duration<double> wait_time) override;
|
||||
std::unordered_map<uint8_t, std::shared_ptr<ICommunicationClient>> get_lossy_clients(
|
||||
const std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> &rx_queue,
|
||||
std::vector<uint8_t> &skip_modules) override;
|
||||
std::unordered_map<uint8_t, std::shared_ptr<ICommunicationClient>> get_lossless_clients(
|
||||
const std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> &rx_queue,
|
||||
std::vector<uint8_t> &skip_modules) override;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
std::unordered_map<uint8_t, std::shared_ptr<ICommunicationClient>> create_clients(
|
||||
const std::shared_ptr<BlockingQueue<std::unique_ptr<std::vector<uint8_t>>>> &rx_queue,
|
||||
std::vector<uint8_t> &skip_modules);
|
||||
static void send_mdns_query(socket_t sock, const sockaddr_in &addr);
|
||||
static std::optional<mDNSRobotModule> parse_response(uint8_t *buffer, int size);
|
||||
static std::tuple<std::string, int> read_mdns_name(const uint8_t *buffer, int size, int ptr);
|
||||
|
||||
std::unordered_map<uint8_t, mDNSRobotModule> module_to_mdns{};
|
||||
};
|
||||
|
||||
#endif // MDNSDISCOVERYSERVICE_H
|
||||
19
include/mDNSRobotModule.h
Normal file
19
include/mDNSRobotModule.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-07-05.
|
||||
//
|
||||
|
||||
#ifndef ROBOTMODULEINSTANCE_H
|
||||
#define ROBOTMODULEINSTANCE_H
|
||||
|
||||
#include "flatbuffers_generated/RobotModule_generated.h"
|
||||
#include <string>
|
||||
|
||||
struct mDNSRobotModule {
|
||||
int id;
|
||||
std::string ip;
|
||||
std::string hostname;
|
||||
ModuleType module_type;
|
||||
std::vector<int> connected_module_ids;
|
||||
};
|
||||
|
||||
#endif //ROBOTMODULEINSTANCE_H
|
||||
24
include/util/ip.h
Normal file
24
include/util/ip.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef IP_UTIL_H
|
||||
#define IP_UTIL_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#define CLOSE_SOCKET close
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
bool is_valid_ipv4(const std::string &ip) {
|
||||
struct in_addr addr;
|
||||
return inet_pton(AF_INET, ip.c_str(), &addr) == 1;
|
||||
}
|
||||
|
||||
#endif // IP_UTIL_H
|
||||
32
include/util/log.h
Normal file
32
include/util/log.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by sligh on 2026-01-09.
|
||||
//
|
||||
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#define ERRBUF_SIZE 300
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void print_errno() {
|
||||
char errbuf[ERRBUF_SIZE];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, WSAGetLastError(), 0, errbuf, sizeof(errbuf),
|
||||
NULL);
|
||||
spdlog::error("{}", errbuf);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
void print_errno() {
|
||||
spdlog::error("{}", strerror(errno));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif //LOG_H
|
||||
23
include/util/string.h
Normal file
23
include/util/string.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-07-05.
|
||||
//
|
||||
|
||||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
inline std::vector<std::string> split(const std::string &str, const char delimiter) {
|
||||
std::vector<std::string> result;
|
||||
std::stringstream ss(str);
|
||||
std::string token;
|
||||
|
||||
while (std::getline(ss, token, delimiter)) {
|
||||
result.push_back(token);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif //STRING_H
|
||||
Reference in New Issue
Block a user