/* 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) { /* 2.12.11 factory image is good enough; custom slaves roll back */ 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); }