commit
						5a87095e30
					
				
							
								
								
									
										154
									
								
								Bluetooth.h
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								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 <https://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| #if MCU_VARIANT == MCU_ESP32 | ||||
| #include "BluetoothSerial.h" | ||||
| #include "esp_bt_main.h" | ||||
| #include "esp_bt_device.h" | ||||
| 
 | ||||
| #elif MCU_VARIANT == MCU_NRF52 | ||||
| #include <bluefruit.h> | ||||
| #include <math.h> | ||||
| #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 | ||||
|  | ||||
							
								
								
									
										7
									
								
								Config.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								Config.h
									
									
									
									
									
								
							| @ -313,7 +313,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 | ||||
| @ -324,8 +324,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; | ||||
|  | ||||
| @ -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)); | ||||
| 
 | ||||
| @ -140,7 +146,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 | ||||
|  | ||||
							
								
								
									
										66
									
								
								Utilities.h
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								Utilities.h
									
									
									
									
									
								
							| @ -18,8 +18,13 @@ | ||||
| #if HAS_EEPROM  | ||||
|     #include <EEPROM.h> | ||||
| #elif PLATFORM == PLATFORM_NRF52 | ||||
|     #include "flash_nrf5x.h" | ||||
|     int written_bytes = 0; | ||||
|     #include <Adafruit_LittleFS.h> | ||||
|     #include <InternalFileSystem.h> | ||||
|     using namespace Adafruit_LittleFS_Namespace; | ||||
|     #define EEPROM_FILE "eeprom" | ||||
|     bool file_exists = false; | ||||
|     int written_bytes = 4; | ||||
|     File file(InternalFS); | ||||
| #endif | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| @ -1104,10 +1109,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 | ||||
| @ -1176,23 +1204,31 @@ 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 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #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); | ||||
| @ -1329,8 +1365,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 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										204
									
								
								flash_cache.c
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								flash_cache.c
									
									
									
									
									
								
							| @ -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 <string.h> | ||||
| #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 | ||||
| @ -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 <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #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 | ||||
							
								
								
									
										179
									
								
								flash_nrf5x.c
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								flash_nrf5x.c
									
									
									
									
									
								
							| @ -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 | ||||
| @ -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 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user