Skip to content

Factory Update Actions

The factory_update_actions module implements the recovery and update operations executed by the factory partition application. It is the operational core of the recovery menu: it flashes new firmware or UI resources from an SD card, switches between OTA application partitions, and restores the OTA data sector so that a power-cycle from inside the recovery environment always resumes the correct application slot.

This module runs on every supported board variant. The logic is identical across all boards; only display driver includes and layout scaling constants (FONT_WIDTH, BTN_CIRCLE_R, SCREEN_WIDTH) differ between implementations. Each board hosts its own copy inside boards/<board>/Factory/main/main.c.

The factory application is a standalone ESP-IDF application stored in a dedicated factory flash partition, entirely separate from the main firmware and independent of LVGL. The module hierarchy inside the factory app is:

Factory_Application_&_Bootloader
└── factory_app / factory_app_core
├── factory_app_entry – app_main, hardware init
├── factory_menu_system – menu rendering, navigation
├── factory_update_actions ← THIS MODULE
├── factory_visual_feedback – draw_progress, draw_result, draw_flashing_screen
├── factory_snapshot – GPIO0 screen-capture helper (optional)
└── factory_input_dispatch – dispatch_button, touch_hint_hit_test

first call

menu ready

optional

optional

app_main

(factory_app_entry)

restore_otadata_from_backup

(startup - before anything else)

probe_sd_files

(refresh SD availability flags)

factory_menu_system

(user selection)

execute_selected_action

action_boot_partition

boot_partition

action_sd_update

(firmware flash)

action_sd_update_res

(resources flash)

ESP-IDF OTA API

esp_ota_begin / write / end

esp_ota_set_boot_partition

ESP-IDF Flash API

esp_flash_read / write / erase

esp_partition_write

SD Card

esp3dfw.bin → .ok / .bad

ui_resources.bin → .ok / .bad

factory_visual_feedback

draw_progress / draw_result

draw_flashing_screen

factory_snapshot

(ENABLE_SNAPSHOT only)


The module is divided into three functional areas, each documented in full detail separately.

Implements restore_otadata_from_backup. Called once at startup — before display, SD, or menu initialization — it reads a backup copy of the ESP32 OTA data sector from a reserved pre-partition-table flash address (0xB000), validates it with a 32-bit magic number (0xAA55AA55), and writes it back to the real OTA data location (0x10000/0x11000). This ensures that power-cycling from within the recovery environment resumes the correct main application slot without user intervention.

Key highlights:

  • The backup is written by the main firmware (in esp444.cpp) before it switches the boot partition to factory.
  • Requires CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED=y because 0xB000 is below the first partition table entry.
  • After a successful restore, the backup sector is immediately erased to prevent repeated restores on subsequent boots.
  • Returns false (no-op) when no valid backup is present — normal cold boots skip silently.

Implements probe_sd_files, action_sd_update, and action_sd_update_res.

  • probe_sd_files — Mounts the SD card and checks for esp3dfw.bin and ui_resources.bin. Sets sd_has_fw and sd_has_res boolean flags that the menu uses to show/hide SD-availability indicators. Called on startup and after returning from any failed update.

  • action_sd_update(target_label) — Full OTA firmware flash: opens esp3dfw.bin, validates the file size against the target partition, calls esp_ota_begin → loops esp_ota_write in 1 KB chunks (updating draw_progress each iteration) → calls esp_ota_end, sets the boot partition, renames the file to esp3dfw.ok, and restarts. On any failure, aborts via esp_ota_abort and renames to esp3dfw.bad.

  • action_sd_update_res — Resources partition flash: opens ui_resources.bin, reads its 16-byte build header ("ESP3" + 12-char variant string) for variant mismatch logging, erases the entire ui_resources data partition, then writes in 1 KB chunks via esp_partition_write. On success renames to ui_resources.ok and restarts; on failure renames to ui_resources.bad.

Implements boot_partition, action_boot_partition, and execute_selected_action.

  • boot_partition(label) — Low-level helper: locates a partition by label with esp_partition_find_first, calls esp_ota_set_boot_partition, then esp_restart.

  • action_boot_partition(label) — UI wrapper: shows a status line (e.g. “Booting app0…”), calls boot_partition, and shows an error via show_status if the partition was not found.

  • execute_selected_action — The central dispatch switch: reads the selected menu item’s menu_action_t value and routes to the correct action function.


typedef enum {
MENU_ACTION_BOOT_APP0, // Switch boot partition → app0, restart
MENU_ACTION_BOOT_APP1, // Switch boot partition → app1, restart
MENU_ACTION_SD_UPDATE_APP0, // Flash esp3dfw.bin → app0, restart
MENU_ACTION_SD_UPDATE_APP1, // Flash esp3dfw.bin → app1, restart
MENU_ACTION_SD_UPDATE_RES, // Flash ui_resources.bin → ui_resources partition, restart
} menu_action_t;

