Root cause of the dead data path (assoc/scan/RPC fine, zero data frames): esp-hosted 1.4.x is formally incompatible with IDF 5.5 (esp-hosted-mcu#47) and the factory C6 slave firmware was ancient (couldn't even answer a version RPC). Waveshare's examples pin 1.4.* — do not follow them. Fix: - host: espressif/esp_hosted ^2.12 (+ esp_wifi_remote 1.6) - slave: 2.12.11 network_adapter.bin embedded in the app (c6_ota.c streams it to the C6 over the SDIO RPC channel at boot when the reported version is < 2.x; ~10s, no wires, idempotent) - RAM diet for hosted 2.x's footprint (MEMPOOL_PREFER_SPIRAM, reduced WIFI_RMT buffers) — without it internal SRAM famine boot-loops in xTaskCreateStaticPinnedToCore before app_main - conservative 20MHz SDIO clock for first verified data path Verified on hardware: DHCP lease (even that healed), 8/8 pings to router and tower-of-joy at 1-5ms, WebSocket to the gateway connected, device registered at /devices as desklock-p4 with fw version. Also: wifi_diag.c L1 SoftAP diagnostic mode (DESKLOCK-DIAG) with review fixes, boot ping ladder in net.c, static-IP fallback, face_status() line, docs for the whole failure taxonomy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
88 lines
2.8 KiB
C
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) {
|
|
ESP_LOGI(TAG, "C6 fw already 2.x — 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);
|
|
}
|