From a5ac67d999356a92d583a6a061d61254a0a278f7 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 15 Feb 2026 19:25:06 -0800 Subject: [PATCH 1/8] don't block the thread while waiting for wifi flash erase --- firmware/ext/atwinc1500/spi_flash/source/spi_flash.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/ext/atwinc1500/spi_flash/source/spi_flash.cpp b/firmware/ext/atwinc1500/spi_flash/source/spi_flash.cpp index 4b41087444..7f159a26bd 100755 --- a/firmware/ext/atwinc1500/spi_flash/source/spi_flash.cpp +++ b/firmware/ext/atwinc1500/spi_flash/source/spi_flash.cpp @@ -687,7 +687,7 @@ sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz) uint32 t; t = GetTickCount(); #endif - M2M_PRINT("\r\n>Start erasing...\r\n"); + M2M_INFO(">Start erasing..."); for(i = u32Offset; i < (u32Sz +u32Offset); i += (16*FLASH_PAGE_SZ)) { ret += spi_flash_write_enable(); @@ -696,14 +696,15 @@ sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz) ret += spi_flash_read_status_reg(&tmp); do { + nm_bsp_sleep(10); if(ret != M2M_SUCCESS) goto ERR; ret += spi_flash_read_status_reg(&tmp); }while(tmp & 0x01); } - M2M_PRINT("Done\r\n"); + M2M_INFO("Done!"); #ifdef PROFILING - M2M_PRINT("#Erase time = %f sec\n", (GetTickCount()-t)/1000.0); + M2M_INFO("#Erase time = %f sec\n", (GetTickCount()-t)/1000.0); #endif ERR: return ret; From ebf90ea3ca36a76a001233ab9976b1088cc96159 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 15 Feb 2026 19:25:25 -0800 Subject: [PATCH 2/8] add a region for WiFi update buffer --- firmware/hw_layer/mmc_card.h | 3 +++ firmware/hw_layer/mmc_card_attach.cpp | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/firmware/hw_layer/mmc_card.h b/firmware/hw_layer/mmc_card.h index cfdff1d125..d9004ab7ef 100644 --- a/firmware/hw_layer/mmc_card.h +++ b/firmware/hw_layer/mmc_card.h @@ -11,6 +11,8 @@ #include "buffered_writer.h" +#include + BaseBlockDevice* initializeMmcBlockDevice(); void stopMmcBlockDevice(); @@ -45,5 +47,6 @@ namespace sd_mem { FATFS* getFs(); FIL* getLogFileFd(); SdLogBufferWriter& getLogBuffer(); +std::array& getWifiUpdateBuffer(); } // namespace sd_mem #endif // EFI_PROD_CODE diff --git a/firmware/hw_layer/mmc_card_attach.cpp b/firmware/hw_layer/mmc_card_attach.cpp index f9e7142f69..daab26c2da 100644 --- a/firmware/hw_layer/mmc_card_attach.cpp +++ b/firmware/hw_layer/mmc_card_attach.cpp @@ -36,13 +36,14 @@ struct { FATFS fs; FIL file; SdLogBufferWriter logBuffer; + std::array wifiUpdateBuffer; } usedPart; - static_assert(sizeof(usedPart) <= 2048); + static_assert(sizeof(usedPart) <= 4096); // Fill the struct out to a full MPU region - uint8_t padding[2048 - sizeof(usedPart)]; -} mmcCardCacheControlledStorage SDMMC_MEMORY(2048); + uint8_t padding[4096 - sizeof(usedPart)]; +} mmcCardCacheControlledStorage SDMMC_MEMORY(4096); namespace sd_mem { FATFS* getFs() { @@ -56,6 +57,10 @@ FIL* getLogFileFd() { SdLogBufferWriter& getLogBuffer() { return mmcCardCacheControlledStorage.usedPart.logBuffer; } + +std::array& getWifiUpdateBuffer() { + return mmcCardCacheControlledStorage.usedPart.wifiUpdateBuffer; +} } // namespace sd_mem #endif // !EFI_BOOTLOADER @@ -132,8 +137,8 @@ BaseBlockDevice* initializeMmcBlockDevice() { #if defined(STM32H7XX) && !EFI_BOOTLOADER { void* base = &mmcCardCacheControlledStorage; - static_assert(sizeof(mmcCardCacheControlledStorage) == 2048); - uint32_t size = MPU_RASR_SIZE_2K; + static_assert(sizeof(mmcCardCacheControlledStorage) == 4096); + uint32_t size = MPU_RASR_SIZE_4K; mpuConfigureRegion( MPU_REGION_5, From b64025f550068d5d2ee14fe98032371304ad7f7d Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 15 Feb 2026 19:26:21 -0800 Subject: [PATCH 3/8] implement WiFi firmware update from SD --- firmware/console/binary_log/sd_file_log.cpp | 8 +- firmware/hw_layer/mmc_card_mount.cpp | 44 +++-- firmware/net/net.mk | 2 +- firmware/net/wifi_firmware_updater.cpp | 194 -------------------- firmware/net/wifi_sd_firmware_updater.cpp | 152 +++++++++++++++ firmware/net/wifi_sd_firmware_updater.h | 11 ++ firmware/net/wifi_socket.cpp | 5 + 7 files changed, 207 insertions(+), 209 deletions(-) delete mode 100644 firmware/net/wifi_firmware_updater.cpp create mode 100644 firmware/net/wifi_sd_firmware_updater.cpp create mode 100644 firmware/net/wifi_sd_firmware_updater.h diff --git a/firmware/console/binary_log/sd_file_log.cpp b/firmware/console/binary_log/sd_file_log.cpp index 7308197d92..3ecaf5e226 100644 --- a/firmware/console/binary_log/sd_file_log.cpp +++ b/firmware/console/binary_log/sd_file_log.cpp @@ -243,7 +243,13 @@ static void sdTriggerLogger() { #endif /* EFI_TOOTH_LOGGER */ } -static THD_WORKING_AREA(sdCardLoggerStack, 3 * UTILITY_THREAD_STACK_SIZE); // MMC monitor thread +#if EFI_WIFI +// WiFi needs extra stack, as WiFi firmware update happens from here +static THD_WORKING_AREA(sdCardLoggerStack, 6 * UTILITY_THREAD_STACK_SIZE); +#else // not EFI_WIFI +static THD_WORKING_AREA(sdCardLoggerStack, 4 * UTILITY_THREAD_STACK_SIZE); +#endif + static THD_FUNCTION(sdCardLoggerThread, arg) { (void)arg; chRegSetThreadName("MMC Card Logger"); diff --git a/firmware/hw_layer/mmc_card_mount.cpp b/firmware/hw_layer/mmc_card_mount.cpp index 2f6f17d096..8b4913f5a5 100644 --- a/firmware/hw_layer/mmc_card_mount.cpp +++ b/firmware/hw_layer/mmc_card_mount.cpp @@ -7,6 +7,10 @@ #include "ff.h" #include "mass_storage_init.h" +#if EFI_WIFI +#include "wifi_sd_firmware_updater.h" +#endif + static bool fs_ready = false; #if HAL_USE_USB_MSD @@ -27,19 +31,38 @@ bool mountSdFilesystem() { // if no card, don't try to mount FS if (!cardBlockDevice) { +#if EFI_WIFI + signalWifiSdUpdateComplete(); +#endif return false; } + // Mount filesystem immediately (before USB wait) + if (f_mount(sd_mem::getFs(), "/", 1) != FR_OK) { + efiPrintf("SD card failed to mount filesystem"); + stopMmcBlockDevice(); +#if EFI_WIFI + signalWifiSdUpdateComplete(); +#endif + return false; + } + +#if EFI_WIFI + // Check for WiFi firmware update/dump trigger files on SD card + tryUpdateWifiFirmwareFromSd(); + tryDumpWifiFirmwareToSd(); + signalWifiSdUpdateComplete(); +#endif + #if HAL_USE_USB_MSD // Wait for the USB stack to wake up, or a 5 second timeout, whichever occurs first msg_t usbResult = usbConnectedSemaphore.wait(TIME_MS2I(5000)); bool hasUsb = usbResult == MSG_OK; - // If we have a device AND USB is connected, mount the card to USB, otherwise - // mount the null device and try to mount the filesystem ourselves - if (cardBlockDevice && hasUsb) { - // Mount the real card to USB + // If USB is connected, unmount filesystem and hand card to USB + if (hasUsb) { + f_mount(nullptr, "/", 0); attachMsdSdCard(cardBlockDevice); // At this point we're done: don't try to write files ourselves @@ -47,15 +70,10 @@ bool mountSdFilesystem() { } #endif - // We were able to connect the SD card, mount the filesystem - if (f_mount(sd_mem::getFs(), "/", 1) == FR_OK) { - efiPrintf("SD card mounted!"); - fs_ready = true; - return true; - } else { - efiPrintf("SD card failed to mount filesystem"); - return false; - } + // No USB — filesystem already mounted, proceed with logging + efiPrintf("SD card mounted!"); + fs_ready = true; + return true; } void unmountSdFilesystem() { diff --git a/firmware/net/net.mk b/firmware/net/net.mk index ffb32e552b..0311a8dd8d 100644 --- a/firmware/net/net.mk +++ b/firmware/net/net.mk @@ -1,6 +1,6 @@ ALLCPPSRC += \ $(PROJECT_DIR)/net/wifi_socket.cpp \ - # $(PROJECT_DIR)/net/wifi_firmware_updater.cpp \ + $(PROJECT_DIR)/net/wifi_sd_firmware_updater.cpp ALLINC += \ $(PROJECT_DIR)/net \ diff --git a/firmware/net/wifi_firmware_updater.cpp b/firmware/net/wifi_firmware_updater.cpp deleted file mode 100644 index 6eb990988e..0000000000 --- a/firmware/net/wifi_firmware_updater.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "spi_flash/include/spi_flash.h" - -#include "usbcfg.h" - -static bool isBigEndian() { - uint32_t test = 0x11223344; - uint8_t* pTest = reinterpret_cast(&test); - return pTest[0] == 0x11; -} - -static uint32_t fromNetwork32(uint32_t from) { - static const bool be = isBigEndian(); - if (be) { - return from; - } else { - uint8_t* pFrom = reinterpret_cast(&from); - uint32_t to; - to = pFrom[0]; - to <<= 8; - to |= pFrom[1]; - to <<= 8; - to |= pFrom[2]; - to <<= 8; - to |= pFrom[3]; - return to; - } -} - -static uint16_t fromNetwork16(uint16_t from) { - static bool be = isBigEndian(); - if (be) { - return from; - } else { - uint8_t* pFrom = reinterpret_cast(&from); - uint16_t to; - to = pFrom[0]; - to <<= 8; - to |= pFrom[1]; - return to; - } -} - -static uint32_t toNetwork32(uint32_t to) { - return fromNetwork32(to); -} - -static uint16_t toNetwork16(uint16_t to) { - return fromNetwork16(to); -} - -typedef struct __attribute__((__packed__)) { - uint8_t command; - uint32_t address; - uint32_t arg1; - uint16_t payloadLength; - - // payloadLenght bytes of data follows... -} UartPacket; - -static const int MAX_PAYLOAD_SIZE = 256; - -#define CMD_READ_FLASH 0x01 -#define CMD_WRITE_FLASH 0x02 -#define CMD_ERASE_FLASH 0x03 -#define CMD_MAX_PAYLOAD_SIZE 0x50 -#define CMD_HELLO 0x99 - -static int readch() { - uint8_t buf; - int ret = chnReadTimeout(&SDU1, &buf, 1, TIME_MS2I(1)); - - if (ret == 0) { - return -1; - } else { - return (int)buf; - } -} - -static void receivePacket(UartPacket* pkt, uint8_t* payload) { - // Read command - uint8_t* p = reinterpret_cast(pkt); - uint16_t l = sizeof(UartPacket); - while (l > 0) { - int c = readch(); - if (c == -1) - continue; - *p++ = c; - l--; - } - - // Convert parameters from network byte order to cpu byte order - pkt->address = fromNetwork32(pkt->address); - pkt->arg1 = fromNetwork32(pkt->arg1); - pkt->payloadLength = fromNetwork16(pkt->payloadLength); - - // Read payload - l = pkt->payloadLength; - while (l > 0) { - int c = readch(); - if (c == -1) - continue; - *payload++ = c; - l--; - } -} - -// Allocated statically so the compiler can tell us -// about the amount of used RAM -static UartPacket pkt; -static uint8_t payload[MAX_PAYLOAD_SIZE]; - -static void serialPrint(const uint8_t* data, size_t length) { - chnWriteTimeout(&SDU1, data, length, TIME_MS2I(100)); -} - -static void serialPrintStr(const char* str) { - size_t len = strlen(str); - serialPrint(reinterpret_cast(str), len); -} - -struct WifiUpdaterThread : public ThreadController<4096> { - WifiUpdaterThread() - : ThreadController("WifiPump", NORMALPRIO - 10) {} - void ThreadTask() override { - if (M2M_SUCCESS != m2m_wifi_download_mode()) { - return; - } - - auto flashSize = spi_flash_get_size(); - (void)flashSize; - - // int ret = spi_flash_erase(0, FLASH_SECTOR_SZ); - //(void)ret; - - usb_serial_start(); - - while (true) { - while (!is_usb_serial_ready()) { - chThdSleepMilliseconds(1); - } - - receivePacket(&pkt, payload); - - if (pkt.command == CMD_HELLO) { - if (pkt.address == 0x11223344 && pkt.arg1 == 0x55667788) { - serialPrintStr("v10000"); - } - } - - if (pkt.command == CMD_MAX_PAYLOAD_SIZE) { - uint16_t res = toNetwork16(MAX_PAYLOAD_SIZE); - serialPrint(reinterpret_cast(&res), sizeof(res)); - } - - if (pkt.command == CMD_READ_FLASH) { - uint32_t address = pkt.address; - uint32_t len = pkt.arg1; - if (spi_flash_read(payload, address, len) != M2M_SUCCESS) { - serialPrintStr("ER"); - } else { - serialPrint(payload, len); - serialPrintStr("OK"); - } - } - - if (pkt.command == CMD_WRITE_FLASH) { - uint32_t address = pkt.address; - uint32_t len = pkt.payloadLength; - if (spi_flash_write(payload, address, len) != M2M_SUCCESS) { - serialPrintStr("ER"); - } else { - serialPrintStr("OK"); - } - } - - if (pkt.command == CMD_ERASE_FLASH) { - uint32_t address = pkt.address; - uint32_t len = pkt.arg1; - if (spi_flash_erase(address, len) != M2M_SUCCESS) { - serialPrintStr("ER"); - // serialPrintStr("OK"); - } else { - serialPrintStr("OK"); - } - } - } - } -}; - -static WifiUpdaterThread wifiUpdater; - -void startWifiUpdater() { - wifiUpdater.start(); -} diff --git a/firmware/net/wifi_sd_firmware_updater.cpp b/firmware/net/wifi_sd_firmware_updater.cpp new file mode 100644 index 0000000000..aa21e67edc --- /dev/null +++ b/firmware/net/wifi_sd_firmware_updater.cpp @@ -0,0 +1,152 @@ +#include "pch.h" + +#if EFI_WIFI + +#include "ff.h" +#include "mmc_card.h" +#include "spi_flash/include/spi_flash.h" +#include "driver/include/m2m_wifi.h" +#include "programmer/programmer.h" + +static chibios_rt::BinarySemaphore sdUpdateDoneSemaphore(/* taken =*/true); + +void signalWifiSdUpdateComplete() { + sdUpdateDoneSemaphore.signal(); +} + +void waitForWifiSdUpdateComplete() { + sdUpdateDoneSemaphore.wait(); +} + +void tryUpdateWifiFirmwareFromSd() { + FILINFO finfo; + if (f_stat("atwinc1500.bin", &finfo) != FR_OK) { + efiPrintf("WiFi: atwinc1500.bin not found, skipping update."); + return; // no file, nothing to do + } + + Timer t; + t.reset(); + + efiPrintf("WiFi: found atwinc1500.bin (%lu bytes), updating...", (uint32_t)finfo.fsize); + + if (m2m_wifi_download_mode() != M2M_SUCCESS) { + efiPrintf("WiFi: failed to enter download mode"); + return; + } + + FIL* fd = sd_mem::getLogFileFd(); // reuse DMA-safe FIL + if (f_open(fd, "atwinc1500.bin", FA_READ) != FR_OK) { + efiPrintf("WiFi: failed to open file"); + m2m_wifi_deinit(nullptr); + return; + } + + uint32_t fileSize = finfo.fsize; + uint32_t eraseSize = ((fileSize + FLASH_SECTOR_SZ - 1) / FLASH_SECTOR_SZ) * FLASH_SECTOR_SZ; + + efiPrintf("WiFi: erasing %lu bytes", eraseSize); + if (spi_flash_erase(0, eraseSize) != M2M_SUCCESS) { + efiPrintf("WiFi: erase failed"); + f_close(fd); + m2m_wifi_deinit(nullptr); + return; + } + + auto& wifiUpdateBuffer = sd_mem::getWifiUpdateBuffer(); + + uint32_t offset = 0; + while (offset < fileSize) { + UINT bytesRead; + if (f_read(fd, wifiUpdateBuffer.data(), wifiUpdateBuffer.size(), &bytesRead) != FR_OK || bytesRead == 0) { + efiPrintf("WiFi: read error at offset %lu", offset); + f_close(fd); + m2m_wifi_deinit(nullptr); + return; + } + + if (spi_flash_write(wifiUpdateBuffer.data(), offset, bytesRead) != M2M_SUCCESS) { + efiPrintf("WiFi: write failed at offset %lu", offset); + f_close(fd); + m2m_wifi_deinit(nullptr); + return; + } + + offset += bytesRead; + efiPrintf("WiFi: wrote %lu / %lu", offset, fileSize); + } + + f_close(fd); + + m2m_wifi_deinit(nullptr); + + // Delete .done if it exists from a previous update, then rename + f_unlink("atwinc1500.done"); + f_rename("atwinc1500.bin", "atwinc1500.done"); + efiPrintf("WiFi: firmware update complete in %.1f sec!", t.getElapsedSeconds()); +} + +void tryDumpWifiFirmwareToSd() { + if (f_stat("atwinc1500.read", nullptr) != FR_OK) { + return; // no trigger file, nothing to do + } + + Timer t; + t.reset(); + + efiPrintf("WiFi: found atwinc1500.read, dumping firmware..."); + + if (m2m_wifi_download_mode() != M2M_SUCCESS) { + efiPrintf("WiFi: failed to enter download mode"); + m2m_wifi_deinit(nullptr); + return; + } + + uint32_t flashSize = programmer_get_flash_size(); + efiPrintf("WiFi: flash size %lu bytes", flashSize); + + FIL* fd = sd_mem::getLogFileFd(); + f_unlink("atwinc1500_dump.bin"); + if (f_open(fd, "atwinc1500_dump.bin", FA_CREATE_NEW | FA_WRITE) != FR_OK) { + efiPrintf("WiFi: failed to create dump file"); + m2m_wifi_deinit(nullptr); + return; + } + + auto& wifiUpdateBuffer = sd_mem::getWifiUpdateBuffer(); + + uint32_t offset = 0; + while (offset < flashSize) { + uint32_t chunkSize = flashSize - offset; + if (chunkSize > wifiUpdateBuffer.size()) { + chunkSize = wifiUpdateBuffer.size(); + } + + if (spi_flash_read(wifiUpdateBuffer.data(), offset, chunkSize) != M2M_SUCCESS) { + efiPrintf("WiFi: read failed at offset %lu", offset); + f_close(fd); + m2m_wifi_deinit(nullptr); + return; + } + + UINT bytesWritten; + if (f_write(fd, wifiUpdateBuffer.data(), chunkSize, &bytesWritten) != FR_OK || bytesWritten != chunkSize) { + efiPrintf("WiFi: file write error at offset %lu", offset); + f_close(fd); + m2m_wifi_deinit(nullptr); + return; + } + + offset += chunkSize; + efiPrintf("WiFi: dumped %lu / %lu", offset, flashSize); + } + + f_close(fd); + m2m_wifi_deinit(nullptr); + + f_unlink("atwinc1500.read"); + + efiPrintf("WiFi: firmware dump complete in %.1f sec!", t.getElapsedSeconds()); +} + +#endif // EFI_WIFI diff --git a/firmware/net/wifi_sd_firmware_updater.h b/firmware/net/wifi_sd_firmware_updater.h new file mode 100644 index 0000000000..a2f1c7f031 --- /dev/null +++ b/firmware/net/wifi_sd_firmware_updater.h @@ -0,0 +1,11 @@ +#pragma once + +void tryUpdateWifiFirmwareFromSd(); +void tryDumpWifiFirmwareToSd(); + +// Signal that SD-based WiFi firmware operations are complete. +// Must be called even if no update was performed, to unblock WiFi init. +void signalWifiSdUpdateComplete(); + +// Block until SD-based WiFi firmware operations are complete (or skipped). +void waitForWifiSdUpdateComplete(); diff --git a/firmware/net/wifi_socket.cpp b/firmware/net/wifi_socket.cpp index a45d17a603..a4b90d6941 100644 --- a/firmware/net/wifi_socket.cpp +++ b/firmware/net/wifi_socket.cpp @@ -3,6 +3,7 @@ #if EFI_WIFI #include "wifi_socket.h" +#include "wifi_sd_firmware_updater.h" #include "thread_controller.h" #include "driver/include/m2m_wifi.h" #include "socket/include/socket.h" @@ -230,6 +231,10 @@ class WifiHelperThread : public ThreadController<4096> { WifiHelperThread() : ThreadController("WiFi", WIFI_THREAD_PRIORITY) {} void ThreadTask() override { + // Wait for any SD-based WiFi firmware update to finish + // before we try to initialize the WiFi module + waitForWifiSdUpdateComplete(); + if (!initWifi()) { return; } From d8ec3183b9d6f7b531c31bb0c3f2dcbfe73618f8 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 15 Feb 2026 21:38:56 -0800 Subject: [PATCH 4/8] print percent rather than just bytes --- firmware/net/wifi_sd_firmware_updater.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/firmware/net/wifi_sd_firmware_updater.cpp b/firmware/net/wifi_sd_firmware_updater.cpp index aa21e67edc..56291a7417 100644 --- a/firmware/net/wifi_sd_firmware_updater.cpp +++ b/firmware/net/wifi_sd_firmware_updater.cpp @@ -56,6 +56,7 @@ void tryUpdateWifiFirmwareFromSd() { auto& wifiUpdateBuffer = sd_mem::getWifiUpdateBuffer(); uint32_t offset = 0; + int lastPct = -1; while (offset < fileSize) { UINT bytesRead; if (f_read(fd, wifiUpdateBuffer.data(), wifiUpdateBuffer.size(), &bytesRead) != FR_OK || bytesRead == 0) { @@ -73,7 +74,11 @@ void tryUpdateWifiFirmwareFromSd() { } offset += bytesRead; - efiPrintf("WiFi: wrote %lu / %lu", offset, fileSize); + int pct = offset * 100 / fileSize; + if (pct / 5 != lastPct / 5) { + efiPrintf("WiFi: writing %d%% (%lu / %lu)", pct, offset, fileSize); + lastPct = pct; + } } f_close(fd); @@ -116,6 +121,7 @@ void tryDumpWifiFirmwareToSd() { auto& wifiUpdateBuffer = sd_mem::getWifiUpdateBuffer(); uint32_t offset = 0; + int lastPct = -1; while (offset < flashSize) { uint32_t chunkSize = flashSize - offset; if (chunkSize > wifiUpdateBuffer.size()) { @@ -138,7 +144,11 @@ void tryDumpWifiFirmwareToSd() { } offset += chunkSize; - efiPrintf("WiFi: dumped %lu / %lu", offset, flashSize); + int pct = offset * 100 / flashSize; + if (pct / 5 != lastPct / 5) { + efiPrintf("WiFi: dumping %d%% (%lu / %lu)", pct, offset, flashSize); + lastPct = pct; + } } f_close(fd); From 40501257a9c9aa6c10b8ead94e574e7c77da26c4 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 15 Feb 2026 21:39:24 -0800 Subject: [PATCH 5/8] don't strand the user if the filesystem is bad --- firmware/hw_layer/mmc_card_mount.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/firmware/hw_layer/mmc_card_mount.cpp b/firmware/hw_layer/mmc_card_mount.cpp index 8b4913f5a5..549e8d9e9b 100644 --- a/firmware/hw_layer/mmc_card_mount.cpp +++ b/firmware/hw_layer/mmc_card_mount.cpp @@ -38,19 +38,19 @@ bool mountSdFilesystem() { } // Mount filesystem immediately (before USB wait) - if (f_mount(sd_mem::getFs(), "/", 1) != FR_OK) { - efiPrintf("SD card failed to mount filesystem"); - stopMmcBlockDevice(); + bool mounted = f_mount(sd_mem::getFs(), "/", 1) == FR_OK; + + if (mounted) { #if EFI_WIFI - signalWifiSdUpdateComplete(); + // Check for WiFi firmware update/dump trigger files on SD card + tryUpdateWifiFirmwareFromSd(); + tryDumpWifiFirmwareToSd(); #endif - return false; + } else { + efiPrintf("SD card failed to mount filesystem"); } #if EFI_WIFI - // Check for WiFi firmware update/dump trigger files on SD card - tryUpdateWifiFirmwareFromSd(); - tryDumpWifiFirmwareToSd(); signalWifiSdUpdateComplete(); #endif @@ -60,9 +60,11 @@ bool mountSdFilesystem() { bool hasUsb = usbResult == MSG_OK; - // If USB is connected, unmount filesystem and hand card to USB if (hasUsb) { - f_mount(nullptr, "/", 0); + // Unmount filesystem (if mounted) before handing card to USB + if (mounted) { + f_mount(nullptr, "/", 0); + } attachMsdSdCard(cardBlockDevice); // At this point we're done: don't try to write files ourselves @@ -70,6 +72,11 @@ bool mountSdFilesystem() { } #endif + if (!mounted) { + stopMmcBlockDevice(); + return false; + } + // No USB — filesystem already mounted, proceed with logging efiPrintf("SD card mounted!"); fs_ready = true; From 8803be0daaad5ef231152496981a50a02945a98e Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Mon, 16 Feb 2026 03:00:54 -0800 Subject: [PATCH 6/8] defer USB entirely until the update is done --- firmware/hw_layer/mmc_card_mount.cpp | 39 ++++++++++++------- .../stm32/serial_over_usb/usbconsole.cpp | 10 +++++ .../ports/stm32/serial_over_usb/usbconsole.h | 1 + 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/firmware/hw_layer/mmc_card_mount.cpp b/firmware/hw_layer/mmc_card_mount.cpp index 549e8d9e9b..808ad3ed80 100644 --- a/firmware/hw_layer/mmc_card_mount.cpp +++ b/firmware/hw_layer/mmc_card_mount.cpp @@ -6,6 +6,7 @@ #include "ff.h" #include "mass_storage_init.h" +#include "usbconsole.h" #if EFI_WIFI #include "wifi_sd_firmware_updater.h" @@ -22,6 +23,9 @@ void onUsbConnectedNotifyMmcI() { #endif /* HAL_USE_USB_MSD */ bool mountSdFilesystem() { + Timer t; + t.reset(); + auto cardBlockDevice = initializeMmcBlockDevice(); #if EFI_TUNER_STUDIO @@ -33,11 +37,15 @@ bool mountSdFilesystem() { if (!cardBlockDevice) { #if EFI_WIFI signalWifiSdUpdateComplete(); +#endif +#if HAL_USE_USB_MSD + // No SD card - connect USB bus now so serial and INI drive still work + connectUsbBus(); #endif return false; } - // Mount filesystem immediately (before USB wait) + // Mount filesystem temporarily for WiFi update check bool mounted = f_mount(sd_mem::getFs(), "/", 1) == FR_OK; if (mounted) { @@ -46,6 +54,8 @@ bool mountSdFilesystem() { tryUpdateWifiFirmwareFromSd(); tryDumpWifiFirmwareToSd(); #endif + // Unmount — we'll either hand the card to USB or re-mount for logging + f_mount(nullptr, "/", 0); } else { efiPrintf("SD card failed to mount filesystem"); } @@ -55,32 +65,35 @@ bool mountSdFilesystem() { #endif #if HAL_USE_USB_MSD - // Wait for the USB stack to wake up, or a 5 second timeout, whichever occurs first + // Now connect the USB bus - the host will enumerate and see the real SD card + connectUsbBus(); + + // Wait for the USB enumeration, or a 5 second timeout, whichever occurs first msg_t usbResult = usbConnectedSemaphore.wait(TIME_MS2I(5000)); bool hasUsb = usbResult == MSG_OK; if (hasUsb) { - // Unmount filesystem (if mounted) before handing card to USB - if (mounted) { - f_mount(nullptr, "/", 0); - } + // Mount the real card to USB attachMsdSdCard(cardBlockDevice); // At this point we're done: don't try to write files ourselves return false; } + + // Reclaim the card back from USB so that it doesn't get double mounted + attachMsdSdCard(nullptr); #endif - if (!mounted) { - stopMmcBlockDevice(); + // We were able to connect the SD card, mount the filesystem + if (f_mount(sd_mem::getFs(), "/", 1) == FR_OK) { + efiPrintf("SD card mounted!"); + fs_ready = true; + return true; + } else { + efiPrintf("SD card failed to mount filesystem"); return false; } - - // No USB — filesystem already mounted, proceed with logging - efiPrintf("SD card mounted!"); - fs_ready = true; - return true; } void unmountSdFilesystem() { diff --git a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp index ffe2be9f1d..5d01865de8 100644 --- a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp +++ b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp @@ -42,11 +42,21 @@ void usb_serial_start() { chThdSleepMilliseconds(250); #endif /* EFI_SKIP_USB_DISCONNECT */ usbStart(serusbcfg.usbp, &usbcfg); + + // Don't connect the bus yet if MSD is enabled - the SD card thread + // will connect after mounting the card so the host sees real media + // from the start, rather than swapping the null device later. +#if !HAL_USE_USB_MSD usbConnectBus(serusbcfg.usbp); +#endif isUsbSerialInitialized = true; } +void connectUsbBus() { + usbConnectBus(serusbcfg.usbp); +} + bool is_usb_serial_ready() { return isUsbSerialInitialized && SDU1.config->usbp->state == USB_ACTIVE; } diff --git a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h index 171b1d9af8..e0412e27e9 100644 --- a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h +++ b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h @@ -12,6 +12,7 @@ extern "C" { #endif /* __cplusplus */ void usb_serial_start(void); +void connectUsbBus(void); bool is_usb_serial_ready(void); #ifdef __cplusplus From f0295de3359b3c7abf9c83edc147ca22641e984d Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Mon, 16 Feb 2026 03:10:26 -0800 Subject: [PATCH 7/8] use a semaphore so everything happens on the original thread --- firmware/hw_layer/mmc_card_mount.cpp | 11 ++++------ .../stm32/serial_over_usb/usbconsole.cpp | 22 +++++++++++++------ .../ports/stm32/serial_over_usb/usbconsole.h | 15 +++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/firmware/hw_layer/mmc_card_mount.cpp b/firmware/hw_layer/mmc_card_mount.cpp index 808ad3ed80..b368487986 100644 --- a/firmware/hw_layer/mmc_card_mount.cpp +++ b/firmware/hw_layer/mmc_card_mount.cpp @@ -39,8 +39,8 @@ bool mountSdFilesystem() { signalWifiSdUpdateComplete(); #endif #if HAL_USE_USB_MSD - // No SD card - connect USB bus now so serial and INI drive still work - connectUsbBus(); + // No SD card - allow USB to enumerate so serial and INI drive still work + allowUsbEnumeration(); #endif return false; } @@ -65,8 +65,8 @@ bool mountSdFilesystem() { #endif #if HAL_USE_USB_MSD - // Now connect the USB bus - the host will enumerate and see the real SD card - connectUsbBus(); + // Allow USB to enumerate - the host will see the real SD card + allowUsbEnumeration(); // Wait for the USB enumeration, or a 5 second timeout, whichever occurs first msg_t usbResult = usbConnectedSemaphore.wait(TIME_MS2I(5000)); @@ -80,9 +80,6 @@ bool mountSdFilesystem() { // At this point we're done: don't try to write files ourselves return false; } - - // Reclaim the card back from USB so that it doesn't get double mounted - attachMsdSdCard(nullptr); #endif // We were able to connect the SD card, mount the filesystem diff --git a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp index 5d01865de8..25d76c1466 100644 --- a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp +++ b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.cpp @@ -16,6 +16,12 @@ static bool isUsbSerialInitialized = false; +#if HAL_USE_USB_MSD +// When MSD is enabled, defer USB bus connection until the SD card thread +// has finished any WiFi firmware updates and is ready to present media. +static chibios_rt::BinarySemaphore usbEnumerationAllowed(/* taken =*/true); +#endif + /** * start USB serial using hard-coded communications pins (see comments inside the code) */ @@ -43,18 +49,20 @@ void usb_serial_start() { #endif /* EFI_SKIP_USB_DISCONNECT */ usbStart(serusbcfg.usbp, &usbcfg); - // Don't connect the bus yet if MSD is enabled - the SD card thread - // will connect after mounting the card so the host sees real media - // from the start, rather than swapping the null device later. -#if !HAL_USE_USB_MSD - usbConnectBus(serusbcfg.usbp); +#if HAL_USE_USB_MSD + // Wait for the SD card thread to signal that it's ready + usbEnumerationAllowed.wait(); #endif + usbConnectBus(serusbcfg.usbp); + isUsbSerialInitialized = true; } -void connectUsbBus() { - usbConnectBus(serusbcfg.usbp); +void allowUsbEnumeration() { +#if HAL_USE_USB_MSD + usbEnumerationAllowed.signal(); +#endif } bool is_usb_serial_ready() { diff --git a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h index e0412e27e9..651fe70c24 100644 --- a/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h +++ b/firmware/hw_layer/ports/stm32/serial_over_usb/usbconsole.h @@ -7,14 +7,9 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +void usb_serial_start(); +bool is_usb_serial_ready(); -void usb_serial_start(void); -void connectUsbBus(void); -bool is_usb_serial_ready(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +#if HAL_USE_USB_MSD +void allowUsbEnumeration(); +#endif From 9daeac44abea35a61e53952eca64b736871ce7f9 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Mon, 2 Mar 2026 01:45:35 -0800 Subject: [PATCH 8/8] unblock firmware WiFI as it never tries to update --- firmware/bootloader/openblt_chibios/openblt_net.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/bootloader/openblt_chibios/openblt_net.cpp b/firmware/bootloader/openblt_chibios/openblt_net.cpp index e7ecd51a89..7ade70f8e0 100644 --- a/firmware/bootloader/openblt_chibios/openblt_net.cpp +++ b/firmware/bootloader/openblt_chibios/openblt_net.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "wifi_socket.h" +#include "wifi_sd_firmware_updater.h" #include "thread_controller.h" #include "socket/include/socket.h" @@ -40,6 +41,10 @@ void NetDeferredInit() { didInit = true; + // In the bootloader the SD-card WiFi firmware update never runs, so unblock + // WifiHelperThread (which waits on this semaphore before it calls initWifi()). + signalWifiSdUpdateComplete(); + initWifi(); wifiInitFinisher.startThread();