From a2b3ae4970a73b507374290972b00c570e205405 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 4 Aug 2021 18:12:51 +0700 Subject: [PATCH] clean up main --- src/main.c | 235 ++++++++++++++++++++++++++++------------------------- 1 file changed, 123 insertions(+), 112 deletions(-) diff --git a/src/main.c b/src/main.c index 3f2c8ae..cd0a342 100644 --- a/src/main.c +++ b/src/main.c @@ -101,7 +101,8 @@ void usb_teardown(void); * - DFU_MAGIC_OTA_RESET : entered by soft reset, SD is not inited yet * - DFU_MAGIC_SERIAL_ONLY_RESET : with CDC interface only * - DFU_MAGIC_UF2_RESET : with CDC and MSC interfaces - * - DFU_MAGIC_SKIP : skip DFU entirely including double reset delay + * - DFU_MAGIC_SKIP : skip DFU entirely including double reset delay, + * Can be used with systemoff or quick reset to app * * Note: for DFU_MAGIC_OTA_APPJUM Softdevice must not initialized. * since it is already in application. In all other case of OTA SD must be initialized @@ -122,6 +123,7 @@ void usb_teardown(void); // Allow for using reset button essentially to swap between application and bootloader. // This is controlled by a flag in the app and is the behavior of CPX and all Arcade boards when using MakeCode. +// DFU_DBL_RESET magic is used to determined which mode is entered #define APP_ASKS_FOR_SINGLE_TAP_RESET() (*((uint32_t*)(DFU_BANK_0_REGION_START + 0x200)) == 0x87eeb07c) // These value must be the same with one in dfu_transport_ble.c @@ -132,20 +134,24 @@ enum { BLE_CONN_CFG_HIGH_BANDWIDTH = 1 }; //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ -static uint32_t softdev_init(bool init_softdevice); - uint32_t* dbl_reset_mem = ((uint32_t*) DFU_DBL_RESET_MEM ); // true if ble, false if serial bool _ota_dfu = false; bool _ota_connected = false; +bool _sd_inited = false; bool is_ota(void) { return _ota_dfu; } -void softdev_mbr_init(void) +static void check_dfu_mode(void); +static uint32_t ble_stack_init(void); + +// The SoftDevice must only be initialized if a chip reset has occurred. +// Soft reset (jump ) from application must not reinitialize the SoftDevice. +static void mbr_init_sd(void) { PRINTF("SD_MBR_COMMAND_INIT_SD\r\n"); sd_mbr_command_t com = { .command = SD_MBR_COMMAND_INIT_SD }; @@ -162,25 +168,6 @@ int main(void) // Note: skip it for now since this will prevent us to change the size of bootloader in the future // bootloader_mbr_addrs_populate(); - // SD is already Initialized in case of BOOTLOADER_DFU_OTA_MAGIC - bool sd_inited = (NRF_POWER->GPREGRET == DFU_MAGIC_OTA_APPJUM); - - // Start Bootloader in BLE OTA mode - _ota_dfu = (NRF_POWER->GPREGRET == DFU_MAGIC_OTA_APPJUM) || (NRF_POWER->GPREGRET == DFU_MAGIC_OTA_RESET); - - // Serial only mode - bool serial_only_dfu = (NRF_POWER->GPREGRET == DFU_MAGIC_SERIAL_ONLY_RESET); - bool uf2_dfu = (NRF_POWER->GPREGRET == DFU_MAGIC_UF2_RESET); - - // start either serial, uf2 or ble - bool dfu_start = _ota_dfu || serial_only_dfu || uf2_dfu || - (((*dbl_reset_mem) == DFU_DBL_RESET_MAGIC) && (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)); - - bool const dfu_skip = (NRF_POWER->GPREGRET == DFU_MAGIC_SKIP); - - // Clear GPREGRET if it is our values - if (dfu_start || dfu_skip) NRF_POWER->GPREGRET = 0; - // Save bootloader version to pre-defined register, retrieved by application // TODO move to CF2 BOOTLOADER_VERSION_REGISTER = (MK_BOOTLOADER_VERSION); @@ -203,84 +190,9 @@ int main(void) led_state(STATE_WRITING_FINISHED); } - /*------------- Determine DFU mode (Serial, OTA, FRESET or normal) -------------*/ - if ( !dfu_skip ) - { - // DFU button pressed - dfu_start = dfu_start || button_pressed(BUTTON_DFU); - - // DFU + FRESET are pressed --> OTA - _ota_dfu = _ota_dfu || ( button_pressed(BUTTON_DFU) && button_pressed(BUTTON_FRESET) ) ; - - bool const valid_app = bootloader_app_is_valid(); - bool const just_start_app = valid_app && !dfu_start && (*dbl_reset_mem) == DFU_DBL_RESET_APP; - - if (!just_start_app && APP_ASKS_FOR_SINGLE_TAP_RESET()) dfu_start = 1; - - // App mode: register 1st reset and DFU startup (nrf52832) - if ( ! (just_start_app || dfu_start || !valid_app) ) - { - // Register our first reset for double reset detection - (*dbl_reset_mem) = DFU_DBL_RESET_MAGIC; - -#ifdef NRF52832_XXAA - /* Even DFU is not active, we still force an 1000 ms dfu serial mode when startup - * to support auto programming from Arduino IDE - * - * Note: Supposedly during this time if RST is press, it will count as double reset. - * However Double Reset WONT work with nrf52832 since its SRAM got cleared anyway. - */ - bootloader_dfu_start(false, DFU_SERIAL_STARTUP_INTERVAL, false); -#else - // if RST is pressed during this delay --> if will enter dfu - NRFX_DELAY_MS(DFU_DBL_RESET_DELAY); -#endif - } - - if (APP_ASKS_FOR_SINGLE_TAP_RESET()) - { - (*dbl_reset_mem) = DFU_DBL_RESET_APP; - } - else - { - (*dbl_reset_mem) = 0; - } - - if ( dfu_start || !valid_app ) - { - if ( _ota_dfu ) - { - led_state(STATE_BLE_DISCONNECTED); - softdev_init(!sd_inited); - sd_inited = true; - } - else - { - led_state(STATE_USB_UNMOUNTED); - usb_init(serial_only_dfu); - } - - // Initiate an update of the firmware. - if (APP_ASKS_FOR_SINGLE_TAP_RESET() || uf2_dfu || serial_only_dfu) - { - // If USB is not enumerated in 3s (eg. because we're running on battery), we restart into app. - bootloader_dfu_start(_ota_dfu, 3000, true); - } - else - { - // No timeout if bootloader requires user action (double-reset). - bootloader_dfu_start(_ota_dfu, 0, false); - } - - if ( _ota_dfu ) - { - sd_softdevice_disable(); - }else - { - usb_teardown(); - } - } - } + // Check all inputs and enter DFU if needed + // Return when DFU process is complete (or not entered at all) + check_dfu_mode(); // Reset peripherals board_teardown(); @@ -299,7 +211,7 @@ int main(void) if ( is_sd_existed() ) { // MBR forward IRQ to SD (if not already) - if ( !sd_inited ) softdev_mbr_init(); + if ( !_sd_inited ) mbr_init_sd(); // Make sure SD is disabled sd_softdevice_disable(); @@ -315,18 +227,117 @@ int main(void) NVIC_SystemReset(); } -/** - * Initializes the SotdDevice by following SD specs section - * "Master Boot Record and SoftDevice initializaton procedure" - * - * @param[in] init_softdevice true if SoftDevice should be initialized. The SoftDevice must only - * be initialized if a chip reset has occurred. Soft reset (jump ) from - * application must not reinitialize the SoftDevice. - */ -static uint32_t softdev_init(bool init_softdevice) +static void check_dfu_mode(void) { - if (init_softdevice) softdev_mbr_init(); + uint32_t const gpregret = NRF_POWER->GPREGRET; + // SD is already Initialized in case of BOOTLOADER_DFU_OTA_MAGIC + _sd_inited = (gpregret == DFU_MAGIC_OTA_APPJUM); + + // Start Bootloader in BLE OTA mode + _ota_dfu = (gpregret == DFU_MAGIC_OTA_APPJUM) || (gpregret == DFU_MAGIC_OTA_RESET); + + // Serial only mode + bool serial_only_dfu = (gpregret == DFU_MAGIC_SERIAL_ONLY_RESET); + bool uf2_dfu = (gpregret == DFU_MAGIC_UF2_RESET); + + // start either serial, uf2 or ble + bool dfu_start = _ota_dfu || serial_only_dfu || uf2_dfu || + (((*dbl_reset_mem) == DFU_DBL_RESET_MAGIC) && (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)); + + bool const dfu_skip = (gpregret == DFU_MAGIC_SKIP); + + // Clear GPREGRET if it is our values + if (dfu_start || dfu_skip) NRF_POWER->GPREGRET = 0; + + // skip dfu entirely + if (dfu_skip) return; + + /*------------- Determine DFU mode (Serial, OTA, FRESET or normal) -------------*/ + // DFU button pressed + dfu_start = dfu_start || button_pressed(BUTTON_DFU); + + // DFU + FRESET are pressed --> OTA + _ota_dfu = _ota_dfu || ( button_pressed(BUTTON_DFU) && button_pressed(BUTTON_FRESET) ) ; + + bool const valid_app = bootloader_app_is_valid(); + bool const just_start_app = valid_app && !dfu_start && (*dbl_reset_mem) == DFU_DBL_RESET_APP; + + if (!just_start_app && APP_ASKS_FOR_SINGLE_TAP_RESET()) dfu_start = 1; + + // App mode: register 1st reset or DFU startup for nrf52832 + if ( ! (just_start_app || dfu_start || !valid_app) ) + { + // Register our first reset for double reset detection + (*dbl_reset_mem) = DFU_DBL_RESET_MAGIC; + +#ifdef NRF52832_XXAA + /* Even DFU is not active, we still force an 1000 ms dfu serial mode when startup + * to support auto programming from Arduino IDE + * + * Note: Double Reset WONT work with nrf52832 since all its SRAM got cleared with GPIO reset. + */ + bootloader_dfu_start(false, DFU_SERIAL_STARTUP_INTERVAL, false); +#else + // if RST is pressed during this delay (double reset)--> if will enter dfu + NRFX_DELAY_MS(DFU_DBL_RESET_DELAY); +#endif + } + + if (APP_ASKS_FOR_SINGLE_TAP_RESET()) + { + (*dbl_reset_mem) = DFU_DBL_RESET_APP; + } + else + { + (*dbl_reset_mem) = 0; + } + + // Enter DFU mode accordingly to input + if ( dfu_start || !valid_app ) + { + if ( _ota_dfu ) + { + led_state(STATE_BLE_DISCONNECTED); + + if (!_sd_inited ) mbr_init_sd(); + _sd_inited = true; + + ble_stack_init(); + } + else + { + led_state(STATE_USB_UNMOUNTED); + usb_init(serial_only_dfu); + } + + // Initiate an update of the firmware. + if (APP_ASKS_FOR_SINGLE_TAP_RESET() || uf2_dfu || serial_only_dfu) + { + // If USB is not enumerated in 3s (eg. because we're running on battery), we restart into app. + bootloader_dfu_start(_ota_dfu, 3000, true); + } + else + { + // No timeout if bootloader requires user action (double-reset). + bootloader_dfu_start(_ota_dfu, 0, false); + } + + if ( _ota_dfu ) + { + sd_softdevice_disable(); + }else + { + usb_teardown(); + } + } +} + + +// Initializes the SotdDevice by following SD specs section +// "Master Boot Record and SoftDevice initializaton procedure" +static uint32_t ble_stack_init(void) +{ // Forward vector table to bootloader address so that we can handle BLE events sd_softdevice_vector_table_base_set(BOOTLOADER_REGION_START);