livoxProto1: udpCmdDemux now consults per-device handler registry

Device class objects now have a per-Device unordered_map of handlers
keyed by cmd_set+cmd_id.
This commit is contained in:
2025-10-22 07:28:00 -04:00
parent 10afec2532
commit 8e1d609ca1
3 changed files with 64 additions and 29 deletions
+3 -1
View File
@@ -257,6 +257,7 @@ void main(const std::shared_ptr<smo::ComponentThread> &componentThread,
protoState.smoCallbacks = smoCallbacks; protoState.smoCallbacks = smoCallbacks;
protoState.deviceManager = std::make_unique<DeviceManager>(); protoState.deviceManager = std::make_unique<DeviceManager>();
protoState.deviceManager->broadcastListener.start(); protoState.deviceManager->broadcastListener.start();
protoState.deviceManager->udpCommandDemuxer.start();
} }
void exit(void) void exit(void)
@@ -265,10 +266,11 @@ void exit(void)
return; return;
} }
protoState.deviceManager->udpCommandDemuxer.stop();
protoState.deviceManager->broadcastListener.stop(); protoState.deviceManager->broadcastListener.stop();
protoState.deviceManager.reset(); protoState.deviceManager.reset();
protoState.componentThread.reset(); protoState.componentThread.reset();
protoState.isInitialized = false; protoState.isInitialized = false;
} }
} // namespace livoxProto1 } // namespace livoxProto1
+35 -28
View File
@@ -1743,11 +1743,11 @@ void Device::cleanupPcloudDataSocket()
pcloudDataActive.store(false); pcloudDataActive.store(false);
} }
void Device::handleUdpDgram(const uint8_t *data, ssize_t bytesReceived, void Device::handleUdpDgram(
const struct sockaddr_in &senderAddr) const uint8_t *data, ssize_t bytesReceived,
const struct sockaddr_in &senderAddr
)
{ {
(void)senderAddr;
// Check minimum size for any valid protocol message // Check minimum size for any valid protocol message
if (bytesReceived < static_cast<ssize_t>( if (bytesReceived < static_cast<ssize_t>(
sizeof(comms::Header) + sizeof(comms::Command))) sizeof(comms::Header) + sizeof(comms::Command)))
@@ -1760,37 +1760,44 @@ void Device::handleUdpDgram(const uint8_t *data, ssize_t bytesReceived,
uint8_t cmd_set = data[sizeof(comms::Header)]; uint8_t cmd_set = data[sizeof(comms::Header)];
uint8_t cmd_id = data[sizeof(comms::Header) + 1]; uint8_t cmd_id = data[sizeof(comms::Header) + 1];
// Route based on command type // Look for a registered handler for this command
if (cmd_set == 0x00 && cmd_id == 0x01) auto key = std::make_pair(cmd_set, cmd_id);
auto it = udpCommandHandlers.find(key);
if (it != udpCommandHandlers.end())
{ {
// Handshake ACK - check if we have enough data for HandshakeResponse // Found a registered handler, invoke it
if (bytesReceived >= static_cast<ssize_t>( try
sizeof(comms::HandshakeResponse)))
{ {
std::cout << __func__ << ": Received handshake ACK from " it->second(data, bytesReceived, senderAddr);
<< discoveredDevice.deviceIdentifier << std::endl;
} }
} catch (const std::exception& e)
else if (cmd_set == 0x00 && cmd_id == 0x03)
{
// Heartbeat ACK - check if we have enough data for HeartbeatMessage
if (bytesReceived >= static_cast<ssize_t>(
sizeof(comms::HeartbeatMessage)))
{ {
// Empty intentionally. std::cerr << __func__ << ": Exception in command handler for "
} << discoveredDevice.deviceIdentifier
} << " cmd_set=" << (int)cmd_set
else if (cmd_set == 0x00 && cmd_id == 0x04) << " cmd_id=" << (int)cmd_id
{ << ": " << e.what() << std::endl;
// Sampling response - check if we have enough data for SamplingResponse
if (bytesReceived >= static_cast<ssize_t>(
sizeof(comms::SamplingResponse)))
{
std::cout << __func__ << ": Received sampling response from "
<< discoveredDevice.deviceIdentifier << std::endl;
} }
} }
// Unknown command types are silently ignored // Unknown command types are silently ignored
} }
void Device::registerUdpCommandHandler(
uint8_t cmd_set, uint8_t cmd_id,
std::function<void(
const uint8_t* data, ssize_t bytesReceived,
const struct sockaddr_in& senderAddr)> handler
)
{
auto key = std::make_pair(cmd_set, cmd_id);
udpCommandHandlers[key] = std::move(handler);
}
void Device::unregisterUdpCommandHandler(uint8_t cmd_set, uint8_t cmd_id)
{
auto key = std::make_pair(cmd_set, cmd_id);
udpCommandHandlers.erase(key);
}
} // namespace livoxProto1 } // namespace livoxProto1
+26
View File
@@ -7,6 +7,7 @@
#include <atomic> #include <atomic>
#include <optional> #include <optional>
#include <functional> #include <functional>
#include <unordered_map>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@@ -16,6 +17,16 @@
#include "protocol.h" #include "protocol.h"
#include <callback.h> #include <callback.h>
// Custom hash function for std::pair<uint8_t, uint8_t>
namespace std {
template<>
struct hash<std::pair<uint8_t, uint8_t>> {
size_t operator()(const std::pair<uint8_t, uint8_t>& p) const noexcept {
return (static_cast<size_t>(p.first) << 8) | static_cast<size_t>(p.second);
}
};
}
// Forward declaration // Forward declaration
namespace smo { namespace smo {
class ComponentThread; class ComponentThread;
@@ -146,10 +157,25 @@ public:
const uint8_t* data, ssize_t bytesReceived, const uint8_t* data, ssize_t bytesReceived,
const struct sockaddr_in& senderAddr); const struct sockaddr_in& senderAddr);
// Command handler registration
void registerUdpCommandHandler(
uint8_t cmd_set, uint8_t cmd_id,
std::function<void(
const uint8_t* data, ssize_t bytesReceived,
const struct sockaddr_in& senderAddr)> handler);
void unregisterUdpCommandHandler(uint8_t cmd_set, uint8_t cmd_id);
private: private:
// Point cloud data setup // Point cloud data setup
bool setupPcloudDataSocket(); bool setupPcloudDataSocket();
void cleanupPcloudDataSocket(); void cleanupPcloudDataSocket();
// Command handler map
std::unordered_map<
std::pair<uint8_t, uint8_t>,
std::function<void(
const uint8_t* data, ssize_t bytesReceived,
const struct sockaddr_in& senderAddr)>> udpCommandHandlers;
}; };
} // namespace livoxProto1 } // namespace livoxProto1