/* AFTER — the SAME pipeline, event-driven: a sensor DATA-READY interrupt defers each sample into
* the pipeline (rawQ -> FILTER task -> filtQ -> ALERT task). Wokwi, ST Nucleo-C031C6.
* When ALERT does heavy work it blocks ONLY ITSELF — the sensor keeps firing and samples BUFFER in
* the queue, so nothing is missed. This is how you read a real MAX30102 (its data-ready INT pin),
* instead of polling it in a loop.
* LEDs (optional): yellow on a dropped glitch, red on an alert.
*/
#include <STM32FreeRTOS.h>
#include "sensor_contract.h"
#define LED_YELLOW PB1
#define LED_RED PB14
QueueHandle_t rawQ, filtQ;
/* sensor DATA-READY ISR: capture the sample, defer to the pipeline, return fast. */
static void SensorDataReadyISR(const SensorSample_t *s) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(rawQ, s, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/* FAKE data-ready IRQ: fires every 250 ms regardless of how busy the downstream is. */
static void SensorSourceTask(void *pv) {
(void)pv; uint32_t seq = 0;
for (;;) {
vTaskDelay(pdMS_TO_TICKS(250));
seq++;
SensorSample_t s = hh_make_sample(seq);
SensorDataReadyISR(&s); // on real HW: the MAX30102 INT / EXTI handler
}
}
static void FilterTask(void *pv) {
(void)pv; SensorSample_t s;
for (;;) if (xQueueReceive(rawQ, &s, portMAX_DELAY) == pdTRUE) {
if (hh_valid(&s)) {
xQueueSend(filtQ, &s, portMAX_DELAY);
} else {
digitalWrite(LED_YELLOW, HIGH);
Serial.print("seq="); Serial.print(s.seq); Serial.println(" FILTER: drop glitch");
vTaskDelay(pdMS_TO_TICKS(15)); digitalWrite(LED_YELLOW, LOW);
}
}
}
static void AlertTask(void *pv) {
(void)pv; SensorSample_t f;
for (;;) if (xQueueReceive(filtQ, &f, portMAX_DELAY) == pdTRUE) {
const char *lvl = "OK";
if (f.spo2_pct < 90.0f) lvl = "CRITICAL"; else if (f.temp_c >= 38.0f) lvl = "HIGH";
bool a = (lvl[0] != 'O');
digitalWrite(LED_RED, a ? HIGH : LOW);
Serial.print("seq="); Serial.print(f.seq); Serial.print(" ALERT: "); Serial.println(lvl);
if (a) {
vTaskDelay(pdMS_TO_TICKS(500)); // heavy handling — blocks ONLY this task
Serial.print(" (heavy alert done; "); Serial.print(uxQueueMessagesWaiting(filtQ));
Serial.println(" sample(s) buffered while busy -- none missed)");
}
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_YELLOW, OUTPUT); pinMode(LED_RED, OUTPUT);
rawQ = xQueueCreate(16, sizeof(SensorSample_t));
filtQ = xQueueCreate(16, sizeof(SensorSample_t));
Serial.println("AFTER: pipeline is EVENT-DRIVEN (data-ready IRQ -> tasks)");
xTaskCreate(SensorSourceTask, "SENSOR", 256, NULL, 3, NULL); // fires on time, always
xTaskCreate(FilterTask, "FILTER", 256, NULL, 2, NULL);
xTaskCreate(AlertTask, "ALERT", 256, NULL, 1, NULL);
vTaskStartScheduler();
}
void loop() {}
Loading
st-nucleo-c031c6
st-nucleo-c031c6