[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 471 additions and 116 deletions

View File

@ -75,5 +75,5 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
void archive_scene_rename_on_exit(void* context) { void archive_scene_rename_on_exit(void* context) {
ArchiveApp* archive = (ArchiveApp*)context; ArchiveApp* archive = (ArchiveApp*)context;
// Clear view // Clear view
text_input_clean(archive->text_input); text_input_reset(archive->text_input);
} }

View File

@ -2,7 +2,8 @@
#include "battery_service.h" #include "battery_service.h"
#include "bt_keys_storage.h" #include "bt_keys_storage.h"
#include <applications/notification/notification_messages.h> #include <notification/notification_messages.h>
#include <gui/elements.h>
#define TAG "BtSrv" #define TAG "BtSrv"
@ -29,17 +30,46 @@ static ViewPort* bt_statusbar_view_port_alloc(Bt* bt) {
return statusbar_view_port; return statusbar_view_port;
} }
static void bt_pin_code_show_event_handler(Bt* bt, uint32_t pin) { static void bt_pin_code_view_port_draw_callback(Canvas* canvas, void* context) {
furi_assert(bt); 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); notification_message(bt->notification, &sequence_display_on);
string_t pin_str; gui_view_port_send_to_front(bt->gui, bt->pin_code_view_port);
dialog_message_set_icon(bt->dialog_message, &I_BLE_Pairing_128x64, 0, 0); view_port_enabled_set(bt->pin_code_view_port, true);
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); static void bt_pin_code_hide(Bt* bt) {
dialog_message_set_buttons(bt->dialog_message, "Quit", NULL, NULL); bt->pin_code = 0;
dialog_message_show(bt->dialogs, bt->dialog_message); if(view_port_is_enabled(bt->pin_code_view_port)) {
string_clear(pin_str); view_port_enabled_set(bt->pin_code_view_port, false);
}
} }
static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) { static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) {
@ -84,11 +114,14 @@ Bt* bt_alloc() {
// Setup statusbar view port // Setup statusbar view port
bt->statusbar_view_port = bt_statusbar_view_port_alloc(bt); 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 // Notification
bt->notification = furi_record_open("notification"); bt->notification = furi_record_open("notification");
// Gui // Gui
bt->gui = furi_record_open("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->statusbar_view_port, GuiLayerStatusBarLeft);
gui_add_view_port(bt->gui, bt->pin_code_view_port, GuiLayerFullscreen);
// Dialogs // Dialogs
bt->dialogs = furi_record_open("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) { if(event.type == GapEventTypeConnected) {
// Update status bar // Update status bar
bt->status = BtStatusConnected; bt->status = BtStatusConnected;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; BtMessage message = {.type = BtMessageTypeUpdateStatus};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
if(bt->profile == BtProfileSerial) { if(bt->profile == BtProfileSerial) {
// Open RPC session // Open RPC session
@ -192,12 +225,12 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
ret = true; ret = true;
} else if(event.type == GapEventTypeStartAdvertising) { } else if(event.type == GapEventTypeStartAdvertising) {
bt->status = BtStatusAdvertising; bt->status = BtStatusAdvertising;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; BtMessage message = {.type = BtMessageTypeUpdateStatus};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true; ret = true;
} else if(event.type == GapEventTypeStopAdvertising) { } else if(event.type == GapEventTypeStopAdvertising) {
bt->status = BtStatusOff; bt->status = BtStatusOff;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; BtMessage message = {.type = BtMessageTypeUpdateStatus};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true; ret = true;
} else if(event.type == GapEventTypePinCodeShow) { } else if(event.type == GapEventTypePinCodeShow) {
@ -313,9 +346,10 @@ int32_t bt_srv() {
BtMessage message; BtMessage message;
while(1) { while(1) {
furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK); furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK);
if(message.type == BtMessageTypeUpdateStatusbar) { if(message.type == BtMessageTypeUpdateStatus) {
// Update statusbar // Update view ports
bt_statusbar_update(bt); bt_statusbar_update(bt);
bt_pin_code_hide(bt);
if(bt->status_changed_cb) { if(bt->status_changed_cb) {
bt->status_changed_cb(bt->status, bt->status_changed_ctx); 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); furi_hal_bt_update_battery_level(message.data.battery_level);
} else if(message.type == BtMessageTypePinCodeShow) { } else if(message.type == BtMessageTypePinCodeShow) {
// Display PIN code // 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) { } else if(message.type == BtMessageTypeKeysStorageUpdated) {
bt_save_key_storage(bt); bt_save_key_storage(bt);
} else if(message.type == BtMessageTypeSetProfile) { } else if(message.type == BtMessageTypeSetProfile) {
bt_change_profile(bt, &message); bt_change_profile(bt, &message);
} else if(message.type == BtMessageTypeForgetBondedDevices) {
bt_delete_key_storage(bt);
} }
} }
return 0; 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); 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 #ifdef __cplusplus
} }
#endif #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_cb = callback;
bt->status_changed_ctx = context; 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) #define BT_API_UNLOCK_EVENT (1UL << 0)
typedef enum { typedef enum {
BtMessageTypeUpdateStatusbar, BtMessageTypeUpdateStatus,
BtMessageTypeUpdateBatteryLevel, BtMessageTypeUpdateBatteryLevel,
BtMessageTypePinCodeShow, BtMessageTypePinCodeShow,
BtMessageTypeKeysStorageUpdated, BtMessageTypeKeysStorageUpdated,
BtMessageTypeSetProfile, BtMessageTypeSetProfile,
BtMessageTypeForgetBondedDevices,
} BtMessageType; } BtMessageType;
typedef union { typedef union {
@ -49,6 +50,8 @@ struct Bt {
NotificationApp* notification; NotificationApp* notification;
Gui* gui; Gui* gui;
ViewPort* statusbar_view_port; ViewPort* statusbar_view_port;
ViewPort* pin_code_view_port;
uint32_t pin_code;
DialogsApp* dialogs; DialogsApp* dialogs;
DialogMessage* dialog_message; DialogMessage* dialog_message;
Power* power; Power* power;

View File

@ -39,3 +39,16 @@ bool bt_save_key_storage(Bt* bt) {
file_worker_free(file_worker); file_worker_free(file_worker);
return file_saved; 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_load_key_storage(Bt* bt);
bool bt_save_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 // Load settings
bt_settings_load(&app->settings); bt_settings_load(&app->settings);
app->gui = furi_record_open("gui"); app->gui = furi_record_open("gui");
app->bt = furi_record_open("bt");
// View Dispatcher and Scene Manager
app->view_dispatcher = view_dispatcher_alloc(); app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&bt_settings_scene_handlers, app); app->scene_manager = scene_manager_alloc(&bt_settings_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher); 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); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Gui Modules
app->var_item_list = variable_item_list_alloc(); app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, app->view_dispatcher,
BtSettingsAppViewVarItemList, BtSettingsAppViewVarItemList,
variable_item_list_get_view(app->var_item_list)); 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); scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneStart);
return app; return app;
} }
void bt_settings_app_free(BtSettingsApp* app) { void bt_settings_app_free(BtSettingsApp* app) {
furi_assert(app); furi_assert(app);
// Variable item list // Gui modules
view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewVarItemList); view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewVarItemList);
variable_item_list_free(app->var_item_list); 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); view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager); scene_manager_free(app->scene_manager);
// Records // Records
furi_record_close("gui"); furi_record_close("gui");
furi_record_close("bt");
free(app); free(app);
} }

View File

@ -1,22 +1,33 @@
#pragma once #pragma once
#include <furi.h> #include <furi.h>
#include <bt/bt_service/bt.h>
#include <gui/gui.h> #include <gui/gui.h>
#include <gui/view.h> #include <gui/view.h>
#include <gui/view_dispatcher.h> #include <gui/view_dispatcher.h>
#include <gui/scene_manager.h> #include <gui/scene_manager.h>
#include <gui/modules/variable_item_list.h> #include <gui/modules/variable_item_list.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/popup.h>
#include "../bt_settings.h" #include "../bt_settings.h"
#include "scenes/bt_settings_scene.h" #include "scenes/bt_settings_scene.h"
typedef struct { typedef struct {
BtSettings settings; BtSettings settings;
Bt* bt;
Gui* gui; Gui* gui;
SceneManager* scene_manager; SceneManager* scene_manager;
ViewDispatcher* view_dispatcher; ViewDispatcher* view_dispatcher;
VariableItemList* var_item_list; VariableItemList* var_item_list;
DialogEx* dialog;
Popup* popup;
} BtSettingsApp; } 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, 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 "../bt_settings_app.h"
#include "furi_hal_bt.h" #include "furi_hal_bt.h"
#define SCENE_START_FORGET_DEV_SELECTED_EVENT (10UL)
enum BtSetting { enum BtSetting {
BtSettingOff, BtSettingOff,
BtSettingOn, BtSettingOn,
@ -8,8 +10,8 @@ enum BtSetting {
}; };
const char* const bt_settings_text[BtSettingNum] = { const char* const bt_settings_text[BtSettingNum] = {
"Off", "OFF",
"On", "ON",
}; };
static void bt_settings_scene_start_var_list_change_callback(VariableItem* item) { 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); 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) { void bt_settings_scene_start_on_enter(void* context) {
BtSettingsApp* app = context; BtSettingsApp* app = context;
VariableItemList* var_item_list = app->var_item_list; 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_index(item, BtSettingOff);
variable_item_set_current_value_text(item, bt_settings_text[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 { } else {
item = variable_item_list_add(var_item_list, "Bluetooth", 1, NULL, NULL); item = variable_item_list_add(var_item_list, "Bluetooth", 1, NULL, NULL);
variable_item_set_current_value_text(item, "Broken"); 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) { if(event.event == BtSettingOn) {
furi_hal_bt_start_advertising(); furi_hal_bt_start_advertising();
app->settings.enabled = true; app->settings.enabled = true;
consumed = true;
} else if(event.event == BtSettingOff) { } else if(event.event == BtSettingOff) {
app->settings.enabled = false; app->settings.enabled = false;
furi_hal_bt_stop_advertising(); 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; return consumed;
} }
void bt_settings_scene_start_on_exit(void* context) { void bt_settings_scene_start_on_exit(void* context) {
BtSettingsApp* app = context; BtSettingsApp* app = context;
variable_item_list_clean(app->var_item_list); variable_item_list_reset(app->var_item_list);
} }

View File

@ -10,7 +10,7 @@ static void desktop_settings_scene_favorite_submenu_callback(void* context, uint
void desktop_settings_scene_favorite_on_enter(void* context) { void desktop_settings_scene_favorite_on_enter(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
Submenu* submenu = app->submenu; Submenu* submenu = app->submenu;
submenu_clean(submenu); submenu_reset(submenu);
for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) {
submenu_add_item( submenu_add_item(
@ -45,5 +45,5 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e
void desktop_settings_scene_favorite_on_exit(void* context) { void desktop_settings_scene_favorite_on_exit(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
SAVE_DESKTOP_SETTINGS(&app->settings); SAVE_DESKTOP_SETTINGS(&app->settings);
submenu_clean(app->submenu); submenu_reset(app->submenu);
} }

View File

@ -9,7 +9,7 @@ static void desktop_settings_scene_pincode_menu_submenu_callback(void* context,
void desktop_settings_scene_pincode_menu_on_enter(void* context) { void desktop_settings_scene_pincode_menu_on_enter(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
Submenu* submenu = app->submenu; Submenu* submenu = app->submenu;
submenu_clean(submenu); submenu_reset(submenu);
if(!app->settings.pincode.length) { if(!app->settings.pincode.length) {
submenu_add_item( submenu_add_item(
@ -74,5 +74,5 @@ bool desktop_settings_scene_pincode_menu_on_event(void* context, SceneManagerEve
void desktop_settings_scene_pincode_menu_on_exit(void* context) { void desktop_settings_scene_pincode_menu_on_exit(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
submenu_clean(app->submenu); submenu_reset(app->submenu);
} }

View File

@ -53,5 +53,5 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
void desktop_settings_scene_start_on_exit(void* context) { void desktop_settings_scene_start_on_exit(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
submenu_clean(app->submenu); submenu_reset(app->submenu);
} }

View File

@ -95,5 +95,5 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) {
void gpio_scene_start_on_exit(void* context) { void gpio_scene_start_on_exit(void* context) {
GpioApp* app = context; GpioApp* app = context;
variable_item_list_clean(app->var_item_list); variable_item_list_reset(app->var_item_list);
} }

View File

@ -135,6 +135,6 @@ void gpio_scene_usb_uart_cfg_on_exit(void* context) {
app->scene_manager, app->scene_manager,
GpioAppViewUsbUartCfg, GpioAppViewUsbUartCfg,
variable_item_list_get_selected_item_index(app->var_item_list)); variable_item_list_get_selected_item_index(app->var_item_list));
variable_item_list_clean(app->var_item_list); variable_item_list_reset(app->var_item_list);
free(cfg_set); free(cfg_set);
} }

View File

@ -241,7 +241,7 @@ View* button_menu_get_view(ButtonMenu* button_menu) {
return button_menu->view; return button_menu->view;
} }
void button_menu_clean(ButtonMenu* button_menu) { void button_menu_reset(ButtonMenu* button_menu) {
furi_assert(button_menu); furi_assert(button_menu);
with_view_model( with_view_model(

View File

@ -39,7 +39,7 @@ View* button_menu_get_view(ButtonMenu* button_menu);
* *
* @param button_menu ButtonMenu instance * @param button_menu ButtonMenu instance
*/ */
void button_menu_clean(ButtonMenu* button_menu); void button_menu_reset(ButtonMenu* button_menu);
/** Add item to button menu instance /** Add item to button menu instance
* *

View File

@ -112,7 +112,7 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re
void button_panel_free(ButtonPanel* button_panel) { void button_panel_free(ButtonPanel* button_panel) {
furi_assert(button_panel); furi_assert(button_panel);
button_panel_clean(button_panel); button_panel_reset(button_panel);
with_view_model( with_view_model(
button_panel->view, (ButtonPanelModel * model) { button_panel->view, (ButtonPanelModel * model) {
@ -125,7 +125,7 @@ void button_panel_free(ButtonPanel* button_panel) {
free(button_panel); free(button_panel);
} }
void button_panel_clean(ButtonPanel* button_panel) { void button_panel_reset(ButtonPanel* button_panel) {
furi_assert(button_panel); furi_assert(button_panel);
with_view_model( with_view_model(

View File

@ -39,7 +39,7 @@ void button_panel_free(ButtonPanel* button_panel);
* *
* @param button_panel ButtonPanel instance * @param button_panel ButtonPanel instance
*/ */
void button_panel_clean(ButtonPanel* button_panel); void button_panel_reset(ButtonPanel* button_panel);
/** Reserve space for adding items. /** Reserve space for adding items.
* *

View File

@ -244,7 +244,7 @@ void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) {
}); });
} }
void dialog_ex_clean(DialogEx* dialog_ex) { void dialog_ex_reset(DialogEx* dialog_ex) {
furi_assert(dialog_ex); furi_assert(dialog_ex);
TextElement clean_text_el = { TextElement clean_text_el = {
.text = NULL, .x = 0, .y = 0, .horizontal = AlignLeft, .vertical = AlignLeft}; .text = NULL, .x = 0, .y = 0, .horizontal = AlignLeft, .vertical = AlignLeft};

View File

@ -143,8 +143,8 @@ void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text);
* *
* @param dialog_ex DialogEx instance * @param dialog_ex DialogEx instance
*/ */
void dialog_ex_clean(DialogEx* dialog_ex); void dialog_ex_reset(DialogEx* dialog_ex);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -146,7 +146,7 @@ Menu* menu_alloc() {
void menu_free(Menu* menu) { void menu_free(Menu* menu) {
furi_assert(menu); furi_assert(menu);
menu_clean(menu); menu_reset(menu);
view_free(menu->view); view_free(menu->view);
free(menu); free(menu);
} }
@ -180,7 +180,7 @@ void menu_add_item(
}); });
} }
void menu_clean(Menu* menu) { void menu_reset(Menu* menu) {
furi_assert(menu); furi_assert(menu);
with_view_model( with_view_model(
menu->view, (MenuModel * model) { menu->view, (MenuModel * model) {

View File

@ -59,7 +59,7 @@ void menu_add_item(
* *
* @param menu Menu instance * @param menu Menu instance
*/ */
void menu_clean(Menu* menu); void menu_reset(Menu* menu);
/** Set current menu item /** Set current menu item
* *

View File

@ -226,4 +226,20 @@ void popup_enable_timeout(Popup* popup) {
void popup_disable_timeout(Popup* popup) { void popup_disable_timeout(Popup* popup) {
popup->timer_enabled = false; popup->timer_enabled = false;
} }
void popup_reset(Popup* popup) {
furi_assert(popup);
with_view_model(
popup->view, (PopupModel * model) {
memset(&model->header, 0, sizeof(model->header));
memset(&model->text, 0, sizeof(model->text));
memset(&model->icon, 0, sizeof(model->icon));
return false;
});
popup->callback = NULL;
popup->context = NULL;
popup->timer_enabled = false;
popup->timer_period_in_ms = 0;
}

View File

@ -123,6 +123,12 @@ void popup_enable_timeout(Popup* popup);
*/ */
void popup_disable_timeout(Popup* popup); void popup_disable_timeout(Popup* popup);
/** Reset popup instance state
*
* @param popup Popup instance
*/
void popup_reset(Popup* popup);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -177,7 +177,7 @@ void submenu_add_item(
}); });
} }
void submenu_clean(Submenu* submenu) { void submenu_reset(Submenu* submenu) {
furi_assert(submenu); furi_assert(submenu);
with_view_model( with_view_model(

View File

@ -57,7 +57,7 @@ void submenu_add_item(
* *
* @param submenu Submenu instance * @param submenu Submenu instance
*/ */
void submenu_clean(Submenu* submenu); void submenu_reset(Submenu* submenu);
/** Set submenu item selector /** Set submenu item selector
* *

View File

@ -164,7 +164,7 @@ View* text_box_get_view(TextBox* text_box) {
return text_box->view; return text_box->view;
} }
void text_box_clean(TextBox* text_box) { void text_box_reset(TextBox* text_box) {
furi_assert(text_box); furi_assert(text_box);
with_view_model( with_view_model(

View File

@ -44,7 +44,7 @@ View* text_box_get_view(TextBox* text_box);
* *
* @param text_box TextBox instance * @param text_box TextBox instance
*/ */
void text_box_clean(TextBox* text_box); void text_box_reset(TextBox* text_box);
/** Set text for text_box /** Set text for text_box
* *

View File

@ -425,7 +425,7 @@ TextInput* text_input_alloc() {
return false; return false;
}); });
text_input_clean(text_input); text_input_reset(text_input);
return text_input; return text_input;
} }
@ -450,7 +450,7 @@ void text_input_free(TextInput* text_input) {
free(text_input); free(text_input);
} }
void text_input_clean(TextInput* text_input) { void text_input_reset(TextInput* text_input) {
furi_assert(text_input); furi_assert(text_input);
with_view_model( with_view_model(
text_input->view, (TextInputModel * model) { text_input->view, (TextInputModel * model) {

View File

@ -36,7 +36,7 @@ void text_input_free(TextInput* text_input);
* *
* @param text_input Text input instance * @param text_input Text input instance
*/ */
void text_input_clean(TextInput* text_input); void text_input_reset(TextInput* text_input);
/** Get text input view /** Get text input view
* *
@ -84,4 +84,4 @@ void text_input_set_header_text(TextInput* text_input, const char* text);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -312,7 +312,7 @@ void variable_item_list_free(VariableItemList* variable_item_list) {
free(variable_item_list); free(variable_item_list);
} }
void variable_item_list_clean(VariableItemList* variable_item_list) { void variable_item_list_reset(VariableItemList* variable_item_list) {
furi_assert(variable_item_list); furi_assert(variable_item_list);
with_view_model( with_view_model(

View File

@ -32,7 +32,7 @@ void variable_item_list_free(VariableItemList* variable_item_list);
* *
* @param variable_item_list VariableItemList instance * @param variable_item_list VariableItemList instance
*/ */
void variable_item_list_clean(VariableItemList* variable_item_list); void variable_item_list_reset(VariableItemList* variable_item_list);
/** Get VariableItemList View instance /** Get VariableItemList View instance
* *

View File

@ -52,7 +52,7 @@ void iButtonSceneAddType::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager(); iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu(); Submenu* submenu = view->get_submenu();
submenu_clean(submenu); submenu_reset(submenu);
} }
void iButtonSceneAddType::submenu_callback(void* context, uint32_t index) { void iButtonSceneAddType::submenu_callback(void* context, uint32_t index) {
@ -63,4 +63,4 @@ void iButtonSceneAddType::submenu_callback(void* context, uint32_t index) {
event.payload.menu_index = index; event.payload.menu_index = index;
app->get_view_manager()->send_event(&event); app->get_view_manager()->send_event(&event);
} }

View File

@ -57,7 +57,7 @@ void iButtonSceneReadedKeyMenu::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager(); iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu(); Submenu* submenu = view->get_submenu();
submenu_clean(submenu); submenu_reset(submenu);
} }
void iButtonSceneReadedKeyMenu::submenu_callback(void* context, uint32_t index) { void iButtonSceneReadedKeyMenu::submenu_callback(void* context, uint32_t index) {
@ -68,4 +68,4 @@ void iButtonSceneReadedKeyMenu::submenu_callback(void* context, uint32_t index)
event.payload.menu_index = index; event.payload.menu_index = index;
app->get_view_manager()->send_event(&event); app->get_view_manager()->send_event(&event);
} }

View File

@ -48,7 +48,7 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
void iButtonSceneSaveName::on_exit(iButtonApp* app) { void iButtonSceneSaveName::on_exit(iButtonApp* app) {
TextInput* text_input = app->get_view_manager()->get_text_input(); TextInput* text_input = app->get_view_manager()->get_text_input();
text_input_clean(text_input); text_input_reset(text_input);
} }
void iButtonSceneSaveName::text_input_callback(void* context) { void iButtonSceneSaveName::text_input_callback(void* context) {
@ -58,4 +58,4 @@ void iButtonSceneSaveName::text_input_callback(void* context) {
event.type = iButtonEvent::Type::EventTypeTextEditResult; event.type = iButtonEvent::Type::EventTypeTextEditResult;
app->get_view_manager()->send_event(&event); app->get_view_manager()->send_event(&event);
} }

View File

@ -59,7 +59,7 @@ void iButtonSceneSavedKeyMenu::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager(); iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu(); Submenu* submenu = view->get_submenu();
submenu_clean(submenu); submenu_reset(submenu);
} }
void iButtonSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) { void iButtonSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) {
@ -70,4 +70,4 @@ void iButtonSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) {
event.payload.menu_index = index; event.payload.menu_index = index;
app->get_view_manager()->send_event(&event); app->get_view_manager()->send_event(&event);
} }

View File

@ -49,7 +49,7 @@ void iButtonSceneStart::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager(); iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu(); Submenu* submenu = view->get_submenu();
submenu_clean(submenu); submenu_reset(submenu);
} }
void iButtonSceneStart::submenu_callback(void* context, uint32_t index) { void iButtonSceneStart::submenu_callback(void* context, uint32_t index) {
@ -60,4 +60,4 @@ void iButtonSceneStart::submenu_callback(void* context, uint32_t index) {
event.payload.menu_index = index; event.payload.menu_index = index;
app->get_view_manager()->send_event(&event); app->get_view_manager()->send_event(&event);
} }

View File

@ -75,5 +75,5 @@ void IrdaAppSceneEdit::on_exit(IrdaApp* app) {
IrdaAppViewManager* view_manager = app->get_view_manager(); IrdaAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu(); Submenu* submenu = view_manager->get_submenu();
submenu_clean(submenu); submenu_reset(submenu);
} }

View File

@ -53,5 +53,5 @@ void IrdaAppSceneEditKeySelect::on_exit(IrdaApp* app) {
IrdaAppViewManager* view_manager = app->get_view_manager(); IrdaAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu(); Submenu* submenu = view_manager->get_submenu();
submenu_clean(submenu); submenu_reset(submenu);
} }

View File

@ -132,5 +132,5 @@ void IrdaAppSceneRemote::on_exit(IrdaApp* app) {
IrdaAppViewManager* view_manager = app->get_view_manager(); IrdaAppViewManager* view_manager = app->get_view_manager();
ButtonMenu* button_menu = view_manager->get_button_menu(); ButtonMenu* button_menu = view_manager->get_button_menu();
button_menu_clean(button_menu); button_menu_reset(button_menu);
} }

View File

@ -62,5 +62,5 @@ void IrdaAppSceneStart::on_exit(IrdaApp* app) {
Submenu* submenu = view_manager->get_submenu(); Submenu* submenu = view_manager->get_submenu();
app->get_remote_manager()->reset_remote(); app->get_remote_manager()->reset_remote();
submenu_clean(submenu); submenu_reset(submenu);
} }

View File

@ -53,5 +53,5 @@ void IrdaAppSceneUniversal::on_exit(IrdaApp* app) {
IrdaAppViewManager* view_manager = app->get_view_manager(); IrdaAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu(); Submenu* submenu = view_manager->get_submenu();
submenu_clean(submenu); submenu_reset(submenu);
} }

View File

@ -102,5 +102,5 @@ bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) {
void IrdaAppSceneUniversalCommon::on_exit(IrdaApp* app) { void IrdaAppSceneUniversalCommon::on_exit(IrdaApp* app) {
IrdaAppViewManager* view_manager = app->get_view_manager(); IrdaAppViewManager* view_manager = app->get_view_manager();
ButtonPanel* button_panel = view_manager->get_button_panel(); ButtonPanel* button_panel = view_manager->get_button_panel();
button_panel_clean(button_panel); button_panel_reset(button_panel);
} }

View File

@ -429,7 +429,7 @@ void loader_show_menu() {
} }
void loader_update_menu() { void loader_update_menu() {
menu_clean(loader_instance->primary_menu); menu_reset(loader_instance->primary_menu);
loader_build_menu(); loader_build_menu();
} }

View File

@ -81,5 +81,5 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_card_menu_on_exit(void* context) { void nfc_scene_card_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
submenu_clean(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -199,7 +199,7 @@ void nfc_scene_device_info_on_exit(void* context) {
dialog_ex_set_context(dialog_ex, NULL); dialog_ex_set_context(dialog_ex, NULL);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
// Clear TextBox // Clear TextBox
text_box_clean(nfc->text_box); text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store); string_reset(nfc->text_box_store);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
// Clear Bank Card // Clear Bank Card

View File

@ -54,5 +54,5 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_mifare_ul_menu_on_exit(void* context) { void nfc_scene_mifare_ul_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
submenu_clean(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -126,6 +126,6 @@ void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
// Clean TextBox // Clean TextBox
TextBox* text_box = nfc->text_box; TextBox* text_box = nfc->text_box;
text_box_clean(text_box); text_box_reset(text_box);
string_reset(nfc->text_box_store); string_reset(nfc->text_box_store);
} }

View File

@ -60,5 +60,5 @@ void nfc_scene_save_name_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
// Clear view // Clear view
text_input_clean(nfc->text_input); text_input_reset(nfc->text_input);
} }

View File

@ -81,5 +81,5 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_saved_menu_on_exit(void* context) { void nfc_scene_saved_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
submenu_clean(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -55,5 +55,5 @@ bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_scripts_menu_on_exit(void* context) { void nfc_scene_scripts_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
submenu_clean(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -45,5 +45,5 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_set_type_on_exit(void* context) { void nfc_scene_set_type_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
submenu_clean(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -78,5 +78,5 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_start_on_exit(void* context) { void nfc_scene_start_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
submenu_clean(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -39,5 +39,5 @@ bool power_settings_scene_power_off_on_event(void* context, SceneManagerEvent ev
void power_settings_scene_power_off_on_exit(void* context) { void power_settings_scene_power_off_on_exit(void* context) {
PowerSettingsApp* app = context; PowerSettingsApp* app = context;
dialog_ex_clean(app->dialog); dialog_ex_reset(app->dialog);
} }

View File

@ -48,5 +48,5 @@ bool power_settings_scene_reboot_on_event(void* context, SceneManagerEvent event
void power_settings_scene_reboot_on_exit(void* context) { void power_settings_scene_reboot_on_exit(void* context) {
PowerSettingsApp* app = context; PowerSettingsApp* app = context;
submenu_clean(app->submenu); submenu_reset(app->submenu);
} }

View File

@ -60,5 +60,5 @@ bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event)
void power_settings_scene_start_on_exit(void* context) { void power_settings_scene_start_on_exit(void* context) {
PowerSettingsApp* app = context; PowerSettingsApp* app = context;
submenu_clean(app->submenu); submenu_reset(app->submenu);
} }

View File

@ -115,5 +115,5 @@ bool storage_settings_scene_start_on_event(void* context, SceneManagerEvent even
void storage_settings_scene_start_on_exit(void* context) { void storage_settings_scene_start_on_exit(void* context) {
StorageSettings* app = context; StorageSettings* app = context;
submenu_clean(app->submenu); submenu_reset(app->submenu);
} }

View File

@ -56,5 +56,5 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
void subghz_scene_more_raw_on_exit(void* context) { void subghz_scene_more_raw_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
submenu_clean(subghz->submenu); submenu_reset(subghz->submenu);
} }

View File

@ -66,7 +66,7 @@ void subghz_scene_receiver_on_enter(void* context) {
string_init(str_buff); string_init(str_buff);
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
subghz_history_clean(subghz->txrx->history); subghz_history_reset(subghz->txrx->history);
} }
//Load history to receiver //Load history to receiver

View File

@ -161,7 +161,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
void subghz_scene_receiver_config_on_exit(void* context) { void subghz_scene_receiver_config_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
variable_item_list_clean(subghz->variable_item_list); variable_item_list_reset(subghz->variable_item_list);
scene_manager_set_scene_state( scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
} }

View File

@ -91,7 +91,7 @@ void subghz_scene_save_name_on_exit(void* context) {
text_input_set_validator(subghz->text_input, NULL, NULL); text_input_set_validator(subghz->text_input, NULL, NULL);
validator_is_file_free(validator_context); validator_is_file_free(validator_context);
text_input_clean(subghz->text_input); text_input_reset(subghz->text_input);
scene_manager_set_scene_state( scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
} }

View File

@ -67,5 +67,5 @@ bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
void subghz_scene_saved_menu_on_exit(void* context) { void subghz_scene_saved_menu_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
submenu_clean(subghz->submenu); submenu_reset(subghz->submenu);
} }

View File

@ -202,5 +202,5 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
void subghz_scene_set_type_on_exit(void* context) { void subghz_scene_set_type_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
submenu_clean(subghz->submenu); submenu_reset(subghz->submenu);
} }

View File

@ -97,5 +97,5 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
void subghz_scene_start_on_exit(void* context) { void subghz_scene_start_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
submenu_clean(subghz->submenu); submenu_reset(subghz->submenu);
} }

View File

@ -57,5 +57,5 @@ bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) {
void subghz_scene_test_on_exit(void* context) { void subghz_scene_test_on_exit(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
submenu_clean(subghz->submenu); submenu_reset(subghz->submenu);
} }

View File

@ -60,7 +60,7 @@ FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t
return instance->history[idx].preset; return instance->history[idx].preset;
} }
void subghz_history_clean(SubGhzHistory* instance) { void subghz_history_reset(SubGhzHistory* instance) {
furi_assert(instance); furi_assert(instance);
instance->last_index_write = 0; instance->last_index_write = 0;
instance->code_last_found = 0; instance->code_last_found = 0;
@ -168,4 +168,4 @@ bool subghz_history_add_to_history(
instance->last_index_write++; instance->last_index_write++;
return true; return true;
} }

View File

@ -21,7 +21,7 @@ void subghz_history_free(SubGhzHistory* instance);
* *
* @param instance - SubGhzHistory instance * @param instance - SubGhzHistory instance
*/ */
void subghz_history_clean(SubGhzHistory* instance); void subghz_history_reset(SubGhzHistory* instance);
/** Set frequency and preset to history[idx] /** Set frequency and preset to history[idx]
* *

46
firmware/targets/f6/ble_glue/gap.c Normal file → Executable file
View File

@ -94,9 +94,17 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
case EVT_LE_META_EVENT: case EVT_LE_META_EVENT:
meta_evt = (evt_le_meta_event*)event_pckt->data; meta_evt = (evt_le_meta_event*)event_pckt->data;
switch(meta_evt->subevent) { switch(meta_evt->subevent) {
case EVT_LE_CONN_UPDATE_COMPLETE: case EVT_LE_CONN_UPDATE_COMPLETE: {
FURI_LOG_D(TAG, "Connection update event"); 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);
break; break;
}
case EVT_LE_PHY_UPDATE_COMPLETE: case EVT_LE_PHY_UPDATE_COMPLETE:
evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data;
@ -129,6 +137,15 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
// Update connection status and handle // Update connection status and handle
gap->state = GapStateConnected; gap->state = GapStateConnected;
gap->service.connection_handle = connection_complete_event->Connection_Handle; 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");
}
// Start pairing by sending security request // Start pairing by sending security request
aci_gap_slave_security_req(connection_complete_event->Connection_Handle); aci_gap_slave_security_req(connection_complete_event->Connection_Handle);
@ -184,28 +201,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
} break; } break;
case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: case EVT_BLUE_GAP_AUTHORIZATION_REQUEST:
FURI_LOG_I(TAG, "Authorization request event"); FURI_LOG_D(TAG, "Authorization request event");
break; break;
case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED:
FURI_LOG_I(TAG, "Slave security initiated"); FURI_LOG_D(TAG, "Slave security initiated");
break; break;
case EVT_BLUE_GAP_BOND_LOST: case EVT_BLUE_GAP_BOND_LOST:
FURI_LOG_I(TAG, "Bond lost event. Start rebonding"); FURI_LOG_D(TAG, "Bond lost event. Start rebonding");
aci_gap_allow_rebond(gap->service.connection_handle); aci_gap_allow_rebond(gap->service.connection_handle);
break; break;
case EVT_BLUE_GAP_DEVICE_FOUND: case EVT_BLUE_GAP_DEVICE_FOUND:
FURI_LOG_I(TAG, "Device found event"); FURI_LOG_D(TAG, "Device found event");
break; break;
case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: case EVT_BLUE_GAP_ADDR_NOT_RESOLVED:
FURI_LOG_I(TAG, "Address not resolved event"); FURI_LOG_D(TAG, "Address not resolved event");
break; break;
case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION:
FURI_LOG_I(TAG, "Key press notification event"); FURI_LOG_D(TAG, "Key press notification event");
break; break;
case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: { case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: {
@ -234,8 +251,19 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
break; break;
case EVT_BLUE_GAP_PROCEDURE_COMPLETE: case EVT_BLUE_GAP_PROCEDURE_COMPLETE:
FURI_LOG_I(TAG, "Procedure complete event"); FURI_LOG_D(TAG, "Procedure complete event");
break; break;
case EVT_BLUE_L2CAP_CONNECTION_UPDATE_RESP: {
uint16_t result =
((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result;
if(result == 0) {
FURI_LOG_D(TAG, "Connection parameters accepted");
} else if(result == 1) {
FURI_LOG_D(TAG, "Connection parameters denied");
}
break;
}
} }
default: default:
break; break;

View File

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

25
firmware/targets/f6/furi_hal/furi_hal_bt.c Normal file → Executable file
View File

@ -42,6 +42,13 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = {
.bonding_mode = true, .bonding_mode = true,
.pairing_method = GapPairingPinCodeShow, .pairing_method = GapPairingPinCodeShow,
.mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR,
.conn_param =
{
.conn_int_min = 0x08,
.conn_int_max = 0x18,
.slave_latency = 0,
.supervisor_timeout = 50,
},
}, },
}, },
[FuriHalBtProfileHidKeyboard] = [FuriHalBtProfileHidKeyboard] =
@ -55,6 +62,14 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = {
.bonding_mode = true, .bonding_mode = true,
.pairing_method = GapPairingPinCodeVerifyYesNo, .pairing_method = GapPairingPinCodeVerifyYesNo,
.mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR,
// TODO optimize
.conn_param =
{
.conn_int_min = 0x12,
.conn_int_max = 0x1e,
.slave_latency = 6,
.supervisor_timeout = 700,
},
}, },
}, },
}; };
@ -277,6 +292,16 @@ void furi_hal_bt_nvm_sram_sem_release() {
HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0);
} }
bool furi_hal_bt_clear_white_list() {
furi_hal_bt_nvm_sram_sem_acquire();
tBleStatus status = aci_gap_clear_security_db();
if(status) {
FURI_LOG_E(TAG, "Clear while list failed with status %d", status);
}
furi_hal_bt_nvm_sram_sem_release();
return status != BLE_STATUS_SUCCESS;
}
void furi_hal_bt_dump_state(string_t buffer) { void furi_hal_bt_dump_state(string_t buffer) {
if(furi_hal_bt_is_alive()) { if(furi_hal_bt_is_alive()) {
uint8_t HCI_Version; uint8_t HCI_Version;

View File

@ -112,6 +112,7 @@ C_SOURCES += \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \

46
firmware/targets/f7/ble_glue/gap.c Normal file → Executable file
View File

@ -94,9 +94,17 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
case EVT_LE_META_EVENT: case EVT_LE_META_EVENT:
meta_evt = (evt_le_meta_event*)event_pckt->data; meta_evt = (evt_le_meta_event*)event_pckt->data;
switch(meta_evt->subevent) { switch(meta_evt->subevent) {
case EVT_LE_CONN_UPDATE_COMPLETE: case EVT_LE_CONN_UPDATE_COMPLETE: {
FURI_LOG_D(TAG, "Connection update event"); 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);
break; break;
}
case EVT_LE_PHY_UPDATE_COMPLETE: case EVT_LE_PHY_UPDATE_COMPLETE:
evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data;
@ -129,6 +137,15 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
// Update connection status and handle // Update connection status and handle
gap->state = GapStateConnected; gap->state = GapStateConnected;
gap->service.connection_handle = connection_complete_event->Connection_Handle; 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");
}
// Start pairing by sending security request // Start pairing by sending security request
aci_gap_slave_security_req(connection_complete_event->Connection_Handle); aci_gap_slave_security_req(connection_complete_event->Connection_Handle);
@ -184,28 +201,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
} break; } break;
case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: case EVT_BLUE_GAP_AUTHORIZATION_REQUEST:
FURI_LOG_I(TAG, "Authorization request event"); FURI_LOG_D(TAG, "Authorization request event");
break; break;
case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED:
FURI_LOG_I(TAG, "Slave security initiated"); FURI_LOG_D(TAG, "Slave security initiated");
break; break;
case EVT_BLUE_GAP_BOND_LOST: case EVT_BLUE_GAP_BOND_LOST:
FURI_LOG_I(TAG, "Bond lost event. Start rebonding"); FURI_LOG_D(TAG, "Bond lost event. Start rebonding");
aci_gap_allow_rebond(gap->service.connection_handle); aci_gap_allow_rebond(gap->service.connection_handle);
break; break;
case EVT_BLUE_GAP_DEVICE_FOUND: case EVT_BLUE_GAP_DEVICE_FOUND:
FURI_LOG_I(TAG, "Device found event"); FURI_LOG_D(TAG, "Device found event");
break; break;
case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: case EVT_BLUE_GAP_ADDR_NOT_RESOLVED:
FURI_LOG_I(TAG, "Address not resolved event"); FURI_LOG_D(TAG, "Address not resolved event");
break; break;
case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION:
FURI_LOG_I(TAG, "Key press notification event"); FURI_LOG_D(TAG, "Key press notification event");
break; break;
case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: { case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: {
@ -234,8 +251,19 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
break; break;
case EVT_BLUE_GAP_PROCEDURE_COMPLETE: case EVT_BLUE_GAP_PROCEDURE_COMPLETE:
FURI_LOG_I(TAG, "Procedure complete event"); FURI_LOG_D(TAG, "Procedure complete event");
break; break;
case EVT_BLUE_L2CAP_CONNECTION_UPDATE_RESP: {
uint16_t result =
((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result;
if(result == 0) {
FURI_LOG_D(TAG, "Connection parameters accepted");
} else if(result == 1) {
FURI_LOG_D(TAG, "Connection parameters denied");
}
break;
}
} }
default: default:
break; break;

View File

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

25
firmware/targets/f7/furi_hal/furi_hal_bt.c Normal file → Executable file
View File

@ -42,6 +42,13 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = {
.bonding_mode = true, .bonding_mode = true,
.pairing_method = GapPairingPinCodeShow, .pairing_method = GapPairingPinCodeShow,
.mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR,
.conn_param =
{
.conn_int_min = 0x08,
.conn_int_max = 0x18,
.slave_latency = 0,
.supervisor_timeout = 50,
},
}, },
}, },
[FuriHalBtProfileHidKeyboard] = [FuriHalBtProfileHidKeyboard] =
@ -55,6 +62,14 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = {
.bonding_mode = true, .bonding_mode = true,
.pairing_method = GapPairingPinCodeVerifyYesNo, .pairing_method = GapPairingPinCodeVerifyYesNo,
.mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR,
// TODO optimize
.conn_param =
{
.conn_int_min = 0x12,
.conn_int_max = 0x1e,
.slave_latency = 6,
.supervisor_timeout = 700,
},
}, },
}, },
}; };
@ -277,6 +292,16 @@ void furi_hal_bt_nvm_sram_sem_release() {
HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0);
} }
bool furi_hal_bt_clear_white_list() {
furi_hal_bt_nvm_sram_sem_acquire();
tBleStatus status = aci_gap_clear_security_db();
if(status) {
FURI_LOG_E(TAG, "Clear while list failed with status %d", status);
}
furi_hal_bt_nvm_sram_sem_release();
return status != BLE_STATUS_SUCCESS;
}
void furi_hal_bt_dump_state(string_t buffer) { void furi_hal_bt_dump_state(string_t buffer) {
if(furi_hal_bt_is_alive()) { if(furi_hal_bt_is_alive()) {
uint8_t HCI_Version; uint8_t HCI_Version;

View File

@ -112,6 +112,7 @@ C_SOURCES += \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \
$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \

View File

@ -121,6 +121,12 @@ void furi_hal_bt_nvm_sram_sem_acquire();
*/ */
void furi_hal_bt_nvm_sram_sem_release(); void furi_hal_bt_nvm_sram_sem_release();
/** Clear key storage
*
* @return true on success
*/
bool furi_hal_bt_clear_white_list();
/** Set key storage change callback /** Set key storage change callback
* *
* @param callback BleGlueKeyStorageChangedCallback instance * @param callback BleGlueKeyStorageChangedCallback instance

View File

@ -13,7 +13,7 @@ View* SubmenuVM::get_view() {
} }
void SubmenuVM::clean() { void SubmenuVM::clean() {
submenu_clean(submenu); submenu_reset(submenu);
} }
void SubmenuVM::add_item( void SubmenuVM::add_item(

View File

@ -13,7 +13,7 @@ View* TextInputVM::get_view() {
} }
void TextInputVM::clean() { void TextInputVM::clean() {
text_input_clean(text_input); text_input_reset(text_input);
} }
void TextInputVM::set_result_callback( void TextInputVM::set_result_callback(