DÍA 031 DE 365

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

📖 Teoría Explícita: Punteros a Funciones y Matriz de Transición

1. ¿Qué es un Puntero a Función?

Hasta hoy, sabías que un puntero guarda la dirección de memoria SRAM de una variable (como uint32_t). Pero el código compilado de tus funciones también vive en alguna parte: en la memoria Flash. Un Puntero a Función es una variable que guarda la dirección hexadecimal exacta donde comienza el código máquina de una función específica. Permite invocar rutinas dinámicamente sin usar declaraciones if-else.

2. Estructura de Transición de Estados

Una Máquina de Estados Finitos (FSM) profesional se define como una tabla rígida (Matriz). Cada fila de esta tabla responde a una ecuación lógica simple: Si estoy en el Estado X, y sucede el Evento Y, debo pasar al Estado Z y ejecutar la Función W.

3. Seguridad y Memoria Constante

La belleza de este enfoque en el desarrollo de hardware (bare-metal) es que esta matriz completa se declara como const. Al alojarse exclusivamente en la memoria Flash (sección .rodata), no consumes un solo byte de RAM para tu motor lógico, liberando recursos para búferes de comunicación o el histórico de tickets.

ARQUITECTURA FSM: MATRIZ DE TRANSICIÓN Estado Actual Evento (Input) Siguiente Estado Acción (*Puntero) ST_REPOSO EV_BOTON_START ST_AUTENTICANDO Iniciar_Autorizacion() ST_AUTENTICANDO EV_TOKEN_OK ST_DESPACHANDO Abrir_Valvulas() ST_DESPACHANDO EV_ALCANZA_META ST_REPOSO Corte_Seguro() Motor Dinámico: Itera el arreglo y dispara la dirección de memoria

⚙️ Ejercicios Prácticos: Código C Estricto

Ejercicio 1: Reestructuraremos el control de flujo de tu sistema. En lugar de un switch-case infinito, declararemos nuestra tabla en la memoria Flash (ROM) e implementaremos un buscador (Dispatcher) que cruzará los datos y llamará la función adecuada en 1 sola iteración limpia.


#include <stdint.h>

// --- 1. DEFINICIONES DE ENUMS ESTRICTOS ---
typedef enum {
    ST_REPOSO       = 0x10,
    ST_AUTENTICANDO = 0x20,
    ST_DESPACHANDO  = 0x30
} Estado_e;

typedef enum {
    EV_NINGUNO        = 0x00,
    EV_BOTON_START    = 0x01,
    EV_TOKEN_OK       = 0x02,
    EV_ALCANZA_META   = 0x03
} Evento_e;

// --- 2. PUNTERO A FUNCIÓN Y ESTRUCTURA (CORE FSM) ---
// Define 'Accion_t' como un puntero a una función que no recibe ni retorna nada.
typedef void (*Accion_t)(void);

typedef struct {
    Estado_e  estado_actual;
    Evento_e  evento_recibido;
    Estado_e  siguiente_estado;
    Accion_t  funcion_accion;    // La dirección del código a ejecutar
} Transicion_t;


// --- 3. FUNCIONES DE ACCIÓN (Callbacks) ---
void Acción_Solicitar_Token(void) {
    // Mandar petición por UART al ESP32
}

void Acción_Activar_Solenoides(void) {
    // GPIO High a los relevadores de las válvulas
}

void Acción_Cierre_Flujo(void) {
    // GPIO Low y cálculo final de metrología
}


// --- 4. LA MATRIZ DE TRANSICIÓN (Anclada en Flash) ---
const Transicion_t FSM_Tabla_Gas[] = {
    {ST_REPOSO,       EV_BOTON_START,  ST_AUTENTICANDO, Acción_Solicitar_Token},
    {ST_AUTENTICANDO, EV_TOKEN_OK,     ST_DESPACHANDO,  Acción_Activar_Solenoides},
    {ST_DESPACHANDO,  EV_ALCANZA_META, ST_REPOSO,       Acción_Cierre_Flujo}
};

// Macro para calcular cuántas filas tiene la tabla dinámicamente
#define NUM_TRANSICIONES (sizeof(FSM_Tabla_Gas) / sizeof(FSM_Tabla_Gas[0]))


// --- 5. EL MOTOR (DISPATCHER) ---
Estado_e Estado_Actual_Sistema = ST_REPOSO;

void FSM_Procesar_Evento(Evento_e evento_nuevo) {
    if (evento_nuevo == EV_NINGUNO) return;
    
    // Iteramos por la tabla para encontrar la coincidencia
    for(uint8_t i = 0; i < NUM_TRANSICIONES; i++) {
        if(FSM_Tabla_Gas[i].estado_actual == Estado_Actual_Sistema && 
           FSM_Tabla_Gas[i].evento_recibido == evento_nuevo) {
            
            // Verificación de seguridad Anti-HardFault (Puntero nulo)
            if(FSM_Tabla_Gas[i].funcion_accion != 0x00) {
                // LLAMADA DINÁMICA A LA FUNCIÓN
                FSM_Tabla_Gas[i].funcion_accion();
            }
            
            // Actualizar estado
            Estado_Actual_Sistema = FSM_Tabla_Gas[i].siguiente_estado;
            break;
        }
    }
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Arquitectura Modular de Control Industrial.

Con este diseño arquitectónico, el núcleo de tu Despachador (el Motor Dispatcher) jamás tendrá que ser modificado de nuevo. Si en la próxima semana decides agregar un estado de "Falla de Flujómetro" o una transición para el "Botón de Paro de Emergencia", el código del main no cambia en lo absoluto. Únicamente añades una nueva línea a la tabla FSM_Tabla_Gas. Esto permite que tu hardware escale masivamente sin comprometer la limpieza ni la seguridad del flujo de control principal. Además, alojar la lógica estructural en la Flash te preserva valiosa SRAM.

📝 Resumen del Día