En C, un struct agrupa variables de diferentes tipos (ej. un ID, un volumen y un precio) en un solo bloque. Un Array de Structs lleva esto al siguiente nivel: crea una lista contigua de estos bloques en la memoria SRAM. Es el equivalente arquitectónico a un archivero donde cada cajón (el índice del arreglo) contiene una carpeta perfectamente estructurada (el struct).
Al definir Ticket_t base_datos[100]; de forma global o estática, el compilador secuestra inmediatamente la memoria necesaria durante el arranque del microcontrolador. Si cada ticket pesa 12 bytes, el compilador bloquea 1200 bytes físicos de SRAM de por vida. Esto garantiza que sin importar qué pase en tu software, el espacio para guardar los despachos del día siempre estará disponible y nunca se sobreescribirá accidentalmente.
Para gestionar esta base de datos, necesitamos una variable adicional de control: un índice que recuerde en qué "cajón" nos quedamos. Cada vez que el despachador finaliza una venta, guardamos los datos en base_datos[indice] y sumamos 1 al índice. Este enfoque convierte la memoria SRAM en un registro histórico ultrarrápido (Logger).
Ejercicio 1: Crea la estructura de datos para un Ticket usando matemática de punto fijo (cero floats). Luego instánciala en un arreglo global estático y construye la función de inserción que proteja la memoria contra desbordamientos (Out-of-Bounds).
#include <stdint.h>
#include <stdbool.h>
// --- 1. DEFINICIONES MAESTRAS ---
// Limitamos la BD a 100 ventas por turno.
// Si cada Ticket_t pesa 12 bytes, esto consumirá 1200 bytes de SRAM.
#define MAX_VENTAS_TURNO 100
typedef struct {
uint32_t id_ticket; // ID secuencial de la venta
uint32_t volumen_ml; // Volumen en mililitros (Punto fijo)
uint32_t total_centavos; // Dinero en centavos (Punto fijo)
} Ticket_t;
// --- 2. ASIGNACIÓN ESTÁTICA DE MEMORIA (DATA/BSS SEGMENT) ---
// El modificador 'static' encapsula el arreglo en este archivo.
// Inicializamos el arreglo en ceros implícitamente.
static Ticket_t bd_turno[MAX_VENTAS_TURNO];
// El cursor que controla en qué índice guardaremos la próxima venta
static uint16_t cursor_ventas = 0;
static uint32_t contador_global_folios = 0;
// --- 3. FUNCIÓN DE INSERCIÓN BARE-METAL ---
bool Registrar_Fin_De_Venta(uint32_t volumen_despachado, uint32_t dinero_calculado) {
// RED DE SEGURIDAD 1: Evitar el Buffer Overflow
// Si llegamos a 100, la memoria del turno está llena.
// Rechazamos el registro para evitar corromper la memoria contigua.
if (cursor_ventas >= MAX_VENTAS_TURNO) {
return false; // Error: Memoria Llena. Requiere Corte de Turno.
}
// RED DE SEGURIDAD 2: Filtrado lógico (Failsafe)
// Un volumen de cero no constituye una venta válida.
if (volumen_despachado == 0) {
return false;
}
// Incrementar el folio global
contador_global_folios++;
// Guardar los datos en el "cajón" actual usando el operador punto (.)
bd_turno[cursor_ventas].id_ticket = contador_global_folios;
bd_turno[cursor_ventas].volumen_ml = volumen_despachado;
bd_turno[cursor_ventas].total_centavos = dinero_calculado;
// Avanzar el cursor para la siguiente venta
cursor_ventas++;
return true; // Registro exitoso
}
// --- 4. FUNCIÓN DE CORTE DE TURNO ---
void Reiniciar_Turno(void) {
// En C no existe "Delete". Para borrar la base de datos,
// simplemente reiniciamos el cursor a 0. La próxima venta
// sobrescribirá físicamente la posición 0 antigua.
cursor_ventas = 0;
}
Objetivo del día: Historial de Transacciones (Logger Estático).
Con esta implementación, tu Despachador de Gas LP es capaz de sobrevivir a cortes de red (Wi-Fi). Si el módulo ESP32 pierde la conexión con el servidor central durante horas, la lógica del núcleo STM32 seguirá facturando y acumulando los despachos en este arreglo. Cuando el internet regrese, el ESP32 simplemente consultará esta base de datos iterando desde [0] hasta [cursor_ventas - 1] para sincronizar todas las transacciones sin haber perdido una sola gota de información.
(MAX_SIZE - 1). Escribir fuera de los límites es la vulnerabilidad más letal en lenguaje C.