DÍA 235 DE 365

Fase 5: Diseño Industrial y Proyecto Final

📖 Teoría a Estudiar

¿Qué es MISRA-C?

El lenguaje C fue diseñado para escribir sistemas operativos rápidos, asumiendo que el programador "sabe lo que hace". C te permite leer memoria que no te pertenece, dividir por cero y sobreescribir punteros de ejecución. En un videojuego, esto causa que la aplicación se cierre (Crash). En una bomba de infusión médica o en nuestro Despachador de Gas LP, esto causa la muerte.

MISRA (Motor Industry Software Reliability Association) es un conjunto de reglas creadas originalmente por Ford y Rover para el software de frenos ABS. Hoy es el estándar global para todo sistema crítico embebido (SIL-3 / SIL-4). Si tu código viola una regla MISRA, no puede ser implementado en un hardware crítico. Así de simple.

Las 10 Reglas de Oro de Seguridad Total (Adaptación Industrial)

Aplica esto como un dogma en tu STM32 y serás mejor que el 90% de los programadores comerciales:

  1. Cero Asignación Dinámica (Muerte a malloc): Prohibido usar malloc() o free(). Con 96KB de RAM, la memoria se fragmentará en 3 meses, tu RTOS se quedará sin bloque continuo (Heap Exhaustion) y la máquina colapsará. Usa static o arrays de tamaño fijo en tiempo de compilación.
  2. Prohibidos los Punteros Salvajes: Un puntero no puede tener más de dos niveles de indirección (**ptr). Deben inicializarse siempre a NULL o a una dirección válida.
  3. Tipado Fuerte Estricto (stdint.h): Olvida el tipo int o long. Su tamaño cambia entre compiladores de 16, 32 y 64 bits. Usa EXCLUSIVAMENTE uint8_t, int32_t, uint32_t, etc. Sabes exactamente qué tamaño tiene en memoria.
  4. El Mandamiento del default: Todo switch-case DEBE tener un bloque default, incluso si crees que todas las opciones están cubiertas. En ese bloque debes atrapar errores catastróficos.
  5. Sin Códigos Muertos (Dead Code): Cualquier función o variable que no se utilice debe ser eliminada. El código muerto confunde auditorías y desperdicia valiosos sectores Flash.
  6. Límites de Arrays: Nunca se debe confiar en los índices entrantes. Antes de acceder a buffer[i], se debe validar que i < MAX_SIZE.
  7. Sin Recursividad: Una función no debe llamarse a sí misma. La recursividad desborda el Pila (Stack Overflow) en procesadores ARM con memoria finita.
  8. Inicialización Obligatoria: Las variables no pueden declararse vacías (uint8_t estado;). Deben tener un valor conocido desde el ciclo 1 (uint8_t estado = 0;).
  9. Conversión Implícita Prohibida (Casting): No mezcles tipos con signos y sin signos, ni promuevas de 8 bits a 32 bits sin un cast explícito que el desarrollador haya pensado.
  10. No goto: El uso de saltos incondicionales rompe el flujo estructurado del programa y hace el análisis estático casi imposible.
ARQUITECTURA DE SOFTWARE SIL (SAFETY INTEGRITY LEVEL) CON MISRA-C Código Fuente (.c) Escrito por Ingenieros malloc(1024); int valvula; array[i] = 1; uint8_t buffer[10] MISRA-C CHECKER (Análisis Estático de Compilador) ERROR 21.3 (Dynamic Mem) ERROR 4.6 (Basic Types) ERROR 18.1 (Bounds Check) COMPLIANT (Pasa) HARDWARE CRÍTICO (STM32) Válvula de Gas LP 10 Años Uptime La Compilación ABORTARÁ si encuentra una sola violación MISRA-C.

⚙️ Ejercicios Prácticos

Laboratorio de Código C: No basta con saber qué reglas usar, hay que saber cómo se ven. A continuación, compararemos un fragmento de código escrito por un estudiante con un fragmento certificado bajo la directiva MISRA-C para controlar la válvula electromecánica.


/**
 * @file valvula_control.c
 * @brief Comparativa: C Estándar (Peligroso) vs C-MISRA (Industrial)
 */

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

// =========================================================================
// ❌ EL MODO AMATEUR (VIOLA LAS REGLAS MISRA-C)
// =========================================================================
// - Usa 'int' (Violación Regla 4.6: Tipos básicos sin tamaño fijo).
// - No inicializa 'status' (Violación Regla 9.1: Valor antes de uso).
// - No hay 'default' en el switch (Violación Regla 16.4).
// - Asume que 'pin_array' no se desbordará.

