diff --git a/esp32s3/balance/main/CMakeLists.txt b/esp32s3/balance/main/CMakeLists.txt index 2fd31d5..518a489 100644 --- a/esp32s3/balance/main/CMakeLists.txt +++ b/esp32s3/balance/main/CMakeLists.txt @@ -1,4 +1,22 @@ idf_component_register( - SRCS "main.c" "orin_serial.c" "vesc_can.c" + SRCS + "main.c" + "orin_serial.c" + "vesc_can.c" + "gitea_ota.c" + "ota_self.c" + "uart_ota.c" + "ota_display.c" INCLUDE_DIRS "." + REQUIRES + esp_wifi + esp_http_client + esp_https_ota + nvs_flash + app_update + mbedtls + cJSON + driver + freertos + esp_timer ) diff --git a/esp32s3/balance/main/main.c b/esp32s3/balance/main/main.c index c382c04..f8c4796 100644 --- a/esp32s3/balance/main/main.c +++ b/esp32s3/balance/main/main.c @@ -1,15 +1,11 @@ -/* main.c — ESP32-S3 BALANCE app_main (bd-66hx) - * - * Initializes Orin serial and VESC CAN TWAI, creates tasks: - * orin_rx — parse incoming Orin commands - * orin_tx — transmit queued serial frames - * vesc_rx — receive VESC CAN telemetry, proxy to Orin - * telem — periodic TELEM_STATUS to Orin @ 10 Hz - * drive — apply Orin drive commands to VESCs via CAN - */ +/* main.c — ESP32-S3 BALANCE app_main (bd-66hx + OTA beads) */ #include "orin_serial.h" #include "vesc_can.h" +#include "gitea_ota.h" +#include "ota_self.h" +#include "uart_ota.h" +#include "ota_display.h" #include "config.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -86,7 +82,10 @@ static void drive_task(void *arg) void app_main(void) { - ESP_LOGI(TAG, "ESP32-S3 BALANCE bd-66hx starting"); + ESP_LOGI(TAG, "ESP32-S3 BALANCE starting"); + + /* OTA rollback health check — must be called within OTA_ROLLBACK_WINDOW_S */ + ota_self_health_check(); /* Init peripherals */ orin_serial_init(); @@ -106,6 +105,10 @@ void app_main(void) xTaskCreate(telem_task, "telem", 2048, NULL, 5, NULL); xTaskCreate(drive_task, "drive", 2048, NULL, 8, NULL); + /* OTA subsystem — WiFi version checker + display overlay */ + gitea_ota_init(); + ota_display_init(); + ESP_LOGI(TAG, "all tasks started"); /* app_main returns — FreeRTOS scheduler continues */ } diff --git a/esp32s3/balance/main/orin_serial.c b/esp32s3/balance/main/orin_serial.c index 2cb3ef4..52de20b 100644 --- a/esp32s3/balance/main/orin_serial.c +++ b/esp32s3/balance/main/orin_serial.c @@ -1,17 +1,18 @@ -/* orin_serial.c — Orin↔ESP32-S3 serial protocol implementation (bd-66hx) - * - * Implements the binary framing protocol matching bd-wim1 (Orin side). - * CRC8-SMBUS: poly=0x07, init=0x00, covers LEN+TYPE+PAYLOAD bytes. - */ +/* orin_serial.c — Orin↔ESP32-S3 serial protocol (bd-66hx + bd-1s1s OTA cmds) */ #include "orin_serial.h" #include "config.h" +#include "gitea_ota.h" +#include "ota_self.h" +#include "uart_ota.h" +#include "version.h" #include "driver/uart.h" #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include +#include static const char *TAG = "orin"; @@ -206,6 +207,46 @@ static void dispatch_cmd(uint8_t type, const uint8_t *payload, uint8_t len, orin_send_ack(tx_q, type); break; + case CMD_OTA_CHECK: + /* Trigger an immediate Gitea version check */ + gitea_ota_check_now(); + orin_send_version_info(tx_q, OTA_TARGET_BALANCE, + BALANCE_FW_VERSION, + g_balance_update.available + ? g_balance_update.version : ""); + orin_send_version_info(tx_q, OTA_TARGET_IO, + IO_FW_VERSION, + g_io_update.available + ? g_io_update.version : ""); + orin_send_ack(tx_q, type); + break; + + case CMD_OTA_UPDATE: + if (len < 1u) { orin_send_nack(tx_q, type, ERR_BAD_LEN); break; } + { + uint8_t target = payload[0]; + bool triggered = false; + if (target == OTA_TARGET_IO || target == OTA_TARGET_BOTH) { + if (!uart_ota_trigger()) { + orin_send_nack(tx_q, type, + g_io_update.available ? ERR_OTA_BUSY : ERR_OTA_NO_UPDATE); + break; + } + triggered = true; + } + if (target == OTA_TARGET_BALANCE || target == OTA_TARGET_BOTH) { + if (!ota_self_trigger()) { + if (!triggered) { + orin_send_nack(tx_q, type, + g_balance_update.available ? ERR_OTA_BUSY : ERR_OTA_NO_UPDATE); + break; + } + } + } + orin_send_ack(tx_q, type); + } + break; + default: ESP_LOGW(TAG, "unknown cmd type=0x%02x", type); break; @@ -290,3 +331,24 @@ void orin_serial_tx_task(void *arg) } } } + +/* ── OTA telemetry helpers (bd-1s1s) ── */ + +void orin_send_ota_status(QueueHandle_t q, uint8_t target, + uint8_t state, uint8_t progress, uint8_t err) +{ + /* TELEM_OTA_STATUS: uint8 target, uint8 state, uint8 progress, uint8 err */ + uint8_t p[4] = {target, state, progress, err}; + enqueue(q, TELEM_OTA_STATUS, p, 4u); +} + +void orin_send_version_info(QueueHandle_t q, uint8_t target, + const char *current, const char *available) +{ + /* TELEM_VERSION_INFO: uint8 target, char current[16], char available[16] */ + uint8_t p[33]; + p[0] = target; + strncpy((char *)&p[1], current, 16); p[16] = '\0'; + strncpy((char *)&p[17], available ? available : "", 16); p[32] = '\0'; + enqueue(q, TELEM_VERSION_INFO, p, 33u); +} diff --git a/esp32s3/balance/main/orin_serial.h b/esp32s3/balance/main/orin_serial.h index d533794..6df1f0c 100644 --- a/esp32s3/balance/main/orin_serial.h +++ b/esp32s3/balance/main/orin_serial.h @@ -29,14 +29,27 @@ #define TELEM_STATUS 0x80u /* status @ 10 Hz */ #define TELEM_VESC_LEFT 0x81u /* VESC ID 56 telemetry @ 10 Hz */ #define TELEM_VESC_RIGHT 0x82u /* VESC ID 68 telemetry @ 10 Hz */ +#define TELEM_OTA_STATUS 0x83u /* OTA state + progress (bd-1s1s) */ +#define TELEM_VERSION_INFO 0x84u /* firmware version report (bd-1s1s) */ #define RESP_ACK 0xA0u #define RESP_NACK 0xA1u +/* ── OTA commands (Orin → ESP32, bd-1s1s) ── */ +#define CMD_OTA_CHECK 0x10u /* no payload: trigger Gitea version check */ +#define CMD_OTA_UPDATE 0x11u /* uint8 target: 0=balance, 1=io, 2=both */ + +/* ── OTA target constants ── */ +#define OTA_TARGET_BALANCE 0x00u +#define OTA_TARGET_IO 0x01u +#define OTA_TARGET_BOTH 0x02u + /* ── NACK error codes ── */ #define ERR_BAD_CRC 0x01u #define ERR_BAD_LEN 0x02u #define ERR_ESTOP_ACTIVE 0x03u #define ERR_DISARMED 0x04u +#define ERR_OTA_BUSY 0x05u +#define ERR_OTA_NO_UPDATE 0x06u /* ── Balance state (mirrored from TELEM_STATUS.balance_state) ── */ typedef enum { @@ -92,3 +105,9 @@ void orin_send_vesc(QueueHandle_t q, uint8_t telem_type, int16_t current_ma, uint16_t temp_c_x10); void orin_send_ack(QueueHandle_t q, uint8_t cmd_type); void orin_send_nack(QueueHandle_t q, uint8_t cmd_type, uint8_t err); + +/* OTA telemetry helpers (bd-1s1s) */ +void orin_send_ota_status(QueueHandle_t q, uint8_t target, + uint8_t state, uint8_t progress, uint8_t err); +void orin_send_version_info(QueueHandle_t q, uint8_t target, + const char *current, const char *available); diff --git a/esp32s3/io/main/CMakeLists.txt b/esp32s3/io/main/CMakeLists.txt index 46381b1..57d5760 100644 --- a/esp32s3/io/main/CMakeLists.txt +++ b/esp32s3/io/main/CMakeLists.txt @@ -1,4 +1,10 @@ idf_component_register( SRCS "main.c" "uart_ota_recv.c" INCLUDE_DIRS "." + REQUIRES + app_update + mbedtls + driver + freertos + esp_timer )