1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Merge branch 'dev' into nestednonces

This commit is contained in:
あく
2024-10-16 18:07:13 +01:00
committed by GitHub
52 changed files with 488 additions and 2435 deletions

View File

@@ -7,7 +7,7 @@ App(
icon="A_BadUsb_14", icon="A_BadUsb_14",
order=70, order=70,
resources="resources", resources="resources",
fap_libs=["assets"], fap_libs=["assets", "ble_profile"],
fap_icon="icon.png", fap_icon="icon.png",
fap_category="USB", fap_category="USB",
) )

View File

@@ -35,6 +35,7 @@ static void bad_usb_load_settings(BadUsbApp* app) {
FuriString* temp_str = furi_string_alloc(); FuriString* temp_str = furi_string_alloc();
uint32_t version = 0; uint32_t version = 0;
uint32_t interface = 0;
if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) { if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) {
do { do {
@@ -44,6 +45,8 @@ static void bad_usb_load_settings(BadUsbApp* app) {
break; break;
if(!flipper_format_read_string(fff, "layout", temp_str)) break; if(!flipper_format_read_string(fff, "layout", temp_str)) break;
if(!flipper_format_read_uint32(fff, "interface", &interface, 1)) break;
if(interface > BadUsbHidInterfaceBle) break;
state = true; state = true;
} while(0); } while(0);
@@ -53,6 +56,7 @@ static void bad_usb_load_settings(BadUsbApp* app) {
if(state) { if(state) {
furi_string_set(app->keyboard_layout, temp_str); furi_string_set(app->keyboard_layout, temp_str);
app->interface = interface;
Storage* fs_api = furi_record_open(RECORD_STORAGE); Storage* fs_api = furi_record_open(RECORD_STORAGE);
FileInfo layout_file_info; FileInfo layout_file_info;
@@ -64,6 +68,7 @@ static void bad_usb_load_settings(BadUsbApp* app) {
} }
} else { } else {
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
app->interface = BadUsbHidInterfaceUsb;
} }
furi_string_free(temp_str); furi_string_free(temp_str);
@@ -79,6 +84,9 @@ static void bad_usb_save_settings(BadUsbApp* app) {
fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION)) fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION))
break; break;
if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break; if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break;
uint32_t interface_id = app->interface;
if(!flipper_format_write_uint32(fff, "interface", (const uint32_t*)&interface_id, 1))
break;
} while(0); } while(0);
} }
@@ -86,6 +94,11 @@ static void bad_usb_save_settings(BadUsbApp* app) {
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
} }
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface) {
app->interface = interface;
bad_usb_view_set_interface(app->bad_usb_view, interface);
}
BadUsbApp* bad_usb_app_alloc(char* arg) { BadUsbApp* bad_usb_app_alloc(char* arg) {
BadUsbApp* app = malloc(sizeof(BadUsbApp)); BadUsbApp* app = malloc(sizeof(BadUsbApp));
@@ -117,7 +130,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
// Custom Widget // Custom Widget
app->widget = widget_alloc(); app->widget = widget_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); app->view_dispatcher, BadUsbAppViewWidget, widget_get_view(app->widget));
// Popup
app->popup = popup_alloc();
view_dispatcher_add_view(app->view_dispatcher, BadUsbAppViewPopup, popup_get_view(app->popup));
app->var_item_list = variable_item_list_alloc(); app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
@@ -163,9 +180,13 @@ void bad_usb_app_free(BadUsbApp* app) {
bad_usb_view_free(app->bad_usb_view); bad_usb_view_free(app->bad_usb_view);
// Custom Widget // Custom Widget
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError); view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWidget);
widget_free(app->widget); widget_free(app->widget);
// Popup
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewPopup);
popup_free(app->popup);
// Config menu // Config menu
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
variable_item_list_free(app->var_item_list); variable_item_list_free(app->var_item_list);

View File

@@ -13,6 +13,7 @@
#include <notification/notification_messages.h> #include <notification/notification_messages.h>
#include <gui/modules/variable_item_list.h> #include <gui/modules/variable_item_list.h>
#include <gui/modules/widget.h> #include <gui/modules/widget.h>
#include <gui/modules/popup.h>
#include "views/bad_usb_view.h" #include "views/bad_usb_view.h"
#include <furi_hal_usb.h> #include <furi_hal_usb.h>
@@ -33,6 +34,7 @@ struct BadUsbApp {
NotificationApp* notifications; NotificationApp* notifications;
DialogsApp* dialogs; DialogsApp* dialogs;
Widget* widget; Widget* widget;
Popup* popup;
VariableItemList* var_item_list; VariableItemList* var_item_list;
BadUsbAppError error; BadUsbAppError error;
@@ -41,11 +43,15 @@ struct BadUsbApp {
BadUsb* bad_usb_view; BadUsb* bad_usb_view;
BadUsbScript* bad_usb_script; BadUsbScript* bad_usb_script;
BadUsbHidInterface interface;
FuriHalUsbInterface* usb_if_prev; FuriHalUsbInterface* usb_if_prev;
}; };
typedef enum { typedef enum {
BadUsbAppViewError, BadUsbAppViewWidget,
BadUsbAppViewPopup,
BadUsbAppViewWork, BadUsbAppViewWork,
BadUsbAppViewConfig, BadUsbAppViewConfig,
} BadUsbAppView; } BadUsbAppView;
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface);

View File

@@ -1,9 +1,12 @@
#include "bad_usb_hid.h" #include "bad_usb_hid.h"
#include <extra_profiles/hid_profile.h> #include <extra_profiles/hid_profile.h>
#include <bt/bt_service/bt.h>
#include <storage/storage.h> #include <storage/storage.h>
#define TAG "BadUSB HID" #define TAG "BadUSB HID"
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
void* hid_usb_init(FuriHalUsbHidConfig* hid_cfg) { void* hid_usb_init(FuriHalUsbHidConfig* hid_cfg) {
furi_check(furi_hal_usb_set_config(&usb_hid, hid_cfg)); furi_check(furi_hal_usb_set_config(&usb_hid, hid_cfg));
return NULL; return NULL;
@@ -69,6 +72,155 @@ static const BadUsbHidApi hid_api_usb = {
.release_all = hid_usb_release_all, .release_all = hid_usb_release_all,
.get_led_state = hid_usb_get_led_state, .get_led_state = hid_usb_get_led_state,
}; };
const BadUsbHidApi* bad_usb_hid_get_interface() {
return &hid_api_usb; typedef struct {
Bt* bt;
FuriHalBleProfileBase* profile;
HidStateCallback state_callback;
void* callback_context;
bool is_connected;
} BleHidInstance;
static const BleProfileHidParams ble_hid_params = {
.device_name_prefix = "BadUSB",
.mac_xor = 0x0002,
};
static void hid_ble_connection_status_callback(BtStatus status, void* context) {
furi_assert(context);
BleHidInstance* ble_hid = context;
ble_hid->is_connected = (status == BtStatusConnected);
if(ble_hid->state_callback) {
ble_hid->state_callback(ble_hid->is_connected, ble_hid->callback_context);
}
}
void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) {
UNUSED(hid_cfg);
BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance));
ble_hid->bt = furi_record_open(RECORD_BT);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, (void*)&ble_hid_params);
furi_check(ble_hid->profile);
furi_hal_bt_start_advertising();
bt_set_status_changed_callback(ble_hid->bt, hid_ble_connection_status_callback, ble_hid);
return ble_hid;
}
void hid_ble_deinit(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bt_set_status_changed_callback(ble_hid->bt, NULL, NULL);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(ble_hid->bt);
furi_check(bt_profile_restore_default(ble_hid->bt));
furi_record_close(RECORD_BT);
free(ble_hid);
}
void hid_ble_set_state_callback(void* inst, HidStateCallback cb, void* context) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
ble_hid->state_callback = cb;
ble_hid->callback_context = context;
}
bool hid_ble_is_connected(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_hid->is_connected;
}
bool hid_ble_kb_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_press(ble_hid->profile, button);
}
bool hid_ble_kb_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_release(ble_hid->profile, button);
}
bool hid_ble_consumer_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_press(ble_hid->profile, button);
}
bool hid_ble_consumer_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_release(ble_hid->profile, button);
}
bool hid_ble_release_all(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bool state = ble_profile_hid_kb_release_all(ble_hid->profile);
state &= ble_profile_hid_consumer_key_release_all(ble_hid->profile);
return state;
}
uint8_t hid_ble_get_led_state(void* inst) {
UNUSED(inst);
FURI_LOG_W(TAG, "hid_ble_get_led_state not implemented");
return 0;
}
static const BadUsbHidApi hid_api_ble = {
.init = hid_ble_init,
.deinit = hid_ble_deinit,
.set_state_callback = hid_ble_set_state_callback,
.is_connected = hid_ble_is_connected,
.kb_press = hid_ble_kb_press,
.kb_release = hid_ble_kb_release,
.consumer_press = hid_ble_consumer_press,
.consumer_release = hid_ble_consumer_release,
.release_all = hid_ble_release_all,
.get_led_state = hid_ble_get_led_state,
};
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface) {
if(interface == BadUsbHidInterfaceUsb) {
return &hid_api_usb;
} else {
return &hid_api_ble;
}
}
void bad_usb_hid_ble_remove_pairing(void) {
Bt* bt = furi_record_open(RECORD_BT);
bt_disconnect(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
furi_hal_bt_stop_advertising();
bt_keys_storage_set_storage_path(bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
bt_forget_bonded_devices(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(bt);
furi_check(bt_profile_restore_default(bt));
furi_record_close(RECORD_BT);
} }

View File

@@ -7,6 +7,11 @@ extern "C" {
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
typedef enum {
BadUsbHidInterfaceUsb,
BadUsbHidInterfaceBle,
} BadUsbHidInterface;
typedef struct { typedef struct {
void* (*init)(FuriHalUsbHidConfig* hid_cfg); void* (*init)(FuriHalUsbHidConfig* hid_cfg);
void (*deinit)(void* inst); void (*deinit)(void* inst);
@@ -21,7 +26,7 @@ typedef struct {
uint8_t (*get_led_state)(void* inst); uint8_t (*get_led_state)(void* inst);
} BadUsbHidApi; } BadUsbHidApi;
const BadUsbHidApi* bad_usb_hid_get_interface(); const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface);
void bad_usb_hid_ble_remove_pairing(void); void bad_usb_hid_ble_remove_pairing(void);

View File

@@ -650,7 +650,7 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), 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) { BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface) {
furi_assert(file_path); furi_assert(file_path);
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
@@ -660,7 +660,7 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path) {
bad_usb->st.state = BadUsbStateInit; bad_usb->st.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0'; bad_usb->st.error[0] = '\0';
bad_usb->hid = bad_usb_hid_get_interface(); bad_usb->hid = bad_usb_hid_get_interface(interface);
bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb); bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
furi_thread_start(bad_usb->thread); furi_thread_start(bad_usb->thread);

View File

@@ -34,7 +34,7 @@ typedef struct {
typedef struct BadUsbScript BadUsbScript; typedef struct BadUsbScript BadUsbScript;
BadUsbScript* bad_usb_script_open(FuriString* file_path); BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface);
void bad_usb_script_close(BadUsbScript* bad_usb); void bad_usb_script_close(BadUsbScript* bad_usb);

View File

@@ -1,12 +1,17 @@
REM This is BadUSB demo script for ChromeOS by kowalski7cc REM This is BadUSB demo script for Chrome and ChromeOS by kowalski7cc
REM Exit from Overview
ESC
REM Open a new tab REM Open a new tab
CTRL t CTRL t
REM wait for some slower chromebooks REM wait for some slower chromebooks
DELAY 1000 DELAY 1000
REM Make sure we have omnibox focus
CTRL l
DELAY 200
REM Open an empty editable page REM Open an empty editable page
DEFAULT_DELAY 50 DEFAULT_DELAY 50
STRING data:text/html, <html contenteditable autofocus><style>body{font-family:monospace;} STRING data:text/html, <html contenteditable autofocus><title>Flipper Zero BadUSB Demo</title><style>body{font-family:monospace;}
ENTER ENTER
DELAY 500 DELAY 500

View File

@@ -5,14 +5,22 @@ REM Check the `lsusb` command to know your own devices IDs
REM This is BadUSB demo script for Linux/Gnome REM This is BadUSB demo script for Linux/Gnome
REM Exit from Overview
ESC
DELAY 200
REM Open terminal window REM Open terminal window
DELAY 1000
ALT F2 ALT F2
DELAY 500 DELAY 1000
STRING gnome-terminal --maximize REM Let's guess user terminal, based on (almost) glib order with ptyxis now default in Fedora 41
DELAY 500 STRING sh -c "xdg-terminal-exec||kgx||ptyxis||gnome-terminal||mate-terminal||xfce4-terminal||tilix||konsole||xterm"
DELAY 300
ENTER
REM It can take a bit to open the correct terminal
DELAY 1500
REM Make sure we are running in a POSIX-compliant shell
STRING env sh
ENTER ENTER
DELAY 750
REM Clear the screen in case some banner was displayed REM Clear the screen in case some banner was displayed
STRING clear STRING clear

View File

@@ -0,0 +1,59 @@
#include "../bad_usb_app_i.h"
enum SubmenuIndex {
ConfigIndexKeyboardLayout,
ConfigIndexBleUnpair,
};
void bad_usb_scene_config_select_callback(void* context, uint32_t index) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
}
static void draw_menu(BadUsbApp* bad_usb) {
VariableItemList* var_item_list = bad_usb->var_item_list;
variable_item_list_reset(var_item_list);
variable_item_list_add(var_item_list, "Keyboard Layout (global)", 0, NULL, NULL);
variable_item_list_add(var_item_list, "Remove Pairing", 0, NULL, NULL);
}
void bad_usb_scene_config_on_enter(void* context) {
BadUsbApp* bad_usb = context;
VariableItemList* var_item_list = bad_usb->var_item_list;
variable_item_list_set_enter_callback(
var_item_list, bad_usb_scene_config_select_callback, bad_usb);
draw_menu(bad_usb);
variable_item_list_set_selected_item(var_item_list, 0);
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) {
consumed = true;
if(event.event == ConfigIndexKeyboardLayout) {
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout);
} else if(event.event == ConfigIndexBleUnpair) {
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfirmUnpair);
} else {
furi_crash("Unknown key type");
}
}
return consumed;
}
void bad_usb_scene_config_on_exit(void* context) {
BadUsbApp* bad_usb = context;
VariableItemList* var_item_list = bad_usb->var_item_list;
variable_item_list_reset(var_item_list);
}