int pines_valvulas[3] = {10, 11, 12};

void Control_Valvula_Malo(int numero_valvula, int comando) {
    int status; 
    
    // Si numero_valvula es 5, leerá memoria RAM fuera del arreglo (Buffer Overread)
    int pin = pines_valvulas[numero_valvula];
    
    switch(comando) {
        case 0:
            // Apagar PIN
            status = 0;
            break;
        case 1:
            // Encender PIN
            status = 1;
            break;
    }
    
    // Si comando era 2, status contendrá basura (memoria residual)
    // y aplicará un estado indeterminado al hardware físico.
    Aplicar_Hardware(pin, status); 
}


// =========================================================================
// ✅ EL MODO ARQUITECTO INDUSTRIAL (CUMPLE MISRA-C)
// =========================================================================
// - Tipos estrictos (uint8_t).
// - Constantes ('static const' en lugar de variables globales libres).
// - Comprobación explícita de límites de matriz.
// - Switch con 'default' seguro.
// - Enum en lugar de "números mágicos" 0 y 1.

#define MAX_VALVULAS 3U // La 'U' obliga al compilador a tratarlo como Unsigned

typedef enum {
    VALVULA_CERRAR = 0U,
    VALVULA_ABRIR  = 1U
} EstadoValvula_t;

static const uint8_t pines_valvulas_safe[MAX_VALVULAS] = {10U, 11U, 12U};

/**
 * @brief Aplica estado seguro a válvula física
 * @param num_valvula Índice de la válvula (0 a 2)
 * @param comando     Estado requerido de la enumeración
 */
void Control_Valvula_Seguro(uint8_t num_valvula, EstadoValvula_t comando) {
    
    // 1. Regla MISRA: Inicialización explícita a un estado SEGURO.
    uint8_t status_hardware = 0U; 
    
    // 2. Regla MISRA: Validación estricta de límites (Evita Buffer Overflow)
    if (num_valvula >= MAX_VALVULAS) {
        // Log Error Crítico OOB (Out-of-Bounds)
        // Entrar a Failsafe.
        return; 
    }
    
    uint8_t pin_objetivo = pines_valvulas_safe[num_valvula];
    
    // 3. Regla MISRA: Estructuras de decisión completas
    switch(comando) {
        case VALVULA_CERRAR:
            status_hardware = 0U;
            break;
            
        case VALVULA_ABRIR:
            status_hardware = 1U;
            break;
            
        default:
            // 4. Regla MISRA: El caso default DEBE existir. 
            // Si la RAM se corrompió y 'comando' es 45, entramos aquí.
            // Acción Segura Definitiva: Cerramos Válvula de Gas.
            status_hardware = 0U; 
            // Disparar Alarma_Sistema_Corrupto();
            break;
    }
    
    Aplicar_Hardware_Seguro(pin_objetivo, status_hardware);
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Certificación SIL (Safety Integrity Level) y Mitigación de Riesgos Catastróficos.

Imagina que estás escribiendo el código de tu STM32 y usas un arreglo de 4 posiciones para guardar la telemetría de 4 sensores de flujo. Por un error humano de cálculo, un bucle for intenta escribir en la posición número 5. En lenguajes de alto nivel como Python, el programa simplemente arrojaría una excepción (`IndexError`). Pero el C Bare-Metal de tu STM32 no hace preguntas; obedece ciegamente. Escribirá el dato del sensor en el bloque de memoria RAM que estaba junto al arreglo. ¿Qué pasaría si ese bloque de memoria casualmente controlaba la variable "Estado de la Válvula"? El gas comenzará a salir de forma incontrolable a la atmósfera de la estación, sin que ningún log registre el fallo.

Al auditar todo el Firmware de tu Despachador de Gas LP con las **Normas MISRA-C:2012**, garantizas que tu sistema sea determinista, seguro y auditable. Utilizar tipos estrictos (`uint8_t`), erradicar el `malloc` dinámico (evitando que la RAM se fragmente tras 2 años encendida), obligar a escribir bloques `default` que cierren las válvulas si un dato se corrompe, y usar validación de límites (Bounds Checking) convertirá tu PCB casera en un equipo certificable internacionalmente para Zonas de Riesgo Explosivo (Normas IEC 61508 / ATEX). Has cruzado la línea de Programador a Arquitecto de Seguridad Industrial.

📝 Resumen del Día