mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge branch 'ul-dev' into xfw-dev
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -30,7 +30,7 @@ bindings/
|
||||
Brewfile.lock.json
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
/.vscode/
|
||||
|
||||
# Visual Studio
|
||||
.vs/
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
App(
|
||||
appid="UART_Echo",
|
||||
name="[GPIO] UART Echo",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="uart_echo_app",
|
||||
cdefines=["APP_UART_ECHO"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
fap_icon="uart_10px.png",
|
||||
fap_category="GPIO",
|
||||
fap_category="Debug",
|
||||
)
|
||||
|
||||
@@ -84,7 +84,7 @@ static void test_rpc_setup(void) {
|
||||
|
||||
rpc = furi_record_open(RECORD_RPC);
|
||||
for(int i = 0; !(rpc_session[0].session) && (i < 10000); ++i) {
|
||||
rpc_session[0].session = rpc_session_open(rpc);
|
||||
rpc_session[0].session = rpc_session_open(rpc, RpcOwnerUnknown);
|
||||
furi_delay_tick(1);
|
||||
}
|
||||
furi_check(rpc_session[0].session);
|
||||
@@ -104,7 +104,7 @@ static void test_rpc_setup_second_session(void) {
|
||||
furi_check(!(rpc_session[1].session));
|
||||
|
||||
for(int i = 0; !(rpc_session[1].session) && (i < 10000); ++i) {
|
||||
rpc_session[1].session = rpc_session_open(rpc);
|
||||
rpc_session[1].session = rpc_session_open(rpc, RpcOwnerUnknown);
|
||||
furi_delay_tick(1);
|
||||
}
|
||||
furi_check(rpc_session[1].session);
|
||||
|
||||
@@ -152,7 +152,12 @@ bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
||||
|
||||
if(instance->spi) {
|
||||
avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
|
||||
instance->cfg->lockbytes = instance->buff[6];
|
||||
instance->cfg->fusebytes = instance->buff[7];
|
||||
instance->cfg->flashpoll = instance->buff[8];
|
||||
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as “flashpoll”
|
||||
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as <EFBFBD>flashpoll<EFBFBD>
|
||||
instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
|
||||
instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
|
||||
instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
|
||||
@@ -317,7 +317,12 @@ static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
||||
|
||||
if(instance->spi) {
|
||||
avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ App(
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flipfrid_start",
|
||||
requires=["gui", "storage", "dialogs", "input", "notification"],
|
||||
stack_size=1 * 1024,
|
||||
stack_size=2 * 1024,
|
||||
order=180,
|
||||
fap_icon="rfid_10px.png",
|
||||
fap_category="Tools",
|
||||
|
||||
18
applications/external/flipfrid/flipfrid.c
vendored
18
applications/external/flipfrid/flipfrid.c
vendored
@@ -61,6 +61,16 @@ FlipFridState* flipfrid_alloc() {
|
||||
flipfrid->proto_name = furi_string_alloc();
|
||||
flipfrid->data_str = furi_string_alloc();
|
||||
|
||||
flipfrid->main_menu_items[0] = furi_string_alloc_set("Default Values");
|
||||
flipfrid->main_menu_items[1] = furi_string_alloc_set("BF Customer ID");
|
||||
flipfrid->main_menu_items[2] = furi_string_alloc_set("Load File");
|
||||
flipfrid->main_menu_items[3] = furi_string_alloc_set("Load UIDs from file");
|
||||
|
||||
flipfrid->main_menu_proto_items[0] = furi_string_alloc_set("EM4100");
|
||||
flipfrid->main_menu_proto_items[1] = furi_string_alloc_set("HIDProx");
|
||||
flipfrid->main_menu_proto_items[2] = furi_string_alloc_set("PAC/Stanley");
|
||||
flipfrid->main_menu_proto_items[3] = furi_string_alloc_set("H10301");
|
||||
|
||||
flipfrid->previous_scene = NoneScene;
|
||||
flipfrid->current_scene = SceneEntryPoint;
|
||||
flipfrid->is_running = true;
|
||||
@@ -103,6 +113,14 @@ void flipfrid_free(FlipFridState* flipfrid) {
|
||||
furi_string_free(flipfrid->proto_name);
|
||||
furi_string_free(flipfrid->data_str);
|
||||
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(flipfrid->main_menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(flipfrid->main_menu_proto_items[i]);
|
||||
}
|
||||
|
||||
free(flipfrid->data);
|
||||
free(flipfrid->payload);
|
||||
|
||||
|
||||
2
applications/external/flipfrid/flipfrid.h
vendored
2
applications/external/flipfrid/flipfrid.h
vendored
@@ -75,6 +75,8 @@ typedef struct {
|
||||
FlipFridProtos proto;
|
||||
FuriString* attack_name;
|
||||
FuriString* proto_name;
|
||||
FuriString* main_menu_items[4];
|
||||
FuriString* main_menu_proto_items[4];
|
||||
|
||||
DialogsApp* dialogs;
|
||||
FuriString* notification_msg;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
FuriString* main_menu_items[4];
|
||||
FuriString* main_menu_proto_items[4];
|
||||
|
||||
void flipfrid_scene_entrypoint_menu_callback(
|
||||
FlipFridState* context,
|
||||
uint32_t index,
|
||||
@@ -68,31 +65,14 @@ void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
|
||||
menu_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
main_menu_items[0] = furi_string_alloc_set("Default Values");
|
||||
main_menu_items[1] = furi_string_alloc_set("BF Customer ID");
|
||||
main_menu_items[2] = furi_string_alloc_set("Load File");
|
||||
main_menu_items[3] = furi_string_alloc_set("Load UIDs from file");
|
||||
|
||||
context->menu_proto_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_proto_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
main_menu_proto_items[0] = furi_string_alloc_set("EM4100");
|
||||
main_menu_proto_items[1] = furi_string_alloc_set("HIDProx");
|
||||
main_menu_proto_items[2] = furi_string_alloc_set("PAC/Stanley");
|
||||
main_menu_proto_items[3] = furi_string_alloc_set("H10301");
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(main_menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(main_menu_proto_items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) {
|
||||
@@ -145,73 +125,77 @@ void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(main_menu_items[context->menu_index] != NULL) {
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(context->main_menu_items != NULL) {
|
||||
if(context->main_menu_items[context->menu_index] != NULL) {
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index]));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index]));
|
||||
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
|
||||
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
furi_string_get_cstr(context->main_menu_proto_items[context->menu_proto_index]));
|
||||
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index]));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
if(context->menu_proto_index < H10301) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index + 1]));
|
||||
if(context->menu_proto_index < H10301) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
applications/external/gps_nmea_uart/gps.c
vendored
20
applications/external/gps_nmea_uart/gps.c
vendored
@@ -139,20 +139,14 @@ int32_t gps_app(void* p) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
gps_uart_deinit_thread(gps_uart);
|
||||
switch(gps_uart->baudrate) {
|
||||
case GPS_BAUDRATE_9k:
|
||||
gps_uart->baudrate = GPS_BAUDRATE_57k;
|
||||
break;
|
||||
case GPS_BAUDRATE_57k:
|
||||
gps_uart->baudrate = GPS_BAUDRATE_115k;
|
||||
break;
|
||||
case GPS_BAUDRATE_115k:
|
||||
gps_uart->baudrate = GPS_BAUDRATE_9k;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
const int baudrate_length =
|
||||
sizeof(gps_baudrates) / sizeof(gps_baudrates[0]);
|
||||
current_gps_baudrate++;
|
||||
if(current_gps_baudrate >= baudrate_length) {
|
||||
current_gps_baudrate = 0;
|
||||
}
|
||||
gps_uart->baudrate = gps_baudrates[current_gps_baudrate];
|
||||
|
||||
gps_uart_init_thread(gps_uart);
|
||||
gps_uart->changing_baudrate = true;
|
||||
view_port_update(view_port);
|
||||
|
||||
@@ -169,7 +169,7 @@ GpsUart* gps_uart_enable() {
|
||||
|
||||
gps_uart->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
gps_uart->baudrate = GPS_BAUDRATE_57k;
|
||||
gps_uart->baudrate = gps_baudrates[current_gps_baudrate];
|
||||
|
||||
gps_uart_init_thread(gps_uart);
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
#include <furi_hal.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#define GPS_BAUDRATE_9k 9600
|
||||
#define GPS_BAUDRATE_57k 57600
|
||||
#define GPS_BAUDRATE_115k 115200
|
||||
#define RX_BUF_SIZE 1024
|
||||
|
||||
static const int gps_baudrates[5] = {9600, 19200, 38400, 57600, 115200};
|
||||
static int current_gps_baudrate = 3;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
float latitude;
|
||||
|
||||
BIN
applications/external/hid_app/assets/Pause_icon_9x9.png
vendored
Normal file
BIN
applications/external/hid_app/assets/Pause_icon_9x9.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
41
applications/external/hid_app/hid.c
vendored
41
applications/external/hid_app/hid.c
vendored
@@ -7,9 +7,11 @@
|
||||
|
||||
enum HidDebugSubmenuIndex {
|
||||
HidSubmenuIndexKeynote,
|
||||
HidSubmenuIndexKeynoteVertical,
|
||||
HidSubmenuIndexKeyboard,
|
||||
HidSubmenuIndexMedia,
|
||||
HidSubmenuIndexTikTok,
|
||||
HidSubmenuIndexYTShorts,
|
||||
HidSubmenuIndexMouse,
|
||||
HidSubmenuIndexMouseJiggler,
|
||||
};
|
||||
@@ -20,6 +22,9 @@ static void hid_submenu_callback(void* context, uint32_t index) {
|
||||
if(index == HidSubmenuIndexKeynote) {
|
||||
app->view_id = HidViewKeynote;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote);
|
||||
} else if(index == HidSubmenuIndexKeynoteVertical) {
|
||||
app->view_id = HidViewKeynoteVertical;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynoteVertical);
|
||||
} else if(index == HidSubmenuIndexKeyboard) {
|
||||
app->view_id = HidViewKeyboard;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeyboard);
|
||||
@@ -32,6 +37,9 @@ static void hid_submenu_callback(void* context, uint32_t index) {
|
||||
} else if(index == HidSubmenuIndexTikTok) {
|
||||
app->view_id = BtHidViewTikTok;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok);
|
||||
} else if(index == HidSubmenuIndexYTShorts) {
|
||||
app->view_id = BtHidViewYTShorts;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts);
|
||||
} else if(index == HidSubmenuIndexMouseJiggler) {
|
||||
app->view_id = HidViewMouseJiggler;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
|
||||
@@ -50,11 +58,13 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con
|
||||
}
|
||||
}
|
||||
hid_keynote_set_connected_status(hid->hid_keynote, connected);
|
||||
hid_keynote_vertical_set_connected_status(hid->hid_keynote_vertical, connected);
|
||||
hid_keyboard_set_connected_status(hid->hid_keyboard, connected);
|
||||
hid_media_set_connected_status(hid->hid_media, connected);
|
||||
hid_mouse_set_connected_status(hid->hid_mouse, connected);
|
||||
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
|
||||
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
|
||||
hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected);
|
||||
}
|
||||
|
||||
static void hid_dialog_callback(DialogExResult result, void* context) {
|
||||
@@ -100,6 +110,12 @@ Hid* hid_alloc(HidTransport transport) {
|
||||
app->device_type_submenu = submenu_alloc();
|
||||
submenu_add_item(
|
||||
app->device_type_submenu, "Keynote", HidSubmenuIndexKeynote, hid_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->device_type_submenu,
|
||||
"Keynote Vertical",
|
||||
HidSubmenuIndexKeynoteVertical,
|
||||
hid_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
@@ -113,6 +129,12 @@ Hid* hid_alloc(HidTransport transport) {
|
||||
HidSubmenuIndexTikTok,
|
||||
hid_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->device_type_submenu,
|
||||
"[Beta]YT Shorts Controller",
|
||||
HidSubmenuIndexYTShorts,
|
||||
hid_submenu_callback,
|
||||
app);
|
||||
}
|
||||
submenu_add_item(
|
||||
app->device_type_submenu,
|
||||
@@ -148,6 +170,15 @@ Hid* hid_app_alloc_view(void* context) {
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, HidViewKeynote, hid_keynote_get_view(app->hid_keynote));
|
||||
|
||||
// Keynote Vertical view
|
||||
app->hid_keynote_vertical = hid_keynote_vertical_alloc(app);
|
||||
view_set_previous_callback(
|
||||
hid_keynote_vertical_get_view(app->hid_keynote_vertical), hid_exit_confirm_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
HidViewKeynoteVertical,
|
||||
hid_keynote_vertical_get_view(app->hid_keynote_vertical));
|
||||
|
||||
// Keyboard view
|
||||
app->hid_keyboard = hid_keyboard_alloc(app);
|
||||
view_set_previous_callback(hid_keyboard_get_view(app->hid_keyboard), hid_exit_confirm_view);
|
||||
@@ -166,6 +197,12 @@ Hid* hid_app_alloc_view(void* context) {
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtHidViewTikTok, hid_tiktok_get_view(app->hid_tiktok));
|
||||
|
||||
// YTShorts view
|
||||
app->hid_ytshorts = hid_ytshorts_alloc(app);
|
||||
view_set_previous_callback(hid_ytshorts_get_view(app->hid_ytshorts), hid_exit_confirm_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtHidViewYTShorts, hid_ytshorts_get_view(app->hid_ytshorts));
|
||||
|
||||
// Mouse view
|
||||
app->hid_mouse = hid_mouse_alloc(app);
|
||||
view_set_previous_callback(hid_mouse_get_view(app->hid_mouse), hid_exit_confirm_view);
|
||||
@@ -199,6 +236,8 @@ void hid_free(Hid* app) {
|
||||
dialog_ex_free(app->dialog);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynote);
|
||||
hid_keynote_free(app->hid_keynote);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynoteVertical);
|
||||
hid_keynote_vertical_free(app->hid_keynote_vertical);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard);
|
||||
hid_keyboard_free(app->hid_keyboard);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewMedia);
|
||||
@@ -209,6 +248,8 @@ void hid_free(Hid* app) {
|
||||
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
|
||||
hid_tiktok_free(app->hid_tiktok);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewYTShorts);
|
||||
hid_ytshorts_free(app->hid_ytshorts);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
// Close records
|
||||
|
||||
6
applications/external/hid_app/hid.h
vendored
6
applications/external/hid_app/hid.h
vendored
@@ -17,11 +17,13 @@
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include "views/hid_keynote.h"
|
||||
#include "views/hid_keynote_vertical.h"
|
||||
#include "views/hid_keyboard.h"
|
||||
#include "views/hid_media.h"
|
||||
#include "views/hid_mouse.h"
|
||||
#include "views/hid_mouse_jiggler.h"
|
||||
#include "views/hid_tiktok.h"
|
||||
#include "views/hid_ytshorts.h"
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
|
||||
|
||||
@@ -40,11 +42,13 @@ struct Hid {
|
||||
Submenu* device_type_submenu;
|
||||
DialogEx* dialog;
|
||||
HidKeynote* hid_keynote;
|
||||
HidKeynoteVertical* hid_keynote_vertical;
|
||||
HidKeyboard* hid_keyboard;
|
||||
HidMedia* hid_media;
|
||||
HidMouse* hid_mouse;
|
||||
HidMouseJiggler* hid_mouse_jiggler;
|
||||
HidTikTok* hid_tiktok;
|
||||
HidYTShorts* hid_ytshorts;
|
||||
|
||||
HidTransport transport;
|
||||
uint32_t view_id;
|
||||
@@ -62,4 +66,4 @@ void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy);
|
||||
void hid_hal_mouse_scroll(Hid* instance, int8_t delta);
|
||||
void hid_hal_mouse_press(Hid* instance, uint16_t event);
|
||||
void hid_hal_mouse_release(Hid* instance, uint16_t event);
|
||||
void hid_hal_mouse_release_all(Hid* instance);
|
||||
void hid_hal_mouse_release_all(Hid* instance);
|
||||
|
||||
4
applications/external/hid_app/views.h
vendored
4
applications/external/hid_app/views.h
vendored
@@ -1,10 +1,12 @@
|
||||
typedef enum {
|
||||
HidViewSubmenu,
|
||||
HidViewKeynote,
|
||||
HidViewKeynoteVertical,
|
||||
HidViewKeyboard,
|
||||
HidViewMedia,
|
||||
HidViewMouse,
|
||||
HidViewMouseJiggler,
|
||||
BtHidViewTikTok,
|
||||
BtHidViewYTShorts,
|
||||
HidViewExitConfirm,
|
||||
} HidView;
|
||||
} HidView;
|
||||
|
||||
228
applications/external/hid_app/views/hid_keynote_vertical.c
vendored
Normal file
228
applications/external/hid_app/views/hid_keynote_vertical.c
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
#include "hid_keynote_vertical.h"
|
||||
#include <gui/elements.h>
|
||||
#include "../hid.h"
|
||||
|
||||
#include "hid_icons.h"
|
||||
|
||||
#define TAG "HidKeynoteVertical"
|
||||
|
||||
struct HidKeynoteVertical {
|
||||
View* view;
|
||||
Hid* hid;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool left_pressed;
|
||||
bool up_pressed;
|
||||
bool right_pressed;
|
||||
bool down_pressed;
|
||||
bool ok_pressed;
|
||||
bool back_pressed;
|
||||
bool connected;
|
||||
HidTransport transport;
|
||||
} HidKeynoteVerticalModel;
|
||||
|
||||
static void
|
||||
hid_keynote_vertical_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) {
|
||||
canvas_draw_triangle(canvas, x, y, 5, 3, dir);
|
||||
if(dir == CanvasDirectionBottomToTop) {
|
||||
canvas_draw_line(canvas, x, y + 6, x, y - 1);
|
||||
} else if(dir == CanvasDirectionTopToBottom) {
|
||||
canvas_draw_line(canvas, x, y - 6, x, y + 1);
|
||||
} else if(dir == CanvasDirectionRightToLeft) {
|
||||
canvas_draw_line(canvas, x + 6, y, x - 1, y);
|
||||
} else if(dir == CanvasDirectionLeftToRight) {
|
||||
canvas_draw_line(canvas, x - 6, y, x + 1, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_keynote_vertical_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidKeynoteVerticalModel* model = context;
|
||||
|
||||
// Header
|
||||
if(model->transport == HidTransportBle) {
|
||||
if(model->connected) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
|
||||
}
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 24, 14, AlignLeft, AlignTop, "Vertical Up --->");
|
||||
|
||||
canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit");
|
||||
|
||||
// Up
|
||||
canvas_draw_icon(canvas, 21, 24, &I_Button_18x18);
|
||||
if(model->up_pressed) {
|
||||
elements_slightly_rounded_box(canvas, 24, 26, 13, 13);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
hid_keynote_vertical_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Down
|
||||
canvas_draw_icon(canvas, 21, 45, &I_Button_18x18);
|
||||
if(model->down_pressed) {
|
||||
elements_slightly_rounded_box(canvas, 24, 47, 13, 13);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
hid_keynote_vertical_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Left
|
||||
canvas_draw_icon(canvas, 0, 35, &I_Button_18x18);
|
||||
if(model->left_pressed) {
|
||||
elements_slightly_rounded_box(canvas, 3, 37, 13, 13);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
hid_keynote_vertical_draw_arrow(canvas, 7, 43, CanvasDirectionRightToLeft);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Right
|
||||
canvas_draw_icon(canvas, 42, 35, &I_Button_18x18);
|
||||
if(model->right_pressed) {
|
||||
elements_slightly_rounded_box(canvas, 45, 37, 13, 13);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
hid_keynote_vertical_draw_arrow(canvas, 53, 43, CanvasDirectionLeftToRight);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Ok
|
||||
canvas_draw_icon(canvas, 63, 25, &I_Space_65x18);
|
||||
if(model->ok_pressed) {
|
||||
elements_slightly_rounded_box(canvas, 66, 27, 60, 13);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9);
|
||||
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Space");
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Back
|
||||
canvas_draw_icon(canvas, 63, 45, &I_Space_65x18);
|
||||
if(model->back_pressed) {
|
||||
elements_slightly_rounded_box(canvas, 66, 47, 60, 13);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
|
||||
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back");
|
||||
}
|
||||
|
||||
static void
|
||||
hid_keynote_vertical_process(HidKeynoteVertical* hid_keynote_vertical, InputEvent* event) {
|
||||
with_view_model(
|
||||
hid_keynote_vertical->view,
|
||||
HidKeynoteVerticalModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = true;
|
||||
hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_LEFT_ARROW);
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = true;
|
||||
hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_RIGHT_ARROW);
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
model->left_pressed = true;
|
||||
hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_DOWN_ARROW);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
model->right_pressed = true;
|
||||
hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_UP_ARROW);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = true;
|
||||
hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_SPACEBAR);
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_pressed = true;
|
||||
}
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = false;
|
||||
hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_LEFT_ARROW);
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = false;
|
||||
hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_RIGHT_ARROW);
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
model->left_pressed = false;
|
||||
hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_DOWN_ARROW);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
model->right_pressed = false;
|
||||
hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_UP_ARROW);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = false;
|
||||
hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_SPACEBAR);
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_pressed = false;
|
||||
}
|
||||
} else if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyBack) {
|
||||
hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_DELETE);
|
||||
hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_DELETE);
|
||||
hid_hal_consumer_key_press(hid_keynote_vertical->hid, HID_CONSUMER_AC_BACK);
|
||||
hid_hal_consumer_key_release(hid_keynote_vertical->hid, HID_CONSUMER_AC_BACK);
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static bool hid_keynote_vertical_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HidKeynoteVertical* hid_keynote_vertical = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeLong && event->key == InputKeyBack) {
|
||||
hid_hal_keyboard_release_all(hid_keynote_vertical->hid);
|
||||
} else {
|
||||
hid_keynote_vertical_process(hid_keynote_vertical, event);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
HidKeynoteVertical* hid_keynote_vertical_alloc(Hid* hid) {
|
||||
HidKeynoteVertical* hid_keynote_vertical = malloc(sizeof(HidKeynoteVertical));
|
||||
hid_keynote_vertical->view = view_alloc();
|
||||
hid_keynote_vertical->hid = hid;
|
||||
view_set_context(hid_keynote_vertical->view, hid_keynote_vertical);
|
||||
view_allocate_model(
|
||||
hid_keynote_vertical->view, ViewModelTypeLocking, sizeof(HidKeynoteVerticalModel));
|
||||
view_set_draw_callback(hid_keynote_vertical->view, hid_keynote_vertical_draw_callback);
|
||||
view_set_input_callback(hid_keynote_vertical->view, hid_keynote_vertical_input_callback);
|
||||
|
||||
with_view_model(
|
||||
hid_keynote_vertical->view,
|
||||
HidKeynoteVerticalModel * model,
|
||||
{ model->transport = hid->transport; },
|
||||
true);
|
||||
|
||||
return hid_keynote_vertical;
|
||||
}
|
||||
|
||||
void hid_keynote_vertical_free(HidKeynoteVertical* hid_keynote_vertical) {
|
||||
furi_assert(hid_keynote_vertical);
|
||||
view_free(hid_keynote_vertical->view);
|
||||
free(hid_keynote_vertical);
|
||||
}
|
||||
|
||||
View* hid_keynote_vertical_get_view(HidKeynoteVertical* hid_keynote_vertical) {
|
||||
furi_assert(hid_keynote_vertical);
|
||||
return hid_keynote_vertical->view;
|
||||
}
|
||||
|
||||
void hid_keynote_vertical_set_connected_status(
|
||||
HidKeynoteVertical* hid_keynote_vertical,
|
||||
bool connected) {
|
||||
furi_assert(hid_keynote_vertical);
|
||||
with_view_model(
|
||||
hid_keynote_vertical->view,
|
||||
HidKeynoteVerticalModel * model,
|
||||
{ model->connected = connected; },
|
||||
true);
|
||||
}
|
||||
16
applications/external/hid_app/views/hid_keynote_vertical.h
vendored
Normal file
16
applications/external/hid_app/views/hid_keynote_vertical.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct Hid Hid;
|
||||
typedef struct HidKeynoteVertical HidKeynoteVertical;
|
||||
|
||||
HidKeynoteVertical* hid_keynote_vertical_alloc(Hid* bt_hid);
|
||||
|
||||
void hid_keynote_vertical_free(HidKeynoteVertical* hid_keynote_vertical);
|
||||
|
||||
View* hid_keynote_vertical_get_view(HidKeynoteVertical* hid_keynote_vertical);
|
||||
|
||||
void hid_keynote_vertical_set_connected_status(
|
||||
HidKeynoteVertical* hid_keynote_vertical,
|
||||
bool connected);
|
||||
18
applications/external/hid_app/views/hid_mouse.c
vendored
18
applications/external/hid_app/views/hid_mouse.c
vendored
@@ -93,17 +93,23 @@ static void hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
||||
|
||||
// Ok
|
||||
if(model->left_mouse_pressed) {
|
||||
canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9);
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Back
|
||||
if(model->right_mouse_pressed) {
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9);
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) {
|
||||
|
||||
69
applications/external/hid_app/views/hid_tiktok.c
vendored
69
applications/external/hid_app/views/hid_tiktok.c
vendored
@@ -19,6 +19,7 @@ typedef struct {
|
||||
bool ok_pressed;
|
||||
bool connected;
|
||||
bool is_cursor_set;
|
||||
bool back_mouse_pressed;
|
||||
HidTransport transport;
|
||||
} HidTikTokModel;
|
||||
|
||||
@@ -40,53 +41,63 @@ static void hid_tiktok_draw_callback(Canvas* canvas, void* context) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
// Keypad circles
|
||||
canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47);
|
||||
canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47);
|
||||
|
||||
// Pause
|
||||
if(model->back_mouse_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Up
|
||||
if(model->up_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 96, 11, &I_Arr_up_7x9);
|
||||
canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Down
|
||||
if(model->down_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 96, 44, &I_Arr_dwn_7x9);
|
||||
canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Left
|
||||
if(model->left_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 81, 29, &I_Voldwn_6x6);
|
||||
canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Right
|
||||
if(model->right_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 111, 29, &I_Volup_8x6);
|
||||
canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Ok
|
||||
if(model->ok_pressed) {
|
||||
canvas_draw_icon(canvas, 91, 23, &I_Like_pressed_17x17);
|
||||
canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 94, 27, &I_Like_def_11x9);
|
||||
canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9);
|
||||
}
|
||||
// Exit
|
||||
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||
@@ -102,7 +113,8 @@ static void hid_tiktok_reset_cursor(HidTikTok* hid_tiktok) {
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
// Move cursor from the corner
|
||||
hid_hal_mouse_move(hid_tiktok->hid, 20, 120);
|
||||
hid_hal_mouse_move(hid_tiktok->hid, 40, 120);
|
||||
hid_hal_mouse_move(hid_tiktok->hid, 0, 120);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
|
||||
@@ -120,6 +132,8 @@ static void
|
||||
hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +151,8 @@ static void
|
||||
hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = false;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,31 +178,26 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) {
|
||||
} else if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyOk) {
|
||||
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
furi_delay_ms(25);
|
||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
furi_delay_ms(100);
|
||||
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
furi_delay_ms(25);
|
||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
// Emulate up swipe
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -6);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -19);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
// Emulate down swipe
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 6);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 12);
|
||||
// Swipe to new video
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 19);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
// Swipe to previous video
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -19);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
hid_hal_consumer_key_release_all(hid_tiktok->hid);
|
||||
// Pause
|
||||
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT);
|
||||
furi_delay_ms(25);
|
||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
|
||||
268
applications/external/hid_app/views/hid_ytshorts.c
vendored
Normal file
268
applications/external/hid_app/views/hid_ytshorts.c
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "hid_ytshorts.h"
|
||||
#include "../hid.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "hid_icons.h"
|
||||
|
||||
#define TAG "HidYTShorts"
|
||||
|
||||
struct HidYTShorts {
|
||||
View* view;
|
||||
Hid* hid;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool left_pressed;
|
||||
bool up_pressed;
|
||||
bool right_pressed;
|
||||
bool down_pressed;
|
||||
bool ok_pressed;
|
||||
bool connected;
|
||||
bool is_cursor_set;
|
||||
bool back_mouse_pressed;
|
||||
HidTransport transport;
|
||||
} HidYTShortsModel;
|
||||
|
||||
static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidYTShortsModel* model = context;
|
||||
|
||||
// Header
|
||||
if(model->transport == HidTransportBle) {
|
||||
if(model->connected) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
|
||||
}
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Shorts");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
// Keypad circles
|
||||
canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47);
|
||||
|
||||
// Pause
|
||||
if(model->back_mouse_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Up
|
||||
if(model->up_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Down
|
||||
if(model->down_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Left
|
||||
if(model->left_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Right
|
||||
if(model->right_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Ok
|
||||
if(model->ok_pressed) {
|
||||
canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9);
|
||||
}
|
||||
// Exit
|
||||
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
|
||||
}
|
||||
|
||||
static void hid_ytshorts_reset_cursor(HidYTShorts* hid_ytshorts) {
|
||||
// Set cursor to the phone's left up corner
|
||||
// Delays to guarantee one packet per connection interval
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
hid_hal_mouse_move(hid_ytshorts->hid, -127, -127);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
// Move cursor from the corner
|
||||
hid_hal_mouse_move(hid_ytshorts->hid, 40, 120);
|
||||
hid_hal_mouse_move(hid_ytshorts->hid, 0, 120);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
|
||||
static void hid_ytshorts_process_press(
|
||||
HidYTShorts* hid_ytshorts,
|
||||
HidYTShortsModel* model,
|
||||
InputEvent* event) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
model->left_pressed = true;
|
||||
hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
model->right_pressed = true;
|
||||
hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_ytshorts_process_release(
|
||||
HidYTShorts* hid_ytshorts,
|
||||
HidYTShortsModel* model,
|
||||
InputEvent* event) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = false;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = false;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
model->left_pressed = false;
|
||||
hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
model->right_pressed = false;
|
||||
hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = false;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool hid_ytshorts_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HidYTShorts* hid_ytshorts = context;
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
hid_ytshorts->view,
|
||||
HidYTShortsModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
hid_ytshorts_process_press(hid_ytshorts, model, event);
|
||||
if(model->connected && !model->is_cursor_set) {
|
||||
hid_ytshorts_reset_cursor(hid_ytshorts);
|
||||
model->is_cursor_set = true;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
hid_ytshorts_process_release(hid_ytshorts, model, event);
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyOk) {
|
||||
hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
// Swipe to new video
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 6);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 10);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
// Swipe to previous video
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -6);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -10);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
// Pause
|
||||
hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
if(event->key == InputKeyBack) {
|
||||
hid_hal_consumer_key_release_all(hid_ytshorts->hid);
|
||||
model->is_cursor_set = false;
|
||||
consumed = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid) {
|
||||
HidYTShorts* hid_ytshorts = malloc(sizeof(HidYTShorts));
|
||||
hid_ytshorts->hid = bt_hid;
|
||||
hid_ytshorts->view = view_alloc();
|
||||
view_set_context(hid_ytshorts->view, hid_ytshorts);
|
||||
view_allocate_model(hid_ytshorts->view, ViewModelTypeLocking, sizeof(HidYTShortsModel));
|
||||
view_set_draw_callback(hid_ytshorts->view, hid_ytshorts_draw_callback);
|
||||
view_set_input_callback(hid_ytshorts->view, hid_ytshorts_input_callback);
|
||||
|
||||
with_view_model(
|
||||
hid_ytshorts->view,
|
||||
HidYTShortsModel * model,
|
||||
{ model->transport = bt_hid->transport; },
|
||||
true);
|
||||
|
||||
return hid_ytshorts;
|
||||
}
|
||||
|
||||
void hid_ytshorts_free(HidYTShorts* hid_ytshorts) {
|
||||
furi_assert(hid_ytshorts);
|
||||
view_free(hid_ytshorts->view);
|
||||
free(hid_ytshorts);
|
||||
}
|
||||
|
||||
View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts) {
|
||||
furi_assert(hid_ytshorts);
|
||||
return hid_ytshorts->view;
|
||||
}
|
||||
|
||||
void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected) {
|
||||
furi_assert(hid_ytshorts);
|
||||
with_view_model(
|
||||
hid_ytshorts->view,
|
||||
HidYTShortsModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
model->is_cursor_set = false;
|
||||
},
|
||||
true);
|
||||
}
|
||||
14
applications/external/hid_app/views/hid_ytshorts.h
vendored
Normal file
14
applications/external/hid_app/views/hid_ytshorts.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct Hid Hid;
|
||||
typedef struct HidYTShorts HidYTShorts;
|
||||
|
||||
HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid);
|
||||
|
||||
void hid_ytshorts_free(HidYTShorts* hid_ytshorts);
|
||||
|
||||
View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts);
|
||||
|
||||
void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected);
|
||||
16
applications/external/ibtn_fuzzer/ibtnfuzzer.c
vendored
16
applications/external/ibtn_fuzzer/ibtnfuzzer.c
vendored
@@ -59,6 +59,14 @@ iBtnFuzzerState* ibtnfuzzer_alloc() {
|
||||
ibtnfuzzer->proto_name = furi_string_alloc();
|
||||
ibtnfuzzer->data_str = furi_string_alloc();
|
||||
|
||||
ibtnfuzzer->main_menu_items[0] = furi_string_alloc_set("Default Values");
|
||||
ibtnfuzzer->main_menu_items[1] = furi_string_alloc_set("Load File");
|
||||
ibtnfuzzer->main_menu_items[2] = furi_string_alloc_set("Load UIDs from file");
|
||||
|
||||
ibtnfuzzer->main_menu_proto_items[0] = furi_string_alloc_set("DS1990");
|
||||
ibtnfuzzer->main_menu_proto_items[1] = furi_string_alloc_set("Metakom");
|
||||
ibtnfuzzer->main_menu_proto_items[2] = furi_string_alloc_set("Cyfral");
|
||||
|
||||
ibtnfuzzer->previous_scene = NoneScene;
|
||||
ibtnfuzzer->current_scene = SceneEntryPoint;
|
||||
ibtnfuzzer->is_running = true;
|
||||
@@ -105,6 +113,14 @@ void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) {
|
||||
furi_string_free(ibtnfuzzer->proto_name);
|
||||
furi_string_free(ibtnfuzzer->data_str);
|
||||
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
furi_string_free(ibtnfuzzer->main_menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
furi_string_free(ibtnfuzzer->main_menu_proto_items[i]);
|
||||
}
|
||||
|
||||
free(ibtnfuzzer->data);
|
||||
free(ibtnfuzzer->payload);
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ typedef struct {
|
||||
iBtnFuzzerProtos proto;
|
||||
FuriString* attack_name;
|
||||
FuriString* proto_name;
|
||||
FuriString* main_menu_items[3];
|
||||
FuriString* main_menu_proto_items[3];
|
||||
|
||||
DialogsApp* dialogs;
|
||||
FuriString* notification_msg;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include "ibtnfuzzer_scene_entrypoint.h"
|
||||
|
||||
FuriString* main_menu_items[3];
|
||||
FuriString* main_menu_proto_items[3];
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_menu_callback(
|
||||
iBtnFuzzerState* context,
|
||||
uint32_t index,
|
||||
@@ -61,30 +58,14 @@ void ibtnfuzzer_scene_entrypoint_on_enter(iBtnFuzzerState* context) {
|
||||
menu_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
main_menu_items[0] = furi_string_alloc_set("Default Values");
|
||||
main_menu_items[1] = furi_string_alloc_set("Load File");
|
||||
main_menu_items[2] = furi_string_alloc_set("Load UIDs from file");
|
||||
|
||||
context->menu_proto_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_proto_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
main_menu_proto_items[0] = furi_string_alloc_set("DS1990");
|
||||
main_menu_proto_items[1] = furi_string_alloc_set("Metakom");
|
||||
main_menu_proto_items[2] = furi_string_alloc_set("Cyfral");
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_exit(iBtnFuzzerState* context) {
|
||||
context->enter_rerun = false;
|
||||
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
furi_string_free(main_menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
furi_string_free(main_menu_proto_items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_tick(iBtnFuzzerState* context) {
|
||||
@@ -142,74 +123,79 @@ void ibtnfuzzer_scene_entrypoint_on_draw(Canvas* canvas, iBtnFuzzerState* contex
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(main_menu_items[context->menu_index] != NULL) {
|
||||
if(context->menu_index > iBtnFuzzerAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(context->main_menu_items != NULL) {
|
||||
if(context->main_menu_items[context->menu_index] != NULL) {
|
||||
if(context->menu_index > iBtnFuzzerAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index]));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index]));
|
||||
if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
|
||||
if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
if(context->menu_proto_index > DS1990) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
|
||||
if(context->menu_proto_index > DS1990) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
if(context->main_menu_proto_items[context->menu_proto_index] != NULL) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index]));
|
||||
}
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
if(main_menu_proto_items[context->menu_proto_index] != NULL) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index]));
|
||||
}
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
if(context->menu_proto_index < Cyfral) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index + 1]));
|
||||
if(context->menu_proto_index < Cyfral) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@ void picopass_worker_elite_dict_attack(PicopassWorker* picopass_worker) {
|
||||
picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context);
|
||||
break;
|
||||
}
|
||||
picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context);
|
||||
picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -596,6 +596,9 @@ int32_t picopass_worker_task(void* context) {
|
||||
picopass_worker_write_key(picopass_worker);
|
||||
} else if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) {
|
||||
picopass_worker_elite_dict_attack(picopass_worker);
|
||||
} else if(picopass_worker->state == PicopassWorkerStateStop) {
|
||||
FURI_LOG_D(TAG, "Worker state stop");
|
||||
// no-op
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "Unknown state %d", picopass_worker->state);
|
||||
}
|
||||
|
||||
@@ -116,8 +116,7 @@ bool picopass_scene_elite_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneEliteDictAttack);
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == PicopassWorkerEventSuccess ||
|
||||
event.event == PicopassWorkerEventAborted) {
|
||||
if(event.event == PicopassWorkerEventSuccess) {
|
||||
if(state == DictAttackStateUserDictInProgress ||
|
||||
state == DictAttackStateStandardDictInProgress) {
|
||||
picopass_worker_stop(picopass->worker);
|
||||
@@ -127,6 +126,9 @@ bool picopass_scene_elite_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.event == PicopassWorkerEventAborted) {
|
||||
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == PicopassWorkerEventCardDetected) {
|
||||
dict_attack_set_card_detected(picopass->dict_attack);
|
||||
consumed = true;
|
||||
|
||||
@@ -136,7 +136,7 @@ static void cfg_read_file_path(
|
||||
*is_enabled = 0;
|
||||
} else {
|
||||
*text_file_label = extract_filename(furi_string_get_cstr(text_file_path), 16);
|
||||
FURI_LOG_D(TAG, "%s file: %s", read_key, furi_string_get_cstr(text_file_path));
|
||||
//FURI_LOG_D(TAG, "%s file: %s", read_key, furi_string_get_cstr(text_file_path));
|
||||
*is_enabled = 1;
|
||||
}
|
||||
flipper_format_rewind(fff_file);
|
||||
@@ -155,7 +155,7 @@ static void cfg_read_file_label(
|
||||
if(is_enabled == 1) {
|
||||
*text_file_label = char_to_str((char*)furi_string_get_cstr(temp_label), 16);
|
||||
}
|
||||
FURI_LOG_D(TAG, "%s label: %s", read_key, *text_file_label);
|
||||
//FURI_LOG_D(TAG, "%s label: %s", read_key, *text_file_label);
|
||||
}
|
||||
flipper_format_rewind(fff_file);
|
||||
furi_string_free(temp_label);
|
||||
@@ -355,6 +355,10 @@ bool subghz_remote_key_load(
|
||||
|
||||
bool res = false;
|
||||
|
||||
subghz_custom_btn_set(0);
|
||||
keeloq_reset_original_btn();
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
do {
|
||||
// load frequency from file
|
||||
if(!flipper_format_read_uint32(fff_file, "Frequency", &preset->frequency, 1)) {
|
||||
@@ -386,6 +390,10 @@ bool subghz_remote_key_load(
|
||||
FURI_LOG_E(TAG, "Could not read Protocol.");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_rewind(fff_data)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!furi_string_cmp_str(preset->protocol, "RAW")) {
|
||||
subghz_protocol_raw_gen_fff_data(fff_data, path);
|
||||
@@ -394,10 +402,7 @@ bool subghz_remote_key_load(
|
||||
FURI_LOG_E(TAG, "Unable to insert or update Repeat");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_rewind(fff_data)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
stream_copy_full(
|
||||
flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data));
|
||||
@@ -406,10 +411,6 @@ bool subghz_remote_key_load(
|
||||
FURI_LOG_E(TAG, "Unable to insert or update Repeat");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_rewind(fff_data)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!flipper_format_rewind(fff_file)) {
|
||||
@@ -467,7 +468,7 @@ bool subghz_remote_save_protocol_to_file(FlipperFormat* fff_file, const char* de
|
||||
stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS);
|
||||
|
||||
saved = true;
|
||||
FURI_LOG_D(TAG, "(save) OK Save");
|
||||
//FURI_LOG_D(TAG, "(save) OK Save");
|
||||
} while(0);
|
||||
furi_string_free(file_dir);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
@@ -527,7 +528,8 @@ static bool subghz_remote_send_sub(SubGHzRemote* app, FlipperFormat* fff_data) {
|
||||
bool res = false;
|
||||
do {
|
||||
if(!furi_hal_subghz_is_tx_allowed(app->txpreset->frequency)) {
|
||||
printf(
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"In your settings, only reception on this frequency (%lu) is allowed,\r\n"
|
||||
"the actual operation of the subghz remote app is not possible\r\n ",
|
||||
app->txpreset->frequency);
|
||||
@@ -544,7 +546,11 @@ static bool subghz_remote_send_sub(SubGHzRemote* app, FlipperFormat* fff_data) {
|
||||
break;
|
||||
}
|
||||
|
||||
subghz_transmitter_deserialize(app->tx_transmitter, fff_data);
|
||||
if(subghz_transmitter_deserialize(app->tx_transmitter, fff_data) !=
|
||||
SubGhzProtocolStatusOk) {
|
||||
FURI_LOG_E(TAG, "Deserialize error!");
|
||||
break;
|
||||
}
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_idle();
|
||||
@@ -575,7 +581,7 @@ static bool subghz_remote_send_sub(SubGHzRemote* app, FlipperFormat* fff_data) {
|
||||
}
|
||||
|
||||
static void subghz_remote_send_signal(SubGHzRemote* app, Storage* storage, const char* path) {
|
||||
FURI_LOG_D(TAG, "Sending: %s", path);
|
||||
//FURI_LOG_D(TAG, "Sending: %s", path);
|
||||
|
||||
app->tx_file_path = path;
|
||||
|
||||
@@ -615,7 +621,7 @@ static void subghz_remote_send_signal(SubGHzRemote* app, Storage* storage, const
|
||||
static void subghz_remote_process_signal(SubGHzRemote* app, FuriString* signal) {
|
||||
view_port_update(app->view_port);
|
||||
|
||||
FURI_LOG_D(TAG, "signal = %s", furi_string_get_cstr(signal));
|
||||
//FURI_LOG_D(TAG, "signal = %s", furi_string_get_cstr(signal));
|
||||
|
||||
if(strlen(furi_string_get_cstr(signal)) > 12) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
@@ -745,6 +751,8 @@ void subghz_remote_subghz_alloc(SubGHzRemote* app) {
|
||||
app->environment, EXT_PATH("subghz/assets/came_atomo"));
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
app->environment, EXT_PATH("subghz/assets/nice_flor_s"));
|
||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||
app->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
|
||||
subghz_environment_set_protocol_registry(app->environment, (void*)&subghz_protocol_registry);
|
||||
|
||||
app->subghz_receiver = subghz_receiver_alloc_init(app->environment);
|
||||
@@ -867,14 +875,14 @@ int32_t subghz_remote_app(void* p) {
|
||||
bool exit_loop = false;
|
||||
|
||||
if(app->file_result == 2) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"U: %s - D: %s - L: %s - R: %s - O: %s ",
|
||||
furi_string_get_cstr(app->up_file),
|
||||
furi_string_get_cstr(app->down_file),
|
||||
furi_string_get_cstr(app->left_file),
|
||||
furi_string_get_cstr(app->right_file),
|
||||
furi_string_get_cstr(app->ok_file));
|
||||
//FURI_LOG_D(
|
||||
//TAG,
|
||||
//"U: %s - D: %s - L: %s - R: %s - O: %s ",
|
||||
//furi_string_get_cstr(app->up_file),
|
||||
//furi_string_get_cstr(app->down_file),
|
||||
//furi_string_get_cstr(app->left_file),
|
||||
//furi_string_get_cstr(app->right_file),
|
||||
//furi_string_get_cstr(app->ok_file));
|
||||
|
||||
//variables to control multiple button presses and status updates
|
||||
app->send_status = "Idle";
|
||||
@@ -892,11 +900,11 @@ int32_t subghz_remote_app(void* p) {
|
||||
while(1) {
|
||||
furi_check(
|
||||
furi_message_queue_get(app->input_queue, &input, FuriWaitForever) == FuriStatusOk);
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"key: %s type: %s",
|
||||
input_get_key_name(input.key),
|
||||
input_get_type_name(input.type));
|
||||
//FURI_LOG_D(
|
||||
//TAG,
|
||||
//"key: %s type: %s",
|
||||
//input_get_key_name(input.key),
|
||||
//input_get_type_name(input.type));
|
||||
|
||||
switch(input.key) {
|
||||
case InputKeyUp:
|
||||
@@ -998,12 +1006,12 @@ int32_t subghz_remote_app(void* p) {
|
||||
}
|
||||
|
||||
if(app->processing == 0) {
|
||||
FURI_LOG_D(TAG, "processing 0");
|
||||
//FURI_LOG_D(TAG, "processing 0");
|
||||
app->send_status = "Idle";
|
||||
app->send_status_c = 0;
|
||||
app->button = 0;
|
||||
} else if(app->processing == 1) {
|
||||
FURI_LOG_D(TAG, "processing 1");
|
||||
//FURI_LOG_D(TAG, "processing 1");
|
||||
|
||||
app->send_status = "Send";
|
||||
|
||||
@@ -1046,11 +1054,11 @@ int32_t subghz_remote_app(void* p) {
|
||||
while(1) {
|
||||
furi_check(
|
||||
furi_message_queue_get(app->input_queue, &input, FuriWaitForever) == FuriStatusOk);
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"key: %s type: %s",
|
||||
input_get_key_name(input.key),
|
||||
input_get_type_name(input.type));
|
||||
//FURI_LOG_D(
|
||||
//TAG,
|
||||
//"key: %s type: %s",
|
||||
//input_get_key_name(input.key),
|
||||
//input_get_type_name(input.type));
|
||||
|
||||
switch(input.key) {
|
||||
case InputKeyRight:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "reset.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi/core/string.h>
|
||||
#include "../../cli_helpers.h"
|
||||
#include "../../../services/config/config.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
#pragma weak strnlen
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
size_t strnlen(const char* s, size_t maxlen);
|
||||
@@ -57,7 +57,7 @@ static char* totp_config_file_backup_i(Storage* storage) {
|
||||
}
|
||||
|
||||
if(backup_file_exists ||
|
||||
!storage_common_copy(storage, CONFIG_FILE_PATH, backup_path) == FSE_OK) {
|
||||
storage_common_copy(storage, CONFIG_FILE_PATH, backup_path) != FSE_OK) {
|
||||
FURI_LOG_E(LOGGING_TAG, "Unable to take a backup");
|
||||
free(backup_path);
|
||||
return NULL;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <furi.h>
|
||||
#include "../../types/plugin_state.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "constants.h"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "crypto.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_crypto.h>
|
||||
#include <furi_hal_random.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include "../config/config.h"
|
||||
#include "../../types/common.h"
|
||||
#include "memset_s.h"
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#include "totp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <timezone_utils.h>
|
||||
#include "../hmac/hmac_sha1.h"
|
||||
#include "../hmac/hmac_sha256.h"
|
||||
#include "../hmac/hmac_sha512.h"
|
||||
#include "../hmac/byteswap.h"
|
||||
#include "../../lib/timezone_utils/timezone_utils.h"
|
||||
|
||||
#define HMAC_MAX_RESULT_SIZE HMAC_SHA512_RESULT_SIZE
|
||||
|
||||
|
||||
7
applications/external/totp/totp_app.c
vendored
7
applications/external/totp/totp_app.c
vendored
@@ -1,10 +1,7 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <stdlib.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include "features_config.h"
|
||||
@@ -104,10 +101,6 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
||||
}
|
||||
|
||||
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(plugin_state->mutex == NULL) {
|
||||
FURI_LOG_E(LOGGING_TAG, "Cannot create mutex\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "token_info.h"
|
||||
#include <furi_hal.h>
|
||||
#include <base32.h>
|
||||
#include <base64.h>
|
||||
#include <memset_s.h>
|
||||
#include <strnlen.h>
|
||||
#include "common.h"
|
||||
#include "../services/crypto/crypto.h"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi/core/string.h>
|
||||
|
||||
#define TOTP_TOKEN_DURATION_DEFAULT (30)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "totp_input_text.h"
|
||||
#include <gui/view_i.h>
|
||||
#include "../../../lib/polyfills/strnlen.h"
|
||||
|
||||
void view_draw(View* view, Canvas* canvas) {
|
||||
furi_assert(view);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
|
||||
@@ -2,19 +2,16 @@
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <totp_icons.h>
|
||||
#include <roll_value.h>
|
||||
#include "totp_scene_generate_token.h"
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../types/common.h"
|
||||
#include "../../constants.h"
|
||||
#include "../../../services/totp/totp.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../../services/crypto/crypto.h"
|
||||
#include "../../../services/convert/convert.h"
|
||||
#include "../../../lib/polyfills/memset_s.h"
|
||||
#include "../../../lib/roll_value/roll_value.h"
|
||||
#include "../../scene_director.h"
|
||||
#include "../token_menu/totp_scene_token_menu.h"
|
||||
#include "../../../features_config.h"
|
||||
#include "../../../workers/generate_totp_code/generate_totp_code.h"
|
||||
#include "../../../workers/usb_type_code/usb_type_code.h"
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
#include "../../../workers/bt_type_code/bt_type_code.h"
|
||||
@@ -23,18 +20,26 @@
|
||||
|
||||
#define PROGRESS_BAR_MARGIN (3)
|
||||
#define PROGRESS_BAR_HEIGHT (4)
|
||||
static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
|
||||
|
||||
typedef struct {
|
||||
uint8_t progress_bar_x;
|
||||
uint8_t progress_bar_width;
|
||||
uint8_t code_total_length;
|
||||
uint8_t code_offset_x;
|
||||
uint8_t code_offset_x_inc;
|
||||
uint8_t code_offset_y;
|
||||
} UiPrecalculatedDimensions;
|
||||
|
||||
typedef struct {
|
||||
uint16_t current_token_index;
|
||||
char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
|
||||
bool need_token_update;
|
||||
TokenInfo* current_token;
|
||||
uint32_t last_token_gen_time;
|
||||
TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
|
||||
NotificationMessage const** notification_sequence_new_token;
|
||||
NotificationMessage const** notification_sequence_badusb;
|
||||
NotificationMessage const** notification_sequence_automation;
|
||||
FuriMutex* last_code_update_sync;
|
||||
TotpGenerateCodeWorkerContext* generate_code_worker_context;
|
||||
UiPrecalculatedDimensions ui_precalculated_dimensions;
|
||||
} SceneState;
|
||||
|
||||
static const NotificationSequence*
|
||||
@@ -80,7 +85,7 @@ static const NotificationSequence*
|
||||
|
||||
static const NotificationSequence*
|
||||
get_notification_sequence_automation(const PluginState* plugin_state, SceneState* scene_state) {
|
||||
if(scene_state->notification_sequence_badusb == NULL) {
|
||||
if(scene_state->notification_sequence_automation == NULL) {
|
||||
uint8_t i = 0;
|
||||
uint8_t length = 3;
|
||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||
@@ -91,109 +96,102 @@ static const NotificationSequence*
|
||||
length += 6;
|
||||
}
|
||||
|
||||
scene_state->notification_sequence_badusb = malloc(sizeof(void*) * length);
|
||||
furi_check(scene_state->notification_sequence_badusb != NULL);
|
||||
scene_state->notification_sequence_automation = malloc(sizeof(void*) * length);
|
||||
furi_check(scene_state->notification_sequence_automation != NULL);
|
||||
|
||||
scene_state->notification_sequence_badusb[i++] = &message_blue_255;
|
||||
scene_state->notification_sequence_automation[i++] = &message_blue_255;
|
||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_vibro_on;
|
||||
scene_state->notification_sequence_automation[i++] = &message_vibro_on;
|
||||
}
|
||||
|
||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_note_d5; //-V525
|
||||
scene_state->notification_sequence_badusb[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_badusb[i++] = &message_note_e4;
|
||||
scene_state->notification_sequence_badusb[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_badusb[i++] = &message_note_f3;
|
||||
scene_state->notification_sequence_automation[i++] = &message_note_d5; //-V525
|
||||
scene_state->notification_sequence_automation[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_automation[i++] = &message_note_e4;
|
||||
scene_state->notification_sequence_automation[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_automation[i++] = &message_note_f3;
|
||||
}
|
||||
|
||||
scene_state->notification_sequence_badusb[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_automation[i++] = &message_delay_50;
|
||||
|
||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_vibro_off;
|
||||
scene_state->notification_sequence_automation[i++] = &message_vibro_off;
|
||||
}
|
||||
|
||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_sound_off;
|
||||
scene_state->notification_sequence_automation[i++] = &message_sound_off;
|
||||
}
|
||||
|
||||
scene_state->notification_sequence_badusb[i++] = NULL;
|
||||
scene_state->notification_sequence_automation[i++] = NULL;
|
||||
}
|
||||
|
||||
return (NotificationSequence*)scene_state->notification_sequence_badusb;
|
||||
}
|
||||
|
||||
static void
|
||||
int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) {
|
||||
if(i_token_code == OTP_ERROR) {
|
||||
memset(&str[0], '-', len);
|
||||
} else {
|
||||
if(algo == STEAM) {
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26];
|
||||
i_token_code = i_token_code / 26;
|
||||
}
|
||||
} else {
|
||||
for(int8_t i = len - 1; i >= 0; i--) {
|
||||
str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10);
|
||||
i_token_code = i_token_code / 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str[len] = '\0';
|
||||
}
|
||||
|
||||
static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
|
||||
switch(algo) {
|
||||
case SHA1:
|
||||
case STEAM:
|
||||
return TOTP_ALGO_SHA1;
|
||||
case SHA256:
|
||||
return TOTP_ALGO_SHA256;
|
||||
case SHA512:
|
||||
return TOTP_ALGO_SHA512;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return (NotificationSequence*)scene_state->notification_sequence_automation;
|
||||
}
|
||||
|
||||
static void update_totp_params(PluginState* const plugin_state) {
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
if(scene_state->current_token_index < plugin_state->tokens_count) {
|
||||
TokenInfo* tokenInfo =
|
||||
scene_state->current_token =
|
||||
list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data;
|
||||
|
||||
scene_state->need_token_update = true;
|
||||
scene_state->current_token = tokenInfo;
|
||||
totp_generate_code_worker_notify(
|
||||
scene_state->generate_code_worker_context, TotpGenerateCodeWorkerEventForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_state) {
|
||||
uint8_t code_length = scene_state->current_token->digits;
|
||||
uint8_t offset_x = scene_state->ui_precalculated_dimensions.code_offset_x;
|
||||
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||
uint8_t total_length = code_length * (char_width + modeNine_15ptFontInfo.spacePixels);
|
||||
uint8_t offset_x = (SCREEN_WIDTH - total_length) >> 1;
|
||||
uint8_t offset_x_inc = char_width + modeNine_15ptFontInfo.spacePixels;
|
||||
uint8_t offset_y = SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1);
|
||||
uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc;
|
||||
for(uint8_t i = 0; i < code_length; i++) {
|
||||
char ch = scene_state->last_code[i];
|
||||
uint8_t char_index = ch - modeNine_15ptFontInfo.startChar;
|
||||
canvas_draw_xbm(
|
||||
canvas,
|
||||
offset_x,
|
||||
offset_y,
|
||||
char_width,
|
||||
modeNine_15ptFontInfo.height,
|
||||
&modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]);
|
||||
if(ch >= modeNine_15ptFontInfo.startChar && ch <= modeNine_15ptFontInfo.endChar) {
|
||||
uint8_t char_index = ch - modeNine_15ptFontInfo.startChar;
|
||||
canvas_draw_xbm(
|
||||
canvas,
|
||||
offset_x,
|
||||
scene_state->ui_precalculated_dimensions.code_offset_y,
|
||||
char_width,
|
||||
modeNine_15ptFontInfo.height,
|
||||
&modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]);
|
||||
}
|
||||
|
||||
offset_x += offset_x_inc;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_new_token_code_generated(bool time_left, void* context) {
|
||||
const PluginState* plugin_state = context;
|
||||
SceneState* scene_state = plugin_state->current_scene_state;
|
||||
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||
scene_state->ui_precalculated_dimensions.code_total_length =
|
||||
scene_state->current_token->digits * (char_width + modeNine_15ptFontInfo.spacePixels);
|
||||
scene_state->ui_precalculated_dimensions.code_offset_x =
|
||||
(SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1;
|
||||
scene_state->ui_precalculated_dimensions.code_offset_x_inc =
|
||||
char_width + modeNine_15ptFontInfo.spacePixels;
|
||||
scene_state->ui_precalculated_dimensions.code_offset_y =
|
||||
SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1);
|
||||
|
||||
if(time_left) {
|
||||
notification_message(
|
||||
plugin_state->notification_app,
|
||||
get_notification_sequence_new_token(plugin_state, plugin_state->current_scene_state));
|
||||
}
|
||||
}
|
||||
|
||||
static void on_code_lifetime_updated_generated(float code_lifetime_percent, void* context) {
|
||||
SceneState* scene_state = context;
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_width =
|
||||
(uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent);
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_x =
|
||||
((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) -
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_width) >>
|
||||
1) +
|
||||
PROGRESS_BAR_MARGIN;
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_activate(
|
||||
PluginState* plugin_state,
|
||||
const GenerateTokenSceneContext* context) {
|
||||
@@ -231,15 +229,14 @@ void totp_scene_generate_token_activate(
|
||||
} else {
|
||||
scene_state->current_token_index = context->current_token_index;
|
||||
}
|
||||
scene_state->need_token_update = true;
|
||||
|
||||
plugin_state->current_scene_state = scene_state;
|
||||
FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
|
||||
update_totp_params(plugin_state);
|
||||
|
||||
scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(plugin_state->automation_method & AutomationMethodBadUsb) {
|
||||
scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start(
|
||||
&scene_state->last_code[0],
|
||||
scene_state->last_code,
|
||||
TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
|
||||
scene_state->last_code_update_sync);
|
||||
}
|
||||
@@ -252,11 +249,28 @@ void totp_scene_generate_token_activate(
|
||||
}
|
||||
totp_bt_type_code_worker_start(
|
||||
plugin_state->bt_type_code_worker_context,
|
||||
&scene_state->last_code[0],
|
||||
scene_state->last_code,
|
||||
TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
|
||||
scene_state->last_code_update_sync);
|
||||
}
|
||||
#endif
|
||||
|
||||
scene_state->generate_code_worker_context = totp_generate_code_worker_start(
|
||||
scene_state->last_code,
|
||||
&scene_state->current_token,
|
||||
scene_state->last_code_update_sync,
|
||||
plugin_state->timezone_offset,
|
||||
plugin_state->iv);
|
||||
|
||||
totp_generate_code_worker_set_code_generated_handler(
|
||||
scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state);
|
||||
|
||||
totp_generate_code_worker_set_lifetime_changed_handler(
|
||||
scene_state->generate_code_worker_context,
|
||||
&on_code_lifetime_updated_generated,
|
||||
scene_state);
|
||||
|
||||
update_totp_params(plugin_state);
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
|
||||
@@ -278,54 +292,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
return;
|
||||
}
|
||||
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
|
||||
bool is_new_token_time = curr_ts % scene_state->current_token->duration == 0;
|
||||
if(is_new_token_time && scene_state->last_token_gen_time != curr_ts) {
|
||||
scene_state->need_token_update = true;
|
||||
}
|
||||
|
||||
if(scene_state->need_token_update) {
|
||||
scene_state->need_token_update = false;
|
||||
scene_state->last_token_gen_time = curr_ts;
|
||||
|
||||
const TokenInfo* tokenInfo = scene_state->current_token;
|
||||
|
||||
if(tokenInfo->token != NULL && tokenInfo->token_length > 0) {
|
||||
furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever);
|
||||
size_t key_length;
|
||||
uint8_t* key = totp_crypto_decrypt(
|
||||
tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
|
||||
|
||||
int_token_to_str(
|
||||
totp_at(
|
||||
get_totp_algo_impl(tokenInfo->algo),
|
||||
key,
|
||||
key_length,
|
||||
curr_ts,
|
||||
plugin_state->timezone_offset,
|
||||
tokenInfo->duration),
|
||||
scene_state->last_code,
|
||||
tokenInfo->digits,
|
||||
tokenInfo->algo);
|
||||
memset_s(key, key_length, 0, key_length);
|
||||
free(key);
|
||||
} else {
|
||||
furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever);
|
||||
int_token_to_str(0, scene_state->last_code, tokenInfo->digits, tokenInfo->algo);
|
||||
}
|
||||
|
||||
furi_mutex_release(scene_state->last_code_update_sync);
|
||||
|
||||
if(is_new_token_time) {
|
||||
notification_message(
|
||||
plugin_state->notification_app,
|
||||
get_notification_sequence_new_token(plugin_state, scene_state));
|
||||
}
|
||||
}
|
||||
const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
uint16_t token_name_width = canvas_string_width(canvas, scene_state->current_token->name);
|
||||
@@ -353,17 +320,11 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
|
||||
draw_totp_code(canvas, scene_state);
|
||||
|
||||
const uint8_t TOKEN_LIFETIME = scene_state->current_token->duration;
|
||||
float percentDone = (float)(TOKEN_LIFETIME - curr_ts % TOKEN_LIFETIME) / (float)TOKEN_LIFETIME;
|
||||
uint8_t barWidth = (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * percentDone);
|
||||
uint8_t barX =
|
||||
((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) - barWidth) >> 1) + PROGRESS_BAR_MARGIN;
|
||||
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
barX,
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_x,
|
||||
SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT,
|
||||
barWidth,
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_width,
|
||||
PROGRESS_BAR_HEIGHT);
|
||||
|
||||
if(plugin_state->tokens_count > 1) {
|
||||
@@ -493,6 +454,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
|
||||
if(plugin_state->current_scene_state == NULL) return;
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
totp_generate_code_worker_stop(scene_state->generate_code_worker_context);
|
||||
|
||||
if(plugin_state->automation_method & AutomationMethodBadUsb) {
|
||||
totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context);
|
||||
}
|
||||
@@ -506,8 +469,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
|
||||
free(scene_state->notification_sequence_new_token);
|
||||
}
|
||||
|
||||
if(scene_state->notification_sequence_badusb != NULL) {
|
||||
free(scene_state->notification_sequence_badusb);
|
||||
if(scene_state->notification_sequence_automation != NULL) {
|
||||
free(scene_state->notification_sequence_automation);
|
||||
}
|
||||
|
||||
furi_mutex_free(scene_state->last_code_update_sync);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "bt_type_code.h"
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include <bt/bt_service/bt_i.h>
|
||||
#include <storage/storage.h>
|
||||
#include "../../types/common.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../common.h"
|
||||
#include "../type_code_common.h"
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys")
|
||||
|
||||
@@ -16,15 +17,15 @@ static inline bool totp_type_code_worker_stop_requested() {
|
||||
static void totp_type_code_worker_bt_set_app_mac(uint8_t* mac) {
|
||||
uint8_t max_i;
|
||||
size_t uid_size = furi_hal_version_uid_size();
|
||||
if(uid_size < 6) {
|
||||
if(uid_size < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN) {
|
||||
max_i = uid_size;
|
||||
} else {
|
||||
max_i = 6;
|
||||
max_i = TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN;
|
||||
}
|
||||
|
||||
const uint8_t* uid = furi_hal_version_uid();
|
||||
memcpy(mac, uid, max_i);
|
||||
for(uint8_t i = max_i; i < 6; i++) {
|
||||
for(uint8_t i = max_i; i < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN; i++) {
|
||||
mac[i] = 0;
|
||||
}
|
||||
|
||||
@@ -39,23 +40,21 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context
|
||||
i++;
|
||||
} while(!context->is_connected && i < 100 && !totp_type_code_worker_stop_requested());
|
||||
|
||||
if(context->is_connected && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
|
||||
if(context->is_connected &&
|
||||
furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) {
|
||||
totp_type_code_worker_execute_automation(
|
||||
&furi_hal_bt_hid_kb_press,
|
||||
&furi_hal_bt_hid_kb_release,
|
||||
context->string,
|
||||
context->string_length,
|
||||
context->code_buffer,
|
||||
context->code_buffer_size,
|
||||
context->flags);
|
||||
furi_mutex_release(context->string_sync);
|
||||
furi_mutex_release(context->code_buffer_sync);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t totp_type_code_worker_callback(void* context) {
|
||||
furi_check(context);
|
||||
FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(context_mutex == NULL) {
|
||||
return 251;
|
||||
}
|
||||
|
||||
TotpBtTypeCodeWorkerContext* bt_context = context;
|
||||
|
||||
@@ -92,13 +91,13 @@ static void connection_status_changed_callback(BtStatus status, void* context) {
|
||||
|
||||
void totp_bt_type_code_worker_start(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync) {
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync) {
|
||||
furi_check(context != NULL);
|
||||
context->string = code_buf;
|
||||
context->string_length = code_buf_length;
|
||||
context->string_sync = code_buf_update_sync;
|
||||
context->code_buffer = code_buffer;
|
||||
context->code_buffer_size = code_buffer_size;
|
||||
context->code_buffer_sync = code_buffer_sync;
|
||||
context->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(context->thread, "TOTPBtHidWorker");
|
||||
furi_thread_set_stack_size(context->thread, 1024);
|
||||
@@ -137,7 +136,6 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() {
|
||||
bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH);
|
||||
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
totp_type_code_worker_bt_set_app_mac(&context->bt_mac[0]);
|
||||
memcpy(
|
||||
&context->previous_bt_name[0],
|
||||
furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard),
|
||||
@@ -148,8 +146,10 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() {
|
||||
TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN);
|
||||
char new_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
|
||||
snprintf(new_name, sizeof(new_name), "%s TOTP Auth", furi_hal_version_get_name_ptr());
|
||||
uint8_t new_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
totp_type_code_worker_bt_set_app_mac(new_bt_mac);
|
||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, new_name);
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, context->bt_mac);
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, new_bt_mac);
|
||||
#endif
|
||||
|
||||
if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include <furi/core/string.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include "../../features_config.h"
|
||||
|
||||
@@ -14,34 +16,33 @@
|
||||
typedef uint8_t TotpBtTypeCodeWorkerEvent;
|
||||
|
||||
typedef struct {
|
||||
char* string;
|
||||
uint8_t string_length;
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* string_sync;
|
||||
FuriMutex* code_buffer_sync;
|
||||
Bt* bt;
|
||||
bool is_advertising;
|
||||
bool is_connected;
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
uint8_t bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
|
||||
uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
#endif
|
||||
} TotpBtTypeCodeWorkerContext;
|
||||
|
||||
enum TotpBtTypeCodeWorkerEvents {
|
||||
TotpBtTypeCodeWorkerEventReserved = 0b0000,
|
||||
TotpBtTypeCodeWorkerEventStop = 0b0100,
|
||||
TotpBtTypeCodeWorkerEventType = 0b1000
|
||||
TotpBtTypeCodeWorkerEventReserved = 0b00,
|
||||
TotpBtTypeCodeWorkerEventStop = 0b01,
|
||||
TotpBtTypeCodeWorkerEventType = 0b10
|
||||
};
|
||||
|
||||
TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init();
|
||||
void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context);
|
||||
void totp_bt_type_code_worker_start(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync);
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync);
|
||||
void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context);
|
||||
void totp_bt_type_code_worker_notify(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
|
||||
181
applications/external/totp/workers/generate_totp_code/generate_totp_code.c
vendored
Normal file
181
applications/external/totp/workers/generate_totp_code/generate_totp_code.c
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "generate_totp_code.h"
|
||||
#include "../../services/crypto/crypto.h"
|
||||
#include "../../services/totp/totp.h"
|
||||
#include "../../services/convert/convert.h"
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <memset_s.h>
|
||||
|
||||
#define ONE_SEC_MS (1000)
|
||||
|
||||
static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
|
||||
|
||||
static void
|
||||
int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) {
|
||||
str[len] = '\0';
|
||||
if(i_token_code == OTP_ERROR) {
|
||||
memset(&str[0], '-', len);
|
||||
} else {
|
||||
if(algo == STEAM) {
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26];
|
||||
i_token_code = i_token_code / 26;
|
||||
}
|
||||
} else {
|
||||
for(int8_t i = len - 1; i >= 0; i--) {
|
||||
str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10);
|
||||
i_token_code = i_token_code / 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
|
||||
switch(algo) {
|
||||
case SHA1:
|
||||
case STEAM:
|
||||
return TOTP_ALGO_SHA1;
|
||||
case SHA256:
|
||||
return TOTP_ALGO_SHA256;
|
||||
case SHA512:
|
||||
return TOTP_ALGO_SHA512;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void generate_totp_code(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
const TokenInfo* token_info,
|
||||
uint32_t current_ts) {
|
||||
if(token_info->token != NULL && token_info->token_length > 0) {
|
||||
size_t key_length;
|
||||
uint8_t* key = totp_crypto_decrypt(
|
||||
token_info->token, token_info->token_length, context->iv, &key_length);
|
||||
|
||||
int_token_to_str(
|
||||
totp_at(
|
||||
get_totp_algo_impl(token_info->algo),
|
||||
key,
|
||||
key_length,
|
||||
current_ts,
|
||||
context->timezone_offset,
|
||||
token_info->duration),
|
||||
context->code_buffer,
|
||||
token_info->digits,
|
||||
token_info->algo);
|
||||
memset_s(key, key_length, 0, key_length);
|
||||
free(key);
|
||||
} else {
|
||||
int_token_to_str(0, context->code_buffer, token_info->digits, token_info->algo);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t totp_generate_worker_callback(void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TotpGenerateCodeWorkerContext* t_context = context;
|
||||
|
||||
while(true) {
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
TotpGenerateCodeWorkerEventStop | TotpGenerateCodeWorkerEventForceUpdate,
|
||||
FuriFlagWaitAny,
|
||||
ONE_SEC_MS);
|
||||
|
||||
if(flags ==
|
||||
(uint32_t)
|
||||
FuriFlagErrorTimeout) { // If timeout, consider as no error, as we expect this and can handle gracefully
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
furi_check((flags & FuriFlagError) == 0); //-V562
|
||||
|
||||
if(flags & TotpGenerateCodeWorkerEventStop) break;
|
||||
|
||||
const TokenInfo* token_info = *(t_context->token_info);
|
||||
if(token_info == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t curr_ts = furi_hal_rtc_get_timestamp();
|
||||
|
||||
bool time_left = false;
|
||||
if(flags & TotpGenerateCodeWorkerEventForceUpdate ||
|
||||
(time_left = (curr_ts % token_info->duration) == 0)) {
|
||||
if(furi_mutex_acquire(t_context->code_buffer_sync, FuriWaitForever) == FuriStatusOk) {
|
||||
generate_totp_code(t_context, token_info, curr_ts);
|
||||
curr_ts = furi_hal_rtc_get_timestamp();
|
||||
furi_mutex_release(t_context->code_buffer_sync);
|
||||
if(t_context->on_new_code_generated_handler != NULL) {
|
||||
(*(t_context->on_new_code_generated_handler))(
|
||||
time_left, t_context->on_new_code_generated_handler_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(t_context->on_code_lifetime_changed_handler != NULL) {
|
||||
(*(t_context->on_code_lifetime_changed_handler))(
|
||||
(float)(token_info->duration - curr_ts % token_info->duration) /
|
||||
(float)token_info->duration,
|
||||
t_context->on_code_lifetime_changed_handler_context);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||
char* code_buffer,
|
||||
TokenInfo** token_info,
|
||||
FuriMutex* code_buffer_sync,
|
||||
float timezone_offset,
|
||||
uint8_t* iv) {
|
||||
TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext));
|
||||
furi_check(context != NULL);
|
||||
context->code_buffer = code_buffer;
|
||||
context->token_info = token_info;
|
||||
context->code_buffer_sync = code_buffer_sync;
|
||||
context->timezone_offset = timezone_offset;
|
||||
context->iv = iv;
|
||||
context->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(context->thread, "TOTPGenerateWorker");
|
||||
furi_thread_set_stack_size(context->thread, 2048);
|
||||
furi_thread_set_context(context->thread, context);
|
||||
furi_thread_set_callback(context->thread, totp_generate_worker_callback);
|
||||
furi_thread_start(context->thread);
|
||||
return context;
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context) {
|
||||
furi_check(context != NULL);
|
||||
furi_thread_flags_set(furi_thread_get_id(context->thread), TotpGenerateCodeWorkerEventStop);
|
||||
furi_thread_join(context->thread);
|
||||
furi_thread_free(context->thread);
|
||||
free(context);
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_notify(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TotpGenerateCodeWorkerEvent event) {
|
||||
furi_check(context != NULL);
|
||||
furi_thread_flags_set(furi_thread_get_id(context->thread), event);
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_set_code_generated_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
|
||||
void* on_new_code_generated_handler_context) {
|
||||
furi_check(context != NULL);
|
||||
context->on_new_code_generated_handler = on_new_code_generated_handler;
|
||||
context->on_new_code_generated_handler_context = on_new_code_generated_handler_context;
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_set_lifetime_changed_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
|
||||
void* on_code_lifetime_changed_handler_context) {
|
||||
furi_check(context != NULL);
|
||||
context->on_code_lifetime_changed_handler = on_code_lifetime_changed_handler;
|
||||
context->on_code_lifetime_changed_handler_context = on_code_lifetime_changed_handler_context;
|
||||
}
|
||||
49
applications/external/totp/workers/generate_totp_code/generate_totp_code.h
vendored
Normal file
49
applications/external/totp/workers/generate_totp_code/generate_totp_code.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include "../../types/token_info.h"
|
||||
|
||||
typedef uint8_t TotpGenerateCodeWorkerEvent;
|
||||
|
||||
typedef void (*TOTP_NEW_CODE_GENERATED_HANDLER)(bool time_left, void* context);
|
||||
typedef void (*TOTP_CODE_LIFETIME_CHANGED_HANDLER)(float code_lifetime_percent, void* context);
|
||||
|
||||
typedef struct {
|
||||
char* code_buffer;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
TokenInfo** token_info;
|
||||
float timezone_offset;
|
||||
uint8_t* iv;
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
|
||||
void* on_new_code_generated_handler_context;
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
|
||||
void* on_code_lifetime_changed_handler_context;
|
||||
} TotpGenerateCodeWorkerContext;
|
||||
|
||||
enum TotGenerateCodeWorkerEvents {
|
||||
TotpGenerateCodeWorkerEventReserved = 0b00,
|
||||
TotpGenerateCodeWorkerEventStop = 0b01,
|
||||
TotpGenerateCodeWorkerEventForceUpdate = 0b10
|
||||
};
|
||||
|
||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||
char* code_buffer,
|
||||
TokenInfo** token_info,
|
||||
FuriMutex* code_buffer_sync,
|
||||
float timezone_offset,
|
||||
uint8_t* iv);
|
||||
void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context);
|
||||
void totp_generate_code_worker_notify(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TotpGenerateCodeWorkerEvent event);
|
||||
void totp_generate_code_worker_set_code_generated_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
|
||||
void* on_new_code_generated_handler_context);
|
||||
void totp_generate_code_worker_set_lifetime_changed_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
|
||||
void* on_code_lifetime_changed_handler_context);
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common.h"
|
||||
#include <furi/furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "type_code_common.h"
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include "../../services/convert/convert.h"
|
||||
|
||||
static const uint8_t hid_number_keys[] = {
|
||||
@@ -42,18 +42,18 @@ static void totp_type_code_worker_press_key(
|
||||
void totp_type_code_worker_execute_automation(
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||
const char* string,
|
||||
uint8_t string_length,
|
||||
const char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
TokenAutomationFeature features) {
|
||||
furi_delay_ms(500);
|
||||
uint8_t i = 0;
|
||||
totp_type_code_worker_press_key(
|
||||
HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features);
|
||||
|
||||
while(i < string_length && string[i] != 0) {
|
||||
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(string[i]);
|
||||
while(i < code_buffer_size && code_buffer[i] != 0) {
|
||||
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]);
|
||||
if(char_index > 9) {
|
||||
char_index = string[i] - 0x41 + 10;
|
||||
char_index = code_buffer[i] - 0x41 + 10;
|
||||
}
|
||||
|
||||
if(char_index > 35) break;
|
||||
@@ -7,6 +7,6 @@ typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
|
||||
void totp_type_code_worker_execute_automation(
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||
const char* string,
|
||||
uint8_t string_length,
|
||||
const char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
TokenAutomationFeature features);
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "usb_type_code.h"
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include "../../services/convert/convert.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../common.h"
|
||||
#include "../type_code_common.h"
|
||||
|
||||
static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
|
||||
if(context->usb_mode_prev != NULL) {
|
||||
@@ -25,14 +26,14 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
|
||||
} while(!furi_hal_hid_is_connected() && i < 100 && !totp_type_code_worker_stop_requested());
|
||||
|
||||
if(furi_hal_hid_is_connected() &&
|
||||
furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
|
||||
furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) {
|
||||
totp_type_code_worker_execute_automation(
|
||||
&furi_hal_hid_kb_press,
|
||||
&furi_hal_hid_kb_release,
|
||||
context->string,
|
||||
context->string_length,
|
||||
context->code_buffer,
|
||||
context->code_buffer_size,
|
||||
context->flags);
|
||||
furi_mutex_release(context->string_sync);
|
||||
furi_mutex_release(context->code_buffer_sync);
|
||||
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
@@ -43,9 +44,6 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
|
||||
static int32_t totp_type_code_worker_callback(void* context) {
|
||||
furi_check(context);
|
||||
FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(context_mutex == NULL) {
|
||||
return 251;
|
||||
}
|
||||
|
||||
while(true) {
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
@@ -70,14 +68,14 @@ static int32_t totp_type_code_worker_callback(void* context) {
|
||||
}
|
||||
|
||||
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync) {
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync) {
|
||||
TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext));
|
||||
furi_check(context != NULL);
|
||||
context->string = code_buf;
|
||||
context->string_length = code_buf_length;
|
||||
context->string_sync = code_buf_update_sync;
|
||||
context->code_buffer = code_buffer;
|
||||
context->code_buffer_size = code_buffer_size;
|
||||
context->code_buffer_sync = code_buffer_sync;
|
||||
context->thread = furi_thread_alloc();
|
||||
context->usb_mode_prev = NULL;
|
||||
furi_thread_set_name(context->thread, "TOTPUsbHidWorker");
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <furi/core/check.h>
|
||||
#include <furi_hal_usb.h>
|
||||
|
||||
typedef uint8_t TotpUsbTypeCodeWorkerEvent;
|
||||
|
||||
typedef struct {
|
||||
char* string;
|
||||
uint8_t string_length;
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* string_sync;
|
||||
FuriMutex* code_buffer_sync;
|
||||
FuriHalUsbInterface* usb_mode_prev;
|
||||
} TotpUsbTypeCodeWorkerContext;
|
||||
|
||||
@@ -22,9 +25,9 @@ enum TotpUsbTypeCodeWorkerEvents {
|
||||
};
|
||||
|
||||
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync);
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync);
|
||||
void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context);
|
||||
void totp_usb_type_code_worker_notify(
|
||||
TotpUsbTypeCodeWorkerContext* context,
|
||||
|
||||
@@ -114,13 +114,9 @@ void uart_terminal_scene_console_output_on_enter(void* context) {
|
||||
// Send command with CR+LF or newline '\n'
|
||||
if(app->is_command && app->selected_tx_string) {
|
||||
if(app->TERMINAL_MODE == 1) {
|
||||
// char buffer[240];
|
||||
// snprintf(buffer, 240, "%s\r\n", (app->selected_tx_string));
|
||||
// uart_terminal_uart_tx((unsigned char *)buffer, strlen(buffer));
|
||||
uart_terminal_uart_tx(
|
||||
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
|
||||
uart_terminal_uart_tx((uint8_t*)("\r"), 1);
|
||||
uart_terminal_uart_tx((uint8_t*)("\n"), 1);
|
||||
uart_terminal_uart_tx((uint8_t*)("\r\n"), 2);
|
||||
} else {
|
||||
uart_terminal_uart_tx(
|
||||
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
|
||||
@@ -149,9 +145,4 @@ void uart_terminal_scene_console_output_on_exit(void* context) {
|
||||
|
||||
// Unregister rx callback
|
||||
uart_terminal_uart_set_handle_rx_data_cb(app->uart, NULL);
|
||||
|
||||
// Automatically logut when exiting view
|
||||
//if(app->is_command) {
|
||||
// uart_terminal_uart_tx((uint8_t*)("exit\n"), strlen("exit\n"));
|
||||
//}
|
||||
}
|
||||
@@ -8,4 +8,5 @@ App(
|
||||
order=90,
|
||||
fap_icon="wifi_10px.png",
|
||||
fap_category="WiFi",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -44,24 +44,24 @@ void wifi_marauder_scene_text_input_on_enter(void* context) {
|
||||
}
|
||||
|
||||
// Setup view
|
||||
TextInput* text_input = app->text_input;
|
||||
WIFI_TextInput* text_input = app->text_input;
|
||||
// Add help message to header
|
||||
if(app->special_case_input_step == 1) {
|
||||
text_input_set_header_text(text_input, "Enter source MAC");
|
||||
wifi_text_input_set_header_text(text_input, "Enter source MAC");
|
||||
} else if(0 == strncmp("ssid -a -g", app->selected_tx_string, strlen("ssid -a -g"))) {
|
||||
text_input_set_header_text(text_input, "Enter # SSIDs to generate");
|
||||
wifi_text_input_set_header_text(text_input, "Enter # SSIDs to generate");
|
||||
} else if(0 == strncmp("ssid -a -n", app->selected_tx_string, strlen("ssid -a -n"))) {
|
||||
text_input_set_header_text(text_input, "Enter SSID name to add");
|
||||
wifi_text_input_set_header_text(text_input, "Enter SSID name to add");
|
||||
} else if(0 == strncmp("ssid -r", app->selected_tx_string, strlen("ssid -r"))) {
|
||||
text_input_set_header_text(text_input, "Remove target from SSID list");
|
||||
wifi_text_input_set_header_text(text_input, "Remove target from SSID list");
|
||||
} else if(0 == strncmp("select -a", app->selected_tx_string, strlen("select -a"))) {
|
||||
text_input_set_header_text(text_input, "Add target from AP list");
|
||||
wifi_text_input_set_header_text(text_input, "Add target from AP list");
|
||||
} else if(0 == strncmp("select -s", app->selected_tx_string, strlen("select -s"))) {
|
||||
text_input_set_header_text(text_input, "Add target from SSID list");
|
||||
wifi_text_input_set_header_text(text_input, "Add target from SSID list");
|
||||
} else {
|
||||
text_input_set_header_text(text_input, "Add command arguments");
|
||||
wifi_text_input_set_header_text(text_input, "Add command arguments");
|
||||
}
|
||||
text_input_set_result_callback(
|
||||
wifi_text_input_set_result_callback(
|
||||
text_input,
|
||||
wifi_marauder_scene_text_input_callback,
|
||||
app,
|
||||
@@ -84,7 +84,7 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev
|
||||
consumed = true;
|
||||
} else if(event.event == WifiMarauderEventSaveSourceMac) {
|
||||
if(12 != strlen(app->text_input_store)) {
|
||||
text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!");
|
||||
wifi_text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!");
|
||||
} else {
|
||||
snprintf(
|
||||
app->special_case_input_src_addr,
|
||||
@@ -106,12 +106,12 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev
|
||||
// Advance scene to input destination MAC, clear text input
|
||||
app->special_case_input_step = 2;
|
||||
bzero(app->text_input_store, WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE);
|
||||
text_input_set_header_text(app->text_input, "Enter destination MAC");
|
||||
wifi_text_input_set_header_text(app->text_input, "Enter destination MAC");
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == WifiMarauderEventSaveDestinationMac) {
|
||||
if(12 != strlen(app->text_input_store)) {
|
||||
text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!");
|
||||
wifi_text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!");
|
||||
} else {
|
||||
snprintf(
|
||||
app->special_case_input_dst_addr,
|
||||
@@ -150,5 +150,5 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev
|
||||
void wifi_marauder_scene_text_input_on_exit(void* context) {
|
||||
WifiMarauderApp* app = context;
|
||||
|
||||
text_input_reset(app->text_input);
|
||||
wifi_text_input_reset(app->text_input);
|
||||
}
|
||||
|
||||
@@ -66,9 +66,11 @@ WifiMarauderApp* wifi_marauder_app_alloc() {
|
||||
app->text_box_store = furi_string_alloc();
|
||||
furi_string_reserve(app->text_box_store, WIFI_MARAUDER_TEXT_BOX_STORE_SIZE);
|
||||
|
||||
app->text_input = text_input_alloc();
|
||||
app->text_input = wifi_text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, WifiMarauderAppViewTextInput, text_input_get_view(app->text_input));
|
||||
app->view_dispatcher,
|
||||
WifiMarauderAppViewTextInput,
|
||||
wifi_text_input_get_view(app->text_input));
|
||||
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
@@ -137,7 +139,7 @@ void wifi_marauder_app_free(WifiMarauderApp* app) {
|
||||
widget_free(app->widget);
|
||||
text_box_free(app->text_box);
|
||||
furi_string_free(app->text_box_store);
|
||||
text_input_free(app->text_input);
|
||||
wifi_text_input_free(app->text_input);
|
||||
storage_file_free(app->capture_file);
|
||||
storage_file_free(app->log_file);
|
||||
storage_file_free(app->save_pcap_setting_file);
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/text_box.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include "wifi_marauder_text_input.h"
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
@@ -42,7 +42,7 @@ struct WifiMarauderApp {
|
||||
FuriString* text_box_store;
|
||||
size_t text_box_store_strlen;
|
||||
TextBox* text_box;
|
||||
TextInput* text_input;
|
||||
WIFI_TextInput* text_input;
|
||||
Storage* storage;
|
||||
File* capture_file;
|
||||
File* log_file;
|
||||
|
||||
625
applications/external/wifi_marauder_companion/wifi_marauder_text_input.c
vendored
Normal file
625
applications/external/wifi_marauder_companion/wifi_marauder_text_input.c
vendored
Normal file
@@ -0,0 +1,625 @@
|
||||
#include "wifi_marauder_text_input.h"
|
||||
#include <gui/elements.h>
|
||||
#include "assets_icons.h"
|
||||
#include "wifi_marauder_app_i.h"
|
||||
#include <furi.h>
|
||||
|
||||
struct WIFI_TextInput {
|
||||
View* view;
|
||||
FuriTimer* timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char text;
|
||||
const uint8_t x;
|
||||
const uint8_t y;
|
||||
} WIFI_TextInputKey;
|
||||
|
||||
typedef struct {
|
||||
const char* header;
|
||||
char* text_buffer;
|
||||
size_t text_buffer_size;
|
||||
bool clear_default_text;
|
||||
|
||||
WIFI_TextInputCallback callback;
|
||||
void* callback_context;
|
||||
|
||||
uint8_t selected_row;
|
||||
uint8_t selected_column;
|
||||
|
||||
WIFI_TextInputValidatorCallback validator_callback;
|
||||
void* validator_callback_context;
|
||||
FuriString* validator_text;
|
||||
bool valadator_message_visible;
|
||||
} WIFI_TextInputModel;
|
||||
|
||||
static const uint8_t keyboard_origin_x = 1;
|
||||
static const uint8_t keyboard_origin_y = 29;
|
||||
static const uint8_t keyboard_row_count = 4;
|
||||
|
||||
#define ENTER_KEY '\r'
|
||||
#define BACKSPACE_KEY '\b'
|
||||
|
||||
static const WIFI_TextInputKey keyboard_keys_row_1[] = {
|
||||
{'{', 1, 0},
|
||||
{'(', 9, 0},
|
||||
{'[', 17, 0},
|
||||
{'|', 25, 0},
|
||||
{'@', 33, 0},
|
||||
{'&', 41, 0},
|
||||
{'#', 49, 0},
|
||||
{';', 57, 0},
|
||||
{'^', 65, 0},
|
||||
{'*', 73, 0},
|
||||
{'`', 81, 0},
|
||||
{'"', 89, 0},
|
||||
{'~', 97, 0},
|
||||
{'\'', 105, 0},
|
||||
{'.', 113, 0},
|
||||
{'/', 120, 0},
|
||||
};
|
||||
|
||||
static const WIFI_TextInputKey keyboard_keys_row_2[] = {
|
||||
{'q', 1, 10},
|
||||
{'w', 9, 10},
|
||||
{'e', 17, 10},
|
||||
{'r', 25, 10},
|
||||
{'t', 33, 10},
|
||||
{'y', 41, 10},
|
||||
{'u', 49, 10},
|
||||
{'i', 57, 10},
|
||||
{'o', 65, 10},
|
||||
{'p', 73, 10},
|
||||
{'0', 81, 10},
|
||||
{'1', 89, 10},
|
||||
{'2', 97, 10},
|
||||
{'3', 105, 10},
|
||||
{'=', 113, 10},
|
||||
{'-', 120, 10},
|
||||
};
|
||||
|
||||
static const WIFI_TextInputKey keyboard_keys_row_3[] = {
|
||||
{'a', 1, 21},
|
||||
{'s', 9, 21},
|
||||
{'d', 18, 21},
|
||||
{'f', 25, 21},
|
||||
{'g', 33, 21},
|
||||
{'h', 41, 21},
|
||||
{'j', 49, 21},
|
||||
{'k', 57, 21},
|
||||
{'l', 65, 21},
|
||||
{BACKSPACE_KEY, 72, 13},
|
||||
{'4', 89, 21},
|
||||
{'5', 97, 21},
|
||||
{'6', 105, 21},
|
||||
{'$', 113, 21},
|
||||
{'%', 120, 21},
|
||||
|
||||
};
|
||||
|
||||
static const WIFI_TextInputKey keyboard_keys_row_4[] = {
|
||||
{'z', 1, 33},
|
||||
{'x', 9, 33},
|
||||
{'c', 18, 33},
|
||||
{'v', 25, 33},
|
||||
{'b', 33, 33},
|
||||
{'n', 41, 33},
|
||||
{'m', 49, 33},
|
||||
{'_', 57, 33},
|
||||
{ENTER_KEY, 64, 24},
|
||||
{'7', 89, 33},
|
||||
{'8', 97, 33},
|
||||
{'9', 105, 33},
|
||||
{'!', 113, 33},
|
||||
{'+', 120, 33},
|
||||
};
|
||||
|
||||
static uint8_t get_row_size(uint8_t row_index) {
|
||||
uint8_t row_size = 0;
|
||||
|
||||
switch(row_index + 1) {
|
||||
case 1:
|
||||
row_size = sizeof(keyboard_keys_row_1) / sizeof(WIFI_TextInputKey);
|
||||
break;
|
||||
case 2:
|
||||
row_size = sizeof(keyboard_keys_row_2) / sizeof(WIFI_TextInputKey);
|
||||
break;
|
||||
case 3:
|
||||
row_size = sizeof(keyboard_keys_row_3) / sizeof(WIFI_TextInputKey);
|
||||
break;
|
||||
case 4:
|
||||
row_size = sizeof(keyboard_keys_row_4) / sizeof(WIFI_TextInputKey);
|
||||
break;
|
||||
}
|
||||
|
||||
return row_size;
|
||||
}
|
||||
|
||||
static const WIFI_TextInputKey* get_row(uint8_t row_index) {
|
||||
const WIFI_TextInputKey* row = NULL;
|
||||
|
||||
switch(row_index + 1) {
|
||||
case 1:
|
||||
row = keyboard_keys_row_1;
|
||||
break;
|
||||
case 2:
|
||||
row = keyboard_keys_row_2;
|
||||
break;
|
||||
case 3:
|
||||
row = keyboard_keys_row_3;
|
||||
break;
|
||||
case 4:
|
||||
row = keyboard_keys_row_4;
|
||||
break;
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
static char get_selected_char(WIFI_TextInputModel* model) {
|
||||
return get_row(model->selected_row)[model->selected_column].text;
|
||||
}
|
||||
|
||||
static bool char_is_lowercase(char letter) {
|
||||
return (letter >= 0x61 && letter <= 0x7A);
|
||||
}
|
||||
|
||||
static char char_to_uppercase(const char letter) {
|
||||
switch(letter) {
|
||||
case '_':
|
||||
return 0x20;
|
||||
break;
|
||||
case '(':
|
||||
return 0x29;
|
||||
break;
|
||||
case '{':
|
||||
return 0x7d;
|
||||
break;
|
||||
case '[':
|
||||
return 0x5d;
|
||||
break;
|
||||
case '/':
|
||||
return 0x5c;
|
||||
break;
|
||||
case ';':
|
||||
return 0x3a;
|
||||
break;
|
||||
case '.':
|
||||
return 0x2c;
|
||||
break;
|
||||
case '!':
|
||||
return 0x3f;
|
||||
break;
|
||||
case '<':
|
||||
return 0x3e;
|
||||
break;
|
||||
}
|
||||
if(char_is_lowercase(letter)) {
|
||||
return (letter - 0x20);
|
||||
} else {
|
||||
return letter;
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_text_input_backspace_cb(WIFI_TextInputModel* model) {
|
||||
uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer);
|
||||
if(text_length > 0) {
|
||||
model->text_buffer[text_length - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
WIFI_TextInputModel* model = _model;
|
||||
//uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
|
||||
uint8_t needed_string_width = canvas_width(canvas) - 8;
|
||||
uint8_t start_pos = 4;
|
||||
|
||||
const char* text = model->text_buffer;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_draw_str(canvas, 2, 7, model->header);
|
||||
elements_slightly_rounded_frame(canvas, 1, 8, 126, 12);
|
||||
|
||||
if(canvas_string_width(canvas, text) > needed_string_width) {
|
||||
canvas_draw_str(canvas, start_pos, 17, "...");
|
||||
start_pos += 6;
|
||||
needed_string_width -= 8;
|
||||
}
|
||||
|
||||
while(text != 0 && canvas_string_width(canvas, text) > needed_string_width) {
|
||||
text++;
|
||||
}
|
||||
|
||||
if(model->clear_default_text) {
|
||||
elements_slightly_rounded_box(
|
||||
canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 2, 10);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
} else {
|
||||
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 18, "|");
|
||||
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 18, "|");
|
||||
}
|
||||
canvas_draw_str(canvas, start_pos, 17, text);
|
||||
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
|
||||
for(uint8_t row = 0; row <= keyboard_row_count; row++) {
|
||||
const uint8_t column_count = get_row_size(row);
|
||||
const WIFI_TextInputKey* keys = get_row(row);
|
||||
|
||||
for(size_t column = 0; column < column_count; column++) {
|
||||
if(keys[column].text == ENTER_KEY) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
if(model->selected_row == row && model->selected_column == column) {
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
&I_KeySaveSelected_24x11);
|
||||
} else {
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
&I_KeySave_24x11);
|
||||
}
|
||||
} else if(keys[column].text == BACKSPACE_KEY) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
if(model->selected_row == row && model->selected_column == column) {
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
&I_KeyBackspaceSelected_16x9);
|
||||
} else {
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
&I_KeyBackspace_16x9);
|
||||
}
|
||||
} else {
|
||||
if(model->selected_row == row && model->selected_column == column) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x - 1,
|
||||
keyboard_origin_y + keys[column].y - 8,
|
||||
7,
|
||||
10);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
canvas_draw_glyph(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
keys[column].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(model->valadator_message_visible) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, 8, 10, 110, 48);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42);
|
||||
canvas_draw_rframe(canvas, 8, 8, 112, 50, 3);
|
||||
canvas_draw_rframe(canvas, 9, 9, 110, 48, 2);
|
||||
elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text));
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_text_input_handle_up(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) {
|
||||
UNUSED(wifi_text_input);
|
||||
if(model->selected_row > 0) {
|
||||
model->selected_row--;
|
||||
if(model->selected_column > get_row_size(model->selected_row) - 6) {
|
||||
model->selected_column = model->selected_column + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_text_input_handle_down(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) {
|
||||
UNUSED(wifi_text_input);
|
||||
if(model->selected_row < keyboard_row_count - 1) {
|
||||
model->selected_row++;
|
||||
if(model->selected_column > get_row_size(model->selected_row) - 4) {
|
||||
model->selected_column = model->selected_column - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_text_input_handle_left(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) {
|
||||
UNUSED(wifi_text_input);
|
||||
if(model->selected_column > 0) {
|
||||
model->selected_column--;
|
||||
} else {
|
||||
model->selected_column = get_row_size(model->selected_row) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_text_input_handle_right(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) {
|
||||
UNUSED(wifi_text_input);
|
||||
if(model->selected_column < get_row_size(model->selected_row) - 1) {
|
||||
model->selected_column++;
|
||||
} else {
|
||||
model->selected_column = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_text_input_handle_ok(
|
||||
WIFI_TextInput* wifi_text_input,
|
||||
WIFI_TextInputModel* model,
|
||||
bool shift) {
|
||||
char selected = get_selected_char(model);
|
||||
uint8_t text_length = strlen(model->text_buffer);
|
||||
|
||||
if(shift) {
|
||||
selected = char_to_uppercase(selected);
|
||||
}
|
||||
|
||||
if(selected == ENTER_KEY) {
|
||||
if(model->validator_callback &&
|
||||
(!model->validator_callback(
|
||||
model->text_buffer, model->validator_text, model->validator_callback_context))) {
|
||||
model->valadator_message_visible = true;
|
||||
furi_timer_start(wifi_text_input->timer, furi_kernel_get_tick_frequency() * 4);
|
||||
} else if(model->callback != 0 && text_length > 0) {
|
||||
model->callback(model->callback_context);
|
||||
}
|
||||
} else if(selected == BACKSPACE_KEY) {
|
||||
wifi_text_input_backspace_cb(model);
|
||||
} else {
|
||||
if(model->clear_default_text) {
|
||||
text_length = 0;
|
||||
}
|
||||
if(text_length < (model->text_buffer_size - 1)) {
|
||||
model->text_buffer[text_length] = selected;
|
||||
model->text_buffer[text_length + 1] = 0;
|
||||
}
|
||||
}
|
||||
model->clear_default_text = false;
|
||||
}
|
||||
|
||||
static bool wifi_text_input_view_input_callback(InputEvent* event, void* context) {
|
||||
WIFI_TextInput* wifi_text_input = context;
|
||||
furi_assert(wifi_text_input);
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
// Acquire model
|
||||
WIFI_TextInputModel* model = view_get_model(wifi_text_input->view);
|
||||
|
||||
if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) &&
|
||||
model->valadator_message_visible) {
|
||||
model->valadator_message_visible = false;
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort) {
|
||||
consumed = true;
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
wifi_text_input_handle_up(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
wifi_text_input_handle_down(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
wifi_text_input_handle_left(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
wifi_text_input_handle_right(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
wifi_text_input_handle_ok(wifi_text_input, model, false);
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
consumed = true;
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
wifi_text_input_handle_up(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
wifi_text_input_handle_down(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
wifi_text_input_handle_left(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
wifi_text_input_handle_right(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
wifi_text_input_handle_ok(wifi_text_input, model, true);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
wifi_text_input_backspace_cb(model);
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
} else if(event->type == InputTypeRepeat) {
|
||||
consumed = true;
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
wifi_text_input_handle_up(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
wifi_text_input_handle_down(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
wifi_text_input_handle_left(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
wifi_text_input_handle_right(wifi_text_input, model);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
wifi_text_input_backspace_cb(model);
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit model
|
||||
view_commit_model(wifi_text_input->view, consumed);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void wifi_text_input_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
WIFI_TextInput* wifi_text_input = context;
|
||||
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{ model->valadator_message_visible = false; },
|
||||
true);
|
||||
}
|
||||
|
||||
WIFI_TextInput* wifi_text_input_alloc() {
|
||||
WIFI_TextInput* wifi_text_input = malloc(sizeof(WIFI_TextInput));
|
||||
wifi_text_input->view = view_alloc();
|
||||
view_set_context(wifi_text_input->view, wifi_text_input);
|
||||
view_allocate_model(wifi_text_input->view, ViewModelTypeLocking, sizeof(WIFI_TextInputModel));
|
||||
view_set_draw_callback(wifi_text_input->view, wifi_text_input_view_draw_callback);
|
||||
view_set_input_callback(wifi_text_input->view, wifi_text_input_view_input_callback);
|
||||
|
||||
wifi_text_input->timer =
|
||||
furi_timer_alloc(wifi_text_input_timer_callback, FuriTimerTypeOnce, wifi_text_input);
|
||||
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{ model->validator_text = furi_string_alloc(); },
|
||||
false);
|
||||
|
||||
wifi_text_input_reset(wifi_text_input);
|
||||
|
||||
return wifi_text_input;
|
||||
}
|
||||
|
||||
void wifi_text_input_free(WIFI_TextInput* wifi_text_input) {
|
||||
furi_assert(wifi_text_input);
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{ furi_string_free(model->validator_text); },
|
||||
false);
|
||||
|
||||
// Send stop command
|
||||
furi_timer_stop(wifi_text_input->timer);
|
||||
// Release allocated memory
|
||||
furi_timer_free(wifi_text_input->timer);
|
||||
|
||||
view_free(wifi_text_input->view);
|
||||
|
||||
free(wifi_text_input);
|
||||
}
|
||||
|
||||
void wifi_text_input_reset(WIFI_TextInput* wifi_text_input) {
|
||||
furi_assert(wifi_text_input);
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{
|
||||
model->text_buffer_size = 0;
|
||||
model->header = "";
|
||||
model->selected_row = 0;
|
||||
model->selected_column = 0;
|
||||
model->clear_default_text = false;
|
||||
model->text_buffer = NULL;
|
||||
model->text_buffer_size = 0;
|
||||
model->callback = NULL;
|
||||
model->callback_context = NULL;
|
||||
model->validator_callback = NULL;
|
||||
model->validator_callback_context = NULL;
|
||||
furi_string_reset(model->validator_text);
|
||||
model->valadator_message_visible = false;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
View* wifi_text_input_get_view(WIFI_TextInput* wifi_text_input) {
|
||||
furi_assert(wifi_text_input);
|
||||
return wifi_text_input->view;
|
||||
}
|
||||
|
||||
void wifi_text_input_set_result_callback(
|
||||
WIFI_TextInput* wifi_text_input,
|
||||
WIFI_TextInputCallback callback,
|
||||
void* callback_context,
|
||||
char* text_buffer,
|
||||
size_t text_buffer_size,
|
||||
bool clear_default_text) {
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{
|
||||
model->callback = callback;
|
||||
model->callback_context = callback_context;
|
||||
model->text_buffer = text_buffer;
|
||||
model->text_buffer_size = text_buffer_size;
|
||||
model->clear_default_text = clear_default_text;
|
||||
if(text_buffer && text_buffer[0] != '\0') {
|
||||
// Set focus on Save
|
||||
model->selected_row = 2;
|
||||
model->selected_column = 8;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void wifi_text_input_set_validator(
|
||||
WIFI_TextInput* wifi_text_input,
|
||||
WIFI_TextInputValidatorCallback callback,
|
||||
void* callback_context) {
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{
|
||||
model->validator_callback = callback;
|
||||
model->validator_callback_context = callback_context;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
WIFI_TextInputValidatorCallback
|
||||
wifi_text_input_get_validator_callback(WIFI_TextInput* wifi_text_input) {
|
||||
WIFI_TextInputValidatorCallback validator_callback = NULL;
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{ validator_callback = model->validator_callback; },
|
||||
false);
|
||||
return validator_callback;
|
||||
}
|
||||
|
||||
void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* wifi_text_input) {
|
||||
void* validator_callback_context = NULL;
|
||||
with_view_model(
|
||||
wifi_text_input->view,
|
||||
WIFI_TextInputModel * model,
|
||||
{ validator_callback_context = model->validator_callback_context; },
|
||||
false);
|
||||
return validator_callback_context;
|
||||
}
|
||||
|
||||
void wifi_text_input_set_header_text(WIFI_TextInput* wifi_text_input, const char* text) {
|
||||
with_view_model(
|
||||
wifi_text_input->view, WIFI_TextInputModel * model, { model->header = text; }, true);
|
||||
}
|
||||
82
applications/external/wifi_marauder_companion/wifi_marauder_text_input.h
vendored
Normal file
82
applications/external/wifi_marauder_companion/wifi_marauder_text_input.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "wifi_marauder_validators.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Text input anonymous structure */
|
||||
typedef struct WIFI_TextInput WIFI_TextInput;
|
||||
typedef void (*WIFI_TextInputCallback)(void* context);
|
||||
typedef bool (*WIFI_TextInputValidatorCallback)(const char* text, FuriString* error, void* context);
|
||||
|
||||
/** Allocate and initialize text input
|
||||
*
|
||||
* This text input is used to enter string
|
||||
*
|
||||
* @return WIFI_TextInput instance
|
||||
*/
|
||||
WIFI_TextInput* wifi_text_input_alloc();
|
||||
|
||||
/** Deinitialize and free text input
|
||||
*
|
||||
* @param wifi_text_input WIFI_TextInput instance
|
||||
*/
|
||||
void wifi_text_input_free(WIFI_TextInput* wifi_text_input);
|
||||
|
||||
/** Clean text input view Note: this function does not free memory
|
||||
*
|
||||
* @param wifi_text_input Text input instance
|
||||
*/
|
||||
void wifi_text_input_reset(WIFI_TextInput* wifi_text_input);
|
||||
|
||||
/** Get text input view
|
||||
*
|
||||
* @param wifi_text_input WIFI_TextInput instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* wifi_text_input_get_view(WIFI_TextInput* wifi_text_input);
|
||||
|
||||
/** Set text input result callback
|
||||
*
|
||||
* @param wifi_text_input WIFI_TextInput instance
|
||||
* @param callback callback fn
|
||||
* @param callback_context callback context
|
||||
* @param text_buffer pointer to YOUR text buffer, that we going
|
||||
* to modify
|
||||
* @param text_buffer_size YOUR text buffer size in bytes. Max string
|
||||
* length will be text_buffer_size-1.
|
||||
* @param clear_default_text clear text from text_buffer on first OK
|
||||
* event
|
||||
*/
|
||||
void wifi_text_input_set_result_callback(
|
||||
WIFI_TextInput* wifi_text_input,
|
||||
WIFI_TextInputCallback callback,
|
||||
void* callback_context,
|
||||
char* text_buffer,
|
||||
size_t text_buffer_size,
|
||||
bool clear_default_text);
|
||||
|
||||
void wifi_text_input_set_validator(
|
||||
WIFI_TextInput* wifi_text_input,
|
||||
WIFI_TextInputValidatorCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
WIFI_TextInputValidatorCallback
|
||||
wifi_text_input_get_validator_callback(WIFI_TextInput* wifi_text_input);
|
||||
|
||||
void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* wifi_text_input);
|
||||
|
||||
/** Set text input header text
|
||||
*
|
||||
* @param wifi_text_input WIFI_TextInput instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void wifi_text_input_set_header_text(WIFI_TextInput* wifi_text_input, const char* text);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
57
applications/external/wifi_marauder_companion/wifi_marauder_validators.c
vendored
Normal file
57
applications/external/wifi_marauder_companion/wifi_marauder_validators.c
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <furi.h>
|
||||
#include "wifi_marauder_validators.h"
|
||||
#include <storage/storage.h>
|
||||
|
||||
struct ValidatorIsFile {
|
||||
char* app_path_folder;
|
||||
const char* app_extension;
|
||||
char* current_name;
|
||||
};
|
||||
|
||||
bool validator_is_file_callback(const char* text, FuriString* error, void* context) {
|
||||
furi_assert(context);
|
||||
ValidatorIsFile* instance = context;
|
||||
|
||||
if(instance->current_name != NULL) {
|
||||
if(strcmp(instance->current_name, text) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
FuriString* path = furi_string_alloc_printf(
|
||||
"%s/%s%s", instance->app_path_folder, text, instance->app_extension);
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
if(storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK) {
|
||||
ret = false;
|
||||
furi_string_printf(error, "This name\nexists!\nChoose\nanother one.");
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
furi_string_free(path);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ValidatorIsFile* validator_is_file_alloc_init(
|
||||
const char* app_path_folder,
|
||||
const char* app_extension,
|
||||
const char* current_name) {
|
||||
ValidatorIsFile* instance = malloc(sizeof(ValidatorIsFile));
|
||||
|
||||
instance->app_path_folder = strdup(app_path_folder);
|
||||
instance->app_extension = app_extension;
|
||||
if(current_name != NULL) {
|
||||
instance->current_name = strdup(current_name);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void validator_is_file_free(ValidatorIsFile* instance) {
|
||||
furi_assert(instance);
|
||||
free(instance->app_path_folder);
|
||||
free(instance->current_name);
|
||||
free(instance);
|
||||
}
|
||||
21
applications/external/wifi_marauder_companion/wifi_marauder_validators.h
vendored
Normal file
21
applications/external/wifi_marauder_companion/wifi_marauder_validators.h
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/common_defines.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef struct ValidatorIsFile ValidatorIsFile;
|
||||
|
||||
ValidatorIsFile* validator_is_file_alloc_init(
|
||||
const char* app_path_folder,
|
||||
const char* app_extension,
|
||||
const char* current_name);
|
||||
|
||||
void validator_is_file_free(ValidatorIsFile* instance);
|
||||
|
||||
bool validator_is_file_callback(const char* text, FuriString* error, void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "fap_loader_app.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal_debug.h>
|
||||
|
||||
#include <assets_icons.h>
|
||||
#include <gui/gui.h>
|
||||
@@ -24,8 +25,6 @@ struct FapLoader {
|
||||
Loading* loading;
|
||||
};
|
||||
|
||||
volatile bool fap_loader_debug_active = false;
|
||||
|
||||
bool fap_loader_load_name_and_icon(
|
||||
FuriString* path,
|
||||
Storage* storage,
|
||||
@@ -154,7 +153,7 @@ static bool fap_loader_run_selected_app(FapLoader* loader, bool ignore_mismatch)
|
||||
FuriThread* thread = flipper_application_spawn(loader->app, NULL);
|
||||
|
||||
/* This flag is set by the debugger - to break on app start */
|
||||
if(fap_loader_debug_active) {
|
||||
if(furi_hal_debug_is_gdb_session_active()) {
|
||||
FURI_LOG_W(TAG, "Triggering BP for debugger");
|
||||
/* After hitting this, you can set breakpoints in your .fap's code
|
||||
* Note that you have to toggle breakpoints that were set before */
|
||||
|
||||
@@ -35,12 +35,6 @@ typedef enum {
|
||||
SubGhzSpeakerStateEnable,
|
||||
} SubGhzSpeakerState;
|
||||
|
||||
/** SubGhzStarLineIgnore state */
|
||||
typedef enum {
|
||||
SubGhzStarLineIgnoreDisable,
|
||||
SubGhzStarLineIgnoreEnable,
|
||||
} SubGhzStarLineIgnoreState;
|
||||
|
||||
/** SubGhzRxKeyState state */
|
||||
typedef enum {
|
||||
SubGhzRxKeyStateIDLE,
|
||||
|
||||
@@ -19,12 +19,9 @@ ADD_SCENE(subghz, test_static, TestStatic)
|
||||
ADD_SCENE(subghz, test_packet, TestPacket)
|
||||
#endif
|
||||
ADD_SCENE(subghz, set_type, SetType)
|
||||
ADD_SCENE(subghz, set_fix_faac, SetFixFaac)
|
||||
ADD_SCENE(subghz, set_cnt_faac, SetCntFaac)
|
||||
ADD_SCENE(subghz, set_seed_faac, SetSeedFaac)
|
||||
ADD_SCENE(subghz, set_fix_bft, SetFixBft)
|
||||
ADD_SCENE(subghz, set_cnt_bft, SetCntBft)
|
||||
ADD_SCENE(subghz, set_seed_bft, SetSeedBft)
|
||||
ADD_SCENE(subghz, set_fix, SetFix)
|
||||
ADD_SCENE(subghz, set_cnt, SetCnt)
|
||||
ADD_SCENE(subghz, set_seed, SetSeed)
|
||||
ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer)
|
||||
ADD_SCENE(subghz, ext_module_settings, ExtModuleSettings)
|
||||
ADD_SCENE(subghz, read_raw, ReadRAW)
|
||||
|
||||
@@ -62,26 +62,31 @@ static void subghz_scene_add_to_history_callback(
|
||||
void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
FuriString* str_buff;
|
||||
str_buff = furi_string_alloc();
|
||||
FuriString* item_name;
|
||||
FuriString* item_time;
|
||||
uint16_t idx = subghz_history_get_item(subghz->txrx->history);
|
||||
item_name = furi_string_alloc();
|
||||
item_time = furi_string_alloc();
|
||||
|
||||
if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) {
|
||||
furi_string_reset(str_buff);
|
||||
furi_string_reset(item_name);
|
||||
furi_string_reset(item_time);
|
||||
|
||||
subghz->state_notifications = SubGhzNotificationStateRxDone;
|
||||
|
||||
subghz_history_get_text_item_menu(
|
||||
subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
|
||||
subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx);
|
||||
subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx);
|
||||
subghz_view_receiver_add_item_to_menu(
|
||||
subghz->subghz_receiver,
|
||||
furi_string_get_cstr(str_buff),
|
||||
subghz_history_get_type_protocol(
|
||||
subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
|
||||
furi_string_get_cstr(item_name),
|
||||
furi_string_get_cstr(item_time),
|
||||
subghz_history_get_type_protocol(subghz->txrx->history, idx));
|
||||
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
}
|
||||
subghz_receiver_reset(receiver);
|
||||
furi_string_free(str_buff);
|
||||
furi_string_free(item_name);
|
||||
furi_string_free(item_time);
|
||||
}
|
||||
|
||||
bool subghz_scene_decode_raw_start(SubGhz* subghz) {
|
||||
@@ -159,8 +164,10 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) {
|
||||
void subghz_scene_decode_raw_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
FuriString* str_buff;
|
||||
str_buff = furi_string_alloc();
|
||||
FuriString* item_name;
|
||||
FuriString* item_time;
|
||||
item_name = furi_string_alloc();
|
||||
item_time = furi_string_alloc();
|
||||
|
||||
subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock);
|
||||
subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile);
|
||||
@@ -183,14 +190,18 @@ void subghz_scene_decode_raw_on_enter(void* context) {
|
||||
//Load history to receiver
|
||||
subghz_view_receiver_exit(subghz->subghz_receiver);
|
||||
for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
|
||||
furi_string_reset(str_buff);
|
||||
subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
|
||||
furi_string_reset(item_name);
|
||||
furi_string_reset(item_time);
|
||||
subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i);
|
||||
subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i);
|
||||
subghz_view_receiver_add_item_to_menu(
|
||||
subghz->subghz_receiver,
|
||||
furi_string_get_cstr(str_buff),
|
||||
furi_string_get_cstr(item_name),
|
||||
furi_string_get_cstr(item_time),
|
||||
subghz_history_get_type_protocol(subghz->txrx->history, i));
|
||||
}
|
||||
furi_string_free(str_buff);
|
||||
furi_string_free(item_name);
|
||||
furi_string_free(item_time);
|
||||
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "../helpers/subghz_custom_event.h"
|
||||
|
||||
uint8_t value_index_exm;
|
||||
uint8_t value_index_dpin;
|
||||
uint8_t value_index_cnt;
|
||||
uint8_t value_index_pwr;
|
||||
static uint8_t value_index_exm;
|
||||
static uint8_t value_index_dpin;
|
||||
static uint8_t value_index_cnt;
|
||||
static uint8_t value_index_pwr;
|
||||
static uint8_t value_index_time;
|
||||
|
||||
#define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const))
|
||||
const char* const radio_modules_variables_text[] = {
|
||||
@@ -18,6 +19,12 @@ const char* const ext_mod_power_text[EXT_MOD_POWER_COUNT] = {
|
||||
"OFF",
|
||||
};
|
||||
|
||||
#define TIMESTAMP_NAMES_COUNT 2
|
||||
const char* const timestamp_names_text[TIMESTAMP_NAMES_COUNT] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
|
||||
#define DEBUG_P_COUNT 2
|
||||
const char* const debug_pin_text[DEBUG_P_COUNT] = {
|
||||
"OFF",
|
||||
@@ -104,6 +111,17 @@ static void subghz_scene_receiver_config_set_ext_mod_power(VariableItem* item) {
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_timestamp_file_names(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, timestamp_names_text[index]);
|
||||
|
||||
furi_hal_subghz_set_timestamp_file_names((index == 1));
|
||||
subghz->last_settings->timestamp_file_names = (index == 1);
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
}
|
||||
|
||||
void subghz_scene_ext_module_settings_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
@@ -129,6 +147,16 @@ void subghz_scene_ext_module_settings_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, value_index_pwr);
|
||||
variable_item_set_current_value_text(item, ext_mod_power_text[value_index_pwr]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Time in names",
|
||||
TIMESTAMP_NAMES_COUNT,
|
||||
subghz_scene_receiver_config_set_timestamp_file_names,
|
||||
subghz);
|
||||
value_index_time = furi_hal_subghz_get_timestamp_file_names();
|
||||
variable_item_set_current_value_index(item, value_index_time);
|
||||
variable_item_set_current_value_text(item, timestamp_names_text[value_index_time]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Debug Pin",
|
||||
|
||||
@@ -239,7 +239,11 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
subghz_read_raw_set_status(
|
||||
subghz->subghz_read_raw,
|
||||
SubGhzReadRAWStatusIDLE,
|
||||
"",
|
||||
subghz->txrx->raw_threshold_rssi);
|
||||
} else {
|
||||
if(scene_manager_has_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSaved) ||
|
||||
|
||||
@@ -91,34 +91,41 @@ static void subghz_scene_add_to_history_callback(
|
||||
void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
FuriString* str_buff;
|
||||
str_buff = furi_string_alloc();
|
||||
FuriString* item_name;
|
||||
FuriString* item_time;
|
||||
uint16_t idx = subghz_history_get_item(subghz->txrx->history);
|
||||
item_name = furi_string_alloc();
|
||||
item_time = furi_string_alloc();
|
||||
|
||||
if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) {
|
||||
furi_string_reset(str_buff);
|
||||
furi_string_reset(item_name);
|
||||
furi_string_reset(item_time);
|
||||
|
||||
subghz->state_notifications = SubGhzNotificationStateRxDone;
|
||||
|
||||
subghz_history_get_text_item_menu(
|
||||
subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
|
||||
subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx);
|
||||
subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx);
|
||||
subghz_view_receiver_add_item_to_menu(
|
||||
subghz->subghz_receiver,
|
||||
furi_string_get_cstr(str_buff),
|
||||
subghz_history_get_type_protocol(
|
||||
subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
|
||||
furi_string_get_cstr(item_name),
|
||||
furi_string_get_cstr(item_time),
|
||||
subghz_history_get_type_protocol(subghz->txrx->history, idx));
|
||||
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
}
|
||||
subghz_receiver_reset(receiver);
|
||||
furi_string_free(str_buff);
|
||||
furi_string_free(item_name);
|
||||
furi_string_free(item_time);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
||||
}
|
||||
|
||||
void subghz_scene_receiver_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
FuriString* str_buff;
|
||||
str_buff = furi_string_alloc();
|
||||
FuriString* item_name;
|
||||
FuriString* item_time;
|
||||
item_name = furi_string_alloc();
|
||||
item_time = furi_string_alloc();
|
||||
|
||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
|
||||
subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0);
|
||||
@@ -132,22 +139,28 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
//Load history to receiver
|
||||
subghz_view_receiver_exit(subghz->subghz_receiver);
|
||||
for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
|
||||
furi_string_reset(str_buff);
|
||||
subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
|
||||
furi_string_reset(item_name);
|
||||
furi_string_reset(item_time);
|
||||
subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i);
|
||||
subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i);
|
||||
subghz_view_receiver_add_item_to_menu(
|
||||
subghz->subghz_receiver,
|
||||
furi_string_get_cstr(str_buff),
|
||||
furi_string_get_cstr(item_name),
|
||||
furi_string_get_cstr(item_time),
|
||||
subghz_history_get_type_protocol(subghz->txrx->history, i));
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
||||
}
|
||||
furi_string_free(str_buff);
|
||||
furi_string_free(item_name);
|
||||
furi_string_free(item_time);
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
subghz_view_receiver_set_callback(
|
||||
subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
|
||||
subghz_receiver_set_rx_callback(
|
||||
subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz);
|
||||
|
||||
if(subghz->txrx->starline_state == SubGhzStarLineIgnoreEnable) {
|
||||
// TODO: Replace with proper solution based on protocol flags, remove kostily and velosipedy from here
|
||||
// Needs to be done after subghz refactoring merge!!!
|
||||
if(subghz->txrx->ignore_starline == true) {
|
||||
SubGhzProtocolDecoderBase* protocoldecoderbase = NULL;
|
||||
protocoldecoderbase =
|
||||
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Star Line");
|
||||
@@ -156,6 +169,31 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
protocoldecoderbase, NULL, subghz->txrx->receiver);
|
||||
}
|
||||
}
|
||||
if(subghz->txrx->ignore_auto_alarms == true) {
|
||||
SubGhzProtocolDecoderBase* protocoldecoderbase = NULL;
|
||||
protocoldecoderbase =
|
||||
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "KIA Seed");
|
||||
if(protocoldecoderbase) {
|
||||
subghz_protocol_decoder_base_set_decoder_callback(
|
||||
protocoldecoderbase, NULL, subghz->txrx->receiver);
|
||||
}
|
||||
protocoldecoderbase = NULL;
|
||||
protocoldecoderbase =
|
||||
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Scher-Khan");
|
||||
if(protocoldecoderbase) {
|
||||
subghz_protocol_decoder_base_set_decoder_callback(
|
||||
protocoldecoderbase, NULL, subghz->txrx->receiver);
|
||||
}
|
||||
}
|
||||
if(subghz->txrx->ignore_magellan == true) {
|
||||
SubGhzProtocolDecoderBase* protocoldecoderbase = NULL;
|
||||
protocoldecoderbase =
|
||||
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Magellan");
|
||||
if(protocoldecoderbase) {
|
||||
subghz_protocol_decoder_base_set_decoder_callback(
|
||||
protocoldecoderbase, NULL, subghz->txrx->receiver);
|
||||
}
|
||||
}
|
||||
|
||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
||||
|
||||
@@ -7,6 +7,8 @@ enum SubGhzSettingIndex {
|
||||
SubGhzSettingIndexModulation,
|
||||
SubGhzSettingIndexBinRAW,
|
||||
SubGhzSettingIndexIgnoreStarline,
|
||||
SubGhzSettingIndexIgnoreCars,
|
||||
SubGhzSettingIndexIgnoreMagellan,
|
||||
SubGhzSettingIndexSound,
|
||||
SubGhzSettingIndexLock,
|
||||
SubGhzSettingIndexRAWThresholdRSSI,
|
||||
@@ -69,14 +71,22 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = {
|
||||
SubGhzProtocolFlag_Decodable,
|
||||
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW,
|
||||
};
|
||||
#define STAR_LINE_COUNT 2
|
||||
const char* const star_line_text[STAR_LINE_COUNT] = {
|
||||
#define STARLINE_COUNT 2
|
||||
const char* const starline_text[STARLINE_COUNT] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
const uint32_t star_line_value[STAR_LINE_COUNT] = {
|
||||
SubGhzStarLineIgnoreDisable,
|
||||
SubGhzStarLineIgnoreEnable,
|
||||
|
||||
#define AUTO_ALARMS_COUNT 2
|
||||
const char* const auto_alarms_text[AUTO_ALARMS_COUNT] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
|
||||
#define MAGELLAN_COUNT 2
|
||||
const char* const magellan_text[MAGELLAN_COUNT] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
|
||||
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
|
||||
@@ -231,8 +241,24 @@ static void subghz_scene_receiver_config_set_starline(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, star_line_text[index]);
|
||||
subghz->txrx->starline_state = star_line_value[index];
|
||||
variable_item_set_current_value_text(item, starline_text[index]);
|
||||
subghz->txrx->ignore_starline = (index == 1);
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_auto_alarms(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, auto_alarms_text[index]);
|
||||
subghz->txrx->ignore_auto_alarms = (index == 1);
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_magellan(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, magellan_text[index]);
|
||||
subghz->txrx->ignore_magellan = (index == 1);
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
|
||||
@@ -313,15 +339,36 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
SubGhzCustomEventManagerSet) {
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Ignore StarLine:",
|
||||
STAR_LINE_COUNT,
|
||||
"Ignore Starline:",
|
||||
STARLINE_COUNT,
|
||||
subghz_scene_receiver_config_set_starline,
|
||||
subghz);
|
||||
|
||||
value_index =
|
||||
value_index_uint32(subghz->txrx->starline_state, star_line_value, STAR_LINE_COUNT);
|
||||
value_index = subghz->txrx->ignore_starline;
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, star_line_text[value_index]);
|
||||
variable_item_set_current_value_text(item, starline_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Ignore Cars:",
|
||||
AUTO_ALARMS_COUNT,
|
||||
subghz_scene_receiver_config_set_auto_alarms,
|
||||
subghz);
|
||||
|
||||
value_index = subghz->txrx->ignore_auto_alarms;
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, auto_alarms_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Ignore Magellan:",
|
||||
MAGELLAN_COUNT,
|
||||
subghz_scene_receiver_config_set_magellan,
|
||||
subghz);
|
||||
|
||||
value_index = subghz->txrx->ignore_magellan;
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, magellan_text[value_index]);
|
||||
}
|
||||
|
||||
// Enable speaker, will send all incoming noises and signals to speaker so you can listen how your remote sounds like :)
|
||||
|
||||
@@ -115,6 +115,9 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) {
|
||||
void subghz_scene_receiver_info_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
keeloq_reset_original_btn();
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
subghz_scene_receiver_info_draw_widget(subghz);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,18 +14,34 @@ void subghz_scene_save_name_text_input_callback(void* context) {
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveName);
|
||||
}
|
||||
|
||||
void subghz_scene_save_name_get_timefilename(FuriString* name) {
|
||||
void subghz_scene_save_name_get_timefilename(
|
||||
FuriString* name,
|
||||
const char* proto_name,
|
||||
bool fulldate) {
|
||||
FuriHalRtcDateTime datetime = {0};
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
furi_string_printf(
|
||||
name,
|
||||
"RAW_%.4d%.2d%.2d-%.2d%.2d%.2d",
|
||||
datetime.year,
|
||||
datetime.month,
|
||||
datetime.day,
|
||||
datetime.hour,
|
||||
datetime.minute,
|
||||
datetime.second);
|
||||
if(fulldate) {
|
||||
furi_string_printf(
|
||||
name,
|
||||
"%s_%.4d%.2d%.2d-%.2d%.2d%.2d",
|
||||
proto_name,
|
||||
datetime.year,
|
||||
datetime.month,
|
||||
datetime.day,
|
||||
datetime.hour,
|
||||
datetime.minute,
|
||||
datetime.second);
|
||||
} else {
|
||||
furi_string_printf(
|
||||
name,
|
||||
"%s_%.2d%.2d-%.2d%.2d%.2d",
|
||||
proto_name,
|
||||
datetime.month,
|
||||
datetime.day,
|
||||
datetime.hour,
|
||||
datetime.minute,
|
||||
datetime.second);
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_scene_save_name_on_enter(void* context) {
|
||||
@@ -42,8 +58,31 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
|
||||
if(!subghz_path_is_file(subghz->file_path)) {
|
||||
char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0};
|
||||
set_random_name(file_name_buf, SUBGHZ_MAX_LEN_NAME);
|
||||
furi_string_set(file_name, file_name_buf);
|
||||
if(furi_hal_subghz_get_timestamp_file_names()) {
|
||||
if(subghz->txrx->decoder_result != 0x0) {
|
||||
if(subghz->txrx->decoder_result != NULL) {
|
||||
if(strlen(subghz->txrx->decoder_result->protocol->name) != 0) {
|
||||
if(scene_manager_has_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSetType)) {
|
||||
subghz_scene_save_name_get_timefilename(file_name, "S", true);
|
||||
} else {
|
||||
subghz_scene_save_name_get_timefilename(
|
||||
file_name, subghz->txrx->decoder_result->protocol->name, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
subghz_scene_save_name_get_timefilename(file_name, "S", true);
|
||||
}
|
||||
} else {
|
||||
subghz_scene_save_name_get_timefilename(file_name, "S", true);
|
||||
}
|
||||
} else {
|
||||
subghz_scene_save_name_get_timefilename(file_name, "S", true);
|
||||
}
|
||||
} else {
|
||||
set_random_name(file_name_buf, SUBGHZ_MAX_LEN_NAME);
|
||||
furi_string_set(file_name, file_name_buf);
|
||||
}
|
||||
furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
|
||||
//highlighting the entire filename by default
|
||||
dev_name_empty = true;
|
||||
@@ -57,7 +96,7 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) ==
|
||||
SubGhzCustomEventManagerSetRAW) {
|
||||
dev_name_empty = true;
|
||||
subghz_scene_save_name_get_timefilename(file_name);
|
||||
subghz_scene_save_name_get_timefilename(file_name, "RAW", true);
|
||||
}
|
||||
}
|
||||
furi_string_set(subghz->file_path, dir_name);
|
||||
|
||||
66
applications/main/subghz/scenes/subghz_scene_set_cnt.c
Normal file
66
applications/main/subghz/scenes/subghz_scene_set_cnt.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define TAG "SubGhzSetCnt"
|
||||
|
||||
void subghz_scene_set_cnt_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_cnt_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
SubGhzCustomEvent state =
|
||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType);
|
||||
|
||||
switch(state) {
|
||||
case SubmenuIndexBFTClone:
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_cnt_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->cnt,
|
||||
2);
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_433:
|
||||
case SubmenuIndexFaacSLH_868:
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in hex, 20bits");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_cnt_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->cnt,
|
||||
3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_cnt_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_cnt_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define TAG "SubGhzSetCntBft"
|
||||
|
||||
void subghz_scene_set_cnt_bft_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_cnt_bft_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_cnt_bft_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->cnt,
|
||||
2);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_cnt_bft_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeedBft);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_cnt_bft_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define TAG "SubGhzSetCntFaac"
|
||||
|
||||
void subghz_scene_set_cnt_faac_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_cnt_faac_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in hex, 20bits");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_cnt_faac_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->cnt,
|
||||
3);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_cnt_faac_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeedFaac);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_cnt_faac_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define TAG "SubGhzSetFixBft"
|
||||
#define TAG "SubGhzSetFix"
|
||||
|
||||
void subghz_scene_set_fix_bft_byte_input_callback(void* context) {
|
||||
void subghz_scene_set_fix_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_fix_bft_on_enter(void* context) {
|
||||
void subghz_scene_set_fix_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
@@ -16,7 +16,7 @@ void subghz_scene_set_fix_bft_on_enter(void* context) {
|
||||
byte_input_set_header_text(byte_input, "Enter FIX in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_fix_bft_byte_input_callback,
|
||||
subghz_scene_set_fix_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->fix,
|
||||
@@ -24,20 +24,20 @@ void subghz_scene_set_fix_bft_on_enter(void* context) {
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_fix_bft_on_event(void* context, SceneManagerEvent event) {
|
||||
bool subghz_scene_set_fix_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCntBft);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCnt);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_fix_bft_on_exit(void* context) {
|
||||
void subghz_scene_set_fix_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
@@ -1,46 +0,0 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define TAG "SubGhzSetFixFaac"
|
||||
|
||||
void subghz_scene_set_fix_faac_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_fix_faac_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter FIX in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_fix_faac_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->fix,
|
||||
4);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_fix_faac_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCntFaac);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_fix_faac_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
}
|
||||
168
applications/main/subghz/scenes/subghz_scene_set_seed.c
Normal file
168
applications/main/subghz/scenes/subghz_scene_set_seed.c
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "../subghz_i.h"
|
||||
#include <lib/subghz/protocols/faac_slh.h>
|
||||
#include <lib/subghz/protocols/keeloq.h>
|
||||
|
||||
#define TAG "SubGhzSetSeed"
|
||||
|
||||
void subghz_scene_set_seed_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_seed_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter SEED in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_seed_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->seed,
|
||||
4);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
bool generated_protocol = false;
|
||||
uint32_t fix_part, cnt, seed;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
SubGhzCustomEvent state =
|
||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType);
|
||||
|
||||
switch(state) {
|
||||
case SubmenuIndexBFTClone:
|
||||
fix_part = subghz->txrx->secure_data->fix[0] << 24 |
|
||||
subghz->txrx->secure_data->fix[1] << 16 |
|
||||
subghz->txrx->secure_data->fix[2] << 8 |
|
||||
subghz->txrx->secure_data->fix[3];
|
||||
|
||||
cnt = subghz->txrx->secure_data->cnt[0] << 8 | subghz->txrx->secure_data->cnt[1];
|
||||
|
||||
seed = subghz->txrx->secure_data->seed[0] << 24 |
|
||||
subghz->txrx->secure_data->seed[1] << 16 |
|
||||
subghz->txrx->secure_data->seed[2] << 8 |
|
||||
subghz->txrx->secure_data->seed[3];
|
||||
|
||||
subghz->txrx->transmitter =
|
||||
subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq");
|
||||
if(subghz->txrx->transmitter) {
|
||||
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
|
||||
subghz_protocol_keeloq_bft_create_data(
|
||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||
subghz->txrx->fff_data,
|
||||
fix_part & 0x0FFFFFFF,
|
||||
fix_part >> 28,
|
||||
cnt,
|
||||
seed,
|
||||
"BFT",
|
||||
subghz->txrx->preset);
|
||||
|
||||
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
||||
}
|
||||
|
||||
flipper_format_write_hex(
|
||||
subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
||||
|
||||
flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT");
|
||||
|
||||
generated_protocol = true;
|
||||
}
|
||||
|
||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
||||
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_433:
|
||||
case SubmenuIndexFaacSLH_868:
|
||||
fix_part = subghz->txrx->secure_data->fix[0] << 24 |
|
||||
subghz->txrx->secure_data->fix[1] << 16 |
|
||||
subghz->txrx->secure_data->fix[2] << 8 |
|
||||
subghz->txrx->secure_data->fix[3];
|
||||
|
||||
cnt = subghz->txrx->secure_data->cnt[0] << 16 |
|
||||
subghz->txrx->secure_data->cnt[1] << 8 | subghz->txrx->secure_data->cnt[2];
|
||||
|
||||
seed = subghz->txrx->secure_data->seed[0] << 24 |
|
||||
subghz->txrx->secure_data->seed[1] << 16 |
|
||||
subghz->txrx->secure_data->seed[2] << 8 |
|
||||
subghz->txrx->secure_data->seed[3];
|
||||
|
||||
subghz->txrx->transmitter =
|
||||
subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH");
|
||||
if(subghz->txrx->transmitter) {
|
||||
SubGhzCustomEvent state =
|
||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType);
|
||||
|
||||
if(state == SubmenuIndexFaacSLH_433) {
|
||||
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
|
||||
} else if(state == SubmenuIndexFaacSLH_868) {
|
||||
subghz_preset_init(subghz, "AM650", 868350000, NULL, 0);
|
||||
}
|
||||
subghz_protocol_faac_slh_create_data(
|
||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||
subghz->txrx->fff_data,
|
||||
fix_part >> 4,
|
||||
fix_part & 0xf,
|
||||
(cnt & 0xFFFFF),
|
||||
seed,
|
||||
"FAAC_SLH",
|
||||
subghz->txrx->preset);
|
||||
// RogueMaster dont steal!
|
||||
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
||||
}
|
||||
|
||||
flipper_format_write_hex(
|
||||
subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
||||
|
||||
generated_protocol = true;
|
||||
}
|
||||
|
||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
||||
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(generated_protocol) {
|
||||
subghz_file_name_clear(subghz);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_seed_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#include "../subghz_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <lib/subghz/protocols/keeloq.h>
|
||||
|
||||
#define TAG "SubGhzSetSeedBft"
|
||||
|
||||
void subghz_scene_set_seed_bft_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_seed_bft_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
// RogueMaster don't steal!!!
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter SEED in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_seed_bft_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->seed,
|
||||
4);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_seed_bft_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
bool generated_protocol = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
uint32_t fix_part =
|
||||
subghz->txrx->secure_data->fix[0] << 24 | subghz->txrx->secure_data->fix[1] << 16 |
|
||||
subghz->txrx->secure_data->fix[2] << 8 | subghz->txrx->secure_data->fix[3];
|
||||
|
||||
uint16_t cnt = subghz->txrx->secure_data->cnt[0] << 8 |
|
||||
subghz->txrx->secure_data->cnt[1];
|
||||
|
||||
uint32_t seed = subghz->txrx->secure_data->seed[0] << 24 |
|
||||
subghz->txrx->secure_data->seed[1] << 16 |
|
||||
subghz->txrx->secure_data->seed[2] << 8 |
|
||||
subghz->txrx->secure_data->seed[3];
|
||||
|
||||
subghz->txrx->transmitter =
|
||||
subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq");
|
||||
if(subghz->txrx->transmitter) {
|
||||
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
|
||||
subghz_protocol_keeloq_bft_create_data(
|
||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||
subghz->txrx->fff_data,
|
||||
fix_part & 0x0FFFFFFF,
|
||||
fix_part >> 28,
|
||||
cnt,
|
||||
seed,
|
||||
"BFT",
|
||||
subghz->txrx->preset);
|
||||
|
||||
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
||||
}
|
||||
|
||||
flipper_format_write_hex(
|
||||
subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
||||
|
||||
flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT");
|
||||
|
||||
generated_protocol = true;
|
||||
} else {
|
||||
generated_protocol = false;
|
||||
}
|
||||
|
||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
||||
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
if(generated_protocol) {
|
||||
subghz_file_name_clear(subghz);
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzAddManually);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_seed_bft_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
#include "../subghz_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <lib/subghz/protocols/faac_slh.h>
|
||||
|
||||
#define TAG "SubGhzSetSeedFaac"
|
||||
|
||||
void subghz_scene_set_seed_faac_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void subghz_scene_set_seed_faac_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter SEED in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_seed_faac_byte_input_callback,
|
||||
NULL,
|
||||
subghz,
|
||||
subghz->txrx->secure_data->seed,
|
||||
4);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_set_seed_faac_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
bool generated_protocol = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventByteInputDone) {
|
||||
uint32_t fix_part =
|
||||
subghz->txrx->secure_data->fix[0] << 24 | subghz->txrx->secure_data->fix[1] << 16 |
|
||||
subghz->txrx->secure_data->fix[2] << 8 | subghz->txrx->secure_data->fix[3];
|
||||
|
||||
uint32_t cnt = subghz->txrx->secure_data->cnt[0] << 16 |
|
||||
subghz->txrx->secure_data->cnt[1] << 8 |
|
||||
subghz->txrx->secure_data->cnt[2];
|
||||
|
||||
uint32_t seed = subghz->txrx->secure_data->seed[0] << 24 |
|
||||
subghz->txrx->secure_data->seed[1] << 16 |
|
||||
subghz->txrx->secure_data->seed[2] << 8 |
|
||||
subghz->txrx->secure_data->seed[3];
|
||||
|
||||
subghz->txrx->transmitter =
|
||||
subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH");
|
||||
if(subghz->txrx->transmitter) {
|
||||
SubGhzCustomEvent state =
|
||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType);
|
||||
|
||||
if(state == SubmenuIndexFaacSLH_433) {
|
||||
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
|
||||
} else if(state == SubmenuIndexFaacSLH_868) {
|
||||
subghz_preset_init(subghz, "AM650", 868350000, NULL, 0);
|
||||
}
|
||||
subghz_protocol_faac_slh_create_data(
|
||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||
subghz->txrx->fff_data,
|
||||
fix_part >> 4,
|
||||
fix_part & 0xf,
|
||||
(cnt & 0xFFFFF),
|
||||
seed,
|
||||
"FAAC_SLH",
|
||||
subghz->txrx->preset);
|
||||
// RogueMaster dont steal!
|
||||
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
||||
}
|
||||
|
||||
flipper_format_write_hex(
|
||||
subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
||||
|
||||
generated_protocol = true;
|
||||
} else {
|
||||
generated_protocol = false;
|
||||
}
|
||||
|
||||
subghz_transmitter_free(subghz->txrx->transmitter);
|
||||
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
if(generated_protocol) {
|
||||
subghz_file_name_clear(subghz);
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzAddManually);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_set_seed_faac_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
}
|
||||
@@ -389,13 +389,13 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
uint32_t key = subghz_random_serial();
|
||||
switch(event.event) {
|
||||
case SubmenuIndexFaacSLH_868:
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix);
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_433:
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix);
|
||||
break;
|
||||
case SubmenuIndexBFTClone:
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix);
|
||||
break;
|
||||
case SubmenuIndexPricenton:
|
||||
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||
|
||||
@@ -52,6 +52,10 @@ bool subghz_scene_transmitter_update_data_show(void* context) {
|
||||
|
||||
void subghz_scene_transmitter_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
keeloq_reset_original_btn();
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
if(!subghz_scene_transmitter_update_data_show(subghz)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError);
|
||||
@@ -74,9 +78,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
} else {
|
||||
if(subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||
subghz_scene_transmitter_update_data_show(subghz);
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef struct {
|
||||
FlipperFormat* flipper_string;
|
||||
uint8_t type;
|
||||
SubGhzRadioPreset* preset;
|
||||
FuriHalRtcDateTime datetime;
|
||||
} SubGhzHistoryItem;
|
||||
|
||||
ARRAY_DEF(SubGhzHistoryItemArray, SubGhzHistoryItem, M_POD_OPLIST)
|
||||
@@ -164,6 +165,12 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* outp
|
||||
furi_string_set(output, item->item_str);
|
||||
}
|
||||
|
||||
void subghz_history_get_time_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx) {
|
||||
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
|
||||
FuriHalRtcDateTime* t = &item->datetime;
|
||||
furi_string_printf(output, "%.2d:%.2d:%.2d ", t->hour, t->minute, t->second);
|
||||
}
|
||||
|
||||
bool subghz_history_add_to_history(
|
||||
SubGhzHistory* instance,
|
||||
void* context,
|
||||
@@ -195,6 +202,7 @@ bool subghz_history_add_to_history(
|
||||
furi_string_set(item->preset->name, preset->name);
|
||||
item->preset->data = preset->data;
|
||||
item->preset->data_size = preset->data_size;
|
||||
furi_hal_rtc_get_datetime(&item->datetime);
|
||||
|
||||
item->item_str = furi_string_alloc();
|
||||
item->flipper_string = flipper_format_string_alloc();
|
||||
|
||||
@@ -78,6 +78,14 @@ const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t i
|
||||
*/
|
||||
void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx);
|
||||
|
||||
/** Get time item menu to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param output - FuriString* output
|
||||
* @param idx - record index
|
||||
*/
|
||||
void subghz_history_get_time_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx);
|
||||
|
||||
/** Get string the remaining number of records to history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "subghz_history.h"
|
||||
#include <toolbox/stream/stream.h>
|
||||
|
||||
/**
|
||||
* @brief Generate filename like 000.tmp
|
||||
*
|
||||
* @param index - index of file, timestamp doesn't accepted!
|
||||
*/
|
||||
FuriString* subghz_history_generate_temp_filename(uint32_t index);
|
||||
|
||||
/**
|
||||
* @brief Check if directory for temporary files is exists
|
||||
*
|
||||
* @param instance SubGhzHistory*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool subghz_history_is_tmp_dir_exists(SubGhzHistory* instance);
|
||||
|
||||
/**
|
||||
* @brief Check SD card and create temporary dir if not exists,
|
||||
* Result write_tmp_files without this unstable work is GUARANTEED
|
||||
*
|
||||
* @param instance - SubGhzHistory*
|
||||
* @return - true all ok
|
||||
* @return - false we have a problems
|
||||
*/
|
||||
bool subghz_history_check_sdcard(SubGhzHistory* instance);
|
||||
|
||||
/**
|
||||
* @brief Recursive delete dir and files and create new temp dir
|
||||
*
|
||||
* @param instance - SubGhzHistory*
|
||||
* @return true - if all ok
|
||||
* @return false - if something failed
|
||||
*/
|
||||
void subghz_history_clear_tmp_dir(SubGhzHistory* instance);
|
||||
|
||||
/**
|
||||
* @brief Free item and free all resources
|
||||
*
|
||||
* @param current_item - SubGhzHistoryItem*
|
||||
*/
|
||||
void subghz_history_item_free(void* current_item);
|
||||
|
||||
/**
|
||||
* @brief free all items in array
|
||||
*
|
||||
* @param instance
|
||||
*/
|
||||
void subghz_history_clean_item_array(SubGhzHistory* instance);
|
||||
|
||||
/**
|
||||
* @brief Write temp file fully, without splitting
|
||||
*
|
||||
* @param instance - SubGhzHistory*
|
||||
* @param current_item - SubGhzHistoryItem*
|
||||
* @param dir_path - full path to file
|
||||
*/
|
||||
void subghz_history_tmp_write_file_full(
|
||||
SubGhzHistory* instance,
|
||||
void* current_item,
|
||||
FuriString* dir_path);
|
||||
|
||||
/**
|
||||
* @brief Write temp spited to lines
|
||||
*
|
||||
* @param instance - SubGhzHistory*
|
||||
* @param current_item - SubGhzHistoryItem*
|
||||
* @param dir_path - full path to file
|
||||
* @return true - file saved
|
||||
* @return false - error occurred
|
||||
*/
|
||||
bool subghz_history_tmp_write_file_split(
|
||||
SubGhzHistory* instance,
|
||||
void* current_item,
|
||||
const char* dir_path);
|
||||
|
||||
/**
|
||||
* @brief generate random value
|
||||
*
|
||||
* @param min - min value
|
||||
* @param max - max value
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t subghz_history_rand_range(uint32_t min, uint32_t max);
|
||||
|
||||
/**
|
||||
* @brief write random noise signals to file applying to max line value
|
||||
*
|
||||
* @param file - Stream*
|
||||
* @param is_negative_start - first value is negative or positive?
|
||||
* @param current_position - 0 if started from beginning
|
||||
* @param empty_line - add RAW_Data to this line
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool subghz_history_write_file_noise(
|
||||
Stream* file,
|
||||
bool is_negative_start,
|
||||
size_t current_position,
|
||||
bool empty_line);
|
||||
|
||||
/**
|
||||
* @brief taken from flipper_format_stream_read_value_line but takes only one int32 value
|
||||
*
|
||||
* @param stream - Stream*
|
||||
* @param _data - int32_t* output data
|
||||
* @param data_size - size of data
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool subghz_history_read_int32(Stream* stream, int32_t* _data, const uint16_t data_size);
|
||||
|
||||
/**
|
||||
* @brief write payload to file spliting by lines
|
||||
*
|
||||
* @param src - Stream* of source
|
||||
* @param file - Stream* of file
|
||||
* @param is_negative_start - first value is negative or positive?
|
||||
* @param current_position - by default is 0 but in this value returned last position of payload
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool subghz_history_write_file_data(
|
||||
Stream* src,
|
||||
Stream* file,
|
||||
bool* is_negative_start,
|
||||
size_t* current_position);
|
||||
|
||||
/**
|
||||
* @brief taken from flipper_format_stream_read_valid_key
|
||||
*
|
||||
* @param stream - Stream*
|
||||
* @param key - FuriString* output value
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool subghz_history_stream_read_valid_key(Stream* stream, FuriString* key);
|
||||
|
||||
/**
|
||||
* @brief taken from flipper_format_stream_seek_to_key
|
||||
*
|
||||
* @param stream - Stream*
|
||||
* @param key - key
|
||||
* @param strict_mode - false
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool subghz_history_stream_seek_to_key(Stream* stream, const char* key, bool strict_mode);
|
||||
|
||||
/**
|
||||
* @brief taken from flipper_format_stream_read_value
|
||||
*
|
||||
* @param stream - Stream*
|
||||
* @param value - FuriString* output value
|
||||
* @param last - return position is last flag
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last);
|
||||
@@ -106,9 +106,11 @@ static bool subghz_tx(SubGhz* subghz, uint32_t frequency) {
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
subghz_speaker_on(subghz);
|
||||
bool ret = furi_hal_subghz_tx();
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
|
||||
if(ret) {
|
||||
subghz_speaker_on(subghz);
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -116,6 +118,7 @@ void subghz_idle(SubGhz* subghz) {
|
||||
furi_assert(subghz);
|
||||
furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
|
||||
furi_hal_subghz_idle();
|
||||
subghz_speaker_off(subghz);
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,9 @@ struct SubGhzTxRx {
|
||||
SubGhzTxRxState txrx_state;
|
||||
SubGhzHopperState hopper_state;
|
||||
SubGhzSpeakerState speaker_state;
|
||||
SubGhzStarLineIgnoreState starline_state;
|
||||
bool ignore_starline;
|
||||
bool ignore_auto_alarms;
|
||||
bool ignore_magellan;
|
||||
uint8_t hopper_timeout;
|
||||
uint8_t hopper_idx_frequency;
|
||||
SubGhzRxKeyState rx_key_state;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER "FATrigger"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_ENABLED "External"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER "ExtPower"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_TIMESTAMP_FILE_NAMES "TimestampNames"
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void) {
|
||||
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
|
||||
@@ -45,6 +46,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
float temp_frequency_analyzer_trigger = 0;
|
||||
bool temp_external_module_enabled = false;
|
||||
bool temp_external_module_power_5v_disable = false;
|
||||
bool temp_timestamp_file_names = false;
|
||||
//int32_t temp_preset = 0;
|
||||
bool frequency_analyzer_feedback_level_was_read = false;
|
||||
bool frequency_analyzer_trigger_was_read = false;
|
||||
@@ -76,6 +78,11 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER,
|
||||
(bool*)&temp_external_module_power_5v_disable,
|
||||
1);
|
||||
flipper_format_read_bool(
|
||||
fff_data_file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_TIMESTAMP_FILE_NAMES,
|
||||
(bool*)&temp_timestamp_file_names,
|
||||
1);
|
||||
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH);
|
||||
@@ -89,6 +96,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL;
|
||||
instance->frequency_analyzer_trigger = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER;
|
||||
instance->external_module_enabled = false;
|
||||
instance->timestamp_file_names = false;
|
||||
|
||||
} else {
|
||||
instance->frequency = temp_frequency;
|
||||
@@ -109,6 +117,11 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
|
||||
instance->external_module_power_5v_disable = temp_external_module_power_5v_disable;
|
||||
|
||||
instance->timestamp_file_names = temp_timestamp_file_names;
|
||||
|
||||
// Set globally
|
||||
furi_hal_subghz_set_timestamp_file_names(instance->timestamp_file_names);
|
||||
|
||||
if(instance->external_module_power_5v_disable) {
|
||||
furi_hal_subghz_set_external_power_disable(true);
|
||||
furi_hal_subghz_disable_ext_power();
|
||||
@@ -189,6 +202,13 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
|
||||
1)) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_insert_or_update_bool(
|
||||
file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_TIMESTAMP_FILE_NAMES,
|
||||
&instance->timestamp_file_names,
|
||||
1)) {
|
||||
break;
|
||||
}
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef struct {
|
||||
float frequency_analyzer_trigger;
|
||||
bool external_module_enabled;
|
||||
bool external_module_power_5v_disable;
|
||||
bool timestamp_file_names;
|
||||
} SubGhzLastSettings;
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void);
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
|
||||
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
|
||||
|
||||
#define SCROLL_INTERVAL (606)
|
||||
#define SCROLL_DELAY (2)
|
||||
|
||||
typedef struct {
|
||||
FuriString* item_str;
|
||||
FuriString* time;
|
||||
uint8_t type;
|
||||
} SubGhzReceiverMenuItem;
|
||||
|
||||
@@ -53,6 +57,7 @@ struct SubGhzViewReceiver {
|
||||
View* view;
|
||||
SubGhzViewReceiverCallback callback;
|
||||
void* context;
|
||||
FuriTimer* scroll_timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -67,6 +72,7 @@ typedef struct {
|
||||
SubGhzViewReceiverBarShow bar_show;
|
||||
SubGhzViewReceiverMode mode;
|
||||
uint8_t u_rssi;
|
||||
size_t scroll_counter;
|
||||
} SubGhzViewReceiverModel;
|
||||
|
||||
void subghz_view_receiver_set_mode(
|
||||
@@ -146,6 +152,7 @@ static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiv
|
||||
void subghz_view_receiver_add_item_to_menu(
|
||||
SubGhzViewReceiver* subghz_receiver,
|
||||
const char* name,
|
||||
const char* time,
|
||||
uint8_t type) {
|
||||
furi_assert(subghz_receiver);
|
||||
with_view_model(
|
||||
@@ -154,6 +161,7 @@ void subghz_view_receiver_add_item_to_menu(
|
||||
{
|
||||
SubGhzReceiverMenuItem* item_menu =
|
||||
SubGhzReceiverMenuItemArray_push_raw(model->history->data);
|
||||
item_menu->time = furi_string_alloc_set(time);
|
||||
item_menu->item_str = furi_string_alloc_set(name);
|
||||
item_menu->type = type;
|
||||
if((model->idx == model->history_item - 1)) {
|
||||
@@ -242,14 +250,30 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
|
||||
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
|
||||
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
|
||||
furi_string_set(str_buff, item_menu->item_str);
|
||||
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 7 : MAX_LEN_PX);
|
||||
size_t scroll_counter = model->scroll_counter;
|
||||
if(model->idx == idx) {
|
||||
subghz_view_receiver_draw_frame(canvas, i, scrollbar);
|
||||
if(scroll_counter < SCROLL_DELAY) {
|
||||
// Show time of signal one moment
|
||||
furi_string_set(str_buff, item_menu->time);
|
||||
scroll_counter = 0;
|
||||
} else {
|
||||
scroll_counter -= SCROLL_DELAY;
|
||||
}
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
scroll_counter = 0;
|
||||
}
|
||||
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
|
||||
canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff));
|
||||
elements_scrollable_text_line(
|
||||
canvas,
|
||||
15,
|
||||
9 + i * FRAME_HEIGHT,
|
||||
(scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX),
|
||||
str_buff,
|
||||
scroll_counter,
|
||||
(model->idx != idx),
|
||||
false);
|
||||
furi_string_reset(str_buff);
|
||||
}
|
||||
if(scrollbar) {
|
||||
@@ -357,6 +381,13 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_view_receiver_scroll_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzViewReceiver* subghz_receiver = context;
|
||||
with_view_model(
|
||||
subghz_receiver->view, SubGhzViewReceiverModel * model, { model->scroll_counter++; }, true);
|
||||
}
|
||||
|
||||
static void subghz_view_receiver_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzViewReceiver* subghz_receiver = context;
|
||||
@@ -416,6 +447,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
||||
SubGhzViewReceiverModel * model,
|
||||
{
|
||||
if(model->idx != 0) model->idx--;
|
||||
model->scroll_counter = 0;
|
||||
},
|
||||
true);
|
||||
} else if(
|
||||
@@ -427,6 +459,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
||||
{
|
||||
if((model->history_item != 0) && (model->idx != model->history_item - 1))
|
||||
model->idx++;
|
||||
model->scroll_counter = 0;
|
||||
},
|
||||
true);
|
||||
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
|
||||
@@ -446,6 +479,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
||||
|
||||
if(it->index == (size_t)(model->idx)) {
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->time);
|
||||
item->type = 0;
|
||||
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
|
||||
}
|
||||
@@ -479,6 +513,13 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
||||
|
||||
void subghz_view_receiver_enter(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzViewReceiver* subghz_receiver = context;
|
||||
with_view_model(
|
||||
subghz_receiver->view,
|
||||
SubGhzViewReceiverModel * model,
|
||||
{ model->scroll_counter = 0; },
|
||||
true);
|
||||
furi_timer_start(subghz_receiver->scroll_timer, SCROLL_INTERVAL);
|
||||
}
|
||||
|
||||
void subghz_view_receiver_exit(void* context) {
|
||||
@@ -495,6 +536,7 @@ void subghz_view_receiver_exit(void* context) {
|
||||
for
|
||||
M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) {
|
||||
furi_string_free(item_menu->item_str);
|
||||
furi_string_free(item_menu->time);
|
||||
item_menu->type = 0;
|
||||
}
|
||||
SubGhzReceiverMenuItemArray_reset(model->history->data);
|
||||
@@ -504,6 +546,7 @@ void subghz_view_receiver_exit(void* context) {
|
||||
},
|
||||
false);
|
||||
furi_timer_stop(subghz_receiver->timer);
|
||||
furi_timer_stop(subghz_receiver->scroll_timer);
|
||||
}
|
||||
|
||||
SubGhzViewReceiver* subghz_view_receiver_alloc() {
|
||||
@@ -522,6 +565,9 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
|
||||
view_set_enter_callback(subghz_receiver->view, subghz_view_receiver_enter);
|
||||
view_set_exit_callback(subghz_receiver->view, subghz_view_receiver_exit);
|
||||
|
||||
subghz_receiver->scroll_timer = furi_timer_alloc(
|
||||
subghz_view_receiver_scroll_timer_callback, FuriTimerTypePeriodic, subghz_receiver);
|
||||
|
||||
with_view_model(
|
||||
subghz_receiver->view,
|
||||
SubGhzViewReceiverModel * model,
|
||||
@@ -543,6 +589,8 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
|
||||
void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) {
|
||||
furi_assert(subghz_receiver);
|
||||
|
||||
furi_timer_free(subghz_receiver->scroll_timer);
|
||||
|
||||
with_view_model(
|
||||
subghz_receiver->view,
|
||||
SubGhzViewReceiverModel * model,
|
||||
@@ -554,6 +602,7 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) {
|
||||
for
|
||||
M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) {
|
||||
furi_string_free(item_menu->item_str);
|
||||
furi_string_free(item_menu->time);
|
||||
item_menu->type = 0;
|
||||
}
|
||||
SubGhzReceiverMenuItemArray_clear(model->history->data);
|
||||
|
||||
@@ -40,6 +40,7 @@ void subghz_view_receiver_add_data_progress(
|
||||
void subghz_view_receiver_add_item_to_menu(
|
||||
SubGhzViewReceiver* subghz_receiver,
|
||||
const char* name,
|
||||
const char* time,
|
||||
uint8_t type);
|
||||
|
||||
uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
@@ -137,6 +137,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
|
||||
true);
|
||||
|
||||
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
|
||||
subghz_custom_btn_set(0);
|
||||
with_view_model(
|
||||
subghz_transmitter->view,
|
||||
SubGhzViewTransmitterModel * model,
|
||||
|
||||
@@ -240,7 +240,7 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
|
||||
furi_event_flag_clear(bt->rpc_event, BT_RPC_EVENT_DISCONNECTED);
|
||||
if(bt->profile == BtProfileSerial) {
|
||||
// Open RPC session
|
||||
bt->rpc_session = rpc_session_open(bt->rpc);
|
||||
bt->rpc_session = rpc_session_open(bt->rpc, RpcOwnerBle);
|
||||
if(bt->rpc_session) {
|
||||
FURI_LOG_I(TAG, "Open RPC connection");
|
||||
rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback);
|
||||
|
||||
@@ -39,6 +39,12 @@ static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Lock_7x8);
|
||||
}
|
||||
|
||||
static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) {
|
||||
UNUSED(context);
|
||||
furi_assert(canvas);
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Muted_8x8);
|
||||
}
|
||||
|
||||
static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
@@ -139,6 +145,18 @@ void desktop_unlock(Desktop* desktop) {
|
||||
desktop_auto_lock_arm(desktop);
|
||||
}
|
||||
|
||||
void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) {
|
||||
desktop->in_transition = true;
|
||||
if(enabled) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode);
|
||||
} else {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode);
|
||||
}
|
||||
desktop_lock_menu_set_stealth_mode_state(desktop->lock_menu, enabled);
|
||||
view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled);
|
||||
desktop->in_transition = false;
|
||||
}
|
||||
|
||||
Desktop* desktop_alloc() {
|
||||
Desktop* desktop = malloc(sizeof(Desktop));
|
||||
|
||||
@@ -222,6 +240,18 @@ Desktop* desktop_alloc() {
|
||||
view_port_enabled_set(desktop->lock_icon_viewport, false);
|
||||
gui_add_view_port(desktop->gui, desktop->lock_icon_viewport, GuiLayerStatusBarLeft);
|
||||
|
||||
// Stealth mode icon
|
||||
desktop->stealth_mode_icon_viewport = view_port_alloc();
|
||||
view_port_set_width(desktop->stealth_mode_icon_viewport, icon_get_width(&I_Muted_8x8));
|
||||
view_port_draw_callback_set(
|
||||
desktop->stealth_mode_icon_viewport, desktop_stealth_mode_icon_draw_callback, desktop);
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) {
|
||||
view_port_enabled_set(desktop->stealth_mode_icon_viewport, true);
|
||||
} else {
|
||||
view_port_enabled_set(desktop->stealth_mode_icon_viewport, false);
|
||||
}
|
||||
gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft);
|
||||
|
||||
// Special case: autostart application is already running
|
||||
desktop->loader = furi_record_open(RECORD_LOADER);
|
||||
if(loader_is_locked(desktop->loader) &&
|
||||
|
||||
@@ -58,6 +58,7 @@ struct Desktop {
|
||||
DesktopViewPinInput* pin_input_view;
|
||||
|
||||
ViewPort* lock_icon_viewport;
|
||||
ViewPort* stealth_mode_icon_viewport;
|
||||
|
||||
AnimationManager* animation_manager;
|
||||
|
||||
@@ -77,3 +78,4 @@ Desktop* desktop_alloc();
|
||||
void desktop_free(Desktop* desktop);
|
||||
void desktop_lock(Desktop* desktop);
|
||||
void desktop_unlock(Desktop* desktop);
|
||||
void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled);
|
||||
|
||||
@@ -28,6 +28,8 @@ void desktop_scene_lock_menu_on_enter(void* context) {
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop);
|
||||
desktop_lock_menu_set_pin_state(desktop->lock_menu, desktop->settings.pin_code.length > 0);
|
||||
desktop_lock_menu_set_stealth_mode_state(
|
||||
desktop->lock_menu, furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode));
|
||||
desktop_lock_menu_set_idx(desktop->lock_menu, 3);
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
@@ -129,6 +131,12 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("apps/.Main/xtreme_app.fap"));
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockMenuEventStealthModeOn:
|
||||
desktop_set_stealth_mode_state(desktop, true);
|
||||
break;
|
||||
case DesktopLockMenuEventStealthModeOff:
|
||||
desktop_set_stealth_mode_state(desktop, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ typedef enum {
|
||||
DesktopLockMenuEventLockPin,
|
||||
DesktopLockMenuEventLockPinOff,
|
||||
DesktopLockMenuEventXtreme,
|
||||
DesktopLockMenuEventStealthModeOn,
|
||||
DesktopLockMenuEventStealthModeOff,
|
||||
|
||||
DesktopAnimationEventCheckAnimation,
|
||||
DesktopAnimationEventNewIdleAnimation,
|
||||
|
||||
@@ -48,6 +48,14 @@ void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is
|
||||
true);
|
||||
}
|
||||
|
||||
void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode) {
|
||||
with_view_model(
|
||||
lock_menu->view,
|
||||
DesktopLockMenuViewModel * model,
|
||||
{ model->stealth_mode = stealth_mode; },
|
||||
true);
|
||||
}
|
||||
|
||||
void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) {
|
||||
furi_assert(idx < DesktopLockMenuIndexTotalCount);
|
||||
with_view_model(
|
||||
@@ -110,7 +118,7 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) {
|
||||
value = total - m->lock_menu->notification->settings.display_brightness * total;
|
||||
break;
|
||||
case DesktopLockMenuIndexVolume:
|
||||
icon = &I_Volup_8x6;
|
||||
icon = m->stealth_mode ? &I_Muted_8x8 : &I_Volup_8x6;
|
||||
value = total - m->lock_menu->notification->settings.speaker_volume * total;
|
||||
break;
|
||||
default:
|
||||
@@ -181,6 +189,7 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
|
||||
uint8_t idx = 0;
|
||||
int pin_lock = 0;
|
||||
bool show_lock_menu = false;
|
||||
bool stealth_mode = false;
|
||||
bool consumed = true;
|
||||
|
||||
with_view_model(
|
||||
@@ -188,6 +197,7 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
|
||||
DesktopLockMenuViewModel * model,
|
||||
{
|
||||
show_lock_menu = model->show_lock_menu;
|
||||
stealth_mode = model->stealth_mode;
|
||||
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
|
||||
if(model->show_lock_menu) {
|
||||
if(event->key == InputKeyUp) {
|
||||
@@ -292,6 +302,9 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
|
||||
case DesktopLockMenuIndexXtreme:
|
||||
desktop_event = DesktopLockMenuEventXtreme;
|
||||
break;
|
||||
case DesktopLockMenuIndexVolume:
|
||||
desktop_event = stealth_mode ? DesktopLockMenuEventStealthModeOff : DesktopLockMenuEventStealthModeOn;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ typedef struct {
|
||||
int pin_lock;
|
||||
bool show_lock_menu;
|
||||
DesktopLockMenuView* lock_menu;
|
||||
bool stealth_mode;
|
||||
} DesktopLockMenuViewModel;
|
||||
|
||||
void desktop_lock_menu_set_callback(
|
||||
@@ -37,6 +38,7 @@ void desktop_lock_menu_set_callback(
|
||||
|
||||
View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu);
|
||||
void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set);
|
||||
void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode);
|
||||
void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx);
|
||||
DesktopLockMenuView* desktop_lock_menu_alloc();
|
||||
void desktop_lock_menu_free(DesktopLockMenuView* lock_menu);
|
||||
|
||||
@@ -273,6 +273,8 @@ Menu* menu_alloc() {
|
||||
void menu_free(Menu* menu) {
|
||||
furi_assert(menu);
|
||||
menu_reset(menu);
|
||||
with_view_model(
|
||||
menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false);
|
||||
view_free(menu->view);
|
||||
furi_timer_free(menu->scroll_timer);
|
||||
free(menu);
|
||||
|
||||
@@ -20,9 +20,9 @@ static const uint8_t reset_sound_mask = 1 << 4;
|
||||
static const uint8_t reset_display_mask = 1 << 5;
|
||||
static const uint8_t reset_blink_mask = 1 << 6;
|
||||
|
||||
void notification_vibro_on();
|
||||
void notification_vibro_on(bool force);
|
||||
void notification_vibro_off();
|
||||
void notification_sound_on(float freq, float volume);
|
||||
void notification_sound_on(float freq, float volume, bool force);
|
||||
void notification_sound_off();
|
||||
|
||||
uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value);
|
||||
@@ -141,17 +141,21 @@ uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) {
|
||||
}
|
||||
|
||||
// generics
|
||||
void notification_vibro_on() {
|
||||
furi_hal_vibro_on(true);
|
||||
void notification_vibro_on(bool force) {
|
||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) {
|
||||
furi_hal_vibro_on(true);
|
||||
}
|
||||
}
|
||||
|
||||
void notification_vibro_off() {
|
||||
furi_hal_vibro_on(false);
|
||||
}
|
||||
|
||||
void notification_sound_on(float freq, float volume) {
|
||||
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
|
||||
furi_hal_speaker_start(freq, volume);
|
||||
void notification_sound_on(float freq, float volume, bool force) {
|
||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) {
|
||||
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
|
||||
furi_hal_speaker_start(freq, volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +178,8 @@ void notification_process_notification_message(
|
||||
NotificationApp* app,
|
||||
NotificationAppMessage* message) {
|
||||
uint32_t notification_message_index = 0;
|
||||
bool force_volume = false;
|
||||
bool force_vibro = false;
|
||||
const NotificationMessage* notification_message;
|
||||
notification_message = (*message->sequence)[notification_message_index];
|
||||
|
||||
@@ -269,7 +275,7 @@ void notification_process_notification_message(
|
||||
break;
|
||||
case NotificationMessageTypeVibro:
|
||||
if(notification_message->data.vibro.on) {
|
||||
if(vibro_setting) notification_vibro_on();
|
||||
if(vibro_setting) notification_vibro_on(force_vibro);
|
||||
} else {
|
||||
notification_vibro_off();
|
||||
}
|
||||
@@ -278,7 +284,8 @@ void notification_process_notification_message(
|
||||
case NotificationMessageTypeSoundOn:
|
||||
notification_sound_on(
|
||||
notification_message->data.sound.frequency,
|
||||
notification_message->data.sound.volume * speaker_volume_setting);
|
||||
notification_message->data.sound.volume * speaker_volume_setting,
|
||||
force_volume);
|
||||
reset_mask |= reset_sound_mask;
|
||||
break;
|
||||
case NotificationMessageTypeSoundOff:
|
||||
@@ -307,9 +314,11 @@ void notification_process_notification_message(
|
||||
break;
|
||||
case NotificationMessageTypeForceSpeakerVolumeSetting:
|
||||
speaker_volume_setting = notification_message->data.forced_settings.speaker_volume;
|
||||
force_volume = true;
|
||||
break;
|
||||
case NotificationMessageTypeForceVibroSetting:
|
||||
vibro_setting = notification_message->data.forced_settings.vibro;
|
||||
force_vibro = true;
|
||||
break;
|
||||
case NotificationMessageTypeForceDisplayBrightnessSetting:
|
||||
display_brightness_setting =
|
||||
|
||||
@@ -512,6 +512,10 @@ static void power_check_battery_level_change(Power* power) {
|
||||
}
|
||||
}
|
||||
|
||||
void power_trigger_ui_update(Power* power) {
|
||||
view_port_update(power->battery_view_port);
|
||||
}
|
||||
|
||||
int32_t power_srv(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
@@ -543,7 +547,9 @@ int32_t power_srv(void* p) {
|
||||
power_check_battery_level_change(power);
|
||||
|
||||
// Update battery view port
|
||||
if(need_refresh) view_port_update(power->battery_view_port);
|
||||
if(need_refresh) {
|
||||
view_port_update(power->battery_view_port);
|
||||
}
|
||||
|
||||
// Check OTG status and disable it in case of fault
|
||||
if(furi_hal_power_is_otg_enabled()) {
|
||||
|
||||
@@ -113,6 +113,12 @@ bool power_is_battery_healthy(Power* power);
|
||||
*/
|
||||
void power_enable_low_battery_level_notification(Power* power, bool enable);
|
||||
|
||||
/** Trigger UI update for changing battery layout
|
||||
*
|
||||
* @param power Power instance
|
||||
*/
|
||||
void power_trigger_ui_update(Power* power);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -76,6 +76,7 @@ struct RpcSession {
|
||||
RpcBufferIsEmptyCallback buffer_is_empty_callback;
|
||||
RpcSessionClosedCallback closed_callback;
|
||||
RpcSessionTerminatedCallback terminated_callback;
|
||||
RpcOwner owner;
|
||||
void* context;
|
||||
};
|
||||
|
||||
@@ -83,6 +84,11 @@ struct Rpc {
|
||||
FuriMutex* busy_mutex;
|
||||
};
|
||||
|
||||
RpcOwner rpc_session_get_owner(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
return session->owner;
|
||||
}
|
||||
|
||||
static void rpc_close_session_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(context);
|
||||
@@ -348,7 +354,7 @@ static void rpc_session_free_callback(FuriThreadState thread_state, void* contex
|
||||
}
|
||||
}
|
||||
|
||||
RpcSession* rpc_session_open(Rpc* rpc) {
|
||||
RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) {
|
||||
furi_assert(rpc);
|
||||
|
||||
RpcSession* session = malloc(sizeof(RpcSession));
|
||||
@@ -357,6 +363,7 @@ RpcSession* rpc_session_open(Rpc* rpc) {
|
||||
session->rpc = rpc;
|
||||
session->terminate = false;
|
||||
session->decode_error = false;
|
||||
session->owner = owner;
|
||||
RpcHandlerDict_init(session->handlers);
|
||||
|
||||
session->decoded_message = malloc(sizeof(PB_Main));
|
||||
|
||||
@@ -30,6 +30,21 @@ typedef void (*RpcSessionClosedCallback)(void* context);
|
||||
* and all operations were finished */
|
||||
typedef void (*RpcSessionTerminatedCallback)(void* context);
|
||||
|
||||
/** RPC owner */
|
||||
typedef enum {
|
||||
RpcOwnerUnknown = 0,
|
||||
RpcOwnerBle,
|
||||
RpcOwnerUsb,
|
||||
RpcOwnerCount,
|
||||
} RpcOwner;
|
||||
|
||||
/** Get RPC session owner
|
||||
*
|
||||
* @param session pointer to RpcSession descriptor
|
||||
* @return session owner
|
||||
*/
|
||||
RpcOwner rpc_session_get_owner(RpcSession* session);
|
||||
|
||||
/** Open RPC session
|
||||
*
|
||||
* USAGE:
|
||||
@@ -44,10 +59,11 @@ typedef void (*RpcSessionTerminatedCallback)(void* context);
|
||||
*
|
||||
*
|
||||
* @param rpc instance
|
||||
* @param owner owner of session
|
||||
* @return pointer to RpcSession descriptor, or
|
||||
* NULL if RPC is busy and can't open session now
|
||||
*/
|
||||
RpcSession* rpc_session_open(Rpc* rpc);
|
||||
RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner);
|
||||
|
||||
/** Close RPC session
|
||||
* It is guaranteed that no callbacks will be called
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user