View File

@@ -1,4 +1,7 @@
ADD_SCENE(bad_usb, file_select, FileSelect) ADD_SCENE(bad_usb, file_select, FileSelect)
ADD_SCENE(bad_usb, work, Work) ADD_SCENE(bad_usb, work, Work)
ADD_SCENE(bad_usb, error, Error) ADD_SCENE(bad_usb, error, Error)
ADD_SCENE(bad_usb, config, Config)
ADD_SCENE(bad_usb, config_layout, ConfigLayout) ADD_SCENE(bad_usb, config_layout, ConfigLayout)
ADD_SCENE(bad_usb, confirm_unpair, ConfirmUnpair)
ADD_SCENE(bad_usb, unpair_done, UnpairDone)

View File

@@ -1,42 +1,42 @@
#include "../bad_ble_app_i.h" #include "../bad_usb_app_i.h"
void bad_ble_scene_confirm_unpair_widget_callback( void bad_usb_scene_confirm_unpair_widget_callback(
GuiButtonType type, GuiButtonType type,
InputType input_type, InputType input_type,
void* context) { void* context) {
UNUSED(input_type); UNUSED(input_type);
SceneManagerEvent event = {.type = SceneManagerEventTypeCustom, .event = type}; SceneManagerEvent event = {.type = SceneManagerEventTypeCustom, .event = type};
bad_ble_scene_confirm_unpair_on_event(context, event); bad_usb_scene_confirm_unpair_on_event(context, event);
} }
void bad_ble_scene_confirm_unpair_on_enter(void* context) { void bad_usb_scene_confirm_unpair_on_enter(void* context) {
BadBleApp* bad_ble = context; BadUsbApp* bad_usb = context;
Widget* widget = bad_ble->widget; Widget* widget = bad_usb->widget;
widget_add_button_element( widget_add_button_element(
widget, GuiButtonTypeLeft, "Cancel", bad_ble_scene_confirm_unpair_widget_callback, context); widget, GuiButtonTypeLeft, "Cancel", bad_usb_scene_confirm_unpair_widget_callback, context);
widget_add_button_element( widget_add_button_element(
widget, widget,
GuiButtonTypeRight, GuiButtonTypeRight,
"Unpair", "Unpair",
bad_ble_scene_confirm_unpair_widget_callback, bad_usb_scene_confirm_unpair_widget_callback,
context); context);
widget_add_text_box_element( widget_add_text_box_element(
widget, 0, 0, 128, 64, AlignCenter, AlignTop, "\e#Unpair the Device?\e#\n", false); widget, 0, 0, 128, 64, AlignCenter, AlignTop, "\e#Unpair the Device?\e#\n", false);
view_dispatcher_switch_to_view(bad_ble->view_dispatcher, BadBleAppViewWidget); view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewWidget);
} }
bool bad_ble_scene_confirm_unpair_on_event(void* context, SceneManagerEvent event) { bool bad_usb_scene_confirm_unpair_on_event(void* context, SceneManagerEvent event) {
BadBleApp* bad_ble = context; BadUsbApp* bad_usb = context;
SceneManager* scene_manager = bad_ble->scene_manager; SceneManager* scene_manager = bad_usb->scene_manager;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == GuiButtonTypeRight) { if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(scene_manager, BadBleSceneUnpairDone); scene_manager_next_scene(scene_manager, BadUsbSceneUnpairDone);
} else if(event.event == GuiButtonTypeLeft) { } else if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager); scene_manager_previous_scene(scene_manager);
} }
@@ -45,9 +45,9 @@ bool bad_ble_scene_confirm_unpair_on_event(void* context, SceneManagerEvent even
return consumed; return consumed;
} }
void bad_ble_scene_confirm_unpair_on_exit(void* context) { void bad_usb_scene_confirm_unpair_on_exit(void* context) {
BadBleApp* bad_ble = context; BadUsbApp* bad_usb = context;
Widget* widget = bad_ble->widget; Widget* widget = bad_usb->widget;
widget_reset(widget); widget_reset(widget);
} }

View File

@@ -43,7 +43,7 @@ void bad_usb_scene_error_on_enter(void* context) {
"Disconnect from\nPC or phone to\nuse this function."); "Disconnect from\nPC or phone to\nuse this function.");
} }
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError); view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWidget);
} }
bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) { bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) {

View File

@@ -0,0 +1,39 @@
#include "../bad_usb_app_i.h"
static void bad_usb_scene_unpair_done_popup_callback(void* context) {
BadUsbApp* bad_usb = context;
scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneConfig);
}
void bad_usb_scene_unpair_done_on_enter(void* context) {
BadUsbApp* bad_usb = context;
Popup* popup = bad_usb->popup;
bad_usb_hid_ble_remove_pairing();
popup_set_icon(popup, 48, 4, &I_DolphinDone_80x58);
popup_set_header(popup, "Done", 20, 19, AlignLeft, AlignBottom);
popup_set_callback(popup, bad_usb_scene_unpair_done_popup_callback);
popup_set_context(popup, bad_usb);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewPopup);
}
bool bad_usb_scene_unpair_done_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
UNUSED(bad_usb);
UNUSED(event);
bool consumed = false;
return consumed;
}
void bad_usb_scene_unpair_done_on_exit(void* context) {
BadUsbApp* bad_usb = context;
Popup* popup = bad_usb->popup;
UNUSED(popup);
popup_reset(popup);
}

View File

@@ -20,14 +20,27 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
bad_usb_script_close(app->bad_usb_script); bad_usb_script_close(app->bad_usb_script);
app->bad_usb_script = NULL; app->bad_usb_script = NULL;
if(app->interface == BadUsbHidInterfaceBle) {
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
} else {
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfigLayout); scene_manager_next_scene(app->scene_manager, BadUsbSceneConfigLayout);
} }
}
consumed = true; consumed = true;
} else if(event.event == InputKeyOk) { } else if(event.event == InputKeyOk) {
bad_usb_script_start_stop(app->bad_usb_script); bad_usb_script_start_stop(app->bad_usb_script);
consumed = true; consumed = true;
} else if(event.event == InputKeyRight) { } else if(event.event == InputKeyRight) {
if(bad_usb_view_is_idle_state(app->bad_usb_view)) {
bad_usb_set_interface(
app,
app->interface == BadUsbHidInterfaceBle ? BadUsbHidInterfaceUsb :
BadUsbHidInterfaceBle);
bad_usb_script_close(app->bad_usb_script);
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
} else {
bad_usb_script_pause_resume(app->bad_usb_script); bad_usb_script_pause_resume(app->bad_usb_script);
}
consumed = true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
@@ -39,7 +52,9 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
void bad_usb_scene_work_on_enter(void* context) { void bad_usb_scene_work_on_enter(void* context) {
BadUsbApp* app = context; BadUsbApp* app = context;
app->bad_usb_script = bad_usb_script_open(app->file_path); bad_usb_view_set_interface(app->bad_usb_view, app->interface);
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout); bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
FuriString* file_name; FuriString* file_name;

View File

@@ -18,6 +18,7 @@ typedef struct {
BadUsbState state; BadUsbState state;
bool pause_wait; bool pause_wait;
uint8_t anim_frame; uint8_t anim_frame;
BadUsbHidInterface interface;
} BadUsbModel; } BadUsbModel;
static void bad_usb_draw_callback(Canvas* canvas, void* _model) { static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
@@ -40,14 +41,24 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
furi_string_reset(disp_str); furi_string_reset(disp_str);
if(model->interface == BadUsbHidInterfaceBle) {
canvas_draw_icon(canvas, 22, 24, &I_Bad_BLE_48x22);
} else {
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22); canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
}
BadUsbWorkerState state = model->state.state; BadUsbWorkerState state = model->state.state;
if((state == BadUsbStateIdle) || (state == BadUsbStateDone) || if((state == BadUsbStateIdle) || (state == BadUsbStateDone) ||
(state == BadUsbStateNotConnected)) { (state == BadUsbStateNotConnected)) {
elements_button_center(canvas, "Run"); elements_button_center(canvas, "Run");
if(model->interface == BadUsbHidInterfaceBle) {
elements_button_right(canvas, "USB");
elements_button_left(canvas, "Config");
} else {
elements_button_right(canvas, "BLE");
elements_button_left(canvas, "Layout"); elements_button_left(canvas, "Layout");
}
} else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) { } else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) {
elements_button_center(canvas, "Stop"); elements_button_center(canvas, "Stop");
if(!model->pause_wait) { if(!model->pause_wait) {
@@ -266,6 +277,10 @@ void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st) {
true); true);
} }
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface) {
with_view_model(bad_usb->view, BadUsbModel * model, { model->interface = interface; }, true);
}
bool bad_usb_view_is_idle_state(BadUsb* bad_usb) { bool bad_usb_view_is_idle_state(BadUsb* bad_usb) {
bool is_idle = false; bool is_idle = false;
with_view_model( with_view_model(

View File

@@ -23,4 +23,6 @@ void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout);
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st); void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st);
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface);
bool bad_usb_view_is_idle_state(BadUsb* bad_usb); bool bad_usb_view_is_idle_state(BadUsb* bad_usb);

View File

@@ -209,6 +209,15 @@ App(
sources=["plugins/supported_cards/hworld.c"], sources=["plugins/supported_cards/hworld.c"],
) )
App(
appid="trt_parser",
apptype=FlipperAppType.PLUGIN,
entry_point="trt_plugin_ep",
targets=["f7"],
requires=["nfc"],
sources=["plugins/supported_cards/trt.c"],
)
App( App(
appid="nfc_start", appid="nfc_start",
targets=["f7"], targets=["f7"],

View File

@@ -0,0 +1,94 @@
// Flipper Zero parser for for Tianjin Railway Transit (TRT)
// https://en.wikipedia.org/wiki/Tianjin_Metro
// Reverse engineering and parser development by @Torron (Github: @zinongli)
#include "nfc_supported_card_plugin.h"
#include <flipper_application.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
#include <bit_lib.h>
#define TAG "TrtParser"
#define LATEST_SALE_MARKER 0x02
#define FULL_SALE_TIME_STAMP_PAGE 0x09
#define BALANCE_PAGE 0x08
#define SALE_RECORD_TIME_STAMP_A 0x0C
#define SALE_RECORD_TIME_STAMP_B 0x0E
#define SALE_YEAR_OFFSET 2000
static bool trt_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_assert(device);
furi_assert(parsed_data);
const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight);
bool parsed = false;
do {
uint8_t latest_sale_page = 0;
// Look for sale record signature
if(data->page[SALE_RECORD_TIME_STAMP_A].data[0] == LATEST_SALE_MARKER) {
latest_sale_page = SALE_RECORD_TIME_STAMP_A;
} else if(data->page[SALE_RECORD_TIME_STAMP_B].data[0] == LATEST_SALE_MARKER) {
latest_sale_page = SALE_RECORD_TIME_STAMP_B;
} else {
break;
}
// Check if the sale record was backed up
const uint8_t* partial_record_pointer = &data->page[latest_sale_page - 1].data[0];
const uint8_t* full_record_pointer = &data->page[FULL_SALE_TIME_STAMP_PAGE].data[0];
uint32_t latest_sale_record = bit_lib_get_bits_32(partial_record_pointer, 3, 20);
uint32_t latest_sale_full_record = bit_lib_get_bits_32(full_record_pointer, 0, 27);
if(latest_sale_record != (latest_sale_full_record & 0xFFFFF)) break;
// Parse date
// yyy yyyymmmm dddddhhh hhnnnnnn
uint16_t sale_year = ((latest_sale_full_record & 0x7F00000) >> 20) + SALE_YEAR_OFFSET;
uint8_t sale_month = (latest_sale_full_record & 0xF0000) >> 16;
uint8_t sale_day = (latest_sale_full_record & 0xF800) >> 11;
uint8_t sale_hour = (latest_sale_full_record & 0x7C0) >> 6;
uint8_t sale_minute = latest_sale_full_record & 0x3F;
// Parse balance
uint16_t balance = bit_lib_get_bits_16(&data->page[BALANCE_PAGE].data[2], 0, 16);
uint16_t balance_yuan = balance / 100;
uint8_t balance_cent = balance % 100;
// Format string for rendering
furi_string_cat_printf(parsed_data, "\e#TRT Tianjin Metro\n");
furi_string_cat_printf(parsed_data, "Single-Use Ticket\n");
furi_string_cat_printf(parsed_data, "Balance: %u.%02u RMB\n", balance_yuan, balance_cent);
furi_string_cat_printf(
parsed_data,
"Sale Date: \n%04u-%02d-%02d %02d:%02d",
sale_year,
sale_month,
sale_day,
sale_hour,
sale_minute);
parsed = true;
} while(false);
return parsed;
}
/* Actual implementation of app<>plugin interface */
static const NfcSupportedCardsPlugin trt_plugin = {
.protocol = NfcProtocolMfUltralight,
.verify = NULL,
.read = NULL,
.parse = trt_parse,
};
/* Plugin descriptor to comply with basic plugin specification */
static const FlipperAppPluginDescriptor trt_plugin_descriptor = {
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
.entry_point = &trt_plugin,
};
/* Plugin entry point - must return a pointer to const descriptor */
const FlipperAppPluginDescriptor* trt_plugin_ep(void) {
return &trt_plugin_descriptor;
}

View File

@@ -1351,3 +1351,8 @@ E69DD9015A43
C8382A233993 C8382A233993
7B304F2A12A6 7B304F2A12A6
FC9418BF788B FC9418BF788B
# H World Hotel Chain Room Keys
543071543071
5F01015F0101
200510241234

View File

@@ -523,7 +523,7 @@ int32_t desktop_srv(void* p) {
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { if(desktop_pin_code_is_set()) {
desktop_lock(desktop); desktop_lock(desktop);
} }

View File

@@ -1,12 +0,0 @@
App(
appid="bad_ble",
name="Bad BLE",
apptype=FlipperAppType.EXTERNAL,
entry_point="bad_ble_app",
stack_size=2 * 1024,
icon="A_BadUsb_14",
fap_libs=["assets", "ble_profile"],
fap_icon="icon.png",
fap_icon_assets="assets",
fap_category="Bluetooth",
)

View File

@@ -1,196 +0,0 @@
#include "bad_ble_app_i.h"
#include <furi.h>
#include <furi_hal.h>
#include <storage/storage.h>
#include <lib/toolbox/path.h>
#include <flipper_format/flipper_format.h>
#define BAD_BLE_SETTINGS_PATH BAD_BLE_APP_BASE_FOLDER "/.badble.settings"
#define BAD_BLE_SETTINGS_FILE_TYPE "Flipper BadBLE Settings File"
#define BAD_BLE_SETTINGS_VERSION 1
#define BAD_BLE_SETTINGS_DEFAULT_LAYOUT BAD_BLE_APP_PATH_LAYOUT_FOLDER "/en-US.kl"
static bool bad_ble_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
BadBleApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool bad_ble_app_back_event_callback(void* context) {
furi_assert(context);
BadBleApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void bad_ble_app_tick_event_callback(void* context) {
furi_assert(context);
BadBleApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
static void bad_ble_load_settings(BadBleApp* app) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
bool state = false;
FuriString* temp_str = furi_string_alloc();
uint32_t version = 0;
if(flipper_format_file_open_existing(fff, BAD_BLE_SETTINGS_PATH)) {
do {
if(!flipper_format_read_header(fff, temp_str, &version)) break;
if((strcmp(furi_string_get_cstr(temp_str), BAD_BLE_SETTINGS_FILE_TYPE) != 0) ||
(version != BAD_BLE_SETTINGS_VERSION))
break;
if(!flipper_format_read_string(fff, "layout", temp_str)) break;
state = true;
} while(0);
}
flipper_format_free(fff);
furi_record_close(RECORD_STORAGE);
if(state) {
furi_string_set(app->keyboard_layout, temp_str);
Storage* fs_api = furi_record_open(RECORD_STORAGE);
FileInfo layout_file_info;
FS_Error file_check_err = storage_common_stat(
fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info);
furi_record_close(RECORD_STORAGE);
if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) {
furi_string_set(app->keyboard_layout, BAD_BLE_SETTINGS_DEFAULT_LAYOUT);
}
} else {
furi_string_set(app->keyboard_layout, BAD_BLE_SETTINGS_DEFAULT_LAYOUT);
}
furi_string_free(temp_str);
}
static void bad_ble_save_settings(BadBleApp* app) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
if(flipper_format_file_open_always(fff, BAD_BLE_SETTINGS_PATH)) {
do {
if(!flipper_format_write_header_cstr(
fff, BAD_BLE_SETTINGS_FILE_TYPE, BAD_BLE_SETTINGS_VERSION))
break;
if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break;
} while(0);
}
flipper_format_free(fff);
furi_record_close(RECORD_STORAGE);
}
BadBleApp* bad_ble_app_alloc(char* arg) {
BadBleApp* app = malloc(sizeof(BadBleApp));
app->bad_ble_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_ble_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();
app->scene_manager = scene_manager_alloc(&bad_ble_scene_handlers, app);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, bad_ble_app_tick_event_callback, 500);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, bad_ble_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, bad_ble_app_back_event_callback);
// Custom Widget
app->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadBleAppViewWidget, widget_get_view(app->widget));
// Popup
app->popup = popup_alloc();
view_dispatcher_add_view(app->view_dispatcher, BadBleAppViewPopup, popup_get_view(app->popup));
app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
BadBleAppViewConfig,
variable_item_list_get_view(app->var_item_list));
app->bad_ble_view = bad_ble_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadBleAppViewWork, bad_ble_view_get_view(app->bad_ble_view));
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
if(!furi_string_empty(app->file_path)) {
scene_manager_next_scene(app->scene_manager, BadBleSceneWork);
} else {
furi_string_set(app->file_path, BAD_BLE_APP_BASE_FOLDER);
scene_manager_next_scene(app->scene_manager, BadBleSceneFileSelect);
}
return app;
}
void bad_ble_app_free(BadBleApp* app) {
furi_assert(app);
if(app->bad_ble_script) {
bad_ble_script_close(app->bad_ble_script);
app->bad_ble_script = NULL;
}
// Views
view_dispatcher_remove_view(app->view_dispatcher, BadBleAppViewWork);
bad_ble_view_free(app->bad_ble_view);
// Custom Widget
view_dispatcher_remove_view(app->view_dispatcher, BadBleAppViewWidget);
widget_free(app->widget);
// Popup
view_dispatcher_remove_view(app->view_dispatcher, BadBleAppViewPopup);
popup_free(app->popup);
// Config menu
view_dispatcher_remove_view(app->view_dispatcher, BadBleAppViewConfig);
variable_item_list_free(app->var_item_list);
// 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_ble_save_settings(app);
furi_string_free(app->file_path);
furi_string_free(app->keyboard_layout);
free(app);
}
int32_t bad_ble_app(void* p) {
BadBleApp* bad_ble_app = bad_ble_app_alloc((char*)p);
view_dispatcher_run(bad_ble_app->view_dispatcher);
bad_ble_app_free(bad_ble_app);
return 0;
}

View File

@@ -1,11 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct BadBleApp BadBleApp;
#ifdef __cplusplus
}
#endif

View File

@@ -1,53 +0,0 @@
#pragma once
#include "bad_ble_app.h"
#include "scenes/bad_ble_scene.h"
#include "helpers/ducky_script.h"
#include "helpers/bad_ble_hid.h"
#include <gui/gui.h>
#include <assets_icons.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <dialogs/dialogs.h>
#include <notification/notification_messages.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/widget.h>
#include <gui/modules/popup.h>
#include "views/bad_ble_view.h"
#define BAD_BLE_APP_BASE_FOLDER EXT_PATH("badusb")
#define BAD_BLE_APP_PATH_LAYOUT_FOLDER BAD_BLE_APP_BASE_FOLDER "/assets/layouts"
#define BAD_BLE_APP_SCRIPT_EXTENSION ".txt"
#define BAD_BLE_APP_LAYOUT_EXTENSION ".kl"
typedef enum {
BadBleAppErrorNoFiles,
BadBleAppErrorCloseRpc,
} BadBleAppError;
struct BadBleApp {
Gui* gui;
ViewDispatcher* view_dispatcher;
SceneManager* scene_manager;
NotificationApp* notifications;
DialogsApp* dialogs;
Widget* widget;
Popup* popup;
VariableItemList* var_item_list;
BadBleAppError error;
FuriString* file_path;
FuriString* keyboard_layout;
BadBle* bad_ble_view;
BadBleScript* bad_ble_script;
BadBleHidInterface interface;
};
typedef enum {
BadBleAppViewWidget,
BadBleAppViewPopup,
BadBleAppViewWork,
BadBleAppViewConfig,
} BadBleAppView;

View File

@@ -1,157 +0,0 @@
#include "bad_ble_hid.h"
#include <extra_profiles/hid_profile.h>
#include <bt/bt_service/bt.h>
#include <storage/storage.h>
#define TAG "BadBLE HID"
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
typedef struct {
Bt* bt;
FuriHalBleProfileBase* profile;
HidStateCallback state_callback;
void* callback_context;
bool is_connected;
} BleHidInstance;
static const BleProfileHidParams ble_hid_params = {
.device_name_prefix = "BadBLE",
.mac_xor = 0x0002,
};
static void hid_ble_connection_status_callback(BtStatus status, void* context) {
furi_assert(context);
BleHidInstance* ble_hid = context;
ble_hid->is_connected = (status == BtStatusConnected);
if(ble_hid->state_callback) {
ble_hid->state_callback(ble_hid->is_connected, ble_hid->callback_context);
}
}
void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) {
UNUSED(hid_cfg);
BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance));
ble_hid->bt = furi_record_open(RECORD_BT);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, (void*)&ble_hid_params);
furi_check(ble_hid->profile);
furi_hal_bt_start_advertising();
bt_set_status_changed_callback(ble_hid->bt, hid_ble_connection_status_callback, ble_hid);
return ble_hid;
}
void hid_ble_deinit(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bt_set_status_changed_callback(ble_hid->bt, NULL, NULL);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(ble_hid->bt);
furi_check(bt_profile_restore_default(ble_hid->bt));
furi_record_close(RECORD_BT);
free(ble_hid);
}
void hid_ble_set_state_callback(void* inst, HidStateCallback cb, void* context) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
ble_hid->state_callback = cb;
ble_hid->callback_context = context;
}
bool hid_ble_is_connected(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_hid->is_connected;
}
bool hid_ble_kb_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_press(ble_hid->profile, button);
}
bool hid_ble_kb_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_release(ble_hid->profile, button);
}
bool hid_ble_consumer_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_press(ble_hid->profile, button);
}
bool hid_ble_consumer_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_release(ble_hid->profile, button);
}
bool hid_ble_release_all(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bool state = ble_profile_hid_kb_release_all(ble_hid->profile);
state &= ble_profile_hid_consumer_key_release_all(ble_hid->profile);
return state;
}
uint8_t hid_ble_get_led_state(void* inst) {
UNUSED(inst);
FURI_LOG_W(TAG, "hid_ble_get_led_state not implemented");
return 0;
}
static const BadBleHidApi hid_api_ble = {
.init = hid_ble_init,
.deinit = hid_ble_deinit,
.set_state_callback = hid_ble_set_state_callback,
.is_connected = hid_ble_is_connected,
.kb_press = hid_ble_kb_press,
.kb_release = hid_ble_kb_release,
.consumer_press = hid_ble_consumer_press,
.consumer_release = hid_ble_consumer_release,
.release_all = hid_ble_release_all,
.get_led_state = hid_ble_get_led_state,
};
const BadBleHidApi* bad_ble_hid_get_interface(BadBleHidInterface interface) {
UNUSED(interface);
return &hid_api_ble;
}
void bad_ble_hid_ble_remove_pairing(void) {
Bt* bt = furi_record_open(RECORD_BT);
bt_disconnect(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
furi_hal_bt_stop_advertising();
bt_keys_storage_set_storage_path(bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
bt_forget_bonded_devices(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(bt);
furi_check(bt_profile_restore_default(bt));
furi_record_close(RECORD_BT);
}

View File

@@ -1,34 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <furi.h>
#include <furi_hal.h>
typedef enum {
BadBleHidInterfaceBle,
} BadBleHidInterface;
typedef struct {
void* (*init)(FuriHalUsbHidConfig* hid_cfg);
void (*deinit)(void* inst);
void (*set_state_callback)(void* inst, HidStateCallback cb, void* context);
bool (*is_connected)(void* inst);
bool (*kb_press)(void* inst, uint16_t button);
bool (*kb_release)(void* inst, uint16_t button);
bool (*consumer_press)(void* inst, uint16_t button);
bool (*consumer_release)(void* inst, uint16_t button);
bool (*release_all)(void* inst);
uint8_t (*get_led_state)(void* inst);
} BadBleHidApi;
const BadBleHidApi* bad_ble_hid_get_interface(BadBleHidInterface interface);
void bad_ble_hid_ble_remove_pairing(void);
#ifdef __cplusplus
}
#endif

View File

@@ -1,716 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <lib/toolbox/args.h>
#include <lib/toolbox/strint.h>
#include <storage/storage.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
#include <dolphin/dolphin.h>
#define TAG "BadBle"
#define WORKER_TAG TAG "Worker"
#define BADUSB_ASCII_TO_KEY(script, x) \
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
typedef enum {
WorkerEvtStartStop = (1 << 0),
WorkerEvtPauseResume = (1 << 1),
WorkerEvtEnd = (1 << 2),
WorkerEvtConnect = (1 << 3),
WorkerEvtDisconnect = (1 << 4),
} WorkerEvtFlags;
static const char ducky_cmd_id[] = {"ID"};
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,
};
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;
}
bool ducky_is_line_end(const char chr) {
return (chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n');
}
uint16_t ducky_get_keycode(BadBleScript* bad_ble, const char* param, bool accept_chars) {
uint16_t keycode = ducky_get_keycode_by_name(param);
if(keycode != HID_KEYBOARD_NONE) {
return keycode;
}
if((accept_chars) && (strlen(param) > 0)) {
return BADUSB_ASCII_TO_KEY(bad_ble, param[0]) & 0xFF;
}
return 0;
}
bool ducky_get_number(const char* param, uint32_t* val) {
uint32_t value = 0;
if(strint_to_uint32(param, NULL, &value, 10) == StrintParseNoError) {
*val = value;
return true;
}
return false;
}
void ducky_numlock_on(BadBleScript* bad_ble) {
if((bad_ble->hid->get_led_state(bad_ble->hid_inst) & HID_KB_LED_NUM) == 0) {
bad_ble->hid->kb_press(bad_ble->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
bad_ble->hid->kb_release(bad_ble->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
}
}
bool ducky_numpad_press(BadBleScript* bad_ble, const char num) {
if((num < '0') || (num > '9')) return false;
uint16_t key = numpad_keys[num - '0'];
bad_ble->hid->kb_press(bad_ble->hid_inst, key);
bad_ble->hid->kb_release(bad_ble->hid_inst, key);
return true;
}
bool ducky_altchar(BadBleScript* bad_ble, const char* charcode) {
uint8_t i = 0;
bool state = false;
bad_ble->hid->kb_press(bad_ble->hid_inst, KEY_MOD_LEFT_ALT);
while(!ducky_is_line_end(charcode[i])) {
state = ducky_numpad_press(bad_ble, charcode[i]);
if(state == false) break;
i++;
}
bad_ble->hid->kb_release(bad_ble->hid_inst, KEY_MOD_LEFT_ALT);
return state;
}
bool ducky_altstring(BadBleScript* bad_ble, 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_ble, temp_str);
if(state == false) break;
i++;
}
return state;
}
int32_t ducky_error(BadBleScript* bad_ble, const char* text, ...) {
va_list args;
va_start(args, text);
vsnprintf(bad_ble->st.error, sizeof(bad_ble->st.error), text, args);
va_end(args);
return SCRIPT_STATE_ERROR;
}
bool ducky_string(BadBleScript* bad_ble, const char* param) {
uint32_t i = 0;
while(param[i] != '\0') {
if(param[i] != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_ble, param[i]);
if(keycode != HID_KEYBOARD_NONE) {
bad_ble->hid->kb_press(bad_ble->hid_inst, keycode);
bad_ble->hid->kb_release(bad_ble->hid_inst, keycode);
}
} else {
bad_ble->hid->kb_press(bad_ble->hid_inst, HID_KEYBOARD_RETURN);
bad_ble->hid->kb_release(bad_ble->hid_inst, HID_KEYBOARD_RETURN);
}
i++;
}
bad_ble->stringdelay = 0;
return true;
}
static bool ducky_string_next(BadBleScript* bad_ble) {
if(bad_ble->string_print_pos >= furi_string_size(bad_ble->string_print)) {
return true;
}
char print_char = furi_string_get_char(bad_ble->string_print, bad_ble->string_print_pos);
if(print_char != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_ble, print_char);
if(keycode != HID_KEYBOARD_NONE) {
bad_ble->hid->kb_press(bad_ble->hid_inst, keycode);
bad_ble->hid->kb_release(bad_ble->hid_inst, keycode);
}
} else {
bad_ble->hid->kb_press(bad_ble->hid_inst, HID_KEYBOARD_RETURN);
bad_ble->hid->kb_release(bad_ble->hid_inst, HID_KEYBOARD_RETURN);
}
bad_ble->string_print_pos++;
return false;
}
static int32_t ducky_parse_line(BadBleScript* bad_ble, FuriString* line) {
uint32_t line_len = furi_string_size(line);
const char* line_tmp = furi_string_get_cstr(line);
if(line_len == 0) {
return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
}
FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
// Ducky Lang Functions
int32_t cmd_result = ducky_execute_cmd(bad_ble, line_tmp);
if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
return cmd_result;
}
// Special keys + modifiers
uint16_t key = ducky_get_keycode(bad_ble, line_tmp, false);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_ble, "No keycode defined for %s", line_tmp);
}
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_ble, line_tmp, true);
}
bad_ble->hid->kb_press(bad_ble->hid_inst, key);
bad_ble->hid->kb_release(bad_ble->hid_inst, key);
return 0;
}
static bool ducky_set_usb_id(BadBleScript* bad_ble, const char* line) {
if(sscanf(line, "%lX:%lX", &bad_ble->hid_cfg.vid, &bad_ble->hid_cfg.pid) == 2) {
bad_ble->hid_cfg.manuf[0] = '\0';
bad_ble->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_ble->hid_cfg.manuf,
bad_ble->hid_cfg.product);
}
FURI_LOG_D(
WORKER_TAG,
"set id: %04lX:%04lX mfr:%s product:%s",
bad_ble->hid_cfg.vid,
bad_ble->hid_cfg.pid,
bad_ble->hid_cfg.manuf,
bad_ble->hid_cfg.product);
return true;
}
return false;
}
static void bad_ble_hid_state_callback(bool state, void* context) {
furi_assert(context);
BadBleScript* bad_ble = context;
if(state == true) {
furi_thread_flags_set(furi_thread_get_id(bad_ble->thread), WorkerEvtConnect);
} else {
furi_thread_flags_set(furi_thread_get_id(bad_ble->thread), WorkerEvtDisconnect);
}
}
static bool ducky_script_preload(BadBleScript* bad_ble, File* script_file) {
uint8_t ret = 0;
uint32_t line_len = 0;
furi_string_reset(bad_ble->line);
do {
ret = storage_file_read(script_file, bad_ble->file_buf, FILE_BUFFER_LEN);
for(uint16_t i = 0; i < ret; i++) {
if(bad_ble->file_buf[i] == '\n' && line_len > 0) {
bad_ble->st.line_nb++;
line_len = 0;
} else {
if(bad_ble->st.line_nb == 0) { // Save first line
furi_string_push_back(bad_ble->line, bad_ble->file_buf[i]);
}
line_len++;
}
}
if(storage_file_eof(script_file)) {
if(line_len > 0) {
bad_ble->st.line_nb++;
break;
}
}
} while(ret > 0);
const char* line_tmp = furi_string_get_cstr(bad_ble->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_ble, &line_tmp[strlen(ducky_cmd_id) + 1]);
}
if(id_set) {
bad_ble->hid_inst = bad_ble->hid->init(&bad_ble->hid_cfg);
} else {
bad_ble->hid_inst = bad_ble->hid->init(NULL);
}
bad_ble->hid->set_state_callback(bad_ble->hid_inst, bad_ble_hid_state_callback, bad_ble);
storage_file_seek(script_file, 0, true);
furi_string_reset(bad_ble->line);
return true;
}
static int32_t ducky_script_execute_next(BadBleScript* bad_ble, File* script_file) {
int32_t delay_val = 0;
if(bad_ble->repeat_cnt > 0) {
bad_ble->repeat_cnt--;
delay_val = ducky_parse_line(bad_ble, bad_ble->line_prev);
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
return delay_val;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
return delay_val;
} else if(delay_val < 0) { // Script error
bad_ble->st.error_line = bad_ble->st.line_cur - 1;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_ble->st.line_cur - 1U);
return SCRIPT_STATE_ERROR;
} else {
return delay_val + bad_ble->defdelay;
}
}
furi_string_set(bad_ble->line_prev, bad_ble->line);
furi_string_reset(bad_ble->line);
while(1) {
if(bad_ble->buf_len == 0) {
bad_ble->buf_len = storage_file_read(script_file, bad_ble->file_buf, FILE_BUFFER_LEN);
if(storage_file_eof(script_file)) {
if((bad_ble->buf_len < FILE_BUFFER_LEN) && (bad_ble->file_end == false)) {
bad_ble->file_buf[bad_ble->buf_len] = '\n';
bad_ble->buf_len++;
bad_ble->file_end = true;
}
}
bad_ble->buf_start = 0;
if(bad_ble->buf_len == 0) return SCRIPT_STATE_END;
}
for(uint8_t i = bad_ble->buf_start; i < (bad_ble->buf_start + bad_ble->buf_len); i++) {
if(bad_ble->file_buf[i] == '\n' && furi_string_size(bad_ble->line) > 0) {
bad_ble->st.line_cur++;
bad_ble->buf_len = bad_ble->buf_len + bad_ble->buf_start - (i + 1);
bad_ble->buf_start = i + 1;
furi_string_trim(bad_ble->line);
delay_val = ducky_parse_line(bad_ble, bad_ble->line);
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
return delay_val;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
return delay_val;
} else if(delay_val < 0) {
bad_ble->st.error_line = bad_ble->st.line_cur;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_ble->st.line_cur);
return SCRIPT_STATE_ERROR;
} else {
return delay_val + bad_ble->defdelay;
}
} else {
furi_string_push_back(bad_ble->line, bad_ble->file_buf[i]);
}
}
bad_ble->buf_len = 0;
if(bad_ble->file_end) return SCRIPT_STATE_END;
}
return 0;
}
static uint32_t bad_ble_flags_get(uint32_t flags_mask, uint32_t timeout) {
uint32_t flags = furi_thread_flags_get();
furi_check((flags & FuriFlagError) == 0);
if(flags == 0) {
flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
} else {
uint32_t state = furi_thread_flags_clear(flags);
furi_check((state & FuriFlagError) == 0);
}
return flags;
}
static int32_t bad_ble_worker(void* context) {
BadBleScript* bad_ble = context;
BadBleWorkerState worker_state = BadBleStateInit;
BadBleWorkerState pause_state = BadBleStateRunning;
int32_t delay_val = 0;
FURI_LOG_I(WORKER_TAG, "Init");
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
bad_ble->line = furi_string_alloc();
bad_ble->line_prev = furi_string_alloc();
bad_ble->string_print = furi_string_alloc();
while(1) {
if(worker_state == BadBleStateInit) { // State: initialization
if(storage_file_open(
script_file,
furi_string_get_cstr(bad_ble->file_path),
FSAM_READ,
FSOM_OPEN_EXISTING)) {
if((ducky_script_preload(bad_ble, script_file)) && (bad_ble->st.line_nb > 0)) {
if(bad_ble->hid->is_connected(bad_ble->hid_inst)) {
worker_state = BadBleStateIdle; // Ready to run
} else {
worker_state = BadBleStateNotConnected; // USB not connected
}
} else {
worker_state = BadBleStateScriptError; // Script preload error
}
} else {
FURI_LOG_E(WORKER_TAG, "File open error");
worker_state = BadBleStateFileError; // File open error
}
bad_ble->st.state = worker_state;
} else if(worker_state == BadBleStateNotConnected) { // State: USB not connected
uint32_t flags = bad_ble_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriWaitForever);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) {
worker_state = BadBleStateIdle; // Ready to run
} else if(flags & WorkerEvtStartStop) {
worker_state = BadBleStateWillRun; // Will run when USB is connected
}
bad_ble->st.state = worker_state;
} else if(worker_state == BadBleStateIdle) { // State: ready to start
uint32_t flags = bad_ble_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtDisconnect, FuriWaitForever);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) { // Start executing script
dolphin_deed(DolphinDeedBadUsbPlayScript);
delay_val = 0;
bad_ble->buf_len = 0;
bad_ble->st.line_cur = 0;
bad_ble->defdelay = 0;
bad_ble->stringdelay = 0;
bad_ble->defstringdelay = 0;
bad_ble->repeat_cnt = 0;
bad_ble->key_hold_nb = 0;
bad_ble->file_end = false;
storage_file_seek(script_file, 0, true);
worker_state = BadBleStateRunning;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadBleStateNotConnected; // USB disconnected
}
bad_ble->st.state = worker_state;
} else if(worker_state == BadBleStateWillRun) { // State: start on connection
uint32_t flags = bad_ble_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) { // Start executing script
dolphin_deed(DolphinDeedBadUsbPlayScript);
delay_val = 0;
bad_ble->buf_len = 0;
bad_ble->st.line_cur = 0;
bad_ble->defdelay = 0;
bad_ble->stringdelay = 0;
bad_ble->defstringdelay = 0;
bad_ble->repeat_cnt = 0;
bad_ble->file_end = false;
storage_file_seek(script_file, 0, true);
// extra time for PC to recognize Flipper as keyboard
flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriFlagWaitAny | FuriFlagNoClear,
1500);
if(flags == (unsigned)FuriFlagErrorTimeout) {
// If nothing happened - start script execution
worker_state = BadBleStateRunning;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadBleStateIdle;
furi_thread_flags_clear(WorkerEvtStartStop);
}
} else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution
worker_state = BadBleStateNotConnected;
}
bad_ble->st.state = worker_state;
} else if(worker_state == BadBleStateRunning) { // State: running
uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriFlagWaitAny,
delay_cur);
delay_val -= delay_cur;
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadBleStateIdle; // Stop executing script
bad_ble->hid->release_all(bad_ble->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadBleStateNotConnected; // USB disconnected
bad_ble->hid->release_all(bad_ble->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadBleStateRunning;
worker_state = BadBleStatePaused; // Pause
}
bad_ble->st.state = worker_state;
continue;
} else if(
(flags == (unsigned)FuriFlagErrorTimeout) ||
(flags == (unsigned)FuriFlagErrorResource)) {
if(delay_val > 0) {
bad_ble->st.delay_remain--;
continue;
}
bad_ble->st.state = BadBleStateRunning;
delay_val = ducky_script_execute_next(bad_ble, script_file);
if(delay_val == SCRIPT_STATE_ERROR) { // Script error
delay_val = 0;
worker_state = BadBleStateScriptError;
bad_ble->st.state = worker_state;
bad_ble->hid->release_all(bad_ble->hid_inst);
} else if(delay_val == SCRIPT_STATE_END) { // End of script
delay_val = 0;
worker_state = BadBleStateIdle;
bad_ble->st.state = BadBleStateDone;
bad_ble->hid->release_all(bad_ble->hid_inst);
continue;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
delay_val = bad_ble->defdelay;
bad_ble->string_print_pos = 0;
worker_state = BadBleStateStringDelay;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input
worker_state = BadBleStateWaitForBtn;
bad_ble->st.state = BadBleStateWaitForBtn; // Show long delays
} else if(delay_val > 1000) {
bad_ble->st.state = BadBleStateDelay; // Show long delays
bad_ble->st.delay_remain = delay_val / 1000;
}
} else {
furi_check((flags & FuriFlagError) == 0);
}
} else if(worker_state == BadBleStateWaitForBtn) { // State: Wait for button Press
uint32_t flags = bad_ble_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriWaitForever);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
delay_val = 0;
worker_state = BadBleStateRunning;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadBleStateNotConnected; // USB disconnected
bad_ble->hid->release_all(bad_ble->hid_inst);
}
bad_ble->st.state = worker_state;
continue;
}
} else if(worker_state == BadBleStatePaused) { // State: Paused
uint32_t flags = bad_ble_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriWaitForever);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadBleStateIdle; // Stop executing script
bad_ble->st.state = worker_state;
bad_ble->hid->release_all(bad_ble->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadBleStateNotConnected; // USB disconnected
bad_ble->st.state = worker_state;
bad_ble->hid->release_all(bad_ble->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
if(pause_state == BadBleStateRunning) {
if(delay_val > 0) {
bad_ble->st.state = BadBleStateDelay;
bad_ble->st.delay_remain = delay_val / 1000;
} else {
bad_ble->st.state = BadBleStateRunning;
delay_val = 0;
}
worker_state = BadBleStateRunning; // Resume
} else if(pause_state == BadBleStateStringDelay) {
bad_ble->st.state = BadBleStateRunning;
worker_state = BadBleStateStringDelay; // Resume
}
}
continue;
}
} else if(worker_state == BadBleStateStringDelay) { // State: print string with delays
uint32_t delay = (bad_ble->stringdelay == 0) ? bad_ble->defstringdelay :
bad_ble->stringdelay;
uint32_t flags = bad_ble_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
delay);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadBleStateIdle; // Stop executing script
bad_ble->hid->release_all(bad_ble->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadBleStateNotConnected; // USB disconnected
bad_ble->hid->release_all(bad_ble->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadBleStateStringDelay;
worker_state = BadBleStatePaused; // Pause
}
bad_ble->st.state = worker_state;
continue;
} else if(
(flags == (unsigned)FuriFlagErrorTimeout) ||
(flags == (unsigned)FuriFlagErrorResource)) {
bool string_end = ducky_string_next(bad_ble);
if(string_end) {
bad_ble->stringdelay = 0;
worker_state = BadBleStateRunning;
}
} else {
furi_check((flags & FuriFlagError) == 0);
}
} else if(
(worker_state == BadBleStateFileError) ||
(worker_state == BadBleStateScriptError)) { // State: error
uint32_t flags =
bad_ble_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
if(flags & WorkerEvtEnd) {
break;
}
}
}
bad_ble->hid->set_state_callback(bad_ble->hid_inst, NULL, NULL);
bad_ble->hid->deinit(bad_ble->hid_inst);
storage_file_close(script_file);
storage_file_free(script_file);
furi_string_free(bad_ble->line);
furi_string_free(bad_ble->line_prev);
furi_string_free(bad_ble->string_print);
FURI_LOG_I(WORKER_TAG, "End");
return 0;
}
static void bad_ble_script_set_default_keyboard_layout(BadBleScript* bad_ble) {
furi_assert(bad_ble);
memset(bad_ble->layout, HID_KEYBOARD_NONE, sizeof(bad_ble->layout));
memcpy(bad_ble->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_ble->layout)));
}
BadBleScript* bad_ble_script_open(FuriString* file_path, BadBleHidInterface interface) {
furi_assert(file_path);
BadBleScript* bad_ble = malloc(sizeof(BadBleScript));
bad_ble->file_path = furi_string_alloc();
furi_string_set(bad_ble->file_path, file_path);
bad_ble_script_set_default_keyboard_layout(bad_ble);
bad_ble->st.state = BadBleStateInit;
bad_ble->st.error[0] = '\0';
bad_ble->hid = bad_ble_hid_get_interface(interface);
bad_ble->thread = furi_thread_alloc_ex("BadBleWorker", 2048, bad_ble_worker, bad_ble);
furi_thread_start(bad_ble->thread);
return bad_ble;
} //-V773
void bad_ble_script_close(BadBleScript* bad_ble) {
furi_assert(bad_ble);
furi_thread_flags_set(furi_thread_get_id(bad_ble->thread), WorkerEvtEnd);
furi_thread_join(bad_ble->thread);
furi_thread_free(bad_ble->thread);
furi_string_free(bad_ble->file_path);
free(bad_ble);
}
void bad_ble_script_set_keyboard_layout(BadBleScript* bad_ble, FuriString* layout_path) {
furi_assert(bad_ble);
if((bad_ble->st.state == BadBleStateRunning) || (bad_ble->st.state == BadBleStateDelay)) {
// 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)) { //-V1051
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_ble->layout, layout, sizeof(layout));
}
}
storage_file_close(layout_file);
} else {
bad_ble_script_set_default_keyboard_layout(bad_ble);
}
storage_file_free(layout_file);
}
void bad_ble_script_start_stop(BadBleScript* bad_ble) {
furi_assert(bad_ble);
furi_thread_flags_set(furi_thread_get_id(bad_ble->thread), WorkerEvtStartStop);
}
void bad_ble_script_pause_resume(BadBleScript* bad_ble) {
furi_assert(bad_ble);
furi_thread_flags_set(furi_thread_get_id(bad_ble->thread), WorkerEvtPauseResume);
}
BadBleState* bad_ble_script_get_state(BadBleScript* bad_ble) {
furi_assert(bad_ble);
return &(bad_ble->st);
}

