DÍA 058 DE 365

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

📖 Teoría a Estudiar

JSON sin Librerías: Concatenación Segura Bare-Metal

Cuando un sistema embebido necesita comunicarse con la nube, servidores web o aplicaciones móviles, el formato estándar de intercambio de datos es JSON (JavaScript Object Notation). El instinto inicial de un desarrollador web es importar una librería externa (como cJSON o Arduino_JSON) para serializar los datos.

En sistemas industriales, esto es un error letal. Las librerías JSON genéricas utilizan asignación dinámica de memoria (malloc y free) para construir árboles de datos. En un microcontrolador que opera 24/7, asignar y liberar memoria constantemente causa fragmentación del Heap. Tarde o temprano, la memoria RAM se agota, el puntero devuelve NULL y el equipo sufre un colapso (HardFault).

La solución profesional es tratar al JSON por lo que realmente es: una simple cadena de texto (String). Podemos construirla nosotros mismos usando la función estándar snprintf sobre un búfer estático preasignado, garantizando un comportamiento 100% determinista y libre de fugas de memoria.

CONSTRUCCIÓN ESTÁTICA DE JSON VARIABLES EN RAM ID: 9942 Litros: 15.50 snprintf() Formateo Seguro "{\"id\": %d, \"L\": %lu}" BÚFER ESTÁTICO (char buffer[128]) { " i d " : 9942 , ... "L": 15.50 }

Los 3 Pilares del C-String JSON

  1. Búfer Fijo: Declaramos un arreglo de char con un tamaño máximo conocido que vivirá en la sección `.bss` o en la pila (Stack). Evitamos malloc().
  2. Uso de snprintf: A diferencia de sprintf, la versión segura snprintf exige pasar el tamaño del búfer. Si el JSON supera el límite, la función trunca la cadena en lugar de sobrescribir memoria adyacente y causar un cuelgue.
  3. Escapado de Comillas: En C, las comillas dobles delimitan un string. Para insertar una comilla dentro del JSON, utilizamos el carácter de escape barra invertida: \".

⚙️ Ejercicios Prácticos

Ejercicio 1: Programa una función que tome los datos operativos de un despacho (operando con enteros de punto fijo para proteger la memoria FPU) y construya una cadena JSON válida, lista para ser enviada por UART o Wi-Fi.


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

// --- 1. CONFIGURACIÓN DEL BÚFER ---
// Dimensionar según la cantidad máxima de caracteres que tendrá el JSON.
#define TAMANO_BUFFER_JSON 256 

char json_payload[TAMANO_BUFFER_JSON];


// --- 2. FUNCIÓN DE SERIALIZACIÓN ---
void generar_ticket_json(uint32_t id_ticket, uint32_t ml_despachados, uint32_t centavos_cobrados) {
    
    // Convertimos de unidades mínimas enteras a representaciones decimales 
    // sin usar la lenta instrucción 'float' de la CPU.
    
    // Litros: 15500 ml -> 15 Litros, 500 ml
    uint32_t litros_enteros = ml_despachados / 1000;
    uint32_t litros_decimal = ml_despachados % 1000;
    
    // Dinero: 25075 centavos -> 250 Pesos, 75 centavos
    uint32_t pesos = centavos_cobrados / 100;
    uint32_t centavos = centavos_cobrados % 100;
    
    // Concatenación segura. Nota cómo las claves JSON llevan \"
    // y cómo formateamos los decimales rellenando ceros a la izquierda (%03lu, %02lu).
    int bytes_escritos = snprintf(json_payload, TAMANO_BUFFER_JSON,
        "{"
        "\"id\": %lu, "
        "\"equipo\": \"BOMBA_01\", "
        "\"volumen_L\": %lu.%03lu, "
        "\"total_MXN\": %lu.%02lu, "
        "\"estado\": \"OK\""
        "}",
        id_ticket, 
        litros_enteros, litros_decimal,
        pesos, centavos
    );
    
    // Verificamos si hubo truncamiento (Overflow)
    if (bytes_escritos >= TAMANO_BUFFER_JSON) {
        printf("ERROR: El JSON supero la capacidad del buffer.\n");
        // Manejar el error...
    } else {
        // Listo para enviar al módulo de telemetría (ESP32 / Modem LTE)
        printf("Carga lista para enviar (%d bytes):\n%s\n", bytes_escritos, json_payload);
    }
}


int main(void) {
    
    // Simulación del fin de un despacho
    uint32_t transaccion_actual = 8402;
    uint32_t sensor_flujo_ml = 20500;     // 20.500 Litros
    uint32_t calculo_precio_cent = 43050; // $430.50 MXN
    
    generar_ticket_json(transaccion_actual, sensor_flujo_ml, calculo_precio_cent);
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Telemetría y Conectividad IoT Industrial.

Un equipo despachador moderno no está aislado; necesita reportar ventas, cortes de caja y alarmas de presión a un servidor central. Si utilizas un módulo Wi-Fi auxiliar, deberás enviar la información desde tu microcontrolador principal estructurada en JSON. Al usar snprintf como aprendiste hoy, eliminas por completo la necesidad de importar pesadas librerías de terceros.

Esta decisión de arquitectura "Bare-Metal" asegura que tu dispensador de Gas LP pueda generar decenas de miles de tickets a lo largo de los años sin sufrir de fragmentación de memoria (el temido "Memory Leak"). Esto es lo que distingue un prototipo escolar (que requiere reiniciarse cada 3 días porque se congela) de un diseño de tesis de grado industrial que puede operar ininterrumpidamente durante años en campo.

📝 Resumen del Día

❓ Cuestionario de Autoevaluación

1. ¿Qué ocurriría si usamos sprintf() en lugar de snprintf() y nuestro texto JSON termina teniendo 300 caracteres en un búfer de 256?
Respuesta: Se producirá un "Buffer Overflow" (Desbordamiento de Búfer). La función sprintf escribirá los 44 caracteres sobrantes fuera de los límites del arreglo, sobrescribiendo otras variables adyacentes en la memoria RAM o corrompiendo la pila de retorno. Esto causará un fallo crítico (HardFault) o un comportamiento errático en tu máquina.

2. ¿Por qué usamos %02lu para imprimir los centavos en lugar de solo %lu?
Respuesta: Es el padding (relleno). Si el costo total termina en 5 centavos (ej. 200 pesos con 5 centavos), %lu imprimirá "200.5", lo cual matemáticamente representa 50 centavos, causando un grave error contable. Al usar %02lu, forzamos a que siempre se impriman al menos dos dígitos rellenando con ceros a la izquierda, resultando correctamente en "200.05".