diff --git a/CHANGELOG.md b/CHANGELOG.md index 114b685f7..483a37c23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/doc/manual/docs-template/how_to.md b/doc/manual/docs-template/how_to.md index 521ff1242..1f45278fe 100644 --- a/doc/manual/docs-template/how_to.md +++ b/doc/manual/docs-template/how_to.md @@ -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: diff --git a/platform/embedded/btstack_tlv_flash_bank.c b/platform/embedded/btstack_tlv_flash_bank.c index 4abd8cff1..56c79554f 100644 --- a/platform/embedded/btstack_tlv_flash_bank.c +++ b/platform/embedded/btstack_tlv_flash_bank.c @@ -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