RoboidControl-cpp/Participant.cpp
2025-02-08 11:30:19 +01:00

283 lines
8.6 KiB
C++

#include "Participant.h"
#include "Thing.h"
#include "UdpArduino.h"
#include "UdpPosix.h"
#include "UdpWindows.h"
#if defined(_WIN32) || defined(_WIN64)
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#elif defined(__unix__) || defined(__APPLE__)
#include <arpa/inet.h>
#include <chrono>
#include <fcntl.h> // For fcntl
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
namespace Passer {
namespace Control {
Participant::Participant() {}
Participant::Participant(int port) {
this->ipAddress = "0.0.0.0";
this->port = port;
this->senders.push_back(this);
// int randomPort = (rand() % (65535 - 49152 + 1)) + 49152;
this->localPort = port;
// SetupUDP(randomPort, ipAddress, port);
}
Participant::Participant(const char *ipAddress, int port) {
this->ipAddress = ipAddress;
this->port = port;
this->senders.push_back(this);
// int randomPort = (rand() % (65535 - 49152 + 1)) + 49152;
this->localPort = port; // randomPort;
// SetupUDP(randomPort, ipAddress, port);
}
void Participant::begin() {
SetupUDP(this->localPort, this->ipAddress, this->port);
}
void Participant::SetupUDP(int localPort, const char *remoteIpAddress,
int remotePort) {
#if defined(_WIN32) || defined(_WIN64)
UdpWindows *thisWindows = static_cast<UdpWindows *>(this);
thisWindows->Setup(localPort, remoteIpAddress, remotePort);
#elif defined(__unix__) || defined(__APPLE__)
UdpPosix *thisPosix = static_cast<UdpPosix *>(this);
thisPosix->Setup(localPort, remoteIpAddress, remotePort);
#elif defined(ARDUINO)
UdpArduino *thisArduino = static_cast<UdpArduino *>(this);
thisArduino->Setup(localPort, remoteIpAddress, remotePort);
#endif
this->connected = true;
}
void Participant::Update(unsigned long currentTimeMs) {
if (currentTimeMs == 0) {
#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->connected == false)
begin();
if (this->publishInterval > 0 && currentTimeMs > this->nextPublishMe) {
ClientMsg *msg = new ClientMsg(this->networkId);
this->Publish(msg);
delete msg;
std::cout << this->name << " published ClientMsg\n";
this->nextPublishMe = currentTimeMs + this->publishInterval;
}
this->ReceiveUDP();
this->UpdateAll(currentTimeMs);
}
void Participant::ReceiveUDP() {
#if defined(_WIN32) || defined(_WIN64)
UdpWindows *thisWindows = static_cast<UdpWindows *>(this);
thisWindows->Receive();
#elif defined(__unix__) || defined(__APPLE__)
UdpPosix *thisPosix = static_cast<UdpPosix *>(this);
thisPosix->Receive();
#elif defined(ARDUINO)
UdpArduino *thisArduino = static_cast<UdpArduino *>(this);
thisArduino->Receive();
#endif
}
Participant *Participant::GetParticipant(const char *ipAddress, int port) {
for (Participant *sender : this->senders) {
if (sender->ipAddress == ipAddress && sender->port == port)
return sender;
}
return nullptr;
}
Participant *Participant::AddParticipant(const char *ipAddress, int port) {
std::cout << "New Participant " << ipAddress << ":" << port << "\n";
Participant *participant = new Participant(ipAddress, port);
participant->networkId = (unsigned char)this->senders.size();
this->senders.push_back(participant);
return participant;
}
#pragma region Send
void Participant::SendThingInfo(RemoteParticipant *remoteParticipant,
Thing *thing) {
std::cout << "Send thing info\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;
}
void Passer::Control::Participant::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;
CustomMsg *customMsg = new CustomMsg(this->networkId, thing);
this->Publish(customMsg);
delete customMsg;
}
bool Participant::Send(RemoteParticipant *remoteParticipant, IMessage *msg) {
int bufferSize = msg->Serialize(this->buffer);
if (bufferSize <= 0)
return true;
#if defined(_WIN32) || defined(_WIN64)
UdpWindows *thisWindows = static_cast<UdpWindows *>(this);
return thisWindows->Send(remoteParticipant, bufferSize);
#elif defined(__unix__) || defined(__APPLE__)
UdpPosix *thisPosix = static_cast<UdpPosix *>(this);
return thisPosix->Send(remoteParticipant, bufferSize);
#elif defined(ARDUINO)
UdpArduino *thisArduino = static_cast<UdpArduino *>(this);
return thisArduino->Send(remoteParticipant, bufferSize);
#endif
}
bool Participant::Publish(IMessage *msg) {
#if defined(_WIN32) || defined(_WIN64)
UdpWindows *thisWindows = static_cast<UdpWindows *>(this);
return thisWindows->Publish(msg);
#elif defined(__unix__) || defined(__APPLE__)
UdpPosix *thisPosix = static_cast<UdpPosix *>(this);
return thisPosix->Publish(msg);
#elif defined(ARDUINO)
UdpArduino *thisArduino = static_cast<UdpArduino *>(this);
return thisArduino->Publish(msg);
#endif
}
// Send
#pragma endregion
#pragma region Receive
void Participant::ReceiveData(unsigned char bufferSize,
RemoteParticipant *remoteParticipant) {
unsigned char msgId = this->buffer[0];
// std::cout << "receive msg " << (int)msgId << "\n";
switch (msgId) {
case ClientMsg::id: {
ClientMsg *msg = new ClientMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
case NetworkIdMsg::id: {
NetworkIdMsg *msg = new NetworkIdMsg(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 CustomMsg::id: {
CustomMsg *msg = new CustomMsg(this->buffer);
Process(remoteParticipant, msg);
delete msg;
} break;
};
}
void Participant::Process(RemoteParticipant *sender, ClientMsg *msg) {}
void Participant::Process(RemoteParticipant *sender, NetworkIdMsg *msg) {
std::cout << this->name << ": process NetworkId [" << (int)this->networkId
<< "/" << (int)msg->networkId << "]\n";
if (this->networkId != msg->networkId) {
this->networkId = msg->networkId;
for (Thing *thing : this->things)
this->SendThingInfo(sender, thing);
}
}
void Participant::Process(RemoteParticipant *sender, InvestigateMsg *msg) {}
void Participant::Process(RemoteParticipant *sender, ThingMsg *msg) {}
void Participant::Process(RemoteParticipant *sender, NameMsg *msg) {
Thing *thing = sender->Get(msg->networkId, msg->thingId);
if (thing != nullptr) {
int nameLength = msg->nameLength;
char *thingName = new char[nameLength + 1];
strcpy(thingName, msg->name);
thingName[nameLength] = '\0';
thing->name = thingName;
std::cout << "thing name = " << thing->name << " length = " << nameLength
<< "\n";
}
}
void Participant::Process(RemoteParticipant *sender, PoseMsg *msg) {}
void Participant::Process(RemoteParticipant *sender, CustomMsg *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->ProcessBytes(msg->bytes);
else
std::cout << "custom msg for unknown thing " << (int)msg->networkId << ":"
<< (int)msg->thingId << "\n";
}
// Receive
#pragma endregion
} // namespace Control
} // namespace Passer