From f05153ed5c2e8dc54f64c238f3c0a63dc4aa836d Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 16 Sep 2021 19:12:07 +0300 Subject: [PATCH] [FL-1816] Fix ble radio stack is alive check (#707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bt: fix bt_is_alive return, add bt_is_active * bt: fix bt_is_alive return * Cli: show heap usage in ps. * FuriHal: strict sequence for flash operations * Scripts: add stress test * Core: proper heap calculation. Co-authored-by: あく --- applications/bt/bt_service/bt.c | 6 +-- applications/cli/cli_commands.c | 12 +++-- core/furi/memmgr_heap.c | 18 +++---- core/furi/memmgr_heap.h | 2 + firmware/targets/f6/furi-hal/furi-hal-bt.c | 26 +++++++--- firmware/targets/f6/furi-hal/furi-hal-flash.c | 12 ++--- firmware/targets/f7/furi-hal/furi-hal-bt.c | 26 +++++++--- firmware/targets/f7/furi-hal/furi-hal-flash.c | 12 ++--- .../targets/furi-hal-include/furi-hal-bt.h | 7 ++- scripts/storage.py | 48 +++++++++++++++++++ 10 files changed, 125 insertions(+), 44 deletions(-) diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index 672919fa066..d50cdf0e9ba 100755 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -67,17 +67,17 @@ int32_t bt_srv() { } } // Update statusbar - view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive()); + view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_active()); BtMessage message; while(1) { furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK); if(message.type == BtMessageTypeUpdateStatusbar) { // Update statusbar - view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive()); + view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_active()); } else if(message.type == BtMessageTypeUpdateBatteryLevel) { // Update battery level - if(furi_hal_bt_is_alive()) { + if(furi_hal_bt_is_active()) { battery_svc_update_level(message.data.battery_level); } } else if(message.type == BtMessageTypePinCodeShow) { diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index 616808e0a7c..eb459457b43 100644 --- a/applications/cli/cli_commands.c +++ b/applications/cli/cli_commands.c @@ -385,17 +385,19 @@ void cli_command_ps(Cli* cli, string_t args, void* context) { const uint8_t threads_num_max = 32; osThreadId_t threads_id[threads_num_max]; uint8_t thread_num = osThreadEnumerate(threads_id, threads_num_max); - printf("%d threads in total:\r\n", thread_num); - printf("%-20s %-14s %-14s %s\r\n", "Name", "Stack start", "Stack alloc", "Stack watermark"); + printf( + "%-20s %-14s %-8s %-8s %s\r\n", "Name", "Stack start", "Heap", "Stack", "Stack min free"); for(uint8_t i = 0; i < thread_num; i++) { TaskControlBlock* tcb = (TaskControlBlock*)threads_id[i]; printf( - "%-20s 0x%-12lx %-14ld %ld\r\n", + "%-20s 0x%-12lx %-8d %-8ld %-8ld\r\n", osThreadGetName(threads_id[i]), (uint32_t)tcb->pxStack, - (uint32_t)(tcb->pxEndOfStack - tcb->pxStack + 1) * sizeof(uint32_t), - osThreadGetStackSpace(threads_id[i]) * sizeof(uint32_t)); + memmgr_heap_get_thread_memory(threads_id[i]), + (uint32_t)(tcb->pxEndOfStack - tcb->pxStack + 1) * sizeof(StackType_t), + osThreadGetStackSpace(threads_id[i])); } + printf("\r\nTotal: %d", thread_num); } void cli_command_free(Cli* cli, string_t args, void* context) { diff --git a/core/furi/memmgr_heap.c b/core/furi/memmgr_heap.c index 16116f1e6ba..8e57914e96c 100644 --- a/core/furi/memmgr_heap.c +++ b/core/furi/memmgr_heap.c @@ -155,19 +155,21 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id) { } size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) { - size_t leftovers = 0; + size_t leftovers = MEMMGR_HEAP_UNKNOWN; vTaskSuspendAll(); { memmgr_heap_thread_trace_depth++; MemmgrHeapAllocDict_t* alloc_dict = MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); - furi_check(alloc_dict); - MemmgrHeapAllocDict_it_t alloc_dict_it; - for(MemmgrHeapAllocDict_it(alloc_dict_it, *alloc_dict); - !MemmgrHeapAllocDict_end_p(alloc_dict_it); - MemmgrHeapAllocDict_next(alloc_dict_it)) { - MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it); - leftovers += data->value; + if(alloc_dict) { + leftovers = 0; + MemmgrHeapAllocDict_it_t alloc_dict_it; + for(MemmgrHeapAllocDict_it(alloc_dict_it, *alloc_dict); + !MemmgrHeapAllocDict_end_p(alloc_dict_it); + MemmgrHeapAllocDict_next(alloc_dict_it)) { + MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it); + leftovers += data->value; + } } memmgr_heap_thread_trace_depth--; } diff --git a/core/furi/memmgr_heap.h b/core/furi/memmgr_heap.h index 327f8d4f0e7..cbb8fa89ced 100644 --- a/core/furi/memmgr_heap.h +++ b/core/furi/memmgr_heap.h @@ -7,6 +7,8 @@ extern "C" { #endif +#define MEMMGR_HEAP_UNKNOWN 0xFFFFFFFF + /** Memmgr heap enable thread allocation tracking * @param thread_id - thread id to track */ diff --git a/firmware/targets/f6/furi-hal/furi-hal-bt.c b/firmware/targets/f6/furi-hal/furi-hal-bt.c index 89e03b38127..7fab63edd3f 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f6/furi-hal/furi-hal-bt.c @@ -24,7 +24,7 @@ void furi_hal_bt_start_advertising() { } void furi_hal_bt_stop_advertising() { - if(furi_hal_bt_is_alive()) { + if(furi_hal_bt_is_active()) { gap_stop_advertising(); } } @@ -52,6 +52,11 @@ void furi_hal_bt_dump_state(string_t buffer) { } bool furi_hal_bt_is_alive() { + BleGlueStatus status = APPE_Status(); + return (status == BleGlueStatusBroken) || (status == BleGlueStatusStarted); +} + +bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } @@ -67,7 +72,7 @@ bool furi_hal_bt_wait_startup() { return true; } -bool furi_hal_bt_lock_flash() { +bool furi_hal_bt_lock_flash(bool erase_flag) { if (!furi_hal_bt_wait_startup()) { return false; } @@ -75,18 +80,25 @@ bool furi_hal_bt_lock_flash() { while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { osDelay(1); } - - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); + HAL_FLASH_Unlock(); - while(LL_FLASH_IsOperationSuspended()) {}; + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); + + while(LL_FLASH_IsActiveFlag_OperationSuspended()) {}; + + __disable_irq(); return true; } -void furi_hal_bt_unlock_flash() { - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); +void furi_hal_bt_unlock_flash(bool erase_flag) { + __enable_irq(); + + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + HAL_FLASH_Lock(); + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); } diff --git a/firmware/targets/f6/furi-hal/furi-hal-flash.c b/firmware/targets/f6/furi-hal/furi-hal-flash.c index 5346965fd30..c9922122ef3 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-flash.c +++ b/firmware/targets/f6/furi-hal/furi-hal-flash.c @@ -57,7 +57,7 @@ size_t furi_hal_flash_get_free_page_count() { } bool furi_hal_flash_erase(uint8_t page, uint8_t count) { - if (!furi_hal_bt_lock_flash()) { + if (!furi_hal_bt_lock_flash(true)) { return false; } FLASH_EraseInitTypeDef erase; @@ -66,24 +66,24 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count) { erase.NbPages = count; uint32_t error; HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); - furi_hal_bt_unlock_flash(); + furi_hal_bt_unlock_flash(true); return status == HAL_OK; } bool furi_hal_flash_write_dword(size_t address, uint64_t data) { - if (!furi_hal_bt_lock_flash()) { + if (!furi_hal_bt_lock_flash(false)) { return false; } HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); - furi_hal_bt_unlock_flash(); + furi_hal_bt_unlock_flash(false); return status == HAL_OK; } bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { - if (!furi_hal_bt_lock_flash()) { + if (!furi_hal_bt_lock_flash(false)) { return false; } HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); - furi_hal_bt_unlock_flash(); + furi_hal_bt_unlock_flash(false); return status == HAL_OK; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-bt.c b/firmware/targets/f7/furi-hal/furi-hal-bt.c index 89e03b38127..7fab63edd3f 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f7/furi-hal/furi-hal-bt.c @@ -24,7 +24,7 @@ void furi_hal_bt_start_advertising() { } void furi_hal_bt_stop_advertising() { - if(furi_hal_bt_is_alive()) { + if(furi_hal_bt_is_active()) { gap_stop_advertising(); } } @@ -52,6 +52,11 @@ void furi_hal_bt_dump_state(string_t buffer) { } bool furi_hal_bt_is_alive() { + BleGlueStatus status = APPE_Status(); + return (status == BleGlueStatusBroken) || (status == BleGlueStatusStarted); +} + +bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } @@ -67,7 +72,7 @@ bool furi_hal_bt_wait_startup() { return true; } -bool furi_hal_bt_lock_flash() { +bool furi_hal_bt_lock_flash(bool erase_flag) { if (!furi_hal_bt_wait_startup()) { return false; } @@ -75,18 +80,25 @@ bool furi_hal_bt_lock_flash() { while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { osDelay(1); } - - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); + HAL_FLASH_Unlock(); - while(LL_FLASH_IsOperationSuspended()) {}; + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); + + while(LL_FLASH_IsActiveFlag_OperationSuspended()) {}; + + __disable_irq(); return true; } -void furi_hal_bt_unlock_flash() { - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); +void furi_hal_bt_unlock_flash(bool erase_flag) { + __enable_irq(); + + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + HAL_FLASH_Lock(); + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); } diff --git a/firmware/targets/f7/furi-hal/furi-hal-flash.c b/firmware/targets/f7/furi-hal/furi-hal-flash.c index 5346965fd30..c9922122ef3 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-flash.c +++ b/firmware/targets/f7/furi-hal/furi-hal-flash.c @@ -57,7 +57,7 @@ size_t furi_hal_flash_get_free_page_count() { } bool furi_hal_flash_erase(uint8_t page, uint8_t count) { - if (!furi_hal_bt_lock_flash()) { + if (!furi_hal_bt_lock_flash(true)) { return false; } FLASH_EraseInitTypeDef erase; @@ -66,24 +66,24 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count) { erase.NbPages = count; uint32_t error; HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); - furi_hal_bt_unlock_flash(); + furi_hal_bt_unlock_flash(true); return status == HAL_OK; } bool furi_hal_flash_write_dword(size_t address, uint64_t data) { - if (!furi_hal_bt_lock_flash()) { + if (!furi_hal_bt_lock_flash(false)) { return false; } HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); - furi_hal_bt_unlock_flash(); + furi_hal_bt_unlock_flash(false); return status == HAL_OK; } bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { - if (!furi_hal_bt_lock_flash()) { + if (!furi_hal_bt_lock_flash(false)) { return false; } HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); - furi_hal_bt_unlock_flash(); + furi_hal_bt_unlock_flash(false); return status == HAL_OK; } diff --git a/firmware/targets/furi-hal-include/furi-hal-bt.h b/firmware/targets/furi-hal-include/furi-hal-bt.h index c5c284dba77..61cc413e77f 100644 --- a/firmware/targets/furi-hal-include/furi-hal-bt.h +++ b/firmware/targets/furi-hal-include/furi-hal-bt.h @@ -19,6 +19,9 @@ void furi_hal_bt_start_advertising(); /** Stop advertising */ void furi_hal_bt_stop_advertising(); +/** Returns true if BLE is advertising */ +bool furi_hal_bt_is_active(); + /** Get BT/BLE system component state */ void furi_hal_bt_dump_state(string_t buffer); @@ -32,10 +35,10 @@ bool furi_hal_bt_wait_startup(); * Lock shared access to flash controller * @return true if lock was successful, false if not */ -bool furi_hal_bt_lock_flash(); +bool furi_hal_bt_lock_flash(bool erase_flag); /** Unlock shared access to flash controller */ -void furi_hal_bt_unlock_flash(); +void furi_hal_bt_unlock_flash(bool erase_flag); /** Start ble tone tx at given channel and power */ void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power); diff --git a/scripts/storage.py b/scripts/storage.py index 739686b693c..a56dcd8b9b9 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -1,12 +1,15 @@ #!/usr/bin/env python3 from flipper.storage import FlipperStorage + import logging import argparse import os import sys import binascii import posixpath +import filecmp +import tempfile class Main: @@ -56,6 +59,16 @@ def __init__(self): self.parser_list.add_argument("flipper_path", help="Flipper path", default="/") self.parser_list.set_defaults(func=self.list) + self.parser_stress = self.subparsers.add_parser("stress", help="Stress test") + self.parser.add_argument( + "-c", "--count", type=int, default=10, help="Iteration count" + ) + self.parser_stress.add_argument("flipper_path", help="Flipper path") + self.parser_stress.add_argument( + "file_size", type=int, help="Test file size in bytes" + ) + self.parser_stress.set_defaults(func=self.stress) + # logging self.logger = logging.getLogger() @@ -262,6 +275,41 @@ def list(self): storage.list_tree(self.args.flipper_path) storage.stop() + def stress(self): + self.logger.error("This test is wearing out flash memory.") + self.logger.error("Never use it with internal storage(/int)") + + if self.args.flipper_path.startswith( + "/int" + ) or self.args.flipper_path.startswith("/any"): + self.logger.error("Stop at this point or device warranty will be void") + say = input("Anything to say? ").strip().lower() + if say != "void": + return + say = input("Why, Mr. Anderson? ").strip().lower() + if say != "because": + return + + with tempfile.TemporaryDirectory() as tmpdirname: + send_file_name = os.path.join(tmpdirname, "send") + receive_file_name = os.path.join(tmpdirname, "receive") + open(send_file_name, "w").write("A" * self.args.file_size) + storage = FlipperStorage(self.args.port) + storage.start() + if storage.exist_file(self.args.flipper_path): + self.logger.error("File exists, remove it first") + return + while self.args.count > 0: + storage.send_file(send_file_name, self.args.flipper_path) + storage.receive_file(self.args.flipper_path, receive_file_name) + if not filecmp.cmp(receive_file_name, send_file_name): + self.logger.error("Files mismatch") + break + storage.remove(self.args.flipper_path) + os.unlink(receive_file_name) + self.args.count -= 1 + storage.stop() + if __name__ == "__main__": Main()()