btstack_flash_bank: write empty tag instead of overwriting existing tag with ENABLE_TLV_FLASH_WRITE_ONCE

This commit is contained in:
Matthias Ringwald 2023-01-18 14:24:58 +01:00
parent 5bc527fedb
commit 052e5e4278
3 changed files with 122 additions and 75 deletions

View File

@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## Changed
- GAP: add gap_set_peer_privacy_mode with default LE_PRIVACY_MODE_DEVICE
- bluetooth: indicated identity address in resolved address types
- btstack_flash_bank: write empty tag instead of overwriting existing tag with ENABLE_TLV_FLASH_WRITE_ONCE
## Release v1.5.5

View File

@ -75,55 +75,56 @@ POSIX platform properties:
### ENABLE_* directives {#sec:enableDirectives}
BTstack properties:
| \#define | Description |
|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
| ENABLE_CLASSIC | Enable Classic related code in HCI and L2CAP |
| ENABLE_BLE | Enable BLE related code in HCI and L2CAP |
| ENABLE_EHCILL | Enable eHCILL low power mode on TI CC256x/WL18xx chipsets |
| ENABLE_H5 | Enable support for SLIP mode in `btstack_uart.h` drivers for HCI H5 ('Three-Wire Mode') |
| ENABLE_LOG_DEBUG | Enable log_debug messages |
| ENABLE_LOG_ERROR | Enable log_error messages |
| ENABLE_LOG_INFO | Enable log_info messages |
| ENABLE_SCO_OVER_HCI | Enable SCO over HCI for chipsets (if supported) |
| ENABLE_SCO_OVER_PCM | Enable SCO ofer PCM/I2S for chipsets (if supported) |
| ENABLE_HFP_WIDE_BAND_SPEECH | Enable support for mSBC codec used in HFP profile for Wide-Band Speech |
| ENABLE_HFP_AT_MESSAGES | Enable `HFP_SUBEVENT_AT_MESSAGE_SENT` and `HFP_SUBEVENT_AT_MESSAGE_RECEIVED` events |
| ENABLE_LE_PERIPHERAL | Enable support for LE Peripheral Role in HCI and Security Manager |
| ENBALE_LE_CENTRAL | Enable support for LE Central Role in HCI and Security Manager |
| ENABLE_LE_SECURE_CONNECTIONS | Enable LE Secure Connections |
| ENABLE_LE_PROACTIVE_AUTHENTICATION | Enable automatic encryption for bonded devices on re-connect |
| ENABLE_GATT_CLIENT_PAIRING | Enable GATT Client to start pairing and retry operation on security error |
| ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS | Use [micro-ecc library](https://github.com/kmackay/micro-ecc) for ECC operations |
| ENABLE_LE_DATA_LENGTH_EXTENSION | Enable LE Data Length Extension support |
| ENABLE_LE_EXTENDED_ADVERTISING | Enable extended advertising and scanning |
| ENABLE_LE_PERIODIC_ADVERTISING | Enable periodic advertising and scanning |
| ENABLE_LE_SIGNED_WRITE | Enable LE Signed Writes in ATT/GATT |
| ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION | Enable address resolution for resolvable private addresses in Controller |
| ENABLE_CROSS_TRANSPORT_KEY_DERIVATION | Enable Cross-Transport Key Derivation (CTKD) for Secure Connections |
| ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE | Enable Enhanced Retransmission Mode for L2CAP Channels. Mandatory for AVRCP Browsing |
| ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE | Enable LE credit-based flow-control mode for L2CAP channels |
| ENABLE_L2CAP_ENHANCED_CREDIT_BASED_FLOW_CONTROL_MODE | Enable Enhanced credit-based flow-control mode for L2CAP Channels |
| ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL | Enable HCI Controller to Host Flow Control, see below |
| ENABLE_HCI_SERIALIZED_CONTROLLER_OPERATIONS | Serialize Inquiry, Remote Name Request, and Create Connection operations |
| ENABLE_ATT_DELAYED_RESPONSE | Enable support for delayed ATT operations, see [GATT Server](profiles/#sec:GATTServerProfile) |
| ENABLE_BCM_PCM_WBS | Enable support for Wide-Band Speech codec in BCM controller, requires ENABLE_SCO_OVER_PCM |
| ENABLE_CC256X_ASSISTED_HFP | Enable support for Assisted HFP mode in CC256x Controller, requires ENABLE_SCO_OVER_PCM |
| Enable_RTK_PCM_WBS | Enable support for Wide-Band Speech codec in Realtek controller, requires ENABLE_SCO_OVER_PCM |
| ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND | Enable workaround for bug in CC256x Flow Control during baud rate change, see chipset docs. |
| ENABLE_CYPRESS_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND | Enable workaround for bug in CYW2070x Flow Control during baud rate change, similar to CC256x. |
| ENABLE_LE_LIMIT_ACL_FRAGMENT_BY_MAX_OCTETS | Force HCI to fragment ACL-LE packets to fit into over-the-air packet |
| ENABLE_TLV_FLASH_EXPLICIT_DELETE_FIELD | Enable use of explicit delete field in TLV Flash implemenation - required when flash value cannot be overwritten with zero |
| ENABLE_CONTROLLER_WARM_BOOT | Enable stack startup without power cycle (if supported/possible) |
| ENABLE_SEGGER_RTT | Use SEGGER RTT for console output and packet log, see [additional options](#sec:rttConfiguration) |
| ENABLE_EXPLICIT_CONNECTABLE_MODE_CONTROL | Disable calls to control Connectable Mode by L2CAP |
| ENABLE_EXPLICIT_IO_CAPABILITIES_REPLY | Let application trigger sending IO Capabilities (Negative) Reply |
| ENABLE_EXPLICIT_LINK_KEY_REPLY | Let application trigger sending Link Key (Negative) Response, allows for asynchronous link key lookup |
| ENABLE_EXPLICIT_BR_EDR_SECURITY_MANAGER | Report BR/EDR Security Manager support in L2CAP Information Response |
| ENABLE_CLASSIC_OOB_PAIRING | Enable support for classic Out-of-Band (OOB) pairing |
| ENABLE_A2DP_EXPLICIT_CONFIG | Let application configure stream endpoint (skip auto-config of SBC endpoint) |
| ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION | allow accept or reject of stream start on A2DP_SUBEVENT_START_STREAM_REQUESTED |
| ENABLE_LE_WHITELIST_TOUCH_AFTER_RESOLVING_LIST_UPDATE | Enable Workaround for Controller bug. |
| ENABLE_CONTROLLER_DUMP_PACKETS | Dump number of packets in Controller per type for debugging |
| \#define | Description |
|-----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| ENABLE_CLASSIC | Enable Classic related code in HCI and L2CAP |
| ENABLE_BLE | Enable BLE related code in HCI and L2CAP |
| ENABLE_EHCILL | Enable eHCILL low power mode on TI CC256x/WL18xx chipsets |
| ENABLE_H5 | Enable support for SLIP mode in `btstack_uart.h` drivers for HCI H5 ('Three-Wire Mode') |
| ENABLE_LOG_DEBUG | Enable log_debug messages |
| ENABLE_LOG_ERROR | Enable log_error messages |
| ENABLE_LOG_INFO | Enable log_info messages |
| ENABLE_SCO_OVER_HCI | Enable SCO over HCI for chipsets (if supported) |
| ENABLE_SCO_OVER_PCM | Enable SCO ofer PCM/I2S for chipsets (if supported) |
| ENABLE_HFP_WIDE_BAND_SPEECH | Enable support for mSBC codec used in HFP profile for Wide-Band Speech |
| ENABLE_HFP_AT_MESSAGES | Enable `HFP_SUBEVENT_AT_MESSAGE_SENT` and `HFP_SUBEVENT_AT_MESSAGE_RECEIVED` events |
| ENABLE_LE_PERIPHERAL | Enable support for LE Peripheral Role in HCI and Security Manager |
| ENBALE_LE_CENTRAL | Enable support for LE Central Role in HCI and Security Manager |
| ENABLE_LE_SECURE_CONNECTIONS | Enable LE Secure Connections |
| ENABLE_LE_PROACTIVE_AUTHENTICATION | Enable automatic encryption for bonded devices on re-connect |
| ENABLE_GATT_CLIENT_PAIRING | Enable GATT Client to start pairing and retry operation on security error |
| ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS | Use [micro-ecc library](https://github.com/kmackay/micro-ecc) for ECC operations |
| ENABLE_LE_DATA_LENGTH_EXTENSION | Enable LE Data Length Extension support |
| ENABLE_LE_EXTENDED_ADVERTISING | Enable extended advertising and scanning |
| ENABLE_LE_PERIODIC_ADVERTISING | Enable periodic advertising and scanning |
| ENABLE_LE_SIGNED_WRITE | Enable LE Signed Writes in ATT/GATT |
| ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION | Enable address resolution for resolvable private addresses in Controller |
| ENABLE_CROSS_TRANSPORT_KEY_DERIVATION | Enable Cross-Transport Key Derivation (CTKD) for Secure Connections |
| ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE | Enable Enhanced Retransmission Mode for L2CAP Channels. Mandatory for AVRCP Browsing |
| ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE | Enable LE credit-based flow-control mode for L2CAP channels |
| ENABLE_L2CAP_ENHANCED_CREDIT_BASED_FLOW_CONTROL_MODE | Enable Enhanced credit-based flow-control mode for L2CAP Channels |
| ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL | Enable HCI Controller to Host Flow Control, see below |
| ENABLE_HCI_SERIALIZED_CONTROLLER_OPERATIONS | Serialize Inquiry, Remote Name Request, and Create Connection operations |
| ENABLE_ATT_DELAYED_RESPONSE | Enable support for delayed ATT operations, see [GATT Server](profiles/#sec:GATTServerProfile) |
| ENABLE_BCM_PCM_WBS | Enable support for Wide-Band Speech codec in BCM controller, requires ENABLE_SCO_OVER_PCM |
| ENABLE_CC256X_ASSISTED_HFP | Enable support for Assisted HFP mode in CC256x Controller, requires ENABLE_SCO_OVER_PCM |
| Enable_RTK_PCM_WBS | Enable support for Wide-Band Speech codec in Realtek controller, requires ENABLE_SCO_OVER_PCM |
| ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND | Enable workaround for bug in CC256x Flow Control during baud rate change, see chipset docs. |
| ENABLE_CYPRESS_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND | Enable workaround for bug in CYW2070x Flow Control during baud rate change, similar to CC256x. |
| ENABLE_LE_LIMIT_ACL_FRAGMENT_BY_MAX_OCTETS | Force HCI to fragment ACL-LE packets to fit into over-the-air packet |
| ENABLE_TLV_FLASH_EXPLICIT_DELETE_FIELD | Enable use of explicit delete field in TLV Flash implementation - required when flash value cannot be overwritten with zero |
| ENABLE_TLV_FLASH_WRITE_ONCE | Enable storing of emtpy tag instead of overwriting existing tag - required when flash value cannot be overwritten at all |
| ENABLE_CONTROLLER_WARM_BOOT | Enable stack startup without power cycle (if supported/possible) |
| ENABLE_SEGGER_RTT | Use SEGGER RTT for console output and packet log, see [additional options](#sec:rttConfiguration) |
| ENABLE_EXPLICIT_CONNECTABLE_MODE_CONTROL | Disable calls to control Connectable Mode by L2CAP |
| ENABLE_EXPLICIT_IO_CAPABILITIES_REPLY | Let application trigger sending IO Capabilities (Negative) Reply |
| ENABLE_EXPLICIT_LINK_KEY_REPLY | Let application trigger sending Link Key (Negative) Response, allows for asynchronous link key lookup |
| ENABLE_EXPLICIT_BR_EDR_SECURITY_MANAGER | Report BR/EDR Security Manager support in L2CAP Information Response |
| ENABLE_CLASSIC_OOB_PAIRING | Enable support for classic Out-of-Band (OOB) pairing |
| ENABLE_A2DP_EXPLICIT_CONFIG | Let application configure stream endpoint (skip auto-config of SBC endpoint) |
| ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION | allow accept or reject of stream start on A2DP_SUBEVENT_START_STREAM_REQUESTED |
| ENABLE_LE_WHITELIST_TOUCH_AFTER_RESOLVING_LIST_UPDATE | Enable Workaround for Controller bug. |
| ENABLE_CONTROLLER_DUMP_PACKETS | Dump number of packets in Controller per type for debugging |
Notes:

View File

@ -57,12 +57,19 @@
// Most Flash implementations allow to:
// - erase sector -> all values are 0xff
// - write value (1s -> 0s)
// - overwrite value with zero (remaininig 1s -> 0s)
// - overwrite value with zero (remaining 1s -> 0s)
//
// We use the ability to overwrite a value with zeros to mark deleted enttries (by writing zero into the tag field).
// Some targetes, E.g. Kinetix K64F, do enot allow for that.
// Some targets, E.g. Kinetix K64F, do enot allow for that.
//
// With ENABLE_TLV_FLASH_EXPLICIT_DELETE_FIELD an extra field is reserved to indicate a deleted tag, while keeping main logic
//
// With ENABLE_TLV_FLASH_WRITE_ONCE, tags are never marked as deleted. Instead, an emtpy tag will be written instead.
// Also, lookup and migrate requires to always search until the end of the valid bank
#if defined (ENABLE_TLV_FLASH_EXPLICIT_DELETE_FIELD) && defined (ENABLE_TLV_FLASH_WRITE_ONCE)
#error "Please define either ENABLE_TLV_FLASH_EXPLICIT_DELETE_FIELD or ENABLE_TLV_FLASH_WRITE_ONCE"
#endif
#define BTSTACK_TLV_HEADER_LEN 8
@ -255,32 +262,54 @@ static void btstack_tlv_flash_bank_migrate(btstack_tlv_flash_bank_t * self){
uint32_t tag_len = it.len;
uint32_t tag_index = it.offset;
log_info("migrate pos %u, tag '%x' len %u -> new pos %u",
(unsigned int) tag_index, (unsigned int) it.tag, (unsigned int) tag_len, next_write_pos);
bool tag_valid = true;
// copy header
uint8_t header_buffer[8];
btstack_tlv_flash_bank_read(self, self->current_bank, tag_index, header_buffer, 8);
btstack_tlv_flash_bank_write(self, next_bank, next_write_pos, header_buffer, 8);
tag_index += 8;
next_write_pos += 8;
#ifdef ENABLE_TLV_FLASH_WRITE_ONCE
// search until end for newer entry of same tag
tlv_iterator_t it2;
memcpy(&it2, &it, sizeof(tlv_iterator_t));
while (btstack_tlv_flash_bank_iterator_has_next(self, &it2)){
if ((it2.offset != it.offset) && (it2.tag == it.tag)){
tag_valid = false;
break;
}
tlv_iterator_fetch_next(self, &it2);
}
if (tag_valid == false){
log_info("skip pos %u, tag '%x' as newer entry found at %u", (unsigned int) tag_index, (unsigned int) it.tag,
(unsigned int) it2.offset);
}
#endif
if (tag_valid) {
log_info("migrate pos %u, tag '%x' len %u -> new pos %u",
(unsigned int) tag_index, (unsigned int) it.tag, (unsigned int) tag_len, next_write_pos);
// copy header
uint8_t header_buffer[8];
btstack_tlv_flash_bank_read(self, self->current_bank, tag_index, header_buffer, 8);
btstack_tlv_flash_bank_write(self, next_bank, next_write_pos, header_buffer, 8);
tag_index += 8;
next_write_pos += 8;
#ifdef ENABLE_TLV_FLASH_EXPLICIT_DELETE_FIELD
// skip delete field
tag_index += self->delete_tag_len;
next_write_pos += self->delete_tag_len;
// skip delete field
tag_index += self->delete_tag_len;
next_write_pos += self->delete_tag_len;
#endif
// copy value
int bytes_to_copy = tag_len;
uint8_t copy_buffer[32];
while (bytes_to_copy){
int bytes_this_iteration = btstack_min(bytes_to_copy, sizeof(copy_buffer));
btstack_tlv_flash_bank_read(self, self->current_bank, tag_index, copy_buffer, bytes_this_iteration);
btstack_tlv_flash_bank_write(self, next_bank, next_write_pos, copy_buffer, bytes_this_iteration);
tag_index += bytes_this_iteration;
next_write_pos += bytes_this_iteration;
bytes_to_copy -= bytes_this_iteration;
}
// copy value
int bytes_to_copy = tag_len;
uint8_t copy_buffer[32];
while (bytes_to_copy) {
int bytes_this_iteration = btstack_min(bytes_to_copy, sizeof(copy_buffer));
btstack_tlv_flash_bank_read(self, self->current_bank, tag_index, copy_buffer, bytes_this_iteration);
btstack_tlv_flash_bank_write(self, next_bank, next_write_pos, copy_buffer, bytes_this_iteration);
tag_index += bytes_this_iteration;
next_write_pos += bytes_this_iteration;
bytes_to_copy -= bytes_this_iteration;
}
}
}
tlv_iterator_fetch_next(self, &it);
}
@ -293,6 +322,7 @@ static void btstack_tlv_flash_bank_migrate(btstack_tlv_flash_bank_t * self){
self->write_offset = next_write_pos;
}
#ifndef ENABLE_TLV_FLASH_WRITE_ONCE
static void btstack_tlv_flash_bank_delete_tag_until_offset(btstack_tlv_flash_bank_t * self, uint32_t tag, uint32_t offset){
tlv_iterator_t it;
btstack_tlv_flash_bank_iterator_init(self, &it, self->current_bank);
@ -314,6 +344,7 @@ static void btstack_tlv_flash_bank_delete_tag_until_offset(btstack_tlv_flash_ban
tlv_iterator_fetch_next(self, &it);
}
}
#endif
/**
* Get Value for Tag
@ -335,7 +366,9 @@ static int btstack_tlv_flash_bank_get_tag(void * context, uint32_t tag, uint8_t
log_info("Found tag '%x' at position %u", (unsigned int) tag, (unsigned int) it.offset);
tag_index = it.offset;
tag_len = it.len;
#ifndef ENABLE_TLV_FLASH_WRITE_ONCE
break;
#endif
}
tlv_iterator_fetch_next(self, &it);
}
@ -391,8 +424,10 @@ static int btstack_tlv_flash_bank_store_tag(void * context, uint32_t tag, const
// then entry
btstack_tlv_flash_bank_write(self, self->current_bank, self->write_offset, entry, sizeof(entry));
#ifndef ENABLE_TLV_FLASH_WRITE_ONCE
// overwrite old entries (if exists)
btstack_tlv_flash_bank_delete_tag_until_offset(self, tag, self->write_offset);
#endif
// done
self->write_offset += sizeof(entry) + btstack_tlv_flash_bank_align_size(self, data_size);
@ -410,8 +445,12 @@ static int btstack_tlv_flash_bank_store_tag(void * context, uint32_t tag, const
* @param tag
*/
static void btstack_tlv_flash_bank_delete_tag(void * context, uint32_t tag){
btstack_tlv_flash_bank_t * self = (btstack_tlv_flash_bank_t *) context;
#ifdef ENABLE_TLV_FLASH_WRITE_ONCE
btstack_tlv_flash_bank_store_tag(context, tag, NULL, 0);
#else
btstack_tlv_flash_bank_t * self = (btstack_tlv_flash_bank_t *) context;
btstack_tlv_flash_bank_delete_tag_until_offset(self, tag, self->write_offset);
#endif
}
static const btstack_tlv_t btstack_tlv_flash_bank = {
@ -447,23 +486,29 @@ const btstack_tlv_t * btstack_tlv_flash_bank_init_instance(btstack_tlv_flash_ban
// find last entry and write offset
tlv_iterator_t it;
#ifndef ENABLE_TLV_FLASH_WRITE_ONCE
uint32_t last_tag = 0;
uint32_t last_offset = 0;
btstack_tlv_flash_bank_iterator_init(self, &it, self->current_bank);
#endif
btstack_tlv_flash_bank_iterator_init(self, &it, self->current_bank);
while (btstack_tlv_flash_bank_iterator_has_next(self, &it)){
#ifndef ENABLE_TLV_FLASH_WRITE_ONCE
last_tag = it.tag;
last_offset = it.offset;
#endif
tlv_iterator_fetch_next(self, &it);
}
self->write_offset = it.offset;
if (self->write_offset < self->hal_flash_bank_impl->get_size(self->hal_flash_bank_context)){
#ifndef ENABLE_TLV_FLASH_WRITE_ONCE
// delete older instances of last_tag
// this handles the unlikely case where MCU did reset after new value + header was written but before delete did complete
if (last_tag){
btstack_tlv_flash_bank_delete_tag_until_offset(self, last_tag, last_offset);
}
#endif
// verify that rest of bank is empty
// this handles the unlikely case where MCU did reset after new value was written, but not the tag