DÍA 208 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

Anatomía de una Petición HTTP POST

Una petición HTTP no es magia negra; es un estándar de texto plano estricto. Cuando quieres empujar datos nuevos hacia la nube (como subir una nueva venta de gas), utilizas el verbo POST. La estructura obligatoria consta de tres partes matemáticas:

  1. La Línea de Inicio (Start Line): POST /rutadelapi HTTP/1.1\r\n. Define qué quieres hacer, a dónde va, y el idioma a usar.
  2. Los Encabezados (Headers): Metadatos vitales. Host: (A qué dominio le hablas), Content-Type: (Le avisas que tu cuerpo será un JSON), y el más crítico de todos: Content-Length: (El peso exacto en bytes de tu JSON).
  3. La Línea en Blanco y el Cuerpo: El protocolo exige una línea en blanco absoluta \r\n\r\n para separar los Headers del JSON físico (El Body). Si omites esta línea, el servidor se quedará esperando el final de los encabezados hasta bloquearse.

El Talón de Aquiles: Content-Length

Si tu cadena JSON tiene 42 caracteres, el encabezado debe decir Content-Length: 42. Si te equivocas y pones 41, el servidor recortará el JSON (invalidándolo). Si pones 43, el servidor se quedará en estado de escucha "esperando que llegue ese último byte fantasma", provocando un Timeout del lado de AWS. En C, calcularemos este peso usando strlen() sobre nuestra cadena JSON antes de generar el paquete HTTP final.

ARQUITECTURA DE UN PAQUETE HTTP POST EN TEXTO PLANO Buffer de Transmisión (char buffer_tx[512]) POST /api/v1/ventas HTTP/1.1 \r\n Línea de Inicio Host: api.gas-corporativo.com \r\n Content-Type: application/json \r\n Content-Length: 42 \r\n Encabezados \r\n LA LÍNEA EN BLANCO (Obligatoria) { "ticket": 4082, "litros": 20.50 } Body (Cuerpo) strlen() del Body = 42 bytes

⚙️ Ejercicios Prácticos

Circuito: Seguimos trabajando de forma lógica. El texto que generaremos aquí es el bloque de bytes exacto que inyectaremos mañana a través del comando AT+CIPSEND del ESP32.

Ejercicio 1: Programaremos el "Ensamblador HTTP". Esta función recibirá el payload JSON que construimos ayer y lo "envolverá" dinámicamente con los Headers correspondientes, calculando el peso exacto para garantizar una transmisión perfecta sin bloqueos de servidor.


/**
 * @file http_builder.c
 * @brief Constructor determinista de Encabezados HTTP POST para API REST
 */

#include "stm32f401xe.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

// Dominio y Ruta de nuestro Backend en la Nube
#define HTTP_HOST "api.gas-corporativo.com"
#define HTTP_RUTA "/api/v1/ventas"

// =======================================================
// CONSTRUCTOR DEL PAQUETE HTTP MAESTRO
// =======================================================
/**
 * @brief  Envuelve un JSON en un paquete HTTP POST válido
 * @param  json_payload: El string JSON ya formateado (Día 207)
 * @param  buffer_http_salida: Arreglo donde se construirá el paquete final
 * @param  tamaño_maximo: Seguridad contra desbordamientos (Buffer Overflow)
 * @retval size_t: Cantidad total de bytes del paquete (0 si hubo error)
 */
size_t Generar_Paquete_HTTP_POST(const char* json_payload, char* buffer_http_salida, size_t tamaño_maximo) {
    
    // 1. Calculamos el "peso" estricto de la carga útil (Body)
    // strlen() no cuenta el carácter nulo '\0', cuenta los bytes ASCII reales.
    size_t peso_json = strlen(json_payload);
    
    // 2. Ensamblamos todo usando la función segura snprintf
    // Cuidado con la sintaxis: \r\n es obligatorio según el estándar HTTP/1.1
    // Observa los dos \r\n\r\n antes del %s final. ¡Es la separación sagrada!
    
    int bytes_escritos = snprintf(buffer_http_salida, tamaño_maximo,
        "POST %s HTTP/1.1\r\n"
        "Host: %s\r\n"
        "Content-Type: application/json\r\n"
        "Content-Length: %zu\r\n"
        "\r\n"          // <-- Línea en blanco separadora
        "%s",           // <-- El Cuerpo (JSON)
        HTTP_RUTA,
        HTTP_HOST,
        peso_json,
        json_payload
    );
    
    // 3. Validaciones de Seguridad MISRA-C
    if (bytes_escritos < 0) {
        // Error interno de formateo de C
        return 0; 
    }
    
    if ((size_t)bytes_escritos >= tamaño_maximo) {
        // Peligro: El buffer de transmisión es muy pequeño para el paquete.
        // El paquete se truncó a la mitad. El servidor lo rechazaría.
        // UART_Enviar_String("[HTTP] ERROR: Buffer Tx insuficiente.\r\n");
        return 0; 
    }
    
    // Si todo salió bien, devolvemos el tamaño EXACTO de todo el bloque 
    // (Headers + JSON) que enviaremos al ESP32.
    return (size_t)bytes_escritos;
}

// =======================================================
// PRUEBA DE ESCRITORIO (Cómo se vería en RAM)
// =======================================================
/*
void Test_Construccion_HTTP() {
    
    char mi_json[] = "{\"ticket\":4082,\"litros\":20.50}"; // Peso: 29 bytes
    
    // Asignamos un buffer estático generoso (512 bytes suele ser seguro 
    // para Headers HTTP básicos y JSONs pequeños).
    char buffer_tx[512]; 
    
    size_t tamaño_total = Generar_Paquete_HTTP_POST(mi_json, buffer_tx, sizeof(buffer_tx));
    
    if (tamaño_total > 0) {
        // Si imprimimos buffer_tx por UART para depurar, veríamos exactamente:
        // 
        // POST /api/v1/ventas HTTP/1.1
        // Host: api.gas-corporativo.com
        // Content-Type: application/json
        // Content-Length: 29
        // 
        // {"ticket":4082,"litros":20.50}
    }
}
*/
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Interconexión Nativa con APIs RESTful (Zero Middleware).

Muchas plataformas de hardware para aficionados confían ciegamente en librerías mágicas ocultas (`HTTPClient.h`) que hacen este proceso por detrás. El problema es que esas librerías consumen grandes cantidades de memoria RAM (Heap) gestionando buffers dinámicos, cookies y redirecciones web que un Despachador de Gas industrial jamás utilizará.

Al programar tu propio ensamblador de paquetes **HTTP POST en texto plano**, has eliminado toda dependencia de librerías de terceros (Zero Middleware). Le has enseñado a tu máquina a hablar nativamente con la nube de AWS utilizando únicamente la librería estándar de C (`stdio.h`). Controlas cada byte que entra y sale de la memoria de tu STM32. Si el día de mañana la gasolinera migra de AWS a Microsoft Azure, tu firmware embebido no requiere ser reescrito; solo modificas la constante `HTTP_HOST` y el sistema seguirá inyectando JSONs validados y calculados al milisegundo. Esto es control absoluto a nivel de protocolo.

📝 Resumen del Día