Move the RX capture buffer off the WiFi driver's callback stack
rx_item_t is ~800 bytes at RX_FRAME_MAX_LEN, and wifi_promisc_rx_cb declared one as a local. That callback runs on the WiFi driver's own task, already several frames deep in the driver's call chain, on a stack of roughly 3.5 KB (CONFIG_ESP_WIFI_TASK_STACK_SIZE, left at its default). Putting a fifth of that stack into a single local is a stack-overflow risk that only appears under real traffic - in front of an RSU rather than on the bench - and would present as a random panic rather than anything pointing at its cause. Both instances are now static: one in the callback, one in rx_forward_task. Safe because each is touched by exactly one task, so there is no re-entrancy to guard against; the same reasoning serial_link.c already uses for its static send buffers. xQueueSend copies the struct out before returning, so reusing the callback's buffer on the next frame is fine. Firmware-only, no protocol change, so it does not require a matching app install. Re-verified against live traffic after flashing: 1094 frames over 125 s with zero decode failures, USB errors, detaches, crashes or mutex timeouts. SPATEM capture rose from 3.20/s to 3.98/s against a theoretical maximum of 4.00/s, which is the direction relieving stack pressure would produce, though RF geometry moves between runs and this is not proof. Report updated with T9, the accepted 512-byte ceiling, and the decision to drop Phase B: the intersection use case is CAM-driven and needs none of it.
This commit is contained in:
@@ -188,19 +188,31 @@ static void wifi_promisc_rx_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type)
|
||||
return;
|
||||
}
|
||||
|
||||
rx_item_t item;
|
||||
item.len = length > (int)sizeof(item.data) ? (int)sizeof(item.data) : length;
|
||||
memcpy(item.data, packet->payload, (size_t)item.len);
|
||||
item.rssi = packet->rx_ctrl.rssi;
|
||||
// static, NOT a local: at RX_FRAME_MAX_LEN this struct is ~800 bytes, and this callback runs
|
||||
// on the WiFi driver's own task - already several frames deep in the driver's call chain, on a
|
||||
// stack of roughly 3.5 KB (CONFIG_ESP_WIFI_TASK_STACK_SIZE, left at its default). Putting
|
||||
// ~23% of that stack in one local is a stack-overflow risk that only bites under real traffic,
|
||||
// i.e. in front of an RSU rather than on the bench.
|
||||
//
|
||||
// Safe as a static because the promiscuous callback is only ever invoked from that one task,
|
||||
// so there is no re-entrancy to guard against - the same reasoning serial_link.c uses for its
|
||||
// static send buffers. rx_forward_task has its own separate copy below.
|
||||
static rx_item_t s_cb_item;
|
||||
s_cb_item.len = length > (int)sizeof(s_cb_item.data) ? (int)sizeof(s_cb_item.data) : length;
|
||||
memcpy(s_cb_item.data, packet->payload, (size_t)s_cb_item.len);
|
||||
s_cb_item.rssi = packet->rx_ctrl.rssi;
|
||||
|
||||
// 0 timeout: never block the WiFi driver's own task waiting for queue space.
|
||||
xQueueSend(s_rx_queue, &item, 0);
|
||||
// 0 timeout: never block the WiFi driver's own task waiting for queue space. xQueueSend copies
|
||||
// the struct out before returning, so reusing s_cb_item on the next callback is fine.
|
||||
xQueueSend(s_rx_queue, &s_cb_item, 0);
|
||||
}
|
||||
|
||||
static void rx_forward_task(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
rx_item_t item;
|
||||
// Same reasoning as the callback: ~800 bytes is a fifth of this task's 4 KB stack. Only this
|
||||
// task touches it, and it is fully overwritten by xQueueReceive before every use.
|
||||
static rx_item_t item;
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(s_rx_queue, &item, portMAX_DELAY) != pdTRUE) {
|
||||
|
||||
Reference in New Issue
Block a user