diff --git a/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp b/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp index e4437233..6689290e 100644 --- a/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp +++ b/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp @@ -253,7 +253,7 @@ BLEAdvertising::BLEAdvertising(void) _hdl = BLE_GAP_ADV_SET_HANDLE_NOT_SET; _type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; _start_if_disconnect = true; - _runnning = false; + _running = false; _conn_mask = 0; @@ -321,7 +321,7 @@ void BLEAdvertising::setPeerAddress(const ble_gap_addr_t& peer_addr) { bool BLEAdvertising::isRunning(void) { - return _runnning; + return _running; } bool BLEAdvertising::setBeacon(BLEBeacon& beacon) @@ -339,8 +339,7 @@ void BLEAdvertising::restartOnDisconnect(bool enable) _start_if_disconnect = enable; } -bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout) -{ +bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout) { // ADV Params ble_gap_adv_params_t adv_para = { .properties = { .type = _type, .anonymous = 0 }, @@ -369,17 +368,24 @@ bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout) default: break; } + // stop first if current running since we may change advertising data/params + if (_running) { + sd_ble_gap_adv_stop(_hdl); + } + // gap_adv long-live is required by SD v6 - static ble_gap_adv_data_t gap_adv = { - .adv_data = { .p_data = _data, .len = _count }, - .scan_rsp_data = { .p_data = Bluefruit.ScanResponse.getData(), .len = Bluefruit.ScanResponse.count() } - }; + static ble_gap_adv_data_t gap_adv; + gap_adv.adv_data.p_data = _data; + gap_adv.adv_data.len = _count; + gap_adv.scan_rsp_data.p_data = Bluefruit.ScanResponse.getData(); + gap_adv.scan_rsp_data.len = Bluefruit.ScanResponse.count(); + VERIFY_STATUS( sd_ble_gap_adv_set_configure(&_hdl, &gap_adv, &adv_para), false ); VERIFY_STATUS( sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, _hdl, Bluefruit.getTxPower() ), false ); VERIFY_STATUS( sd_ble_gap_adv_start(_hdl, CONN_CFG_PERIPHERAL), false ); Bluefruit._startConnLed(); // start blinking - _runnning = true; + _running = true; _active_interval = interval; _left_timeout -= min16(_left_timeout, timeout); @@ -403,7 +409,7 @@ bool BLEAdvertising::stop(void) { VERIFY_STATUS( sd_ble_gap_adv_stop(_hdl), false); - _runnning = false; + _running = false; Bluefruit._stopConnLed(); // stop blinking return true; @@ -425,7 +431,7 @@ void BLEAdvertising::_eventHandler(ble_evt_t* evt) { bitSet(_conn_mask, conn_hdl); - _runnning = false; + _running = false; } } break; @@ -436,14 +442,14 @@ void BLEAdvertising::_eventHandler(ble_evt_t* evt) bitClear(_conn_mask, conn_hdl); // Auto start if enabled and not connected to any central - if ( !_runnning && _start_if_disconnect ) start(_stop_timeout); + if ( !_running && _start_if_disconnect ) start(_stop_timeout); } break; case BLE_GAP_EVT_ADV_SET_TERMINATED: if (evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT) { - _runnning = false; + _running = false; // If still advertising, it is only in slow mode --> blink normal Bluefruit.setConnLedInterval(CFG_ADV_BLINKY_INTERVAL); diff --git a/libraries/Bluefruit52Lib/src/BLEAdvertising.h b/libraries/Bluefruit52Lib/src/BLEAdvertising.h index 3a0c556e..43a6a9fe 100644 --- a/libraries/Bluefruit52Lib/src/BLEAdvertising.h +++ b/libraries/Bluefruit52Lib/src/BLEAdvertising.h @@ -154,7 +154,7 @@ class BLEAdvertising : public BLEAdvertisingData uint8_t _hdl; uint8_t _type; bool _start_if_disconnect; - bool _runnning; + bool _running; ble_gap_addr_t _peer_addr; //! Target address for an ADV_DIRECT_IND advertisement uint32_t _conn_mask; diff --git a/libraries/InternalFileSytem/src/flash/flash_nrf5x.c b/libraries/InternalFileSytem/src/flash/flash_nrf5x.c index f9fac1fd..5ee73025 100644 --- a/libraries/InternalFileSytem/src/flash/flash_nrf5x.c +++ b/libraries/InternalFileSytem/src/flash/flash_nrf5x.c @@ -29,13 +29,15 @@ #include "delay.h" #include "rtos.h" - #ifdef NRF52840_XXAA #define BOOTLOADER_ADDR 0xF4000 #else #define BOOTLOADER_ADDR 0x74000 #endif +// How many retry attempts when performing flash operations +#define MAX_RETRY 20 + // defined in linker script extern uint32_t __flash_arduino_start[]; //extern uint32_t __flash_arduino_end[]; @@ -44,12 +46,7 @@ extern uint32_t __flash_arduino_start[]; // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ static SemaphoreHandle_t _sem = NULL; - -void flash_nrf5x_event_cb (uint32_t event) -{ -// if (event != NRF_EVT_FLASH_OPERATION_SUCCESS) LOG_LV1("IFLASH", "Flash op Failed"); - if ( _sem ) xSemaphoreGive(_sem); -} +static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS; // Flash Abstraction Layer static bool fal_erase (uint32_t addr); @@ -70,6 +67,31 @@ static flash_cache_t _cache = .cache_buf = _cache_buffer }; +void flash_nrf5x_event_cb (uint32_t event) { + if ( _sem ) { + // Record the result, for consumption by fal_erase or fal_program + // Used to reattempt failed operations + _flash_op_result = event; + + // Signal to fal_erase or fal_program that our async flash op is now complete + xSemaphoreGive(_sem); + } +} + +// When soft device is enabled, flash ops are async +// Eventual success is reported via callback, which we await +static uint32_t wait_for_async_flash_op_completion(void) { + uint8_t sd_en = 0; + (void) sd_softdevice_is_enabled(&sd_en); + + if (sd_en) { + xSemaphoreTake(_sem, portMAX_DELAY); + return (_flash_op_result == NRF_EVT_FLASH_OPERATION_SUCCESS) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT; + } else { + return NRF_SUCCESS; + } +} + //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ @@ -105,62 +127,48 @@ bool flash_nrf5x_erase(uint32_t addr) static bool fal_erase (uint32_t addr) { // Init semaphore for first call - if ( _sem == NULL ) - { - _sem = xSemaphoreCreateCounting(10, 0); + if ( _sem == NULL ) { + _sem = xSemaphoreCreateBinary(); VERIFY(_sem); } - // retry if busy - uint32_t err; - while ( NRF_ERROR_BUSY == (err = sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE)) ) - { + // Erase the page: Multiple attempts if needed + for (uint8_t attempt = 0; attempt < MAX_RETRY; ++attempt) { + if (NRF_SUCCESS == sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE)) { + if (NRF_SUCCESS == wait_for_async_flash_op_completion()) { + return true; + } + } delay(1); } - VERIFY_STATUS(err, false); - - // wait for async event if SD is enabled - uint8_t sd_en = 0; - (void) sd_softdevice_is_enabled(&sd_en); - - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); - - return true; + return false; } -static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len) -{ - // wait for async event if SD is enabled - uint8_t sd_en = 0; - (void) sd_softdevice_is_enabled(&sd_en); - - uint32_t err; - - // Somehow S140 v6.1.1 assert an error when writing a whole page - // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert - // Workaround: write half page at a time. -#if NRF52832_XXAA - while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4)) ) - { +// helper for fal_program() +static bool fal_sub_program(uint32_t dst, void const * src, uint32_t len) { + for (uint8_t attempt = 0; attempt < MAX_RETRY; ++attempt) { + if (NRF_SUCCESS == sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4)) { + if (NRF_SUCCESS == wait_for_async_flash_op_completion()) { + return true; + } + } delay(1); } - VERIFY_STATUS(err, 0); + return false; +} - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); +static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len) { +#if NRF52832_XXAA + VERIFY(fal_sub_program(dst, src, len), 0); #else - while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8)) ) - { - delay(1); - } - VERIFY_STATUS(err, 0); - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); + // Somehow S140 v6.1.1 assert an error when writing a whole page + // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert + // Workaround: write half page at a time. + VERIFY(fal_sub_program(dst, src, len/2), 0); // 1st half - while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8)) ) - { - delay(1); - } - VERIFY_STATUS(err, 0); - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); + dst += len/2; + src += len/2; + VERIFY(fal_sub_program(dst, src, len/2), 0); // 2nd half #endif return len;