Probar un sistema en "condiciones normales" es fácil; todo funciona cuando el clima es perfecto. El verdadero trabajo del Arquitecto Embebido es probar el sistema bajo condiciones patológicas. Para ello, creamos temporalmente un Chaos Monkey (Mono del Caos), una tarea diseñada exclusivamente para comportarse como hardware averiado y redes saturadas.
Nuestra tarea inyectará deliberadamente tres tipos de ruido en la topología de nuestro RTOS:
osMessageQueuePut devuelva error de buzón lleno.Ejercicio 1: Introduciremos una nueva Tarea en nuestro main.c. Esta tarea se ejecutará solo si definimos una constante de prueba. Usará la generación de números aleatorios para elegir un método de ataque distinto cada pocos milisegundos, simulando la entropía del universo real.
/**
* @file chaos_monkey.c
* @brief Tarea de Inyección de Estrés (Chaos Engineering para RTOS)
*/
#include "stm32f401xe.h"
#include "cmsis_os2.h"
#include <stdlib.h> // Para rand()
// Switch maestro de pruebas (En producción se comenta)
#define TEST_MODO_STRESS_ACTIVO 1
extern osMessageQueueId_t queue_comandos_id;
extern osMutexId_t bus_hardware_mutex_id;
// =======================================================
// LA TAREA DEL CAOS (Prioridad Normal/Baja)
// =======================================================
#if TEST_MODO_STRESS_ACTIVO
void Thread_ChaosMonkey(void *argument) {
// Semilla para caos pseudoaleatorio
srand(osKernelGetTickCount());
Comando_t basura_cmd = { .id = 99, .param = 0.0f };
for (;;) {
// Elegir un ataque al azar (0, 1 o 2)
int ataque = rand() % 3;
switch (ataque) {
case 0:
// ATAQUE 1: Saturación de Cola (Flooding)
// Intenta meter 20 mensajes de golpe en una cola que solo soporta 10.
// Si la Metrología no tiene protección de errores, colapsará.
for (int i=0; i<20; i++) {
// El timeout 0 evita que el mono se bloquee a sí mismo
osMessageQueuePut(queue_comandos_id, &basura_cmd, 0, 0);
}
UART_Enviar_String("[CHAOS] Cola Saturada intencionalmente.\r\n");
break;
case 1:
// ATAQUE 2: Retención de Mutex (Mutex Hogging)
// Toma la llave del I2C/SPI y "finge" ser un periférico muy lento.
if (osMutexAcquire(bus_hardware_mutex_id, 100) == osOK) {
UART_Enviar_String("[CHAOS] Mutex Secuestrado...\r\n");
// Bloquea el bus durante 40ms. Las tareas de Pantalla y Logs
// deberán entrar en Herencia de Prioridad o Bloquearse sin fallar.
osDelay(40);
osMutexRelease(bus_hardware_mutex_id);
UART_Enviar_String("[CHAOS] Mutex Liberado.\r\n");
}
break;
case 2:
// ATAQUE 3: Tormenta de Interrupciones (Interrupt Spam)
// Forzamos al microcontrolador a creer que el sensor de flujo (EXTI0)
// mandó un pulso eléctrico. Lo hacemos 50 veces seguidas.
// Esto bombardeará el Semáforo Binario de la Metrología.
UART_Enviar_String("[CHAOS] Tormenta Eléctrica iniciada!\r\n");
for (int i=0; i<50; i++) {
// Magia Negra de ARM: Disparar ISR por software
NVIC_SetPendingIRQ(EXTI0_IRQn);
// Pequeño delay manual (busy-wait) para simular ruido de 10kHz
for(volatile int j=0; j<1000; j++);
}
break;
}
// El Mono descansa un rato aleatorio antes del siguiente ataque (50 a 250ms)
osDelay(50 + (rand() % 200));
}
}
#endif
// =======================================================
// INICIALIZACIÓN (Modificada)
// =======================================================
int main(void) {
// ... Todo el código del Día 199 intacto ...
#if TEST_MODO_STRESS_ACTIVO
const osThreadAttr_t attr_mono = {
.name = "ChaosTask",
.stack_size = 512,
.priority = osPriorityNormal // Importante que compita con la Pantalla
};
osThreadNew(Thread_ChaosMonkey, NULL, &attr_mono);
#endif
osKernelStart();
while (1);
}
Objetivo del día: Validación final de la Arquitectura RTOS en Condiciones Hostiles.
¡Has llegado al Día 200 de tu jornada! A partir de hoy, no estás diseñando un prototipo escolar; has forjado una pieza de armamento de software industrial.
Al ejecutar y sobrevivir el `Thread_ChaosMonkey`, observaste la pantalla LCD conectada a tu STM32. Viste cómo la UART gritaba "[CHAOS] Tormenta Eléctrica!" y "[CHAOS] Cola Saturada!". Sin embargo, los litros de Gas LP en la pantalla siguieron avanzando suavemente, sin congelarse, y la válvula se cerró en el milisegundo exacto en que alcanzó su meta. El Kernel de FreeRTOS, escudado por tus Mutexes bien programados y el procesamiento diferido de tus Semáforos, absorbió el ataque sin piedad. El TCB (Task Control Block) contuvo los errores. La Tarea Centinela validó que ninguna tarea muriera de Inanición. Has demostrado empíricamente que tu máquina es digna de la certificación de seguridad SIL-3. Está lista para el mundo real.
NVIC_SetPendingIRQ) simula el rebote mecánico de sensores de mala calidad (Bouncing) o ruido electromagnético severo, validando que el *Deferred Interrupt Processing* (Día 189) soporte la carga.osMessageQueuePut (llenando la cola a propósito) comprueba que tu código consumidor verifica los estados de retorno (osStatus_t) en lugar de asumir que todo siempre sale bien, evitando desbordamientos ciegos.