MENU_ACTION_BOOT_APP1 and MENU_ACTION_SD_UPDATE_APP1 are only shown when the app1 partition is detected at runtime by esp_partition_find_first.


ConstantValuePurpose
OTADATA_OFFSET0x10000Real OTA data sector address
OTADATA_SECTOR_SIZE0x1000 (4 KB)Flash erase unit
OTADATA_ENTRY_SIZE32 bytesSize of one OTA data entry
OTADATA_BACKUP_OFFSET0xB000Pre-partition-table backup address
BACKUP_MAGIC_OFFSET0x40Offset within backup sector for the magic word
BACKUP_MAGIC0xAA55AA55Validates that a real backup exists
FW_FILENAME/sdcard/esp3dfw.binFirmware binary on SD
FW_OK_FILENAME/sdcard/esp3dfw.okRename target on success
FW_BAD_FILENAME/sdcard/esp3dfw.badRename target on failure
RES_FILENAME/sdcard/ui_resources.binResources binary on SD
RES_OK_FILENAME/sdcard/ui_resources.okRename target on success
RES_BAD_FILENAME/sdcard/ui_resources.badRename target on failure

⚠️ OTADATA_BACKUP_OFFSET must exactly match the value used in the main firmware (esp444.cpp). A mismatch silently prevents restore from working.

CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED=y

The factory app intentionally writes to flash addresses below the partition table (0xB000). This flag is mandatory for the OTA data restore to function.


factory_visual_feedbackESP-IDF OTA APISD card (sdcard_mount / fopen)execute_selected_actionUserfactory_visual_feedbackESP-IDF OTA APISD card (sdcard_mount / fopen)execute_selected_actionUserloop[1 KB chunks until EOF]Select "SD → app0" or "SD → app1"sdcard_mount()ESP_OKfopen("/sdcard/esp3dfw.bin", "rb")FILE* fw_filedraw_flashing_screen()esp_ota_begin(partition, fw_size, &handle)fread(buf, 1, 1024, fw_file)esp_ota_write(handle, buf, len)draw_progress(written * 100 / fw_size)esp_ota_end(handle)esp_ota_set_boot_partition(app0/app1)rename("esp3dfw.bin" → "esp3dfw.ok")draw_result(true)esp_restart() factory_visual_feedbackui_resources partitionSD cardaction_sd_update_resfactory_visual_feedbackui_resources partitionSD cardaction_sd_update_resloop[1 KB chunks until EOF]sdcard_mount()fopen("/sdcard/ui_resources.bin", "rb")fread(bin_hdr, 1, 16) - log "ESP3" + variant tagdraw_flashing_screen()esp_partition_erase_range(0, partition→size)fread(buf, 1, 1024)esp_partition_write(offset, buf, len)draw_progress(written * 100 / res_size)rename("ui_resources.bin" → "ui_resources.ok")draw_result(true)esp_restart()

OTA Data Restore (restore_otadata_from_backup)

Section titled “OTA Data Restore (restore_otadata_from_backup)”

No / read error

Yes

Yes - OTA was factory-default

No

app_main starts

esp_flash_read(NULL, &magic,

0xB040, 4)

magic ==

0xAA55AA55?

return false - skip restore

Read entry1 @ 0xB000

Read entry2 @ 0xB020

(32 bytes each)

Both entries

all 0xFF?

Skip partition write

esp_flash_erase_region

(0x10000, 0x1000)

(0x11000, 0x1000)

esp_flash_write entry1 → 0x10000

esp_flash_write entry2 → 0x11000

esp_flash_erase_region

(0xB000, 0x1000)

Clear backup

return true


All supported boards share identical update logic. Differences are limited to the display driver include and one IO expander initialization call for SD card chip-select:

BoardLCD DriverSD CSNotes
esp32_2432s028rILI9341GPIOCore functions present; app1-slot items hidden (single-slot)
esp32_3248s035cST7796GPIOFull module
esp32_3248s035rST7796GPIOFull module
esp32s3_4827s043cILI9485GPIOFull module
esp32s3_8048_touch_lcd_7ST7262 (RGB)CH422G EXIO3CH422G I²C IO expander init required before any SD access
esp32s3_8048s043cST7262 (RGB)GPIOFull module
esp32s3_8048s050cST7262 (RGB)GPIOFull module
esp32s3_bzm_tft35_gt911ST7796GPIOFull module
esp32s3_hmi43v3RM68120 (i80)GPIOFull module
esp32s3_zx3d50ce02s_usrc_4832ST7796 i80GPIOFull module
pibot_pendant_v1_0ILI9341GPIOFull module + custom bootloader hook

DocumentRelationship
factory_update_actions_otadata.mdSub-module: OTA data backup and restore
factory_update_actions_sd_flash.mdSub-module: SD card firmware and resources flash operations
factory_update_actions_dispatch.mdSub-module: boot partition management and action dispatch