#pragma once /* uart_ota.h — UART OTA protocol for Balance→IO firmware update (bd-21hv) * * Balance downloads io-firmware.bin from Gitea, then streams it to the IO * board over UART1 (GPIO17/18, 460800 baud) in 1 KB chunks with ACK. * * Protocol frame format (both directions): * [TYPE:1][SEQ:2 BE][LEN:2 BE][PAYLOAD:LEN][CRC8:1] * CRC8-SMBUS over TYPE+SEQ+LEN+PAYLOAD. * * Balance→IO: * OTA_BEGIN (0xC0) payload: uint32 total_size BE + uint8[32] sha256 * OTA_DATA (0xC1) payload: uint8[] chunk (up to 1024 bytes) * OTA_END (0xC2) no payload * OTA_ABORT (0xC3) no payload * * IO→Balance: * OTA_ACK (0xC4) payload: uint16 acked_seq BE * OTA_NACK (0xC5) payload: uint16 failed_seq BE + uint8 err_code * OTA_STATUS (0xC6) payload: uint8 state + uint8 progress% */ #include #include /* UART for Balance→IO OTA */ #include "driver/uart.h" #define UART_OTA_PORT UART_NUM_1 #define UART_OTA_BAUD 460800 #define UART_OTA_TX_GPIO 17 #define UART_OTA_RX_GPIO 18 #define OTA_UART_CHUNK_SIZE 1024 #define OTA_UART_ACK_TIMEOUT_MS 3000 #define OTA_UART_MAX_RETRIES 3 /* Frame type bytes */ #define UART_OTA_BEGIN 0xC0u #define UART_OTA_DATA 0xC1u #define UART_OTA_END 0xC2u #define UART_OTA_ABORT 0xC3u #define UART_OTA_ACK 0xC4u #define UART_OTA_NACK 0xC5u #define UART_OTA_STATUS 0xC6u /* NACK error codes */ #define OTA_ERR_BAD_CRC 0x01u #define OTA_ERR_WRITE 0x02u #define OTA_ERR_SIZE 0x03u typedef enum { UART_OTA_S_IDLE = 0, UART_OTA_S_DOWNLOADING, /* downloading from Gitea */ UART_OTA_S_SENDING, /* sending to IO board */ UART_OTA_S_DONE, UART_OTA_S_FAILED, } uart_ota_send_state_t; extern volatile uart_ota_send_state_t g_uart_ota_state; extern volatile uint8_t g_uart_ota_progress; /* Trigger IO firmware update. Uses g_io_update (from gitea_ota). * Downloads bin, then streams via UART. Returns false if busy or no update. */ bool uart_ota_trigger(void);