[FL-2204] Bluetooth forget devices (#967)

* bt: update connection parameters
* bt: set correct connection latency and timeout
* gui popup: add clean method
* furi_hal_bt: add connection parameters request, clear database
* bt: add forget bonded devices API
* bt_settings: add forget bonded devices GUI
* bt: rework pin code show with view port to hide view
* bt: support conn parameters for different profiles
* furi_hal_bt: sync f6 target
* target f6: fix build
* bt: format sources
* furi_hal_bt: update connection parameters
* bt: update connection params, fix GUI
* FuriHal: fix spelling
* Refactoring: rename _clean to _reset

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich
2022-01-21 20:32:03 +03:00
committed by GitHub
parent d4787e859e
commit 23ff6723cf
82 changed files with 471 additions and 116 deletions

View File

@@ -2,7 +2,8 @@
#include "battery_service.h"
#include "bt_keys_storage.h"
#include <applications/notification/notification_messages.h>
#include <notification/notification_messages.h>
#include <gui/elements.h>
#define TAG "BtSrv"
@@ -29,17 +30,46 @@ static ViewPort* bt_statusbar_view_port_alloc(Bt* bt) {
return statusbar_view_port;
}
static void bt_pin_code_show_event_handler(Bt* bt, uint32_t pin) {
furi_assert(bt);
static void bt_pin_code_view_port_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
Bt* bt = context;
char pin_code_info[24];
canvas_draw_icon(canvas, 0, 0, &I_BLE_Pairing_128x64);
snprintf(pin_code_info, sizeof(pin_code_info), "Pairing code\n%06ld", bt->pin_code);
elements_multiline_text_aligned(canvas, 64, 4, AlignCenter, AlignTop, pin_code_info);
elements_button_left(canvas, "Quit");
}
static void bt_pin_code_view_port_input_callback(InputEvent* event, void* context) {
furi_assert(context);
Bt* bt = context;
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft || event->key == InputKeyBack) {
view_port_enabled_set(bt->pin_code_view_port, false);
}
}
}
static ViewPort* bt_pin_code_view_port_alloc(Bt* bt) {
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, bt_pin_code_view_port_draw_callback, bt);
view_port_input_callback_set(view_port, bt_pin_code_view_port_input_callback, bt);
view_port_enabled_set(view_port, false);
return view_port;
}
static void bt_pin_code_show(Bt* bt, uint32_t pin_code) {
bt->pin_code = pin_code;
notification_message(bt->notification, &sequence_display_on);
string_t pin_str;
dialog_message_set_icon(bt->dialog_message, &I_BLE_Pairing_128x64, 0, 0);
string_init_printf(pin_str, "Pairing code\n%06d", pin);
dialog_message_set_text(
bt->dialog_message, string_get_cstr(pin_str), 64, 4, AlignCenter, AlignTop);
dialog_message_set_buttons(bt->dialog_message, "Quit", NULL, NULL);
dialog_message_show(bt->dialogs, bt->dialog_message);
string_clear(pin_str);
gui_view_port_send_to_front(bt->gui, bt->pin_code_view_port);
view_port_enabled_set(bt->pin_code_view_port, true);
}
static void bt_pin_code_hide(Bt* bt) {
bt->pin_code = 0;
if(view_port_is_enabled(bt->pin_code_view_port)) {
view_port_enabled_set(bt->pin_code_view_port, false);
}
}
static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) {
@@ -84,11 +114,14 @@ Bt* bt_alloc() {
// Setup statusbar view port
bt->statusbar_view_port = bt_statusbar_view_port_alloc(bt);
// Pin code view port
bt->pin_code_view_port = bt_pin_code_view_port_alloc(bt);
// Notification
bt->notification = furi_record_open("notification");
// Gui
bt->gui = furi_record_open("gui");
gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft);
gui_add_view_port(bt->gui, bt->pin_code_view_port, GuiLayerFullscreen);
// Dialogs
bt->dialogs = furi_record_open("dialogs");
@@ -162,7 +195,7 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
if(event.type == GapEventTypeConnected) {
// Update status bar
bt->status = BtStatusConnected;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
BtMessage message = {.type = BtMessageTypeUpdateStatus};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
if(bt->profile == BtProfileSerial) {
// Open RPC session
@@ -192,12 +225,12 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
ret = true;
} else if(event.type == GapEventTypeStartAdvertising) {
bt->status = BtStatusAdvertising;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
BtMessage message = {.type = BtMessageTypeUpdateStatus};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true;
} else if(event.type == GapEventTypeStopAdvertising) {
bt->status = BtStatusOff;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
BtMessage message = {.type = BtMessageTypeUpdateStatus};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true;
} else if(event.type == GapEventTypePinCodeShow) {
@@ -313,9 +346,10 @@ int32_t bt_srv() {
BtMessage message;
while(1) {
furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK);
if(message.type == BtMessageTypeUpdateStatusbar) {
// Update statusbar
if(message.type == BtMessageTypeUpdateStatus) {
// Update view ports
bt_statusbar_update(bt);
bt_pin_code_hide(bt);
if(bt->status_changed_cb) {
bt->status_changed_cb(bt->status, bt->status_changed_ctx);
}
@@ -324,11 +358,13 @@ int32_t bt_srv() {
furi_hal_bt_update_battery_level(message.data.battery_level);
} else if(message.type == BtMessageTypePinCodeShow) {
// Display PIN code
bt_pin_code_show_event_handler(bt, message.data.pin_code);
bt_pin_code_show(bt, message.data.pin_code);
} else if(message.type == BtMessageTypeKeysStorageUpdated) {
bt_save_key_storage(bt);
} else if(message.type == BtMessageTypeSetProfile) {
bt_change_profile(bt, &message);
} else if(message.type == BtMessageTypeForgetBondedDevices) {
bt_delete_key_storage(bt);
}
}
return 0;

View File

@@ -41,6 +41,13 @@ bool bt_set_profile(Bt* bt, BtProfile profile);
*/
void bt_set_status_changed_callback(Bt* bt, BtStatusChangedCallback callback, void* context);
/** Forget bonded devices
* @note Leads to wipe ble key storage and deleting bt.keys
*
* @param bt Bt instance
*/
void bt_forget_bonded_devices(Bt* bt);
#ifdef __cplusplus
}
#endif

View File

@@ -20,3 +20,9 @@ void bt_set_status_changed_callback(Bt* bt, BtStatusChangedCallback callback, vo
bt->status_changed_cb = callback;
bt->status_changed_ctx = context;
}
void bt_forget_bonded_devices(Bt* bt) {
furi_assert(bt);
BtMessage message = {.type = BtMessageTypeForgetBondedDevices};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
}

View File

@@ -19,11 +19,12 @@
#define BT_API_UNLOCK_EVENT (1UL << 0)
typedef enum {
BtMessageTypeUpdateStatusbar,
BtMessageTypeUpdateStatus,
BtMessageTypeUpdateBatteryLevel,
BtMessageTypePinCodeShow,
BtMessageTypeKeysStorageUpdated,
BtMessageTypeSetProfile,
BtMessageTypeForgetBondedDevices,
} BtMessageType;
typedef union {
@@ -49,6 +50,8 @@ struct Bt {
NotificationApp* notification;
Gui* gui;
ViewPort* statusbar_view_port;
ViewPort* pin_code_view_port;
uint32_t pin_code;
DialogsApp* dialogs;
DialogMessage* dialog_message;
Power* power;

View File

@@ -39,3 +39,16 @@ bool bt_save_key_storage(Bt* bt) {
file_worker_free(file_worker);
return file_saved;
}
bool bt_delete_key_storage(Bt* bt) {
furi_assert(bt);
bool delete_succeed = false;
furi_hal_bt_stop_advertising();
delete_succeed = furi_hal_bt_clear_white_list();
if(bt->bt_settings.enabled) {
furi_hal_bt_start_advertising();
}
return delete_succeed;
}

View File

@@ -5,3 +5,5 @@
bool bt_load_key_storage(Bt* bt);
bool bt_save_key_storage(Bt* bt);
bool bt_delete_key_storage(Bt* bt);

View File

@@ -18,7 +18,9 @@ BtSettingsApp* bt_settings_app_alloc() {
// Load settings
bt_settings_load(&app->settings);
app->gui = furi_record_open("gui");
app->bt = furi_record_open("bt");
// View Dispatcher and Scene Manager
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&bt_settings_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
@@ -31,26 +33,45 @@ BtSettingsApp* bt_settings_app_alloc() {
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Gui Modules
app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
BtSettingsAppViewVarItemList,
variable_item_list_get_view(app->var_item_list));
app->dialog = dialog_ex_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BtSettingsAppViewDialog, dialog_ex_get_view(app->dialog));
app->popup = popup_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BtSettingsAppViewPopup, popup_get_view(app->popup));
// Set first scene
scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneStart);
return app;
}
void bt_settings_app_free(BtSettingsApp* app) {
furi_assert(app);
// Variable item list
// Gui modules
view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewVarItemList);
variable_item_list_free(app->var_item_list);
// View dispatcher
view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewDialog);
dialog_ex_free(app->dialog);
view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewPopup);
popup_free(app->popup);
// View Dispatcher and Scene Manager
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
// Records
furi_record_close("gui");
furi_record_close("bt");
free(app);
}

View File

@@ -1,22 +1,33 @@
#pragma once
#include <furi.h>
#include <bt/bt_service/bt.h>
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/popup.h>
#include "../bt_settings.h"
#include "scenes/bt_settings_scene.h"
typedef struct {
BtSettings settings;
Bt* bt;
Gui* gui;
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;
VariableItemList* var_item_list;
DialogEx* dialog;
Popup* popup;
} BtSettingsApp;
typedef enum { BtSettingsAppViewVarItemList } BtSettingsAppView;
typedef enum {
BtSettingsAppViewVarItemList,
BtSettingsAppViewDialog,
BtSettingsAppViewPopup,
} BtSettingsAppView;

View File

@@ -1 +1,3 @@
ADD_SCENE(bt_settings, start, Start)
ADD_SCENE(bt_settings, forget_dev_confirm, ForgetDevConfirm)
ADD_SCENE(bt_settings, forget_dev_success, ForgetDevSuccess)

View File

@@ -0,0 +1,44 @@
#include "../bt_settings_app.h"
#include "furi_hal_bt.h"
void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) {
furi_assert(context);
BtSettingsApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
void bt_settings_scene_forget_dev_confirm_on_enter(void* context) {
BtSettingsApp* app = context;
DialogEx* dialog = app->dialog;
dialog_ex_set_header(dialog, "Unpair all devices?", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog, "All previous pairings\nwill be lost.", 64, 22, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog, "Back");
dialog_ex_set_right_button_text(dialog, "Unpair");
dialog_ex_set_context(dialog, app);
dialog_ex_set_result_callback(dialog, bt_settings_scene_forget_dev_confirm_dialog_callback);
view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewDialog);
}
bool bt_settings_scene_forget_dev_confirm_on_event(void* context, SceneManagerEvent event) {
BtSettingsApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
consumed = scene_manager_previous_scene(app->scene_manager);
} else if(event.event == DialogExResultRight) {
bt_forget_bonded_devices(app->bt);
scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevSuccess);
consumed = true;
}
}
return consumed;
}
void bt_settings_scene_forget_dev_confirm_on_exit(void* context) {
BtSettingsApp* app = context;
dialog_ex_reset(app->dialog);
}

View File

@@ -0,0 +1,43 @@
#include "../bt_settings_app.h"
#include "furi_hal_bt.h"
#define SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT (0UL)
void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) {
BtSettingsApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT);
}
void bt_settings_scene_forget_dev_success_on_enter(void* context) {
BtSettingsApp* app = context;
Popup* popup = app->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Done", 14, 15, AlignLeft, AlignTop);
popup_set_timeout(popup, 1500);
popup_set_context(popup, app);
popup_set_callback(popup, bt_settings_app_scene_forget_dev_success_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewPopup);
}
bool bt_settings_scene_forget_dev_success_on_event(void* context, SceneManagerEvent event) {
BtSettingsApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT) {
if(scene_manager_has_previous_scene(app->scene_manager, BtSettingsAppSceneStart)) {
consumed = scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, BtSettingsAppSceneStart);
}
}
}
return consumed;
}
void bt_settings_scene_forget_dev_success_on_exit(void* context) {
BtSettingsApp* app = context;
popup_reset(app->popup);
}

View File

@@ -1,6 +1,8 @@
#include "../bt_settings_app.h"
#include "furi_hal_bt.h"
#define SCENE_START_FORGET_DEV_SELECTED_EVENT (10UL)
enum BtSetting {
BtSettingOff,
BtSettingOn,
@@ -8,8 +10,8 @@ enum BtSetting {
};
const char* const bt_settings_text[BtSettingNum] = {
"Off",
"On",
"OFF",
"ON",
};
static void bt_settings_scene_start_var_list_change_callback(VariableItem* item) {
@@ -20,6 +22,12 @@ static void bt_settings_scene_start_var_list_change_callback(VariableItem* item)
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
static void bt_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
furi_assert(context);
BtSettingsApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_START_FORGET_DEV_SELECTED_EVENT);
}
void bt_settings_scene_start_on_enter(void* context) {
BtSettingsApp* app = context;
VariableItemList* var_item_list = app->var_item_list;
@@ -40,6 +48,9 @@ void bt_settings_scene_start_on_enter(void* context) {
variable_item_set_current_value_index(item, BtSettingOff);
variable_item_set_current_value_text(item, bt_settings_text[BtSettingOff]);
}
variable_item_list_add(var_item_list, "Forget all paired devices", 1, NULL, NULL);
variable_item_list_set_enter_callback(
var_item_list, bt_settings_scene_start_var_list_enter_callback, app);
} else {
item = variable_item_list_add(var_item_list, "Bluetooth", 1, NULL, NULL);
variable_item_set_current_value_text(item, "Broken");
@@ -56,16 +67,20 @@ bool bt_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.event == BtSettingOn) {
furi_hal_bt_start_advertising();
app->settings.enabled = true;
consumed = true;
} else if(event.event == BtSettingOff) {
app->settings.enabled = false;
furi_hal_bt_stop_advertising();
consumed = true;
} else if(event.event == SCENE_START_FORGET_DEV_SELECTED_EVENT) {
scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevConfirm);
consumed = true;
}
consumed = true;
}
return consumed;
}
void bt_settings_scene_start_on_exit(void* context) {
BtSettingsApp* app = context;
variable_item_list_clean(app->var_item_list);
variable_item_list_reset(app->var_item_list);
}