15#if DETWS_ENABLE_PREEMPT_QUEUE
27 DetwsPqHandler handler[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
28 void *ctx[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
29 size_t high_water[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
35const char *lane_name(detws_pq_lane lane)
39 case detws_pq_lane::DETWS_PQ_LANE_DMA:
40 return "detws_pq_dma";
41 case detws_pq_lane::DETWS_PQ_LANE_FORWARD:
42 return "detws_pq_fwd";
43 case detws_pq_lane::DETWS_PQ_LANE_DEVICE:
44 return "detws_pq_dev";
46 return "detws_pq_user";
51bool lane_ok(detws_pq_lane lane)
53 return (
unsigned)lane < (unsigned)detws_pq_lane::DETWS_PQ_LANE_COUNT;
59uint8_t detws_pq_lane_priority(detws_pq_lane lane)
63 case detws_pq_lane::DETWS_PQ_LANE_DMA:
65 case detws_pq_lane::DETWS_PQ_LANE_FORWARD:
67 case detws_pq_lane::DETWS_PQ_LANE_DEVICE:
69 case detws_pq_lane::DETWS_PQ_LANE_USER:
77#include "freertos/FreeRTOS.h"
78#include "freertos/queue.h"
79#include "freertos/task.h"
88 StaticQueue_t q_struct[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT];
90 QueueHandle_t q[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
91 TaskHandle_t task[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
92 volatile bool run[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
96void note_depth(detws_pq_lane lane, UBaseType_t waiting)
98 if ((
size_t)waiting > s_pq.high_water[(
size_t)lane])
99 s_pq.high_water[(size_t)lane] = (
size_t)waiting;
105void pq_task(
void *arg)
107 detws_pq_lane lane =
static_cast<detws_pq_lane
>(
reinterpret_cast<uintptr_t
>(arg));
111 if (xQueueReceive(s_pqq.q[(
size_t)lane], item, portMAX_DELAY) == pdTRUE && s_pq.handler[(
size_t)lane])
112 s_pq.handler[(
size_t)lane](item, s_pq.ctx[(size_t)lane]);
117bool detws_pq_start_lane(detws_pq_lane lane,
const DetwsPqConfig *cfg)
119 if (!lane_ok(lane) || s_pqq.run[(
size_t)lane] || !cfg || !cfg->handler)
121 s_pq.handler[(size_t)lane] = cfg->handler;
122 s_pq.ctx[(size_t)lane] = cfg->ctx;
123 s_pq.high_water[(size_t)lane] = 0;
124 if (!s_pqq.q[(
size_t)lane])
126 &s_pqq.q_struct[(
size_t)lane]);
127 if (!s_pqq.q[(
size_t)lane])
129 s_pqq.run[(size_t)lane] =
true;
130 uint8_t prio = cfg->priority ? cfg->priority : detws_pq_lane_priority(lane);
131 int core = cfg->core % portNUM_PROCESSORS;
132 if (xTaskCreatePinnedToCore(pq_task, cfg->name ? cfg->name : lane_name(lane),
DETWS_PQ_STACK,
133 (void *)(uintptr_t)lane, prio, &s_pqq.task[(size_t)lane], core) != pdPASS)
135 s_pqq.run[(size_t)lane] =
false;
141bool detws_pq_post_lane(detws_pq_lane lane,
const void *item, uint32_t timeout_ticks)
143 if (!lane_ok(lane) || !s_pqq.q[(
size_t)lane] || !item)
145 if (xQueueSendToBack(s_pqq.q[(
size_t)lane], item, (TickType_t)timeout_ticks) != pdTRUE)
147 note_depth(lane, uxQueueMessagesWaiting(s_pqq.q[(
size_t)lane]));
151bool detws_pq_post_lane_urgent(detws_pq_lane lane,
const void *item, uint32_t timeout_ticks)
153 if (!lane_ok(lane) || !s_pqq.q[(
size_t)lane] || !item)
155 if (xQueueSendToFront(s_pqq.q[(
size_t)lane], item, (TickType_t)timeout_ticks) != pdTRUE)
157 note_depth(lane, uxQueueMessagesWaiting(s_pqq.q[(
size_t)lane]));
161bool detws_pq_post_lane_from_isr(detws_pq_lane lane,
const void *item)
163 if (!lane_ok(lane) || !s_pqq.q[(
size_t)lane] || !item)
165 BaseType_t woke = pdFALSE;
166 if (xQueueSendToBackFromISR(s_pqq.q[(
size_t)lane], item, &woke) != pdTRUE)
168 note_depth(lane, uxQueueMessagesWaitingFromISR(s_pqq.q[(
size_t)lane]));
169 portYIELD_FROM_ISR(woke);
173void detws_pq_drain_lane(detws_pq_lane)
178void detws_pq_stop_lane(detws_pq_lane lane)
182 s_pqq.run[(size_t)lane] =
false;
183 if (s_pqq.task[(
size_t)lane])
185 vTaskDelete(s_pqq.task[(
size_t)lane]);
186 s_pqq.task[(size_t)lane] =
nullptr;
190bool detws_pq_running_lane(detws_pq_lane lane)
192 return lane_ok(lane) && s_pqq.run[(size_t)lane];
195size_t detws_pq_high_water_lane(detws_pq_lane lane)
197 return lane_ok(lane) ? s_pq.high_water[(size_t)lane] : 0;
209 size_t head[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
210 size_t tail[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
211 size_t count[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
212 bool started[(size_t)detws_pq_lane::DETWS_PQ_LANE_COUNT] = {};
216void note_count(detws_pq_lane lane)
218 if (s_pqr.count[(
size_t)lane] > s_pq.high_water[(
size_t)lane])
219 s_pq.high_water[(size_t)lane] = s_pqr.count[(
size_t)lane];
223bool detws_pq_start_lane(detws_pq_lane lane,
const DetwsPqConfig *cfg)
225 if (!lane_ok(lane) || s_pqr.started[(
size_t)lane] || !cfg || !cfg->handler)
227 s_pq.handler[(size_t)lane] = cfg->handler;
228 s_pq.ctx[(size_t)lane] = cfg->ctx;
229 s_pqr.head[(size_t)lane] = 0;
230 s_pqr.tail[(size_t)lane] = 0;
231 s_pqr.count[(size_t)lane] = 0;
232 s_pq.high_water[(size_t)lane] = 0;
233 s_pqr.started[(size_t)lane] =
true;
237bool detws_pq_post_lane(detws_pq_lane lane,
const void *item, uint32_t)
239 if (!lane_ok(lane) || !item || s_pqr.count[(
size_t)lane] >=
DETWS_PQ_DEPTH)
242 s_pqr.head[(size_t)lane] = (s_pqr.head[(
size_t)lane] + 1) %
DETWS_PQ_DEPTH;
243 s_pqr.count[(size_t)lane]++;
248bool detws_pq_post_lane_urgent(detws_pq_lane lane,
const void *item, uint32_t)
250 if (!lane_ok(lane) || !item || s_pqr.count[(
size_t)lane] >=
DETWS_PQ_DEPTH)
252 s_pqr.tail[(size_t)lane] =
255 s_pqr.count[(size_t)lane]++;
260bool detws_pq_post_lane_from_isr(detws_pq_lane lane,
const void *item)
262 return detws_pq_post_lane(lane, item, 0);
265void detws_pq_drain_lane(detws_pq_lane lane)
269 while (s_pqr.count[(
size_t)lane] > 0)
271 if (s_pq.handler[(
size_t)lane])
272 s_pq.handler[(size_t)lane](s_pqr.buf[(
size_t)lane] + s_pqr.tail[(size_t)lane] *
DETWS_PQ_ITEM_SIZE,
273 s_pq.ctx[(
size_t)lane]);
274 s_pqr.tail[(size_t)lane] = (s_pqr.tail[(
size_t)lane] + 1) %
DETWS_PQ_DEPTH;
275 s_pqr.count[(size_t)lane]--;
279void detws_pq_stop_lane(detws_pq_lane lane)
282 s_pqr.started[(size_t)lane] =
false;
285bool detws_pq_running_lane(detws_pq_lane lane)
287 return lane_ok(lane) && s_pqr.started[(size_t)lane];
290size_t detws_pq_high_water_lane(detws_pq_lane lane)
292 return lane_ok(lane) ? s_pq.high_water[(size_t)lane] : 0;
#define DETWS_PQ_INTERNAL_PRIORITY
Base FreeRTOS priority for the internal preempting lanes (DMA / forwarding / device access)....
#define DETWS_PQ_DEPTH
Capacity of the preempting queue in items (static-allocated).
#define DETWS_PQ_ITEM_SIZE
Bytes per preempting-queue item (the posted item must fit).
#define DETWS_PQ_STACK
Stack (bytes) for each preempting-queue processing task (ESP32).
User-configurable preempting work queues + high-priority processing tasks (DETWS_ENABLE_PREEMPT_QUEUE...