View File

@@ -1,55 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <furi.h>
#include <furi_hal.h>
#include "bad_ble_hid.h"
typedef enum {
BadBleStateInit,
BadBleStateNotConnected,
BadBleStateIdle,
BadBleStateWillRun,
BadBleStateRunning,
BadBleStateDelay,
BadBleStateStringDelay,
BadBleStateWaitForBtn,
BadBleStatePaused,
BadBleStateDone,
BadBleStateScriptError,
BadBleStateFileError,
} BadBleWorkerState;
typedef struct {
BadBleWorkerState state;
size_t line_cur;
size_t line_nb;
uint32_t delay_remain;
size_t error_line;
char error[64];
} BadBleState;
typedef struct BadBleScript BadBleScript;
BadBleScript* bad_ble_script_open(FuriString* file_path, BadBleHidInterface interface);
void bad_ble_script_close(BadBleScript* bad_ble);
void bad_ble_script_set_keyboard_layout(BadBleScript* bad_ble, FuriString* layout_path);
void bad_ble_script_start(BadBleScript* bad_ble);
void bad_ble_script_stop(BadBleScript* bad_ble);
void bad_ble_script_start_stop(BadBleScript* bad_ble);
void bad_ble_script_pause_resume(BadBleScript* bad_ble);
BadBleState* bad_ble_script_get_state(BadBleScript* bad_ble);
#ifdef __cplusplus
}
#endif

