# HG changeset patch # User heinrichsweikamp # Date 1771318177 -3600 # Node ID a7ed4eb3142b4c41cf61094913ea3a85f09aac80 # Parent eceb5cb2a8e3ca4d2be198c65f1b977fe1d636bc Exit to Correct Menu when Exiting from 'Reset Menu' Submenus. Write Progress and Success Messages when Flashing the Bootloader. Only Show 'Flash Bootloader' if the Available Bootloader is Different from the Existing One. (mikeller) diff -r eceb5cb2a8e3 -r a7ed4eb3142b Discovery/Inc/firmwareEraseProgram.h --- a/Discovery/Inc/firmwareEraseProgram.h Mon Feb 16 21:33:04 2026 +0100 +++ b/Discovery/Inc/firmwareEraseProgram.h Tue Feb 17 09:49:37 2026 +0100 @@ -39,6 +39,47 @@ /* Exported types ------------------------------------------------------------*/ #define HARDWAREDATA_ADDRESS (0x08000000 + 0x0000A040) + +/* Flash memory layout - Base address of Flash sectors Bank 1 */ +#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */ +#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */ + +/* Base address of Flash sectors Bank 2 */ +#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* Base @ of Sector 12, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_13 ((uint32_t)0x08104000) /* Base @ of Sector 13, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_14 ((uint32_t)0x08108000) /* Base @ of Sector 14, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0810C000) /* Base @ of Sector 15, 16 Kbytes */ +#define ADDR_FLASH_SECTOR_16 ((uint32_t)0x08110000) /* Base @ of Sector 16, 64 Kbytes */ +#define ADDR_FLASH_SECTOR_17 ((uint32_t)0x08120000) /* Base @ of Sector 17, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_18 ((uint32_t)0x08140000) /* Base @ of Sector 18, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_19 ((uint32_t)0x08160000) /* Base @ of Sector 19, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_20 ((uint32_t)0x08180000) /* Base @ of Sector 20, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_21 ((uint32_t)0x081A0000) /* Base @ of Sector 21, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_22 ((uint32_t)0x081C0000) /* Base @ of Sector 22, 128 Kbytes */ +#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) /* Base @ of Sector 23, 128 Kbytes */ + +#define SECTOR_SIZE_128KB ((uint32_t)0x00020000) + +/* Flash memory regions */ +#define FLASH_BOOT_START_ADDR ADDR_FLASH_SECTOR_0 +#define FLASH_BOOT_END_ADDR (ADDR_FLASH_SECTOR_5 - 1) + +#define FLASH_FW_START_ADDR ADDR_FLASH_SECTOR_6 +#define FLASH_FW_END_ADDR (ADDR_FLASH_SECTOR_12 - 1) + +#define FLASH_FW2_START_ADDR ADDR_FLASH_SECTOR_12 +#define FLASH_FW2_END_ADDR (ADDR_FLASH_SECTOR_22 + SECTOR_SIZE_128KB - 1) + /* Exported functions --------------------------------------------------------*/ typedef struct @@ -85,4 +126,7 @@ uint8_t hardware_programmPrimaryBluetoothNameSet(void); uint8_t hardware_programmSecondaryBluetoothNameSet(void); +#ifdef __cplusplus + } +#endif #endif // FIRMWARE_ERASE_PROGRAM_H diff -r eceb5cb2a8e3 -r a7ed4eb3142b Discovery/Src/tMenuEditSystem.c --- a/Discovery/Src/tMenuEditSystem.c Mon Feb 16 21:33:04 2026 +0100 +++ b/Discovery/Src/tMenuEditSystem.c Tue Feb 17 09:49:37 2026 +0100 @@ -42,6 +42,7 @@ #include "motion.h" #include "t7.h" #include "math.h" +#include "firmwareEraseProgram.h" /*#define HAVE_DEBUG_VIEW */ @@ -1507,6 +1508,9 @@ { char text[32]; + resetMenuEdit(CLUT_MenuPageSystem); + setBackMenu((uint32_t)openEdit_System, 0, 5); + text[0] = '\001'; text[1] = TXT_2BYTE; text[2] = TXT2BYTE_ResetMenu; @@ -1549,6 +1553,7 @@ resetMenuEdit(CLUT_MenuPageSystem); + setBackMenu((uint32_t)openEdit_Reset, 0, 0); text[0] = '\001'; text[1] = TXT_2BYTE; @@ -1614,12 +1619,79 @@ write_buttonTextline(TXT2BYTE_ButtonBack,TXT2BYTE_ButtonEnter,TXT2BYTE_ButtonNext); } + +static bool isValidBootloaderBlock(const customBlockInfo_t *info, uint32_t checksum) +{ + if (info == NULL) { + return false; + } + + return (info->Type & 0x0000FF00) == 0x0100 && checksum == info->fletcher; +} + customBlockInfo_t blockInfo; +static bool isBootloaderEqualToSource(const customBlockInfo_t *info) +{ + if (info == NULL) { + return false; + } + + const uint8_t *pSource = (const uint8_t *)0x08100000; + + /* We only compare the bootloader bytes actually present in the source + * image (info->length). Hardware data is device-specific and must be + * skipped in both flash and source when overlapping. */ + + const uint32_t boot_start = FLASH_BOOT_START_ADDR; + const uint32_t hw_off = HARDWAREDATA_ADDRESS - FLASH_BOOT_START_ADDR; + const uint32_t total_boot_capacity = (FLASH_BOOT_END_ADDR - FLASH_BOOT_START_ADDR) + 1; + + /* Bound total to compare by the source-provided length and boot capacity */ + uint32_t total = info->length; + if (total > total_boot_capacity) { + total = total_boot_capacity; + } + + /* Region 1: from start to just before hardware data (if covered) */ + uint32_t r1_len = (total > hw_off) ? hw_off : total; + if (r1_len) { + if (memcmp((void *)boot_start, pSource, r1_len) != 0) { + return false; + } + } + + /* If total is within the hardware block, there's nothing more to compare */ + if (total <= hw_off) { + return true; + } + + /* Skip hardware block overlap in both flash and source */ + uint32_t after_hw_in_source = hw_off + sizeof(SHardwareData); + uint32_t bytes_past_hw = 0; + if (total > after_hw_in_source) { + bytes_past_hw = total - after_hw_in_source; + } else { + /* Source length ends within or at the end of the hardware block */ + return true; + } + + /* Region 2: bytes after hardware data */ + uint32_t r2_flash = HARDWAREDATA_ADDRESS + sizeof(SHardwareData); + uint32_t r2_src = after_hw_in_source; + + if (memcmp((void *)r2_flash, pSource + r2_src, bytes_past_hw) != 0) { + return false; + } + + return true; +} + void openEdit_Maintenance(void) { char text[32]; unsigned char index = 0; + unsigned char nextLine = ME_Y_LINE3; SSettings *pSettings = settingsGetPointer(); SSensorDataDiveO2* pDiveO2Data = NULL; @@ -1629,7 +1701,10 @@ blockInfo.fletcher = swapBytes(pCustumBlockInfo->fletcher); blockInfo.length = swapBytes(pCustumBlockInfo->length); + uint32_t checksum = CalcFletcher32(0x08100000,0x0811FFEF); /* last nibble contains block info => exclude */ + resetMenuEdit(CLUT_MenuPageSystem); + setBackMenu((uint32_t)openEdit_Reset, 0, 5); text[0] = '\001'; text[1] = TXT_2BYTE; @@ -1652,6 +1727,16 @@ write_field_button(StMSYS5_SetBattCharge, 30, 800, ME_Y_LINE2, &FontT48, text); } + /* No need to remember line; we'll update the field text directly */ + +#ifdef ENABLE_ANALYSE_SAMPLES + text[0] = TXT_2BYTE; + text[1] = TXT2BYTE_SetSampleIndex; + text[2] = 0; + write_field_button(StMSYS5_SetSampleIndx, 30, 800, nextLine, &FontT48, text); + nextLine += ME_Y_LINE_STEP; +#endif + if((pSettings->ppo2sensors_source == O2_SENSOR_SOURCE_ANADIG) || (pSettings->ppo2sensors_source == O2_SENSOR_SOURCE_DIGITAL)) { for (index = 0; index < 3; index++) @@ -1664,26 +1749,24 @@ snprintf(text,32,"%c%c (%1.3lf => %1.3f)\016\016Bar",TXT_2BYTE,TXT2BYTE_AdjustAmbPressure,(float)(pDiveO2Data->pressure/1000000.0), stateRealGetPointer()->lifeData.pressure_surface_bar); - write_field_button(StMSYS5_AdjustSurfPres, 30, 800, ME_Y_LINE4, &FontT48, text); + write_field_button(StMSYS5_AdjustSurfPres, 30, 800, nextLine, &FontT48, text); + nextLine += ME_Y_LINE_STEP; } break; } } } - if((blockInfo.Type & 0x0000FF00)== 0x0100) - { - snprintf(text,32,"Flash Bootloader"); - write_field_button(StMSYS5_FlashBoot, 30, 800, ME_Y_LINE4, &FontT48, text); + if (isValidBootloaderBlock(&blockInfo, checksum)) { + if (!isBootloaderEqualToSource(&blockInfo)) { + snprintf(text,32,"Flash Bootloader"); + if (nextLine < ME_Y_LINE5) { + write_field_button(StMSYS5_FlashBoot, 30, 800, nextLine, &FontT48, text); + nextLine += ME_Y_LINE_STEP; + } + } } -#ifdef ENABLE_ANALYSE_SAMPLES - text[0] = TXT_2BYTE; - text[1] = TXT2BYTE_SetSampleIndex; - text[2] = 0; - write_field_button(StMSYS5_SetSampleIndx, 30, 800, ME_Y_LINE4, &FontT48, text); -#endif - setEvent(StMSYS5_SetFactoryBC, (uint32_t)OnAction_SetFactoryDefaults); if(stateRealGetPointer()->lifeData.battery_charge <= 0) { @@ -1700,13 +1783,10 @@ setEvent(StMSYS5_SetSampleIndx, (uint32_t)OnAction_RecoverSampleIdx); #endif - if((blockInfo.Type & 0x0000FF00)== 0x0100) - { - setEvent(StMSYS5_FlashBoot, (uint32_t)OnAction_FlashBootloader); + if (isValidBootloaderBlock(&blockInfo, checksum) && !isBootloaderEqualToSource(&blockInfo)) { + setEvent(StMSYS5_FlashBoot, (uint32_t)OnAction_FlashBootloader); } - - text[0] = TXT_2BYTE; text[1] = TXT2BYTE_WarnBatteryLow; text[2] = 0; @@ -1829,6 +1909,7 @@ } + uint8_t OnAction_SetFactoryDefaults(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action) { settingsWriteFactoryDefaults(settingsGetPointer()->ButtonResponsiveness[3], settingsGetPointer()->buttonBalance); @@ -1941,6 +2022,11 @@ customBlockInfo_t blockInfo; uint32_t checksum; uint8_t* pSource = (uint8_t *) 0x08100000; + uint8_t eraseResult; + uint8_t progResult; + + // Update the button's text directly to show progress + tMenuEdit_newButtonText(editId, "Flashing, please wait"); checksum = CalcFletcher32(0x08100000,0x0811FFEF); /* last nibble contains block info => exclude */ @@ -1948,12 +2034,35 @@ blockInfo.fletcher = swapBytes(pCustumBlockInfo->fletcher); blockInfo.length = swapBytes(pCustumBlockInfo->length); - if(checksum == blockInfo.fletcher) - { + if (isValidBootloaderBlock(&blockInfo, checksum)) { memcpy (&HwInfo, hardwareDataGetPointer(), sizeof(SHardwareData)); /* create backup copy because data will be overwritten during flash erase */ - bootloader_eraseFlashMemory(); - bootloader_programFlashMemory(pSource, blockInfo.length, &HwInfo); + eraseResult = bootloader_eraseFlashMemory(); + if (eraseResult != 0) { + // Lock flash before returning on error + HAL_FLASH_Lock(); + // Show error on the button itself + tMenuEdit_newButtonText(editId, "Erase failed!"); + return UNSPECIFIC_RETURN; + } + + progResult = bootloader_programFlashMemory(pSource, blockInfo.length, &HwInfo); + if (progResult != 0) { + // Lock flash before returning on error (in case program failed before locking) + HAL_FLASH_Lock(); + // Show error on the button itself + tMenuEdit_newButtonText(editId, "Program failed!"); + return UNSPECIFIC_RETURN; + } + + // Show success on the button itself + tMenuEdit_newButtonText(editId, "Flash complete"); + + // Give user time to see the message, then return to the previous menu + // which will cause a refresh and hide the "Flash Bootloader" button + HAL_Delay(1500); + + return EXIT_TO_MENU; } return UNSPECIFIC_RETURN; } diff -r eceb5cb2a8e3 -r a7ed4eb3142b OtherSources/firmwareEraseProgram.c --- a/OtherSources/firmwareEraseProgram.c Mon Feb 16 21:33:04 2026 +0100 +++ b/OtherSources/firmwareEraseProgram.c Tue Feb 17 09:49:37 2026 +0100 @@ -53,45 +53,6 @@ /* Private types -------------------------------------------------------------*/ -/* Base address of the Flash sectors Bank 1 */ -#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */ -#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */ - -/* Base address of the Flash sectors Bank 2 */ -#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* Base @ of Sector 0, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_13 ((uint32_t)0x08104000) /* Base @ of Sector 1, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_14 ((uint32_t)0x08108000) /* Base @ of Sector 2, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0810C000) /* Base @ of Sector 3, 16 Kbytes */ -#define ADDR_FLASH_SECTOR_16 ((uint32_t)0x08110000) /* Base @ of Sector 4, 64 Kbytes */ -#define ADDR_FLASH_SECTOR_17 ((uint32_t)0x08120000) /* Base @ of Sector 5, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_18 ((uint32_t)0x08140000) /* Base @ of Sector 6, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_19 ((uint32_t)0x08160000) /* Base @ of Sector 7, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_20 ((uint32_t)0x08180000) /* Base @ of Sector 8, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_21 ((uint32_t)0x081A0000) /* Base @ of Sector 9, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_22 ((uint32_t)0x081C0000) /* Base @ of Sector 10, 128 Kbytes */ -#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) /* Base @ of Sector 11, 128 Kbytes */ - -#define SECTOR_SIZE_128KB ((uint32_t)0x00020000) - -#define FLASH_BOOT_START_ADDR ADDR_FLASH_SECTOR_0 -#define FLASH_BOOT_END_ADDR (ADDR_FLASH_SECTOR_5 - 1) - -#define FLASH_FW_START_ADDR ADDR_FLASH_SECTOR_6 -#define FLASH_FW_END_ADDR (ADDR_FLASH_SECTOR_12 - 1) - -#define FLASH_FW2_START_ADDR ADDR_FLASH_SECTOR_12 -#define FLASH_FW2_END_ADDR (ADDR_FLASH_SECTOR_22 + SECTOR_SIZE_128KB - 1) - /* Private variables ---------------------------------------------------------*/ static FLASH_EraseInitTypeDef EraseInitStruct; /*Variable used for Erase procedure*/