RoboidControl-cpp/LocalParticipant.cpp
2025-03-07 11:47:45 +01:00

367 lines
12 KiB
C++

#include "LocalParticipant.h"
#include "Thing.h"
#include "Arduino/ArduinoParticipant.h"
#if defined(_WIN32) || defined(_WIN64)
#include <winsock2.h>
#include <ws2tcpip.h>
#include "Windows/WindowsParticipant.h"
#pragma comment(lib, "ws2_32.lib")
#elif defined(__unix__) || defined(__APPLE__)
#include <arpa/inet.h>
#include <fcntl.h> // For fcntl
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <chrono>
#include "Posix/PosixParticipant.h"
#endif
#include <string.h>
namespace RoboidControl {
// LocalParticipant::LocalParticipant() {}
LocalParticipant::LocalParticipant(int port) {
this->ipAddress = "0.0.0.0";
this->port = port;
if (this->port == 0)
this->isIsolated = true;
}
LocalParticipant::LocalParticipant(const char* ipAddress, int port) {
this->ipAddress = "0.0.0.0"; // ipAddress; // maybe this is not needed
// anymore, keeping it to "0.0.0.0"
this->port = port;
if (this->port == 0)
this->isIsolated = true;
else
this->remoteSite = new Participant(ipAddress, port);
}
static LocalParticipant* isolatedParticipant = nullptr;
LocalParticipant* LocalParticipant::Isolated() {
if (isolatedParticipant == nullptr)
isolatedParticipant = new LocalParticipant(0);
return isolatedParticipant;
}
void LocalParticipant::begin() {
if (this->isIsolated)
return;
SetupUDP(this->port, this->ipAddress, this->port);
}
void LocalParticipant::SetupUDP(int localPort,
const char* remoteIpAddress,
int remotePort) {
#if defined(_WIN32) || defined(_WIN64)
Windows::LocalParticipant* thisWindows =
static_cast<Windows::LocalParticipant*>(this);
thisWindows->Setup(localPort, remoteIpAddress, remotePort);
#elif defined(__unix__) || defined(__APPLE__)
Posix::LocalParticipant* thisPosix =
static_cast<Posix::LocalParticipant*>(this);
thisPosix->Setup(localPort, remoteIpAddress, remotePort);
#elif defined(ARDUINO)
Arduino::LocalParticipant* thisArduino =
static_cast<Arduino::LocalParticipant*>(this);
thisArduino->Setup(localPort, remoteIpAddress, remotePort);
#endif
this->connected = true;
}
void LocalParticipant::Update(unsigned long currentTimeMs) {
if (currentTimeMs == 0) {
currentTimeMs = Thing::GetTimeMs();
// #if defined(ARDUINO)
// currentTimeMs = millis();
// #elif defined(__unix__) || defined(__APPLE__)
// auto now = std::chrono::steady_clock::now();
// auto ms =
// std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
// currentTimeMs = static_cast<unsigned long>(ms.count());
// #endif
}
if (this->isIsolated == false) {
if (this->connected == false)
begin();
if (this->publishInterval > 0 && currentTimeMs > this->nextPublishMe) {
ParticipantMsg* msg = new ParticipantMsg(this->networkId);
if (this->remoteSite == nullptr)
this->Publish(msg);
else
this->Send(this->remoteSite, msg);
delete msg;
this->nextPublishMe = currentTimeMs + this->publishInterval;
}
this->ReceiveUDP();
}
for (Thing* thing : this->things) {
if (thing != nullptr) {
thing->Update(currentTimeMs);
if (this->isIsolated == false) {
PoseMsg* poseMsg = new PoseMsg(this->networkId, thing);
for (Participant* sender : this->senders)
this->Send(sender, poseMsg);
delete poseMsg;
}
}
}
}
void LocalParticipant::ReceiveUDP() {
#if defined(_WIN32) || defined(_WIN64)
Windows::LocalParticipant* thisWindows =
static_cast<Windows::LocalParticipant*>(this);
thisWindows->Receive();
#elif defined(__unix__) || defined(__APPLE__)
Posix::LocalParticipant* thisPosix =
static_cast<Posix::LocalParticipant*>(this);
thisPosix->Receive();
#elif defined(ARDUINO)
Arduino::LocalParticipant* thisArduino =
static_cast<Arduino::LocalParticipant*>(this);
thisArduino->Receive();
#endif
}
Participant* LocalParticipant::GetParticipant(const char* ipAddress, int port) {
for (Participant* sender : this->senders) {
if (strcmp(sender->ipAddress, ipAddress) == 0 && sender->port == port)
return sender;
}
return nullptr;
}
Participant* LocalParticipant::AddParticipant(const char* ipAddress, int port) {
// std::cout << "New Participant " << ipAddress << ":" << port << "\n";
Participant* participant = new Participant(ipAddress, port);
#if defined(NO_STD)
participant->networkId = this->senderCount;
this->senders[this->senderCount++] = participant;
#else
participant->networkId = (unsigned char)this->senders.size();
this->senders.push_back(participant);
#endif
return participant;
}
#pragma region Send
void LocalParticipant::SendThingInfo(Participant* remoteParticipant,
Thing* thing) {
// std::cout << "Send thing info " << (int)thing->id << " \n";
ThingMsg* thingMsg = new ThingMsg(this->networkId, thing);
this->Send(remoteParticipant, thingMsg);
delete thingMsg;
NameMsg* nameMsg = new NameMsg(this->networkId, thing);
this->Send(remoteParticipant, nameMsg);
delete nameMsg;
ModelUrlMsg* modelMsg = new ModelUrlMsg(this->networkId, thing);
this->Send(remoteParticipant, modelMsg);
delete modelMsg;
PoseMsg* poseMsg = new PoseMsg(this->networkId, thing, true);
this->Send(remoteParticipant, poseMsg);
delete poseMsg;
BinaryMsg* customMsg = new BinaryMsg(this->networkId, thing);
this->Send(remoteParticipant, customMsg);
delete customMsg;
}
bool LocalParticipant::Send(Participant* remoteParticipant, IMessage* msg) {
int bufferSize = msg->Serialize(this->buffer);
if (bufferSize <= 0)
return true;
#if defined(_WIN32) || defined(_WIN64)
Windows::LocalParticipant* thisWindows =
static_cast<Windows::LocalParticipant*>(this);
return thisWindows->Send(remoteParticipant, bufferSize);
#elif defined(__unix__) || defined(__APPLE__)
Posix::LocalParticipant* thisPosix =
static_cast<Posix::LocalParticipant*>(this);
return thisPosix->Send(remoteParticipant, bufferSize);
#elif defined(ARDUINO)
Arduino::LocalParticipant* thisArduino =
static_cast<Arduino::LocalParticipant*>(this);
return thisArduino->Send(remoteParticipant, bufferSize);
#endif
}
void LocalParticipant::PublishThingInfo(Thing* thing) {
// std::cout << "Publish thing info" << thing->networkId << "\n";
// Strange, when publishing, the network id is irrelevant, because it is
// connected to a specific site...
ThingMsg* thingMsg = new ThingMsg(this->networkId, thing);
this->Publish(thingMsg);
delete thingMsg;
NameMsg* nameMsg = new NameMsg(this->networkId, thing);
this->Publish(nameMsg);
delete nameMsg;
ModelUrlMsg* modelMsg = new ModelUrlMsg(this->networkId, thing);
this->Publish(modelMsg);
delete modelMsg;
PoseMsg* poseMsg = new PoseMsg(this->networkId, thing, true);
this->Publish(poseMsg);
delete poseMsg;
BinaryMsg* customMsg = new BinaryMsg(this->networkId, thing);
this->Publish(customMsg);
delete customMsg;
}
bool LocalParticipant::Publish(IMessage* msg) {
#if defined(_WIN32) || defined(_WIN64)
Windows::LocalParticipant* thisWindows =
static_cast<Windows::LocalParticipant*>(this);
return thisWindows->Publish(msg);
#elif defined(__unix__) || defined(__APPLE__)
Posix::LocalParticipant* thisPosix =
static_cast<Posix::LocalParticipant*>(this);
return thisPosix->Publish(msg);
#elif defined(ARDUINO)
Arduino::LocalParticipant* thisArduino =
static_cast<Arduino::LocalParticipant*>(this);
return thisArduino->Publish(msg);
#endif
}
// Send
#pragma endregion
#pragma region Receive
void LocalParticipant::ReceiveData(unsigned char packetSize,
char* senderIpAddress,
unsigned int senderPort) {
Participant* remoteParticipant =
this->GetParticipant(senderIpAddress, senderPort);
if (remoteParticipant == nullptr) {
remoteParticipant = this->AddParticipant(senderIpAddress, senderPort);
// std::cout << "New sender " << sender_ipAddress << ":" << sender_port
// << "\n";
// std::cout << "New remote participant " << remoteParticipant->ipAddress
// << ":" << remoteParticipant->port << " "
// << (int)remoteParticipant->networkId << "\n";
}
ReceiveData(packetSize, remoteParticipant);
}
void LocalParticipant::ReceiveData(unsigned char bufferSize,
Participant* remoteParticipant) {
unsigned char msgId = this->buffer[0];
// std::cout << "receive msg " << (int)msgId << "\n";
switch (msgId) {
case ParticipantMsg::id: {
ParticipantMsg* msg = new ParticipantMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
case SiteMsg::id: {
SiteMsg* msg = new SiteMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
case InvestigateMsg::id: {
InvestigateMsg* msg = new InvestigateMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
case ThingMsg::id: {
ThingMsg* msg = new ThingMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
case NameMsg::id: {
NameMsg* msg = new NameMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
case PoseMsg::id: {
PoseMsg* msg = new PoseMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
case BinaryMsg::id: {
BinaryMsg* msg = new BinaryMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
};
}
void LocalParticipant::Process(Participant* sender, ParticipantMsg* msg) {}
void LocalParticipant::Process(Participant* sender, SiteMsg* msg) {
// std::cout << this->name << ": process NetworkId [" << (int)this->networkId
// << "/" << (int)msg->networkId << "]\n";
if (this->networkId != msg->networkId) {
this->networkId = msg->networkId;
// std::cout << this->things.size() << " things\n";
for (Thing* thing : this->things)
this->SendThingInfo(sender, thing);
}
}
void LocalParticipant::Process(Participant* sender, InvestigateMsg* msg) {}
void LocalParticipant::Process(Participant* sender, ThingMsg* msg) {}
void LocalParticipant::Process(Participant* sender, NameMsg* msg) {
Thing* thing = sender->Get(msg->networkId, msg->thingId);
if (thing != nullptr) {
int nameLength = msg->nameLength;
int stringLen = nameLength + 1;
char* thingName = new char[stringLen];
#if defined(_WIN32) || defined(_WIN64)
strncpy_s(thingName, stringLen, msg->name,
stringLen - 1); // Leave space for null terminator
#else
// Use strncpy with bounds checking for other platforms (Arduino, POSIX,
// ESP-IDF)
strncpy(thingName, msg->name,
stringLen - 1); // Leave space for null terminator
thingName[stringLen - 1] = '\0'; // Ensure null termination
#endif
thingName[nameLength] = '\0';
thing->name = thingName;
// std::cout << "thing name = " << thing->name << " length = " << nameLength
// << "\n";
}
}
void LocalParticipant::Process(Participant* sender, PoseMsg* msg) {}
void LocalParticipant::Process(Participant* sender, BinaryMsg* msg) {
// std::cout << this->name << ": process Binary [" << (int)this->networkId <<
// "/"
// << (int)msg->networkId << "]\n";
Thing* thing = sender->Get(msg->networkId, msg->thingId);
if (thing != nullptr)
thing->ProcessBinary(msg->bytes);
else {
thing = this->Get(msg->networkId, msg->thingId);
if (thing != nullptr)
thing->ProcessBinary(msg->bytes);
// else
// std::cout << "custom msg for unknown thing [" << (int)msg->networkId
// << "/" << (int)msg->thingId << "]\n";
}
}
// Receive
#pragma endregion
} // namespace RoboidControl