[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>
This commit is contained in:
gornekich 2021-09-16 19:12:07 +03:00 committed by GitHub
parent b4ffc1f81b
commit f05153ed5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 125 additions and 44 deletions

View File

@ -67,17 +67,17 @@ int32_t bt_srv() {
} }
} }
// Update statusbar // 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; BtMessage message;
while(1) { while(1) {
furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK); furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK);
if(message.type == BtMessageTypeUpdateStatusbar) { if(message.type == BtMessageTypeUpdateStatusbar) {
// Update statusbar // 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) { } else if(message.type == BtMessageTypeUpdateBatteryLevel) {
// Update battery level // Update battery level
if(furi_hal_bt_is_alive()) { if(furi_hal_bt_is_active()) {
battery_svc_update_level(message.data.battery_level); battery_svc_update_level(message.data.battery_level);
} }
} else if(message.type == BtMessageTypePinCodeShow) { } else if(message.type == BtMessageTypePinCodeShow) {

View File

@ -385,17 +385,19 @@ void cli_command_ps(Cli* cli, string_t args, void* context) {
const uint8_t threads_num_max = 32; const uint8_t threads_num_max = 32;
osThreadId_t threads_id[threads_num_max]; osThreadId_t threads_id[threads_num_max];
uint8_t thread_num = osThreadEnumerate(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(
printf("%-20s %-14s %-14s %s\r\n", "Name", "Stack start", "Stack alloc", "Stack watermark"); "%-20s %-14s %-8s %-8s %s\r\n", "Name", "Stack start", "Heap", "Stack", "Stack min free");
for(uint8_t i = 0; i < thread_num; i++) { for(uint8_t i = 0; i < thread_num; i++) {
TaskControlBlock* tcb = (TaskControlBlock*)threads_id[i]; TaskControlBlock* tcb = (TaskControlBlock*)threads_id[i];
printf( printf(
"%-20s 0x%-12lx %-14ld %ld\r\n", "%-20s 0x%-12lx %-8d %-8ld %-8ld\r\n",
osThreadGetName(threads_id[i]), osThreadGetName(threads_id[i]),
(uint32_t)tcb->pxStack, (uint32_t)tcb->pxStack,
(uint32_t)(tcb->pxEndOfStack - tcb->pxStack + 1) * sizeof(uint32_t), memmgr_heap_get_thread_memory(threads_id[i]),
osThreadGetStackSpace(threads_id[i]) * sizeof(uint32_t)); (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) { void cli_command_free(Cli* cli, string_t args, void* context) {

View File

@ -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 memmgr_heap_get_thread_memory(osThreadId_t thread_id) {
size_t leftovers = 0; size_t leftovers = MEMMGR_HEAP_UNKNOWN;
vTaskSuspendAll(); vTaskSuspendAll();
{ {
memmgr_heap_thread_trace_depth++; memmgr_heap_thread_trace_depth++;
MemmgrHeapAllocDict_t* alloc_dict = MemmgrHeapAllocDict_t* alloc_dict =
MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id);
furi_check(alloc_dict); if(alloc_dict) {
MemmgrHeapAllocDict_it_t alloc_dict_it; leftovers = 0;
for(MemmgrHeapAllocDict_it(alloc_dict_it, *alloc_dict); MemmgrHeapAllocDict_it_t alloc_dict_it;
!MemmgrHeapAllocDict_end_p(alloc_dict_it); for(MemmgrHeapAllocDict_it(alloc_dict_it, *alloc_dict);
MemmgrHeapAllocDict_next(alloc_dict_it)) { !MemmgrHeapAllocDict_end_p(alloc_dict_it);
MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it); MemmgrHeapAllocDict_next(alloc_dict_it)) {
leftovers += data->value; MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it);
leftovers += data->value;
}
} }
memmgr_heap_thread_trace_depth--; memmgr_heap_thread_trace_depth--;
} }

View File

@ -7,6 +7,8 @@
extern "C" { extern "C" {
#endif #endif
#define MEMMGR_HEAP_UNKNOWN 0xFFFFFFFF
/** Memmgr heap enable thread allocation tracking /** Memmgr heap enable thread allocation tracking
* @param thread_id - thread id to track * @param thread_id - thread id to track
*/ */

View File

@ -24,7 +24,7 @@ void furi_hal_bt_start_advertising() {
} }
void furi_hal_bt_stop_advertising() { void furi_hal_bt_stop_advertising() {
if(furi_hal_bt_is_alive()) { if(furi_hal_bt_is_active()) {
gap_stop_advertising(); gap_stop_advertising();
} }
} }
@ -52,6 +52,11 @@ void furi_hal_bt_dump_state(string_t buffer) {
} }
bool furi_hal_bt_is_alive() { 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; return gap_get_state() > GapStateIdle;
} }
@ -67,7 +72,7 @@ bool furi_hal_bt_wait_startup() {
return true; return true;
} }
bool furi_hal_bt_lock_flash() { bool furi_hal_bt_lock_flash(bool erase_flag) {
if (!furi_hal_bt_wait_startup()) { if (!furi_hal_bt_wait_startup()) {
return false; return false;
} }
@ -75,18 +80,25 @@ bool furi_hal_bt_lock_flash() {
while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) {
osDelay(1); osDelay(1);
} }
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
HAL_FLASH_Unlock(); 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; return true;
} }
void furi_hal_bt_unlock_flash() { void furi_hal_bt_unlock_flash(bool erase_flag) {
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); __enable_irq();
if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF);
HAL_FLASH_Lock(); HAL_FLASH_Lock();
HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID);
} }

View File

@ -57,7 +57,7 @@ size_t furi_hal_flash_get_free_page_count() {
} }
bool furi_hal_flash_erase(uint8_t page, uint8_t 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; return false;
} }
FLASH_EraseInitTypeDef erase; FLASH_EraseInitTypeDef erase;
@ -66,24 +66,24 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count) {
erase.NbPages = count; erase.NbPages = count;
uint32_t error; uint32_t error;
HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error);
furi_hal_bt_unlock_flash(); furi_hal_bt_unlock_flash(true);
return status == HAL_OK; return status == HAL_OK;
} }
bool furi_hal_flash_write_dword(size_t address, uint64_t data) { 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; return false;
} }
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); 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; return status == HAL_OK;
} }
bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { 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; return false;
} }
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); 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; return status == HAL_OK;
} }

