Просмотр исходного кода

[FL-1816] Fix ble radio stack is alive check (#707)

* 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: あく <alleteam@gmail.com>
gornekich 4 лет назад
Родитель
Сommit
f05153ed5c

+ 3 - 3
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) {

+ 7 - 5
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) {

+ 10 - 8
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--;
     }

+ 2 - 0
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
  */

+ 19 - 7
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);
 }
 

+ 6 - 6
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;
 }

+ 19 - 7
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);
 }
 

+ 6 - 6
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;
 }

+ 5 - 2
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);

+ 48 - 0
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 @@ class Main:
         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 @@ class Main:
         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()()