View File

@@ -1,241 +0,0 @@
#include <furi_hal.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
typedef int32_t (*DuckyCmdCallback)(BadBleScript* bad_usb, const char* line, int32_t param);
typedef struct {
char* name;
DuckyCmdCallback callback;
int32_t param;
} DuckyCmd;
static int32_t ducky_fnc_delay(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint32_t delay_val = 0;
bool state = ducky_get_number(line, &delay_val);
if((state) && (delay_val > 0)) {
return (int32_t)delay_val;
}
return ducky_error(bad_usb, "Invalid number %s", line);
}
static int32_t ducky_fnc_defdelay(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_usb->defdelay);
if(!state) {
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_strdelay(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_usb->stringdelay);
if(!state) {
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_defstrdelay(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_usb->defstringdelay);
if(!state) {
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_string(BadBleScript* bad_usb, const char* line, int32_t param) {
line = &line[ducky_get_command_len(line) + 1];
furi_string_set_str(bad_usb->string_print, line);
if(param == 1) {
furi_string_cat(bad_usb->string_print, "\n");
}
if(bad_usb->stringdelay == 0 &&
bad_usb->defstringdelay == 0) { // stringdelay not set - run command immediately
bool state = ducky_string(bad_usb, furi_string_get_cstr(bad_usb->string_print));
if(!state) {
return ducky_error(bad_usb, "Invalid string %s", line);
}
} else { // stringdelay is set - run command in thread to keep handling external events
return SCRIPT_STATE_STRING_START;
}
return 0;
}
static int32_t ducky_fnc_repeat(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_usb->repeat_cnt);
if((!state) || (bad_usb->repeat_cnt == 0)) {
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_sysrq(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->release_all(bad_usb->hid_inst);
return 0;
}
static int32_t ducky_fnc_altchar(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on(bad_usb);
bool state = ducky_altchar(bad_usb, line);
if(!state) {
return ducky_error(bad_usb, "Invalid altchar %s", line);
}
return 0;
}
static int32_t ducky_fnc_altstring(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on(bad_usb);
bool state = ducky_altstring(bad_usb, line);
if(!state) {
return ducky_error(bad_usb, "Invalid altstring %s", line);
}
return 0;
}
static int32_t ducky_fnc_hold(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_usb->key_hold_nb++;
if(bad_usb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
return ducky_error(bad_usb, "Too many keys are hold");
}
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
return 0;
}
static int32_t ducky_fnc_release(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
if(bad_usb->key_hold_nb == 0) {
return ducky_error(bad_usb, "No keys are hold");
}
bad_usb->key_hold_nb--;
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}
static int32_t ducky_fnc_media(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_media_keycode_by_name(line);
if(key == HID_CONSUMER_UNASSIGNED) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_usb->hid->consumer_press(bad_usb->hid_inst, key);
bad_usb->hid->consumer_release(bad_usb->hid_inst, key);
return 0;
}
static int32_t ducky_fnc_globe(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_usb->hid->consumer_press(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
bad_usb->hid->consumer_release(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE);
return 0;
}
static int32_t ducky_fnc_waitforbutton(BadBleScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
UNUSED(bad_usb);
UNUSED(line);
return SCRIPT_STATE_WAIT_FOR_BTN;
}
static const DuckyCmd ducky_commands[] = {
{"REM", NULL, -1},
{"ID", NULL, -1},
{"DELAY", ducky_fnc_delay, -1},
{"STRING", ducky_fnc_string, 0},
{"STRINGLN", ducky_fnc_string, 1},
{"DEFAULT_DELAY", ducky_fnc_defdelay, -1},
{"DEFAULTDELAY", ducky_fnc_defdelay, -1},
{"STRINGDELAY", ducky_fnc_strdelay, -1},
{"STRING_DELAY", ducky_fnc_strdelay, -1},
{"DEFAULT_STRING_DELAY", ducky_fnc_defstrdelay, -1},
{"DEFAULTSTRINGDELAY", ducky_fnc_defstrdelay, -1},
{"REPEAT", ducky_fnc_repeat, -1},
{"SYSRQ", ducky_fnc_sysrq, -1},
{"ALTCHAR", ducky_fnc_altchar, -1},
{"ALTSTRING", ducky_fnc_altstring, -1},
{"ALTCODE", ducky_fnc_altstring, -1},
{"HOLD", ducky_fnc_hold, -1},
{"RELEASE", ducky_fnc_release, -1},
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
{"MEDIA", ducky_fnc_media, -1},
{"GLOBE", ducky_fnc_globe, -1},
};
#define TAG "BadBle"
#define WORKER_TAG TAG "Worker"
int32_t ducky_execute_cmd(BadBleScript* bad_usb, const char* line) {
size_t cmd_word_len = strcspn(line, " ");
for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) {
size_t cmd_compare_len = strlen(ducky_commands[i].name);
if(cmd_compare_len != cmd_word_len) {
continue;
}
if(strncmp(line, ducky_commands[i].name, cmd_compare_len) == 0) {
if(ducky_commands[i].callback == NULL) {
return 0;
} else {
return (ducky_commands[i].callback)(bad_usb, line, ducky_commands[i].param);
}
}
}
return SCRIPT_STATE_CMD_UNKNOWN;
}

View File

@@ -1,76 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <furi.h>
#include <furi_hal.h>
#include "ducky_script.h"
#include "bad_ble_hid.h"
#define SCRIPT_STATE_ERROR (-1)
#define SCRIPT_STATE_END (-2)
#define SCRIPT_STATE_NEXT_LINE (-3)
#define SCRIPT_STATE_CMD_UNKNOWN (-4)
#define SCRIPT_STATE_STRING_START (-5)
#define SCRIPT_STATE_WAIT_FOR_BTN (-6)
#define FILE_BUFFER_LEN 16
struct BadBleScript {
FuriHalUsbHidConfig hid_cfg;
const BadBleHidApi* hid;
void* hid_inst;
FuriThread* thread;
BadBleState st;
FuriString* file_path;
uint8_t file_buf[FILE_BUFFER_LEN + 1];
uint8_t buf_start;
uint8_t buf_len;
bool file_end;
uint32_t defdelay;
uint32_t stringdelay;
uint32_t defstringdelay;
uint16_t layout[128];
FuriString* line;
FuriString* line_prev;
uint32_t repeat_cnt;
uint8_t key_hold_nb;
FuriString* string_print;
size_t string_print_pos;
};
uint16_t ducky_get_keycode(BadBleScript* bad_usb, const char* param, bool accept_chars);
uint32_t ducky_get_command_len(const char* line);
bool ducky_is_line_end(const char chr);
uint16_t ducky_get_keycode_by_name(const char* param);
uint16_t ducky_get_media_keycode_by_name(const char* param);
bool ducky_get_number(const char* param, uint32_t* val);
void ducky_numlock_on(BadBleScript* bad_usb);
bool ducky_numpad_press(BadBleScript* bad_usb, const char num);
bool ducky_altchar(BadBleScript* bad_usb, const char* charcode);
bool ducky_altstring(BadBleScript* bad_usb, const char* param);
bool ducky_string(BadBleScript* bad_usb, const char* param);
int32_t ducky_execute_cmd(BadBleScript* bad_usb, const char* line);
int32_t ducky_error(BadBleScript* bad_usb, const char* text, ...);
#ifdef __cplusplus
}
#endif

View File

@@ -1,133 +0,0 @@
#include <furi_hal.h>
#include "ducky_script_i.h"
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},
{"F13", HID_KEYBOARD_F13},
{"F14", HID_KEYBOARD_F14},
{"F15", HID_KEYBOARD_F15},
{"F16", HID_KEYBOARD_F16},
{"F17", HID_KEYBOARD_F17},
{"F18", HID_KEYBOARD_F18},
{"F19", HID_KEYBOARD_F19},
{"F20", HID_KEYBOARD_F20},
{"F21", HID_KEYBOARD_F21},
{"F22", HID_KEYBOARD_F22},
{"F23", HID_KEYBOARD_F23},
{"F24", HID_KEYBOARD_F24},
};
static const DuckyKey ducky_media_keys[] = {
{"POWER", HID_CONSUMER_POWER},
{"REBOOT", HID_CONSUMER_RESET},
{"SLEEP", HID_CONSUMER_SLEEP},
{"LOGOFF", HID_CONSUMER_AL_LOGOFF},
{"EXIT", HID_CONSUMER_AC_EXIT},
{"HOME", HID_CONSUMER_AC_HOME},
{"BACK", HID_CONSUMER_AC_BACK},
{"FORWARD", HID_CONSUMER_AC_FORWARD},
{"REFRESH", HID_CONSUMER_AC_REFRESH},
{"SNAPSHOT", HID_CONSUMER_SNAPSHOT},
{"PLAY", HID_CONSUMER_PLAY},
{"PAUSE", HID_CONSUMER_PAUSE},
{"PLAY_PAUSE", HID_CONSUMER_PLAY_PAUSE},
{"NEXT_TRACK", HID_CONSUMER_SCAN_NEXT_TRACK},
{"PREV_TRACK", HID_CONSUMER_SCAN_PREVIOUS_TRACK},
{"STOP", HID_CONSUMER_STOP},
{"EJECT", HID_CONSUMER_EJECT},
{"MUTE", HID_CONSUMER_MUTE},
{"VOLUME_UP", HID_CONSUMER_VOLUME_INCREMENT},
{"VOLUME_DOWN", HID_CONSUMER_VOLUME_DECREMENT},
{"FN", HID_CONSUMER_FN_GLOBE},
{"BRIGHT_UP", HID_CONSUMER_BRIGHTNESS_INCREMENT},
{"BRIGHT_DOWN", HID_CONSUMER_BRIGHTNESS_DECREMENT},
};
uint16_t ducky_get_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_keys); 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;
}
}
return HID_KEYBOARD_NONE;
}
uint16_t ducky_get_media_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_media_keys); i++) {
size_t key_cmd_len = strlen(ducky_media_keys[i].name);
if((strncmp(param, ducky_media_keys[i].name, key_cmd_len) == 0) &&
(ducky_is_line_end(param[key_cmd_len]))) {
return ducky_media_keys[i].keycode;
}
}
return HID_CONSUMER_UNASSIGNED;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

