#pragma once #if HAS_UDP_MULTICAST #include "configuration.h" #include "main.h" #include "mesh/Router.h" #include #include #if HAS_ETHERNET && defined(USE_WS5500) #include #define ETH ETH2 #endif // HAS_ETHERNET #define UDP_MULTICAST_DEFAUL_PORT 4403 // Default port for UDP multicast is same as TCP api server #define UDP_MULTICAST_THREAD_INTERVAL_MS 15000 class UdpMulticastThread : public concurrency::OSThread { public: UdpMulticastThread() : OSThread("UdpMulticast") { udpIpAddress = IPAddress(224, 0, 0, 69); } void start() { if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT, 64)) { #if !defined(ARCH_PORTDUINO) // FIXME(PORTDUINO): arduino lacks IPAddress::toString() LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str()); #else LOG_DEBUG("UDP Listening"); #endif udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); }); } else { LOG_DEBUG("Failed to listen on UDP"); } } void onReceive(AsyncUDPPacket packet) { size_t packetLength = packet.length(); #ifndef ARCH_PORTDUINO // FIXME(PORTDUINO): arduino lacks IPAddress::toString() LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength); #endif meshtastic_MeshPacket mp; LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength); bool isPacketDecoded = pb_decode_from_bytes(packet.data(), packetLength, &meshtastic_MeshPacket_msg, &mp); if (isPacketDecoded && router) { UniquePacketPoolPacket p = packetPool.allocUniqueCopy(mp); // Unset received SNR/RSSI p->rx_snr = 0; p->rx_rssi = 0; router->enqueueReceivedMessage(p.release()); } } bool onSend(const meshtastic_MeshPacket *mp) { if (!mp || !udp) { return false; } #if !defined(ARCH_PORTDUINO) if (WiFi.status() != WL_CONNECTED) { return false; } #endif LOG_DEBUG("Broadcasting packet over UDP (id=%u)", mp->id); uint8_t buffer[meshtastic_MeshPacket_size]; size_t encodedLength = pb_encode_to_bytes(buffer, sizeof(buffer), &meshtastic_MeshPacket_msg, mp); udp.writeTo(buffer, encodedLength, udpIpAddress, UDP_MULTICAST_DEFAUL_PORT); return true; } protected: int32_t runOnce() override { canSleep = true; // TODO: Implement nodeinfo broadcast return UDP_MULTICAST_THREAD_INTERVAL_MS; } private: IPAddress udpIpAddress; AsyncUDP udp; }; #endif // HAS_UDP_MULTICAST