DÍA 050 DE 365

Fase 1: Fundamentos de C y Lógica de Software

📖 Teoría a Estudiar

Test Unitario e Inyección de Datos Falsos (Mocking)

Uno de los mayores errores en el desarrollo de sistemas embebidos de grado industrial es acoplar la lógica matemática directamente al hardware. Si tu función para calcular el flujo de líquido lee el registro del hardware directamente (ej. ADC1->DR), no puedes probar tu lógica sin tener el hardware conectado, encendido y con gas fluyendo.

La solución es el Desacoplamiento. Consiste en diseñar tus funciones para que reciban datos a través de parámetros. En producción, el parámetro viene del sensor real. En desarrollo, tú inyectas datos falsos (mocks) desde la PC para forzar escenarios extremos (sobrepresión, desconexión, ceros) y verificar matemáticamente si el código sobrevive sin necesidad de flashear el microcontrolador.

LÓGICA PURA EN C calcular_volumen(raw_val) PRODUCCIÓN STM32 ADC DMA Data Real UNIT TEST (PC) Scripts de Inyección Mock (0x0FFF) RESULTADO Verificable

Los Pasos para el Test Unitario

  1. Aislar: Extrae la fórmula o el algoritmo de toma de decisiones a una función que devuelva un valor y no interactúe con pines ni registros (ej. GPIOA).
  2. Inyectar: Crea un archivo de prueba en C que se compile nativamente en tu computadora (GCC/MinGW), no para el microcontrolador. Llama a tu función pasándole parámetros diseñados a mano (casos borde).
  3. Afirmar (Assert): Usa la macro assert() de la librería estándar para obligar al programa a cerrarse con error si la función no devuelve el valor matemático esperado.

⚙️ Ejercicios Prácticos

Ejercicio 1: Desacopla la lógica de conversión de presión y escribe un test unitario que inyecte 3 escenarios distintos: cero absoluto, presión normal y saturación de sensor.


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

// ========================================================
// 1. CÓDIGO DE PRODUCCIÓN (Hardware Agnostic)
// Este código irá al STM32, pero está 100% aislado.
// ========================================================

// Transductor de presión 0-250 PSI. ADC de 12 bits (0-4095).
uint32_t calcular_presion_psi(uint16_t adc_raw) {
    // Si hay un error de hardware y manda ruido por encima de 4095
    if (adc_raw > 4095) { 
        return 0xFFFFFFFF; // Código de error de saturación
    }
    
    // Mapeo lineal usando punto fijo (Día 38)
    // Formula: PSI = (ADC * Rango_PSI) / Res_ADC
    uint32_t presion = (adc_raw * 250) / 4095;
    return presion;
}


// ========================================================
// 2. ENTORNO DE TEST (Se compila y corre en tu PC)
// ========================================================
void ejecutar_tests_unitarios() {
    printf("Iniciando bateria de tests de presion...\n");

    // Test 1: Inyección de límite inferior (Mock = 0)
    assert(calcular_presion_psi(0) == 0);
    printf("[OK] Test Límite Inferior (0 PSI)\n");

    // Test 2: Inyección de límite superior seguro (Mock = 4095)
    assert(calcular_presion_psi(4095) == 250);
    printf("[OK] Test Límite Superior (250 PSI)\n");

    // Test 3: Inyección de media escala (Mock = 2047)
    // (2047 * 250) / 4095 = 124.96 -> 124 truncado
    assert(calcular_presion_psi(2047) == 124);
    printf("[OK] Test Media Escala (124 PSI)\n");

    // Test 4: Manejo de fallas de hardware (Out of bounds)
    assert(calcular_presion_psi(5000) == 0xFFFFFFFF);
    printf("[OK] Test Tolerancia a Fallos\n");

    printf("TODOS LOS TESTS PASADOS CON EXITO.\n\n");
}

int main(void) {
    // Al ejecutar este ejecutable en tu consola de Windows/Linux,
    // validarás instantáneamente que la matemática de tu firmware es perfecta.
    ejecutar_tests_unitarios();
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Validación de Seguridad Lógica sin Hardware Físico.

El despachador industrial que estás diseñando desde cero manejará un elemento peligroso y a alta presión. No puedes permitirte descubrir un fallo de desbordamiento de variable (overflow) en el momento en que se esté llenando un cilindro de gas. Separar tu Súper Bucle de tu lógica de control te da superpoderes como desarrollador.

En este punto, la rutina que calcula la presión actual del tanque y corta las válvulas de suministro se probará miles de veces en tu computadora mediante inyección de lecturas de ADC simuladas (Test Unitarios), antes de siquiera tocar la memoria Flash de tu STM32 y conectar los módulos de relevadores. Si tu lógica falla en la inyección de datos críticos, el test detendrá la compilación. Esto es software de grado industrial.

📝 Resumen del Día

❓ Cuestionario de Autoevaluación

1. ¿Qué ocurriría si intentas ejecutar un script con un `assert()` directamente dentro de la memoria Flash del STM32 durante su operación normal?
Respuesta: Si la condición falla en un microcontrolador (bare-metal o con RTOS), la librería estándar de C invocará rutinariamente la función abort(). Al no tener un sistema operativo como Windows para mostrar el error, el microcontrolador entrará en un ciclo infinito de pánico (HardFault) o se reiniciará si el Watchdog está activo. Por ello, los Test Unitarios se compilan como un proyecto separado y se ejecutan exclusivamente en la computadora del desarrollador (PC) antes del despliegue.

2. Si una función se encarga de apagar una bomba de gas modificando un pin (ej. `GPIOB->ODR = 0;`), ¿cómo la podemos someter a un Test Unitario?
Respuesta: Tienes que refactorizar. En lugar de escribir en el registro GPIOB directamente, la función debe devolver un estado (ej. enum { BOMBA_ENCENDIDA, BOMBA_APAGADA }) basado en las lecturas inyectadas. Luego, en la capa superior de tu Súper Bucle, tomas ese valor devuelto y aplicas físicamente la acción al hardware. De esta forma, puedes probar la lógica de la decisión por separado.