Fix nRF52 AsyncUDP multicast TX/RX race condition causing garbled packets (#9765)
socketSendUDP() calls yield() while waiting for SEND_OK, allowing the cooperative scheduler to run AsyncUDP::runOnce(). When runOnce() calls parsePacket() on the same socket during an active send, the multicast loopback packet arriving from the switch produces a garbled 8-byte RX header (wrong source IP, wrong payload length), leading to protobuf decode errors in UdpMulticastHandler. Add a volatile isSending flag that writeTo() sets around endPacket() (the only yield point). runOnce() checks this flag and skips parsePacket() while a send is in progress. Loopback packets stay buffered in the W5100S RX buffer and are read cleanly on the next poll cycle. Also propagate writeTo() return value in UdpMulticastHandler::onSend() instead of unconditionally returning true. Made-with: Cursor Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
co-authored by
GitHub
Ben Meadors
parent
5b1ea922f3
commit
86dad90573
@@ -105,8 +105,7 @@ class UdpMulticastHandler final
|
||||
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;
|
||||
return udp.writeTo(buffer, encodedLength, udpIpAddress, UDP_MULTICAST_DEFAUL_PORT);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -33,7 +33,10 @@ bool AsyncUDP::writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t p
|
||||
if (!udp.beginPacket(ip, port))
|
||||
return false;
|
||||
udp.write(data, len);
|
||||
return udp.endPacket();
|
||||
isSending = true;
|
||||
bool ok = udp.endPacket();
|
||||
isSending = false;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void AsyncUDP::close()
|
||||
@@ -70,7 +73,7 @@ const uint8_t *AsyncUDPPacket::data()
|
||||
|
||||
int32_t AsyncUDP::runOnce()
|
||||
{
|
||||
if (_onPacket && udp.parsePacket() > 0) {
|
||||
if (_onPacket && !isSending && udp.parsePacket() > 0) {
|
||||
AsyncUDPPacket packet(udp);
|
||||
_onPacket(packet);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class AsyncUDP : public Print, private concurrency::OSThread
|
||||
private:
|
||||
EthernetUDP udp;
|
||||
uint16_t localPort;
|
||||
volatile bool isSending = false;
|
||||
std::function<void(AsyncUDPPacket)> _onPacket;
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user