diff --git a/applications/ReadMe.md b/applications/ReadMe.md index 3bd2aeb06..efc9afd86 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -25,7 +25,7 @@ Applications for factory testing the Flipper. Applications for main Flipper menu. - `archive` - Archive and file manager -- `bad_usb` - Bad USB application +- `bad_kb` - Bad KB application - `fap_loader` - External applications loader - `gpio` - GPIO application: includes USART bridge and GPIO control - `ibutton` - iButton application, onewire keys and more diff --git a/applications/debug/file_browser_test/file_browser_app.c b/applications/debug/file_browser_test/file_browser_app.c index c3e7c898b..60ddf1b68 100644 --- a/applications/debug/file_browser_test/file_browser_app.c +++ b/applications/debug/file_browser_test/file_browser_app.c @@ -49,7 +49,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) { app->file_path = furi_string_alloc(); app->file_browser = file_browser_alloc(app->file_path); - file_browser_configure(app->file_browser, "*", NULL, true, false, &I_badusb_10px, true); + file_browser_configure(app->file_browser, "*", NULL, true, false, &I_badkb_10px, true); view_dispatcher_add_view( app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget)); diff --git a/applications/debug/file_browser_test/icons/badusb_10px.png b/applications/debug/file_browser_test/icons/badkb_10px.png similarity index 100% rename from applications/debug/file_browser_test/icons/badusb_10px.png rename to applications/debug/file_browser_test/icons/badkb_10px.png diff --git a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c index 9eb26944f..9211ff3bb 100644 --- a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c +++ b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c @@ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - furi_string_set(app->file_path, ANY_PATH("badusb/demo_windows.txt")); + furi_string_set(app->file_path, ANY_PATH("badkb/demo_windows.txt")); scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser); consumed = true; } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/main/application.fam b/applications/main/application.fam index 9820ee3ac..eefb801b3 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -9,7 +9,7 @@ App( "lfrfid", "nfc", "subghz", - "bad_usb", + "bad_kb", "u2f", "fap_loader", "sub_playlist", @@ -30,7 +30,7 @@ App( "lfrfid", "nfc", "subghz", - # "bad_usb", + # "bad_kb", # "u2f", "fap_loader", "archive", diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 43a9a651a..36da022da 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -14,7 +14,7 @@ static const char* tab_default_paths[] = { [ArchiveTabSubGhz] = ANY_PATH("subghz"), [ArchiveTabLFRFID] = ANY_PATH("lfrfid"), [ArchiveTabInfrared] = ANY_PATH("infrared"), - [ArchiveTabBadUsb] = ANY_PATH("badusb"), + [ArchiveTabBadKb] = ANY_PATH("badkb"), [ArchiveTabU2f] = "/app:u2f", [ArchiveTabApplications] = ANY_PATH("apps"), [ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX, @@ -27,7 +27,7 @@ static const char* known_ext[] = { [ArchiveFileTypeSubGhz] = ".sub", [ArchiveFileTypeLFRFID] = ".rfid", [ArchiveFileTypeInfrared] = ".ir", - [ArchiveFileTypeBadUsb] = ".txt", + [ArchiveFileTypeBadKb] = ".txt", [ArchiveFileTypeU2f] = "?", [ArchiveFileTypeApplication] = ".fap", [ArchiveFileTypeUpdateManifest] = ".fuf", @@ -42,7 +42,7 @@ static const ArchiveFileTypeEnum known_type[] = { [ArchiveTabSubGhz] = ArchiveFileTypeSubGhz, [ArchiveTabLFRFID] = ArchiveFileTypeLFRFID, [ArchiveTabInfrared] = ArchiveFileTypeInfrared, - [ArchiveTabBadUsb] = ArchiveFileTypeBadUsb, + [ArchiveTabBadKb] = ArchiveFileTypeBadKb, [ArchiveTabU2f] = ArchiveFileTypeU2f, [ArchiveTabApplications] = ArchiveFileTypeApplication, [ArchiveTabInternal] = ArchiveFileTypeUnknown, diff --git a/applications/main/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c index 5c06c1bda..83eb2a845 100644 --- a/applications/main/archive/helpers/archive_files.c +++ b/applications/main/archive/helpers/archive_files.c @@ -16,11 +16,11 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder for(size_t i = 0; i < COUNT_OF(known_ext); i++) { if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue; if(furi_string_search(file->path, known_ext[i], 0) != FURI_STRING_FAILURE) { - if(i == ArchiveFileTypeBadUsb) { - if(furi_string_search( - file->path, archive_get_default_path(ArchiveTabBadUsb)) == 0) { + if(i == ArchiveFileTypeBadKb) { + if(furi_string_search(file->path, archive_get_default_path(ArchiveTabBadKb)) == + 0) { file->type = i; - return; // *.txt file is a BadUSB script only if it is in BadUSB folder + return; // *.txt file is a BadKB script only if it is in BadKB folder } } else { file->type = i; diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index d84f7088a..863a8e7da 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -15,7 +15,7 @@ typedef enum { ArchiveFileTypeSubGhz, ArchiveFileTypeLFRFID, ArchiveFileTypeInfrared, - ArchiveFileTypeBadUsb, + ArchiveFileTypeBadKb, ArchiveFileTypeU2f, ArchiveFileTypeApplication, ArchiveFileTypeUpdateManifest, diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index f88efb0c4..0696647ea 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -17,7 +17,7 @@ static const char* flipper_app_name[] = { [ArchiveFileTypeSubGhz] = "Sub-GHz", [ArchiveFileTypeLFRFID] = "125 kHz RFID", [ArchiveFileTypeInfrared] = "Infrared", - [ArchiveFileTypeBadUsb] = "Bad USB", + [ArchiveFileTypeBadKb] = "Bad KB", [ArchiveFileTypeU2f] = "U2F", [ArchiveFileTypeApplication] = "Applications", [ArchiveFileTypeUpdateManifest] = "UpdaterApp", diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 26ed17d75..9351f687b 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -16,7 +16,7 @@ static const char* ArchiveTabNames[] = { [ArchiveTabSubGhz] = "Sub-GHz", [ArchiveTabLFRFID] = "RFID LF", [ArchiveTabInfrared] = "Infrared", - [ArchiveTabBadUsb] = "Bad USB", + [ArchiveTabBadKb] = "Bad KB", [ArchiveTabU2f] = "U2F", [ArchiveTabApplications] = "Apps", [ArchiveTabInternal] = "Internal", @@ -29,7 +29,7 @@ static const Icon* ArchiveItemIcons[] = { [ArchiveFileTypeSubGhz] = &I_sub1_10px, [ArchiveFileTypeLFRFID] = &I_125_10px, [ArchiveFileTypeInfrared] = &I_ir_10px, - [ArchiveFileTypeBadUsb] = &I_badusb_10px, + [ArchiveFileTypeBadKb] = &I_badkb_10px, [ArchiveFileTypeU2f] = &I_u2f_10px, [ArchiveFileTypeApplication] = &I_Apps_10px, [ArchiveFileTypeUpdateManifest] = &I_update_10px, @@ -110,7 +110,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { menu_array_push_raw(model->context_menu), item_pin, ArchiveBrowserEventFileMenuPin); - if(selected->type <= ArchiveFileTypeBadUsb) { + if(selected->type <= ArchiveFileTypeBadKb) { archive_menu_add_item( menu_array_push_raw(model->context_menu), item_show, @@ -130,7 +130,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { menu_array_push_raw(model->context_menu), item_info, ArchiveBrowserEventFileMenuInfo); - if(selected->type <= ArchiveFileTypeBadUsb) { + if(selected->type <= ArchiveFileTypeBadKb) { archive_menu_add_item( menu_array_push_raw(model->context_menu), item_show, @@ -158,7 +158,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { menu_array_push_raw(model->context_menu), item_info, ArchiveBrowserEventFileMenuInfo); - if(selected->type <= ArchiveFileTypeBadUsb) { + if(selected->type <= ArchiveFileTypeBadKb) { archive_menu_add_item( menu_array_push_raw(model->context_menu), item_show, @@ -589,4 +589,4 @@ void browser_free(ArchiveBrowserView* browser) { view_free(browser->view); free(browser); -} \ No newline at end of file +} diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index 6e6582405..1ce35cb53 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -28,7 +28,7 @@ typedef enum { ArchiveTabNFC, ArchiveTabInfrared, ArchiveTabIButton, - ArchiveTabBadUsb, + ArchiveTabBadKb, ArchiveTabU2f, ArchiveTabApplications, ArchiveTabInternal, diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_kb/application.fam similarity index 55% rename from applications/main/bad_usb/application.fam rename to applications/main/bad_kb/application.fam index 2442dd3aa..09531da81 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_kb/application.fam @@ -1,15 +1,15 @@ App( - appid="bad_usb", - name="Bad USB", + appid="bad_kb", + name="Bad KB", apptype=FlipperAppType.APP, - entry_point="bad_usb_app", - cdefines=["APP_BAD_USB"], + entry_point="bad_kb_app", + cdefines=["APP_BAD_KB"], requires=[ "gui", "dialogs", ], stack_size=2 * 1024, - icon="A_BadUsb_14", + icon="A_BadKb_14", order=70, fap_libs=["assets"], ) diff --git a/applications/main/bad_kb/bad_kb_app.c b/applications/main/bad_kb/bad_kb_app.c new file mode 100644 index 000000000..0a47b7492 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_app.c @@ -0,0 +1,221 @@ +#include "bad_kb_app_i.h" +#include "bad_kb_settings_filename.h" +#include +#include +#include +#include + +#include +#include + +#define BAD_KB_SETTINGS_PATH BAD_KB_APP_BASE_FOLDER "/" BAD_KB_SETTINGS_FILE_NAME + +static bool bad_kb_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + BadKbApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool bad_kb_app_back_event_callback(void* context) { + furi_assert(context); + BadKbApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void bad_kb_app_tick_event_callback(void* context) { + furi_assert(context); + BadKbApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +static void bad_kb_load_settings(BadKbApp* app) { + File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(storage_file_open(settings_file, BAD_KB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + char chr; + while((storage_file_read(settings_file, &chr, 1) == 1) && + !storage_file_eof(settings_file) && !isspace(chr)) { + furi_string_push_back(app->keyboard_layout, chr); + } + } + storage_file_close(settings_file); + storage_file_free(settings_file); +} + +static void bad_kb_save_settings(BadKbApp* app) { + File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(storage_file_open(settings_file, BAD_KB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { + storage_file_write( + settings_file, + furi_string_get_cstr(app->keyboard_layout), + furi_string_size(app->keyboard_layout)); + storage_file_write(settings_file, "\n", 1); + } + storage_file_close(settings_file); + storage_file_free(settings_file); +} + +void bad_kb_set_name(BadKbApp* app, const char* fmt, ...) { + furi_assert(app); + + va_list args; + va_start(args, fmt); + + vsnprintf(app->name, BAD_KB_ADV_NAME_MAX_LEN, fmt, args); + + va_end(args); +} + +BadKbApp* bad_kb_app_alloc(char* arg) { + BadKbApp* app = malloc(sizeof(BadKbApp)); + + app->bad_kb_script = NULL; + + app->file_path = furi_string_alloc(); + app->keyboard_layout = furi_string_alloc(); + if(arg && strlen(arg)) { + furi_string_set(app->file_path, arg); + } + + bad_kb_load_settings(app); + + app->gui = furi_record_open(RECORD_GUI); + app->notifications = furi_record_open(RECORD_NOTIFICATION); + app->dialogs = furi_record_open(RECORD_DIALOGS); + + app->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(app->view_dispatcher); + + app->scene_manager = scene_manager_alloc(&bad_kb_scene_handlers, app); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, bad_kb_app_tick_event_callback, 500); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, bad_kb_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, bad_kb_app_back_event_callback); + + Bt* bt = furi_record_open(RECORD_BT); + app->bt = bt; + const char* adv_name = bt_get_profile_adv_name(bt); + memcpy(app->name, adv_name, BAD_KB_ADV_NAME_MAX_LEN); + memcpy(app->bt_old_config.name, adv_name, BAD_KB_ADV_NAME_MAX_LEN); + + const uint8_t* mac_addr = bt_get_profile_mac_address(bt); + memcpy(app->mac, mac_addr, BAD_KB_MAC_ADDRESS_LEN); + memcpy(app->bt_old_config.mac, mac_addr, BAD_KB_MAC_ADDRESS_LEN); + + // Custom Widget + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewError, widget_get_view(app->widget)); + + app->var_item_list_bt = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + BadKbAppViewConfigBt, + variable_item_list_get_view(app->var_item_list_bt)); + app->var_item_list_usb = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + BadKbAppViewConfigUsb, + variable_item_list_get_view(app->var_item_list_usb)); + + app->bad_kb_view = bad_kb_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewWork, bad_kb_get_view(app->bad_kb_view)); + + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewConfigName, text_input_get_view(app->text_input)); + + app->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewConfigMac, byte_input_get_view(app->byte_input)); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + if(furi_hal_usb_is_locked()) { + app->error = BadKbAppErrorCloseRpc; + scene_manager_next_scene(app->scene_manager, BadKbSceneError); + } else { + if(!furi_string_empty(app->file_path)) { + app->bad_kb_script = bad_kb_script_open(app->file_path, app->is_bt ? app->bt : NULL); + bad_kb_script_set_keyboard_layout(app->bad_kb_script, app->keyboard_layout); + scene_manager_next_scene(app->scene_manager, BadKbSceneWork); + } else { + furi_string_set(app->file_path, BAD_KB_APP_BASE_FOLDER); + scene_manager_next_scene(app->scene_manager, BadKbSceneFileSelect); + } + } + + return app; +} + +void bad_kb_app_free(BadKbApp* app) { + furi_assert(app); + + if(app->bad_kb_script) { + bad_kb_script_close(app->bad_kb_script); + app->bad_kb_script = NULL; + } + + // Views + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewWork); + bad_kb_free(app->bad_kb_view); + + // Custom Widget + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewError); + widget_free(app->widget); + + // Variable item list + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigBt); + variable_item_list_free(app->var_item_list_bt); + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigUsb); + variable_item_list_free(app->var_item_list_usb); + + // Text Input + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigName); + text_input_free(app->text_input); + + // Byte Input + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigMac); + byte_input_free(app->byte_input); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + // restores bt config + // BtProfile have already been switched to the previous one + // so we directly modify the right profile + bad_kb_connection_deinit(app->bt); + if(strcmp(app->bt_old_config.name, app->name) != 0) { + furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, app->bt_old_config.name); + } + if(memcmp(app->bt_old_config.mac, app->mac, BAD_KB_MAC_ADDRESS_LEN) != 0) { + furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->bt_old_config.mac); + } + + // Close records + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_BT); + + bad_kb_save_settings(app); + + furi_string_free(app->file_path); + furi_string_free(app->keyboard_layout); + + free(app); +} + +int32_t bad_kb_app(void* p) { + BadKbApp* bad_kb_app = bad_kb_app_alloc((char*)p); + + view_dispatcher_run(bad_kb_app->view_dispatcher); + + bad_kb_app_free(bad_kb_app); + return 0; +} diff --git a/applications/main/bad_kb/bad_kb_app.h b/applications/main/bad_kb/bad_kb_app.h new file mode 100644 index 000000000..e75a94651 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_app.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BadKbApp BadKbApp; + +void bad_kb_set_name(BadKbApp* app, const char* fmt, ...); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/bad_kb/bad_kb_app_i.h b/applications/main/bad_kb/bad_kb_app_i.h new file mode 100644 index 000000000..913830e72 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_app_i.h @@ -0,0 +1,80 @@ +#pragma once + +#include "bad_kb_app.h" +#include "scenes/bad_kb_scene.h" +#include "bad_kb_script.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "views/bad_kb_view.h" + +#define BAD_KB_APP_BASE_FOLDER ANY_PATH("badkb") +#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/layouts" +#define BAD_KB_APP_SCRIPT_EXTENSION ".txt" +#define BAD_KB_APP_LAYOUT_EXTENSION ".kl" + +#define BAD_KB_MAC_ADDRESS_LEN 6 // need replace with MAC size maccro +#define BAD_KB_ADV_NAME_MAX_LEN 18 + +typedef enum { + BadKbAppErrorNoFiles, + BadKbAppErrorCloseRpc, +} BadKbAppError; + +typedef enum BadKbCustomEvent { + BadKbAppCustomEventTextEditResult, + BadKbAppCustomEventByteInputDone, + BadKbCustomEventErrorBack +} BadKbCustomEvent; + +typedef struct { + uint8_t mac[BAD_KB_MAC_ADDRESS_LEN]; + char name[BAD_KB_ADV_NAME_MAX_LEN + 1]; + + // number of bt keys before starting the app (all keys added in + // the bt keys file then will be removed) + uint16_t n_keys; +} BadKbBtConfig; + +struct BadKbApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + DialogsApp* dialogs; + Widget* widget; + VariableItemList* var_item_list_bt; + VariableItemList* var_item_list_usb; + + Bt* bt; + TextInput* text_input; + ByteInput* byte_input; + uint8_t mac[BAD_KB_MAC_ADDRESS_LEN]; + char name[BAD_KB_ADV_NAME_MAX_LEN + 1]; + BadKbBtConfig bt_old_config; + + BadKbAppError error; + FuriString* file_path; + FuriString* keyboard_layout; + BadKb* bad_kb_view; + BadKbScript* bad_kb_script; + + bool is_bt; +}; + +typedef enum { + BadKbAppViewError, + BadKbAppViewWork, + BadKbAppViewConfigBt, + BadKbAppViewConfigUsb, + BadKbAppViewConfigMac, + BadKbAppViewConfigName +} BadKbAppView; diff --git a/applications/main/bad_kb/bad_kb_script.c b/applications/main/bad_kb/bad_kb_script.c new file mode 100644 index 000000000..98177209e --- /dev/null +++ b/applications/main/bad_kb/bad_kb_script.c @@ -0,0 +1,978 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bad_kb_script.h" +#include + +#include + +#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("apps/Tools/.bt_hid.keys") + +#define TAG "BadKB" +#define WORKER_TAG TAG "Worker" +#define FILE_BUFFER_LEN 16 + +#define SCRIPT_STATE_ERROR (-1) +#define SCRIPT_STATE_END (-2) +#define SCRIPT_STATE_NEXT_LINE (-3) + +#define BADKB_ASCII_TO_KEY(script, x) \ + (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) + +typedef enum { + WorkerEvtToggle = (1 << 0), + WorkerEvtEnd = (1 << 1), + WorkerEvtConnect = (1 << 2), + WorkerEvtDisconnect = (1 << 3), +} WorkerEvtFlags; + +typedef enum { + LevelRssi122_100, + LevelRssi99_80, + LevelRssi79_60, + LevelRssi59_40, + LevelRssi39_0, + LevelRssiNum, + LevelRssiError = 0xFF, +} LevelRssiRange; + +typedef enum { + BadKbConnectionModeNone, + BadKbConnectionModeUsb, + BadKbConnectionModeBt, +} BadKbConnectionMode; + +/** + * Delays for waiting between HID key press and key release +*/ +const uint8_t bt_hid_delays[LevelRssiNum] = { + 30, // LevelRssi122_100 + 25, // LevelRssi99_80 + 20, // LevelRssi79_60 + 17, // LevelRssi59_40 + 14, // LevelRssi39_0 +}; + +struct BadKbScript { + FuriHalUsbHidConfig hid_cfg; + BadKbState st; + FuriString* file_path; + FuriString* keyboard_layout; + uint32_t defdelay; + uint16_t layout[128]; + FuriThread* thread; + uint8_t file_buf[FILE_BUFFER_LEN + 1]; + uint8_t buf_start; + uint8_t buf_len; + bool file_end; + FuriString* line; + + FuriString* line_prev; + uint32_t repeat_cnt; + + Bt* bt; +}; + +typedef struct { + char* name; + uint16_t keycode; +} DuckyKey; + +static const DuckyKey ducky_keys[] = { + {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, + {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, + {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, + {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, + {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, + {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, + + {"CTRL", KEY_MOD_LEFT_CTRL}, + {"CONTROL", KEY_MOD_LEFT_CTRL}, + {"SHIFT", KEY_MOD_LEFT_SHIFT}, + {"ALT", KEY_MOD_LEFT_ALT}, + {"GUI", KEY_MOD_LEFT_GUI}, + {"WINDOWS", KEY_MOD_LEFT_GUI}, + + {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, + {"DOWN", HID_KEYBOARD_DOWN_ARROW}, + {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, + {"LEFT", HID_KEYBOARD_LEFT_ARROW}, + {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, + {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, + {"UPARROW", HID_KEYBOARD_UP_ARROW}, + {"UP", HID_KEYBOARD_UP_ARROW}, + + {"ENTER", HID_KEYBOARD_RETURN}, + {"BREAK", HID_KEYBOARD_PAUSE}, + {"PAUSE", HID_KEYBOARD_PAUSE}, + {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, + {"DELETE", HID_KEYBOARD_DELETE}, + {"BACKSPACE", HID_KEYPAD_BACKSPACE}, + {"END", HID_KEYBOARD_END}, + {"ESC", HID_KEYBOARD_ESCAPE}, + {"ESCAPE", HID_KEYBOARD_ESCAPE}, + {"HOME", HID_KEYBOARD_HOME}, + {"INSERT", HID_KEYBOARD_INSERT}, + {"NUMLOCK", HID_KEYPAD_NUMLOCK}, + {"PAGEUP", HID_KEYBOARD_PAGE_UP}, + {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, + {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, + {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, + {"SPACE", HID_KEYBOARD_SPACEBAR}, + {"TAB", HID_KEYBOARD_TAB}, + {"MENU", HID_KEYBOARD_APPLICATION}, + {"APP", HID_KEYBOARD_APPLICATION}, + + {"F1", HID_KEYBOARD_F1}, + {"F2", HID_KEYBOARD_F2}, + {"F3", HID_KEYBOARD_F3}, + {"F4", HID_KEYBOARD_F4}, + {"F5", HID_KEYBOARD_F5}, + {"F6", HID_KEYBOARD_F6}, + {"F7", HID_KEYBOARD_F7}, + {"F8", HID_KEYBOARD_F8}, + {"F9", HID_KEYBOARD_F9}, + {"F10", HID_KEYBOARD_F10}, + {"F11", HID_KEYBOARD_F11}, + {"F12", HID_KEYBOARD_F12}, +}; + +static const char ducky_cmd_comment[] = {"REM"}; +static const char ducky_cmd_id[] = {"ID"}; +static const char ducky_cmd_delay[] = {"DELAY "}; +static const char ducky_cmd_string[] = {"STRING "}; +static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; +static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; +static const char ducky_cmd_repeat[] = {"REPEAT "}; +static const char ducky_cmd_sysrq[] = {"SYSRQ "}; + +static const char ducky_cmd_altchar[] = {"ALTCHAR "}; +static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; +static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; + +static const char ducky_cmd_lang[] = {"DUCKY_LANG"}; + +static const uint8_t numpad_keys[10] = { + HID_KEYPAD_0, + HID_KEYPAD_1, + HID_KEYPAD_2, + HID_KEYPAD_3, + HID_KEYPAD_4, + HID_KEYPAD_5, + HID_KEYPAD_6, + HID_KEYPAD_7, + HID_KEYPAD_8, + HID_KEYPAD_9, +}; + +BadKbConnectionMode connection_mode = BadKbConnectionModeNone; +FuriHalUsbInterface* usb_mode_prev = NULL; +GapPairing bt_mode_prev = GapPairingNone; +bool bt_connected = false; +bool usb_connected = false; +uint8_t bt_timeout = 0; + +static LevelRssiRange bt_remote_rssi_range(Bt* bt) { + BtRssi rssi_data = {0}; + + if(!bt_remote_rssi(bt, &rssi_data)) return LevelRssiError; + + if(rssi_data.rssi <= 39) + return LevelRssi39_0; + else if(rssi_data.rssi <= 59) + return LevelRssi59_40; + else if(rssi_data.rssi <= 79) + return LevelRssi79_60; + else if(rssi_data.rssi <= 99) + return LevelRssi99_80; + else if(rssi_data.rssi <= 122) + return LevelRssi122_100; + + return LevelRssiError; +} + +static inline void update_bt_timeout(Bt* bt) { + LevelRssiRange r = bt_remote_rssi_range(bt); + if(r < LevelRssiNum) { + bt_timeout = bt_hid_delays[r]; + FURI_LOG_D(WORKER_TAG, "BLE Key timeout : %u", bt_timeout); + } +} + +static bool ducky_get_number(const char* param, uint32_t* val) { + uint32_t value = 0; + if(sscanf(param, "%lu", &value) == 1) { + *val = value; + return true; + } + return false; +} + +static uint32_t ducky_get_command_len(const char* line) { + uint32_t len = strlen(line); + for(uint32_t i = 0; i < len; i++) { + if(line[i] == ' ') return i; + } + return 0; +} + +static bool ducky_is_line_end(const char chr) { + return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n')); +} + +static void ducky_numlock_on(BadKbScript* bad_kb) { + if(bad_kb->bt) { + if((furi_hal_bt_hid_get_led_state() & HID_KB_LED_NUM) == 0) { // FIXME + furi_hal_bt_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); + } + } else { + if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { + furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); + furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); + } + } +} + +static bool ducky_numpad_press(BadKbScript* bad_kb, const char num) { + if((num < '0') || (num > '9')) return false; + + uint16_t key = numpad_keys[num - '0']; + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(key); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(key); + } else { + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release(key); + } + + return true; +} + +static bool ducky_altchar(BadKbScript* bad_kb, const char* charcode) { + uint8_t i = 0; + bool state = false; + + FURI_LOG_I(WORKER_TAG, "char %s", charcode); + + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT); + } else { + furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); + } + + while(!ducky_is_line_end(charcode[i])) { + state = ducky_numpad_press(bad_kb, charcode[i]); + if(state == false) break; + i++; + } + + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT); + } else { + furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); + } + return state; +} + +static bool ducky_altstring(BadKbScript* bad_kb, const char* param) { + uint32_t i = 0; + bool state = false; + + while(param[i] != '\0') { + if((param[i] < ' ') || (param[i] > '~')) { + i++; + continue; // Skip non-printable chars + } + + char temp_str[4]; + snprintf(temp_str, 4, "%u", param[i]); + + state = ducky_altchar(bad_kb, temp_str); + if(state == false) break; + i++; + } + return state; +} + +static bool ducky_string(BadKbScript* bad_kb, const char* param) { + uint32_t i = 0; + while(param[i] != '\0') { + uint16_t keycode = BADKB_ASCII_TO_KEY(bad_kb, param[i]); + if(keycode != HID_KEYBOARD_NONE) { + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(keycode); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(keycode); + } else { + furi_hal_hid_kb_press(keycode); + furi_hal_hid_kb_release(keycode); + } + } + i++; + } + return true; +} + +static uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_chars) { + for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { + size_t key_cmd_len = strlen(ducky_keys[i].name); + if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && + (ducky_is_line_end(param[key_cmd_len]))) { + return ducky_keys[i].keycode; + } + } + if((accept_chars) && (strlen(param) > 0)) { + return (BADKB_ASCII_TO_KEY(bad_kb, param[0]) & 0xFF); + } + return 0; +} + +static int32_t + ducky_parse_line(BadKbScript* bad_kb, FuriString* line, char* error, size_t error_len) { + uint32_t line_len = furi_string_size(line); + const char* line_tmp = furi_string_get_cstr(line); + bool state = false; + + if(line_len == 0) { + return SCRIPT_STATE_NEXT_LINE; // Skip empty lines + } + + FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); + + // General commands + if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) { + // REM - comment line + return (0); + } else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { + // ID - executed in ducky_script_preload + return (0); + } else if(strncmp(line_tmp, ducky_cmd_lang, strlen(ducky_cmd_lang)) == 0) { + // DUCKY_LANG - ignore command to retain compatibility with existing scripts + return (0); + } else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) { + // DELAY + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint32_t delay_val = 0; + state = ducky_get_number(line_tmp, &delay_val); + if((state) && (delay_val > 0)) { + return (int32_t)delay_val; + } + if(error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return SCRIPT_STATE_ERROR; + } else if( + (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) || + (strncmp(line_tmp, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) { + // DEFAULT_DELAY + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_get_number(line_tmp, &bad_kb->defdelay); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { + // STRING + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_string(bad_kb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid string %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { + // ALTCHAR + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + ducky_numlock_on(bad_kb); + state = ducky_altchar(bad_kb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid altchar %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if( + (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) || + (strncmp(line_tmp, ducky_cmd_altstr_2, strlen(ducky_cmd_altstr_2)) == 0)) { + // ALTSTRING + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + ducky_numlock_on(bad_kb); + state = ducky_altstring(bad_kb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid altstring %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { + // REPEAT + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_get_number(line_tmp, &bad_kb->repeat_cnt); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { + // SYSRQ + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint16_t key = ducky_get_keycode(bad_kb, line_tmp, true); + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + furi_hal_bt_hid_kb_press(key); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(key); + furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + } else { + furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release_all(); + } + return (0); + } else { + // Special keys + modifiers + uint16_t key = ducky_get_keycode(bad_kb, line_tmp, false); + if(key == HID_KEYBOARD_NONE) { + if(error != NULL) { + snprintf(error, error_len, "No keycode defined for %s", line_tmp); + } + return SCRIPT_STATE_ERROR; + } + if((key & 0xFF00) != 0) { + // It's a modifier key + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + key |= ducky_get_keycode(bad_kb, line_tmp, true); + } + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(key); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(key); + } else { + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release(key); + } + return (0); + } +} + +static bool ducky_set_usb_id(BadKbScript* bad_kb, const char* line) { + if(sscanf(line, "%lX:%lX", &bad_kb->hid_cfg.vid, &bad_kb->hid_cfg.pid) == 2) { + bad_kb->hid_cfg.manuf[0] = '\0'; + bad_kb->hid_cfg.product[0] = '\0'; + + uint8_t id_len = ducky_get_command_len(line); + if(!ducky_is_line_end(line[id_len + 1])) { + sscanf( + &line[id_len + 1], + "%31[^\r\n:]:%31[^\r\n]", + bad_kb->hid_cfg.manuf, + bad_kb->hid_cfg.product); + } + FURI_LOG_D( + WORKER_TAG, + "set id: %04lX:%04lX mfr:%s product:%s", + bad_kb->hid_cfg.vid, + bad_kb->hid_cfg.pid, + bad_kb->hid_cfg.manuf, + bad_kb->hid_cfg.product); + return true; + } + return false; +} + +static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { + uint8_t ret = 0; + uint32_t line_len = 0; + + furi_string_reset(bad_kb->line); + + do { + ret = storage_file_read(script_file, bad_kb->file_buf, FILE_BUFFER_LEN); + for(uint16_t i = 0; i < ret; i++) { + if(bad_kb->file_buf[i] == '\n' && line_len > 0) { + bad_kb->st.line_nb++; + line_len = 0; + } else { + if(bad_kb->st.line_nb == 0) { // Save first line + furi_string_push_back(bad_kb->line, bad_kb->file_buf[i]); + } + line_len++; + } + } + if(storage_file_eof(script_file)) { + if(line_len > 0) { + bad_kb->st.line_nb++; + break; + } + } + } while(ret > 0); + + if(!bad_kb->bt) { + const char* line_tmp = furi_string_get_cstr(bad_kb->line); + bool id_set = false; // Looking for ID command at first line + if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { + id_set = ducky_set_usb_id(bad_kb, &line_tmp[strlen(ducky_cmd_id) + 1]); + } + + if(id_set) { + furi_check(furi_hal_usb_set_config(&usb_hid, &bad_kb->hid_cfg)); + } else { + furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); + } + } + + storage_file_seek(script_file, 0, true); + furi_string_reset(bad_kb->line); + + return true; +} + +static int32_t ducky_script_execute_next(BadKbScript* bad_kb, File* script_file) { + int32_t delay_val = 0; + + if(bad_kb->repeat_cnt > 0) { + bad_kb->repeat_cnt--; + delay_val = ducky_parse_line( + bad_kb, bad_kb->line_prev, bad_kb->st.error, sizeof(bad_kb->st.error)); + if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line + return 0; + } else if(delay_val < 0) { // Script error + bad_kb->st.error_line = bad_kb->st.line_cur - 1; + FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_kb->st.line_cur - 1U); + return SCRIPT_STATE_ERROR; + } else { + return (delay_val + bad_kb->defdelay); + } + } + + furi_string_set(bad_kb->line_prev, bad_kb->line); + furi_string_reset(bad_kb->line); + + while(1) { + if(bad_kb->buf_len == 0) { + bad_kb->buf_len = storage_file_read(script_file, bad_kb->file_buf, FILE_BUFFER_LEN); + if(storage_file_eof(script_file)) { + if((bad_kb->buf_len < FILE_BUFFER_LEN) && (bad_kb->file_end == false)) { + bad_kb->file_buf[bad_kb->buf_len] = '\n'; + bad_kb->buf_len++; + bad_kb->file_end = true; + } + } + + bad_kb->buf_start = 0; + if(bad_kb->buf_len == 0) return SCRIPT_STATE_END; + } + for(uint8_t i = bad_kb->buf_start; i < (bad_kb->buf_start + bad_kb->buf_len); i++) { + if(bad_kb->file_buf[i] == '\n' && furi_string_size(bad_kb->line) > 0) { + bad_kb->st.line_cur++; + bad_kb->buf_len = bad_kb->buf_len + bad_kb->buf_start - (i + 1); + bad_kb->buf_start = i + 1; + furi_string_trim(bad_kb->line); + delay_val = ducky_parse_line( + bad_kb, bad_kb->line, bad_kb->st.error, sizeof(bad_kb->st.error)); + if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line + return 0; + } else if(delay_val < 0) { + bad_kb->st.error_line = bad_kb->st.line_cur; + if(delay_val == SCRIPT_STATE_NEXT_LINE) { + snprintf( + bad_kb->st.error, sizeof(bad_kb->st.error), "Forbidden empty line"); + FURI_LOG_E( + WORKER_TAG, "Forbidden empty line at line %u", bad_kb->st.line_cur); + } else { + FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_kb->st.line_cur); + } + return SCRIPT_STATE_ERROR; + } else { + return (delay_val + bad_kb->defdelay); + } + } else { + furi_string_push_back(bad_kb->line, bad_kb->file_buf[i]); + } + } + bad_kb->buf_len = 0; + if(bad_kb->file_end) return SCRIPT_STATE_END; + } + + return 0; +} + +static void bad_kb_bt_hid_state_callback(BtStatus status, void* context) { + furi_assert(context); + BadKbScript* bad_kb = (BadKbScript*)context; + bool state = (status == BtStatusConnected); + + if(state == true) { + LevelRssiRange r = bt_remote_rssi_range(bad_kb->bt); + if(r != LevelRssiError) { + bt_timeout = bt_hid_delays[r]; + } + bt_connected = true; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtConnect); + } else { + bt_connected = false; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtDisconnect); + } +} + +static void bad_kb_usb_hid_state_callback(bool state, void* context) { + furi_assert(context); + BadKbScript* bad_kb = context; + + if(state == true) { + usb_connected = true; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtConnect); + } else { + usb_connected = false; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtDisconnect); + } +} + +void bad_kb_bt_init(Bt* bt) { + bt_timeout = bt_hid_delays[LevelRssi39_0]; + bt_disconnect(bt); + furi_delay_ms(200); + bt_keys_storage_set_storage_path(bt, HID_BT_KEYS_STORAGE_PATH); + furi_assert(bt_set_profile(bt, BtProfileHidKeyboard)); + bt_mode_prev = bt_get_profile_pairing_method(bt); + bt_set_profile_pairing_method(bt, GapPairingNone); + furi_hal_bt_start_advertising(); + // disable peer key adding to bt SRAM storage + bt_disable_peer_key_update(bt); + + connection_mode = BadKbConnectionModeBt; +} + +void bad_kb_bt_deinit(Bt* bt) { + // release all keys + // bt_hid_hold_while_keyboard_buffer_full(6, 3000); + + // stop ble + bt_disconnect(bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + + bt_keys_storage_set_default_path(bt); + + bt_set_profile_pairing_method(bt, bt_mode_prev); + + // fails if ble radio stack isn't ready when switching profile + // if it happens, maybe we should increase the delay after bt_disconnect + bt_set_profile(bt, BtProfileSerial); + + // starts saving peer keys (bounded devices) + bt_enable_peer_key_update(bt); + + connection_mode = BadKbConnectionModeNone; +} + +void bad_kb_usb_init() { + usb_mode_prev = furi_hal_usb_get_config(); + + connection_mode = BadKbConnectionModeUsb; +} + +void bad_kb_usb_deinit() { + furi_hal_usb_set_config(usb_mode_prev, NULL); + + connection_mode = BadKbConnectionModeNone; +} + +void bad_kb_connection_init(Bt* bt) { + if(connection_mode != BadKbConnectionModeNone) return; + + if(bt) { + bad_kb_bt_init(bt); + } else { + bad_kb_usb_init(); + } +} + +void bad_kb_connection_deinit(Bt* bt) { + if(connection_mode == BadKbConnectionModeNone) return; + + if(connection_mode == BadKbConnectionModeBt) { + bad_kb_bt_deinit(bt); + } else { + bad_kb_usb_deinit(); + } +} + +static int32_t bad_kb_worker(void* context) { + BadKbScript* bad_kb = context; + + BadKbWorkerState worker_state = BadKbStateInit; + int32_t delay_val = 0; + + bad_kb_connection_init(bad_kb->bt); + + if(bad_kb->bt) { + bt_set_status_changed_callback(bad_kb->bt, bad_kb_bt_hid_state_callback, bad_kb); + } else { + furi_hal_hid_set_state_callback(bad_kb_usb_hid_state_callback, bad_kb); + } + + FURI_LOG_I(WORKER_TAG, "Init"); + File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + bad_kb->line = furi_string_alloc(); + bad_kb->line_prev = furi_string_alloc(); + + while(1) { + if(worker_state == BadKbStateInit) { // State: initialization + if(storage_file_open( + script_file, + furi_string_get_cstr(bad_kb->file_path), + FSAM_READ, + FSOM_OPEN_EXISTING)) { + if((ducky_script_preload(bad_kb, script_file)) && (bad_kb->st.line_nb > 0)) { + if(bad_kb->bt) { + worker_state = BadKbStateNotConnected; // Ready to run + } else { + if(furi_hal_hid_is_connected()) { + worker_state = BadKbStateIdle; // Ready to run + } else { + worker_state = BadKbStateNotConnected; // Not connected + } + } + } else { + worker_state = BadKbStateScriptError; // Script preload error + } + } else { + FURI_LOG_E(WORKER_TAG, "File open error"); + worker_state = BadKbStateFileError; // File open error + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateNotConnected) { // State: Not connected + if((bad_kb->bt && bt_connected) || (!bad_kb->bt && usb_connected)) { + worker_state = BadKbStateIdle; // Ready to run + } else { + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtConnect) { + worker_state = BadKbStateIdle; // Ready to run + } else if(flags & WorkerEvtToggle) { + worker_state = BadKbStateWillRun; // Will run when connected + } + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateIdle) { // State: ready to start + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtToggle) { // Start executing script + DOLPHIN_DEED(DolphinDeedBadKbPlayScript); + delay_val = 0; + bad_kb->buf_len = 0; + bad_kb->st.line_cur = 0; + bad_kb->defdelay = 0; + bad_kb->repeat_cnt = 0; + bad_kb->file_end = false; + storage_file_seek(script_file, 0, true); + bad_kb_script_set_keyboard_layout(bad_kb, bad_kb->keyboard_layout); + worker_state = BadKbStateRunning; + } else if(flags & WorkerEvtDisconnect) { + worker_state = BadKbStateNotConnected; // Disconnected + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateWillRun) { // State: start on connection + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtConnect) { // Start executing script + DOLPHIN_DEED(DolphinDeedBadKbPlayScript); + delay_val = 0; + bad_kb->buf_len = 0; + bad_kb->st.line_cur = 0; + bad_kb->defdelay = 0; + bad_kb->repeat_cnt = 0; + bad_kb->file_end = false; + storage_file_seek(script_file, 0, true); + // extra time for PC to recognize Flipper as keyboard + furi_thread_flags_wait(0, FuriFlagWaitAny, 1500); + if(bad_kb->bt) { + update_bt_timeout(bad_kb->bt); + } + bad_kb_script_set_keyboard_layout(bad_kb, bad_kb->keyboard_layout); + worker_state = BadKbStateRunning; + } else if(flags & WorkerEvtToggle) { // Cancel scheduled execution + worker_state = BadKbStateNotConnected; + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateRunning) { // State: running + uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); + delay_val -= delay_cur; + if(!(flags & FuriFlagError)) { + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtToggle) { + worker_state = BadKbStateIdle; // Stop executing script + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release_all(); + } else { + furi_hal_hid_kb_release_all(); + } + } else if(flags & WorkerEvtDisconnect) { + worker_state = BadKbStateNotConnected; // Disconnected + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release_all(); + } else { + furi_hal_hid_kb_release_all(); + } + } + bad_kb->st.state = worker_state; + continue; + } else if( + (flags == (unsigned)FuriFlagErrorTimeout) || + (flags == (unsigned)FuriFlagErrorResource)) { + if(delay_val > 0) { + bad_kb->st.delay_remain--; + continue; + } + bad_kb->st.state = BadKbStateRunning; + delay_val = ducky_script_execute_next(bad_kb, script_file); + if(delay_val == SCRIPT_STATE_ERROR) { // Script error + delay_val = 0; + worker_state = BadKbStateScriptError; + bad_kb->st.state = worker_state; + } else if(delay_val == SCRIPT_STATE_END) { // End of script + delay_val = 0; + worker_state = BadKbStateIdle; + bad_kb->st.state = BadKbStateDone; + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release_all(); + } else { + furi_hal_hid_kb_release_all(); + } + continue; + } else if(delay_val > 1000) { + bad_kb->st.state = BadKbStateDelay; // Show long delays + bad_kb->st.delay_remain = delay_val / 1000; + } + } else { + furi_check((flags & FuriFlagError) == 0); + } + + } else if( + (worker_state == BadKbStateFileError) || + (worker_state == BadKbStateScriptError)) { // State: error + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd, FuriFlagWaitAny, FuriWaitForever); // Waiting for exit command + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } + } + if(bad_kb->bt) { + update_bt_timeout(bad_kb->bt); + } + } + + if(bad_kb->bt) { + bt_set_status_changed_callback(bad_kb->bt, NULL, NULL); + } else { + furi_hal_hid_set_state_callback(NULL, NULL); + } + + storage_file_close(script_file); + storage_file_free(script_file); + furi_string_free(bad_kb->line); + furi_string_free(bad_kb->line_prev); + + FURI_LOG_I(WORKER_TAG, "End"); + + return 0; +} + +static void bad_kb_script_set_default_keyboard_layout(BadKbScript* bad_kb) { + furi_assert(bad_kb); + furi_string_set_str(bad_kb->keyboard_layout, ""); + memset(bad_kb->layout, HID_KEYBOARD_NONE, sizeof(bad_kb->layout)); + memcpy(bad_kb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_kb->layout))); +} + +BadKbScript* bad_kb_script_open(FuriString* file_path, Bt* bt) { + furi_assert(file_path); + + BadKbScript* bad_kb = malloc(sizeof(BadKbScript)); + bad_kb->file_path = furi_string_alloc(); + furi_string_set(bad_kb->file_path, file_path); + bad_kb->keyboard_layout = furi_string_alloc(); + bad_kb_script_set_default_keyboard_layout(bad_kb); + + bad_kb->st.state = BadKbStateInit; + bad_kb->st.error[0] = '\0'; + + bad_kb->bt = bt; + + bad_kb->thread = furi_thread_alloc_ex("BadKbWorker", 2048, bad_kb_worker, bad_kb); + furi_thread_start(bad_kb->thread); + return bad_kb; +} //-V773 + +void bad_kb_script_close(BadKbScript* bad_kb) { + furi_assert(bad_kb); + furi_record_close(RECORD_STORAGE); + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtEnd); + furi_thread_join(bad_kb->thread); + furi_thread_free(bad_kb->thread); + furi_string_free(bad_kb->file_path); + furi_string_free(bad_kb->keyboard_layout); + free(bad_kb); +} + +void bad_kb_script_set_keyboard_layout(BadKbScript* bad_kb, FuriString* layout_path) { + furi_assert(bad_kb); + + if((bad_kb->st.state == BadKbStateRunning) || (bad_kb->st.state == BadKbStateDelay)) { + // do not update keyboard layout while a script is running + return; + } + + File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(!furi_string_empty(layout_path)) { + furi_string_set(bad_kb->keyboard_layout, layout_path); + if(storage_file_open( + layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) { + uint16_t layout[128]; + if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) { + memcpy(bad_kb->layout, layout, sizeof(layout)); + } + } + storage_file_close(layout_file); + } else { + bad_kb_script_set_default_keyboard_layout(bad_kb); + } + storage_file_free(layout_file); +} + +void bad_kb_script_toggle(BadKbScript* bad_kb) { + furi_assert(bad_kb); + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtToggle); +} + +BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb) { + furi_assert(bad_kb); + return &(bad_kb->st); +} diff --git a/applications/main/bad_kb/bad_kb_script.h b/applications/main/bad_kb/bad_kb_script.h new file mode 100644 index 000000000..0ea701eb8 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_script.h @@ -0,0 +1,53 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct BadKbScript BadKbScript; + +typedef enum { + BadKbStateInit, + BadKbStateNotConnected, + BadKbStateIdle, + BadKbStateWillRun, + BadKbStateRunning, + BadKbStateDelay, + BadKbStateDone, + BadKbStateScriptError, + BadKbStateFileError, +} BadKbWorkerState; + +typedef struct { + BadKbWorkerState state; + uint16_t line_cur; + uint16_t line_nb; + uint32_t delay_remain; + uint16_t error_line; + char error[64]; +} BadKbState; + +void bad_kb_connection_init(Bt* bt); + +void bad_kb_connection_deinit(Bt* bt); + +BadKbScript* bad_kb_script_open(FuriString* file_path, Bt* bt); + +void bad_kb_script_close(BadKbScript* bad_kb); + +void bad_kb_script_set_keyboard_layout(BadKbScript* bad_kb, FuriString* layout_path); + +void bad_kb_script_start(BadKbScript* bad_kb); + +void bad_kb_script_stop(BadKbScript* bad_kb); + +void bad_kb_script_toggle(BadKbScript* bad_kb); + +BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/bad_kb/bad_kb_settings_filename.h b/applications/main/bad_kb/bad_kb_settings_filename.h new file mode 100644 index 000000000..3eb7d3c0a --- /dev/null +++ b/applications/main/bad_kb/bad_kb_settings_filename.h @@ -0,0 +1,3 @@ +#pragma once + +#define BAD_KB_SETTINGS_FILE_NAME ".badkb.settings" diff --git a/applications/main/bad_kb/scenes/bad_kb_scene.c b/applications/main/bad_kb/scenes/bad_kb_scene.c new file mode 100644 index 000000000..f90d23a77 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene.c @@ -0,0 +1,30 @@ +#include "bad_kb_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const bad_kb_scene_on_enter_handlers[])(void*) = { +#include "bad_kb_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const bad_kb_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "bad_kb_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const bad_kb_scene_on_exit_handlers[])(void* context) = { +#include "bad_kb_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers bad_kb_scene_handlers = { + .on_enter_handlers = bad_kb_scene_on_enter_handlers, + .on_event_handlers = bad_kb_scene_on_event_handlers, + .on_exit_handlers = bad_kb_scene_on_exit_handlers, + .scene_num = BadKbSceneNum, +}; diff --git a/applications/main/bad_usb/scenes/bad_usb_scene.h b/applications/main/bad_kb/scenes/bad_kb_scene.h similarity index 68% rename from applications/main/bad_usb/scenes/bad_usb_scene.h rename to applications/main/bad_kb/scenes/bad_kb_scene.h index 68a753210..82db02873 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene.h +++ b/applications/main/bad_kb/scenes/bad_kb_scene.h @@ -3,27 +3,27 @@ #include // Generate scene id and total number -#define ADD_SCENE(prefix, name, id) BadUsbScene##id, +#define ADD_SCENE(prefix, name, id) BadKbScene##id, typedef enum { -#include "bad_usb_scene_config.h" - BadUsbSceneNum, -} BadUsbScene; +#include "bad_kb_scene_config.h" + BadKbSceneNum, +} BadKbScene; #undef ADD_SCENE -extern const SceneManagerHandlers bad_usb_scene_handlers; +extern const SceneManagerHandlers bad_kb_scene_handlers; // Generate scene on_enter handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); -#include "bad_usb_scene_config.h" +#include "bad_kb_scene_config.h" #undef ADD_SCENE // Generate scene on_event handlers declaration #define ADD_SCENE(prefix, name, id) \ bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); -#include "bad_usb_scene_config.h" +#include "bad_kb_scene_config.h" #undef ADD_SCENE // Generate scene on_exit handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); -#include "bad_usb_scene_config.h" +#include "bad_kb_scene_config.h" #undef ADD_SCENE diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config.h b/applications/main/bad_kb/scenes/bad_kb_scene_config.h new file mode 100644 index 000000000..794468eba --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config.h @@ -0,0 +1,8 @@ +ADD_SCENE(bad_kb, file_select, FileSelect) +ADD_SCENE(bad_kb, work, Work) +ADD_SCENE(bad_kb, error, Error) +ADD_SCENE(bad_kb, config_bt, ConfigBt) +ADD_SCENE(bad_kb, config_usb, ConfigUsb) +ADD_SCENE(bad_kb, config_layout, ConfigLayout) +ADD_SCENE(bad_kb, config_name, ConfigName) +ADD_SCENE(bad_kb, config_mac, ConfigMac) diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_bt.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_bt.c new file mode 100644 index 000000000..394783828 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_bt.c @@ -0,0 +1,84 @@ +#include "../bad_kb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" + +enum VarItemListIndex { + VarItemListIndexConnection, + VarItemListIndexKeyboardLayout, + VarItemListIndexAdvertisementName, + VarItemListIndexMacAddress, +}; + +void bad_kb_scene_config_bt_connection_callback(VariableItem* item) { + BadKbApp* bad_kb = variable_item_get_context(item); + bad_kb->is_bt = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, VarItemListIndexConnection); +} + +void bad_kb_scene_config_bt_var_item_list_callback(void* context, uint32_t index) { + BadKbApp* bad_kb = context; + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, index); +} + +void bad_kb_scene_config_bt_on_enter(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_bt; + VariableItem* item; + + item = variable_item_list_add( + var_item_list, "Connection", 2, bad_kb_scene_config_bt_connection_callback, bad_kb); + variable_item_set_current_value_index(item, bad_kb->is_bt); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + + item = variable_item_list_add(var_item_list, "Keyboard layout", 0, NULL, bad_kb); + + item = variable_item_list_add(var_item_list, "BT device name", 0, NULL, bad_kb); + + item = variable_item_list_add(var_item_list, "BT MAC address", 0, NULL, bad_kb); + + variable_item_list_set_enter_callback( + var_item_list, bad_kb_scene_config_bt_var_item_list_callback, bad_kb); + + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigBt); +} + +bool bad_kb_scene_config_bt_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(bad_kb->scene_manager, BadKbSceneConfigBt, event.event); + consumed = true; + if(event.event == VarItemListIndexKeyboardLayout) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigLayout); + } else if(event.event == VarItemListIndexConnection) { + bad_kb_script_close(bad_kb->bad_kb_script); + bad_kb_connection_deinit(bad_kb->bt); + bad_kb->bad_kb_script = + bad_kb_script_open(bad_kb->file_path, bad_kb->is_bt ? bad_kb->bt : NULL); + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + scene_manager_previous_scene(bad_kb->scene_manager); + if(bad_kb->is_bt) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigBt); + } else { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigUsb); + } + } else if(event.event == VarItemListIndexAdvertisementName) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigName); + } else if(event.event == VarItemListIndexMacAddress) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigMac); + // } else { + // furi_crash("Unknown key type"); + } + } + + return consumed; +} + +void bad_kb_scene_config_bt_on_exit(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_bt; + + variable_item_list_reset(var_item_list); +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c new file mode 100644 index 000000000..006ad31bd --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c @@ -0,0 +1,48 @@ +#include "../bad_kb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" +#include + +static bool bad_kb_layout_select(BadKbApp* bad_kb) { + furi_assert(bad_kb); + + FuriString* predefined_path; + predefined_path = furi_string_alloc(); + if(!furi_string_empty(bad_kb->keyboard_layout)) { + furi_string_set(predefined_path, bad_kb->keyboard_layout); + } else { + furi_string_set(predefined_path, BAD_KB_APP_PATH_LAYOUT_FOLDER); + } + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options( + &browser_options, BAD_KB_APP_LAYOUT_EXTENSION, &I_keyboard_10px); + + // Input events and views are managed by file_browser + bool res = dialog_file_browser_show( + bad_kb->dialogs, bad_kb->keyboard_layout, predefined_path, &browser_options); + + furi_string_free(predefined_path); + return res; +} + +void bad_kb_scene_config_layout_on_enter(void* context) { + BadKbApp* bad_kb = context; + + if(bad_kb_layout_select(bad_kb)) { + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + } + scene_manager_previous_scene(bad_kb->scene_manager); +} + +bool bad_kb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + // BadKbApp* bad_kb = context; + return false; +} + +void bad_kb_scene_config_layout_on_exit(void* context) { + UNUSED(context); + // BadKbApp* bad_kb = context; +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_mac.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_mac.c new file mode 100644 index 000000000..0dc4be10a --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_mac.c @@ -0,0 +1,57 @@ +#include "../bad_kb_app_i.h" + +#define TAG "BadKbConfigMac" + +static uint8_t* reverse_mac_addr(uint8_t* mac) { + uint8_t tmp; + for(int i = 0; i < 3; i++) { + tmp = mac[i]; + mac[i] = mac[5 - i]; + mac[5 - i] = tmp; + } + return mac; +} + +void bad_kb_scene_config_mac_byte_input_callback(void* context) { + BadKbApp* bad_kb = context; + + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, BadKbAppCustomEventByteInputDone); +} + +void bad_kb_scene_config_mac_on_enter(void* context) { + BadKbApp* bad_kb = context; + + // Setup view + ByteInput* byte_input = bad_kb->byte_input; + byte_input_set_header_text(byte_input, "Enter new MAC address"); + byte_input_set_result_callback( + byte_input, + bad_kb_scene_config_mac_byte_input_callback, + NULL, + bad_kb, + reverse_mac_addr(bad_kb->mac), + GAP_MAC_ADDR_SIZE); + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigMac); +} + +bool bad_kb_scene_config_mac_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == BadKbAppCustomEventByteInputDone) { + bt_set_profile_mac_address(bad_kb->bt, reverse_mac_addr(bad_kb->mac)); + scene_manager_previous_scene(bad_kb->scene_manager); + consumed = true; + } + } + return consumed; +} + +void bad_kb_scene_config_mac_on_exit(void* context) { + BadKbApp* bad_kb = context; + + // Clear view + byte_input_set_result_callback(bad_kb->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(bad_kb->byte_input, ""); +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_name.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_name.c new file mode 100644 index 000000000..82dd7a850 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_name.c @@ -0,0 +1,45 @@ +#include "../bad_kb_app_i.h" + +static void bad_kb_scene_config_name_text_input_callback(void* context) { + BadKbApp* bad_kb = context; + + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, BadKbAppCustomEventTextEditResult); +} + +void bad_kb_scene_config_name_on_enter(void* context) { + BadKbApp* bad_kb = context; + TextInput* text_input = bad_kb->text_input; + + text_input_set_header_text(text_input, "Set BLE adv name"); + + text_input_set_result_callback( + text_input, + bad_kb_scene_config_name_text_input_callback, + bad_kb, + bad_kb->name, + BAD_KB_ADV_NAME_MAX_LEN, + true); + + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigName); +} + +bool bad_kb_scene_config_name_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == BadKbAppCustomEventTextEditResult) { + bt_set_profile_adv_name(bad_kb->bt, bad_kb->name); + } + scene_manager_previous_scene(bad_kb->scene_manager); + } + return consumed; +} + +void bad_kb_scene_config_name_on_exit(void* context) { + BadKbApp* bad_kb = context; + TextInput* text_input = bad_kb->text_input; + + text_input_reset(text_input); +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_usb.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_usb.c new file mode 100644 index 000000000..fc265b64e --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_usb.c @@ -0,0 +1,74 @@ +#include "../bad_kb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" + +enum VarItemListIndex { + VarItemListIndexConnection, + VarItemListIndexKeyboardLayout, +}; + +void bad_kb_scene_config_usb_connection_callback(VariableItem* item) { + BadKbApp* bad_kb = variable_item_get_context(item); + bad_kb->is_bt = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, VarItemListIndexConnection); +} + +void bad_kb_scene_config_usb_var_item_list_callback(void* context, uint32_t index) { + BadKbApp* bad_kb = context; + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, index); +} + +void bad_kb_scene_config_usb_on_enter(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_usb; + VariableItem* item; + + item = variable_item_list_add( + var_item_list, "Connection", 2, bad_kb_scene_config_usb_connection_callback, bad_kb); + variable_item_set_current_value_index(item, bad_kb->is_bt); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + + item = variable_item_list_add(var_item_list, "Keyboard layout", 0, NULL, bad_kb); + + variable_item_list_set_enter_callback( + var_item_list, bad_kb_scene_config_usb_var_item_list_callback, bad_kb); + + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigUsb); +} + +bool bad_kb_scene_config_usb_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(bad_kb->scene_manager, BadKbSceneConfigUsb, event.event); + consumed = true; + if(event.event == VarItemListIndexKeyboardLayout) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigLayout); + } else if(event.event == VarItemListIndexConnection) { + bad_kb_script_close(bad_kb->bad_kb_script); + bad_kb_connection_deinit(bad_kb->bt); + bad_kb->bad_kb_script = + bad_kb_script_open(bad_kb->file_path, bad_kb->is_bt ? bad_kb->bt : NULL); + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + scene_manager_previous_scene(bad_kb->scene_manager); + if(bad_kb->is_bt) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigBt); + } else { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigUsb); + } + // } else { + // furi_crash("Unknown key type"); + } + } + + return consumed; +} + +void bad_kb_scene_config_usb_on_exit(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_usb; + + variable_item_list_reset(var_item_list); +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_error.c b/applications/main/bad_kb/scenes/bad_kb_scene_error.c similarity index 68% rename from applications/main/bad_usb/scenes/bad_usb_scene_error.c rename to applications/main/bad_kb/scenes/bad_kb_scene_error.c index 5cef1b7ef..bfec05652 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_error.c +++ b/applications/main/bad_kb/scenes/bad_kb_scene_error.c @@ -1,24 +1,20 @@ -#include "../bad_usb_app_i.h" +#include "../bad_kb_app_i.h" #include "xtreme/assets.h" -typedef enum { - BadUsbCustomEventErrorBack, -} BadUsbCustomEvent; - static void - bad_usb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) { + bad_kb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); - BadUsbApp* app = context; + BadKbApp* app = context; if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { - view_dispatcher_send_custom_event(app->view_dispatcher, BadUsbCustomEventErrorBack); + view_dispatcher_send_custom_event(app->view_dispatcher, BadKbCustomEventErrorBack); } } -void bad_usb_scene_error_on_enter(void* context) { - BadUsbApp* app = context; +void bad_kb_scene_error_on_enter(void* context) { + BadKbApp* app = context; - if(app->error == BadUsbAppErrorNoFiles) { + if(app->error == BadKbAppErrorNoFiles) { widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43); widget_add_string_multiline_element( app->widget, @@ -29,8 +25,8 @@ void bad_usb_scene_error_on_enter(void* context) { FontSecondary, "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files."); widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app); - } else if(app->error == BadUsbAppErrorCloseRpc) { + app->widget, GuiButtonTypeLeft, "Back", bad_kb_scene_error_event_callback, app); + } else if(app->error == BadKbAppErrorCloseRpc) { widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); if(XTREME_ASSETS()->is_nsfw) { widget_add_string_multiline_element( @@ -57,15 +53,15 @@ void bad_usb_scene_error_on_enter(void* context) { } } - view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError); + view_dispatcher_switch_to_view(app->view_dispatcher, BadKbAppViewError); } -bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) { - BadUsbApp* app = context; +bool bad_kb_scene_error_on_event(void* context, SceneManagerEvent event) { + BadKbApp* app = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == BadUsbCustomEventErrorBack) { + if(event.event == BadKbCustomEventErrorBack) { view_dispatcher_stop(app->view_dispatcher); consumed = true; } @@ -73,7 +69,7 @@ bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) { return consumed; } -void bad_usb_scene_error_on_exit(void* context) { - BadUsbApp* app = context; +void bad_kb_scene_error_on_exit(void* context) { + BadKbApp* app = context; widget_reset(app->widget); } diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_file_select.c b/applications/main/bad_kb/scenes/bad_kb_scene_file_select.c new file mode 100644 index 000000000..bb2ddf6ca --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_file_select.c @@ -0,0 +1,53 @@ +#include "../bad_kb_app_i.h" +#include +#include +#include + +static bool bad_kb_file_select(BadKbApp* bad_kb) { + furi_assert(bad_kb); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options( + &browser_options, BAD_KB_APP_SCRIPT_EXTENSION, &I_badkb_10px); + browser_options.base_path = BAD_KB_APP_BASE_FOLDER; + browser_options.skip_assets = true; + + // Input events and views are managed by file_browser + bool res = dialog_file_browser_show( + bad_kb->dialogs, bad_kb->file_path, bad_kb->file_path, &browser_options); + + return res; +} + +void bad_kb_scene_file_select_on_enter(void* context) { + BadKbApp* bad_kb = context; + + furi_hal_usb_disable(); + if(bad_kb->bad_kb_script) { + bad_kb_script_close(bad_kb->bad_kb_script); + bad_kb->bad_kb_script = NULL; + } + + if(bad_kb_file_select(bad_kb)) { + bad_kb->bad_kb_script = + bad_kb_script_open(bad_kb->file_path, bad_kb->is_bt ? bad_kb->bt : NULL); + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneWork); + } else { + furi_hal_usb_enable(); + view_dispatcher_stop(bad_kb->view_dispatcher); + } +} + +bool bad_kb_scene_file_select_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + // BadKbApp* bad_kb = context; + return false; +} + +void bad_kb_scene_file_select_on_exit(void* context) { + UNUSED(context); + // BadKbApp* bad_kb = context; +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_work.c b/applications/main/bad_kb/scenes/bad_kb_scene_work.c new file mode 100644 index 000000000..165ee0289 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_work.c @@ -0,0 +1,58 @@ +#include "../bad_kb_script.h" +#include "../bad_kb_app_i.h" +#include "../views/bad_kb_view.h" +#include +#include "toolbox/path.h" + +void bad_kb_scene_work_button_callback(InputKey key, void* context) { + furi_assert(context); + BadKbApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, key); +} + +bool bad_kb_scene_work_on_event(void* context, SceneManagerEvent event) { + BadKbApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InputKeyLeft) { + if(app->is_bt) { + scene_manager_next_scene(app->scene_manager, BadKbSceneConfigBt); + } else { + scene_manager_next_scene(app->scene_manager, BadKbSceneConfigUsb); + } + consumed = true; + } else if(event.event == InputKeyOk) { + bad_kb_script_toggle(app->bad_kb_script); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeTick) { + bad_kb_set_state(app->bad_kb_view, bad_kb_script_get_state(app->bad_kb_script)); + } + return consumed; +} + +void bad_kb_scene_work_on_enter(void* context) { + BadKbApp* app = context; + + FuriString* file_name; + file_name = furi_string_alloc(); + path_extract_filename(app->file_path, file_name, true); + bad_kb_set_file_name(app->bad_kb_view, furi_string_get_cstr(file_name)); + furi_string_free(file_name); + + FuriString* layout; + layout = furi_string_alloc(); + path_extract_filename(app->keyboard_layout, layout, true); + bad_kb_set_layout(app->bad_kb_view, furi_string_get_cstr(layout)); + furi_string_free(layout); + + bad_kb_set_state(app->bad_kb_view, bad_kb_script_get_state(app->bad_kb_script)); + + bad_kb_set_button_callback(app->bad_kb_view, bad_kb_scene_work_button_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, BadKbAppViewWork); +} + +void bad_kb_scene_work_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_kb/views/bad_kb_view.c similarity index 68% rename from applications/main/bad_usb/views/bad_usb_view.c rename to applications/main/bad_kb/views/bad_kb_view.c index 88a225271..1ffe58e9c 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_kb/views/bad_kb_view.c @@ -1,5 +1,5 @@ -#include "bad_usb_view.h" -#include "../bad_usb_script.h" +#include "bad_kb_view.h" +#include "../bad_kb_script.h" #include #include #include @@ -7,21 +7,21 @@ #define MAX_NAME_LEN 64 -struct BadUsb { +struct BadKb { View* view; - BadUsbButtonCallback callback; + BadKbButtonCallback callback; void* context; }; typedef struct { char file_name[MAX_NAME_LEN]; char layout[MAX_NAME_LEN]; - BadUsbState state; + BadKbState state; uint8_t anim_frame; -} BadUsbModel; +} BadKbModel; -static void bad_usb_draw_callback(Canvas* canvas, void* _model) { - BadUsbModel* model = _model; +static void bad_kb_draw_callback(Canvas* canvas, void* _model) { + BadKbModel* model = _model; FuriString* disp_str; disp_str = furi_string_alloc_set(model->file_name); @@ -46,25 +46,25 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22); - if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) || - (model->state.state == BadUsbStateNotConnected)) { + if((model->state.state == BadKbStateIdle) || (model->state.state == BadKbStateDone) || + (model->state.state == BadKbStateNotConnected)) { if(XTREME_ASSETS()->is_nsfw) { elements_button_center(canvas, "Cum"); } else { elements_button_center(canvas, "Start"); } - } else if((model->state.state == BadUsbStateRunning) || (model->state.state == BadUsbStateDelay)) { + } else if((model->state.state == BadKbStateRunning) || (model->state.state == BadKbStateDelay)) { elements_button_center(canvas, "Stop"); - } else if(model->state.state == BadUsbStateWillRun) { + } else if(model->state.state == BadKbStateWillRun) { elements_button_center(canvas, "Cancel"); } - if((model->state.state == BadUsbStateNotConnected) || - (model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone)) { + if((model->state.state == BadKbStateNotConnected) || (model->state.state == BadKbStateIdle) || + (model->state.state == BadKbStateDone)) { elements_button_left(canvas, "Config"); } - if(model->state.state == BadUsbStateNotConnected) { + if(model->state.state == BadKbStateNotConnected) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); if(XTREME_ASSETS()->is_nsfw) { @@ -74,7 +74,7 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect to"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "a device"); } - } else if(model->state.state == BadUsbStateWillRun) { + } else if(model->state.state == BadKbStateWillRun) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); if(XTREME_ASSETS()->is_nsfw) { @@ -83,12 +83,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run"); } canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect"); - } else if(model->state.state == BadUsbStateFileError) { + } else if(model->state.state == BadKbStateFileError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR"); - } else if(model->state.state == BadUsbStateScriptError) { + } else if(model->state.state == BadKbStateScriptError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); @@ -98,12 +98,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error); - } else if(model->state.state == BadUsbStateIdle) { + } else if(model->state.state == BadKbStateIdle) { canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0"); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateRunning) { + } else if(model->state.state == BadKbStateRunning) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); } else { @@ -116,13 +116,13 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDone) { + } else if(model->state.state == BadKbStateDone) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100"); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDelay) { + } else if(model->state.state == BadKbStateDelay) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); } else { @@ -147,84 +147,78 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { furi_string_free(disp_str); } -static bool bad_usb_input_callback(InputEvent* event, void* context) { +static bool bad_kb_input_callback(InputEvent* event, void* context) { furi_assert(context); - BadUsb* bad_usb = context; + BadKb* bad_kb = context; bool consumed = false; if(event->type == InputTypeShort) { if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) { consumed = true; - furi_assert(bad_usb->callback); - bad_usb->callback(event->key, bad_usb->context); + furi_assert(bad_kb->callback); + bad_kb->callback(event->key, bad_kb->context); } } return consumed; } -BadUsb* bad_usb_alloc() { - BadUsb* bad_usb = malloc(sizeof(BadUsb)); +BadKb* bad_kb_alloc() { + BadKb* bad_kb = malloc(sizeof(BadKb)); - bad_usb->view = view_alloc(); - view_allocate_model(bad_usb->view, ViewModelTypeLocking, sizeof(BadUsbModel)); - view_set_context(bad_usb->view, bad_usb); - view_set_draw_callback(bad_usb->view, bad_usb_draw_callback); - view_set_input_callback(bad_usb->view, bad_usb_input_callback); + bad_kb->view = view_alloc(); + view_allocate_model(bad_kb->view, ViewModelTypeLocking, sizeof(BadKbModel)); + view_set_context(bad_kb->view, bad_kb); + view_set_draw_callback(bad_kb->view, bad_kb_draw_callback); + view_set_input_callback(bad_kb->view, bad_kb_input_callback); - return bad_usb; + return bad_kb; } -void bad_usb_free(BadUsb* bad_usb) { - furi_assert(bad_usb); - view_free(bad_usb->view); - free(bad_usb); +void bad_kb_free(BadKb* bad_kb) { + furi_assert(bad_kb); + view_free(bad_kb->view); + free(bad_kb); } -View* bad_usb_get_view(BadUsb* bad_usb) { - furi_assert(bad_usb); - return bad_usb->view; +View* bad_kb_get_view(BadKb* bad_kb) { + furi_assert(bad_kb); + return bad_kb->view; } -void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context) { - furi_assert(bad_usb); +void bad_kb_set_button_callback(BadKb* bad_kb, BadKbButtonCallback callback, void* context) { + furi_assert(bad_kb); furi_assert(callback); with_view_model( - bad_usb->view, - BadUsbModel * model, + bad_kb->view, + BadKbModel * model, { UNUSED(model); - bad_usb->callback = callback; - bad_usb->context = context; + bad_kb->callback = callback; + bad_kb->context = context; }, true); } -void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) { +void bad_kb_set_file_name(BadKb* bad_kb, const char* name) { furi_assert(name); with_view_model( - bad_usb->view, - BadUsbModel * model, - { strlcpy(model->file_name, name, MAX_NAME_LEN); }, - true); + bad_kb->view, BadKbModel * model, { strlcpy(model->file_name, name, MAX_NAME_LEN); }, true); } -void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) { +void bad_kb_set_layout(BadKb* bad_kb, const char* layout) { furi_assert(layout); with_view_model( - bad_usb->view, - BadUsbModel * model, - { strlcpy(model->layout, layout, MAX_NAME_LEN); }, - true); + bad_kb->view, BadKbModel * model, { strlcpy(model->layout, layout, MAX_NAME_LEN); }, true); } -void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { +void bad_kb_set_state(BadKb* bad_kb, BadKbState* st) { furi_assert(st); with_view_model( - bad_usb->view, - BadUsbModel * model, + bad_kb->view, + BadKbModel * model, { - memcpy(&(model->state), st, sizeof(BadUsbState)); + memcpy(&(model->state), st, sizeof(BadKbState)); model->anim_frame ^= 1; }, true); diff --git a/applications/main/bad_kb/views/bad_kb_view.h b/applications/main/bad_kb/views/bad_kb_view.h new file mode 100644 index 000000000..24fdf4792 --- /dev/null +++ b/applications/main/bad_kb/views/bad_kb_view.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "../bad_kb_script.h" + +typedef struct BadKb BadKb; +typedef void (*BadKbButtonCallback)(InputKey key, void* context); + +BadKb* bad_kb_alloc(); + +void bad_kb_free(BadKb* bad_kb); + +View* bad_kb_get_view(BadKb* bad_kb); + +void bad_kb_set_button_callback(BadKb* bad_kb, BadKbButtonCallback callback, void* context); + +void bad_kb_set_file_name(BadKb* bad_kb, const char* name); + +void bad_kb_set_layout(BadKb* bad_kb, const char* layout); + +void bad_kb_set_state(BadKb* bad_kb, BadKbState* st); diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c deleted file mode 100644 index bb29d3be5..000000000 --- a/applications/main/bad_usb/bad_usb_app.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "bad_usb_app_i.h" -#include "bad_usb_settings_filename.h" -#include -#include -#include -#include - -#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/" BAD_USB_SETTINGS_FILE_NAME - -static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { - furi_assert(context); - BadUsbApp* app = context; - return scene_manager_handle_custom_event(app->scene_manager, event); -} - -static bool bad_usb_app_back_event_callback(void* context) { - furi_assert(context); - BadUsbApp* app = context; - return scene_manager_handle_back_event(app->scene_manager); -} - -static void bad_usb_app_tick_event_callback(void* context) { - furi_assert(context); - BadUsbApp* app = context; - scene_manager_handle_tick_event(app->scene_manager); -} - -static void bad_usb_load_settings(BadUsbApp* app) { - File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - char chr; - while((storage_file_read(settings_file, &chr, 1) == 1) && - !storage_file_eof(settings_file) && !isspace(chr)) { - furi_string_push_back(app->keyboard_layout, chr); - } - } - storage_file_close(settings_file); - storage_file_free(settings_file); -} - -static void bad_usb_save_settings(BadUsbApp* app) { - File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { - storage_file_write( - settings_file, - furi_string_get_cstr(app->keyboard_layout), - furi_string_size(app->keyboard_layout)); - storage_file_write(settings_file, "\n", 1); - } - storage_file_close(settings_file); - storage_file_free(settings_file); -} - -BadUsbApp* bad_usb_app_alloc(char* arg) { - BadUsbApp* app = malloc(sizeof(BadUsbApp)); - - app->bad_usb_script = NULL; - - app->file_path = furi_string_alloc(); - app->keyboard_layout = furi_string_alloc(); - if(arg && strlen(arg)) { - furi_string_set(app->file_path, arg); - } - - bad_usb_load_settings(app); - - app->gui = furi_record_open(RECORD_GUI); - app->notifications = furi_record_open(RECORD_NOTIFICATION); - app->dialogs = furi_record_open(RECORD_DIALOGS); - - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - - app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app); - - view_dispatcher_set_event_callback_context(app->view_dispatcher, app); - view_dispatcher_set_tick_event_callback( - app->view_dispatcher, bad_usb_app_tick_event_callback, 500); - view_dispatcher_set_custom_event_callback( - app->view_dispatcher, bad_usb_app_custom_event_callback); - view_dispatcher_set_navigation_event_callback( - app->view_dispatcher, bad_usb_app_back_event_callback); - - // Custom Widget - app->widget = widget_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); - - app->submenu = submenu_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewConfig, submenu_get_view(app->submenu)); - - app->bad_usb_view = bad_usb_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view)); - - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - if(furi_hal_usb_is_locked()) { - app->error = BadUsbAppErrorCloseRpc; - scene_manager_next_scene(app->scene_manager, BadUsbSceneError); - } else { - if(!furi_string_empty(app->file_path)) { - app->bad_usb_script = bad_usb_script_open(app->file_path); - bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout); - scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); - } else { - furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER); - scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect); - } - } - - return app; -} - -void bad_usb_app_free(BadUsbApp* app) { - furi_assert(app); - - if(app->bad_usb_script) { - bad_usb_script_close(app->bad_usb_script); - app->bad_usb_script = NULL; - } - - // Views - view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); - bad_usb_free(app->bad_usb_view); - - // Custom Widget - view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError); - widget_free(app->widget); - - // Submenu - view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); - submenu_free(app->submenu); - - // View dispatcher - view_dispatcher_free(app->view_dispatcher); - scene_manager_free(app->scene_manager); - - // Close records - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_DIALOGS); - - bad_usb_save_settings(app); - - furi_string_free(app->file_path); - furi_string_free(app->keyboard_layout); - - free(app); -} - -int32_t bad_usb_app(void* p) { - BadUsbApp* bad_usb_app = bad_usb_app_alloc((char*)p); - - view_dispatcher_run(bad_usb_app->view_dispatcher); - - bad_usb_app_free(bad_usb_app); - return 0; -} diff --git a/applications/main/bad_usb/bad_usb_app.h b/applications/main/bad_usb/bad_usb_app.h deleted file mode 100644 index afadd87e9..000000000 --- a/applications/main/bad_usb/bad_usb_app.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct BadUsbApp BadUsbApp; - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h deleted file mode 100644 index b3fbb1679..000000000 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "bad_usb_app.h" -#include "scenes/bad_usb_scene.h" -#include "bad_usb_script.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "views/bad_usb_view.h" - -#define BAD_USB_APP_BASE_FOLDER ANY_PATH("badusb") -#define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/layouts" -#define BAD_USB_APP_SCRIPT_EXTENSION ".txt" -#define BAD_USB_APP_LAYOUT_EXTENSION ".kl" - -typedef enum { - BadUsbAppErrorNoFiles, - BadUsbAppErrorCloseRpc, -} BadUsbAppError; - -struct BadUsbApp { - Gui* gui; - ViewDispatcher* view_dispatcher; - SceneManager* scene_manager; - NotificationApp* notifications; - DialogsApp* dialogs; - Widget* widget; - Submenu* submenu; - - BadUsbAppError error; - FuriString* file_path; - FuriString* keyboard_layout; - BadUsb* bad_usb_view; - BadUsbScript* bad_usb_script; -}; - -typedef enum { - BadUsbAppViewError, - BadUsbAppViewWork, - BadUsbAppViewConfig, -} BadUsbAppView; \ No newline at end of file diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c deleted file mode 100644 index a784ef1a6..000000000 --- a/applications/main/bad_usb/bad_usb_script.c +++ /dev/null @@ -1,725 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "bad_usb_script.h" -#include - -#define TAG "BadUSB" -#define WORKER_TAG TAG "Worker" -#define FILE_BUFFER_LEN 16 - -#define SCRIPT_STATE_ERROR (-1) -#define SCRIPT_STATE_END (-2) -#define SCRIPT_STATE_NEXT_LINE (-3) - -#define BADUSB_ASCII_TO_KEY(script, x) \ - (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) - -typedef enum { - WorkerEvtToggle = (1 << 0), - WorkerEvtEnd = (1 << 1), - WorkerEvtConnect = (1 << 2), - WorkerEvtDisconnect = (1 << 3), -} WorkerEvtFlags; - -struct BadUsbScript { - FuriHalUsbHidConfig hid_cfg; - BadUsbState st; - FuriString* file_path; - uint32_t defdelay; - uint16_t layout[128]; - FuriThread* thread; - uint8_t file_buf[FILE_BUFFER_LEN + 1]; - uint8_t buf_start; - uint8_t buf_len; - bool file_end; - FuriString* line; - - FuriString* line_prev; - uint32_t repeat_cnt; -}; - -typedef struct { - char* name; - uint16_t keycode; -} DuckyKey; - -static const DuckyKey ducky_keys[] = { - {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, - {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, - {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, - {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, - {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, - {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, - - {"CTRL", KEY_MOD_LEFT_CTRL}, - {"CONTROL", KEY_MOD_LEFT_CTRL}, - {"SHIFT", KEY_MOD_LEFT_SHIFT}, - {"ALT", KEY_MOD_LEFT_ALT}, - {"GUI", KEY_MOD_LEFT_GUI}, - {"WINDOWS", KEY_MOD_LEFT_GUI}, - - {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, - {"DOWN", HID_KEYBOARD_DOWN_ARROW}, - {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, - {"LEFT", HID_KEYBOARD_LEFT_ARROW}, - {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, - {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, - {"UPARROW", HID_KEYBOARD_UP_ARROW}, - {"UP", HID_KEYBOARD_UP_ARROW}, - - {"ENTER", HID_KEYBOARD_RETURN}, - {"BREAK", HID_KEYBOARD_PAUSE}, - {"PAUSE", HID_KEYBOARD_PAUSE}, - {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, - {"DELETE", HID_KEYBOARD_DELETE_FORWARD}, - {"BACKSPACE", HID_KEYBOARD_DELETE}, - {"END", HID_KEYBOARD_END}, - {"ESC", HID_KEYBOARD_ESCAPE}, - {"ESCAPE", HID_KEYBOARD_ESCAPE}, - {"HOME", HID_KEYBOARD_HOME}, - {"INSERT", HID_KEYBOARD_INSERT}, - {"NUMLOCK", HID_KEYPAD_NUMLOCK}, - {"PAGEUP", HID_KEYBOARD_PAGE_UP}, - {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, - {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, - {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, - {"SPACE", HID_KEYBOARD_SPACEBAR}, - {"TAB", HID_KEYBOARD_TAB}, - {"MENU", HID_KEYBOARD_APPLICATION}, - {"APP", HID_KEYBOARD_APPLICATION}, - - {"F1", HID_KEYBOARD_F1}, - {"F2", HID_KEYBOARD_F2}, - {"F3", HID_KEYBOARD_F3}, - {"F4", HID_KEYBOARD_F4}, - {"F5", HID_KEYBOARD_F5}, - {"F6", HID_KEYBOARD_F6}, - {"F7", HID_KEYBOARD_F7}, - {"F8", HID_KEYBOARD_F8}, - {"F9", HID_KEYBOARD_F9}, - {"F10", HID_KEYBOARD_F10}, - {"F11", HID_KEYBOARD_F11}, - {"F12", HID_KEYBOARD_F12}, -}; - -static const char ducky_cmd_comment[] = {"REM"}; -static const char ducky_cmd_id[] = {"ID"}; -static const char ducky_cmd_delay[] = {"DELAY "}; -static const char ducky_cmd_string[] = {"STRING "}; -static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; -static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; -static const char ducky_cmd_repeat[] = {"REPEAT "}; -static const char ducky_cmd_sysrq[] = {"SYSRQ "}; - -static const char ducky_cmd_altchar[] = {"ALTCHAR "}; -static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; -static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; - -static const char ducky_cmd_lang[] = {"DUCKY_LANG"}; - -static const uint8_t numpad_keys[10] = { - HID_KEYPAD_0, - HID_KEYPAD_1, - HID_KEYPAD_2, - HID_KEYPAD_3, - HID_KEYPAD_4, - HID_KEYPAD_5, - HID_KEYPAD_6, - HID_KEYPAD_7, - HID_KEYPAD_8, - HID_KEYPAD_9, -}; - -static bool ducky_get_number(const char* param, uint32_t* val) { - uint32_t value = 0; - if(sscanf(param, "%lu", &value) == 1) { - *val = value; - return true; - } - return false; -} - -static uint32_t ducky_get_command_len(const char* line) { - uint32_t len = strlen(line); - for(uint32_t i = 0; i < len; i++) { - if(line[i] == ' ') return i; - } - return 0; -} - -static bool ducky_is_line_end(const char chr) { - return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n')); -} - -static void ducky_numlock_on() { - if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { - furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); - furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); - } -} - -static bool ducky_numpad_press(const char num) { - if((num < '0') || (num > '9')) return false; - - uint16_t key = numpad_keys[num - '0']; - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); - - return true; -} - -static bool ducky_altchar(const char* charcode) { - uint8_t i = 0; - bool state = false; - - FURI_LOG_I(WORKER_TAG, "char %s", charcode); - - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); - - while(!ducky_is_line_end(charcode[i])) { - state = ducky_numpad_press(charcode[i]); - if(state == false) break; - i++; - } - - furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); - return state; -} - -static bool ducky_altstring(const char* param) { - uint32_t i = 0; - bool state = false; - - while(param[i] != '\0') { - if((param[i] < ' ') || (param[i] > '~')) { - i++; - continue; // Skip non-printable chars - } - - char temp_str[4]; - snprintf(temp_str, 4, "%u", param[i]); - - state = ducky_altchar(temp_str); - if(state == false) break; - i++; - } - return state; -} - -static bool ducky_string(BadUsbScript* bad_usb, const char* param) { - uint32_t i = 0; - while(param[i] != '\0') { - uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]); - if(keycode != HID_KEYBOARD_NONE) { - furi_hal_hid_kb_press(keycode); - furi_hal_hid_kb_release(keycode); - } - i++; - } - return true; -} - -static uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) { - for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { - size_t key_cmd_len = strlen(ducky_keys[i].name); - if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && - (ducky_is_line_end(param[key_cmd_len]))) { - return ducky_keys[i].keycode; - } - } - if((accept_chars) && (strlen(param) > 0)) { - return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF); - } - return 0; -} - -static int32_t - ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) { - uint32_t line_len = furi_string_size(line); - const char* line_tmp = furi_string_get_cstr(line); - bool state = false; - - if(line_len == 0) { - return SCRIPT_STATE_NEXT_LINE; // Skip empty lines - } - - FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); - - // General commands - if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) { - // REM - comment line - return (0); - } else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { - // ID - executed in ducky_script_preload - return (0); - } else if(strncmp(line_tmp, ducky_cmd_lang, strlen(ducky_cmd_lang)) == 0) { - // DUCKY_LANG - ignore command to retain compatibility with existing scripts - return (0); - } else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) { - // DELAY - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - uint32_t delay_val = 0; - state = ducky_get_number(line_tmp, &delay_val); - if((state) && (delay_val > 0)) { - return (int32_t)delay_val; - } - if(error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return SCRIPT_STATE_ERROR; - } else if( - (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) || - (strncmp(line_tmp, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) { - // DEFAULT_DELAY - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_get_number(line_tmp, &bad_usb->defdelay); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { - // STRING - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_string(bad_usb, line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid string %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { - // ALTCHAR - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - ducky_numlock_on(); - state = ducky_altchar(line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid altchar %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if( - (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) || - (strncmp(line_tmp, ducky_cmd_altstr_2, strlen(ducky_cmd_altstr_2)) == 0)) { - // ALTSTRING - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - ducky_numlock_on(); - state = ducky_altstring(line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid altstring %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { - // REPEAT - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { - // SYSRQ - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release_all(); - return (0); - } else { - // Special keys + modifiers - uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); - if(key == HID_KEYBOARD_NONE) { - if(error != NULL) { - snprintf(error, error_len, "No keycode defined for %s", line_tmp); - } - return SCRIPT_STATE_ERROR; - } - if((key & 0xFF00) != 0) { - // It's a modifier key - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - key |= ducky_get_keycode(bad_usb, line_tmp, true); - } - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); - return (0); - } -} - -static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { - if(sscanf(line, "%lX:%lX", &bad_usb->hid_cfg.vid, &bad_usb->hid_cfg.pid) == 2) { - bad_usb->hid_cfg.manuf[0] = '\0'; - bad_usb->hid_cfg.product[0] = '\0'; - - uint8_t id_len = ducky_get_command_len(line); - if(!ducky_is_line_end(line[id_len + 1])) { - sscanf( - &line[id_len + 1], - "%31[^\r\n:]:%31[^\r\n]", - bad_usb->hid_cfg.manuf, - bad_usb->hid_cfg.product); - } - FURI_LOG_D( - WORKER_TAG, - "set id: %04lX:%04lX mfr:%s product:%s", - bad_usb->hid_cfg.vid, - bad_usb->hid_cfg.pid, - bad_usb->hid_cfg.manuf, - bad_usb->hid_cfg.product); - return true; - } - return false; -} - -static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { - uint8_t ret = 0; - uint32_t line_len = 0; - - furi_string_reset(bad_usb->line); - - do { - ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN); - for(uint16_t i = 0; i < ret; i++) { - if(bad_usb->file_buf[i] == '\n' && line_len > 0) { - bad_usb->st.line_nb++; - line_len = 0; - } else { - if(bad_usb->st.line_nb == 0) { // Save first line - furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]); - } - line_len++; - } - } - if(storage_file_eof(script_file)) { - if(line_len > 0) { - bad_usb->st.line_nb++; - break; - } - } - } while(ret > 0); - - const char* line_tmp = furi_string_get_cstr(bad_usb->line); - bool id_set = false; // Looking for ID command at first line - if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { - id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]); - } - - if(id_set) { - furi_check(furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg)); - } else { - furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); - } - - storage_file_seek(script_file, 0, true); - furi_string_reset(bad_usb->line); - - return true; -} - -static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_file) { - int32_t delay_val = 0; - - if(bad_usb->repeat_cnt > 0) { - bad_usb->repeat_cnt--; - delay_val = ducky_parse_line( - bad_usb, bad_usb->line_prev, bad_usb->st.error, sizeof(bad_usb->st.error)); - if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line - return 0; - } else if(delay_val < 0) { // Script error - bad_usb->st.error_line = bad_usb->st.line_cur - 1; - FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur - 1U); - return SCRIPT_STATE_ERROR; - } else { - return (delay_val + bad_usb->defdelay); - } - } - - furi_string_set(bad_usb->line_prev, bad_usb->line); - furi_string_reset(bad_usb->line); - - while(1) { - if(bad_usb->buf_len == 0) { - bad_usb->buf_len = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN); - if(storage_file_eof(script_file)) { - if((bad_usb->buf_len < FILE_BUFFER_LEN) && (bad_usb->file_end == false)) { - bad_usb->file_buf[bad_usb->buf_len] = '\n'; - bad_usb->buf_len++; - bad_usb->file_end = true; - } - } - - bad_usb->buf_start = 0; - if(bad_usb->buf_len == 0) return SCRIPT_STATE_END; - } - for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) { - if(bad_usb->file_buf[i] == '\n' && furi_string_size(bad_usb->line) > 0) { - bad_usb->st.line_cur++; - bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1); - bad_usb->buf_start = i + 1; - furi_string_trim(bad_usb->line); - delay_val = ducky_parse_line( - bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error)); - if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line - return 0; - } else if(delay_val < 0) { - bad_usb->st.error_line = bad_usb->st.line_cur; - FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur); - return SCRIPT_STATE_ERROR; - } else { - return (delay_val + bad_usb->defdelay); - } - } else { - furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]); - } - } - bad_usb->buf_len = 0; - if(bad_usb->file_end) return SCRIPT_STATE_END; - } - - return 0; -} - -static void bad_usb_hid_state_callback(bool state, void* context) { - furi_assert(context); - BadUsbScript* bad_usb = context; - - if(state == true) - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); - else - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect); -} - -static int32_t bad_usb_worker(void* context) { - BadUsbScript* bad_usb = context; - - BadUsbWorkerState worker_state = BadUsbStateInit; - int32_t delay_val = 0; - - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); - - FURI_LOG_I(WORKER_TAG, "Init"); - File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - bad_usb->line = furi_string_alloc(); - bad_usb->line_prev = furi_string_alloc(); - - furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb); - - while(1) { - if(worker_state == BadUsbStateInit) { // State: initialization - if(storage_file_open( - script_file, - furi_string_get_cstr(bad_usb->file_path), - FSAM_READ, - FSOM_OPEN_EXISTING)) { - if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) { - if(furi_hal_hid_is_connected()) { - worker_state = BadUsbStateIdle; // Ready to run - } else { - worker_state = BadUsbStateNotConnected; // USB not connected - } - } else { - worker_state = BadUsbStateScriptError; // Script preload error - } - } else { - FURI_LOG_E(WORKER_TAG, "File open error"); - worker_state = BadUsbStateFileError; // File open error - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, - FuriFlagWaitAny, - FuriWaitForever); - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtConnect) { - worker_state = BadUsbStateIdle; // Ready to run - } else if(flags & WorkerEvtToggle) { - worker_state = BadUsbStateWillRun; // Will run when USB is connected - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateIdle) { // State: ready to start - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, - FuriFlagWaitAny, - FuriWaitForever); - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtToggle) { // Start executing script - DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); - delay_val = 0; - bad_usb->buf_len = 0; - bad_usb->st.line_cur = 0; - bad_usb->defdelay = 0; - bad_usb->repeat_cnt = 0; - bad_usb->file_end = false; - storage_file_seek(script_file, 0, true); - worker_state = BadUsbStateRunning; - } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateWillRun) { // State: start on connection - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, - FuriFlagWaitAny, - FuriWaitForever); - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtConnect) { // Start executing script - DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); - delay_val = 0; - bad_usb->buf_len = 0; - bad_usb->st.line_cur = 0; - bad_usb->defdelay = 0; - bad_usb->repeat_cnt = 0; - bad_usb->file_end = false; - storage_file_seek(script_file, 0, true); - // extra time for PC to recognize Flipper as keyboard - furi_thread_flags_wait(0, FuriFlagWaitAny, 1500); - worker_state = BadUsbStateRunning; - } else if(flags & WorkerEvtToggle) { // Cancel scheduled execution - worker_state = BadUsbStateNotConnected; - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateRunning) { // State: running - uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); - delay_val -= delay_cur; - if(!(flags & FuriFlagError)) { - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtToggle) { - worker_state = BadUsbStateIdle; // Stop executing script - furi_hal_hid_kb_release_all(); - } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected - furi_hal_hid_kb_release_all(); - } - bad_usb->st.state = worker_state; - continue; - } else if( - (flags == (unsigned)FuriFlagErrorTimeout) || - (flags == (unsigned)FuriFlagErrorResource)) { - if(delay_val > 0) { - bad_usb->st.delay_remain--; - continue; - } - bad_usb->st.state = BadUsbStateRunning; - delay_val = ducky_script_execute_next(bad_usb, script_file); - if(delay_val == SCRIPT_STATE_ERROR) { // Script error - delay_val = 0; - worker_state = BadUsbStateScriptError; - bad_usb->st.state = worker_state; - } else if(delay_val == SCRIPT_STATE_END) { // End of script - delay_val = 0; - worker_state = BadUsbStateIdle; - bad_usb->st.state = BadUsbStateDone; - furi_hal_hid_kb_release_all(); - continue; - } else if(delay_val > 1000) { - bad_usb->st.state = BadUsbStateDelay; // Show long delays - bad_usb->st.delay_remain = delay_val / 1000; - } - } else { - furi_check((flags & FuriFlagError) == 0); - } - - } else if( - (worker_state == BadUsbStateFileError) || - (worker_state == BadUsbStateScriptError)) { // State: error - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd, FuriFlagWaitAny, FuriWaitForever); // Waiting for exit command - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } - } - } - - furi_hal_hid_set_state_callback(NULL, NULL); - - furi_hal_usb_set_config(usb_mode_prev, NULL); - - storage_file_close(script_file); - storage_file_free(script_file); - furi_string_free(bad_usb->line); - furi_string_free(bad_usb->line_prev); - - FURI_LOG_I(WORKER_TAG, "End"); - - return 0; -} - -static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - memset(bad_usb->layout, HID_KEYBOARD_NONE, sizeof(bad_usb->layout)); - memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout))); -} - -BadUsbScript* bad_usb_script_open(FuriString* file_path) { - furi_assert(file_path); - - BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); - bad_usb->file_path = furi_string_alloc(); - furi_string_set(bad_usb->file_path, file_path); - bad_usb_script_set_default_keyboard_layout(bad_usb); - - bad_usb->st.state = BadUsbStateInit; - bad_usb->st.error[0] = '\0'; - - bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb); - furi_thread_start(bad_usb->thread); - return bad_usb; -} //-V773 - -void bad_usb_script_close(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd); - furi_thread_join(bad_usb->thread); - furi_thread_free(bad_usb->thread); - furi_string_free(bad_usb->file_path); - free(bad_usb); -} - -void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path) { - furi_assert(bad_usb); - - if((bad_usb->st.state == BadUsbStateRunning) || (bad_usb->st.state == BadUsbStateDelay)) { - // do not update keyboard layout while a script is running - return; - } - - File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - if(!furi_string_empty(layout_path)) { - if(storage_file_open( - layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) { - uint16_t layout[128]; - if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) { - memcpy(bad_usb->layout, layout, sizeof(layout)); - } - } - storage_file_close(layout_file); - } else { - bad_usb_script_set_default_keyboard_layout(bad_usb); - } - storage_file_free(layout_file); -} - -void bad_usb_script_toggle(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle); -} - -BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - return &(bad_usb->st); -} diff --git a/applications/main/bad_usb/bad_usb_script.h b/applications/main/bad_usb/bad_usb_script.h deleted file mode 100644 index 1e4d98fe7..000000000 --- a/applications/main/bad_usb/bad_usb_script.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef struct BadUsbScript BadUsbScript; - -typedef enum { - BadUsbStateInit, - BadUsbStateNotConnected, - BadUsbStateIdle, - BadUsbStateWillRun, - BadUsbStateRunning, - BadUsbStateDelay, - BadUsbStateDone, - BadUsbStateScriptError, - BadUsbStateFileError, -} BadUsbWorkerState; - -typedef struct { - BadUsbWorkerState state; - uint16_t line_cur; - uint16_t line_nb; - uint32_t delay_remain; - uint16_t error_line; - char error[64]; -} BadUsbState; - -BadUsbScript* bad_usb_script_open(FuriString* file_path); - -void bad_usb_script_close(BadUsbScript* bad_usb); - -void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path); - -void bad_usb_script_start(BadUsbScript* bad_usb); - -void bad_usb_script_stop(BadUsbScript* bad_usb); - -void bad_usb_script_toggle(BadUsbScript* bad_usb); - -BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/bad_usb/bad_usb_settings_filename.h b/applications/main/bad_usb/bad_usb_settings_filename.h deleted file mode 100644 index 12ba8f31c..000000000 --- a/applications/main/bad_usb/bad_usb_settings_filename.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings" diff --git a/applications/main/bad_usb/scenes/bad_usb_scene.c b/applications/main/bad_usb/scenes/bad_usb_scene.c deleted file mode 100644 index 03c7c4471..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "bad_usb_scene.h" - -// Generate scene on_enter handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, -void (*const bad_usb_scene_on_enter_handlers[])(void*) = { -#include "bad_usb_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_event handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, -bool (*const bad_usb_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { -#include "bad_usb_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_exit handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, -void (*const bad_usb_scene_on_exit_handlers[])(void* context) = { -#include "bad_usb_scene_config.h" -}; -#undef ADD_SCENE - -// Initialize scene handlers configuration structure -const SceneManagerHandlers bad_usb_scene_handlers = { - .on_enter_handlers = bad_usb_scene_on_enter_handlers, - .on_event_handlers = bad_usb_scene_on_event_handlers, - .on_exit_handlers = bad_usb_scene_on_exit_handlers, - .scene_num = BadUsbSceneNum, -}; diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.c b/applications/main/bad_usb/scenes/bad_usb_scene_config.c deleted file mode 100644 index 2a9f2f76c..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "../bad_usb_app_i.h" -#include "furi_hal_power.h" -#include "furi_hal_usb.h" - -enum SubmenuIndex { - SubmenuIndexKeyboardLayout, -}; - -void bad_usb_scene_config_submenu_callback(void* context, uint32_t index) { - BadUsbApp* bad_usb = context; - view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index); -} - -void bad_usb_scene_config_on_enter(void* context) { - BadUsbApp* bad_usb = context; - Submenu* submenu = bad_usb->submenu; - - submenu_add_item( - submenu, - "Keyboard layout", - SubmenuIndexKeyboardLayout, - bad_usb_scene_config_submenu_callback, - bad_usb); - - submenu_set_selected_item( - submenu, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig)); - - view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig); -} - -bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) { - BadUsbApp* bad_usb = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event); - consumed = true; - if(event.event == SubmenuIndexKeyboardLayout) { - scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout); - } else { - furi_crash("Unknown key type"); - } - } - - return consumed; -} - -void bad_usb_scene_config_on_exit(void* context) { - BadUsbApp* bad_usb = context; - Submenu* submenu = bad_usb->submenu; - - submenu_reset(submenu); -} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.h b/applications/main/bad_usb/scenes/bad_usb_scene_config.h deleted file mode 100644 index 423aedc51..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.h +++ /dev/null @@ -1,5 +0,0 @@ -ADD_SCENE(bad_usb, file_select, FileSelect) -ADD_SCENE(bad_usb, work, Work) -ADD_SCENE(bad_usb, error, Error) -ADD_SCENE(bad_usb, config, Config) -ADD_SCENE(bad_usb, config_layout, ConfigLayout) diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c deleted file mode 100644 index 44dcd55af..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "../bad_usb_app_i.h" -#include "furi_hal_power.h" -#include "furi_hal_usb.h" -#include - -static bool bad_usb_layout_select(BadUsbApp* bad_usb) { - furi_assert(bad_usb); - - FuriString* predefined_path; - predefined_path = furi_string_alloc(); - if(!furi_string_empty(bad_usb->keyboard_layout)) { - furi_string_set(predefined_path, bad_usb->keyboard_layout); - } else { - furi_string_set(predefined_path, BAD_USB_APP_PATH_LAYOUT_FOLDER); - } - - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options( - &browser_options, BAD_USB_APP_LAYOUT_EXTENSION, &I_keyboard_10px); - - // Input events and views are managed by file_browser - bool res = dialog_file_browser_show( - bad_usb->dialogs, bad_usb->keyboard_layout, predefined_path, &browser_options); - - furi_string_free(predefined_path); - return res; -} - -void bad_usb_scene_config_layout_on_enter(void* context) { - BadUsbApp* bad_usb = context; - - if(bad_usb_layout_select(bad_usb)) { - bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); - } - scene_manager_previous_scene(bad_usb->scene_manager); -} - -bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - // BadUsbApp* bad_usb = context; - return false; -} - -void bad_usb_scene_config_layout_on_exit(void* context) { - UNUSED(context); - // BadUsbApp* bad_usb = context; -} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c deleted file mode 100644 index b04669252..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "../bad_usb_app_i.h" -#include -#include -#include - -static bool bad_usb_file_select(BadUsbApp* bad_usb) { - furi_assert(bad_usb); - - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options( - &browser_options, BAD_USB_APP_SCRIPT_EXTENSION, &I_badusb_10px); - browser_options.base_path = BAD_USB_APP_BASE_FOLDER; - browser_options.skip_assets = true; - - // Input events and views are managed by file_browser - bool res = dialog_file_browser_show( - bad_usb->dialogs, bad_usb->file_path, bad_usb->file_path, &browser_options); - - return res; -} - -void bad_usb_scene_file_select_on_enter(void* context) { - BadUsbApp* bad_usb = context; - - furi_hal_usb_disable(); - if(bad_usb->bad_usb_script) { - bad_usb_script_close(bad_usb->bad_usb_script); - bad_usb->bad_usb_script = NULL; - } - - if(bad_usb_file_select(bad_usb)) { - bad_usb->bad_usb_script = bad_usb_script_open(bad_usb->file_path); - bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); - - scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork); - } else { - furi_hal_usb_enable(); - view_dispatcher_stop(bad_usb->view_dispatcher); - } -} - -bool bad_usb_scene_file_select_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - // BadUsbApp* bad_usb = context; - return false; -} - -void bad_usb_scene_file_select_on_exit(void* context) { - UNUSED(context); - // BadUsbApp* bad_usb = context; -} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c deleted file mode 100644 index 187b83bd9..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "../bad_usb_script.h" -#include "../bad_usb_app_i.h" -#include "../views/bad_usb_view.h" -#include -#include "toolbox/path.h" - -void bad_usb_scene_work_button_callback(InputKey key, void* context) { - furi_assert(context); - BadUsbApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, key); -} - -bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { - BadUsbApp* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InputKeyLeft) { - scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig); - consumed = true; - } else if(event.event == InputKeyOk) { - bad_usb_script_toggle(app->bad_usb_script); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeTick) { - bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); - } - return consumed; -} - -void bad_usb_scene_work_on_enter(void* context) { - BadUsbApp* app = context; - - FuriString* file_name; - file_name = furi_string_alloc(); - path_extract_filename(app->file_path, file_name, true); - bad_usb_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name)); - furi_string_free(file_name); - - FuriString* layout; - layout = furi_string_alloc(); - path_extract_filename(app->keyboard_layout, layout, true); - bad_usb_set_layout(app->bad_usb_view, furi_string_get_cstr(layout)); - furi_string_free(layout); - - bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); - - bad_usb_set_button_callback(app->bad_usb_view, bad_usb_scene_work_button_callback, app); - view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWork); -} - -void bad_usb_scene_work_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/main/bad_usb/views/bad_usb_view.h b/applications/main/bad_usb/views/bad_usb_view.h deleted file mode 100644 index 8447fb055..000000000 --- a/applications/main/bad_usb/views/bad_usb_view.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include "../bad_usb_script.h" - -typedef struct BadUsb BadUsb; -typedef void (*BadUsbButtonCallback)(InputKey key, void* context); - -BadUsb* bad_usb_alloc(); - -void bad_usb_free(BadUsb* bad_usb); - -View* bad_usb_get_view(BadUsb* bad_usb); - -void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context); - -void bad_usb_set_file_name(BadUsb* bad_usb, const char* name); - -void bad_usb_set_layout(BadUsb* bad_usb, const char* layout); - -void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st); diff --git a/applications/main/gpio/scenes/gpio_scene_start.c b/applications/main/gpio/scenes/gpio_scene_start.c index e1242ac97..1c1a665c7 100644 --- a/applications/main/gpio/scenes/gpio_scene_start.c +++ b/applications/main/gpio/scenes/gpio_scene_start.c @@ -1,3 +1,6 @@ +#ifndef __GPIO_SCENE_START_H__ +#define __GPIO_SCENE_START_H__ + #include "../gpio_app_i.h" #include #include @@ -118,3 +121,5 @@ void gpio_scene_start_on_exit(void* context) { GpioApp* app = context; variable_item_list_reset(app->var_item_list); } + +#endif // __GPIO_SCENE_START_H__ \ No newline at end of file diff --git a/applications/plugins/dolphinbackup/storage_DolphinBackup.c b/applications/plugins/dolphinbackup/storage_DolphinBackup.c index 02baddc0f..7e7bd8f36 100644 --- a/applications/plugins/dolphinbackup/storage_DolphinBackup.c +++ b/applications/plugins/dolphinbackup/storage_DolphinBackup.c @@ -16,7 +16,7 @@ static const char* app_dirsDolphinBackup[] = { "nfc", "infrared", "ibutton", - "badusb", + "badkb", ".bt.settings", ".desktop.settings", ".dolphin.state", diff --git a/applications/plugins/mousejacker/icons/badusb_10px.png b/applications/plugins/mousejacker/icons/badkb_10px.png similarity index 100% rename from applications/plugins/mousejacker/icons/badusb_10px.png rename to applications/plugins/mousejacker/icons/badkb_10px.png diff --git a/applications/plugins/mousejacker/images/badusb_10px.png b/applications/plugins/mousejacker/images/badkb_10px.png similarity index 100% rename from applications/plugins/mousejacker/images/badusb_10px.png rename to applications/plugins/mousejacker/images/badkb_10px.png diff --git a/applications/plugins/mousejacker/mousejacker.c b/applications/plugins/mousejacker/mousejacker.c index c45b0e502..3bd772889 100644 --- a/applications/plugins/mousejacker/mousejacker.c +++ b/applications/plugins/mousejacker/mousejacker.c @@ -112,7 +112,7 @@ static bool open_ducky_script(Stream* stream, PluginState* plugin_state) { DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options( - &browser_options, MOUSEJACKER_APP_PATH_EXTENSION, &I_badusb_10px); + &browser_options, MOUSEJACKER_APP_PATH_EXTENSION, &I_badkb_10px); browser_options.hide_ext = false; bool ret = dialog_file_browser_show(dialogs, path, path, &browser_options); @@ -396,4 +396,4 @@ int32_t mousejacker_app(void* p) { free(plugin_state); return 0; -} \ No newline at end of file +} diff --git a/applications/plugins/totp/services/config/config.c b/applications/plugins/totp/services/config/config.c index cd19d19d4..c5193ac2e 100644 --- a/applications/plugins/totp/services/config/config.c +++ b/applications/plugins/totp/services/config/config.c @@ -132,7 +132,7 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr( fff_data_file, - "How to notify user when new token is generated or badusb mode is activated (possible values: 0 - do not notify, 1 - sound, 2 - vibro, 3 sound and vibro)"); + "How to notify user when new token is generated or badkb mode is activated (possible values: 0 - do not notify, 1 - sound, 2 - vibro, 3 sound and vibro)"); flipper_format_write_uint32( fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1); @@ -769,4 +769,4 @@ void totp_config_file_reset() { Storage* storage = totp_open_storage(); storage_simply_remove(storage, CONFIG_FILE_PATH); totp_close_storage(); -} \ No newline at end of file +} diff --git a/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c index 41c52b435..18d1791f4 100644 --- a/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -24,7 +24,7 @@ typedef struct { uint32_t last_token_gen_time; TotpTypeCodeWorkerContext* type_code_worker_context; NotificationMessage const** notification_sequence_new_token; - NotificationMessage const** notification_sequence_badusb; + NotificationMessage const** notification_sequence_badkb; } SceneState; static const NotificationSequence* @@ -69,8 +69,8 @@ static const NotificationSequence* } static const NotificationSequence* - get_notification_sequence_badusb(const PluginState* plugin_state, SceneState* scene_state) { - if(scene_state->notification_sequence_badusb == NULL) { + get_notification_sequence_badkb(const PluginState* plugin_state, SceneState* scene_state) { + if(scene_state->notification_sequence_badkb == NULL) { uint8_t i = 0; uint8_t length = 3; if(plugin_state->notification_method & NotificationMethodVibro) { @@ -81,36 +81,36 @@ static const NotificationSequence* length += 6; } - scene_state->notification_sequence_badusb = malloc(sizeof(void*) * length); - furi_check(scene_state->notification_sequence_badusb != NULL); + scene_state->notification_sequence_badkb = malloc(sizeof(void*) * length); + furi_check(scene_state->notification_sequence_badkb != NULL); - scene_state->notification_sequence_badusb[i++] = &message_blue_255; + scene_state->notification_sequence_badkb[i++] = &message_blue_255; if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_badusb[i++] = &message_vibro_on; + scene_state->notification_sequence_badkb[i++] = &message_vibro_on; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_badusb[i++] = &message_note_d5; //-V525 - scene_state->notification_sequence_badusb[i++] = &message_delay_50; - scene_state->notification_sequence_badusb[i++] = &message_note_e4; - scene_state->notification_sequence_badusb[i++] = &message_delay_50; - scene_state->notification_sequence_badusb[i++] = &message_note_f3; + scene_state->notification_sequence_badkb[i++] = &message_note_d5; //-V525 + scene_state->notification_sequence_badkb[i++] = &message_delay_50; + scene_state->notification_sequence_badkb[i++] = &message_note_e4; + scene_state->notification_sequence_badkb[i++] = &message_delay_50; + scene_state->notification_sequence_badkb[i++] = &message_note_f3; } - scene_state->notification_sequence_badusb[i++] = &message_delay_50; + scene_state->notification_sequence_badkb[i++] = &message_delay_50; if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_badusb[i++] = &message_vibro_off; + scene_state->notification_sequence_badkb[i++] = &message_vibro_off; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_badusb[i++] = &message_sound_off; + scene_state->notification_sequence_badkb[i++] = &message_sound_off; } - scene_state->notification_sequence_badusb[i++] = NULL; + scene_state->notification_sequence_badkb[i++] = NULL; } - return (NotificationSequence*)scene_state->notification_sequence_badusb; + return (NotificationSequence*)scene_state->notification_sequence_badkb; } static void int_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) { @@ -340,7 +340,7 @@ bool totp_scene_generate_token_handle_event( scene_state->type_code_worker_context, TotpTypeCodeWorkerEventType); notification_message( plugin_state->notification_app, - get_notification_sequence_badusb(plugin_state, scene_state)); + get_notification_sequence_badkb(plugin_state, scene_state)); return true; } @@ -399,8 +399,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { free(scene_state->notification_sequence_new_token); } - if(scene_state->notification_sequence_badusb != NULL) { - free(scene_state->notification_sequence_badusb); + if(scene_state->notification_sequence_badkb != NULL) { + free(scene_state->notification_sequence_badkb); } free(scene_state); diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index 3f1577751..7abef0e68 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -77,6 +77,8 @@ static void bt_pin_code_hide(Bt* bt) { static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) { furi_assert(bt); + if(bt_get_profile_pairing_method(bt) == GapPairingNone) return true; + notification_message(bt->notification, &sequence_display_backlight_on); FuriString* pin_str; dialog_message_set_icon(bt->dialog_message, XTREME_ASSETS()->I_BLE_Pairing_128x64, 0, 0); @@ -86,6 +88,7 @@ static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) { dialog_message_set_buttons(bt->dialog_message, "Cancel", "OK", NULL); DialogMessageButton button = dialog_message_show(bt->dialogs, bt->dialog_message); furi_string_free(pin_str); + return button == DialogMessageButtonCenter; } @@ -370,6 +373,87 @@ static void bt_close_connection(Bt* bt) { furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT); } +static inline FuriHalBtProfile get_hal_bt_profile(BtProfile profile) { + if(profile == BtProfileHidKeyboard) { + return FuriHalBtProfileHidKeyboard; + } else { + return FuriHalBtProfileSerial; + } +} + +static void bt_restart(Bt* bt) { + furi_hal_bt_change_app(get_hal_bt_profile(bt->profile), bt_on_gap_event_callback, bt); + furi_hal_bt_start_advertising(); +} + +void bt_set_profile_adv_name(Bt* bt, const char* fmt, ...) { + furi_assert(bt); + furi_assert(fmt); + + char name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; + va_list args; + va_start(args, fmt); + vsnprintf(name, sizeof(name), fmt, args); + va_end(args); + furi_hal_bt_set_profile_adv_name(get_hal_bt_profile(bt->profile), name); + + bt_restart(bt); +} + +const char* bt_get_profile_adv_name(Bt* bt) { + furi_assert(bt); + return furi_hal_bt_get_profile_adv_name(get_hal_bt_profile(bt->profile)); +} + +void bt_set_profile_mac_address(Bt* bt, const uint8_t mac[6]) { + furi_assert(bt); + furi_assert(mac); + + furi_hal_bt_set_profile_mac_addr(get_hal_bt_profile(bt->profile), mac); + + bt_restart(bt); +} + +const uint8_t* bt_get_profile_mac_address(Bt* bt) { + furi_assert(bt); + return furi_hal_bt_get_profile_mac_addr(get_hal_bt_profile(bt->profile)); +} + +bool bt_remote_rssi(Bt* bt, BtRssi* rssi) { + furi_assert(bt); + UNUSED(rssi); + + uint8_t rssi_val; + uint32_t since = furi_hal_bt_get_conn_rssi(&rssi_val); + + if(since == 0) return false; + + rssi->rssi = rssi_val; + rssi->since = since; + + return true; +} + +void bt_set_profile_pairing_method(Bt* bt, GapPairing pairing_method) { + furi_assert(bt); + furi_hal_bt_set_profile_pairing_method(get_hal_bt_profile(bt->profile), pairing_method); + bt_restart(bt); +} + +GapPairing bt_get_profile_pairing_method(Bt* bt) { + furi_assert(bt); + return furi_hal_bt_get_profile_pairing_method(get_hal_bt_profile(bt->profile)); +} + +void bt_disable_peer_key_update(Bt* bt) { + UNUSED(bt); + furi_hal_bt_set_key_storage_change_callback(NULL, NULL); +} + +void bt_enable_peer_key_update(Bt* bt) { + furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); +} + int32_t bt_srv(void* p) { UNUSED(p); Bt* bt = bt_alloc(); diff --git a/applications/services/bt/bt_service/bt.h b/applications/services/bt/bt_service/bt.h index ca47936db..a79c227f7 100644 --- a/applications/services/bt/bt_service/bt.h +++ b/applications/services/bt/bt_service/bt.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -23,6 +24,11 @@ typedef enum { BtProfileHidKeyboard, } BtProfile; +typedef struct { + uint8_t rssi; + uint32_t since; +} BtRssi; + typedef void (*BtStatusChangedCallback)(BtStatus status, void* context); /** Change BLE Profile @@ -35,6 +41,28 @@ typedef void (*BtStatusChangedCallback)(BtStatus status, void* context); */ bool bt_set_profile(Bt* bt, BtProfile profile); +void bt_set_profile_adv_name(Bt* bt, const char* fmt, ...); +const char* bt_get_profile_adv_name(Bt* bt); + +void bt_set_profile_mac_address(Bt* bt, const uint8_t mac[6]); +const uint8_t* bt_get_profile_mac_address(Bt* bt); + +bool bt_remote_rssi(Bt* bt, BtRssi* rssi); + +void bt_set_profile_pairing_method(Bt* bt, GapPairing pairing_method); +GapPairing bt_get_profile_pairing_method(Bt* bt); + +/** Stop saving new peer key to flash (in .bt.keys file) + * +*/ +void bt_disable_peer_key_update(Bt* bt); + +/** Enable saving peer key to internal flash (enable by default) + * + * @note This function should be called if bt_disable_peer_key_update was called before +*/ +void bt_enable_peer_key_update(Bt* bt); + /** Disconnect from Central * * @param bt Bt instance diff --git a/applications/services/dolphin/helpers/dolphin_deed.c b/applications/services/dolphin/helpers/dolphin_deed.c index 51db56fdf..4b9f11599 100644 --- a/applications/services/dolphin/helpers/dolphin_deed.c +++ b/applications/services/dolphin/helpers/dolphin_deed.c @@ -34,7 +34,7 @@ static const DolphinDeedWeight dolphin_deed_weights[] = { {2, DolphinAppIbutton}, // DolphinDeedIbuttonEmulate {2, DolphinAppIbutton}, // DolphinDeedIbuttonAdd - {3, DolphinAppBadusb}, // DolphinDeedBadUsbPlayScript + {3, DolphinAppBadKb}, // DolphinDeedBadKbPlayScript {3, DolphinAppPlugin}, // DolphinDeedU2fAuthorized {1, DolphinAppPlugin}, // DolphinDeedGpioUartBridge @@ -50,7 +50,7 @@ static uint8_t dolphin_deed_limits[] = { 20, // DolphinAppNfc 20, // DolphinAppIr 20, // DolphinAppIbutton - 20, // DolphinAppBadusb + 20, // DolphinAppBadKb 20, // DolphinAppPlugin }; diff --git a/applications/services/dolphin/helpers/dolphin_deed.h b/applications/services/dolphin/helpers/dolphin_deed.h index c9cd18f31..51adf6b20 100644 --- a/applications/services/dolphin/helpers/dolphin_deed.h +++ b/applications/services/dolphin/helpers/dolphin_deed.h @@ -12,7 +12,7 @@ typedef enum { DolphinAppNfc, DolphinAppIr, DolphinAppIbutton, - DolphinAppBadusb, + DolphinAppBadKb, DolphinAppPlugin, DolphinAppMAX, } DolphinApp; @@ -50,7 +50,7 @@ typedef enum { DolphinDeedIbuttonEmulate, DolphinDeedIbuttonAdd, - DolphinDeedBadUsbPlayScript, + DolphinDeedBadKbPlayScript, DolphinDeedU2fAuthorized, DolphinDeedGpioUartBridge, diff --git a/assets/icons/Archive/badusb_10px.png b/assets/icons/Archive/badkb_10px.png similarity index 100% rename from assets/icons/Archive/badusb_10px.png rename to assets/icons/Archive/badkb_10px.png diff --git a/assets/icons/BadUsb/Clock_18x18.png b/assets/icons/BadKb/Clock_18x18.png similarity index 100% rename from assets/icons/BadUsb/Clock_18x18.png rename to assets/icons/BadKb/Clock_18x18.png diff --git a/assets/icons/BadUsb/Error_18x18.png b/assets/icons/BadKb/Error_18x18.png similarity index 100% rename from assets/icons/BadUsb/Error_18x18.png rename to assets/icons/BadKb/Error_18x18.png diff --git a/assets/icons/BadUsb/EviSmile1_18x21.png b/assets/icons/BadKb/EviSmile1_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviSmile1_18x21.png rename to assets/icons/BadKb/EviSmile1_18x21.png diff --git a/assets/icons/BadUsb/EviSmile2_18x21.png b/assets/icons/BadKb/EviSmile2_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviSmile2_18x21.png rename to assets/icons/BadKb/EviSmile2_18x21.png diff --git a/assets/icons/BadUsb/EviWaiting1_18x21.png b/assets/icons/BadKb/EviWaiting1_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviWaiting1_18x21.png rename to assets/icons/BadKb/EviWaiting1_18x21.png diff --git a/assets/icons/BadUsb/EviWaiting2_18x21.png b/assets/icons/BadKb/EviWaiting2_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviWaiting2_18x21.png rename to assets/icons/BadKb/EviWaiting2_18x21.png diff --git a/assets/icons/BadUsb/Percent_10x14.png b/assets/icons/BadKb/Percent_10x14.png similarity index 100% rename from assets/icons/BadUsb/Percent_10x14.png rename to assets/icons/BadKb/Percent_10x14.png diff --git a/assets/icons/BadUsb/Smile_18x18.png b/assets/icons/BadKb/Smile_18x18.png similarity index 100% rename from assets/icons/BadUsb/Smile_18x18.png rename to assets/icons/BadKb/Smile_18x18.png diff --git a/assets/icons/BadUsb/UsbTree_48x22.png b/assets/icons/BadKb/UsbTree_48x22.png similarity index 100% rename from assets/icons/BadUsb/UsbTree_48x22.png rename to assets/icons/BadKb/UsbTree_48x22.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_01.png b/assets/icons/MainMenu/BadKb_14/frame_01.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_01.png rename to assets/icons/MainMenu/BadKb_14/frame_01.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_02.png b/assets/icons/MainMenu/BadKb_14/frame_02.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_02.png rename to assets/icons/MainMenu/BadKb_14/frame_02.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_03.png b/assets/icons/MainMenu/BadKb_14/frame_03.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_03.png rename to assets/icons/MainMenu/BadKb_14/frame_03.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_04.png b/assets/icons/MainMenu/BadKb_14/frame_04.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_04.png rename to assets/icons/MainMenu/BadKb_14/frame_04.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_05.png b/assets/icons/MainMenu/BadKb_14/frame_05.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_05.png rename to assets/icons/MainMenu/BadKb_14/frame_05.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_06.png b/assets/icons/MainMenu/BadKb_14/frame_06.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_06.png rename to assets/icons/MainMenu/BadKb_14/frame_06.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_07.png b/assets/icons/MainMenu/BadKb_14/frame_07.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_07.png rename to assets/icons/MainMenu/BadKb_14/frame_07.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_08.png b/assets/icons/MainMenu/BadKb_14/frame_08.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_08.png rename to assets/icons/MainMenu/BadKb_14/frame_08.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_09.png b/assets/icons/MainMenu/BadKb_14/frame_09.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_09.png rename to assets/icons/MainMenu/BadKb_14/frame_09.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_10.png b/assets/icons/MainMenu/BadKb_14/frame_10.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_10.png rename to assets/icons/MainMenu/BadKb_14/frame_10.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_11.png b/assets/icons/MainMenu/BadKb_14/frame_11.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_11.png rename to assets/icons/MainMenu/BadKb_14/frame_11.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_rate b/assets/icons/MainMenu/BadKb_14/frame_rate similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_rate rename to assets/icons/MainMenu/BadKb_14/frame_rate diff --git a/assets/resources/badkb/.badkb.settings b/assets/resources/badkb/.badkb.settings new file mode 100644 index 000000000..4841c2ded --- /dev/null +++ b/assets/resources/badkb/.badkb.settings @@ -0,0 +1 @@ +/any/badkb/layouts/en-US.kl diff --git a/assets/resources/badusb/Kiosk-Evasion-Bruteforce.txt b/assets/resources/badkb/Kiosk-Evasion-Bruteforce.txt similarity index 100% rename from assets/resources/badusb/Kiosk-Evasion-Bruteforce.txt rename to assets/resources/badkb/Kiosk-Evasion-Bruteforce.txt diff --git a/assets/resources/badusb/Wifi-Stealer_ORG.txt b/assets/resources/badkb/Wifi-Stealer_ORG.txt similarity index 100% rename from assets/resources/badusb/Wifi-Stealer_ORG.txt rename to assets/resources/badkb/Wifi-Stealer_ORG.txt diff --git a/assets/resources/badusb/demo_macos.txt b/assets/resources/badkb/demo_macos.txt similarity index 92% rename from assets/resources/badusb/demo_macos.txt rename to assets/resources/badkb/demo_macos.txt index 82543b28f..1fd4544b3 100644 --- a/assets/resources/badusb/demo_macos.txt +++ b/assets/resources/badkb/demo_macos.txt @@ -2,7 +2,7 @@ ID 1234:5678 Apple:Keyboard REM You can change these values to VID/PID of original Apple keyboard REM to bypass Keyboard Setup Assistant -REM This is BadUSB demo script for macOS +REM This is BadKB demo script for macOS REM Open terminal window DELAY 1000 @@ -75,7 +75,7 @@ ENTER HOME ENTER -STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format +STRING Flipper Zero BadKB feature is compatible with USB Rubber Ducky script format ENTER STRING More information about script syntax can be found here: ENTER diff --git a/assets/resources/badusb/demo_windows.txt b/assets/resources/badkb/demo_windows.txt similarity index 92% rename from assets/resources/badusb/demo_windows.txt rename to assets/resources/badkb/demo_windows.txt index 2ed33b3c0..f3b1309d1 100644 --- a/assets/resources/badusb/demo_windows.txt +++ b/assets/resources/badkb/demo_windows.txt @@ -1,4 +1,4 @@ -REM This is BadUSB demo script for windows +REM This is BadKB demo script for windows REM Open windows notepad DELAY 1000 @@ -76,7 +76,7 @@ ENTER HOME ENTER -STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format +STRING Flipper Zero BadKB feature is compatible with USB Rubber Ducky script format ENTER STRING More information about script syntax can be found here: ENTER diff --git a/assets/resources/badusb/assets/layouts/ba-BA.kl b/assets/resources/badkb/layouts/ba-BA.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/ba-BA.kl rename to assets/resources/badkb/layouts/ba-BA.kl diff --git a/assets/resources/badusb/assets/layouts/cz_CS.kl b/assets/resources/badkb/layouts/cz_CS.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/cz_CS.kl rename to assets/resources/badkb/layouts/cz_CS.kl diff --git a/assets/resources/badusb/assets/layouts/da-DA.kl b/assets/resources/badkb/layouts/da-DA.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/da-DA.kl rename to assets/resources/badkb/layouts/da-DA.kl diff --git a/assets/resources/badusb/assets/layouts/de-CH.kl b/assets/resources/badkb/layouts/de-CH.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/de-CH.kl rename to assets/resources/badkb/layouts/de-CH.kl diff --git a/assets/resources/badusb/assets/layouts/de-DE.kl b/assets/resources/badkb/layouts/de-DE.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/de-DE.kl rename to assets/resources/badkb/layouts/de-DE.kl diff --git a/assets/resources/badusb/assets/layouts/dvorak.kl b/assets/resources/badkb/layouts/dvorak.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/dvorak.kl rename to assets/resources/badkb/layouts/dvorak.kl diff --git a/assets/resources/badusb/assets/layouts/en-UK.kl b/assets/resources/badkb/layouts/en-UK.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/en-UK.kl rename to assets/resources/badkb/layouts/en-UK.kl diff --git a/assets/resources/badusb/assets/layouts/en-US.kl b/assets/resources/badkb/layouts/en-US.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/en-US.kl rename to assets/resources/badkb/layouts/en-US.kl diff --git a/assets/resources/badusb/assets/layouts/es-ES.kl b/assets/resources/badkb/layouts/es-ES.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/es-ES.kl rename to assets/resources/badkb/layouts/es-ES.kl diff --git a/assets/resources/badusb/assets/layouts/fr-BE.kl b/assets/resources/badkb/layouts/fr-BE.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-BE.kl rename to assets/resources/badkb/layouts/fr-BE.kl diff --git a/assets/resources/badusb/assets/layouts/fr-CH.kl b/assets/resources/badkb/layouts/fr-CH.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-CH.kl rename to assets/resources/badkb/layouts/fr-CH.kl diff --git a/assets/resources/badusb/assets/layouts/fr-FR.kl b/assets/resources/badkb/layouts/fr-FR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-FR.kl rename to assets/resources/badkb/layouts/fr-FR.kl diff --git a/assets/resources/badusb/assets/layouts/hr-HR.kl b/assets/resources/badkb/layouts/hr-HR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/hr-HR.kl rename to assets/resources/badkb/layouts/hr-HR.kl diff --git a/assets/resources/badusb/assets/layouts/hu-HU.kl b/assets/resources/badkb/layouts/hu-HU.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/hu-HU.kl rename to assets/resources/badkb/layouts/hu-HU.kl diff --git a/assets/resources/badusb/assets/layouts/it-IT.kl b/assets/resources/badkb/layouts/it-IT.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/it-IT.kl rename to assets/resources/badkb/layouts/it-IT.kl diff --git a/assets/resources/badusb/assets/layouts/nb-NO.kl b/assets/resources/badkb/layouts/nb-NO.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/nb-NO.kl rename to assets/resources/badkb/layouts/nb-NO.kl diff --git a/assets/resources/badusb/assets/layouts/nl-NL.kl b/assets/resources/badkb/layouts/nl-NL.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/nl-NL.kl rename to assets/resources/badkb/layouts/nl-NL.kl diff --git a/assets/resources/badusb/assets/layouts/pt-BR.kl b/assets/resources/badkb/layouts/pt-BR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/pt-BR.kl rename to assets/resources/badkb/layouts/pt-BR.kl diff --git a/assets/resources/badusb/assets/layouts/pt-PT.kl b/assets/resources/badkb/layouts/pt-PT.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/pt-PT.kl rename to assets/resources/badkb/layouts/pt-PT.kl diff --git a/assets/resources/badusb/assets/layouts/si-SI.kl b/assets/resources/badkb/layouts/si-SI.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/si-SI.kl rename to assets/resources/badkb/layouts/si-SI.kl diff --git a/assets/resources/badusb/assets/layouts/sk-SK.kl b/assets/resources/badkb/layouts/sk-SK.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/sk-SK.kl rename to assets/resources/badkb/layouts/sk-SK.kl diff --git a/assets/resources/badusb/assets/layouts/sv-SE.kl b/assets/resources/badkb/layouts/sv-SE.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/sv-SE.kl rename to assets/resources/badkb/layouts/sv-SE.kl diff --git a/assets/resources/badusb/assets/layouts/tr-TR.kl b/assets/resources/badkb/layouts/tr-TR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/tr-TR.kl rename to assets/resources/badkb/layouts/tr-TR.kl diff --git a/assets/resources/badusb/.badusb.settings b/assets/resources/badusb/.badusb.settings deleted file mode 100644 index 34330a3c0..000000000 --- a/assets/resources/badusb/.badusb.settings +++ /dev/null @@ -1 +0,0 @@ -/any/badusb/layouts/en-US.kl diff --git a/assets/resources/badusb/layouts/ba-BA.kl b/assets/resources/badusb/layouts/ba-BA.kl deleted file mode 100644 index 379f6c649..000000000 Binary files a/assets/resources/badusb/layouts/ba-BA.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/cz_CS.kl b/assets/resources/badusb/layouts/cz_CS.kl deleted file mode 100644 index d42e9a4ab..000000000 Binary files a/assets/resources/badusb/layouts/cz_CS.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/da-DA.kl b/assets/resources/badusb/layouts/da-DA.kl deleted file mode 100644 index b3fcc6a99..000000000 Binary files a/assets/resources/badusb/layouts/da-DA.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/de-CH.kl b/assets/resources/badusb/layouts/de-CH.kl deleted file mode 100644 index 1704bc9db..000000000 Binary files a/assets/resources/badusb/layouts/de-CH.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/de-DE.kl b/assets/resources/badusb/layouts/de-DE.kl deleted file mode 100644 index 67b05c042..000000000 Binary files a/assets/resources/badusb/layouts/de-DE.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/dvorak.kl b/assets/resources/badusb/layouts/dvorak.kl deleted file mode 100644 index 06b519240..000000000 Binary files a/assets/resources/badusb/layouts/dvorak.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/en-UK.kl b/assets/resources/badusb/layouts/en-UK.kl deleted file mode 100644 index 0f18b39cc..000000000 Binary files a/assets/resources/badusb/layouts/en-UK.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/en-US.kl b/assets/resources/badusb/layouts/en-US.kl deleted file mode 100644 index 8089d8257..000000000 Binary files a/assets/resources/badusb/layouts/en-US.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/es-ES.kl b/assets/resources/badusb/layouts/es-ES.kl deleted file mode 100644 index 15e9d7997..000000000 Binary files a/assets/resources/badusb/layouts/es-ES.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/fr-BE.kl b/assets/resources/badusb/layouts/fr-BE.kl deleted file mode 100644 index ea9e553e8..000000000 Binary files a/assets/resources/badusb/layouts/fr-BE.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/fr-CH.kl b/assets/resources/badusb/layouts/fr-CH.kl deleted file mode 100644 index 1704bc9db..000000000 Binary files a/assets/resources/badusb/layouts/fr-CH.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/fr-FR.kl b/assets/resources/badusb/layouts/fr-FR.kl deleted file mode 100644 index f9193297e..000000000 Binary files a/assets/resources/badusb/layouts/fr-FR.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/hr-HR.kl b/assets/resources/badusb/layouts/hr-HR.kl deleted file mode 100644 index 379f6c649..000000000 Binary files a/assets/resources/badusb/layouts/hr-HR.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/hu-HU.kl b/assets/resources/badusb/layouts/hu-HU.kl deleted file mode 100644 index 90a68e328..000000000 Binary files a/assets/resources/badusb/layouts/hu-HU.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/it-IT.kl b/assets/resources/badusb/layouts/it-IT.kl deleted file mode 100644 index 059e42880..000000000 Binary files a/assets/resources/badusb/layouts/it-IT.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/nb-NO.kl b/assets/resources/badusb/layouts/nb-NO.kl deleted file mode 100644 index 381945bf2..000000000 Binary files a/assets/resources/badusb/layouts/nb-NO.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/nl-NL.kl b/assets/resources/badusb/layouts/nl-NL.kl deleted file mode 100644 index 597d1db8c..000000000 Binary files a/assets/resources/badusb/layouts/nl-NL.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/pt-BR.kl b/assets/resources/badusb/layouts/pt-BR.kl deleted file mode 100644 index d36421cfc..000000000 Binary files a/assets/resources/badusb/layouts/pt-BR.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/pt-PT.kl b/assets/resources/badusb/layouts/pt-PT.kl deleted file mode 100644 index 02450419a..000000000 Binary files a/assets/resources/badusb/layouts/pt-PT.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/si-SI.kl b/assets/resources/badusb/layouts/si-SI.kl deleted file mode 100644 index 379f6c649..000000000 Binary files a/assets/resources/badusb/layouts/si-SI.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/sk-SK.kl b/assets/resources/badusb/layouts/sk-SK.kl deleted file mode 100755 index 0c67458a6..000000000 Binary files a/assets/resources/badusb/layouts/sk-SK.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/sv-SE.kl b/assets/resources/badusb/layouts/sv-SE.kl deleted file mode 100644 index 5c55bb9ef..000000000 Binary files a/assets/resources/badusb/layouts/sv-SE.kl and /dev/null differ diff --git a/assets/resources/badusb/layouts/tr-TR.kl b/assets/resources/badusb/layouts/tr-TR.kl deleted file mode 100644 index 6377b7703..000000000 Binary files a/assets/resources/badusb/layouts/tr-TR.kl and /dev/null differ diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index d229192fd..55773064f 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,15.1,, +Version,+,17.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -579,11 +579,20 @@ Function,+,ble_glue_start,_Bool, Function,+,ble_glue_thread_stop,void, Function,+,ble_glue_wait_for_c2_start,_Bool,int32_t Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t" +Function,+,bt_disable_peer_key_update,void,Bt* Function,+,bt_disconnect,void,Bt* +Function,+,bt_enable_peer_key_update,void,Bt* Function,+,bt_forget_bonded_devices,void,Bt* +Function,+,bt_get_profile_adv_name,const char*,Bt* +Function,+,bt_get_profile_mac_address,const uint8_t*,Bt* +Function,+,bt_get_profile_pairing_method,GapPairing,Bt* Function,+,bt_keys_storage_set_default_path,void,Bt* Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*" +Function,+,bt_remote_rssi,_Bool,"Bt*, BtRssi*" Function,+,bt_set_profile,_Bool,"Bt*, BtProfile" +Function,+,bt_set_profile_adv_name,void,"Bt*, const char*, ..." +Function,+,bt_set_profile_mac_address,void,"Bt*, const uint8_t[6]" +Function,+,bt_set_profile_pairing_method,void,"Bt*, GapPairing" Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*" Function,+,buffered_file_stream_alloc,Stream*,Storage* Function,+,buffered_file_stream_close,_Bool,Stream* @@ -1007,13 +1016,18 @@ Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, voi Function,+,furi_hal_bt_clear_white_list,_Bool, Function,+,furi_hal_bt_dump_state,void,FuriString* Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode +Function,+,furi_hal_bt_get_conn_rssi,uint32_t,uint8_t* Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" +Function,+,furi_hal_bt_get_profile_adv_name,const char*,FuriHalBtProfile +Function,+,furi_hal_bt_get_profile_mac_addr,const uint8_t*,FuriHalBtProfile +Function,+,furi_hal_bt_get_profile_pairing_method,GapPairing,FuriHalBtProfile Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, Function,+,furi_hal_bt_get_rssi,float, Function,+,furi_hal_bt_get_transmitted_packets,uint32_t, Function,+,furi_hal_bt_hid_consumer_key_press,_Bool,uint16_t Function,+,furi_hal_bt_hid_consumer_key_release,_Bool,uint16_t Function,+,furi_hal_bt_hid_consumer_key_release_all,_Bool, +Function,+,furi_hal_bt_hid_get_led_state,uint8_t, Function,+,furi_hal_bt_hid_kb_press,_Bool,uint16_t Function,+,furi_hal_bt_hid_kb_release,_Bool,uint16_t Function,+,furi_hal_bt_hid_kb_release_all,_Bool, @@ -1028,6 +1042,7 @@ Function,-,furi_hal_bt_init,void, Function,+,furi_hal_bt_is_active,_Bool, Function,+,furi_hal_bt_is_alive,_Bool, Function,+,furi_hal_bt_is_ble_gatt_gap_supported,_Bool, +Function,+,furi_hal_bt_is_connected,_Bool, Function,+,furi_hal_bt_is_testing_supported,_Bool, Function,+,furi_hal_bt_lock_core2,void, Function,+,furi_hal_bt_nvm_sram_sem_acquire,void, @@ -1040,6 +1055,9 @@ Function,+,furi_hal_bt_serial_start,void, Function,+,furi_hal_bt_serial_stop,void, Function,+,furi_hal_bt_serial_tx,_Bool,"uint8_t*, uint16_t" Function,+,furi_hal_bt_set_key_storage_change_callback,void,"BleGlueKeyStorageChangedCallback, void*" +Function,+,furi_hal_bt_set_profile_adv_name,void,"FuriHalBtProfile, const char[( 1 + ( 8 + 1 ) ) + 9 - 1]" +Function,+,furi_hal_bt_set_profile_mac_addr,void,"FuriHalBtProfile, const uint8_t[( 6 )]" +Function,+,furi_hal_bt_set_profile_pairing_method,void,"FuriHalBtProfile, GapPairing" Function,+,furi_hal_bt_start_advertising,void, Function,+,furi_hal_bt_start_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" Function,+,furi_hal_bt_start_packet_rx,void,"uint8_t, uint8_t" @@ -1595,6 +1613,7 @@ Function,-,gamma,double,double Function,-,gamma_r,double,"double, int*" Function,-,gammaf,float,float Function,-,gammaf_r,float,"float, int*" +Function,+,gap_get_remote_conn_rssi,uint32_t,int8_t* Function,-,gap_get_state,GapState, Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" Function,-,gap_start_advertising,void, @@ -3040,12 +3059,12 @@ Function,-,subghz_protocol_decoder_star_line_free,void,void* Function,-,subghz_protocol_decoder_star_line_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_star_line_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_star_line_reset,void,void* +Function,-,subghz_protocol_decoder_star_line_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_encoder_alutech_at_4n_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_alutech_at_4n_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_alutech_at_4n_free,void,void* Function,-,subghz_protocol_encoder_alutech_at_4n_stop,void,void* Function,-,subghz_protocol_encoder_alutech_at_4n_yield,LevelDuration,void* -Function,-,subghz_protocol_decoder_star_line_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_encoder_ansonic_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_ansonic_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_ansonic_free,void,void* diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index 8ef037d6b..83944b4b5 100644 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -27,6 +27,8 @@ typedef struct { GapConfig* config; GapConnectionParams connection_params; GapState state; + int8_t conn_rssi; + uint32_t time_rssi_sample; FuriMutex* state_mutex; GapEventCallback on_event_cb; void* context; @@ -52,6 +54,19 @@ static const uint8_t gap_erk[16] = static Gap* gap = NULL; +/** function for updating rssi informations in global Gap object + * +*/ +static inline void fetch_rssi() { + uint8_t ret_rssi = 127; + if(hci_read_rssi(gap->service.connection_handle, &ret_rssi) == BLE_STATUS_SUCCESS) { + gap->conn_rssi = (int8_t)ret_rssi; + gap->time_rssi_sample = furi_get_tick(); + return; + } + FURI_LOG_D(TAG, "Failed to read RSSI"); +} + static void gap_advertise_start(GapState new_state); static int32_t gap_app(void* context); @@ -125,6 +140,9 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { gap->connection_params.supervisor_timeout = event->Supervision_Timeout; FURI_LOG_I(TAG, "Connection parameters event complete"); gap_verify_connection_parameters(gap); + + // save rssi for current connection + fetch_rssi(); break; } @@ -159,6 +177,9 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { gap->service.connection_handle = event->Connection_Handle; gap_verify_connection_parameters(gap); + + fetch_rssi(); + // Start pairing by sending security request aci_gap_slave_security_req(event->Connection_Handle); } break; @@ -243,6 +264,8 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { pairing_complete->Status); aci_gap_terminate(gap->service.connection_handle, 5); } else { + fetch_rssi(); + FURI_LOG_I(TAG, "Pairing complete"); GapEvent event = {.type = GapEventTypeConnected}; gap->on_event_cb(event, gap->context); //-V595 @@ -313,7 +336,7 @@ static void gap_init_svc(Gap* gap) { // Initialize GATT interface aci_gatt_init(); // Initialize GAP interface - // Skip fist symbol AD_TYPE_COMPLETE_LOCAL_NAME + // Skip first symbol AD_TYPE_COMPLETE_LOCAL_NAME char* name = gap->service.adv_name + 1; aci_gap_init( GAP_PERIPHERAL_ROLE, @@ -348,21 +371,31 @@ static void gap_init_svc(Gap* gap) { hci_le_set_default_phy(ALL_PHYS_PREFERENCE, TX_2M_PREFERRED, RX_2M_PREFERRED); // Set I/O capability bool keypress_supported = false; + uint8_t conf_mitm = CFG_MITM_PROTECTION; + uint8_t conf_used_fixed_pin = CFG_USED_FIXED_PIN; if(gap->config->pairing_method == GapPairingPinCodeShow) { aci_gap_set_io_capability(IO_CAP_DISPLAY_ONLY); } else if(gap->config->pairing_method == GapPairingPinCodeVerifyYesNo) { aci_gap_set_io_capability(IO_CAP_DISPLAY_YES_NO); keypress_supported = true; + } else if(gap->config->pairing_method == GapPairingNone) { + // Just works pairing method (IOS accept it, it seems android and linux doesn't) + conf_mitm = 0; + conf_used_fixed_pin = 0; + // if just works isn't supported, we want the numeric comparaison method + aci_gap_set_io_capability(IO_CAP_DISPLAY_YES_NO); + keypress_supported = true; } + // Setup authentication aci_gap_set_authentication_requirement( gap->config->bonding_mode, - CFG_MITM_PROTECTION, + conf_mitm, CFG_SC_SUPPORT, keypress_supported, CFG_ENCRYPTION_KEY_SIZE_MIN, CFG_ENCRYPTION_KEY_SIZE_MAX, - CFG_USED_FIXED_PIN, + conf_used_fixed_pin, // 0x0 for no pin 0, PUBLIC_ADDR); // Configure whitelist @@ -482,6 +515,16 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { gap->advertise_timer = furi_timer_alloc(gap_advetise_timer_callback, FuriTimerTypeOnce, NULL); // Initialization of GATT & GAP layer gap->service.adv_name = config->adv_name; + FURI_LOG_I(TAG, "Advertising name: %s", &(gap->service.adv_name[1])); + FURI_LOG_I( + TAG, + "MAC @ : %02X:%02X:%02X:%02X:%02X:%02X", + config->mac_address[0], + config->mac_address[1], + config->mac_address[2], + config->mac_address[3], + config->mac_address[4], + config->mac_address[5]); gap_init_svc(gap); // Initialization of the BLE Services SVCCTL_Init(); @@ -491,6 +534,9 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { gap->service.connection_handle = 0xFFFF; gap->enable_adv = true; + gap->conn_rssi = 127; + gap->time_rssi_sample = 0; + // Thread configuration gap->thread = furi_thread_alloc_ex("BleGapDriver", 1024, gap_app, gap); furi_thread_start(gap->thread); @@ -510,6 +556,16 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { return true; } +uint32_t gap_get_remote_conn_rssi(int8_t* rssi) { + if(gap && gap->state == GapStateConnected) { + fetch_rssi(); + *rssi = gap->conn_rssi; + + if(gap->time_rssi_sample) return furi_get_tick() - gap->time_rssi_sample; + } + return 0; +} + GapState gap_get_state() { GapState state; if(gap) { diff --git a/firmware/targets/f7/ble_glue/gap.h b/firmware/targets/f7/ble_glue/gap.h index 1e207299f..7b317e06c 100644 --- a/firmware/targets/f7/ble_glue/gap.h +++ b/firmware/targets/f7/ble_glue/gap.h @@ -81,6 +81,8 @@ GapState gap_get_state(); void gap_thread_stop(); +uint32_t gap_get_remote_conn_rssi(int8_t* rssi); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c index 47d242d4d..f983ec13b 100644 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ b/firmware/targets/f7/ble_glue/hid_service.c @@ -14,6 +14,11 @@ typedef struct { uint16_t report_map_char_handle; uint16_t info_char_handle; uint16_t ctrl_point_char_handle; + // led state + uint16_t led_state_char_handle; + uint16_t led_state_desc_handle; + HidLedStateEventCallback led_state_event_callback; + void* led_state_ctx; } HIDSvc; static HIDSvc* hid_svc = NULL; @@ -30,6 +35,25 @@ static SVCCTL_EvtAckStatus_t hid_svc_event_handler(void* event) { } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { // Process notification confirmation ret = SVCCTL_EvtAckFlowEnable; + } else if(blecore_evt->ecode == ACI_GATT_WRITE_PERMIT_REQ_VSEVT_CODE) { + // Process write request + aci_gatt_write_permit_req_event_rp0* req = + (aci_gatt_write_permit_req_event_rp0*)blecore_evt->data; + + furi_check(hid_svc->led_state_event_callback && hid_svc->led_state_ctx); + + // this check is likely to be incorrect, it will actually work in our case + // but we need to investigate gatt api to see what is the rules + // that specify attibute handle value from char handle (or the reverse) + if(req->Attribute_Handle == (hid_svc->led_state_char_handle + 1)) { + hid_svc->led_state_event_callback(req->Data[0], hid_svc->led_state_ctx); + aci_gatt_write_resp(req->Connection_Handle, req->Attribute_Handle, + 0x00, /* write_status = 0 (no error))*/ + 0x00, /* err_code */ + req->Data_Length, req->Data); + aci_gatt_write_char_value(req->Connection_Handle, hid_svc->led_state_char_handle, req->Data_Length, req->Data); + ret = SVCCTL_EvtAckFlowEnable; + } } } return ret; @@ -55,8 +79,8 @@ void hid_svc_start() { PRIMARY_SERVICE, 2 + /* protocol mode */ (4 * HID_SVC_INPUT_REPORT_COUNT) + (3 * HID_SVC_OUTPUT_REPORT_COUNT) + - (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + - 2, /* Service + Report Map + HID Information + HID Control Point */ + (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + 2 + + 4, /* Service + Report Map + HID Information + HID Control Point + LED state */ &hid_svc->svc_handle); if(status) { FURI_LOG_E(TAG, "Failed to add HID service: %d", status); @@ -198,6 +222,44 @@ void hid_svc_start() { } } #endif + // add led state output report + char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; + status = aci_gatt_add_char( + hid_svc->svc_handle, + UUID_TYPE_16, + &char_uuid, + 1, + CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE, + ATTR_PERMISSION_NONE, + GATT_NOTIFY_ATTRIBUTE_WRITE | GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP, + 10, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->led_state_char_handle)); + if(status) { + FURI_LOG_E(TAG, "Failed to add led state characteristic: %d", status); + } + + // add led state char descriptor specifying it is an output report + uint8_t buf[2] = {HID_SVC_REPORT_COUNT + 1, 2}; + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->led_state_char_handle, + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_WRITE, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->led_state_desc_handle)); + if(status) { + FURI_LOG_E(TAG, "Failed to add led state descriptor: %d", status); + } + // Add Report Map characteristic char_uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID; status = aci_gatt_add_char( @@ -247,6 +309,9 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add control point characteristic: %d", status); } + + hid_svc->led_state_event_callback = NULL; + hid_svc->led_state_ctx = NULL; } bool hid_svc_update_report_map(const uint8_t* data, uint16_t len) { @@ -288,6 +353,15 @@ bool hid_svc_update_info(uint8_t* data, uint16_t len) { return true; } +void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context) { + furi_assert(hid_svc); + furi_assert(callback); + furi_assert(context); + + hid_svc->led_state_event_callback = callback; + hid_svc->led_state_ctx = context; +} + bool hid_svc_is_started() { return hid_svc != NULL; } @@ -320,6 +394,10 @@ void hid_svc_stop() { if(status) { FURI_LOG_E(TAG, "Failed to delete Control Point characteristic: %d", status); } + status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->led_state_char_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to delete led state characteristic: %d", status); + } // Delete service status = aci_gatt_del_service(hid_svc->svc_handle); if(status) { diff --git a/firmware/targets/f7/ble_glue/hid_service.h b/firmware/targets/f7/ble_glue/hid_service.h index 723460d49..40d973340 100644 --- a/firmware/targets/f7/ble_glue/hid_service.h +++ b/firmware/targets/f7/ble_glue/hid_service.h @@ -15,6 +15,8 @@ #define HID_SVC_REPORT_COUNT \ (HID_SVC_INPUT_REPORT_COUNT + HID_SVC_OUTPUT_REPORT_COUNT + HID_SVC_FEATURE_REPORT_COUNT) +typedef uint16_t (*HidLedStateEventCallback)(uint8_t state, void* ctx); + void hid_svc_start(); void hid_svc_stop(); @@ -26,3 +28,5 @@ bool hid_svc_update_report_map(const uint8_t* data, uint16_t len); bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len); bool hid_svc_update_info(uint8_t* data, uint16_t len); + +void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context); \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 4e10b90d7..79fbc693f 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -54,27 +54,25 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { }, }, }, - [FuriHalBtProfileHidKeyboard] = - { - .start = furi_hal_bt_hid_start, - .stop = furi_hal_bt_hid_stop, - .config = - { - .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, - .appearance_char = GAP_APPEARANCE_KEYBOARD, - .bonding_mode = true, - .pairing_method = GapPairingPinCodeVerifyYesNo, - .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, - .conn_param = - { - .conn_int_min = 0x18, // 30 ms - .conn_int_max = 0x24, // 45 ms - .slave_latency = 0, - .supervisor_timeout = 0, - }, - }, - }, -}; + [FuriHalBtProfileHidKeyboard] = { + .start = furi_hal_bt_hid_start, + .stop = furi_hal_bt_hid_stop, + .config = + { + .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, + .appearance_char = GAP_APPEARANCE_KEYBOARD, + .bonding_mode = true, + .pairing_method = GapPairingPinCodeVerifyYesNo, + .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, + .conn_param = + { + .conn_int_min = 0x18, // 30 ms + .conn_int_max = 0x24, // 45 ms + .slave_latency = 0, + .supervisor_timeout = 0, + }, + }, + }}; FuriHalBtProfileConfig* current_profile = NULL; void furi_hal_bt_init() { @@ -201,26 +199,26 @@ bool furi_hal_bt_start_app(FuriHalBtProfile profile, GapEventCallback event_cb, FURI_LOG_E(TAG, "Can't start Ble App - unsupported radio stack"); break; } - // Set mac address - memcpy( - profile_config[profile].config.mac_address, - furi_hal_version_get_ble_mac(), - sizeof(profile_config[profile].config.mac_address)); - // Set advertise name - strlcpy( - profile_config[profile].config.adv_name, - furi_hal_version_get_ble_local_device_name_ptr(), - FURI_HAL_VERSION_DEVICE_NAME_LENGTH); - // Configure GAP GapConfig* config = &profile_config[profile].config; + // Configure GAP if(profile == FuriHalBtProfileSerial) { + // Set mac address + memcpy( + profile_config[profile].config.mac_address, + furi_hal_version_get_ble_mac(), + sizeof(profile_config[profile].config.mac_address)); config->adv_service_uuid |= furi_hal_version_get_hw_color(); } else if(profile == FuriHalBtProfileHidKeyboard) { // Change MAC address for HID profile - config->mac_address[2]++; - // Change name Flipper -> Flipper Remote - const char* clicker_str = "Flipper Remote"; - memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str)); + uint8_t default_mac[GAP_MAC_ADDR_SIZE] = FURI_HAL_BT_DEFAULT_MAC_ADDR; + if(memcmp(config->mac_address, default_mac, 6) == 0) { + config->mac_address[2]++; + } + // Change name Flipper -> Control + if(strlen(&config->adv_name[1]) == 0) { + const char* clicker_str = "Control"; + memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str)); + } } if(!gap_init(config, event_cb, context)) { gap_thread_stop(); @@ -282,6 +280,10 @@ bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } +bool furi_hal_bt_is_connected() { + return gap_get_state() == GapStateConnected; +} + void furi_hal_bt_start_advertising() { if(gap_get_state() == GapStateIdle) { gap_start_advertising(); @@ -420,6 +422,21 @@ float furi_hal_bt_get_rssi() { return val; } +/** fill the RSSI of the remote host of the bt connection and returns the last + * time the RSSI was updated + * +*/ +uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi) { + int8_t ret_rssi = 0; + uint32_t since = gap_get_remote_conn_rssi(&ret_rssi); + + if(ret_rssi == 127 || since == 0) return 0; + + *rssi = (uint8_t)abs(ret_rssi); + + return since; +} + uint32_t furi_hal_bt_get_transmitted_packets() { uint32_t packets = 0; aci_hal_le_tx_test_packet_number(&packets); @@ -444,3 +461,45 @@ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode) { FURI_LOG_E(TAG, "Failed to switch C2 mode: %d", fw_start_res); return false; } + +void furi_hal_bt_set_profile_adv_name( + FuriHalBtProfile profile, + const char name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH - 1]) { + furi_assert(profile < FuriHalBtProfileNumber); + furi_assert(name); + + profile_config[profile].config.adv_name[0] = 0x09; + memcpy( + &(profile_config[profile].config.adv_name[1]), + name, + FURI_HAL_VERSION_DEVICE_NAME_LENGTH - 1); +} + +const char* furi_hal_bt_get_profile_adv_name(FuriHalBtProfile profile) { + furi_assert(profile < FuriHalBtProfileNumber); + return &(profile_config[profile].config.adv_name[1]); +} + +void furi_hal_bt_set_profile_mac_addr( + FuriHalBtProfile profile, + const uint8_t mac_addr[GAP_MAC_ADDR_SIZE]) { + furi_assert(profile < FuriHalBtProfileNumber); + furi_assert(mac_addr); + + memcpy(profile_config[profile].config.mac_address, mac_addr, GAP_MAC_ADDR_SIZE); +} + +const uint8_t* furi_hal_bt_get_profile_mac_addr(FuriHalBtProfile profile) { + furi_assert(profile < FuriHalBtProfileNumber); + return profile_config[profile].config.mac_address; +} + +void furi_hal_bt_set_profile_pairing_method(FuriHalBtProfile profile, GapPairing pairing_method) { + furi_assert(profile < FuriHalBtProfileNumber); + profile_config[profile].config.pairing_method = pairing_method; +} + +GapPairing furi_hal_bt_get_profile_pairing_method(FuriHalBtProfile profile) { + furi_assert(profile < FuriHalBtProfileNumber); + return profile_config[profile].config.pairing_method; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index 8259be2f6..6921fbbc5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -20,6 +20,7 @@ enum HidReportId { ReportIdKeyboard = 1, ReportIdMouse = 2, ReportIdConsumer = 3, + ReportIdLEDState = 4, }; // Report numbers corresponded to the report id with an offset of 1 enum HidInputNumber { @@ -63,12 +64,6 @@ static const uint8_t furi_hal_bt_hid_report_map_data[] = { HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_USAGE_PAGE(HID_PAGE_LED), - HID_REPORT_COUNT(8), - HID_REPORT_SIZE(1), - HID_USAGE_MINIMUM(1), - HID_USAGE_MAXIMUM(8), - HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_REPORT_COUNT(FURI_HAL_BT_HID_KB_MAX_KEYS), HID_REPORT_SIZE(8), HID_LOGICAL_MINIMUM(0), @@ -77,6 +72,13 @@ static const uint8_t furi_hal_bt_hid_report_map_data[] = { HID_USAGE_MINIMUM(0), HID_USAGE_MAXIMUM(101), HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_REPORT_ID(ReportIdLEDState), + HID_USAGE_PAGE(HID_PAGE_LED), + HID_REPORT_COUNT(8), + HID_REPORT_SIZE(1), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(8), + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_END_COLLECTION, // Mouse Report HID_USAGE_PAGE(HID_PAGE_DESKTOP), @@ -125,6 +127,62 @@ FuriHalBtHidKbReport* kb_report = NULL; FuriHalBtHidMouseReport* mouse_report = NULL; FuriHalBtHidConsumerReport* consumer_report = NULL; +typedef struct { +// shortcuts +#define s_undefined data.bits.b_undefined +#define s_num_lock data.bits.b_num_lock +#define s_caps_lock data.bits.b_caps_lock +#define s_scroll_lock data.bits.b_scroll_lock +#define s_compose data.bits.b_compose +#define s_kana data.bits.b_kana +#define s_power data.bits.b_power +#define s_shift data.bits.b_shift +#define s_value data.value + union { + struct { + uint8_t b_undefined : 1; + uint8_t b_num_lock : 1; + uint8_t b_caps_lock : 1; + uint8_t b_scroll_lock : 1; + uint8_t b_compose : 1; + uint8_t b_kana : 1; + uint8_t b_power : 1; + uint8_t b_shift : 1; + } bits; + uint8_t value; + } data; +} __attribute__((__packed__)) FuriHalBtHidLedState; + +FuriHalBtHidLedState hid_host_led_state = {.s_value = 0}; + +uint16_t furi_hal_bt_hid_led_state_cb(uint8_t state, void* ctx) { + FuriHalBtHidLedState* led_state = (FuriHalBtHidLedState*)ctx; + + FURI_LOG_D("HalBtHid", "LED state updated !"); + + led_state->s_value = state; + + return 0; +} + +uint8_t furi_hal_bt_hid_get_led_state(void) { + FURI_LOG_D( + "HalBtHid", + "LED state: RFU=%d NUMLOCK=%d CAPSLOCK=%d SCROLLLOCK=%d COMPOSE=%d KANA=%d POWER=%d SHIFT=%d", + hid_host_led_state.s_undefined, + hid_host_led_state.s_num_lock, + hid_host_led_state.s_caps_lock, + hid_host_led_state.s_scroll_lock, + hid_host_led_state.s_compose, + hid_host_led_state.s_kana, + hid_host_led_state.s_power, + hid_host_led_state.s_shift); + + return (hid_host_led_state.s_value >> 1); // bit 0 is undefined (after shift bit location + // match with HID led state bits defines) + // see bad_kb_script.c (ducky_numlock_on function) +} + void furi_hal_bt_hid_start() { // Start device info if(!dev_info_svc_is_started()) { @@ -138,10 +196,13 @@ void furi_hal_bt_hid_start() { if(!hid_svc_is_started()) { hid_svc_start(); } - // Configure HID Keyboard + + hid_svc_register_led_state_callback(furi_hal_bt_hid_led_state_cb, &hid_host_led_state); + kb_report = malloc(sizeof(FuriHalBtHidKbReport)); mouse_report = malloc(sizeof(FuriHalBtHidMouseReport)); consumer_report = malloc(sizeof(FuriHalBtHidConsumerReport)); + // Configure Report Map characteristic hid_svc_update_report_map( furi_hal_bt_hid_report_map_data, sizeof(furi_hal_bt_hid_report_map_data)); @@ -160,6 +221,9 @@ void furi_hal_bt_hid_stop() { furi_assert(kb_report); furi_assert(mouse_report); furi_assert(consumer_report); + + hid_svc_register_led_state_callback(NULL, NULL); + // Stop all services if(dev_info_svc_is_started()) { dev_info_svc_stop(); @@ -180,12 +244,16 @@ void furi_hal_bt_hid_stop() { bool furi_hal_bt_hid_kb_press(uint16_t button) { furi_assert(kb_report); - for(uint8_t i = 0; i < FURI_HAL_BT_HID_KB_MAX_KEYS; i++) { + uint8_t i; + for(i = 0; i < FURI_HAL_BT_HID_KB_MAX_KEYS; i++) { if(kb_report->key[i] == 0) { kb_report->key[i] = button & 0xFF; break; } } + if(i == FURI_HAL_BT_HID_KB_MAX_KEYS) { + return false; + } kb_report->mods |= (button >> 8); return hid_svc_update_input_report( ReportNumberKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h index 196b2edb3..d717d346d 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt.h @@ -224,6 +224,34 @@ uint32_t furi_hal_bt_get_transmitted_packets(); */ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode); +/** Modify profile advertisement name and restart bluetooth + * @param[in] profile profile type + * @param[in] name new adv name +*/ +void furi_hal_bt_set_profile_adv_name( + FuriHalBtProfile profile, + const char name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH - 1]); + +const char* furi_hal_bt_get_profile_adv_name(FuriHalBtProfile profile); + +/** Modify profile mac address and restart bluetooth + * @param[in] profile profile type + * @param[in] mac new mac address +*/ +void furi_hal_bt_set_profile_mac_addr( + FuriHalBtProfile profile, + const uint8_t mac_addr[GAP_MAC_ADDR_SIZE]); + +const uint8_t* furi_hal_bt_get_profile_mac_addr(FuriHalBtProfile profile); + +uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi); + +void furi_hal_bt_set_profile_pairing_method(FuriHalBtProfile profile, GapPairing pairing_method); + +GapPairing furi_hal_bt_get_profile_pairing_method(FuriHalBtProfile profile); + +bool furi_hal_bt_is_connected(void); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h index 4e74bbda7..56a8b4e48 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h @@ -86,6 +86,13 @@ bool furi_hal_bt_hid_consumer_key_release(uint16_t button); */ bool furi_hal_bt_hid_consumer_key_release_all(); +/** Retrieves LED state from remote BT HID host + * + * @return (look at HID usage page to know what each bit of the returned byte means) + * NB: RFU bit has been shifted out in the returned octet so USB defines should work +*/ +uint8_t furi_hal_bt_hid_get_led_state(void); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_version.h b/firmware/targets/furi_hal_include/furi_hal_version.h index a9865f500..63cb948db 100644 --- a/firmware/targets/furi_hal_include/furi_hal_version.h +++ b/firmware/targets/furi_hal_include/furi_hal_version.h @@ -17,7 +17,7 @@ extern "C" { #define FURI_HAL_VERSION_NAME_LENGTH 8 #define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) /** BLE symbol + name */ -#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) +#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) + 9 // for bad kb custom name /** OTP Versions enum */ typedef enum { diff --git a/scripts/fbt_tools/fbt_help.py b/scripts/fbt_tools/fbt_help.py index 9921588ed..afdb36665 100644 --- a/scripts/fbt_tools/fbt_help.py +++ b/scripts/fbt_tools/fbt_help.py @@ -11,7 +11,7 @@ Building: Build all FAP apps fap_{APPID}, launch_app APPSRC={APPID}: Build FAP app with appid={APPID}; upload & start it over USB - faps_copy: + fap_deploy: Build and upload all FAP apps over USB Flashing & debugging: