diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index de4c58d4..aa999e36 100755 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -1,5 +1,6 @@ #include "bt_i.h" #include "battery_service.h" +#include "bt_keys_storage.h" #define BT_SERVICE_TAG "BT" @@ -161,6 +162,14 @@ static void bt_on_gap_event_callback(BleEvent event, void* context) { } } +static void bt_on_key_storage_change_callback(uint8_t* addr, uint16_t size, void* context) { + furi_assert(context); + Bt* bt = context; + FURI_LOG_I(BT_SERVICE_TAG, "Changed addr start: %08lX, size changed: %d", addr, size); + BtMessage message = {.type = BtMessageTypeKeysStorageUpdated}; + furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); +} + static void bt_statusbar_update(Bt* bt) { if(bt->status == BtStatusAdvertising) { view_port_set_width(bt->statusbar_view_port, icon_get_width(&I_Bluetooth_5x8)); @@ -177,7 +186,12 @@ int32_t bt_srv() { Bt* bt = bt_alloc(); furi_record_create("bt", bt); - if(!furi_hal_bt_wait_startup()) { + // Read keys + if(!bt_load_key_storage(bt)) { + FURI_LOG_W(BT_SERVICE_TAG, "Failed to load saved bonding keys"); + } + // Start 2nd core + if(!furi_hal_bt_start_core2()) { FURI_LOG_E(BT_SERVICE_TAG, "Core2 startup failed"); } else { view_port_enabled_set(bt->statusbar_view_port, true); @@ -190,6 +204,8 @@ int32_t bt_srv() { FURI_LOG_E(BT_SERVICE_TAG, "BT App start failed"); } } + furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); + // Update statusbar bt_statusbar_update(bt); @@ -207,6 +223,8 @@ int32_t bt_srv() { } else if(message.type == BtMessageTypePinCodeShow) { // Display PIN code bt_pin_code_show_event_handler(bt, message.data.pin_code); + } else if(message.type == BtMessageTypeKeysStorageUpdated) { + bt_save_key_storage(bt); } } return 0; diff --git a/applications/bt/bt_service/bt_i.h b/applications/bt/bt_service/bt_i.h index 0588378e..3921a4c5 100644 --- a/applications/bt/bt_service/bt_i.h +++ b/applications/bt/bt_service/bt_i.h @@ -25,6 +25,7 @@ typedef enum { BtMessageTypeUpdateStatusbar, BtMessageTypeUpdateBatteryLevel, BtMessageTypePinCodeShow, + BtMessageTypeKeysStorageUpdated, } BtMessageType; typedef union { @@ -38,6 +39,8 @@ typedef struct { } BtMessage; struct Bt { + uint8_t* bt_keys_addr_start; + uint16_t bt_keys_size; BtSettings bt_settings; BtStatus status; osMessageQueueId_t message_queue; diff --git a/applications/bt/bt_service/bt_keys_storage.c b/applications/bt/bt_service/bt_keys_storage.c new file mode 100644 index 00000000..25c74882 --- /dev/null +++ b/applications/bt/bt_service/bt_keys_storage.c @@ -0,0 +1,41 @@ +#include "bt_keys_storage.h" +#include +#include + +#define BT_KEYS_STORAGE_TAG "bt keys storage" +#define BT_KEYS_STORAGE_PATH "/int/bt.keys" + +bool bt_load_key_storage(Bt* bt) { + furi_assert(bt); + + bool file_loaded = false; + furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size); + + FileWorker* file_worker = file_worker_alloc(true); + if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + furi_hal_bt_nvm_sram_sem_acquire(); + if(file_worker_read(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { + file_loaded = true; + } + furi_hal_bt_nvm_sram_sem_release(); + } + file_worker_free(file_worker); + return file_loaded; +} + +bool bt_save_key_storage(Bt* bt) { + furi_assert(bt); + furi_assert(bt->bt_keys_addr_start); + + bool file_saved = false; + FileWorker* file_worker = file_worker_alloc(true); + if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { + furi_hal_bt_nvm_sram_sem_acquire(); + if(file_worker_write(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { + file_saved = true; + } + furi_hal_bt_nvm_sram_sem_release(); + } + file_worker_free(file_worker); + return file_saved; +} diff --git a/applications/bt/bt_service/bt_keys_storage.h b/applications/bt/bt_service/bt_keys_storage.h new file mode 100644 index 00000000..4b09d7f2 --- /dev/null +++ b/applications/bt/bt_service/bt_keys_storage.h @@ -0,0 +1,7 @@ +#pragma once + +#include "bt_i.h" + +bool bt_load_key_storage(Bt* bt); + +bool bt_save_key_storage(Bt* bt); diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c index 374a5f09..5ae97951 100644 --- a/applications/desktop/desktop.c +++ b/applications/desktop/desktop.c @@ -122,8 +122,7 @@ int32_t desktop_srv(void* p) { if(!loaded) { furi_hal_lock_set(false); memset(&desktop->settings, 0, sizeof(desktop->settings)); - bool saved = SAVE_DESKTOP_SETTINGS(&desktop->settings); - furi_check(saved); + SAVE_DESKTOP_SETTINGS(&desktop->settings); } scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); diff --git a/applications/dolphin/helpers/dolphin_state.c b/applications/dolphin/helpers/dolphin_state.c index 450add29..379908c9 100644 --- a/applications/dolphin/helpers/dolphin_state.c +++ b/applications/dolphin/helpers/dolphin_state.c @@ -4,9 +4,10 @@ #include #include -#define DOLPHIN_STORE_PATH "/int/dolphin.state" -#define DOLPHIN_STORE_HEADER_MAGIC 0xD0 -#define DOLPHIN_STORE_HEADER_VERSION 0x01 +#define DOLPHIN_STATE_TAG "DolphinState" +#define DOLPHIN_STATE_PATH "/int/dolphin.state" +#define DOLPHIN_STATE_HEADER_MAGIC 0xD0 +#define DOLPHIN_STATE_HEADER_VERSION 0x01 #define DOLPHIN_LVL_THRESHOLD 20.0f typedef struct { @@ -35,28 +36,42 @@ void dolphin_state_free(DolphinState* dolphin_state) { } bool dolphin_state_save(DolphinState* dolphin_state) { - return saved_struct_save( - DOLPHIN_STORE_PATH, + if(!dolphin_state->dirty) { + return true; + } + + bool result = saved_struct_save( + DOLPHIN_STATE_PATH, &dolphin_state->data, sizeof(DolphinStoreData), - DOLPHIN_STORE_HEADER_MAGIC, - DOLPHIN_STORE_HEADER_VERSION); + DOLPHIN_STATE_HEADER_MAGIC, + DOLPHIN_STATE_HEADER_VERSION); + + if(result) { + FURI_LOG_I(DOLPHIN_STATE_TAG, "State saved"); + dolphin_state->dirty = false; + } else { + FURI_LOG_E(DOLPHIN_STATE_TAG, "Failed to save state"); + } + + return result; } bool dolphin_state_load(DolphinState* dolphin_state) { bool loaded = saved_struct_load( - DOLPHIN_STORE_PATH, + DOLPHIN_STATE_PATH, &dolphin_state->data, sizeof(DolphinStoreData), - DOLPHIN_STORE_HEADER_MAGIC, - DOLPHIN_STORE_HEADER_VERSION); + DOLPHIN_STATE_HEADER_MAGIC, + DOLPHIN_STATE_HEADER_VERSION); + if(!loaded) { - FURI_LOG_W("dolphin-state", "Reset dolphin-state"); + FURI_LOG_W(DOLPHIN_STATE_TAG, "Reset dolphin-state"); memset(dolphin_state, 0, sizeof(*dolphin_state)); - dolphin_state_save(dolphin_state); + dolphin_state->dirty = true; } - return true; + return loaded; } uint64_t dolphin_state_timestamp() { diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 2976f909..46a515a0 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -189,7 +189,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { } else if(input_event->type == InputTypePress) { gui->ongoing_input |= key_bit; } else if(!(gui->ongoing_input & key_bit)) { - FURI_LOG_W( + FURI_LOG_D( "Gui", "non-complementary input, discarding key: %s type: %s, sequence: %p", input_get_key_name(input_event->key), @@ -211,7 +211,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { if(view_port && view_port == gui->ongoing_input_view_port) { view_port_input(view_port, input_event); } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) { - FURI_LOG_W( + FURI_LOG_D( "Gui", "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", gui->ongoing_input_view_port, @@ -221,7 +221,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { input_event->sequence); view_port_input(gui->ongoing_input_view_port, input_event); } else { - FURI_LOG_W( + FURI_LOG_D( "Gui", "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p", gui->ongoing_input_view_port, diff --git a/applications/gui/view_dispatcher.c b/applications/gui/view_dispatcher.c index c0246d97..e50c1809 100644 --- a/applications/gui/view_dispatcher.c +++ b/applications/gui/view_dispatcher.c @@ -236,7 +236,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e } else if(event->type == InputTypeRelease) { view_dispatcher->ongoing_input &= ~key_bit; } else if(!(view_dispatcher->ongoing_input & key_bit)) { - FURI_LOG_W( + FURI_LOG_D( "ViewDispatcher", "non-complementary input, discarding key: %s, type: %s, sequence: %p", input_get_key_name(event->key), @@ -275,7 +275,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e } } } else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) { - FURI_LOG_W( + FURI_LOG_D( "ViewDispatcher", "View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", view_dispatcher->ongoing_input_view, diff --git a/applications/storage/storages/storage-int.c b/applications/storage/storages/storage-int.c index fb4c07be..4a1dca7c 100644 --- a/applications/storage/storages/storage-int.c +++ b/applications/storage/storages/storage-int.c @@ -119,7 +119,7 @@ static int storage_int_device_erase(const struct lfs_config* c, lfs_block_t bloc LFSData* lfs_data = c->context; size_t page = lfs_data->start_page + block; - FURI_LOG_D(TAG, "Device erase: page %d, translated page: %d", block, page); + FURI_LOG_D(TAG, "Device erase: page %d, translated page: %x", block, page); if(furi_hal_flash_erase(page, 1)) { return 0; diff --git a/firmware/targets/f6/ble-glue/app_conf.h b/firmware/targets/f6/ble-glue/app_conf.h index e3820e11..eebdbbdb 100644 --- a/firmware/targets/f6/ble-glue/app_conf.h +++ b/firmware/targets/f6/ble-glue/app_conf.h @@ -427,16 +427,5 @@ typedef enum #define DBG_TRACE_MSG_QUEUE_SIZE 4096 #define MAX_DBG_TRACE_MSG_SIZE 1024 -/****************************************************************************** - * FreeRTOS - ******************************************************************************/ -#define CFG_SHCI_USER_EVT_PROCESS_NAME "ble_shci_evt" -#define CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_SIZE (0) -#define CFG_SHCI_USER_EVT_PROCESS_STACK_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_PRIORITY osPriorityNone -#define CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE (128 * 7) - #define CFG_OTP_BASE_ADDRESS OTP_AREA_BASE #define CFG_OTP_END_ADRESS OTP_AREA_END_ADDR diff --git a/firmware/targets/f6/ble-glue/app_entry.c b/firmware/targets/f6/ble-glue/app_entry.c deleted file mode 100644 index 5c8c0b2a..00000000 --- a/firmware/targets/f6/ble-glue/app_entry.c +++ /dev/null @@ -1,180 +0,0 @@ -#include "app_common.h" -#include "main.h" -#include "app_entry.h" -#include "ble_app.h" -#include "ble.h" -#include "tl.h" -#include "cmsis_os.h" -#include "shci_tl.h" -#include "app_debug.h" -#include - -extern RTC_HandleTypeDef hrtc; - -#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) - -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t EvtPool[POOL_SIZE]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; - -osMutexId_t MtxShciId; -osSemaphoreId_t SemShciId; -osThreadId_t ShciUserEvtProcessId; - -volatile static BleGlueStatus ble_glue_status = BleGlueStatusUninitialized; - -const osThreadAttr_t ShciUserEvtProcess_attr = { - .name = CFG_SHCI_USER_EVT_PROCESS_NAME, - .attr_bits = CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS, - .cb_mem = CFG_SHCI_USER_EVT_PROCESS_CB_MEM, - .cb_size = CFG_SHCI_USER_EVT_PROCESS_CB_SIZE, - .stack_mem = CFG_SHCI_USER_EVT_PROCESS_STACK_MEM, - .priority = CFG_SHCI_USER_EVT_PROCESS_PRIORITY, - .stack_size = CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE -}; - -static void ShciUserEvtProcess(void *argument); -static void SystemPower_Config( void ); -static void appe_Tl_Init( void ); -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ); -static void APPE_SysUserEvtRx( void * pPayload ); - -BleGlueStatus APPE_Status() { - return ble_glue_status; -} - -void APPE_Init() { - ble_glue_status = BleGlueStatusStartup; - SystemPower_Config(); /**< Configure the system Power Mode */ - - // APPD_Init(); - furi_hal_power_insomnia_enter(); - - appe_Tl_Init(); /* Initialize all transport layers */ - - /** - * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) - * received on the system channel before starting the Stack - * This system event is received with APPE_SysUserEvtRx() - */ -} - -/************************************************************* - * - * LOCAL FUNCTIONS - * - *************************************************************/ - -/** - * @brief Configure the system for power optimization - * - * @note This API configures the system to be ready for low power mode - * - * @param None - * @retval None - */ -static void SystemPower_Config(void) { - // Select HSI as system clock source after Wake Up from Stop mode - LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); - - /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ - LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); -} - -static void appe_Tl_Init( void ) { - TL_MM_Config_t tl_mm_config; - SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; - /**< Reference table initialization */ - TL_Init(); - - MtxShciId = osMutexNew( NULL ); - SemShciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */ - - /** FreeRTOS system task creation */ - ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr); - - /**< System channel initialization */ - SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer; - SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot; - shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf); - - /**< Memory Manager channel initialization */ - tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer; - tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer; - tl_mm_config.p_AsynchEvtPool = EvtPool; - tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; - TL_MM_Init( &tl_mm_config ); - - TL_Enable(); -} - -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ) { - switch (status) { - case SHCI_TL_CmdBusy: - osMutexAcquire( MtxShciId, osWaitForever ); - break; - case SHCI_TL_CmdAvailable: - osMutexRelease( MtxShciId ); - break; - default: - break; - } -} - -/** - * The type of the payload for a system user event is tSHCI_UserEvtRxParam - * When the system event is both : - * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) - * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) - * The buffer shall not be released - * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) - * When the status is not filled, the buffer is released by default - */ -static void APPE_SysUserEvtRx( void * pPayload ) { - UNUSED(pPayload); - /* Traces channel initialization */ - // APPD_EnableCPU2( ); - - if(ble_app_init()) { - FURI_LOG_I("Core2", "BLE stack started"); - ble_glue_status = BleGlueStatusStarted; - } else { - FURI_LOG_E("Core2", "BLE stack startup failed"); - ble_glue_status = BleGlueStatusBroken; - } - furi_hal_power_insomnia_exit(); -} - -/************************************************************* - * - * FREERTOS WRAPPER FUNCTIONS - * -*************************************************************/ -static void ShciUserEvtProcess(void *argument) { - UNUSED(argument); - for(;;) { - osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); - shci_user_evt_proc(); - } -} - -/************************************************************* - * - * WRAP FUNCTIONS - * - *************************************************************/ -void shci_notify_asynch_evt(void* pdata) { - UNUSED(pdata); - osThreadFlagsSet( ShciUserEvtProcessId, 1 ); -} - -void shci_cmd_resp_release(uint32_t flag) { - UNUSED(flag); - osSemaphoreRelease( SemShciId ); -} - -void shci_cmd_resp_wait(uint32_t timeout) { - UNUSED(timeout); - osSemaphoreAcquire( SemShciId, osWaitForever ); -} diff --git a/firmware/targets/f6/ble-glue/app_entry.h b/firmware/targets/f6/ble-glue/app_entry.h deleted file mode 100644 index f1ce6038..00000000 --- a/firmware/targets/f6/ble-glue/app_entry.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - BleGlueStatusUninitialized, - BleGlueStatusStartup, - BleGlueStatusBroken, - BleGlueStatusStarted -} BleGlueStatus; - -void APPE_Init(); - -BleGlueStatus APPE_Status(); - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/firmware/targets/f6/ble-glue/ble_app.c b/firmware/targets/f6/ble-glue/ble_app.c index e28facd6..33e5264a 100644 --- a/firmware/targets/f6/ble-glue/ble_app.c +++ b/firmware/targets/f6/ble-glue/ble_app.c @@ -11,6 +11,7 @@ #define BLE_APP_TAG "ble app" PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; typedef struct { osMutexId_t hci_mtx; @@ -26,8 +27,8 @@ static void ble_app_hci_event_handler(void * pPayload); static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status); bool ble_app_init() { + SHCI_CmdStatus_t status; ble_app = furi_alloc(sizeof(BleApp)); - // Allocate semafore and mutex for ble command buffer access ble_app->hci_mtx = osMutexNew(NULL); ble_app->hci_sem = osSemaphoreNew(1, 0, NULL); @@ -43,6 +44,18 @@ bool ble_app_init() { }; hci_init(ble_app_hci_event_handler, (void*)&hci_tl_config); + // Configure NVM store for pairing data + SHCI_C2_CONFIG_Cmd_Param_t config_param = { + .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, + .Config1 =SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, + .BleNvmRamAddress = (uint32_t)ble_app_nvm, + .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, + }; + status = SHCI_C2_Config(&config_param); + if(status) { + FURI_LOG_E(BLE_APP_TAG, "Failed to configure 2nd core: %d", status); + } + // Start ble stack on 2nd core SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { .Header = {{0,0,0}}, // Header unused @@ -67,13 +80,18 @@ bool ble_app_init() { 0, } }; - SHCI_CmdStatus_t status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); + status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); if(status) { FURI_LOG_E(BLE_APP_TAG, "Failed to start ble stack: %d", status); } return status == SHCI_Success; } +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) { + *addr = (uint8_t*)ble_app_nvm; + *size = sizeof(ble_app_nvm); +} + static void ble_app_hci_thread(void *arg) { while(1) { osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); diff --git a/firmware/targets/f6/ble-glue/ble_app.h b/firmware/targets/f6/ble-glue/ble_app.h index 17d8dc5f..64000bde 100644 --- a/firmware/targets/f6/ble-glue/ble_app.h +++ b/firmware/targets/f6/ble-glue/ble_app.h @@ -5,8 +5,10 @@ extern "C" { #endif #include +#include bool ble_app_init(); +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size); #ifdef __cplusplus } diff --git a/firmware/targets/f6/ble-glue/ble_glue.c b/firmware/targets/f6/ble-glue/ble_glue.c new file mode 100644 index 00000000..4a9c144e --- /dev/null +++ b/firmware/targets/f6/ble-glue/ble_glue.c @@ -0,0 +1,173 @@ +#include "ble_glue.h" +#include "app_common.h" +#include "main.h" +#include "ble_app.h" +#include "ble.h" +#include "tl.h" +#include "shci.h" +#include "cmsis_os.h" +#include "shci_tl.h" +#include "app_debug.h" +#include + +#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) + +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_event_pool[POOL_SIZE]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ble_glue_system_cmd_buff; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; + +typedef struct { + osMutexId_t shci_mtx; + osSemaphoreId_t shci_sem; + osThreadId_t shci_user_event_thread_id; + osThreadAttr_t shci_user_event_thread_attr; + BleGlueStatus status; + BleGlueKeyStorageChangedCallback callback; + void* context; +} BleGlue; + +static BleGlue* ble_glue = NULL; + +static void ble_glue_user_event_thread(void *argument); +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status); +static void ble_glue_sys_user_event_callback(void* pPayload); + +BleGlueStatus ble_glue_get_status() { + if(!ble_glue) { + return BleGlueStatusUninitialized; + } + return ble_glue->status; +} + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(ble_glue); + furi_assert(callback); + ble_glue->callback = callback; + ble_glue->context = context; +} + +void ble_glue_init() { + ble_glue = furi_alloc(sizeof(BleGlue)); + ble_glue->status = BleGlueStatusStartup; + ble_glue->shci_user_event_thread_attr.name = "ble_shci_evt"; + ble_glue->shci_user_event_thread_attr.stack_size = 1024; + + // Configure the system Power Mode + // Select HSI as system clock source after Wake Up from Stop mode + LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); + /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ + LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); + furi_hal_power_insomnia_enter(); + + // APPD_Init(); + + // Initialize all transport layers + TL_MM_Config_t tl_mm_config; + SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; + // Reference table initialization + TL_Init(); + + ble_glue->shci_mtx = osMutexNew(NULL); + ble_glue->shci_sem = osSemaphoreNew(1, 0, NULL); + + // FreeRTOS system task creation + ble_glue->shci_user_event_thread_id = osThreadNew(ble_glue_user_event_thread, NULL, &ble_glue->shci_user_event_thread_attr); + + // System channel initialization + SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&ble_glue_system_cmd_buff; + SHci_Tl_Init_Conf.StatusNotCallBack = ble_glue_sys_status_not_callback; + shci_init(ble_glue_sys_user_event_callback, (void*) &SHci_Tl_Init_Conf); + + /**< Memory Manager channel initialization */ + tl_mm_config.p_BleSpareEvtBuffer = ble_glue_ble_spare_event_buff; + tl_mm_config.p_SystemSpareEvtBuffer = ble_glue_system_spare_event_buff; + tl_mm_config.p_AsynchEvtPool = ble_glue_event_pool; + tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; + TL_MM_Init( &tl_mm_config ); + TL_Enable(); + + /* + * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) + * received on the system channel before starting the Stack + * This system event is received with ble_glue_sys_user_event_callback() + */ +} + +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { + switch (status) { + case SHCI_TL_CmdBusy: + osMutexAcquire( ble_glue->shci_mtx, osWaitForever ); + break; + case SHCI_TL_CmdAvailable: + osMutexRelease( ble_glue->shci_mtx ); + break; + default: + break; + } +} + +/* + * The type of the payload for a system user event is tSHCI_UserEvtRxParam + * When the system event is both : + * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) + * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) + * The buffer shall not be released + * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) + * When the status is not filled, the buffer is released by default + */ +static void ble_glue_sys_user_event_callback( void * pPayload ) { + UNUSED(pPayload); + /* Traces channel initialization */ + // APPD_EnableCPU2( ); + + TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload); + + if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) { + if(ble_app_init()) { + FURI_LOG_I("Core2", "BLE stack started"); + ble_glue->status = BleGlueStatusStarted; + if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) { + FURI_LOG_I("Core2", "Flash activity control switched to SEM7"); + } else { + FURI_LOG_E("Core2", "Failed to switch flash activity control to SEM7"); + } + } else { + FURI_LOG_E("Core2", "BLE stack startup failed"); + ble_glue->status = BleGlueStatusBleStackMissing; + } + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) { + FURI_LOG_E("Core2", "Error during initialization"); + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE) { + SHCI_C2_BleNvmRamUpdate_Evt_t* p_sys_ble_nvm_ram_update_event = (SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload; + if(ble_glue->callback) { + ble_glue->callback((uint8_t*)p_sys_ble_nvm_ram_update_event->StartAddress, p_sys_ble_nvm_ram_update_event->Size, ble_glue->context); + } + } +} + +// Wrap functions +static void ble_glue_user_event_thread(void *argument) { + UNUSED(argument); + for(;;) { + osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); + shci_user_evt_proc(); + } +} + +void shci_notify_asynch_evt(void* pdata) { + UNUSED(pdata); + osThreadFlagsSet(ble_glue->shci_user_event_thread_id, 1); +} + +void shci_cmd_resp_release(uint32_t flag) { + UNUSED(flag); + osSemaphoreRelease(ble_glue->shci_sem); +} + +void shci_cmd_resp_wait(uint32_t timeout) { + UNUSED(timeout); + osSemaphoreAcquire(ble_glue->shci_sem, osWaitForever); +} diff --git a/firmware/targets/f6/ble-glue/ble_glue.h b/firmware/targets/f6/ble-glue/ble_glue.h new file mode 100644 index 00000000..e9d6c03f --- /dev/null +++ b/firmware/targets/f6/ble-glue/ble_glue.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context); + +typedef enum { + BleGlueStatusUninitialized, + BleGlueStatusStartup, + BleGlueStatusBleStackMissing, + BleGlueStatusStarted +} BleGlueStatus; + +void ble_glue_init(); + +BleGlueStatus ble_glue_get_status(); + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f6/ble-glue/gap.c b/firmware/targets/f6/ble-glue/gap.c index eae5f87c..9ddae208 100644 --- a/firmware/targets/f6/ble-glue/gap.c +++ b/firmware/targets/f6/ble-glue/gap.c @@ -1,6 +1,5 @@ #include "gap.h" -#include "app_entry.h" #include "ble.h" #include "cmsis_os.h" @@ -375,7 +374,7 @@ static void gap_advetise_timer_callback(void* context) { } bool gap_init(BleEventCallback on_event_cb, void* context) { - if (APPE_Status() != BleGlueStatusStarted) { + if (ble_glue_get_status() != BleGlueStatusStarted) { return false; } diff --git a/firmware/targets/f6/ble-glue/hw_conf.h b/firmware/targets/f6/ble-glue/hw_conf.h index dcda0176..9545238b 100644 --- a/firmware/targets/f6/ble-glue/hw_conf.h +++ b/firmware/targets/f6/ble-glue/hw_conf.h @@ -29,6 +29,37 @@ * Semaphores * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+ *****************************************************************************/ +/** +* Index of the semaphore used the prevent conflicts after standby sleep. +* Each CPUs takes this semaphore at standby wakeup until conclicting elements are restored. +*/ +#define CFG_HW_PWR_STANDBY_SEMID 10 +/** +* The CPU2 may be configured to store the Thread persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* CFG_HW_THREAD_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_THREAD_NVM_SRAM_SEMID 9 + +/** +* The CPU2 may be configured to store the BLE persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* CFG_HW_BLE_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_BLE_NVM_SRAM_SEMID 8 + /** * Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash * The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2 diff --git a/firmware/targets/f6/furi-hal/furi-hal-bt.c b/firmware/targets/f6/furi-hal/furi-hal-bt.c index 97db87c7..a018085c 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f6/furi-hal/furi-hal-bt.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -7,11 +6,37 @@ #include +osMutexId_t furi_hal_bt_core2_mtx = NULL; + void furi_hal_bt_init() { + furi_hal_bt_core2_mtx = osMutexNew(NULL); +} + +static bool furi_hal_bt_wait_startup() { + uint16_t counter = 0; + while (!(ble_glue_get_status() == BleGlueStatusStarted || ble_glue_get_status() == BleGlueStatusBleStackMissing)) { + osDelay(10); + counter++; + if (counter > 1000) { + return false; + } + } + return true; +} + +bool furi_hal_bt_start_core2() { + furi_assert(furi_hal_bt_core2_mtx); + + bool ret = false; + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); // Explicitly tell that we are in charge of CLK48 domain HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID); - // Start Core2, init HCI and start GAP/GATT - APPE_Init(); + // Start Core2 + ble_glue_init(); + // Wait for Core2 start + ret = furi_hal_bt_wait_startup(); + osMutexRelease(furi_hal_bt_core2_mtx); + return ret; } bool furi_hal_bt_init_app(BleEventCallback event_cb, void* context) { @@ -45,8 +70,33 @@ bool furi_hal_bt_tx(uint8_t* data, uint16_t size) { return serial_svc_update_tx(data, size); } +bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) { + bool ret = false; + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusUninitialized || BleGlueStatusStarted) { + ble_app_get_key_storage_buff(key_buff_addr, key_buff_size); + ret = true; + } + return ret; +} + +void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(callback); + ble_glue_set_key_storage_changed_callback(callback, context); +} + +void furi_hal_bt_nvm_sram_sem_acquire() { + while(HAL_HSEM_FastTake(CFG_HW_BLE_NVM_SRAM_SEMID) != HAL_OK) { + osDelay(1); + } +} + +void furi_hal_bt_nvm_sram_sem_release() { + HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); +} + void furi_hal_bt_dump_state(string_t buffer) { - BleGlueStatus status = APPE_Status(); + BleGlueStatus status = ble_glue_get_status(); if (status == BleGlueStatusStarted) { uint8_t HCI_Version; uint16_t HCI_Revision; @@ -68,56 +118,97 @@ void furi_hal_bt_dump_state(string_t buffer) { } bool furi_hal_bt_is_alive() { - BleGlueStatus status = APPE_Status(); - return (status == BleGlueStatusBroken) || (status == BleGlueStatusStarted); + BleGlueStatus status = ble_glue_get_status(); + return (status == BleGlueStatusBleStackMissing) || (status == BleGlueStatusStarted); } bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } -bool furi_hal_bt_wait_startup() { - uint16_t counter = 0; - while (!(APPE_Status() == BleGlueStatusStarted || APPE_Status() == BleGlueStatusBroken)) { - osDelay(10); - counter++; - if (counter > 1000) { - return false; - } - } - return true; -} - -bool furi_hal_bt_lock_flash(bool erase_flag) { - if (!furi_hal_bt_wait_startup()) { - return false; - } - +static void furi_hal_bt_lock_flash_core2(bool erase_flag) { + // Take flash controller ownership while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { - osDelay(1); + taskYIELD(); } + // Unlock flash operation HAL_FLASH_Unlock(); + // Erase activity notification if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); - while(LL_FLASH_IsActiveFlag_OperationSuspended()) { - osDelay(1); - }; + while(true) { + // Wait till flash controller become usable + while(LL_FLASH_IsActiveFlag_OperationSuspended()) { + taskYIELD(); + }; - __disable_irq(); + // Just a little more love + taskENTER_CRITICAL(); - return true; + // Actually we already have mutex for it, but specification is specification + if (HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { + taskEXIT_CRITICAL(); + continue; + } + + // Take sempahopre and prevent core2 from anyting funky + if (HAL_HSEM_FastTake(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != HAL_OK) { + taskEXIT_CRITICAL(); + continue; + } + + break; + } +} + +void furi_hal_bt_lock_flash(bool erase_flag) { + // Acquire dangerous ops mutex + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); + + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_lock_flash_core2(erase_flag); + } else { + HAL_FLASH_Unlock(); + } +} + +static void furi_hal_bt_unlock_flash_core2(bool erase_flag) { + // Funky ops are ok at this point + HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, 0); + + // Task switching is ok + taskEXIT_CRITICAL(); + + // Doesn't make much sense, does it? + while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + taskYIELD(); + } + + // Erase activity over, core2 can continue + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + + // Lock flash controller + HAL_FLASH_Lock(); + + // Release flash controller ownership + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, 0); } void furi_hal_bt_unlock_flash(bool erase_flag) { - __enable_irq(); + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_unlock_flash_core2(erase_flag); + } else { + HAL_FLASH_Lock(); + } - if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); - - HAL_FLASH_Lock(); - - HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); + // Release dangerous ops mutex + osMutexRelease(furi_hal_bt_core2_mtx); } void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power) { diff --git a/firmware/targets/f6/furi-hal/furi-hal-crypto.c b/firmware/targets/f6/furi-hal/furi-hal-crypto.c index 62f569f7..648f3f18 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-crypto.c +++ b/firmware/targets/f6/furi-hal/furi-hal-crypto.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,6 +13,10 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { furi_assert(key); furi_assert(slot); + if(!furi_hal_bt_is_alive()) { + return false; + } + SHCI_C2_FUS_StoreUsrKey_Cmd_Param_t pParam; size_t key_data_size = 0; @@ -44,6 +49,10 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { furi_assert(slot > 0 && slot <= 100); + if(!furi_hal_bt_is_alive()) { + return false; + } + crypt.Instance = AES1; crypt.Init.DataType = CRYP_DATATYPE_32B; crypt.Init.KeySize = CRYP_KEYSIZE_256B; @@ -63,6 +72,10 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { } bool furi_hal_crypto_store_unload_key(uint8_t slot) { + if(!furi_hal_bt_is_alive()) { + return false; + } + furi_check(HAL_CRYP_DeInit(&crypt) == HAL_OK); return SHCI_C2_FUS_UnloadUsrKey(slot) == SHCI_Success; } diff --git a/firmware/targets/f6/furi-hal/furi-hal-flash.c b/firmware/targets/f6/furi-hal/furi-hal-flash.c index c9922122..1e270bc0 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-flash.c +++ b/firmware/targets/f6/furi-hal/furi-hal-flash.c @@ -1,11 +1,14 @@ #include #include -#include #include +#include + /* Free flash space borders, exported by linker */ extern const void __free_flash_start__; +#define FURI_HAL_TAG "FuriHalFlash" +#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" #define FURI_HAL_FLASH_READ_BLOCK 8 #define FURI_HAL_FLASH_WRITE_BLOCK 8 #define FURI_HAL_FLASH_PAGE_SIZE 4096 @@ -57,33 +60,46 @@ 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(true)) { - return false; - } + furi_hal_bt_lock_flash(true); + FLASH_EraseInitTypeDef erase; erase.TypeErase = FLASH_TYPEERASE_PAGES; erase.Page = page; erase.NbPages = count; - uint32_t error; - HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); + + uint32_t error_page = 0; + HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error_page); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Erase failed, ret: %d, page: %d", status, error_page); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(true); - return status == HAL_OK; + + return true; } bool furi_hal_flash_write_dword(size_t address, uint64_t data) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Programming failed, ret: %d, address: %p", status, address); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } +bool furi_hal_flash_write_row(size_t address, size_t source_address) { + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); + furi_check(status == HAL_OK); + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } diff --git a/firmware/targets/f6/furi-hal/furi-hal-flash.h b/firmware/targets/f6/furi-hal/furi-hal-flash.h index 583d53eb..92a65a65 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-flash.h +++ b/firmware/targets/f6/furi-hal/furi-hal-flash.h @@ -80,7 +80,7 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count); */ bool furi_hal_flash_write_dword(size_t address, uint64_t data); -/** Write double word (64 bits) from address +/** Write row: 64 double word (64 bits) from address * * Locking operation, uses HSEM to manage shared access. * @@ -89,4 +89,4 @@ bool furi_hal_flash_write_dword(size_t address, uint64_t data); * * @return true on success */ -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address); +bool furi_hal_flash_write_row(size_t address, size_t source_address); diff --git a/firmware/targets/f7/ble-glue/app_conf.h b/firmware/targets/f7/ble-glue/app_conf.h index e3820e11..eebdbbdb 100644 --- a/firmware/targets/f7/ble-glue/app_conf.h +++ b/firmware/targets/f7/ble-glue/app_conf.h @@ -427,16 +427,5 @@ typedef enum #define DBG_TRACE_MSG_QUEUE_SIZE 4096 #define MAX_DBG_TRACE_MSG_SIZE 1024 -/****************************************************************************** - * FreeRTOS - ******************************************************************************/ -#define CFG_SHCI_USER_EVT_PROCESS_NAME "ble_shci_evt" -#define CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_CB_SIZE (0) -#define CFG_SHCI_USER_EVT_PROCESS_STACK_MEM (0) -#define CFG_SHCI_USER_EVT_PROCESS_PRIORITY osPriorityNone -#define CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE (128 * 7) - #define CFG_OTP_BASE_ADDRESS OTP_AREA_BASE #define CFG_OTP_END_ADRESS OTP_AREA_END_ADDR diff --git a/firmware/targets/f7/ble-glue/app_entry.c b/firmware/targets/f7/ble-glue/app_entry.c deleted file mode 100644 index 5c8c0b2a..00000000 --- a/firmware/targets/f7/ble-glue/app_entry.c +++ /dev/null @@ -1,180 +0,0 @@ -#include "app_common.h" -#include "main.h" -#include "app_entry.h" -#include "ble_app.h" -#include "ble.h" -#include "tl.h" -#include "cmsis_os.h" -#include "shci_tl.h" -#include "app_debug.h" -#include - -extern RTC_HandleTypeDef hrtc; - -#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) - -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t EvtPool[POOL_SIZE]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; -PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; - -osMutexId_t MtxShciId; -osSemaphoreId_t SemShciId; -osThreadId_t ShciUserEvtProcessId; - -volatile static BleGlueStatus ble_glue_status = BleGlueStatusUninitialized; - -const osThreadAttr_t ShciUserEvtProcess_attr = { - .name = CFG_SHCI_USER_EVT_PROCESS_NAME, - .attr_bits = CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS, - .cb_mem = CFG_SHCI_USER_EVT_PROCESS_CB_MEM, - .cb_size = CFG_SHCI_USER_EVT_PROCESS_CB_SIZE, - .stack_mem = CFG_SHCI_USER_EVT_PROCESS_STACK_MEM, - .priority = CFG_SHCI_USER_EVT_PROCESS_PRIORITY, - .stack_size = CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE -}; - -static void ShciUserEvtProcess(void *argument); -static void SystemPower_Config( void ); -static void appe_Tl_Init( void ); -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ); -static void APPE_SysUserEvtRx( void * pPayload ); - -BleGlueStatus APPE_Status() { - return ble_glue_status; -} - -void APPE_Init() { - ble_glue_status = BleGlueStatusStartup; - SystemPower_Config(); /**< Configure the system Power Mode */ - - // APPD_Init(); - furi_hal_power_insomnia_enter(); - - appe_Tl_Init(); /* Initialize all transport layers */ - - /** - * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) - * received on the system channel before starting the Stack - * This system event is received with APPE_SysUserEvtRx() - */ -} - -/************************************************************* - * - * LOCAL FUNCTIONS - * - *************************************************************/ - -/** - * @brief Configure the system for power optimization - * - * @note This API configures the system to be ready for low power mode - * - * @param None - * @retval None - */ -static void SystemPower_Config(void) { - // Select HSI as system clock source after Wake Up from Stop mode - LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); - - /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ - LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); -} - -static void appe_Tl_Init( void ) { - TL_MM_Config_t tl_mm_config; - SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; - /**< Reference table initialization */ - TL_Init(); - - MtxShciId = osMutexNew( NULL ); - SemShciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */ - - /** FreeRTOS system task creation */ - ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr); - - /**< System channel initialization */ - SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer; - SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot; - shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf); - - /**< Memory Manager channel initialization */ - tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer; - tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer; - tl_mm_config.p_AsynchEvtPool = EvtPool; - tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; - TL_MM_Init( &tl_mm_config ); - - TL_Enable(); -} - -static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ) { - switch (status) { - case SHCI_TL_CmdBusy: - osMutexAcquire( MtxShciId, osWaitForever ); - break; - case SHCI_TL_CmdAvailable: - osMutexRelease( MtxShciId ); - break; - default: - break; - } -} - -/** - * The type of the payload for a system user event is tSHCI_UserEvtRxParam - * When the system event is both : - * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) - * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) - * The buffer shall not be released - * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) - * When the status is not filled, the buffer is released by default - */ -static void APPE_SysUserEvtRx( void * pPayload ) { - UNUSED(pPayload); - /* Traces channel initialization */ - // APPD_EnableCPU2( ); - - if(ble_app_init()) { - FURI_LOG_I("Core2", "BLE stack started"); - ble_glue_status = BleGlueStatusStarted; - } else { - FURI_LOG_E("Core2", "BLE stack startup failed"); - ble_glue_status = BleGlueStatusBroken; - } - furi_hal_power_insomnia_exit(); -} - -/************************************************************* - * - * FREERTOS WRAPPER FUNCTIONS - * -*************************************************************/ -static void ShciUserEvtProcess(void *argument) { - UNUSED(argument); - for(;;) { - osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); - shci_user_evt_proc(); - } -} - -/************************************************************* - * - * WRAP FUNCTIONS - * - *************************************************************/ -void shci_notify_asynch_evt(void* pdata) { - UNUSED(pdata); - osThreadFlagsSet( ShciUserEvtProcessId, 1 ); -} - -void shci_cmd_resp_release(uint32_t flag) { - UNUSED(flag); - osSemaphoreRelease( SemShciId ); -} - -void shci_cmd_resp_wait(uint32_t timeout) { - UNUSED(timeout); - osSemaphoreAcquire( SemShciId, osWaitForever ); -} diff --git a/firmware/targets/f7/ble-glue/app_entry.h b/firmware/targets/f7/ble-glue/app_entry.h deleted file mode 100644 index f1ce6038..00000000 --- a/firmware/targets/f7/ble-glue/app_entry.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - BleGlueStatusUninitialized, - BleGlueStatusStartup, - BleGlueStatusBroken, - BleGlueStatusStarted -} BleGlueStatus; - -void APPE_Init(); - -BleGlueStatus APPE_Status(); - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/firmware/targets/f7/ble-glue/ble_app.c b/firmware/targets/f7/ble-glue/ble_app.c index e28facd6..33e5264a 100644 --- a/firmware/targets/f7/ble-glue/ble_app.c +++ b/firmware/targets/f7/ble-glue/ble_app.c @@ -11,6 +11,7 @@ #define BLE_APP_TAG "ble app" PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; typedef struct { osMutexId_t hci_mtx; @@ -26,8 +27,8 @@ static void ble_app_hci_event_handler(void * pPayload); static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status); bool ble_app_init() { + SHCI_CmdStatus_t status; ble_app = furi_alloc(sizeof(BleApp)); - // Allocate semafore and mutex for ble command buffer access ble_app->hci_mtx = osMutexNew(NULL); ble_app->hci_sem = osSemaphoreNew(1, 0, NULL); @@ -43,6 +44,18 @@ bool ble_app_init() { }; hci_init(ble_app_hci_event_handler, (void*)&hci_tl_config); + // Configure NVM store for pairing data + SHCI_C2_CONFIG_Cmd_Param_t config_param = { + .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, + .Config1 =SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, + .BleNvmRamAddress = (uint32_t)ble_app_nvm, + .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, + }; + status = SHCI_C2_Config(&config_param); + if(status) { + FURI_LOG_E(BLE_APP_TAG, "Failed to configure 2nd core: %d", status); + } + // Start ble stack on 2nd core SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { .Header = {{0,0,0}}, // Header unused @@ -67,13 +80,18 @@ bool ble_app_init() { 0, } }; - SHCI_CmdStatus_t status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); + status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); if(status) { FURI_LOG_E(BLE_APP_TAG, "Failed to start ble stack: %d", status); } return status == SHCI_Success; } +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) { + *addr = (uint8_t*)ble_app_nvm; + *size = sizeof(ble_app_nvm); +} + static void ble_app_hci_thread(void *arg) { while(1) { osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); diff --git a/firmware/targets/f7/ble-glue/ble_app.h b/firmware/targets/f7/ble-glue/ble_app.h index 17d8dc5f..64000bde 100644 --- a/firmware/targets/f7/ble-glue/ble_app.h +++ b/firmware/targets/f7/ble-glue/ble_app.h @@ -5,8 +5,10 @@ extern "C" { #endif #include +#include bool ble_app_init(); +void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size); #ifdef __cplusplus } diff --git a/firmware/targets/f7/ble-glue/ble_glue.c b/firmware/targets/f7/ble-glue/ble_glue.c new file mode 100644 index 00000000..4a9c144e --- /dev/null +++ b/firmware/targets/f7/ble-glue/ble_glue.c @@ -0,0 +1,173 @@ +#include "ble_glue.h" +#include "app_common.h" +#include "main.h" +#include "ble_app.h" +#include "ble.h" +#include "tl.h" +#include "shci.h" +#include "cmsis_os.h" +#include "shci_tl.h" +#include "app_debug.h" +#include + +#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) + +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_event_pool[POOL_SIZE]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ble_glue_system_cmd_buff; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; + +typedef struct { + osMutexId_t shci_mtx; + osSemaphoreId_t shci_sem; + osThreadId_t shci_user_event_thread_id; + osThreadAttr_t shci_user_event_thread_attr; + BleGlueStatus status; + BleGlueKeyStorageChangedCallback callback; + void* context; +} BleGlue; + +static BleGlue* ble_glue = NULL; + +static void ble_glue_user_event_thread(void *argument); +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status); +static void ble_glue_sys_user_event_callback(void* pPayload); + +BleGlueStatus ble_glue_get_status() { + if(!ble_glue) { + return BleGlueStatusUninitialized; + } + return ble_glue->status; +} + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(ble_glue); + furi_assert(callback); + ble_glue->callback = callback; + ble_glue->context = context; +} + +void ble_glue_init() { + ble_glue = furi_alloc(sizeof(BleGlue)); + ble_glue->status = BleGlueStatusStartup; + ble_glue->shci_user_event_thread_attr.name = "ble_shci_evt"; + ble_glue->shci_user_event_thread_attr.stack_size = 1024; + + // Configure the system Power Mode + // Select HSI as system clock source after Wake Up from Stop mode + LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); + /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ + LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); + furi_hal_power_insomnia_enter(); + + // APPD_Init(); + + // Initialize all transport layers + TL_MM_Config_t tl_mm_config; + SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; + // Reference table initialization + TL_Init(); + + ble_glue->shci_mtx = osMutexNew(NULL); + ble_glue->shci_sem = osSemaphoreNew(1, 0, NULL); + + // FreeRTOS system task creation + ble_glue->shci_user_event_thread_id = osThreadNew(ble_glue_user_event_thread, NULL, &ble_glue->shci_user_event_thread_attr); + + // System channel initialization + SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&ble_glue_system_cmd_buff; + SHci_Tl_Init_Conf.StatusNotCallBack = ble_glue_sys_status_not_callback; + shci_init(ble_glue_sys_user_event_callback, (void*) &SHci_Tl_Init_Conf); + + /**< Memory Manager channel initialization */ + tl_mm_config.p_BleSpareEvtBuffer = ble_glue_ble_spare_event_buff; + tl_mm_config.p_SystemSpareEvtBuffer = ble_glue_system_spare_event_buff; + tl_mm_config.p_AsynchEvtPool = ble_glue_event_pool; + tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; + TL_MM_Init( &tl_mm_config ); + TL_Enable(); + + /* + * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) + * received on the system channel before starting the Stack + * This system event is received with ble_glue_sys_user_event_callback() + */ +} + +static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { + switch (status) { + case SHCI_TL_CmdBusy: + osMutexAcquire( ble_glue->shci_mtx, osWaitForever ); + break; + case SHCI_TL_CmdAvailable: + osMutexRelease( ble_glue->shci_mtx ); + break; + default: + break; + } +} + +/* + * The type of the payload for a system user event is tSHCI_UserEvtRxParam + * When the system event is both : + * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) + * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) + * The buffer shall not be released + * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) + * When the status is not filled, the buffer is released by default + */ +static void ble_glue_sys_user_event_callback( void * pPayload ) { + UNUSED(pPayload); + /* Traces channel initialization */ + // APPD_EnableCPU2( ); + + TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload); + + if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) { + if(ble_app_init()) { + FURI_LOG_I("Core2", "BLE stack started"); + ble_glue->status = BleGlueStatusStarted; + if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) { + FURI_LOG_I("Core2", "Flash activity control switched to SEM7"); + } else { + FURI_LOG_E("Core2", "Failed to switch flash activity control to SEM7"); + } + } else { + FURI_LOG_E("Core2", "BLE stack startup failed"); + ble_glue->status = BleGlueStatusBleStackMissing; + } + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) { + FURI_LOG_E("Core2", "Error during initialization"); + furi_hal_power_insomnia_exit(); + } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE) { + SHCI_C2_BleNvmRamUpdate_Evt_t* p_sys_ble_nvm_ram_update_event = (SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload; + if(ble_glue->callback) { + ble_glue->callback((uint8_t*)p_sys_ble_nvm_ram_update_event->StartAddress, p_sys_ble_nvm_ram_update_event->Size, ble_glue->context); + } + } +} + +// Wrap functions +static void ble_glue_user_event_thread(void *argument) { + UNUSED(argument); + for(;;) { + osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); + shci_user_evt_proc(); + } +} + +void shci_notify_asynch_evt(void* pdata) { + UNUSED(pdata); + osThreadFlagsSet(ble_glue->shci_user_event_thread_id, 1); +} + +void shci_cmd_resp_release(uint32_t flag) { + UNUSED(flag); + osSemaphoreRelease(ble_glue->shci_sem); +} + +void shci_cmd_resp_wait(uint32_t timeout) { + UNUSED(timeout); + osSemaphoreAcquire(ble_glue->shci_sem, osWaitForever); +} diff --git a/firmware/targets/f7/ble-glue/ble_glue.h b/firmware/targets/f7/ble-glue/ble_glue.h new file mode 100644 index 00000000..e9d6c03f --- /dev/null +++ b/firmware/targets/f7/ble-glue/ble_glue.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context); + +typedef enum { + BleGlueStatusUninitialized, + BleGlueStatusStartup, + BleGlueStatusBleStackMissing, + BleGlueStatusStarted +} BleGlueStatus; + +void ble_glue_init(); + +BleGlueStatus ble_glue_get_status(); + +void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/ble-glue/gap.c b/firmware/targets/f7/ble-glue/gap.c index eae5f87c..9ddae208 100644 --- a/firmware/targets/f7/ble-glue/gap.c +++ b/firmware/targets/f7/ble-glue/gap.c @@ -1,6 +1,5 @@ #include "gap.h" -#include "app_entry.h" #include "ble.h" #include "cmsis_os.h" @@ -375,7 +374,7 @@ static void gap_advetise_timer_callback(void* context) { } bool gap_init(BleEventCallback on_event_cb, void* context) { - if (APPE_Status() != BleGlueStatusStarted) { + if (ble_glue_get_status() != BleGlueStatusStarted) { return false; } diff --git a/firmware/targets/f7/ble-glue/hw_conf.h b/firmware/targets/f7/ble-glue/hw_conf.h index dcda0176..9545238b 100644 --- a/firmware/targets/f7/ble-glue/hw_conf.h +++ b/firmware/targets/f7/ble-glue/hw_conf.h @@ -29,6 +29,37 @@ * Semaphores * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+ *****************************************************************************/ +/** +* Index of the semaphore used the prevent conflicts after standby sleep. +* Each CPUs takes this semaphore at standby wakeup until conclicting elements are restored. +*/ +#define CFG_HW_PWR_STANDBY_SEMID 10 +/** +* The CPU2 may be configured to store the Thread persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +* CFG_HW_THREAD_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_THREAD_NVM_SRAM_SEMID 9 + +/** +* The CPU2 may be configured to store the BLE persistent data either in internal NVM storage on CPU2 or in +* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +* + CPU1 takes CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +* + CPU1 releases CFG_HW_BLE_NVM_SRAM_SEMID semaphore +* CFG_HW_BLE_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +* There is no timing constraint on how long this semaphore can be kept. +*/ +#define CFG_HW_BLE_NVM_SRAM_SEMID 8 + /** * Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash * The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2 diff --git a/firmware/targets/f7/furi-hal/furi-hal-bt.c b/firmware/targets/f7/furi-hal/furi-hal-bt.c index 97db87c7..a018085c 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f7/furi-hal/furi-hal-bt.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -7,11 +6,37 @@ #include +osMutexId_t furi_hal_bt_core2_mtx = NULL; + void furi_hal_bt_init() { + furi_hal_bt_core2_mtx = osMutexNew(NULL); +} + +static bool furi_hal_bt_wait_startup() { + uint16_t counter = 0; + while (!(ble_glue_get_status() == BleGlueStatusStarted || ble_glue_get_status() == BleGlueStatusBleStackMissing)) { + osDelay(10); + counter++; + if (counter > 1000) { + return false; + } + } + return true; +} + +bool furi_hal_bt_start_core2() { + furi_assert(furi_hal_bt_core2_mtx); + + bool ret = false; + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); // Explicitly tell that we are in charge of CLK48 domain HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID); - // Start Core2, init HCI and start GAP/GATT - APPE_Init(); + // Start Core2 + ble_glue_init(); + // Wait for Core2 start + ret = furi_hal_bt_wait_startup(); + osMutexRelease(furi_hal_bt_core2_mtx); + return ret; } bool furi_hal_bt_init_app(BleEventCallback event_cb, void* context) { @@ -45,8 +70,33 @@ bool furi_hal_bt_tx(uint8_t* data, uint16_t size) { return serial_svc_update_tx(data, size); } +bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) { + bool ret = false; + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusUninitialized || BleGlueStatusStarted) { + ble_app_get_key_storage_buff(key_buff_addr, key_buff_size); + ret = true; + } + return ret; +} + +void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context) { + furi_assert(callback); + ble_glue_set_key_storage_changed_callback(callback, context); +} + +void furi_hal_bt_nvm_sram_sem_acquire() { + while(HAL_HSEM_FastTake(CFG_HW_BLE_NVM_SRAM_SEMID) != HAL_OK) { + osDelay(1); + } +} + +void furi_hal_bt_nvm_sram_sem_release() { + HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); +} + void furi_hal_bt_dump_state(string_t buffer) { - BleGlueStatus status = APPE_Status(); + BleGlueStatus status = ble_glue_get_status(); if (status == BleGlueStatusStarted) { uint8_t HCI_Version; uint16_t HCI_Revision; @@ -68,56 +118,97 @@ void furi_hal_bt_dump_state(string_t buffer) { } bool furi_hal_bt_is_alive() { - BleGlueStatus status = APPE_Status(); - return (status == BleGlueStatusBroken) || (status == BleGlueStatusStarted); + BleGlueStatus status = ble_glue_get_status(); + return (status == BleGlueStatusBleStackMissing) || (status == BleGlueStatusStarted); } bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } -bool furi_hal_bt_wait_startup() { - uint16_t counter = 0; - while (!(APPE_Status() == BleGlueStatusStarted || APPE_Status() == BleGlueStatusBroken)) { - osDelay(10); - counter++; - if (counter > 1000) { - return false; - } - } - return true; -} - -bool furi_hal_bt_lock_flash(bool erase_flag) { - if (!furi_hal_bt_wait_startup()) { - return false; - } - +static void furi_hal_bt_lock_flash_core2(bool erase_flag) { + // Take flash controller ownership while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { - osDelay(1); + taskYIELD(); } + // Unlock flash operation HAL_FLASH_Unlock(); + // Erase activity notification if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); - while(LL_FLASH_IsActiveFlag_OperationSuspended()) { - osDelay(1); - }; + while(true) { + // Wait till flash controller become usable + while(LL_FLASH_IsActiveFlag_OperationSuspended()) { + taskYIELD(); + }; - __disable_irq(); + // Just a little more love + taskENTER_CRITICAL(); - return true; + // Actually we already have mutex for it, but specification is specification + if (HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { + taskEXIT_CRITICAL(); + continue; + } + + // Take sempahopre and prevent core2 from anyting funky + if (HAL_HSEM_FastTake(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != HAL_OK) { + taskEXIT_CRITICAL(); + continue; + } + + break; + } +} + +void furi_hal_bt_lock_flash(bool erase_flag) { + // Acquire dangerous ops mutex + osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever); + + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_lock_flash_core2(erase_flag); + } else { + HAL_FLASH_Unlock(); + } +} + +static void furi_hal_bt_unlock_flash_core2(bool erase_flag) { + // Funky ops are ok at this point + HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, 0); + + // Task switching is ok + taskEXIT_CRITICAL(); + + // Doesn't make much sense, does it? + while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + taskYIELD(); + } + + // Erase activity over, core2 can continue + if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + + // Lock flash controller + HAL_FLASH_Lock(); + + // Release flash controller ownership + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, 0); } void furi_hal_bt_unlock_flash(bool erase_flag) { - __enable_irq(); + // If Core2 is running use IPC locking + BleGlueStatus status = ble_glue_get_status(); + if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) { + furi_hal_bt_unlock_flash_core2(erase_flag); + } else { + HAL_FLASH_Lock(); + } - if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); - - HAL_FLASH_Lock(); - - HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); + // Release dangerous ops mutex + osMutexRelease(furi_hal_bt_core2_mtx); } void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power) { diff --git a/firmware/targets/f7/furi-hal/furi-hal-crypto.c b/firmware/targets/f7/furi-hal/furi-hal-crypto.c index 62f569f7..648f3f18 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-crypto.c +++ b/firmware/targets/f7/furi-hal/furi-hal-crypto.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,6 +13,10 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { furi_assert(key); furi_assert(slot); + if(!furi_hal_bt_is_alive()) { + return false; + } + SHCI_C2_FUS_StoreUsrKey_Cmd_Param_t pParam; size_t key_data_size = 0; @@ -44,6 +49,10 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { furi_assert(slot > 0 && slot <= 100); + if(!furi_hal_bt_is_alive()) { + return false; + } + crypt.Instance = AES1; crypt.Init.DataType = CRYP_DATATYPE_32B; crypt.Init.KeySize = CRYP_KEYSIZE_256B; @@ -63,6 +72,10 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { } bool furi_hal_crypto_store_unload_key(uint8_t slot) { + if(!furi_hal_bt_is_alive()) { + return false; + } + furi_check(HAL_CRYP_DeInit(&crypt) == HAL_OK); return SHCI_C2_FUS_UnloadUsrKey(slot) == SHCI_Success; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-flash.c b/firmware/targets/f7/furi-hal/furi-hal-flash.c index c9922122..1e270bc0 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-flash.c +++ b/firmware/targets/f7/furi-hal/furi-hal-flash.c @@ -1,11 +1,14 @@ #include #include -#include #include +#include + /* Free flash space borders, exported by linker */ extern const void __free_flash_start__; +#define FURI_HAL_TAG "FuriHalFlash" +#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" #define FURI_HAL_FLASH_READ_BLOCK 8 #define FURI_HAL_FLASH_WRITE_BLOCK 8 #define FURI_HAL_FLASH_PAGE_SIZE 4096 @@ -57,33 +60,46 @@ 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(true)) { - return false; - } + furi_hal_bt_lock_flash(true); + FLASH_EraseInitTypeDef erase; erase.TypeErase = FLASH_TYPEERASE_PAGES; erase.Page = page; erase.NbPages = count; - uint32_t error; - HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); + + uint32_t error_page = 0; + HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error_page); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Erase failed, ret: %d, page: %d", status, error_page); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(true); - return status == HAL_OK; + + return true; } bool furi_hal_flash_write_dword(size_t address, uint64_t data) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); + if (status != HAL_OK) { + FURI_LOG_E(FURI_HAL_TAG, "Programming failed, ret: %d, address: %p", status, address); + furi_crash(FURI_HAL_CRITICAL_MSG); + } + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { - if (!furi_hal_bt_lock_flash(false)) { - return false; - } +bool furi_hal_flash_write_row(size_t address, size_t source_address) { + furi_hal_bt_lock_flash(false); + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); + furi_check(status == HAL_OK); + furi_hal_bt_unlock_flash(false); - return status == HAL_OK; + + return true; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-flash.h b/firmware/targets/f7/furi-hal/furi-hal-flash.h index 583d53eb..92a65a65 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-flash.h +++ b/firmware/targets/f7/furi-hal/furi-hal-flash.h @@ -80,7 +80,7 @@ bool furi_hal_flash_erase(uint8_t page, uint8_t count); */ bool furi_hal_flash_write_dword(size_t address, uint64_t data); -/** Write double word (64 bits) from address +/** Write row: 64 double word (64 bits) from address * * Locking operation, uses HSEM to manage shared access. * @@ -89,4 +89,4 @@ bool furi_hal_flash_write_dword(size_t address, uint64_t data); * * @return true on success */ -bool furi_hal_flash_write_dword_from(size_t address, size_t source_address); +bool furi_hal_flash_write_row(size_t address, size_t source_address); diff --git a/firmware/targets/furi-hal-include/furi-hal-bt.h b/firmware/targets/furi-hal-include/furi-hal-bt.h index fe9a6de9..461fc4ce 100644 --- a/firmware/targets/furi-hal-include/furi-hal-bt.h +++ b/firmware/targets/furi-hal-include/furi-hal-bt.h @@ -9,6 +9,9 @@ #include #include #include +#include +#include + #define FURI_HAL_BT_PACKET_SIZE_MAX SERIAL_SVC_DATA_LEN_MAX @@ -20,6 +23,12 @@ extern "C" { */ void furi_hal_bt_init(); +/** Start 2nd core and BLE stack + * + * @return true on success + */ +bool furi_hal_bt_start_core2(); + /** Start BLE app * @param event_cb - BleEventCallback instance * @param context - pointer to context @@ -52,6 +61,32 @@ void furi_hal_bt_dump_state(string_t buffer); */ bool furi_hal_bt_is_alive(); +/** Get key storage buffer address and size + * + * @param key_buff_addr pointer to store buffer address + * @param key_buff_size pointer to store buffer size + * + * @return true on success + */ +bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size); + +/** Get SRAM2 hardware semaphore + * @note Must be called before SRAM2 read/write operations + */ +void furi_hal_bt_nvm_sram_sem_acquire(); + +/** Release SRAM2 hardware semaphore + * @note Must be called after SRAM2 read/write operations + */ +void furi_hal_bt_nvm_sram_sem_release(); + +/** Set key storage change callback + * + * @param callback BleGlueKeyStorageChangedCallback instance + * @param context pointer to context + */ +void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context); + /** Set data event callbacks * @param on_received_cb - SerialSvcDataReceivedCallback instance * @param on_sent_cb - SerialSvcDataSentCallback instance @@ -65,16 +100,11 @@ void furi_hal_bt_set_data_event_callbacks(SerialSvcDataReceivedCallback on_recei */ bool furi_hal_bt_tx(uint8_t* data, uint16_t size); -/** Wait for Core2 startup */ -bool furi_hal_bt_wait_startup(); - /** Lock shared access to flash controller * * @param[in] erase_flag true if erase operation - * - * @return true if lock was successful, false if not */ -bool furi_hal_bt_lock_flash(bool erase_flag); +void furi_hal_bt_lock_flash(bool erase_flag); /** Unlock shared access to flash controller * diff --git a/lib/lfs_config.h b/lib/lfs_config.h new file mode 100644 index 00000000..7a883982 --- /dev/null +++ b/lib/lfs_config.h @@ -0,0 +1,187 @@ +#pragma once + +#include + +#ifdef FURI_NDEBUG +#define LFS_NO_ASSERT +#endif + +#define LFS_TAG "Lfs" + +#define LFS_TRACE(...) FURI_LOG_D(LFS_TAG, __VA_ARGS__); + +#define LFS_DEBUG(...) FURI_LOG_I(LFS_TAG, __VA_ARGS__); + +#define LFS_WARN(...) FURI_LOG_W(LFS_TAG, __VA_ARGS__); + +#define LFS_ERROR(...) FURI_LOG_E(LFS_TAG, __VA_ARGS__); + +#define LFS_ASSERT furi_assert + +// Because crc +#undef LFS_CONFIG + +// System includes +#include +#include +#include +#include + +#ifndef LFS_NO_MALLOC +#include +#endif +#ifndef LFS_NO_ASSERT +#include +#endif +#if !defined(LFS_NO_DEBUG) || \ + !defined(LFS_NO_WARN) || \ + !defined(LFS_NO_ERROR) || \ + defined(LFS_YES_TRACE) +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Builtin functions, these may be replaced by more efficient +// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more +// expensive basic C implementation for debugging purposes + +// Min/max functions for unsigned 32-bit numbers +static inline uint32_t lfs_max(uint32_t a, uint32_t b) { + return (a > b) ? a : b; +} + +static inline uint32_t lfs_min(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +// Align to nearest multiple of a size +static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { + return a - (a % alignment); +} + +static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { + return lfs_aligndown(a + alignment-1, alignment); +} + +// Find the smallest power of 2 greater than or equal to a +static inline uint32_t lfs_npw2(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a-1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; a >>= s; r |= s; + s = (a > 0xff ) << 3; a >>= s; r |= s; + s = (a > 0xf ) << 2; a >>= s; r |= s; + s = (a > 0x3 ) << 1; a >>= s; r |= s; + return (r | (a >> 1)) + 1; +#endif +} + +// Count the number of trailing binary zeros in a +// lfs_ctz(0) may be undefined +static inline uint32_t lfs_ctz(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs_npw2((a & -a) + 1) - 1; +#endif +} + +// Count the number of binary ones in a +static inline uint32_t lfs_popc(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif +} + +// Find the sequence comparison of a and b, this is the distance +// between a and b ignoring overflow +static inline int lfs_scmp(uint32_t a, uint32_t b) { + return (int)(unsigned)(a - b); +} + +// Convert between 32-bit little-endian and native order +static inline uint32_t lfs_fromle32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return a; +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t*)&a)[0] << 0) | + (((uint8_t*)&a)[1] << 8) | + (((uint8_t*)&a)[2] << 16) | + (((uint8_t*)&a)[3] << 24); +#endif +} + +static inline uint32_t lfs_tole32(uint32_t a) { + return lfs_fromle32(a); +} + +// Convert between 32-bit big-endian and native order +static inline uint32_t lfs_frombe32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return __builtin_bswap32(a); +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return a; +#else + return (((uint8_t*)&a)[0] << 24) | + (((uint8_t*)&a)[1] << 16) | + (((uint8_t*)&a)[2] << 8) | + (((uint8_t*)&a)[3] << 0); +#endif +} + +static inline uint32_t lfs_tobe32(uint32_t a) { + return lfs_frombe32(a); +} + +// Calculate CRC-32 with polynomial = 0x04c11db7 +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); + +// Allocate memory, only used if buffers are not provided to littlefs +// Note, memory must be 64-bit aligned +static inline void *lfs_malloc(size_t size) { +#ifndef LFS_NO_MALLOC + return malloc(size); +#else + (void)size; + return NULL; +#endif +} + +// Deallocate memory, only used if buffers are not provided to littlefs +static inline void lfs_free(void *p) { +#ifndef LFS_NO_MALLOC + free(p); +#else + (void)p; +#endif +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/lib/lib.mk b/lib/lib.mk index 681b5b59..34f43bd4 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -37,7 +37,7 @@ C_SOURCES += $(FATFS_DIR)/option/unicode.c # Little FS LITTLEFS_DIR = $(LIB_DIR)/littlefs -CFLAGS += -I$(LITTLEFS_DIR) +CFLAGS += -I$(LITTLEFS_DIR) -DLFS_CONFIG=lfs_config.h C_SOURCES += $(LITTLEFS_DIR)/lfs.c C_SOURCES += $(LITTLEFS_DIR)/lfs_util.c diff --git a/make/toolchain.mk b/make/toolchain.mk index 9b4f6f8e..9b7368c2 100644 --- a/make/toolchain.mk +++ b/make/toolchain.mk @@ -18,11 +18,11 @@ BIN = $(CP) -O binary -S DEBUG ?= 1 COMPACT ?= 0 ifeq ($(DEBUG), 1) -CFLAGS += -DFURI_DEBUG -DNDEBUG -DLFS_NO_ASSERT -Og -g +CFLAGS += -DFURI_DEBUG -DNDEBUG -Og -g else ifeq ($(COMPACT), 1) -CFLAGS += -DFURI_NDEBUG -DNDEBUG -DLFS_NO_ASSERT -Os +CFLAGS += -DFURI_NDEBUG -DNDEBUG -Os else -CFLAGS += -DFURI_NDEBUG -DNDEBUG -DLFS_NO_ASSERT -Og +CFLAGS += -DFURI_NDEBUG -DNDEBUG -Og endif CFLAGS += -fdata-sections -ffunction-sections -fno-math-errno -fstack-usage -MMD -MP -MF"$(@:%.o=%.d)"