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.
This commit is contained in:
@@ -57,8 +57,9 @@ const val SERIAL_LINK_MAX_PAYLOAD = 512
|
||||
|
||||
/**
|
||||
* Decoded [SerialFrameType.STATUS] payload: `[status:1][oversizeDrops:2 LE][txFailures:2 LE]
|
||||
* [rxCrcErrors:2 LE]` (7 bytes). Counters are free-running totals since firmware boot and
|
||||
* saturate at 0xFFFF rather than wrapping.
|
||||
* [rxCrcErrors:2 LE][capabilities:1][rxQueueDrops:2 LE]` (10 bytes; the last two fields are an
|
||||
* optional tail — see [capabilities] and [rxQueueDrops]). Counters are free-running totals since
|
||||
* firmware boot and saturate at 0xFFFF rather than wrapping.
|
||||
*
|
||||
* Exists so the phone can tell "link alive, no traffic" from "link dead", and so firmware-side
|
||||
* drops — which otherwise only reach `ESP_LOGW` on the flashing port that the phone isn't
|
||||
@@ -79,6 +80,15 @@ data class EspLinkStatus(
|
||||
* the phone needs from such firmware: it accepts nothing beyond the original messages.
|
||||
*/
|
||||
val capabilities: Int = 0,
|
||||
/**
|
||||
* Promiscuously-captured frames the firmware's `wifi_promisc_rx_cb` had to drop because its
|
||||
* RX queue (8 deep) was still full of frames `rx_forward_task` hadn't finished forwarding —
|
||||
* bytes 8-9 of the payload. 0 for firmware that predates this field (payload of 7 or 8 bytes),
|
||||
* which is the honest answer: such firmware drops these frames identically, it just never
|
||||
* counted them. A nonzero, growing value here — as opposed to [oversizeDrops] — points at
|
||||
* bursty RX outrunning the forward task rather than any one frame being too large.
|
||||
*/
|
||||
val rxQueueDrops: Int = 0,
|
||||
) {
|
||||
/** True when the firmware accepts [SerialFrameType.CAM_TX_PV]. */
|
||||
val supportsCamTxPv: Boolean get() = capabilities and CAP_CAM_TX_PV != 0
|
||||
@@ -99,6 +109,7 @@ data class EspLinkStatus(
|
||||
txFailures = u16(3),
|
||||
rxCrcErrors = u16(5),
|
||||
capabilities = if (payload.size > PAYLOAD_SIZE) payload[7].toInt() and 0xFF else 0,
|
||||
rxQueueDrops = if (payload.size >= 10) u16(8) else 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,13 +330,15 @@ class UsbSerialTransport @Inject constructor(
|
||||
prev.txFailures != status.txFailures ||
|
||||
prev.rxCrcErrors != status.rxCrcErrors ||
|
||||
prev.status != status.status ||
|
||||
prev.capabilities != status.capabilities
|
||||
prev.capabilities != status.capabilities ||
|
||||
prev.rxQueueDrops != status.rxQueueDrops
|
||||
) {
|
||||
Log.i(TAG, "ESP32 counters: status=${status.status} " +
|
||||
"oversizeDrops=${status.oversizeDrops} " +
|
||||
"txFailures=${status.txFailures} " +
|
||||
"rxCrcErrors=${status.rxCrcErrors} " +
|
||||
"capabilities=${status.capabilities}")
|
||||
"capabilities=${status.capabilities} " +
|
||||
"rxQueueDrops=${status.rxQueueDrops}")
|
||||
}
|
||||
_linkStatus.value = status
|
||||
}
|
||||
|
||||
@@ -1219,11 +1219,12 @@ private fun CamPingerCard(
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.mqtt_cam_pinger_fw_counters,
|
||||
s.txFailures, s.oversizeDrops, s.rxCrcErrors,
|
||||
s.txFailures, s.oversizeDrops, s.rxCrcErrors, s.rxQueueDrops,
|
||||
),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = if (s.txFailures > 0 || s.oversizeDrops > 0 || s.rxCrcErrors > 0)
|
||||
ErrorRed else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
color = if (s.txFailures > 0 || s.oversizeDrops > 0 || s.rxCrcErrors > 0 ||
|
||||
s.rxQueueDrops > 0
|
||||
) ErrorRed else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user