Merge branch 'ul-dev' into xfw-dev

This commit is contained in:
Willy-JL
2023-04-23 17:48:05 +01:00
170 changed files with 3650 additions and 1489 deletions

2
.gitignore vendored
View File

@@ -30,7 +30,7 @@ bindings/
Brewfile.lock.json
# Visual Studio Code
.vscode/
/.vscode/
# Visual Studio
.vs/

View File

@@ -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",
)

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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",

View File

@@ -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);

View File

@@ -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;

View File

@@ -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]));
}
}
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -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

View File

@@ -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);

View File

@@ -1,10 +1,12 @@
typedef enum {
HidViewSubmenu,
HidViewKeynote,
HidViewKeynoteVertical,
HidViewKeyboard,
HidViewMedia,
HidViewMouse,
HidViewMouseJiggler,
BtHidViewTikTok,
BtHidViewYTShorts,
HidViewExitConfirm,
} HidView;
} HidView;

View 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);
}

View 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);

View File

@@ -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) {

View File

@@ -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) {

View 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);
}

View 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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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]));
}
}
}
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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:

View File

@@ -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"

View File

@@ -1,3 +1,6 @@
#pragma once
#pragma weak strnlen
#include <stddef.h>
size_t strnlen(const char* s, size_t maxlen);

View File

@@ -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;

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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) {

View File

@@ -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"

View File

@@ -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)

View File

@@ -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);

View File

@@ -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"

View File

@@ -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);

View File

@@ -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)) {

View File

@@ -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,

View 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;
}

View 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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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");

View File

@@ -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,

View File

@@ -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"));
//}
}

View File

@@ -8,4 +8,5 @@ App(
order=90,
fap_icon="wifi_10px.png",
fap_category="WiFi",
fap_libs=["assets"],
)

View File

@@ -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);
}

View File

@@ -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);

View 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;

View 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);
}

View 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

View 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);
}

View 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

View File

@@ -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 */

View File

@@ -35,12 +35,6 @@ typedef enum {
SubGhzSpeakerStateEnable,
} SubGhzSpeakerState;
/** SubGhzStarLineIgnore state */
typedef enum {
SubGhzStarLineIgnoreDisable,
SubGhzStarLineIgnoreEnable,
} SubGhzStarLineIgnoreState;
/** SubGhzRxKeyState state */
typedef enum {
SubGhzRxKeyStateIDLE,

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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",

View File

@@ -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) ||

View File

@@ -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) {

View File

@@ -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 :)

View File

@@ -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);
}

View File

@@ -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);

View 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, "");
}

View File

@@ -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, "");
}

View File

@@ -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, "");
}

View File

@@ -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

View File

@@ -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, "");
}

View 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, "");
}

View File

@@ -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, "");
}

View File

@@ -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, "");
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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();

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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) &&

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -44,6 +44,8 @@ typedef enum {
DesktopLockMenuEventLockPin,
DesktopLockMenuEventLockPinOff,
DesktopLockMenuEventXtreme,
DesktopLockMenuEventStealthModeOn,
DesktopLockMenuEventStealthModeOff,
DesktopAnimationEventCheckAnimation,
DesktopAnimationEventNewIdleAnimation,

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 =

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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));

View File

@@ -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