View File

@@ -1,30 +0,0 @@
#include "bad_ble_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const bad_ble_scene_on_enter_handlers[])(void*) = {
#include "bad_ble_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_ble_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "bad_ble_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_ble_scene_on_exit_handlers[])(void* context) = {
#include "bad_ble_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers bad_ble_scene_handlers = {
.on_enter_handlers = bad_ble_scene_on_enter_handlers,
.on_event_handlers = bad_ble_scene_on_event_handlers,
.on_exit_handlers = bad_ble_scene_on_exit_handlers,
.scene_num = BadBleSceneNum,
};

View File

@@ -1,29 +0,0 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) BadBleScene##id,
typedef enum {
#include "bad_ble_scene_config.h"
BadBleSceneNum,
} BadBleScene;
#undef ADD_SCENE
extern const SceneManagerHandlers bad_ble_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "bad_ble_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_ble_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_ble_scene_config.h"
#undef ADD_SCENE

View File

@@ -1,59 +0,0 @@
#include "../bad_ble_app_i.h"
enum SubmenuIndex {
ConfigIndexKeyboardLayout,
ConfigIndexBleUnpair,
};
void bad_ble_scene_config_select_callback(void* context, uint32_t index) {
BadBleApp* bad_ble = context;
view_dispatcher_send_custom_event(bad_ble->view_dispatcher, index);
}
static void draw_menu(BadBleApp* bad_ble) {
VariableItemList* var_item_list = bad_ble->var_item_list;
variable_item_list_reset(var_item_list);
variable_item_list_add(var_item_list, "Keyboard Layout (Global)", 0, NULL, NULL);
variable_item_list_add(var_item_list, "Unpair Device", 0, NULL, NULL);
}
void bad_ble_scene_config_on_enter(void* context) {
BadBleApp* bad_ble = context;
VariableItemList* var_item_list = bad_ble->var_item_list;
variable_item_list_set_enter_callback(
var_item_list, bad_ble_scene_config_select_callback, bad_ble);
draw_menu(bad_ble);
variable_item_list_set_selected_item(var_item_list, 0);
view_dispatcher_switch_to_view(bad_ble->view_dispatcher, BadBleAppViewConfig);
}
bool bad_ble_scene_config_on_event(void* context, SceneManagerEvent event) {
BadBleApp* bad_ble = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == ConfigIndexKeyboardLayout) {
scene_manager_next_scene(bad_ble->scene_manager, BadBleSceneConfigLayout);
} else if(event.event == ConfigIndexBleUnpair) {
scene_manager_next_scene(bad_ble->scene_manager, BadBleSceneConfirmUnpair);
} else {
furi_crash("Unknown key type");
}
}
return consumed;
}
void bad_ble_scene_config_on_exit(void* context) {
BadBleApp* bad_ble = context;
VariableItemList* var_item_list = bad_ble->var_item_list;
variable_item_list_reset(var_item_list);
}

View File

@@ -1,7 +0,0 @@
ADD_SCENE(bad_ble, file_select, FileSelect)
ADD_SCENE(bad_ble, work, Work)
ADD_SCENE(bad_ble, error, Error)
ADD_SCENE(bad_ble, config, Config)
ADD_SCENE(bad_ble, config_layout, ConfigLayout)
ADD_SCENE(bad_ble, confirm_unpair, ConfirmUnpair)
ADD_SCENE(bad_ble, unpair_done, UnpairDone)

View File

@@ -1,49 +0,0 @@
#include "../bad_ble_app_i.h"
#include <storage/storage.h>
static bool bad_ble_layout_select(BadBleApp* bad_ble) {
furi_assert(bad_ble);
FuriString* predefined_path;
predefined_path = furi_string_alloc();
if(!furi_string_empty(bad_ble->keyboard_layout)) {
furi_string_set(predefined_path, bad_ble->keyboard_layout);
} else {
furi_string_set(predefined_path, BAD_BLE_APP_PATH_LAYOUT_FOLDER);
}
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, BAD_BLE_APP_LAYOUT_EXTENSION, &I_keyboard_10px);
browser_options.base_path = BAD_BLE_APP_PATH_LAYOUT_FOLDER;
browser_options.skip_assets = false;
// Input events and views are managed by file_browser
bool res = dialog_file_browser_show(
bad_ble->dialogs, bad_ble->keyboard_layout, predefined_path, &browser_options);
furi_string_free(predefined_path);
return res;
}
void bad_ble_scene_config_layout_on_enter(void* context) {
BadBleApp* bad_ble = context;
if(bad_ble_layout_select(bad_ble)) {
scene_manager_search_and_switch_to_previous_scene(bad_ble->scene_manager, BadBleSceneWork);
} else {
scene_manager_previous_scene(bad_ble->scene_manager);
}
}
bool bad_ble_scene_config_layout_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
// BadBleApp* bad_ble = context;
return false;
}
void bad_ble_scene_config_layout_on_exit(void* context) {
UNUSED(context);
// BadBleApp* bad_ble = context;
}

View File

@@ -1,65 +0,0 @@
#include "../bad_ble_app_i.h"
typedef enum {
BadBleCustomEventErrorBack,
} BadBleCustomEvent;
static void
bad_ble_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
BadBleApp* app = context;
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
view_dispatcher_send_custom_event(app->view_dispatcher, BadBleCustomEventErrorBack);
}
}
void bad_ble_scene_error_on_enter(void* context) {
BadBleApp* app = context;
if(app->error == BadBleAppErrorNoFiles) {
widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43);
widget_add_string_multiline_element(
app->widget,
81,
4,
AlignCenter,
AlignTop,
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_ble_scene_error_event_callback, app);
} else if(app->error == BadBleAppErrorCloseRpc) {
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
widget_add_string_multiline_element(
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nIs Active!");
widget_add_string_multiline_element(
app->widget,
3,
30,
AlignLeft,
AlignTop,
FontSecondary,
"Disconnect from\nPC or phone to\nuse this function.");
}
view_dispatcher_switch_to_view(app->view_dispatcher, BadBleAppViewWidget);
}
bool bad_ble_scene_error_on_event(void* context, SceneManagerEvent event) {
BadBleApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == BadBleCustomEventErrorBack) {
view_dispatcher_stop(app->view_dispatcher);
consumed = true;
}
}
return consumed;
}
void bad_ble_scene_error_on_exit(void* context) {
BadBleApp* app = context;
widget_reset(app->widget);
}

View File

@@ -1,46 +0,0 @@
#include "../bad_ble_app_i.h"
#include <furi_hal_power.h>
#include <storage/storage.h>
static bool bad_ble_file_select(BadBleApp* bad_ble) {
furi_assert(bad_ble);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, BAD_BLE_APP_SCRIPT_EXTENSION, &I_badusb_10px);
browser_options.base_path = BAD_BLE_APP_BASE_FOLDER;
browser_options.skip_assets = true;
// Input events and views are managed by file_browser
bool res = dialog_file_browser_show(
bad_ble->dialogs, bad_ble->file_path, bad_ble->file_path, &browser_options);
return res;
}
void bad_ble_scene_file_select_on_enter(void* context) {
BadBleApp* bad_ble = context;
if(bad_ble->bad_ble_script) {
bad_ble_script_close(bad_ble->bad_ble_script);
bad_ble->bad_ble_script = NULL;
}
if(bad_ble_file_select(bad_ble)) {
scene_manager_next_scene(bad_ble->scene_manager, BadBleSceneWork);
} else {
view_dispatcher_stop(bad_ble->view_dispatcher);
}
}
bool bad_ble_scene_file_select_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
// BadBleApp* bad_ble = context;
return false;
}
void bad_ble_scene_file_select_on_exit(void* context) {
UNUSED(context);
// BadBleApp* bad_ble = context;
}

View File

@@ -1,37 +0,0 @@
#include "../bad_ble_app_i.h"
static void bad_ble_scene_unpair_done_popup_callback(void* context) {
BadBleApp* bad_ble = context;
scene_manager_search_and_switch_to_previous_scene(bad_ble->scene_manager, BadBleSceneConfig);
}
void bad_ble_scene_unpair_done_on_enter(void* context) {
BadBleApp* bad_ble = context;
Popup* popup = bad_ble->popup;
popup_set_icon(popup, 48, 4, &I_DolphinDone_80x58);
popup_set_header(popup, "Done", 20, 19, AlignLeft, AlignBottom);
popup_set_callback(popup, bad_ble_scene_unpair_done_popup_callback);
popup_set_context(popup, bad_ble);
popup_set_timeout(popup, 1000);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(bad_ble->view_dispatcher, BadBleAppViewPopup);
}
bool bad_ble_scene_unpair_done_on_event(void* context, SceneManagerEvent event) {
BadBleApp* bad_ble = context;
UNUSED(bad_ble);
UNUSED(event);
bool consumed = false;
return consumed;
}
void bad_ble_scene_unpair_done_on_exit(void* context) {
BadBleApp* bad_ble = context;
Popup* popup = bad_ble->popup;
popup_reset(popup);
}

View File

