summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xports/stm32/mboot/Makefile1
-rw-r--r--ports/stm32/mboot/fsload.c14
-rw-r--r--ports/stm32/mboot/main.c206
-rw-r--r--ports/stm32/mboot/mboot.h40
-rw-r--r--ports/stm32/mboot/ui.c255
5 files changed, 321 insertions, 195 deletions
diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile
index 61a102d02..db39daf88 100755
--- a/ports/stm32/mboot/Makefile
+++ b/ports/stm32/mboot/Makefile
@@ -111,6 +111,7 @@ SRC_C += \
gzstream.c \
pack.c \
sdcard.c \
+ ui.c \
vfs_fat.c \
vfs_lfs.c \
drivers/bus/softspi.c \
diff --git a/ports/stm32/mboot/fsload.c b/ports/stm32/mboot/fsload.c
index 2b674369f..231b07afa 100644
--- a/ports/stm32/mboot/fsload.c
+++ b/ports/stm32/mboot/fsload.c
@@ -118,6 +118,7 @@ static int fsload_program_file(bool write_to_flash) {
uint32_t num_elems = get_le32(buf + 270);
size_t file_offset_target = file_offset;
+ size_t bytes_processed = 0;
// Parse each element
for (size_t elem = 0; elem < num_elems; ++elem) {
@@ -163,6 +164,8 @@ static int fsload_program_file(bool write_to_flash) {
}
elem_addr += l;
s -= l;
+ bytes_processed += l;
+ mboot_state_change(MBOOT_STATE_FSLOAD_PROGRESS, write_to_flash << 31 | bytes_processed);
}
file_offset += elem_size;
@@ -295,17 +298,6 @@ int fsload_process(void) {
ret = fsload_validate_and_program_file(&ctx, methods, fname);
}
- // Flash LEDs based on success/failure of update
- for (int i = 0; i < 4; ++i) {
- if (ret == 0) {
- led_state_all(7);
- } else {
- led_state_all(1);
- }
- mp_hal_delay_ms(100);
- led_state_all(0);
- mp_hal_delay_ms(100);
- }
return ret;
}
elem += elem[-1];
diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c
index 10a09fe3e..37c7c0cf5 100644
--- a/ports/stm32/mboot/main.c
+++ b/ports/stm32/mboot/main.c
@@ -109,7 +109,7 @@
#define APP_VALIDITY_BITS (0x00000003)
// For 1ms system ticker.
-static volatile uint32_t systick_ms;
+volatile uint32_t systick_ms;
// Global dfu state
dfu_context_t dfu_context SECTION_NOZERO_BSS;
@@ -398,112 +398,6 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) {
}
/******************************************************************************/
-// LED
-
-#if defined(MBOOT_LED1)
-#define LED0 MBOOT_LED1
-#elif defined(MICROPY_HW_LED1)
-#define LED0 MICROPY_HW_LED1
-#endif
-
-#if defined(MBOOT_LED2)
-#define LED1 MBOOT_LED2
-#elif defined(MICROPY_HW_LED2)
-#define LED1 MICROPY_HW_LED2
-#endif
-
-#if defined(MBOOT_LED3)
-#define LED2 MBOOT_LED3
-#elif defined(MICROPY_HW_LED3)
-#define LED2 MICROPY_HW_LED3
-#endif
-
-#if defined(MBOOT_LED4)
-#define LED3 MBOOT_LED4
-#elif defined(MICROPY_HW_LED4)
-#define LED3 MICROPY_HW_LED4
-#endif
-
-// For flashing states: bit 0 is "active", bit 1 is "inactive", bits 2-6 are flash rate.
-typedef enum {
- LED0_STATE_OFF = 0,
- LED0_STATE_ON = 1,
- LED0_STATE_SLOW_FLASH = (20 << 2) | 1,
- LED0_STATE_FAST_FLASH = (2 << 2) | 1,
- LED0_STATE_SLOW_INVERTED_FLASH = (20 << 2) | 2,
-} led0_state_t;
-
-static led0_state_t led0_cur_state = LED0_STATE_OFF;
-static uint32_t led0_ms_interval = 0;
-static int led0_toggle_count = 0;
-
-MP_WEAK void led_init(void) {
- #if defined(MBOOT_BOARD_LED_INIT)
- // Custom LED init function provided by the board.
- MBOOT_BOARD_LED_INIT();
- #else
- // Init LEDs using GPIO calls.
- mp_hal_pin_output(LED0);
- #ifdef LED1
- mp_hal_pin_output(LED1);
- #endif
- #ifdef LED2
- mp_hal_pin_output(LED2);
- #endif
- #ifdef LED3
- mp_hal_pin_output(LED3);
- #endif
- #endif
-
- led0_cur_state = LED0_STATE_OFF;
-}
-
-MP_WEAK void led_state(uint32_t led, int val) {
- #if defined(MBOOT_BOARD_LED_STATE)
- // Custom LED state function provided by the board.
- return MBOOT_BOARD_LED_STATE(led, val);
- #else
- // Set LEDs using GPIO calls.
- if (val) {
- MICROPY_HW_LED_ON(led);
- } else {
- MICROPY_HW_LED_OFF(led);
- }
- #endif
-}
-
-void led_state_all(unsigned int mask) {
- led_state(LED0, mask & 1);
- #ifdef LED1
- led_state(LED1, mask & 2);
- #endif
- #ifdef LED2
- led_state(LED2, mask & 4);
- #endif
- #ifdef LED3
- led_state(LED3, mask & 8);
- #endif
-}
-
-void led0_state(led0_state_t state) {
- led0_cur_state = state;
- if (state == LED0_STATE_OFF || state == LED0_STATE_ON) {
- led_state(LED0, state);
- }
-}
-
-void led0_update() {
- if (led0_cur_state != LED0_STATE_OFF && systick_ms - led0_ms_interval > 50) {
- uint8_t rate = (led0_cur_state >> 2) & 0x1f;
- led0_ms_interval += 50;
- if (++led0_toggle_count >= rate) {
- led0_toggle_count = 0;
- }
- led_state(LED0, (led0_cur_state & (led0_toggle_count == 0 ? 1 : 2)));
- }
-}
-
-/******************************************************************************/
// FLASH
#if defined(STM32WB)
@@ -617,8 +511,9 @@ static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_bl
#endif
int hw_page_erase(uint32_t addr, uint32_t *next_addr) {
+ mboot_state_change(MBOOT_STATE_ERASE_START, addr);
+
int ret = -1;
- led0_state(LED0_STATE_ON);
#if defined(MBOOT_SPIFLASH_ADDR)
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
@@ -638,12 +533,14 @@ int hw_page_erase(uint32_t addr, uint32_t *next_addr) {
ret = mboot_flash_page_erase(addr, next_addr);
}
- led0_state((ret == 0) ? LED0_STATE_SLOW_FLASH : LED0_STATE_SLOW_INVERTED_FLASH);
+ mboot_state_change(MBOOT_STATE_ERASE_END, ret);
+
return ret;
}
void hw_read(mboot_addr_t addr, size_t len, uint8_t *buf) {
- led0_state(LED0_STATE_FAST_FLASH);
+ mboot_state_change(MBOOT_STATE_READ_START, addr);
+
#if defined(MBOOT_SPIFLASH_ADDR)
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf);
@@ -668,12 +565,14 @@ void hw_read(mboot_addr_t addr, size_t len, uint8_t *buf) {
// Other addresses, just read directly from memory
memcpy(buf, (void *)(uintptr_t)addr, len);
}
- led0_state(LED0_STATE_SLOW_FLASH);
+
+ mboot_state_change(MBOOT_STATE_READ_END, 0);
}
int hw_write(uint32_t addr, const uint8_t *src8, size_t len) {
+ mboot_state_change(MBOOT_STATE_WRITE_START, addr);
+
int ret = -1;
- led0_state(LED0_STATE_FAST_FLASH);
#if defined(MBOOT_SPIFLASH_ADDR)
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
ret = mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, src8);
@@ -691,7 +590,8 @@ int hw_write(uint32_t addr, const uint8_t *src8, size_t len) {
dfu_context.error = MBOOT_ERROR_STR_INVALID_ADDRESS_IDX;
}
- led0_state((ret == 0) ? LED0_STATE_SLOW_FLASH : LED0_STATE_SLOW_INVERTED_FLASH);
+ mboot_state_change(MBOOT_STATE_WRITE_END, ret);
+
return ret;
}
@@ -707,9 +607,10 @@ int do_page_erase(uint32_t addr, uint32_t *next_addr) {
void do_read(mboot_addr_t addr, size_t len, uint8_t *buf) {
#if MBOOT_ENABLE_PACKING
// Read disabled on packed (encrypted) mode.
+ mboot_state_change(MBOOT_STATE_READ_START, addr);
dfu_context.status = DFU_STATUS_ERROR_FILE;
dfu_context.error = MBOOT_ERROR_STR_INVALID_READ_IDX;
- led0_state(LED0_STATE_SLOW_INVERTED_FLASH);
+ mboot_state_change(MBOOT_STATE_READ_END, -MBOOT_ERRNO_FLASH_READ_DISALLOWED);
#else
hw_read(addr, len, buf);
#endif
@@ -1360,71 +1261,6 @@ static int pyb_usbdd_shutdown(void) {
/******************************************************************************/
// main
-#if defined(MBOOT_BOARD_GET_RESET_MODE)
-
-static inline int mboot_get_reset_mode(void) {
- return MBOOT_BOARD_GET_RESET_MODE();
-}
-
-#else
-
-#define RESET_MODE_NUM_STATES (4)
-#define RESET_MODE_TIMEOUT_CYCLES (8)
-#ifdef LED2
-#ifdef LED3
-#define RESET_MODE_LED_STATES 0x8421
-#else
-#define RESET_MODE_LED_STATES 0x7421
-#endif
-#else
-#define RESET_MODE_LED_STATES 0x3210
-#endif
-
-static void usrbtn_init(void) {
- mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0);
-}
-
-static int usrbtn_state(void) {
- return mp_hal_pin_read(MICROPY_HW_USRSW_PIN) == MICROPY_HW_USRSW_PRESSED;
-}
-
-static int mboot_get_reset_mode(void) {
- usrbtn_init();
- int reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
- if (usrbtn_state()) {
- // Cycle through reset modes while USR is held
- // Timeout is roughly 20s, where reset_mode=1
- systick_init();
- led_init();
- reset_mode = 0;
- for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 32; i++) {
- if (i % 32 == 0) {
- if (++reset_mode > RESET_MODE_NUM_STATES) {
- reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
- }
- uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4);
- led_state_all(l);
- }
- if (!usrbtn_state()) {
- break;
- }
- mp_hal_delay_ms(19);
- }
- // Flash the selected reset mode
- for (int i = 0; i < 6; i++) {
- led_state_all(0);
- mp_hal_delay_ms(50);
- uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4);
- led_state_all(l);
- mp_hal_delay_ms(50);
- }
- mp_hal_delay_ms(300);
- }
- return reset_mode;
-}
-
-#endif
-
NORETURN static __attribute__((naked)) void branch_to_application(uint32_t r0, uint32_t bl_addr) {
__asm volatile (
"ldr r2, [r1, #0]\n" // get address of stack pointer
@@ -1566,11 +1402,13 @@ enter_bootloader:
#endif
if ((initial_r0 & 0xffffff80) == 0x70ad0080) {
+ mboot_state_change(MBOOT_STATE_FSLOAD_START, 0);
+ int ret = -1;
#if MBOOT_FSLOAD
// Application passed through elements, validate then process them
const uint8_t *elem_end = elem_search(ELEM_DATA_START, ELEM_TYPE_END);
if (elem_end != NULL && elem_end[-1] == 0) {
- int ret = fsload_process();
+ ret = fsload_process();
// If there is a valid ELEM_TYPE_STATUS element then store the status in the given location.
const uint8_t *elem_status = elem_search(ELEM_DATA_START, ELEM_TYPE_STATUS);
if (elem_status != NULL && elem_status[-1] == 4) {
@@ -1580,8 +1418,8 @@ enter_bootloader:
}
}
#endif
+ mboot_state_change(MBOOT_STATE_FSLOAD_END, ret);
// Always reset because the application is expecting to resume
- led_state_all(0);
leave_bootloader();
}
@@ -1598,8 +1436,7 @@ enter_bootloader:
i2c_init(initial_r0);
#endif
- led_state_all(0);
- led0_state(LED0_STATE_SLOW_FLASH);
+ mboot_state_change(MBOOT_STATE_DFU_START, 0);
#if MBOOT_USB_RESET_ON_DISCONNECT
bool has_connected = false;
@@ -1633,8 +1470,9 @@ enter_bootloader:
#endif
}
+ mboot_state_change(MBOOT_STATE_DFU_END, 0);
+
// Shutdown and leave the bootloader.
- led_state_all(0);
mp_hal_delay_ms(50);
pyb_usbdd_shutdown();
#if defined(MBOOT_I2C_SCL)
diff --git a/ports/stm32/mboot/mboot.h b/ports/stm32/mboot/mboot.h
index 0e04f67f4..0984fd9ac 100644
--- a/ports/stm32/mboot/mboot.h
+++ b/ports/stm32/mboot/mboot.h
@@ -46,9 +46,31 @@
#define MBOOT_ADDRESS_SPACE_64BIT (0)
#endif
+// These enum values are passed as the first argument to mboot_state_change() to
+// notify of a change in state of the bootloader activity. This function has a
+// default implementation in ui.c but can be overridden by a board. Some states
+// have an argument passed along as the second argument to mboot_state_change().
+// If this argument is unused then 0 is passed in. A result of an operation is
+// 0 for success and <0 for failure, with a failure being either an MP_Exxx code
+// or MBOOT_ERRNO_xxx code.
+typedef enum {
+ MBOOT_STATE_DFU_START, // arg: unused
+ MBOOT_STATE_DFU_END, // arg: unused
+ MBOOT_STATE_FSLOAD_START, // arg: unused
+ MBOOT_STATE_FSLOAD_END, // arg: result of fsload operation
+ MBOOT_STATE_FSLOAD_PROGRESS, // arg: total bytes processed so far, high bit set when doing write pass
+ MBOOT_STATE_ERASE_START, // arg: address of erase
+ MBOOT_STATE_ERASE_END, // arg: result of erase
+ MBOOT_STATE_READ_START, // arg: address of read
+ MBOOT_STATE_READ_END, // arg: result of read
+ MBOOT_STATE_WRITE_START, // arg: address of write
+ MBOOT_STATE_WRITE_END, // arg: result of write
+} mboot_state_t;
+
enum {
MBOOT_ERRNO_FLASH_ERASE_DISALLOWED = 200,
MBOOT_ERRNO_FLASH_ERASE_FAILED,
+ MBOOT_ERRNO_FLASH_READ_DISALLOWED,
MBOOT_ERRNO_FLASH_WRITE_DISALLOWED,
MBOOT_ERRNO_DFU_INVALID_HEADER = 210,
@@ -98,10 +120,12 @@ typedef uint64_t mboot_addr_t;
typedef uint32_t mboot_addr_t;
#endif
+extern volatile uint32_t systick_ms;
extern uint8_t _estack[ELEM_DATA_SIZE];
void systick_init(void);
void led_init(void);
+void led0_update(void);
void SystemClock_Config(void);
uint32_t get_le32(const uint8_t *b);
@@ -132,4 +156,20 @@ static inline void mboot_entry_init(uint32_t *initial_r0) {
#endif
}
+#if defined(MBOOT_BOARD_GET_RESET_MODE)
+static inline int mboot_get_reset_mode(void) {
+ return MBOOT_BOARD_GET_RESET_MODE();
+}
+#else
+int mboot_get_reset_mode(void);
+#endif
+
+#if defined(MBOOT_BOARD_STATE_CHANGE)
+static inline void mboot_state_change(mboot_state_t state, uint32_t arg) {
+ return MBOOT_BOARD_STATE_CHANGE(state, arg);
+}
+#else
+void mboot_state_change(mboot_state_t state, uint32_t arg);
+#endif
+
#endif // MICROPY_INCLUDED_STM32_MBOOT_MBOOT_H
diff --git a/ports/stm32/mboot/ui.c b/ports/stm32/mboot/ui.c
new file mode 100644
index 000000000..36cba1cf5
--- /dev/null
+++ b/ports/stm32/mboot/ui.c
@@ -0,0 +1,255 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2022 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "mboot.h"
+#include "ports/stm32/boardctrl.h"
+
+/******************************************************************************/
+// LED
+
+#if defined(MBOOT_LED1)
+#define LED0 MBOOT_LED1
+#elif defined(MICROPY_HW_LED1)
+#define LED0 MICROPY_HW_LED1
+#endif
+
+#if defined(MBOOT_LED2)
+#define LED1 MBOOT_LED2
+#elif defined(MICROPY_HW_LED2)
+#define LED1 MICROPY_HW_LED2
+#endif
+
+#if defined(MBOOT_LED3)
+#define LED2 MBOOT_LED3
+#elif defined(MICROPY_HW_LED3)
+#define LED2 MICROPY_HW_LED3
+#endif
+
+#if defined(MBOOT_LED4)
+#define LED3 MBOOT_LED4
+#elif defined(MICROPY_HW_LED4)
+#define LED3 MICROPY_HW_LED4
+#endif
+
+// For flashing states: bit 0 is "active", bit 1 is "inactive", bits 2-6 are flash rate.
+typedef enum {
+ LED0_STATE_OFF = 0,
+ LED0_STATE_ON = 1,
+ LED0_STATE_SLOW_FLASH = (20 << 2) | 1,
+ LED0_STATE_FAST_FLASH = (2 << 2) | 1,
+ LED0_STATE_SLOW_INVERTED_FLASH = (20 << 2) | 2,
+} led0_state_t;
+
+static led0_state_t led0_cur_state = LED0_STATE_OFF;
+static uint32_t led0_ms_interval = 0;
+static int led0_toggle_count = 0;
+
+MP_WEAK void led_init(void) {
+ #if defined(MBOOT_BOARD_LED_INIT)
+ // Custom LED init function provided by the board.
+ MBOOT_BOARD_LED_INIT();
+ #else
+ // Init LEDs using GPIO calls.
+ mp_hal_pin_output(LED0);
+ #ifdef LED1
+ mp_hal_pin_output(LED1);
+ #endif
+ #ifdef LED2
+ mp_hal_pin_output(LED2);
+ #endif
+ #ifdef LED3
+ mp_hal_pin_output(LED3);
+ #endif
+ #endif
+
+ led0_cur_state = LED0_STATE_OFF;
+}
+
+MP_WEAK void led_state(uint32_t led, int val) {
+ #if defined(MBOOT_BOARD_LED_STATE)
+ // Custom LED state function provided by the board.
+ return MBOOT_BOARD_LED_STATE(led, val);
+ #else
+ // Set LEDs using GPIO calls.
+ if (val) {
+ MICROPY_HW_LED_ON(led);
+ } else {
+ MICROPY_HW_LED_OFF(led);
+ }
+ #endif
+}
+
+void led_state_all(unsigned int mask) {
+ led_state(LED0, mask & 1);
+ #ifdef LED1
+ led_state(LED1, mask & 2);
+ #endif
+ #ifdef LED2
+ led_state(LED2, mask & 4);
+ #endif
+ #ifdef LED3
+ led_state(LED3, mask & 8);
+ #endif
+}
+
+void led0_state(led0_state_t state) {
+ led0_cur_state = state;
+ if (state == LED0_STATE_OFF || state == LED0_STATE_ON) {
+ led_state(LED0, state);
+ }
+}
+
+void led0_update(void) {
+ if (led0_cur_state != LED0_STATE_OFF && systick_ms - led0_ms_interval > 50) {
+ uint8_t rate = (led0_cur_state >> 2) & 0x1f;
+ led0_ms_interval += 50;
+ if (++led0_toggle_count >= rate) {
+ led0_toggle_count = 0;
+ }
+ led_state(LED0, (led0_cur_state & (led0_toggle_count == 0 ? 1 : 2)));
+ }
+}
+
+/******************************************************************************/
+// User button
+
+#if !defined(MBOOT_BOARD_GET_RESET_MODE)
+
+#define RESET_MODE_NUM_STATES (4)
+#define RESET_MODE_TIMEOUT_CYCLES (8)
+#ifdef LED2
+#ifdef LED3
+#define RESET_MODE_LED_STATES 0x8421
+#else
+#define RESET_MODE_LED_STATES 0x7421
+#endif
+#else
+#define RESET_MODE_LED_STATES 0x3210
+#endif
+
+static void usrbtn_init(void) {
+ mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0);
+}
+
+static int usrbtn_state(void) {
+ return mp_hal_pin_read(MICROPY_HW_USRSW_PIN) == MICROPY_HW_USRSW_PRESSED;
+}
+
+int mboot_get_reset_mode(void) {
+ usrbtn_init();
+ int reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
+ if (usrbtn_state()) {
+ // Cycle through reset modes while USR is held
+ // Timeout is roughly 20s, where reset_mode=1
+ systick_init();
+ led_init();
+ reset_mode = 0;
+ for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 32; i++) {
+ if (i % 32 == 0) {
+ if (++reset_mode > RESET_MODE_NUM_STATES) {
+ reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
+ }
+ uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4);
+ led_state_all(l);
+ }
+ if (!usrbtn_state()) {
+ break;
+ }
+ mp_hal_delay_ms(19);
+ }
+ // Flash the selected reset mode
+ for (int i = 0; i < 6; i++) {
+ led_state_all(0);
+ mp_hal_delay_ms(50);
+ uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4);
+ led_state_all(l);
+ mp_hal_delay_ms(50);
+ }
+ mp_hal_delay_ms(300);
+ }
+ return reset_mode;
+}
+
+#endif
+
+/******************************************************************************/
+// State change
+
+#if !defined(MBOOT_BOARD_STATE_CHANGE)
+
+void mboot_state_change(mboot_state_t state, uint32_t arg) {
+ switch (state) {
+ case MBOOT_STATE_DFU_START:
+ led_state_all(0);
+ led0_state(LED0_STATE_SLOW_FLASH);
+ break;
+
+ case MBOOT_STATE_DFU_END:
+ led_state_all(0);
+ break;
+
+ case MBOOT_STATE_FSLOAD_START:
+ break;
+
+ case MBOOT_STATE_FSLOAD_END:
+ // Flash LEDs based on success/failure of update
+ for (int i = 0; i < 4; ++i) {
+ if (arg == 0) {
+ led_state_all(7);
+ } else {
+ led_state_all(1);
+ }
+ mp_hal_delay_ms(100);
+ led_state_all(0);
+ mp_hal_delay_ms(100);
+ }
+ break;
+
+ case MBOOT_STATE_FSLOAD_PROGRESS:
+ break;
+
+ case MBOOT_STATE_ERASE_START:
+ led0_state(LED0_STATE_ON);
+ break;
+
+ case MBOOT_STATE_READ_START:
+ case MBOOT_STATE_WRITE_START:
+ led0_state(LED0_STATE_FAST_FLASH);
+ break;
+
+ case MBOOT_STATE_ERASE_END:
+ case MBOOT_STATE_READ_END:
+ case MBOOT_STATE_WRITE_END:
+ if (arg == 0) {
+ led0_state(LED0_STATE_SLOW_FLASH);
+ } else {
+ led0_state(LED0_STATE_SLOW_INVERTED_FLASH);
+ }
+ break;
+ }
+}
+
+#endif