Fix GUI freeze after NFC classic read (#1074)

* nfc worker: add delay for task switching
* device info service: fix rpc version characteristic
* firmware: move FreeRTOSConfig.h to target include
* dev_info service: fix typo
* ble glue: use osThreadFlags instead of osEventFlags
* Infrared: fix issue with timer lockup
* FuriHal: yeld in flash lock routine
* ble: change connection parameters, display actual params
* ble: verify connection parameters
* ble: fix typo

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
gornekich
2022-03-31 17:57:23 +03:00
committed by GitHub
parent 8b833cb7eb
commit 0bf2702210
10 changed files with 96 additions and 81 deletions

View File

@@ -24,7 +24,6 @@ typedef struct {
osMutexId_t hci_mtx;
osSemaphoreId_t hci_sem;
FuriThread* thread;
osEventFlagsId_t event_flags;
} BleApp;
static BleApp* ble_app = NULL;
@@ -39,7 +38,6 @@ bool ble_app_init() {
// Allocate semafore and mutex for ble command buffer access
ble_app->hci_mtx = osMutexNew(NULL);
ble_app->hci_sem = osSemaphoreNew(1, 0, NULL);
ble_app->event_flags = osEventFlagsNew(NULL);
// HCI transport layer thread to handle user asynch events
ble_app->thread = furi_thread_alloc();
furi_thread_set_name(ble_app->thread, "BleHciDriver");
@@ -108,15 +106,14 @@ void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) {
void ble_app_thread_stop() {
if(ble_app) {
osEventFlagsSet(ble_app->event_flags, BLE_APP_FLAG_KILL_THREAD);
osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread);
furi_assert(thread_id);
osThreadFlagsSet(thread_id, BLE_APP_FLAG_KILL_THREAD);
furi_thread_join(ble_app->thread);
furi_thread_free(ble_app->thread);
// Wait to make sure that EventFlags delivers pending events before memory free
osDelay(50);
// Free resources
osMutexDelete(ble_app->hci_mtx);
osSemaphoreDelete(ble_app->hci_sem);
osEventFlagsDelete(ble_app->event_flags);
free(ble_app);
ble_app = NULL;
memset(&ble_app_cmd_buffer, 0, sizeof(ble_app_cmd_buffer));
@@ -125,9 +122,9 @@ void ble_app_thread_stop() {
static int32_t ble_app_hci_thread(void* arg) {
uint32_t flags = 0;
while(1) {
flags = osEventFlagsWait(
ble_app->event_flags, BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever);
flags = osThreadFlagsWait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever);
if(flags & BLE_APP_FLAG_KILL_THREAD) {
break;
}
@@ -142,7 +139,9 @@ static int32_t ble_app_hci_thread(void* arg) {
// Called by WPAN lib
void hci_notify_asynch_evt(void* pdata) {
if(ble_app) {
osEventFlagsSet(ble_app->event_flags, BLE_APP_FLAG_HCI_EVENT);
osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread);
furi_assert(thread_id);
osThreadFlagsSet(thread_id, BLE_APP_FLAG_HCI_EVENT);
}
}

View File

@@ -40,7 +40,6 @@ typedef enum {
typedef struct {
osMutexId_t shci_mtx;
osSemaphoreId_t shci_sem;
osEventFlagsId_t event_flags;
FuriThread* thread;
BleGlueStatus status;
BleGlueKeyStorageChangedCallback callback;
@@ -83,7 +82,6 @@ void ble_glue_init() {
ble_glue->shci_mtx = osMutexNew(NULL);
ble_glue->shci_sem = osSemaphoreNew(1, 0, NULL);
ble_glue->event_flags = osEventFlagsNew(NULL);
// FreeRTOS system task creation
ble_glue->thread = furi_thread_alloc();
@@ -257,15 +255,14 @@ static void ble_glue_clear_shared_memory() {
void ble_glue_thread_stop() {
if(ble_glue) {
osEventFlagsSet(ble_glue->event_flags, BLE_GLUE_FLAG_KILL_THREAD);
osThreadId_t thread_id = furi_thread_get_thread_id(ble_glue->thread);
furi_assert(thread_id);
osThreadFlagsSet(thread_id, BLE_GLUE_FLAG_KILL_THREAD);
furi_thread_join(ble_glue->thread);
furi_thread_free(ble_glue->thread);
// Wait to make sure that EventFlags delivers pending events before memory free
osDelay(50);
// Free resources
osMutexDelete(ble_glue->shci_mtx);
osSemaphoreDelete(ble_glue->shci_sem);
osEventFlagsDelete(ble_glue->event_flags);
ble_glue_clear_shared_memory();
free(ble_glue);
ble_glue = NULL;
@@ -275,9 +272,9 @@ void ble_glue_thread_stop() {
// Wrap functions
static int32_t ble_glue_shci_thread(void* context) {
uint32_t flags = 0;
while(true) {
flags = osEventFlagsWait(
ble_glue->event_flags, BLE_GLUE_FLAG_ALL, osFlagsWaitAny, osWaitForever);
flags = osThreadFlagsWait(BLE_GLUE_FLAG_ALL, osFlagsWaitAny, osWaitForever);
if(flags & BLE_GLUE_FLAG_SHCI_EVENT) {
shci_user_evt_proc();
}
@@ -292,7 +289,9 @@ static int32_t ble_glue_shci_thread(void* context) {
void shci_notify_asynch_evt(void* pdata) {
UNUSED(pdata);
if(ble_glue) {
osEventFlagsSet(ble_glue->event_flags, BLE_GLUE_FLAG_SHCI_EVENT);
osThreadId_t thread_id = furi_thread_get_thread_id(ble_glue->thread);
furi_assert(thread_id);
osThreadFlagsSet(thread_id, BLE_GLUE_FLAG_SHCI_EVENT);
}
}

12
firmware/targets/f7/ble_glue/dev_info_service.c Normal file → Executable file
View File

@@ -8,8 +8,6 @@
#define TAG "BtDevInfoSvc"
#define DEV_INFO_RPC_VERSION_CHAR_MAX_SIZE (10)
typedef struct {
uint16_t service_handle;
uint16_t man_name_char_handle;
@@ -26,6 +24,7 @@ static const char dev_info_serial_num[] = "1.0";
static const char dev_info_firmware_rev_num[] = TOSTRING(TARGET);
static const char dev_info_software_rev_num[] = GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM
" " BUILD_DATE;
static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION);
static const uint8_t dev_info_rpc_version_uuid[] =
{0x33, 0xa9, 0xb5, 0x3e, 0x87, 0x5d, 0x1a, 0x8e, 0xc8, 0x47, 0x5e, 0xae, 0x6d, 0x66, 0xf6, 0x03};
@@ -107,7 +106,7 @@ void dev_info_svc_start() {
dev_info_svc->service_handle,
UUID_TYPE_128,
(const Char_UUID_t*)dev_info_rpc_version_uuid,
DEV_INFO_RPC_VERSION_CHAR_MAX_SIZE,
strlen(dev_info_rpc_version),
CHAR_PROP_READ,
ATTR_PERMISSION_AUTHEN_READ,
GATT_DONT_NOTIFY_EVENTS,
@@ -155,18 +154,15 @@ void dev_info_svc_start() {
if(status) {
FURI_LOG_E(TAG, "Failed to update software revision char: %d", status);
}
string_t rpc_version;
string_init_printf(rpc_version, "%d.%d", PROTOBUF_MAJOR_VERSION, PROTOBUF_MINOR_VERSION);
status = aci_gatt_update_char_value(
dev_info_svc->service_handle,
dev_info_svc->rpc_version_char_handle,
0,
strlen(string_get_cstr(rpc_version)),
(uint8_t*)string_get_cstr(rpc_version));
strlen(dev_info_rpc_version),
(uint8_t*)dev_info_rpc_version);
if(status) {
FURI_LOG_E(TAG, "Failed to update rpc version char: %d", status);
}
string_clear(rpc_version);
}
void dev_info_svc_stop() {

View File

@@ -10,6 +10,8 @@
#define FAST_ADV_TIMEOUT 30000
#define INITIAL_ADV_TIMEOUT 60000
#define GAP_INTERVAL_TO_MS(x) (uint16_t)((x)*1.25)
typedef struct {
uint16_t gap_svc_handle;
uint16_t dev_name_char_handle;
@@ -23,6 +25,7 @@ typedef struct {
typedef struct {
GapSvc service;
GapConfig* config;
GapConnectionParams connection_params;
GapState state;
osMutexId_t state_mutex;
GapEventCallback on_event_cb;
@@ -58,6 +61,33 @@ static GapScan* gap_scan = NULL;
static void gap_advertise_start(GapState new_state);
static int32_t gap_app(void* context);
static void gap_verify_connection_parameters(Gap* gap) {
furi_assert(gap);
FURI_LOG_I(
TAG,
"Connection parameters: Connection Interval: %d (%d ms), Slave Latency: %d, Supervision Timeout: %d",
gap->connection_params.conn_interval,
GAP_INTERVAL_TO_MS(gap->connection_params.conn_interval),
gap->connection_params.slave_latency,
gap->connection_params.supervisor_timeout);
// Send connection parameters request update if necessary
GapConnectionParamsRequest* params = &gap->config->conn_param;
if(params->conn_int_min > gap->connection_params.conn_interval ||
params->conn_int_max < gap->connection_params.conn_interval) {
FURI_LOG_W(TAG, "Unsupported connection interval. Request connection parameters update");
if(aci_l2cap_connection_parameter_update_req(
gap->service.connection_handle,
params->conn_int_min,
params->conn_int_max,
gap->connection_params.slave_latency,
gap->connection_params.supervisor_timeout)) {
FURI_LOG_E(TAG, "Failed to request connection parameters update");
}
}
}
SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
hci_event_pckt* event_pckt;
evt_le_meta_event* meta_evt;
@@ -97,12 +127,11 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
case EVT_LE_CONN_UPDATE_COMPLETE: {
hci_le_connection_update_complete_event_rp0* event =
(hci_le_connection_update_complete_event_rp0*)meta_evt->data;
FURI_LOG_I(
TAG,
"Connection interval: %d, latency: %d, supervision timeout: %d",
event->Conn_Interval,
event->Conn_Latency,
event->Supervision_Timeout);
gap->connection_params.conn_interval = event->Conn_Interval;
gap->connection_params.slave_latency = event->Conn_Latency;
gap->connection_params.supervisor_timeout = event->Supervision_Timeout;
FURI_LOG_I(TAG, "Connection parameters event complete");
gap_verify_connection_parameters(gap);
break;
}
@@ -124,31 +153,22 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
case EVT_LE_CONN_COMPLETE:
furi_hal_power_insomnia_enter();
hci_le_connection_complete_event_rp0* connection_complete_event =
hci_le_connection_complete_event_rp0* event =
(hci_le_connection_complete_event_rp0*)meta_evt->data;
FURI_LOG_I(
TAG,
"Connection complete for connection handle 0x%x",
connection_complete_event->Connection_Handle);
gap->connection_params.conn_interval = event->Conn_Interval;
gap->connection_params.slave_latency = event->Conn_Latency;
gap->connection_params.supervisor_timeout = event->Supervision_Timeout;
// Stop advertising as connection completed
osTimerStop(gap->advertise_timer);
// Update connection status and handle
gap->state = GapStateConnected;
gap->service.connection_handle = connection_complete_event->Connection_Handle;
GapConnectionParams* params = &gap->config->conn_param;
if(aci_l2cap_connection_parameter_update_req(
gap->service.connection_handle,
params->conn_int_min,
params->conn_int_max,
params->slave_latency,
params->supervisor_timeout)) {
FURI_LOG_W(TAG, "Failed to request connection parameters update");
}
gap->service.connection_handle = event->Connection_Handle;
gap_verify_connection_parameters(gap);
// Start pairing by sending security request
aci_gap_slave_security_req(connection_complete_event->Connection_Handle);
aci_gap_slave_security_req(event->Connection_Handle);
break;
case EVT_LE_ADVERTISING_REPORT: {

View File

@@ -55,12 +55,18 @@ typedef enum {
GapPairingPinCodeVerifyYesNo,
} GapPairing;
typedef struct {
uint16_t conn_interval;
uint16_t slave_latency;
uint16_t supervisor_timeout;
} GapConnectionParams;
typedef struct {
uint16_t conn_int_min;
uint16_t conn_int_max;
uint16_t slave_latency;
uint16_t supervisor_timeout;
} GapConnectionParams;
} GapConnectionParamsRequest;
typedef struct {
uint16_t adv_service_uuid;
@@ -69,7 +75,7 @@ typedef struct {
GapPairing pairing_method;
uint8_t mac_address[GAP_MAC_ADDR_SIZE];
char adv_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH];
GapConnectionParams conn_param;
GapConnectionParamsRequest conn_param;
} GapConfig;
bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context);