Count and surface RX-queue drops on the ESP32-C5's promiscuous path

wifi_promisc_rx_cb() fed s_rx_queue with a 0-timeout xQueueSend() and never
checked whether it succeeded, so a burst of captured frames arriving faster
than rx_forward_task could drain them vanished with no counter anywhere -
none of oversizeDrops/txFailures/rxCrcErrors caught it. Added a rxQueueDrops
counter, threaded it through the STATUS heartbeat as a new trailing uint16
(old firmware/app on either side still parse fine), and surfaced it on the
CAM Pinger card.

Confirmed on the bench: flashed to the production OBU (COM3) and installed
the matching app build on the phone, then watched the counter over logcat
against obu-cam-transmistter's ~3.3 Hz beacon - it is real (0 -> 89 -> 90
across two sessions) but bursty around connect/reconnect rather than a
continuous overflow under steady single-station traffic.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Ashin Walpola
2026-09-22 14:41:53 +02:00
co-authored by Claude Sonnet 5
parent 21e01499d8
commit 71dde3364d
9 changed files with 209 additions and 15 deletions
+14 -2
View File
@@ -52,11 +52,14 @@
// message's own ItsPduHeader.stationID is the meaningful identifier.
// SERIAL_MSG_STATUS (0x03), ESP32 -> phone: heartbeat + counters, sent at 1 Hz so the phone can
// distinguish "link idle" from "link dead" independent of CAM traffic (the app's watchdog in
// UsbSerialTransport.kt declares the link dead after 3 missed beats). Payload is 8 bytes:
// UsbSerialTransport.kt declares the link dead after 3 missed beats). Payload is 10 bytes:
// [status:1][oversize_drops:2 LE][tx_failures:2 LE][rx_crc_errors:2 LE][capabilities:1]
// [rx_queue_drops:2 LE]
// status 0 = ok. The counters are free-running totals since boot, saturating at 0xFFFF.
// capabilities is a bitmask of the SERIAL_CAP_* flags below. It was appended as byte 7 rather
// than inserted, so an app that predates it, and reads only the first 7 bytes, is unaffected.
// than inserted, so an app that predates it, and reads only the first 7 bytes, is unaffected;
// rx_queue_drops (bytes 8-9) follows the same rule for an app that predates it. Either side
// reading a payload shorter than the field it wants should treat that field as 0, not error.
// They exist because the alternative - ESP_LOGW on the flashing port - is invisible to the
// phone, which is the only thing watching during a bench session. Mirrored by EspLinkStatus
// in the app's SerialFrame.kt.
@@ -165,4 +168,13 @@ void serial_link_note_tx_failure(void);
// whose capture buffer is smaller than the largest frames on air.
void serial_link_note_oversize_drop(uint16_t btp_dest_port);
// Counts a promiscuously-captured frame that main.c's wifi_promisc_rx_cb() could not hand to
// rx_forward_task because s_rx_queue was full - i.e. frames arrived faster than the forward task
// (gn_unwrap + a blocking USB write, up to SERIAL_LINK_WRITE_TIMEOUT_MS x 4 per frame under
// contention) could drain them. Unlike oversize_drop this is not about one frame's size; it is
// about a burst of otherwise-forwardable frames. Previously silent - xQueueSend's return value
// was not even checked - so a run of these had no visible symptom beyond "that station's CAM
// count looked a little low."
void serial_link_note_rx_queue_drop(void);
#endif