From 6e8865b2ae285b9c6e565e609d9e63f11a329063 Mon Sep 17 00:00:00 2001 From: "jacob.eva" Date: Sun, 21 Jan 2024 15:12:20 +0000 Subject: [PATCH 1/2] Replace EEPROM backend to be compatible with Adafruit BLE lib --- Config.h | 5 +- RNode_Firmware.ino | 6 ++ Utilities.h | 48 ++++++++--- flash_cache.c | 204 --------------------------------------------- flash_cache.h | 58 ------------- flash_nrf5x.c | 179 --------------------------------------- flash_nrf5x.h | 89 -------------------- 7 files changed, 47 insertions(+), 542 deletions(-) delete mode 100644 flash_cache.c delete mode 100644 flash_cache.h delete mode 100644 flash_nrf5x.c delete mode 100644 flash_nrf5x.h diff --git a/Config.h b/Config.h index 43cb29b..5827e7d 100644 --- a/Config.h +++ b/Config.h @@ -316,8 +316,9 @@ #define CONFIG_UART_BUFFER_SIZE 6144 #define CONFIG_QUEUE_SIZE 6144 #define CONFIG_QUEUE_MAX_LENGTH 200 - #define EEPROM_SIZE 4096 - #define EEPROM_OFFSET EEPROM_SIZE+0xED000-EEPROM_RESERVED + #define EEPROM_SIZE 200 + //#define EEPROM_OFFSET EEPROM_SIZE+0xED000-EEPROM_RESERVED + #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED // following pins are for the sx1262 const int pin_rxen = 37; diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 05acd1a..ce1d2ef 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -54,6 +54,12 @@ void setup() { Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE); #endif + #if MCU_VARIANT == MCU_NRF52 + if (!eeprom_begin()) { + Serial.write("EEPROM initialisation failed.\r\n"); + } + #endif + // Seed the PRNG randomSeed(analogRead(0)); diff --git a/Utilities.h b/Utilities.h index fe61b7c..d6cfdc9 100644 --- a/Utilities.h +++ b/Utilities.h @@ -18,8 +18,13 @@ #if HAS_EEPROM #include #elif PLATFORM == PLATFORM_NRF52 - #include "flash_nrf5x.h" - int written_bytes = 0; + #include + #include + using namespace Adafruit_LittleFS_Namespace; + #define EEPROM_FILE "eeprom" + bool file_exists = false; + int written_bytes = 4; + File file(InternalFS); #endif #include #include "LoRa.h" @@ -1093,10 +1098,33 @@ void promisc_disable() { } #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 + bool eeprom_begin() { + InternalFS.begin(); + + file.open(EEPROM_FILE, FILE_O_READ); + + // if file doesn't exist + if (!file) { + if (file.open(EEPROM_FILE, FILE_O_WRITE)) { + // initialise the file with empty content + uint8_t empty_content[EEPROM_SIZE] = {0}; + file.write(empty_content, EEPROM_SIZE); + return true; + } else { + return false; + } + } else { + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); + return true; + } + } + uint8_t eeprom_read(uint32_t mapped_addr) { uint8_t byte; void* byte_ptr = &byte; - flash_nrf5x_read(byte_ptr, mapped_addr, 1); + file.seek(mapped_addr); + file.read(byte_ptr, 1); return byte; } #endif @@ -1165,18 +1193,18 @@ void eeprom_update(int mapped_addr, uint8_t byte) { #elif !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 uint8_t read_byte; void* read_byte_ptr = &read_byte; - void const * byte_ptr = &byte; - flash_nrf5x_read(read_byte_ptr, mapped_addr, 1); + file.seek(mapped_addr); + file.read(read_byte_ptr, 1); + file.seek(mapped_addr); if (read_byte != byte) { - flash_nrf5x_write(mapped_addr, byte_ptr, 1); + file.write(byte); } - written_bytes++; - // flush the cache every 4 bytes to make sure everything is synced - if (written_bytes == 4) { + if (written_bytes >= 8) { + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); written_bytes = 0; - flash_nrf5x_flush(); } #endif diff --git a/flash_cache.c b/flash_cache.c deleted file mode 100644 index 50d69f7..0000000 --- a/flash_cache.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * 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. - */ -#ifdef NRF52840_XXAA -#include -#include "flash_cache.h" -#include "common_func.h" -#include "variant.h" -#include "wiring_digital.h" - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ -static inline uint32_t page_addr_of (uint32_t addr) -{ - return addr & ~(FLASH_CACHE_SIZE - 1); -} - -static inline uint32_t page_offset_of (uint32_t addr) -{ - return addr & (FLASH_CACHE_SIZE - 1); -} - -int flash_cache_write (flash_cache_t* fc, uint32_t dst, void const * src, uint32_t len) -{ - uint8_t const * src8 = (uint8_t const *) src; - uint32_t remain = len; - - // Program up to page boundary each loop - while ( remain ) - { - uint32_t const page_addr = page_addr_of(dst); - uint32_t const offset = page_offset_of(dst); - - uint32_t wr_bytes = FLASH_CACHE_SIZE - offset; - wr_bytes = min32(remain, wr_bytes); - - // Page changes, flush old and update new cache - if ( page_addr != fc->cache_addr ) - { - flash_cache_flush(fc); - fc->cache_addr = page_addr; - - // read a whole page from flash - fc->read(fc->cache_buf, page_addr, FLASH_CACHE_SIZE); - } - - memcpy(fc->cache_buf + offset, src8, wr_bytes); - - // adjust for next run - src8 += wr_bytes; - remain -= wr_bytes; - dst += wr_bytes; - } - - return len - remain; -} - -void flash_cache_flush (flash_cache_t* fc) -{ - if ( fc->cache_addr == FLASH_CACHE_INVALID_ADDR ) return; - - // skip erase & program if verify() exists, and memory matches - if ( !(fc->verify && fc->verify(fc->cache_addr, fc->cache_buf, FLASH_CACHE_SIZE)) ) - { - // indicator TODO allow to disable flash indicator - ledOn(LED_BUILTIN); - - fc->erase(fc->cache_addr); - fc->program(fc->cache_addr, fc->cache_buf, FLASH_CACHE_SIZE); - - ledOff(LED_BUILTIN); - } - - fc->cache_addr = FLASH_CACHE_INVALID_ADDR; -} - -int flash_cache_read (flash_cache_t* fc, void* dst, uint32_t addr, uint32_t count) -{ - // there is no check for overflow / wraparound for dst + count, addr + count. - // this might be a useful thing to add for at least debug builds. - - // overwrite with cache value if available - if ( (fc->cache_addr != FLASH_CACHE_INVALID_ADDR) && // cache is not valid - !(addr < fc->cache_addr && addr + count <= fc->cache_addr) && // starts before, ends before cache area - !(addr >= fc->cache_addr + FLASH_CACHE_SIZE) ) // starts after end of cache area - { - // This block is entered only when the read overlaps the cache area by at least one byte. - // If the read starts before the cache area, it's further guaranteed - // that count is large enough to cause the read to enter - // the cache area by at least 1 byte. - uint32_t dst_off = 0; - uint32_t src_off = 0; - if (addr < fc->cache_addr) - { - dst_off = fc->cache_addr - addr; - // Read the bytes prior to the cache address - fc->read(dst, addr, dst_off); - } - else - { - src_off = addr - fc->cache_addr; - } - - // Thus, after the above code block executes: - // *** AT MOST ***, only one of src_off and dst_off are non-zero; - // (Both may be zero when the read starts at the start of the cache area.) - // dst_off corresponds to the number of bytes already read from PRIOR to the cache area. - // src_off corresponds to the byte offset to start reading at, from WITHIN the cache area. - - // How many bytes to memcpy from flash area? - // Remember that, AT MOST, one of src_off and dst_off are non-zero. - // If src_off is non-zero, then dst_off is zero, representing that the - // read starts inside the cache. In this case: - // PARAM1 := FLASH_CACHE_SIZE - src_off == maximum possible bytes to read from cache - // PARAM2 := count - // Thus, taking the minimum of the two gives the number of bytes to read from cache, - // in the range [ 1 .. FLASH_CACHE_SIZE-src_off ]. - // Else if dst_off is non-zero, then src_off is zero, representing that the - // read started prior to the cache area. In this case: - // PARAM1 := FLASH_CACHE_SIZE == full size of the cache - // PARAM2 := count - dst_off == total bytes requested, minus the count of those already read - // Because the original request is guaranteed to overlap the cache, the range for - // PARAM2 is ensured to be [ 1 .. count-1 ]. - // Thus, taking the minimum of the two gives the number of bytes to read from cache, - // in the range [ 1 .. FLASH_CACHE_SIZE ] - // Else both src_off and dst_off are zero, representing that the read is starting - // exactly aligned to the cache. - // PARAM1 := FLASH_CACHE_SIZE - // PARAM2 := count - // Thus, taking the minimum of the two gives the number of bytes to read from cache, - // in the range [ 1 .. FLASH_CACHE_SIZE ] - // - // Therefore, in all cases, there is assurance that cache_bytes - // will be in the final range [1..FLASH_CACHE_SIZE]. - uint32_t cache_bytes = minof(FLASH_CACHE_SIZE-src_off, count - dst_off); - - // Use memcpy to read cached data into the buffer - // If src_off is non-zero, then dst_off is zero, representing that the - // read starts inside the cache. In this case: - // PARAM1 := dst - // PARAM2 := fc->cache_buf + src_off - // PARAM3 := cache_bytes - // Thus, all works as expected when starting in the midst of the cache. - // Else if dst_off is non-zero, then src_off is zero, representing that the - // read started prior to the cache. In this case: - // PARAM1 := dst + dst_off == destination offset by number of bytes already read - // PARAM2 := fc->cache_buf - // PARAM3 := cache_bytes - // Thus, all works as expected when starting prior to the cache. - // Else both src_off and dst_off are zero, representing that the read is starting - // exactly aligned to the cache. - // PARAM1 := dst - // PARAM2 := fc->cache_buf - // PARAM3 := cache_bytes - // Thus, all works as expected when starting exactly at the cache boundary - // - // Therefore, in all cases, there is assurance that cache_bytes - // will be in the final range [1..FLASH_CACHE_SIZE]. - memcpy(dst + dst_off, fc->cache_buf + src_off, cache_bytes); - - // Read any final bytes from flash - // As noted above, dst_off represents the count of bytes read prior to the cache - // while cache_bytes represents the count of bytes read from the cache; - // This code block is guaranteed to overlap the cache area by at least one byte. - // Thus, copied will correspond to the total bytes already copied, - // and is guaranteed to be in the range [ 1 .. count ]. - uint32_t copied = dst_off + cache_bytes; - - // - if ( copied < count ) - { - fc->read(dst + copied, addr + copied, count - copied); - } - } - else - { - // not using the cache, so just forward to read from flash - fc->read(dst, addr, count); - } - - return (int) count; -} -#endif diff --git a/flash_cache.h b/flash_cache.h deleted file mode 100644 index ff585e5..0000000 --- a/flash_cache.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * 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. - */ -#ifdef NRF52840_XXAA -#ifndef FLASH_CACHE_H_ -#define FLASH_CACHE_H_ - -#include -#include - -#define FLASH_CACHE_SIZE 4096 // must be a erasable page size -#define FLASH_CACHE_INVALID_ADDR 0xffffffff - -typedef struct -{ - bool (*erase) (uint32_t addr); - uint32_t (*program) (uint32_t dst, void const * src, uint32_t len); - uint32_t (*read) (void* dst, uint32_t src, uint32_t len); - bool (*verify) (uint32_t addr, void const * buf, uint32_t len); - - uint32_t cache_addr; - uint8_t* cache_buf; -} flash_cache_t; - -#ifdef __cplusplus -extern "C" { -#endif - -int flash_cache_write (flash_cache_t* fc, uint32_t dst, void const *src, uint32_t count); -void flash_cache_flush (flash_cache_t* fc); -int flash_cache_read (flash_cache_t* fc, void* dst, uint32_t addr, uint32_t count); - -#ifdef __cplusplus - } -#endif - -#endif /* FLASH_CACHE_H_ */ -#endif diff --git a/flash_nrf5x.c b/flash_nrf5x.c deleted file mode 100644 index 0442a39..0000000 --- a/flash_nrf5x.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * 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. - */ -#ifdef NRF52840_XXAA -#include "flash_nrf5x.h" -#include "flash_cache.h" -#include "nrf_sdm.h" -#include "nrf_soc.h" -#include "delay.h" -#include "rtos.h" - - -#ifdef NRF52840_XXAA - #define BOOTLOADER_ADDR 0xF4000 -#else - #define BOOTLOADER_ADDR 0x74000 -#endif - -// defined in linker script -extern uint32_t __flash_arduino_start[]; -//extern uint32_t __flash_arduino_end[]; - -//--------------------------------------------------------------------+ -// 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); -} - -// Flash Abstraction Layer -static bool fal_erase (uint32_t addr); -static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len); -static uint32_t fal_read (void* dst, uint32_t src, uint32_t len); -static bool fal_verify (uint32_t addr, void const * buf, uint32_t len); - -static uint8_t _cache_buffer[FLASH_CACHE_SIZE] __attribute__((aligned(4))); - -static flash_cache_t _cache = -{ - .erase = fal_erase, - .program = fal_program, - .read = fal_read, - .verify = fal_verify, - - .cache_addr = FLASH_CACHE_INVALID_ADDR, - .cache_buf = _cache_buffer -}; - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ -void flash_nrf5x_flush (void) -{ - flash_cache_flush(&_cache); -} - -int flash_nrf5x_write (uint32_t dst, void const * src, uint32_t len) -{ - // Softdevice region - VERIFY(dst >= ((uint32_t) __flash_arduino_start), -1); - - // Bootloader region - VERIFY(dst < BOOTLOADER_ADDR, -1); - - return flash_cache_write(&_cache, dst, src, len); -} - -int flash_nrf5x_read (void* dst, uint32_t src, uint32_t len) -{ - return flash_cache_read(&_cache, dst, src, len); -} - -bool flash_nrf5x_erase(uint32_t addr) -{ - return fal_erase(addr); -} - -//--------------------------------------------------------------------+ -// HAL for caching -//--------------------------------------------------------------------+ -static bool fal_erase (uint32_t addr) -{ - // Init semaphore for first call - if ( _sem == NULL ) - { - _sem = xSemaphoreCreateCounting(10, 0); - VERIFY(_sem); - } - - // retry if busy - uint32_t err; - while ( NRF_ERROR_BUSY == (err = sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE)) ) - { - 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; -} - -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)) ) - { - delay(1); - } - VERIFY_STATUS(err, 0); - - if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY); -#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); - - 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); -#endif - - return len; -} - -static uint32_t fal_read (void* dst, uint32_t src, uint32_t len) -{ - memcpy(dst, (void*) src, len); - return len; -} - -static bool fal_verify (uint32_t addr, void const * buf, uint32_t len) -{ - return 0 == memcmp((void*) addr, buf, len); -} -#endif diff --git a/flash_nrf5x.h b/flash_nrf5x.h deleted file mode 100644 index 138cf9c..0000000 --- a/flash_nrf5x.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach for Adafruit Industries - * - * 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. - */ -#ifdef NRF52840_XXAA -#ifndef FLASH_NRF52_H_ -#define FLASH_NRF52_H_ - -#include "common_inc.h" - -#define FLASH_NRF52_PAGE_SIZE 4096 - -#ifdef __cplusplus - extern "C" { -#endif - -void flash_nrf5x_flush (void); -bool flash_nrf5x_erase(uint32_t addr); - -int flash_nrf5x_write (uint32_t dst, void const * src, uint32_t len); -int flash_nrf5x_read (void* dst, uint32_t src, uint32_t len); - -//--------------------------------------------------------------------+ -// Write helper -//--------------------------------------------------------------------+ -static inline int flash_nrf5x_write8 (uint32_t dst, uint8_t num) -{ - return flash_nrf5x_write(dst, &num, sizeof(num)); -} - -static inline int flash_nrf5x_write16 (uint32_t dst, uint8_t num) -{ - return flash_nrf5x_write(dst, &num, sizeof(num)); -} -static inline int flash_nrf5x_write32 (uint32_t dst, uint8_t num) -{ - return flash_nrf5x_write(dst, &num, sizeof(num)); -} - -//--------------------------------------------------------------------+ -// Read helper -//--------------------------------------------------------------------+ -static inline uint8_t flash_nrf5x_read8 (uint32_t src) -{ - uint8_t num; - flash_nrf5x_read(&num, src, sizeof(num)); - return num; -} - -static inline uint16_t flash_nrf5x_read16 (uint32_t src) -{ - uint16_t num; - flash_nrf5x_read(&num, src, sizeof(num)); - return num; -} - -static inline uint16_t flash_nrf5x_read32 (uint32_t src) -{ - uint32_t num; - flash_nrf5x_read(&num, src, sizeof(num)); - return num; -} - - -#ifdef __cplusplus - } -#endif - -#endif /* FLASH_NRF52_H_ */ -#endif From 80769f11010835e6673161dec396868d5ae1c099 Mon Sep 17 00:00:00 2001 From: "jacob.eva" Date: Thu, 25 Jan 2024 21:35:40 +0000 Subject: [PATCH 2/2] Add BLE driver for NRF52 --- Bluetooth.h | 154 +++++++++++++++++++++++++++++++++++++++++++++ Config.h | 2 +- RNode_Firmware.ino | 2 +- Utilities.h | 18 +++++- 4 files changed, 173 insertions(+), 3 deletions(-) diff --git a/Bluetooth.h b/Bluetooth.h index f28f02c..e7231a1 100644 --- a/Bluetooth.h +++ b/Bluetooth.h @@ -13,11 +13,24 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#if MCU_VARIANT == MCU_ESP32 #include "BluetoothSerial.h" #include "esp_bt_main.h" #include "esp_bt_device.h" +#elif MCU_VARIANT == MCU_NRF52 +#include +#include +#endif + +#if MCU_VARIANT == MCU_ESP32 BluetoothSerial SerialBT; +#elif MCU_VARIANT == MCU_NRF52 +BLEUart SerialBT; +BLEDis bledis; +BLEBas blebas; +#endif + #define BT_PAIRING_TIMEOUT 35000 uint32_t bt_pairing_started = 0; @@ -138,4 +151,145 @@ char bt_devname[11]; } } +#elif MCU_VARIANT == MCU_NRF52 +uint8_t eeprom_read(uint32_t mapped_addr); + +void bt_stop() { + if (bt_state != BT_STATE_OFF) { + bt_allow_pairing = false; + bt_state = BT_STATE_OFF; + } +} + +void bt_disable_pairing() { + bt_allow_pairing = false; + bt_ssp_pin = 0; + bt_state = BT_STATE_ON; +} + +void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { + if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { + bt_disable_pairing(); + } else { + bt_ssp_pin = 0; + } +} + +bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { + for (int i = 0; i < 6; i++) { + // multiply by tens however many times needed to make numbers appear in order + bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i); + } + kiss_indicate_btpin(); + if (match_request) { + if (bt_allow_pairing) { + return true; + } + } + return false; +} + +void bt_connect_callback(uint16_t conn_handle) { + bt_state = BT_STATE_CONNECTED; + cable_state = CABLE_STATE_DISCONNECTED; +} + +void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { + bt_state = BT_STATE_ON; +} + +bool bt_setup_hw() { + if (!bt_ready) { + #if HAS_EEPROM + if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { + #else + if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { + #endif + bt_enabled = true; + } else { + bt_enabled = false; + } + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.autoConnLed(false); + if (Bluefruit.begin()) { + Bluefruit.setTxPower(4); // Check bluefruit.h for supported values + Bluefruit.Security.setIOCaps(true, true, false); + Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback); + Bluefruit.Periph.setConnectCallback(bt_connect_callback); + Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback); + Bluefruit.Security.setIOCaps(true, true, false); + Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete); + const ble_gap_addr_t gap_addr = Bluefruit.getAddr(); + char *data = (char*)malloc(BT_DEV_ADDR_LEN+1); + for (int i = 0; i < BT_DEV_ADDR_LEN; i++) { + data[i] = gap_addr.addr[i]; + } + #if HAS_EEPROM + data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE)); + #else + data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE)); + #endif + unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN); + memcpy(bt_dh, hash, BT_DEV_HASH_LEN); + sprintf(bt_devname, "RNode %02X%02X", bt_dh[14], bt_dh[15]); + free(data); + + bt_ready = true; + return true; + + } else { return false; } + } else { return false; } +} + +void bt_start() { + if (bt_state == BT_STATE_OFF) { + Bluefruit.setName(bt_devname); + bledis.setManufacturer("Adafruit Industries"); + bledis.setModel("Bluefruit Feather52"); + // start device information service + bledis.begin(); + + SerialBT.begin(); + + blebas.begin(); + + // non-connectable advertising + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + + // Include bleuart 128-bit uuid + Bluefruit.Advertising.addService(SerialBT); + + // There is no room for Name in Advertising packet + // Use Scan response for Name + Bluefruit.ScanResponse.addName(); + + Bluefruit.Advertising.start(0); + + bt_state = BT_STATE_ON; + } +} + +bool bt_init() { + bt_state = BT_STATE_OFF; + if (bt_setup_hw()) { + if (bt_enabled && !console_active) bt_start(); + return true; + } else { + return false; + } +} + +void bt_enable_pairing() { + if (bt_state == BT_STATE_OFF) bt_start(); + bt_allow_pairing = true; + bt_pairing_started = millis(); + bt_state = BT_STATE_PAIRING; +} + +void update_bt() { + if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) { + bt_disable_pairing(); + } +} #endif diff --git a/Config.h b/Config.h index 5827e7d..82bc783 100644 --- a/Config.h +++ b/Config.h @@ -304,7 +304,7 @@ #if BOARD_MODEL == BOARD_RAK4630 #define HAS_EEPROM false #define HAS_DISPLAY false // set for debugging - #define HAS_BLUETOOTH false + #define HAS_BLUETOOTH true #define HAS_CONSOLE false #define HAS_PMU false #define HAS_NP false diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index ce1d2ef..d36be3b 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -140,7 +140,7 @@ void setup() { update_display(); #endif - #if MCU_VARIANT == MCU_ESP32 + #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 #if HAS_PMU == true pmu_ready = init_pmu(); #endif diff --git a/Utilities.h b/Utilities.h index d6cfdc9..44a5e78 100644 --- a/Utilities.h +++ b/Utilities.h @@ -1207,9 +1207,17 @@ void eeprom_update(int mapped_addr, uint8_t byte) { written_bytes = 0; } #endif - } +#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 +void eeprom_flush() { + // sync file contents to flash + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); + written_bytes = 0; +} +#endif + void eeprom_write(uint8_t addr, uint8_t byte) { if (!eeprom_info_locked() && addr >= 0 && addr < EEPROM_RESERVED) { eeprom_update(eeprom_addr(addr), byte); @@ -1344,8 +1352,16 @@ bool eeprom_checksum_valid() { void bt_conf_save(bool is_enabled) { if (is_enabled) { eeprom_update(eeprom_addr(ADDR_CONF_BT), BT_ENABLE_BYTE); + #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 + // have to do a flush because we're only writing 1 byte and it syncs after 8 + eeprom_flush(); + #endif } else { eeprom_update(eeprom_addr(ADDR_CONF_BT), 0x00); + #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 + // have to do a flush because we're only writing 1 byte and it syncs after 8 + eeprom_flush(); + #endif } }