#include "ParticipantUDP.h" #include "Participant.h" #include "Thing.h" #include "Arduino/ArduinoParticipant.h" #include "EspIdf/EspIdfParticipant.h" #include "Posix/PosixParticipant.h" #include "Windows/WindowsParticipant.h" #include "Things/DifferentialDrive.h" #include "Things/DistanceSensor.h" #include "Things/TouchSensor.h" // #include namespace RoboidControl { bool ParticipantSocket::Send(IMessage* msg) { // No message is actually sent, because this class has no networking // implementation return false; } #pragma region Init ParticipantUDPGeneric::ParticipantUDPGeneric(int port) : ParticipantSocket("127.0.0.1", port) { this->name = "ParticipantUDP"; this->remoteSite = nullptr; if (this->port == 0) this->isIsolated = true; registry.Add(this); this->root = Thing::LocalRoot(); //::LocalParticipant->root; this->root->owner = this; this->root->name = "UDP Root"; std::cout << "P2 " << (long)this->root << std::endl; this->Add(this->root); Participant::ReplaceLocalParticipant(*this); } ParticipantUDPGeneric::ParticipantUDPGeneric(const char* ipAddress, int port, int localPort) : ParticipantSocket("127.0.0.1", localPort) { this->name = "ParticipantUDP"; if (this->port == 0) this->isIsolated = true; else this->remoteSite = new ParticipantSocket(ipAddress, port); registry.Add(this); this->root = Thing::LocalRoot(); // Participant::LocalParticipant->root; this->root->owner = this; this->root->name = "UDP Root"; std::cout << "P1 " << (long)this->root << std::endl; this->Add(this->root); Participant::ReplaceLocalParticipant(*this); } void ParticipantUDPGeneric::begin() { if (this->isIsolated || this->remoteSite == nullptr) return; SetupUDP(this->port, this->remoteSite->ipAddress, this->remoteSite->port); } #pragma endregion Init #pragma region Update // The update order // 1. receive external messages // 2. update the state // 3. send out the updated messages void ParticipantUDPGeneric::Update(bool recurse) { unsigned long currentTimeMs = Thing::GetTimeMs(); 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(msg); delete msg; this->nextPublishMe = currentTimeMs + this->publishInterval; } this->ReceiveUDP(); } UpdateMyThings(); UpdateOtherThings(); } void ParticipantUDPGeneric::UpdateMyThings() { for (Thing* thing : this->things) { if (thing == nullptr) // || thing->GetParent() != nullptr) continue; // Why don't we do recursive? // Because when a thing creates a thing in the update, // that new thing is not sent out (because of hierarchyChanged) // before it is updated itself: it is immediatedly updated! thing->Update(false); if (thing->terminate) this->Remove(thing); } } void ParticipantUDPGeneric::UpdateOtherThings() { #if defined(NO_STD) Participant** participants = Participant::registry.GetAll(); for (int ix = 0; ix < Participant::registry.count; ix++) { Participant* participant = participants[ix]; #else for (Participant* participant : registry.GetAll()) { #endif if (participant == nullptr || participant == this) continue; // Call only the Participant version of the Update. // This is to deal with the function where one of the (remote) // participants is actually a local participant participant->Participant::Update(); if (this->isIsolated) continue; for (Thing* thing : participant->things) { PoseMsg* poseMsg = new PoseMsg(participant->networkId, thing); participant->Send(poseMsg); delete poseMsg; BinaryMsg* binaryMsg = new BinaryMsg(participant->networkId, thing); participant->Send(binaryMsg); delete binaryMsg; } } } // Update #pragma endregion #pragma region Send void ParticipantUDPGeneric::SendThingInfo(Participant* remoteParticipant, Thing* thing) { // std::cout << "Send thing info [" << (int)thing->id << "] \n"; ThingMsg* thingMsg = new ThingMsg(this->networkId, thing); remoteParticipant->Send(thingMsg); delete thingMsg; NameMsg* nameMsg = new NameMsg(this->networkId, thing); remoteParticipant->Send(nameMsg); delete nameMsg; ModelUrlMsg* modelMsg = new ModelUrlMsg(this->networkId, thing); remoteParticipant->Send(modelMsg); delete modelMsg; PoseMsg* poseMsg = new PoseMsg(this->networkId, thing, true); remoteParticipant->Send(poseMsg); delete poseMsg; BinaryMsg* binaryMsg = new BinaryMsg(this->networkId, thing); remoteParticipant->Send(binaryMsg); delete binaryMsg; } bool ParticipantUDPGeneric::Send(IMessage* msg) { if (this->remoteSite != nullptr) return this->remoteSite->Send(msg); return true; } void ParticipantUDPGeneric::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; } // Send #pragma endregion #pragma region Receive void ParticipantUDPGeneric::ReceiveData(unsigned char packetSize, char* senderIpAddress, unsigned int senderPort) { // std::cout << "Receive data from " << senderIpAddress << ":" << senderPort // << std::endl; ParticipantSocket* sender = this->registry.Get(senderIpAddress, senderPort); if (sender == nullptr) { sender = this->registry.Add(senderIpAddress, senderPort); #if !defined(NO_STD) // std::cout << "New remote participant " << sender->ipAddress << ":" // << sender->port << std::endl; #endif } ReceiveData(packetSize, sender); } void ParticipantUDPGeneric::ReceiveData(unsigned char bufferSize, ParticipantSocket* sender) { unsigned char msgId = this->buffer[0]; // std::cout << "receive msg " << (int)msgId << "\n"; // std::cout << " buffer size = " <<(int) bufferSize << "\n"; switch (msgId) { case ParticipantMsg::id: { ParticipantMsg* msg = new ParticipantMsg(this->buffer); bufferSize -= msg->length; Process(sender, msg); delete msg; } break; case NetworkIdMsg::id: { NetworkIdMsg* msg = new NetworkIdMsg(this->buffer); bufferSize -= msg->length; Process(sender, msg); delete msg; } break; case InvestigateMsg::id: { InvestigateMsg* msg = new InvestigateMsg(this->buffer); Process(sender, msg); delete msg; } break; case ThingMsg::id: { ThingMsg* msg = new ThingMsg(this->buffer); bufferSize -= msg->length; Process(sender, msg); delete msg; } break; case NameMsg::id: { NameMsg* msg = new NameMsg(this->buffer); bufferSize -= msg->length + msg->nameLength; Process(sender, msg); delete msg; } break; case ModelUrlMsg::id: { ModelUrlMsg* msg = new ModelUrlMsg(this->buffer); bufferSize -= msg->length + msg->urlLength; Process(sender, msg); delete msg; } break; case PoseMsg::id: { PoseMsg* msg = new PoseMsg(this->buffer); bufferSize -= msg->length; Process(sender, msg); delete msg; } break; case BinaryMsg::id: { BinaryMsg* msg = new BinaryMsg(this->buffer); bufferSize -= msg->length + msg->dataLength; Process(sender, msg); delete msg; } break; case TextMsg::id: { TextMsg* msg = new TextMsg(this->buffer); bufferSize -= msg->length + msg->textLength; Process(sender, msg); delete msg; } break; case DestroyMsg::id: { DestroyMsg* msg = new DestroyMsg(this->buffer); bufferSize -= msg->length; Process(sender, msg); delete msg; } break; }; // Check if the buffer has been read completely #if !defined(NO_STD) if (bufferSize > 0) std::cout << "Buffer not fully read, remaining " << (int)bufferSize << "\n"; #endif } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, ParticipantMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": Process ParticipantMsg " << (int)msg->networkId << "\n"; #endif } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, NetworkIdMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": process NetworkIdMsg " << (int)this->networkId << " -> " << (int)msg->networkId << "\n"; #endif 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 ParticipantUDPGeneric::Process(ParticipantSocket* sender, InvestigateMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": Process InvestigateMsg [" << (int)msg->networkId << "/" << (int)msg->thingId << "]\n"; #endif } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, ThingMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": process ThingMsg [" << (int)msg->networkId << "/" << (int)msg->thingId << "] " << (int)msg->thingType << " " << (int)msg->parentId << "\n"; #endif ParticipantSocket* owner = registry.Get(msg->networkId); if (owner == nullptr) { owner = new ParticipantSocket(sender->ipAddress, sender->port); owner->networkId = msg->networkId; registry.Add(owner); } Thing* thing = owner->Get(msg->networkId, msg->thingId); if (thing == nullptr) { bool isRemote = (sender->networkId != owner->networkId); thing = ProcessNewThing(owner, msg, isRemote); thing->id = msg->thingId; thing->type = msg->thingType; thing->isRemote = isRemote; } if (msg->parentId != 0) { thing->SetParent(owner->Get(msg->networkId, msg->parentId)); if (thing->GetParent() == nullptr) std::cout << "Could not find parent" << std::endl; } else thing->SetParent(nullptr); } Thing* ParticipantUDPGeneric::ProcessNewThing(ParticipantSocket* owner, ThingMsg* msg, bool isRemote) { switch (msg->thingType) { case Thing::Type::DistanceSensor: return new DistanceSensor(owner->root); case Thing::Type::TouchSensor: return new TouchSensor(owner->root); case Thing::Type::DifferentialDrive: return new DifferentialDrive(owner->root); default: return new Thing(owner->root); } } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, NameMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": process NameMsg [" << (int)msg->networkId << "/" << (int)msg->thingId << "] "; #endif 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, nameLength); // Leave space for null terminator #endif thingName[nameLength] = '\0'; thing->SetName(thingName); #if !defined(NO_STD) std::cout << thing->GetName(); #endif } #if !defined(NO_STD) std::cout << std::endl; #endif } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, ModelUrlMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": process ModelUrlMsg [" << (int)msg->networkId << "/" << (int)msg->thingId << "]\n"; #endif } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, PoseMsg* msg) { #if !defined(DEBUG) && !defined(NO_STD) std::cout << this->name << ": process PoseMsg [" << (int)this->networkId << "/" << (int)msg->networkId << "] " << (int)msg->poseType << "\n"; #endif Participant* owner = registry.Get(msg->networkId); if (owner == nullptr) return; Thing* thing = owner->Get(msg->networkId, msg->thingId); if (thing == nullptr) return; if ((msg->poseType & PoseMsg::Pose_Position) != 0) thing->SetPosition(msg->position); if ((msg->poseType & PoseMsg::Pose_Orientation) != 0) thing->SetOrientation(msg->orientation); if ((msg->poseType & PoseMsg::Pose_LinearVelocity) != 0) thing->SetLinearVelocity(msg->linearVelocity); if ((msg->poseType & PoseMsg::Pose_AngularVelocity) != 0) thing->SetAngularVelocity(msg->angularVelocity); } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, BinaryMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": process BinaryMsg [" << (int)msg->networkId << "/" << (int)msg->thingId << "]\n"; #endif Participant* owner = registry.Get(msg->networkId); if (owner != nullptr) { Thing* thing = owner->Get(msg->networkId, msg->thingId); if (thing != nullptr) thing->ProcessBinary(msg->data); #if !defined(NO_STD) else { #if defined(DEBUG) std::cout << " unknown thing [" << (int)msg->networkId << "/" << (int)msg->thingId << "]"; #endif } #endif } } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, TextMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": process TextMsg " << (int)msg->textLength << " " << (int)msg->text << "\n"; #endif } void ParticipantUDPGeneric::Process(ParticipantSocket* sender, DestroyMsg* msg) { #if defined(DEBUG) std::cout << this->name << ": process Destroy [" << (int)msg->networkId << "/" << (int)msg->thingId << "]\n"; #endif Thing* thing = sender->Get(msg->networkId, msg->thingId); if (thing != nullptr) this->Remove(thing); } // Receive #pragma endregion #pragma region Registry ParticipantUDP::Registry ParticipantUDPGeneric::registry; ParticipantSocket* ParticipantUDP::Registry::Get(const char* ipAddress, unsigned int port) { #if !defined(NO_STD) for (ParticipantSocket* participant : Registry::participants) { if (participant == nullptr) continue; if (strcmp(participant->ipAddress, ipAddress) == 0 && participant->port == port) { // std::cout << "found participant " << participant->ipAddress << ":" // << (int)participant->port << std::endl; return participant; } } std::cout << "Could not find participant " << ipAddress << ":" << (int)port << std::endl; #endif return nullptr; } ParticipantSocket* ParticipantUDP::Registry::Get(unsigned char participantId) { #if !defined(NO_STD) for (ParticipantSocket* participant : Registry::participants) { if (participant == nullptr) continue; if (participant->networkId == participantId) return participant; } std::cout << "Could not find participant " << (int)participantId << std::endl; #endif return nullptr; } ParticipantSocket* ParticipantUDP::Registry::Add(const char* ipAddress, unsigned int port) { ParticipantSocket* participant = new ParticipantSocket(ipAddress, port); Add(participant); return participant; } void ParticipantUDP::Registry::Add(ParticipantSocket* participant) { Participant* foundParticipant = Get(participant->networkId); // Get(participant->ipAddress, participant->port); if (foundParticipant == nullptr) { #if defined(NO_STD) // this->things[this->thingCount++] = thing; #else Registry::participants.push_back(participant); #endif // std::cout << "Add participant " << participant->ipAddress << ":" // << participant->port << "[" << (int)participant->networkId // << "]\n"; // std::cout << "participants " << // Registry::participants.size() // << "\n"; // } else { // std::cout << "Did not add, existing participant " << // participant->ipAddress // << ":" << participant->port << "[" << // (int)participant->networkId // << "]\n"; } } void ParticipantUDP::Registry::Remove(ParticipantSocket* participant) { // participants.remove(participant); } #if defined(NO_STD) RemoteParticipantUDP** Registry::GetAll() const { return Registry::participants; } #else const std::list& ParticipantUDP::Registry::GetAll() const { return Registry::participants; } #endif // Registry #pragma endregion Registry } // namespace RoboidControl