@@ -1,65 +0,0 @@
#include "../helpers/ducky_script.h"
#include "../bad_ble_app_i.h"
#include "../views/bad_ble_view.h"
#include <furi_hal.h>
#include "toolbox/path.h"
void bad_ble_scene_work_button_callback(InputKey key, void* context) {
furi_assert(context);
BadBleApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, key);
}
bool bad_ble_scene_work_on_event(void* context, SceneManagerEvent event) {
BadBleApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InputKeyLeft) {
if(bad_ble_view_is_idle_state(app->bad_ble_view)) {
bad_ble_script_close(app->bad_ble_script);
app->bad_ble_script = NULL;
scene_manager_next_scene(app->scene_manager, BadBleSceneConfig);
}
consumed = true;
} else if(event.event == InputKeyOk) {
bad_ble_script_start_stop(app->bad_ble_script);
consumed = true;
} else if(event.event == InputKeyRight) {
bad_ble_script_pause_resume(app->bad_ble_script);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
bad_ble_view_set_state(app->bad_ble_view, bad_ble_script_get_state(app->bad_ble_script));
}
return consumed;
}
void bad_ble_scene_work_on_enter(void* context) {
BadBleApp* app = context;
app->bad_ble_script = bad_ble_script_open(app->file_path, app->interface);
bad_ble_script_set_keyboard_layout(app->bad_ble_script, app->keyboard_layout);
FuriString* file_name;
file_name = furi_string_alloc();
path_extract_filename(app->file_path, file_name, true);
bad_ble_view_set_file_name(app->bad_ble_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_ble_view_set_layout(app->bad_ble_view, furi_string_get_cstr(layout));
furi_string_free(layout);
bad_ble_view_set_state(app->bad_ble_view, bad_ble_script_get_state(app->bad_ble_script));
bad_ble_view_set_button_callback(app->bad_ble_view, bad_ble_scene_work_button_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, BadBleAppViewWork);
}
void bad_ble_scene_work_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,284 +0,0 @@
#include "bad_ble_view.h"
#include "../helpers/ducky_script.h"
#include <toolbox/path.h>
#include <gui/elements.h>
#include <assets_icons.h>
#include "bad_ble_icons.h"
#define MAX_NAME_LEN 64
struct BadBle {
View* view;
BadBleButtonCallback callback;
void* context;
};
typedef struct {
char file_name[MAX_NAME_LEN];
char layout[MAX_NAME_LEN];
BadBleState state;
bool pause_wait;
uint8_t anim_frame;
} BadBleModel;
static void bad_ble_draw_callback(Canvas* canvas, void* _model) {
BadBleModel* model = _model;
FuriString* disp_str;
disp_str = furi_string_alloc_set(model->file_name);
elements_string_fit_width(canvas, disp_str, 128 - 2);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
if(strlen(model->layout) == 0) {
furi_string_set(disp_str, "(default)");
} else {
furi_string_printf(disp_str, "(%s)", model->layout);
}
elements_string_fit_width(canvas, disp_str, 128 - 2);
canvas_draw_str(
canvas, 2, 8 + canvas_current_font_height(canvas), furi_string_get_cstr(disp_str));
furi_string_reset(disp_str);
canvas_draw_icon(canvas, 22, 24, &I_Bad_BLE_48x22);
BadBleWorkerState state = model->state.state;
if((state == BadBleStateIdle) || (state == BadBleStateDone) ||
(state == BadBleStateNotConnected)) {
elements_button_center(canvas, "Run");
elements_button_left(canvas, "Config");
} else if((state == BadBleStateRunning) || (state == BadBleStateDelay)) {
elements_button_center(canvas, "Stop");
if(!model->pause_wait) {
elements_button_right(canvas, "Pause");
}
} else if(state == BadBleStatePaused) {
elements_button_center(canvas, "End");
elements_button_right(canvas, "Resume");
} else if(state == BadBleStateWaitForBtn) {
elements_button_center(canvas, "Press to continue");
} else if(state == BadBleStateWillRun) {
elements_button_center(canvas, "Cancel");
}
if(state == BadBleStateNotConnected) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to device");
} else if(state == BadBleStateWillRun) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect");
} else if(state == BadBleStateFileError) {
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(state == BadBleStateScriptError) {
canvas_draw_icon(canvas, 4, 26, &I_Error_18x18);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:");
canvas_set_font(canvas, FontSecondary);
furi_string_printf(disp_str, "line %zu", model->state.error_line);
canvas_draw_str_aligned(
canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
furi_string_reset(disp_str);
furi_string_set_str(disp_str, model->state.error);
elements_string_fit_width(canvas, disp_str, canvas_width(canvas));
canvas_draw_str_aligned(
canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
furi_string_reset(disp_str);
} else if(state == BadBleStateIdle) {
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(state == BadBleStateRunning) {
if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
} else {
canvas_draw_icon(canvas, 4, 23, &I_EviSmile2_18x21);
}
canvas_set_font(canvas, FontBigNumbers);
furi_string_printf(
disp_str, "%zu", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
canvas_draw_str_aligned(
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(state == BadBleStateDone) {
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(state == BadBleStateDelay) {
if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21);
} else {
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21);
}
canvas_set_font(canvas, FontBigNumbers);
furi_string_printf(
disp_str, "%zu", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
canvas_draw_str_aligned(
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);
canvas_set_font(canvas, FontSecondary);
furi_string_printf(disp_str, "delay %lus", model->state.delay_remain);
canvas_draw_str_aligned(
canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
furi_string_reset(disp_str);
} else if((state == BadBleStatePaused) || (state == BadBleStateWaitForBtn)) {
if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21);
} else {
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21);
}
canvas_set_font(canvas, FontBigNumbers);
furi_string_printf(
disp_str, "%zu", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
canvas_draw_str_aligned(
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);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 127, 50, AlignRight, AlignBottom, "Paused");
furi_string_reset(disp_str);
} else {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
}
furi_string_free(disp_str);
}
static bool bad_ble_input_callback(InputEvent* event, void* context) {
furi_assert(context);
BadBle* bad_ble = context;
bool consumed = false;
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
consumed = true;
furi_assert(bad_ble->callback);
bad_ble->callback(event->key, bad_ble->context);
} else if(event->key == InputKeyOk) {
with_view_model(
bad_ble->view, BadBleModel * model, { model->pause_wait = false; }, true);
consumed = true;
furi_assert(bad_ble->callback);
bad_ble->callback(event->key, bad_ble->context);
} else if(event->key == InputKeyRight) {
with_view_model(
bad_ble->view,
BadBleModel * model,
{
if((model->state.state == BadBleStateRunning) ||
(model->state.state == BadBleStateDelay)) {
model->pause_wait = true;
}
},
true);
consumed = true;
furi_assert(bad_ble->callback);
bad_ble->callback(event->key, bad_ble->context);
}
}
return consumed;
}
BadBle* bad_ble_view_alloc(void) {
BadBle* bad_ble = malloc(sizeof(BadBle));
bad_ble->view = view_alloc();
view_allocate_model(bad_ble->view, ViewModelTypeLocking, sizeof(BadBleModel));
view_set_context(bad_ble->view, bad_ble);
view_set_draw_callback(bad_ble->view, bad_ble_draw_callback);
view_set_input_callback(bad_ble->view, bad_ble_input_callback);
return bad_ble;
}
void bad_ble_view_free(BadBle* bad_ble) {
furi_assert(bad_ble);
view_free(bad_ble->view);
free(bad_ble);
}
View* bad_ble_view_get_view(BadBle* bad_ble) {
furi_assert(bad_ble);
return bad_ble->view;
}
void bad_ble_view_set_button_callback(
BadBle* bad_ble,
BadBleButtonCallback callback,
void* context) {
furi_assert(bad_ble);
furi_assert(callback);
with_view_model(
bad_ble->view,
BadBleModel * model,
{
UNUSED(model);
bad_ble->callback = callback;
bad_ble->context = context;
},
true);
}
void bad_ble_view_set_file_name(BadBle* bad_ble, const char* name) {
furi_assert(name);
with_view_model(
bad_ble->view,
BadBleModel * model,
{ strlcpy(model->file_name, name, MAX_NAME_LEN); },
true);
}
void bad_ble_view_set_layout(BadBle* bad_ble, const char* layout) {
furi_assert(layout);
with_view_model(
bad_ble->view,
BadBleModel * model,
{ strlcpy(model->layout, layout, MAX_NAME_LEN); },
true);
}
void bad_ble_view_set_state(BadBle* bad_ble, BadBleState* st) {
furi_assert(st);
with_view_model(
bad_ble->view,
BadBleModel * model,
{
memcpy(&(model->state), st, sizeof(BadBleState));
model->anim_frame ^= 1;
if(model->state.state == BadBleStatePaused) {
model->pause_wait = false;
}
},
true);
}
bool bad_ble_view_is_idle_state(BadBle* bad_ble) {
bool is_idle = false;
with_view_model(
bad_ble->view,
BadBleModel * model,
{
if((model->state.state == BadBleStateIdle) ||
(model->state.state == BadBleStateDone) ||
(model->state.state == BadBleStateNotConnected)) {
is_idle = true;
}
},
false);
return is_idle;
}

View File

@@ -1,26 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/ducky_script.h"
typedef struct BadBle BadBle;
typedef void (*BadBleButtonCallback)(InputKey key, void* context);
BadBle* bad_ble_view_alloc(void);
void bad_ble_view_free(BadBle* bad_ble);
View* bad_ble_view_get_view(BadBle* bad_ble);
void bad_ble_view_set_button_callback(
BadBle* bad_ble,
BadBleButtonCallback callback,
void* context);
void bad_ble_view_set_file_name(BadBle* bad_ble, const char* name);
void bad_ble_view_set_layout(BadBle* bad_ble, const char* layout);
void bad_ble_view_set_state(BadBle* bad_ble, BadBleState* st);
bool bad_ble_view_is_idle_state(BadBle* bad_ble);

View File

@@ -2,7 +2,7 @@ let serial = require("serial");
serial.setup("usart", 230400); serial.setup("usart", 230400);
while (1) { while (1) {
let rx_data = serial.readBytes(1, 0); let rx_data = serial.readBytes(1, 1000);
if (rx_data !== undefined) { if (rx_data !== undefined) {
serial.write(rx_data); serial.write(rx_data);
let data_view = Uint8Array(rx_data); let data_view = Uint8Array(rx_data);

View File

@@ -78,4 +78,4 @@ export declare function print(string: string, delay?: number): void;
* @param string The string to print * @param string The string to print
* @param delay How many milliseconds to wait between key presses * @param delay How many milliseconds to wait between key presses
*/ */
export declare function println(): void; export declare function println(string: string, delay?: number): void;

View File

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 145 B

View File

@@ -9,7 +9,7 @@ It's important to regularly update your Developer Board to ensure that you have
## Step 1. Install the micro Flipper Build Tool ## Step 1. Install the micro Flipper Build Tool
is a cross-platform tool developed and supported by our team that enables basic development tasks for Flipper Zero, such as building and debugging applications, flashing firmware, creating VS Code development configurations, and flashing firmware to the Wi-Fi Developer Board. [micro Flipper Build Tool (uFBT)](https://pypi.org/project/ufbt/) is a cross-platform tool developed and supported by our team that enables basic development tasks for Flipper Zero, such as building and debugging applications, flashing firmware, creating VS Code development configurations, and flashing firmware to the Wi-Fi Developer Board.
**On Linux & macOS:** **On Linux & macOS:**
@@ -43,15 +43,15 @@ To update the firmware, you need to switch your Developer Board to Bootloader mo
- **Windows:** Go to **Device Manager** and expand the **Ports (COM & LPT)** section. - **Windows:** Go to **Device Manager** and expand the **Ports (COM & LPT)** section.
2. Connect the Developer Board to your computer using a USB-C cable. 2. Connect the Developer Board to your computer using a USB-C cable.
\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_update_wired_connection.jpg width=700 \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_update_wired_connection.jpg width=700
3. Switch your Developer Board to Bootloader mode: 3. Switch your Developer Board to Bootloader mode:
1. Press and hold the **BOOT** button. 3.1. Press and hold the **BOOT** button.
2. Press the **RESET** button while holding the **BOOT** button.
3. Release the **BOOT** button.
3.2. Press the **RESET** button while holding the **BOOT** button.
3.3. Release the **BOOT** button.
\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_to_bootloader.png width=700 \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_to_bootloader.png width=700
4. Repeat **Step 1** and view the name of your Developer Board that appeared in the list. 4. Repeat **Step 1** and view the name of your Developer Board that appeared in the list.
@@ -101,7 +101,6 @@ To fix it, try doing the following:
## Step 4. Finish the installation ## Step 4. Finish the installation
1. Reboot the Developer Board by pressing the **RESET** button. 1. Reboot the Developer Board by pressing the **RESET** button.
\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_after_flashing.jpg width=700 \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_after_flashing.jpg width=700
2. Disconnect and reconnect the USB-C cable. 2. Disconnect and reconnect the USB-C cable.

View File

@@ -1,4 +1,4 @@
# Get started with the Dev Board {#dev_board_get_started} # Get started with the Devboard {#dev_board_get_started}
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_developer_board_box_CDN.jpg width=700 \image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_developer_board_box_CDN.jpg width=700

View File

@@ -1,4 +1,4 @@
# Reading logs via the Dev Board {#dev_board_reading_logs} # Reading logs via the Devboard {#dev_board_reading_logs}
The Developer Board allows you to read Flipper Zero logs via UART. Unlike reading logs via the command-line interface (CLI), the Developer Board enables you to collect logs from the device directly to a serial console independently from the operating system of Flipper Zero. It allows you to see the device's logs when it's loading, updating, or crashing. It's useful for debugging and troubleshooting during software development. The Developer Board allows you to read Flipper Zero logs via UART. Unlike reading logs via the command-line interface (CLI), the Developer Board enables you to collect logs from the device directly to a serial console independently from the operating system of Flipper Zero. It allows you to see the device's logs when it's loading, updating, or crashing. It's useful for debugging and troubleshooting during software development.

View File

@@ -54,7 +54,6 @@ To connect the Developer Board in **Wi-Fi client** mode, you need to configure i
4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby 2.4 GHz networks (5 GHz networks aren't supported). 4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby 2.4 GHz networks (5 GHz networks aren't supported).
5. Save the configuration and reboot the Developer Board. 5. Save the configuration and reboot the Developer Board.
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_connect_to_WiFi_CDN.jpg width=700 \image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_connect_to_WiFi_CDN.jpg width=700
6. Now, you can access the Devboard's web interface at [http://blackmagic.local](https://blackmagic.local) via the existing Wi-Fi network without losing connection to the internet. 6. Now, you can access the Devboard's web interface at [http://blackmagic.local](https://blackmagic.local) via the existing Wi-Fi network without losing connection to the internet.

View File

@@ -119,8 +119,6 @@ FuriStatus furi_timer_stop(FuriTimer* instance) {
furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS);
furi_timer_flush();
return FuriStatusOk; return FuriStatusOk;
} }