Files
desklock/firmware/main/c6_ota.c
T
jpmschweitzerandClaude Fable 5 ca2144694a
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Test BLE-coex wedge hypothesis: C6 slave rebuilt with Bluetooth off
The wedge clock is immune to every network-layer change (~300s
regardless of bus width, clock, power-save, DHCP). A slave-side
periodic starver remains; the C6's BLE controller (BT_LE_SLEEP_ENABLE=y
in stock slave, shares the radio/RF arbiter with Wi-Fi) is the prime
suspect. DeskLock uses no Bluetooth, so the stock slave carries a
coexistence scheduler we can delete outright. Custom slave 2.12.12
(CONFIG_BT_ENABLED=n, ESP_HOSTED_CP_BT=n), OTA'd over SDIO. If the
metronome stops, BLE coexistence was starving the SDIO peripheral.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 02:24:31 +02:00

88 lines
2.8 KiB
C

/* One-shot ESP32-C6 slave firmware update over the SDIO RPC channel.
*
* The factory C6 firmware's data path never carried a frame (control RPC
* works; all data traffic dies). This streams a slave image built from the
* exact same esp_hosted version as the host driver, using the RPC OTA
* primitives that ride the (working) control path — no network involved.
*
* Remove the c6_ota_start() call from app_main once the radio is proven.
*/
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_hosted.h"
#include "desklock.h"
static const char *TAG = "c6ota";
extern int rpc_ota_begin(void);
extern int rpc_ota_write(uint8_t *ota_data, uint32_t ota_data_len);
extern int rpc_ota_end(void);
extern const uint8_t slave_bin_start[] asm("_binary_c6_slave_bin_start");
extern const uint8_t slave_bin_end[] asm("_binary_c6_slave_bin_end");
#define CHUNK 1400
static void log_c6_version(const char *when)
{
esp_hosted_coprocessor_fwver_t v = { 0 };
if (esp_hosted_get_coprocessor_fwversion(&v) == ESP_OK) {
ESP_LOGI(TAG, "C6 fw %s: %u.%u.%u", when,
(unsigned)v.major1, (unsigned)v.minor1, (unsigned)v.patch1);
} else {
ESP_LOGW(TAG, "C6 fw %s: version query failed", when);
}
}
static void c6_ota_task(void *arg)
{
(void)arg;
vTaskDelay(pdMS_TO_TICKS(8000)); /* let the hosted transport settle */
esp_hosted_coprocessor_fwver_t v = { 0 };
if (esp_hosted_get_coprocessor_fwversion(&v) == ESP_OK &&
v.major1 == 2 && v.minor1 == 12 && v.patch1 == 12) {
ESP_LOGI(TAG, "C6 fw already 2.12.12-btfree — no OTA needed");
vTaskDelete(NULL);
return;
}
log_c6_version("before");
size_t total = slave_bin_end - slave_bin_start;
ESP_LOGI(TAG, "C6 OTA start: %u bytes", (unsigned)total);
if (rpc_ota_begin() != 0) {
ESP_LOGE(TAG, "ota_begin FAILED (factory partition table may lack OTA slots)");
vTaskDelete(NULL);
return;
}
size_t off = 0;
while (off < total) {
uint32_t n = (total - off) < CHUNK ? (uint32_t)(total - off) : CHUNK;
if (rpc_ota_write((uint8_t *)(slave_bin_start + off), n) != 0) {
ESP_LOGE(TAG, "ota_write FAILED at %u/%u", (unsigned)off, (unsigned)total);
vTaskDelete(NULL);
return;
}
off += n;
if ((off / CHUNK) % 100 == 0) {
ESP_LOGI(TAG, "C6 OTA %u/%u", (unsigned)off, (unsigned)total);
}
}
if (rpc_ota_end() == 0) {
ESP_LOGI(TAG, "C6 OTA SUCCESS — restarting both chips");
vTaskDelay(pdMS_TO_TICKS(3000));
esp_restart();
} else {
ESP_LOGE(TAG, "ota_end FAILED");
}
vTaskDelete(NULL);
}
void c6_ota_start(void)
{
xTaskCreate(c6_ota_task, "c6ota", 6144, NULL, 4, NULL);
}