View File

@ -24,7 +24,7 @@ void furi_hal_bt_start_advertising() {
} }
void furi_hal_bt_stop_advertising() { void furi_hal_bt_stop_advertising() {
if(furi_hal_bt_is_alive()) { if(furi_hal_bt_is_active()) {
gap_stop_advertising(); gap_stop_advertising();
} }
} }
@ -52,6 +52,11 @@ void furi_hal_bt_dump_state(string_t buffer) {
} }
bool furi_hal_bt_is_alive() { 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; return gap_get_state() > GapStateIdle;
} }
@ -67,7 +72,7 @@ bool furi_hal_bt_wait_startup() {
return true; return true;
} }
bool furi_hal_bt_lock_flash() { bool furi_hal_bt_lock_flash(bool erase_flag) {
if (!furi_hal_bt_wait_startup()) { if (!furi_hal_bt_wait_startup()) {
return false; return false;
} }
@ -75,18 +80,25 @@ bool furi_hal_bt_lock_flash() {
while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) {
osDelay(1); osDelay(1);
} }
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
HAL_FLASH_Unlock(); 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; return true;
} }
void furi_hal_bt_unlock_flash() { void furi_hal_bt_unlock_flash(bool erase_flag) {
SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); __enable_irq();
if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF);
HAL_FLASH_Lock(); HAL_FLASH_Lock();
HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID);
} }

View File

@ -57,7 +57,7 @@ size_t furi_hal_flash_get_free_page_count() {
} }
bool furi_hal_flash_erase(uint8_t page, uint8_t 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; return false;
} }
FLASH_EraseInitTypeDef erase; FLASH_EraseInitTypeDef erase;
@ -66,24 +66,24 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count) {
erase.NbPages = count; erase.NbPages = count;
uint32_t error; uint32_t error;
HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error);
furi_hal_bt_unlock_flash(); furi_hal_bt_unlock_flash(true);
return status == HAL_OK; return status == HAL_OK;
} }
bool furi_hal_flash_write_dword(size_t address, uint64_t data) { 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; return false;
} }
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); 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; return status == HAL_OK;
} }
bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { 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; return false;
} }
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); 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; return status == HAL_OK;
} }

View File

@ -19,6 +19,9 @@ void furi_hal_bt_start_advertising();
/** Stop advertising */ /** Stop advertising */
void furi_hal_bt_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 */ /** Get BT/BLE system component state */
void furi_hal_bt_dump_state(string_t buffer); 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 * Lock shared access to flash controller
* @return true if lock was successful, false if not * @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 */ /** 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 */ /** Start ble tone tx at given channel and power */
void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power); void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power);

View File

@ -1,12 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from flipper.storage import FlipperStorage from flipper.storage import FlipperStorage
import logging import logging
import argparse import argparse
import os import os
import sys import sys
import binascii import binascii
import posixpath import posixpath
import filecmp
import tempfile
class Main: class Main:
@ -56,6 +59,16 @@ class Main:
self.parser_list.add_argument("flipper_path", help="Flipper path", default="/") self.parser_list.add_argument("flipper_path", help="Flipper path", default="/")
self.parser_list.set_defaults(func=self.list) 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 # logging
self.logger = logging.getLogger() self.logger = logging.getLogger()
@ -262,6 +275,41 @@ class Main:
storage.list_tree(self.args.flipper_path) storage.list_tree(self.args.flipper_path)
storage.stop() 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__": if __name__ == "__main__":
Main()() Main()()