mirror of
https://github.com/meshtastic/firmware.git
synced 2025-02-26 22:33:24 +00:00
Hello world support for UDP broadcasts over the LAN on ESP32 (#5779)
* UDP local area network meshing on ESP32 * Logs * Comment * Update UdpMulticastThread.h * Changes * Only use router->send
This commit is contained in:
parent
7e063c1dda
commit
d440dbd522
@ -37,6 +37,7 @@ build_flags =
|
|||||||
-DLIBPAX_ARDUINO
|
-DLIBPAX_ARDUINO
|
||||||
-DLIBPAX_WIFI
|
-DLIBPAX_WIFI
|
||||||
-DLIBPAX_BLE
|
-DLIBPAX_BLE
|
||||||
|
-DHAS_UDP_MULTICAST=1
|
||||||
;-DDEBUG_HEAP
|
;-DDEBUG_HEAP
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
10
src/main.cpp
10
src/main.cpp
@ -114,6 +114,11 @@ AccelerometerThread *accelerometerThread = nullptr;
|
|||||||
AudioThread *audioThread = nullptr;
|
AudioThread *audioThread = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_UDP_MULTICAST
|
||||||
|
#include "mesh/udp/UdpMulticastThread.h"
|
||||||
|
UdpMulticastThread *udpThread = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(TCXO_OPTIONAL)
|
#if defined(TCXO_OPTIONAL)
|
||||||
float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if TCXO is optional, put this here so it can be changed further down.
|
float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if TCXO is optional, put this here so it can be changed further down.
|
||||||
#endif
|
#endif
|
||||||
@ -783,6 +788,11 @@ void setup()
|
|||||||
LOG_DEBUG("Start audio thread");
|
LOG_DEBUG("Start audio thread");
|
||||||
audioThread = new AudioThread();
|
audioThread = new AudioThread();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_UDP_MULTICAST
|
||||||
|
LOG_DEBUG("Start multicast thread");
|
||||||
|
udpThread = new UdpMulticastThread();
|
||||||
|
#endif
|
||||||
service = new MeshService();
|
service = new MeshService();
|
||||||
service->init();
|
service->init();
|
||||||
|
|
||||||
|
@ -49,6 +49,11 @@ extern Adafruit_DRV2605 drv;
|
|||||||
extern AudioThread *audioThread;
|
extern AudioThread *audioThread;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_UDP_MULTICAST
|
||||||
|
#include "mesh/udp/UdpMulticastThread.h"
|
||||||
|
extern UdpMulticastThread *udpThread;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Global Screen singleton.
|
// Global Screen singleton.
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
|
|
||||||
|
@ -299,6 +299,9 @@ NodeDB::NodeDB()
|
|||||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||||
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
|
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
|
||||||
|
|
||||||
|
// Uncomment below to always enable UDP broadcasts
|
||||||
|
// config.network.enabled_protocols = meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST;
|
||||||
|
|
||||||
// If we are setup to broadcast on the default channel, ensure that the telemetry intervals are coerced to the minimum value
|
// If we are setup to broadcast on the default channel, ensure that the telemetry intervals are coerced to the minimum value
|
||||||
// of 30 minutes or more
|
// of 30 minutes or more
|
||||||
if (channels.isDefaultChannel(channels.getPrimaryIndex())) {
|
if (channels.isDefaultChannel(channels.getPrimaryIndex())) {
|
||||||
|
@ -274,6 +274,11 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
|||||||
abortSendAndNak(encodeResult, p);
|
abortSendAndNak(encodeResult, p);
|
||||||
return encodeResult; // FIXME - this isn't a valid ErrorCode
|
return encodeResult; // FIXME - this isn't a valid ErrorCode
|
||||||
}
|
}
|
||||||
|
#if HAS_UDP_MULTICAST
|
||||||
|
if (udpThread && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
|
||||||
|
udpThread->onSend(const_cast<meshtastic_MeshPacket *>(p));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||||
// Only publish to MQTT if we're the original transmitter of the packet
|
// Only publish to MQTT if we're the original transmitter of the packet
|
||||||
if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
|
if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
|
||||||
|
70
src/mesh/udp/UdpMulticastThread.h
Normal file
70
src/mesh/udp/UdpMulticastThread.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
#if HAS_UDP_MULTICAST
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "mesh/Router.h"
|
||||||
|
|
||||||
|
#include <AsyncUDP.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#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)) {
|
||||||
|
LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str());
|
||||||
|
udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); });
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Failed to listen on UDP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onReceive(AsyncUDPPacket packet)
|
||||||
|
{
|
||||||
|
size_t packetLength = packet.length();
|
||||||
|
LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength);
|
||||||
|
meshtastic_MeshPacket mp;
|
||||||
|
uint8_t bytes[meshtastic_MeshPacket_size]; // Allocate buffer for the data
|
||||||
|
size_t packetSize = packet.readBytes(bytes, packet.length());
|
||||||
|
LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetSize);
|
||||||
|
bool isPacketDecoded = pb_decode_from_bytes(bytes, 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 || WiFi.status() != WL_CONNECTED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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.broadcastTo(buffer, encodedLength, 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 // ARCH_ESP32
|
@ -112,6 +112,12 @@ static void onNetworkConnected()
|
|||||||
APStartupComplete = true;
|
APStartupComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAS_UDP_MULTICAST
|
||||||
|
if (udpThread) {
|
||||||
|
udpThread->start();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
||||||
#ifndef MESHTASTIC_EXCLUDE_MQTT
|
#ifndef MESHTASTIC_EXCLUDE_MQTT
|
||||||
if (mqtt)
|
if (mqtt)
|
||||||
|
Loading…
Reference in New Issue
Block a user