feat: ESP32-S3 OTA stack — partitions, Gitea checker, self-update, UART IO, display, Orin serial trigger (6 beads) #731
150
esp32s3/balance/main/ota_display.c
Normal file
150
esp32s3/balance/main/ota_display.c
Normal file
@ -0,0 +1,150 @@
|
||||
/* ota_display.c — OTA notification/progress UI on GC9A01 (bd-1yr8)
|
||||
*
|
||||
* Renders OTA state overlaid on the 240×240 round HUD display:
|
||||
* - BADGE: small dot on top-right when update available (idle state)
|
||||
* - UPDATE SCREEN: version compare, Update Balance / Update IO / Update All
|
||||
* - PROGRESS: arc around display perimeter + % + status text
|
||||
* - ERROR: red banner + "RETRY" prompt
|
||||
*
|
||||
* The display_draw_* primitives must be provided by the GC9A01 driver.
|
||||
* Actual SPI driver implementation is in a separate driver bead.
|
||||
*/
|
||||
|
||||
#include "ota_display.h"
|
||||
#include "gitea_ota.h"
|
||||
#include "version.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "ota_disp";
|
||||
|
||||
/* Display centre and radius for the 240×240 GC9A01 */
|
||||
#define CX 120
|
||||
#define CY 120
|
||||
#define RAD 110
|
||||
|
||||
/* ── Availability badge: 8×8 dot at top-right of display ── */
|
||||
static void draw_badge(bool balance_avail, bool io_avail)
|
||||
{
|
||||
uint16_t col = (balance_avail || io_avail) ? COL_ORANGE : COL_BG;
|
||||
display_fill_rect(200, 15, 12, 12, col);
|
||||
}
|
||||
|
||||
/* ── Progress arc: sweeps 0→360° proportional to progress% ── */
|
||||
static void draw_progress_arc(uint8_t pct, uint16_t color)
|
||||
{
|
||||
int end_deg = (int)(360 * pct / 100);
|
||||
display_draw_arc(CX, CY, RAD, 0, end_deg, 6, color);
|
||||
}
|
||||
|
||||
/* ── Status banner: 2 lines of text centred on display ── */
|
||||
static void draw_status(const char *line1, const char *line2,
|
||||
uint16_t fg, uint16_t bg)
|
||||
{
|
||||
display_fill_rect(20, 90, 200, 60, bg);
|
||||
if (line1 && line1[0])
|
||||
display_draw_string(CX - (int)(strlen(line1) * 6 / 2), 96,
|
||||
line1, fg, bg);
|
||||
if (line2 && line2[0])
|
||||
display_draw_string(CX - (int)(strlen(line2) * 6 / 2), 116,
|
||||
line2, fg, bg);
|
||||
}
|
||||
|
||||
/* ── Main render logic ── */
|
||||
void ota_display_update(void)
|
||||
{
|
||||
/* Determine dominant OTA state */
|
||||
ota_self_state_t self = g_ota_self_state;
|
||||
uart_ota_send_state_t io_s = g_uart_ota_state;
|
||||
|
||||
switch (self) {
|
||||
case OTA_SELF_DOWNLOADING:
|
||||
case OTA_SELF_VERIFYING:
|
||||
case OTA_SELF_APPLYING: {
|
||||
/* Balance self-update in progress */
|
||||
char pct_str[16];
|
||||
snprintf(pct_str, sizeof(pct_str), "%d%%", g_ota_self_progress);
|
||||
const char *phase = (self == OTA_SELF_VERIFYING) ? "Verifying..." :
|
||||
(self == OTA_SELF_APPLYING) ? "Applying..." :
|
||||
"Downloading...";
|
||||
draw_progress_arc(g_ota_self_progress, COL_BLUE);
|
||||
draw_status("Updating Balance", pct_str, COL_WHITE, COL_BG);
|
||||
ESP_LOGD(TAG, "balance OTA %s %d%%", phase, g_ota_self_progress);
|
||||
return;
|
||||
}
|
||||
case OTA_SELF_REBOOTING:
|
||||
draw_status("Update complete", "Rebooting...", COL_GREEN, COL_BG);
|
||||
return;
|
||||
case OTA_SELF_FAILED:
|
||||
draw_progress_arc(0, COL_RED);
|
||||
draw_status("Balance update", "FAILED RETRY?", COL_RED, COL_BG);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (io_s) {
|
||||
case UART_OTA_S_DOWNLOADING:
|
||||
draw_progress_arc(g_uart_ota_progress, COL_YELLOW);
|
||||
draw_status("Downloading IO", "firmware...", COL_WHITE, COL_BG);
|
||||
return;
|
||||
case UART_OTA_S_SENDING: {
|
||||
char pct_str[16];
|
||||
snprintf(pct_str, sizeof(pct_str), "%d%%", g_uart_ota_progress);
|
||||
draw_progress_arc(g_uart_ota_progress, COL_YELLOW);
|
||||
draw_status("Updating IO", pct_str, COL_WHITE, COL_BG);
|
||||
return;
|
||||
}
|
||||
case UART_OTA_S_DONE:
|
||||
draw_status("IO update done", "", COL_GREEN, COL_BG);
|
||||
return;
|
||||
case UART_OTA_S_FAILED:
|
||||
draw_progress_arc(0, COL_RED);
|
||||
draw_status("IO update", "FAILED RETRY?", COL_RED, COL_BG);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Idle — show badge if update available */
|
||||
bool bal_avail = g_balance_update.available;
|
||||
bool io_avail = g_io_update.available;
|
||||
draw_badge(bal_avail, io_avail);
|
||||
|
||||
if (bal_avail || io_avail) {
|
||||
/* Show available versions on display when idle */
|
||||
char verline[32];
|
||||
if (bal_avail) {
|
||||
snprintf(verline, sizeof(verline), "Bal v%s rdy",
|
||||
g_balance_update.version);
|
||||
draw_status(verline, io_avail ? "IO update rdy" : "",
|
||||
COL_ORANGE, COL_BG);
|
||||
} else if (io_avail) {
|
||||
snprintf(verline, sizeof(verline), "IO v%s rdy",
|
||||
g_io_update.version);
|
||||
draw_status(verline, "", COL_ORANGE, COL_BG);
|
||||
}
|
||||
} else {
|
||||
/* Clear OTA overlay area */
|
||||
display_fill_rect(20, 90, 200, 60, COL_BG);
|
||||
draw_badge(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Background display task (5 Hz) ── */
|
||||
static void ota_display_task(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
ota_display_update();
|
||||
}
|
||||
}
|
||||
|
||||
void ota_display_init(void)
|
||||
{
|
||||
xTaskCreate(ota_display_task, "ota_disp", 2048, NULL, 3, NULL);
|
||||
ESP_LOGI(TAG, "OTA display task started");
|
||||
}
|
||||
33
esp32s3/balance/main/ota_display.h
Normal file
33
esp32s3/balance/main/ota_display.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
/* ota_display.h — OTA notification UI on GC9A01 round LCD (bd-1yr8)
|
||||
*
|
||||
* GC9A01 240×240 round display via SPI (IO12 CS, IO11 DC, IO10 RST, IO9 BL).
|
||||
* Calls into display_draw_* primitives (provided by display driver layer).
|
||||
* This module owns the "OTA notification overlay" rendered over the HUD.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ota_self.h"
|
||||
#include "uart_ota.h"
|
||||
|
||||
/* ── Display primitives API (must be provided by display driver) ── */
|
||||
void display_fill_rect(int x, int y, int w, int h, uint16_t rgb565);
|
||||
void display_draw_string(int x, int y, const char *str, uint16_t fg, uint16_t bg);
|
||||
void display_draw_arc(int cx, int cy, int r, int start_deg, int end_deg,
|
||||
int thickness, uint16_t color);
|
||||
|
||||
/* ── Colour palette (RGB565) ── */
|
||||
#define COL_BG 0x0000u /* black */
|
||||
#define COL_WHITE 0xFFFFu
|
||||
#define COL_GREEN 0x07E0u
|
||||
#define COL_YELLOW 0xFFE0u
|
||||
#define COL_RED 0xF800u
|
||||
#define COL_BLUE 0x001Fu
|
||||
#define COL_ORANGE 0xFD20u
|
||||
|
||||
/* ── OTA display task: runs at 5 Hz, overlays OTA state on HUD ── */
|
||||
void ota_display_init(void);
|
||||
|
||||
/* Called from main loop or display task to render the OTA overlay */
|
||||
void ota_display_update(void);
|
||||
Loading…
x
Reference in New Issue
Block a user