En ingeniería de hardware, un Test E2E significa validar el Happy Path (Camino Feliz) del usuario final utilizando la menor cantidad de abstracciones de software posible. No usamos RTOS, colas ni *Mutexes* aquí. Queremos que el hardware desnudo demuestre que puede soportar una transacción real sin colapsar por ruido eléctrico, caídas de tensión (Brownouts) o latencias de los buses.
El flujo comercial de tu Despachador de Gas LP obedece a una FSM estricta. Si intentas despachar antes de revisar la hermeticidad, explotas. Si cierras la válvula sin calcular el precio, pierdes dinero. El test de hoy navegará por estos 5 estados cronológicamente, usando el hardware físico real:
Puesto que no podemos desperdiciar 5 litros de gas real cada vez que compilamos el código, simularemos el despacho en el banco de pruebas. Utilizaremos agua presurizada o simplemente aire si no tienes la bomba conectada, y para el caudalímetro usaremos un Generador de Funciones (Onda Cuadrada a 5V) inyectando pulsos directamente al pin EXTI de la placa. La placa creerá que está despachando gas real.
Escribiremos la Tesis condensada en una Máquina de Estados. Usamos variables de Punto Fijo (Fixed-Point) heredadas de los días 298 y 300. Configuraremos la meta en 5.00 Litros. Si al cerrar la válvula y cobrar, el hardware imprimió el ticket sin resetearse, el Título de Ingeniería es tuyo.
/**
* @file e2e_transaction_test.c
* @brief Test Maestro E2E de la Tesis (Hardware Bare-Metal FSM)
*/
#include "stm32f4xx_hal.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
// Dependencias de Módulos (Días 273, 274, 298, 299, 300)
extern uint32_t Read_Pressure_mBar(void);
extern int16_t SPI_Read_PT100_DeciC(void);
extern uint32_t Get_API54_VCF(int16_t temp_deciC);
extern void Valve_Main_Open(void);
extern void Valve_Main_Close(void);
// Constantes Físicas y Financieras
#define TARGET_VOLUME_ML (5000U) // Despachar 5.000 Litros exactos
#define K_FACTOR_SCALED (100755U) // 100.755 Pulsos por Litro (Día 299)
#define PRICE_PER_LITER (1080U) // $10.80 MXN por Litro (Escalado x100)
// Estados del E2E Test
typedef enum {
STATE_IDLE,
STATE_PRECHECK,
STATE_DISPENSING,
STATE_SHUTDOWN,
STATE_REPORT
} E2E_State_t;
// Variables Globales de Estado
volatile uint32_t Flow_Pulses_Count = 0; // Incrementado vía Interrupción EXTI
E2E_State_t current_state = STATE_IDLE;
// =========================================================================
// INTERRUPCIÓN DEL CAUDALÍMETRO (MOCK O REAL)
// =========================================================================
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if(GPIO_Pin == GPIO_PIN_0) { // Asumiendo PA0
// En un escenario real, aquí va el filtro Anti-Glitch del Día 293
Flow_Pulses_Count++;
}
}
// =========================================================================
// MÁQUINA DE ESTADOS E2E (SUPER-LOOP PRINCIPAL)
// =========================================================================
void E2E_Run_Business_Flow(void) {
uint32_t current_vol_mL = 0;
int16_t current_temp = 0;
uint32_t current_vcf = 0;
printf("\r\n[SYS] INICIANDO TEST END-TO-END DE HARDWARE\r\n");
while (1) {
switch (current_state) {
// -----------------------------------------------------
case STATE_IDLE:
printf("[S0] Listo para despachar. Simulando autorización START...\r\n");
HAL_Delay(2000); // Simulamos espera del operario
Flow_Pulses_Count = 0; // Resetear totalizador
current_state = STATE_PRECHECK;
break;
// -----------------------------------------------------
case STATE_PRECHECK:
printf("[S1] Ejecutando Pre-Check de Seguridad...\r\n");
uint32_t pres_mbar = Read_Pressure_mBar();
current_temp = SPI_Read_PT100_DeciC();
printf(" - Presión: %lu mBar | Temp: %.1f C\r\n", pres_mbar, current_temp/10.0f);
// Si la presión es cero (fuga) o temperatura irracional, abortamos.
if (pres_mbar < 500) {
printf(" [X] ABORTO: Presión insuficiente. Revisar tubería.\r\n");
current_state = STATE_IDLE;
} else {
printf(" [V] Hardware OK. Abriendo válvula...\r\n");
Valve_Main_Open(); // Fuego real: 24V al relé
current_state = STATE_DISPENSING;
}
break;
// -----------------------------------------------------
case STATE_DISPENSING:
// En este estado, el inyector de pulsos o el agua está fluyendo.
// Calculamos el volumen compensado térmicamente (API 54)
current_temp = SPI_Read_PT100_DeciC(); // Temp en vivo
current_vcf = Get_API54_VCF(current_temp);
// Matemáticas de 64-bits (Punto Fijo)
uint64_t raw_mL = ((uint64_t)Flow_Pulses_Count * 1000000ULL) / K_FACTOR_SCALED;
current_vol_mL = (uint32_t)((raw_mL * current_vcf) / 10000ULL);
// Evaluar si alcanzamos la meta
if (current_vol_mL >= TARGET_VOLUME_ML) {
Valve_Main_Close(); // Apagado de emergencia hardware
printf("\r\n[S2] META ALCANZADA: %lu mL\r\n", current_vol_mL);
current_state = STATE_SHUTDOWN;
}
break;
// -----------------------------------------------------
case STATE_SHUTDOWN:
printf("[S3] Golpe de Ariete controlado. Retardo de asentamiento...\r\n");
HAL_Delay(1500); // Dar tiempo al relé para cortar el flujo físico
current_state = STATE_REPORT;
break;
// -----------------------------------------------------
case STATE_REPORT:
// Cálculos financieros finales usando enteros
// Costo = (Volumen_mL / 1000) * Price_per_Liter
uint32_t cost_cents = (current_vol_mL * PRICE_PER_LITER) / 1000U;
printf("\r\n======================================\r\n");
printf(" TICKET DE VENTA (E2E MOCK)\r\n");
printf("======================================\r\n");
printf(" Pulsos Físicos : %lu\r\n", Flow_Pulses_Count);
printf(" Temp Promedio : %.1f C\r\n", current_temp / 10.0f);
printf(" Vol Entregado : %.3f L (Compensado)\r\n", current_vol_mL / 1000.0f);
printf(" Total a Cobrar : $%.2f MXN\r\n", cost_cents / 100.0f);
printf("======================================\r\n");
printf("\r\n[V] TRANSACCIÓN EXITOSA. HARDWARE CERTIFICADO.\r\n");
// Reiniciar para la siguiente prueba
HAL_Delay(5000);
current_state = STATE_IDLE;
break;
}
}
}
Objetivo del día: Validación de Misión Crítica (Business Flow Validation) y Robustez Sistémica.
Un error clásico del estudiante es probar el relé un día, probar el ADC otro día, y asumir que juntos funcionarán bien. La termodinámica y el electromagnetismo no perdonan. En el instante exacto en que tu `Valve_Main_Close()` apaga la bobina de 24V de la electroválvula, se genera un pico inverso de voltaje (Flyback). Si tu diseño de PCB (Día 274) o tu cableado blindado (Día 296) fue deficiente, ese pico electromagnético reseteará el STM32 justo antes de calcular el "Ticket de Venta". El cliente se llevará 5 litros de gas gratis y tú tendrás una pantalla en blanco.
Al ejecutar el **Test End-to-End** automatizado, has orquestado una sinfonía de hardware. El procesador consultó la presión analógica, activó potencia industrial, recibió interrupciones de alta velocidad del caudalímetro, compensó la dilatación del líquido leyendo un sensor SPI de ultra-precisión, cortó el flujo a tiempo y calculó el saldo bancario usando matemáticas de 64 bits a prueba de desbordamientos. Todo esto sin colgarse, sin reiniciarse y sin intervención humana. Si tu placa completó este ciclo, el Hardware de tu tesis no es un "prototipo escolar"; es un Producto Comercial listo para ser empacado en cajas y vendido al mundo industrial.
STATE_REPORT valida que la arquitectura de software basada 100% en Enteros Escalados (Fixed-Point Math) es capaz de manejar transacciones de dinero real sin errores de truncamiento asociados al formato de coma flotante.