From aeb02500deaf2448343c818a58c019f737930e13 Mon Sep 17 00:00:00 2001 From: DerSkythe Date: Sat, 24 Sep 2022 21:47:21 +0400 Subject: [PATCH] Deep refactor of SubBrute was made, but it doesn't start. Debug device needed --- applications/plugins/subbrute/application.fam | 2 +- .../subbrute/helpers/subbrute_worker.c | 203 ++++++ .../subbrute/helpers/subbrute_worker.h | 32 + .../scene/subbrute_scene_entrypoint.c | 197 ------ .../scene/subbrute_scene_entrypoint.h | 8 - .../subbrute/scene/subbrute_scene_load_file.c | 222 ------- .../subbrute/scene/subbrute_scene_load_file.h | 8 - .../scene/subbrute_scene_run_attack.c | 384 ------------ .../scene/subbrute_scene_run_attack.h | 8 - .../subbrute/scene/subbrute_scene_save_name.c | 222 ------- .../subbrute/scene/subbrute_scene_save_name.h | 6 - .../scene/subbrute_scene_select_field.c | 121 ---- .../scene/subbrute_scene_select_field.h | 8 - .../plugins/subbrute/scenes/subbrute_scene.h | 29 + .../subbrute/scenes/subbrute_scene_config.h | 6 + .../scenes/subbrute_scene_load_file.c | 61 ++ .../scenes/subbrute_scene_run_attack.c | 158 +++++ .../scenes/subbrute_scene_save_name.c | 75 +++ .../scenes/subbrute_scene_save_success.c | 59 ++ .../scenes/subbrute_scene_setup_attack.c | 96 +++ .../subbrute/scenes/subbrute_scene_start.c | 50 ++ .../plugins/subbrute/scenes/subbute_scene.c | 30 + applications/plugins/subbrute/subbrute.c | 426 ++++++------- applications/plugins/subbrute/subbrute.h | 109 +--- .../plugins/subbrute/subbrute_custom_event.h | 25 + .../plugins/subbrute/subbrute_device.c | 582 ++++++++++++++++++ .../plugins/subbrute/subbrute_device.h | 103 ++++ applications/plugins/subbrute/subbrute_i.h | 87 +++ .../plugins/subbrute/subbrute_utils.c | 13 - .../plugins/subbrute/subbrute_utils.h | 4 - .../subbrute/views/subbrute_attack_view.c | 321 ++++++++++ .../subbrute/views/subbrute_attack_view.h | 36 ++ .../subbrute/views/subbrute_main_view.c | 152 +++++ .../subbrute/views/subbrute_main_view.h | 28 + 34 files changed, 2334 insertions(+), 1537 deletions(-) create mode 100644 applications/plugins/subbrute/helpers/subbrute_worker.c create mode 100644 applications/plugins/subbrute/helpers/subbrute_worker.h delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_entrypoint.c delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_entrypoint.h delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_load_file.c delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_load_file.h delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_run_attack.c delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_run_attack.h delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_save_name.c delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_save_name.h delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_select_field.c delete mode 100644 applications/plugins/subbrute/scene/subbrute_scene_select_field.h create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene.h create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene_config.h create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene_load_file.c create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene_save_name.c create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene_save_success.c create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c create mode 100644 applications/plugins/subbrute/scenes/subbrute_scene_start.c create mode 100644 applications/plugins/subbrute/scenes/subbute_scene.c create mode 100644 applications/plugins/subbrute/subbrute_custom_event.h create mode 100644 applications/plugins/subbrute/subbrute_device.c create mode 100644 applications/plugins/subbrute/subbrute_device.h create mode 100644 applications/plugins/subbrute/subbrute_i.h delete mode 100644 applications/plugins/subbrute/subbrute_utils.c delete mode 100644 applications/plugins/subbrute/subbrute_utils.h create mode 100644 applications/plugins/subbrute/views/subbrute_attack_view.c create mode 100644 applications/plugins/subbrute/views/subbrute_attack_view.h create mode 100644 applications/plugins/subbrute/views/subbrute_main_view.c create mode 100644 applications/plugins/subbrute/views/subbrute_main_view.h diff --git a/applications/plugins/subbrute/application.fam b/applications/plugins/subbrute/application.fam index 752b0e0e6..1afdc539f 100644 --- a/applications/plugins/subbrute/application.fam +++ b/applications/plugins/subbrute/application.fam @@ -2,7 +2,7 @@ App( appid="subbrute", name="Sub-GHz Bruteforcer", apptype=FlipperAppType.EXTERNAL, - entry_point="subbrute_start", + entry_point="subbrute_app", cdefines=["APP_SUB_BRUTE"], requires=["gui","dialogs"], stack_size=2 * 1024, diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.c b/applications/plugins/subbrute/helpers/subbrute_worker.c new file mode 100644 index 000000000..e947aaf2a --- /dev/null +++ b/applications/plugins/subbrute/helpers/subbrute_worker.c @@ -0,0 +1,203 @@ +#include +#include + +#include +#include + +#include "subbrute_worker.h" + +#define TAG "SubBruteWorker" + +struct SubBruteWorker { + FuriThread* thread; + volatile bool worker_running; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* flipper_format; + + uint32_t last_time_tx_data; + FuriMessageQueue* event_queue; + + // Preset and frequency needed + FuriHalSubGhzPreset preset; + uint32_t frequency; + string_t protocol_name; + + //SubBruteWorkerCallback callback; + //void* context; +}; + +/** Taken from subghz_tx_rx_worker.c */ +#define SUBBRUTE_TXRX_WORKER_BUF_SIZE 2048 +#define SUBBRUTE_TXRX_WORKER_MAX_TXRX_SIZE 60 +#define SUBBRUTE_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF 40 +#define SUBBRUTE_TX_TIMEOUT 200 +#define SUBBRUTE_SEND_DELAY 260 + +/** + * Entrypoint for worker + * + * @param context SubBruteWorker* + * @return 0 if ok + */ +int32_t subbrute_worker_thread(void* context) { + furi_assert(context); + SubBruteWorker* instance = (SubBruteWorker*)context; + + if(!instance->worker_running) { + FURI_LOG_W(TAG, "Worker is not set to running state!"); + return -1; + } +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker start"); +#endif + + instance->environment = subghz_environment_alloc(); + instance->transmitter = subghz_transmitter_alloc_init( + instance->environment, string_get_cstr(instance->protocol_name)); + + furi_hal_subghz_reset(); + furi_hal_subghz_load_preset(instance->preset); + instance->frequency = furi_hal_subghz_set_frequency_and_path(instance->frequency); + + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_cc1101_g0, true); + + furi_hal_power_suppress_charge_enter(); + + // Set ready to transmit value + instance->last_time_tx_data = furi_get_tick() - SUBBRUTE_SEND_DELAY; + + while(instance->worker_running) { + // Transmit + if(!furi_hal_subghz_tx()) { + FURI_LOG_E(TAG, "Cannot transmit!"); + break; + } + furi_delay_ms(250); + } + + furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); + furi_hal_subghz_sleep(); + + furi_hal_power_suppress_charge_exit(); + + subghz_transmitter_free(instance->transmitter); + subghz_environment_free(instance->environment); + +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker stop"); +#endif + return 0; +} + +SubBruteWorker* subbrute_worker_alloc() { + SubBruteWorker* instance = malloc(sizeof(SubBruteWorker)); + + instance->thread = furi_thread_alloc(); + furi_thread_set_name(instance->thread, "SubBruteAttackWorker"); + furi_thread_set_stack_size(instance->thread, 2048); + furi_thread_set_context(instance->thread, instance); + furi_thread_set_callback(instance->thread, subbrute_worker_thread); + + //instance->status = SubBruteWorkerStatusIDLE; + instance->worker_running = false; + + instance->flipper_format = flipper_format_string_alloc(); + string_init(instance->protocol_name); + + return instance; +} + +void subbrute_worker_free(SubBruteWorker* instance) { + furi_assert(instance); + furi_assert(!instance->worker_running); + + furi_thread_free(instance->thread); + flipper_format_free(instance->flipper_format); + string_clear(instance->protocol_name); + + free(instance); +} + +bool subbrute_worker_start( + SubBruteWorker* instance, + uint32_t frequency, + FuriHalSubGhzPreset preset, + string_t protocol_name) { + furi_assert(instance); + furi_assert(!instance->worker_running); + + instance->frequency = frequency; + instance->preset = preset; + string_init_move(instance->protocol_name, protocol_name); + + bool res = false; + + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_preset(instance->preset); + + furi_hal_subghz_set_frequency_and_path(instance->frequency); + furi_hal_subghz_flush_rx(); + + if(furi_hal_subghz_is_tx_allowed(frequency)) { + instance->frequency = frequency; + res = true; + } + instance->worker_running = res; + +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Frequency: %d", frequency); +#endif + instance->preset = preset; + + furi_thread_start(instance->thread); + + return res; +} + +void subbrute_worker_stop(SubBruteWorker* instance) { + furi_assert(instance); + + instance->worker_running = false; + + furi_thread_join(instance->thread); + + furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); + furi_hal_subghz_sleep(); +} + +bool subbrute_worker_is_running(SubBruteWorker* instance) { + furi_assert(instance); + + return instance->worker_running; +} + +bool subbrute_worker_can_transmit(SubBruteWorker* instance) { + furi_assert(instance); + + return (furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_SEND_DELAY; +} + +bool subbrute_worker_transmit(SubBruteWorker* instance, string_t payload) { + furi_assert(instance); + furi_assert(instance->worker_running); + + if(!subbrute_worker_can_transmit(instance)) { + FURI_LOG_E(TAG, "Too early to transmit"); + + return false; + } + instance->last_time_tx_data = furi_get_tick(); + + Stream* stream = flipper_format_get_raw_stream(instance->flipper_format); + stream_clean(stream); + stream_write_cstring(stream, string_get_cstr(payload)); + subghz_transmitter_deserialize(instance->transmitter, instance->flipper_format); + + return true; +} \ No newline at end of file diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.h b/applications/plugins/subbrute/helpers/subbrute_worker.h new file mode 100644 index 000000000..d0ed3cbf7 --- /dev/null +++ b/applications/plugins/subbrute/helpers/subbrute_worker.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +typedef struct SubBruteWorker SubBruteWorker; +/** + * Same like SubGhzTxRxWorkerStatus in subghz_tx_rx_worker.h + * using just to not include that file + +typedef enum { + SubBruteWorkerStatusIDLE, + SubBruteWorkerStatusTx, + // SubBruteWorkerStatusRx, +} SubBruteWorkerStatus; + +//typedef void (*SubBruteWorkerCallback)(SubBruteWorkerStatus event, void* context); +*/ +SubBruteWorker* subbrute_worker_alloc(); +void subbrute_worker_free(SubBruteWorker* instance); +bool subbrute_worker_start( + SubBruteWorker* instance, + uint32_t frequency, + FuriHalSubGhzPreset preset, + string_t protocol_name); +void subbrute_worker_stop(SubBruteWorker* instance); +//bool subbrute_worker_write(SubBruteWorker* instance, uint8_t* data, size_t size); +bool subbrute_worker_is_running(SubBruteWorker* instance); +bool subbrute_worker_can_transmit(SubBruteWorker* instance); +bool subbrute_worker_transmit(SubBruteWorker* instance, string_t payload); \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_entrypoint.c b/applications/plugins/subbrute/scene/subbrute_scene_entrypoint.c deleted file mode 100644 index 6f8497b9f..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_entrypoint.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "subbrute_scene_entrypoint.h" -#include "../subbrute_utils.h" - -string_t subbrute_menu_items[10]; - -void subbrute_scene_entrypoint_menu_callback(SubBruteState* context, uint32_t index) { - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - string_set_str(context->protocol, "RAW"); - context->repeat = 5; - context->te = 0; - context->attack = index; - switch(index) { - case SubBruteAttackLoadFile: - context->current_scene = SceneSelectFile; - break; - case SubBruteAttackCAME12bit307: - case SubBruteAttackCAME12bit433: - case SubBruteAttackCAME12bit868: - if(index == SubBruteAttackCAME12bit307) { - context->frequency = 307800000; - } else if(index == SubBruteAttackCAME12bit433) { - context->frequency = 433920000; - } else if(index == SubBruteAttackCAME12bit868) { - context->frequency = 868350000; - } - context->bit = 12; - string_set_str(context->protocol, "CAME"); - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - if(!subbrute_is_frequency_allowed(context)) { - return; - } - context->current_scene = SceneAttack; - break; - case SubBruteAttackChamberlain9bit315: - context->frequency = 315000000; - context->bit = 9; - string_set_str(context->protocol, "Cham_Code"); - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - - if(!subbrute_is_frequency_allowed(context)) { - return; - } - context->current_scene = SceneAttack; - break; - case SubBruteAttackChamberlain9bit390: - context->frequency = 390000000; - context->bit = 9; - string_set_str(context->protocol, "Cham_Code"); - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - - if(!subbrute_is_frequency_allowed(context)) { - return; - } - context->current_scene = SceneAttack; - break; - case SubBruteAttackLinear10bit300: - context->frequency = 300000000; - context->bit = 10; - string_set_str(context->protocol, "Linear"); - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - if(!subbrute_is_frequency_allowed(context)) { - return; - } - context->current_scene = SceneAttack; - break; - case SubBruteAttackLinear10bit310: - context->frequency = 310000000; - context->bit = 10; - string_set_str(context->protocol, "Linear"); - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - if(!subbrute_is_frequency_allowed(context)) { - return; - } - context->current_scene = SceneAttack; - break; - case SubBruteAttackNICE12bit433: - context->frequency = 433920000; - context->bit = 12; - string_set_str(context->protocol, "Nice FLO"); - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - if(!subbrute_is_frequency_allowed(context)) { - return; - } - context->current_scene = SceneAttack; - break; - case SubBruteAttackNICE12bit868: - context->frequency = 868350000; - context->bit = 12; - string_set_str(context->protocol, "Nice FLO"); - string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async"); - if(!subbrute_is_frequency_allowed(context)) { - return; - } - context->current_scene = SceneAttack; - break; - default: - break; - } -} - -void subbrute_scene_entrypoint_on_enter(SubBruteState* context) { - // Clear the previous payload - context->menu_index = 0; - for(uint32_t i = 0; i < 10; i++) { - string_init(subbrute_menu_items[i]); - } - - string_set(subbrute_menu_items[0], "BF existing dump"); - string_set(subbrute_menu_items[1], "CAME 12bit 307mhz"); - string_set(subbrute_menu_items[2], "CAME 12bit 433mhz"); - string_set(subbrute_menu_items[3], "CAME 12bit 868mhz"); - string_set(subbrute_menu_items[4], "Chamberlain 9bit 315mhz"); - string_set(subbrute_menu_items[5], "Chamberlain 9bit 390mhz"); - string_set(subbrute_menu_items[6], "Linear 10bit 300mhz"); - string_set(subbrute_menu_items[7], "Linear 10bit 310mhz"); - string_set(subbrute_menu_items[8], "NICE 12bit 433mhz"); - string_set(subbrute_menu_items[9], "NICE 12bit 868mhz"); -} - -void subbrute_scene_entrypoint_on_exit(SubBruteState* context) { - UNUSED(context); - for(uint32_t i = 0; i < 10; i++) { - string_clear(subbrute_menu_items[i]); - } -} - -void subbrute_scene_entrypoint_on_tick(SubBruteState* context) { - UNUSED(context); -} - -void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context) { - if(event.evt_type == EventTypeKey) { - if(event.input_type == InputTypeShort) { - switch(event.key) { - case InputKeyDown: - if(context->menu_index < SubBruteAttackNICE12bit868) { - context->menu_index++; - } - break; - case InputKeyUp: - if(context->menu_index > SubBruteAttackLoadFile) { - context->menu_index--; - } - break; - case InputKeyLeft: - case InputKeyRight: - break; - case InputKeyOk: - subbrute_scene_entrypoint_menu_callback(context, context->menu_index); - break; - case InputKeyBack: - context->is_running = false; - break; - } - } - } -} - -void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context) { - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "Sub-GHz Bruteforcer"); - - if(context->menu_index > SubBruteAttackLoadFile) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, - 64, - 24, - AlignCenter, - AlignTop, - string_get_cstr(subbrute_menu_items[context->menu_index - 1])); - } - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - 64, - 36, - AlignCenter, - AlignTop, - string_get_cstr(subbrute_menu_items[context->menu_index])); - - if(context->menu_index < SubBruteAttackNICE12bit868) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, - 64, - 48, - AlignCenter, - AlignTop, - string_get_cstr(subbrute_menu_items[context->menu_index + 1])); - } -} \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_entrypoint.h b/applications/plugins/subbrute/scene/subbrute_scene_entrypoint.h deleted file mode 100644 index af6b3bc49..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_entrypoint.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "../subbrute.h" - -void subbrute_scene_entrypoint_on_enter(SubBruteState* context); -void subbrute_scene_entrypoint_on_exit(SubBruteState* context); -void subbrute_scene_entrypoint_on_tick(SubBruteState* context); -void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context); -void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_load_file.c b/applications/plugins/subbrute/scene/subbrute_scene_load_file.c deleted file mode 100644 index e2c99c9cd..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_load_file.c +++ /dev/null @@ -1,222 +0,0 @@ -#include "subbrute_scene_load_file.h" -#include "subbrute_scene_entrypoint.h" -#include "../subbrute_utils.h" -#include - -#define SUBGHZ_APP_PATH_FOLDER "/ext/subghz" - -bool subbrute_load(SubBruteState* context, const char* file_path) { - bool result = false; - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - - string_t temp_str; - string_init(temp_str); - uint32_t temp_data32; - - do { - if(!flipper_format_file_open_existing(fff_data_file, file_path)) { - FURI_LOG_E(TAG, "Error open file %s", file_path); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Error open file"); - break; - } - if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { - FURI_LOG_E(TAG, "Missing or incorrect header"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Missing or incorrect header"); - break; - } - // Frequency - if(flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { - FURI_LOG_I(TAG, "Frequency: %d", temp_data32); - context->frequency = temp_data32; - if(!subbrute_is_frequency_allowed(context)) { - break; - } - } else { - FURI_LOG_E(TAG, "Missing or incorrect Frequency"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Missing or incorrect Frequency"); - break; - } - // Preset - if(!flipper_format_read_string(fff_data_file, "Preset", context->preset)) { - FURI_LOG_E(TAG, "Preset FAIL"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Preset FAIL"); - } - // Protocol - if(!flipper_format_read_string(fff_data_file, "Protocol", context->protocol)) { - FURI_LOG_E(TAG, "Missing Protocol"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Missing Protocol"); - break; - } else { - FURI_LOG_I(TAG, "Protocol: %s", string_get_cstr(context->protocol)); - } - - if(strcmp(string_get_cstr(context->protocol), "RAW") == 0) { - FURI_LOG_E(TAG, "RAW unsupported"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "RAW unsupported"); - break; - } - - const SubGhzProtocol* registry = - subghz_protocol_registry_get_by_name(string_get_cstr(context->protocol)); - - if(registry && registry->type == SubGhzProtocolTypeDynamic) { - FURI_LOG_D(TAG, "Protocol is dynamic - not supported"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Dynamic protocol unsupported"); - break; - } - - context->decoder_result = subghz_receiver_search_decoder_base_by_name( - context->receiver, string_get_cstr(context->protocol)); - - if(context->decoder_result) { - FURI_LOG_I(TAG, "Found decoder"); - } else { - FURI_LOG_E(TAG, "Protocol not found"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Protocol not found"); - break; - } - - // Bit - if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect Bit"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Missing or incorrect Bit"); - break; - } else { - FURI_LOG_I(TAG, "Bit: %d", temp_data32); - context->bit = temp_data32; - } - - // Key - if(!flipper_format_read_string(fff_data_file, "Key", temp_str)) { - FURI_LOG_E(TAG, "Missing or incorrect Key"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Missing or incorrect Key"); - break; - } else { - FURI_LOG_I(TAG, "Key: %s", string_get_cstr(temp_str)); - string_set(context->key, string_get_cstr(temp_str)); - } - - // TE - if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) { - FURI_LOG_E(TAG, "Missing or incorrect TE"); - //string_reset(context->notification_msg); - //string_set_str(context->notification_msg, "Missing or incorrect TE"); - //break; - } else { - FURI_LOG_I(TAG, "TE: %d", temp_data32); - context->te = temp_data32; - } - - // Repeat - if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) { - FURI_LOG_I(TAG, "Repeat: %d", temp_data32); - context->repeat = temp_data32; - } else { - FURI_LOG_I(TAG, "Repeat: 3 (default)"); - context->repeat = 3; - } - - result = true; - } while(0); - - string_clear(temp_str); - flipper_format_file_close(fff_data_file); - flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); - if(result) { - FURI_LOG_I(TAG, "Loaded successfully"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "File looks ok."); - } - - return result; -} - -void subbrute_scene_load_file_on_enter(SubBruteState* context) { - if(subbrute_load_protocol_from_file(context)) { - context->current_scene = SceneSelectField; - } else { - subbrute_scene_entrypoint_on_enter(context); - context->current_scene = SceneEntryPoint; - } -} - -void subbrute_scene_load_file_on_exit(SubBruteState* context) { - UNUSED(context); -} - -void subbrute_scene_load_file_on_tick(SubBruteState* context) { - UNUSED(context); -} - -void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context) { - UNUSED(context); - if(event.evt_type == EventTypeKey) { - if(event.input_type == InputTypeShort) { - switch(event.key) { - case InputKeyDown: - case InputKeyUp: - case InputKeyLeft: - case InputKeyRight: - case InputKeyOk: - break; - case InputKeyBack: - context->current_scene = SceneEntryPoint; - break; - } - } - } -} - -void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context) { - UNUSED(context); - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - // Frame - //canvas_draw_frame(canvas, 0, 0, 128, 64); - - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 64, 16, AlignCenter, AlignTop, "SubGHz Fuzzer"); - canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, "Error: Press back"); -} - -bool subbrute_load_protocol_from_file(SubBruteState* context) { - string_t file_path; - string_init(file_path); - string_set_str(file_path, SUBGHZ_APP_PATH_FOLDER); - context->environment = subghz_environment_alloc(); - context->receiver = subghz_receiver_alloc_init(context->environment); - subghz_receiver_set_filter(context->receiver, SubGhzProtocolFlag_Decodable); - - // Input events and views are managed by file_select - - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); - - bool res = dialog_file_browser_show(context->dialogs, file_path, file_path, &browser_options); - - if(res) { - res = subbrute_load(context, string_get_cstr(file_path)); - } - - subghz_environment_free(context->environment); - subghz_receiver_free(context->receiver); - - string_clear(file_path); - - return res; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_load_file.h b/applications/plugins/subbrute/scene/subbrute_scene_load_file.h deleted file mode 100644 index 9e186b1c9..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_load_file.h +++ /dev/null @@ -1,8 +0,0 @@ -#include "../subbrute.h" - -void subbrute_scene_load_file_on_enter(SubBruteState* context); -void subbrute_scene_load_file_on_exit(SubBruteState* context); -void subbrute_scene_load_file_on_tick(SubBruteState* context); -void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context); -void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context); -bool subbrute_load_protocol_from_file(SubBruteState* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_run_attack.c b/applications/plugins/subbrute/scene/subbrute_scene_run_attack.c deleted file mode 100644 index 4b4507882..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_run_attack.c +++ /dev/null @@ -1,384 +0,0 @@ -#include "subbrute_scene_run_attack.h" -#include -#include - -//uint64_t subbrute_counter = 0; -uint64_t max_value; -bool locked = false; -bool toSave = false; -char subbrute_payload_byte[4]; -#define SUBBRUTE_DELAY 1 - -FuriHalSubGhzPreset str_to_preset(string_t preset) { - if(string_cmp_str(preset, "FuriHalSubGhzPresetOok270Async") == 0) { - return FuriHalSubGhzPresetOok270Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPresetOok650Async") == 0) { - return FuriHalSubGhzPresetOok650Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev238Async") == 0) { - return FuriHalSubGhzPreset2FSKDev238Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev476Async") == 0) { - return FuriHalSubGhzPreset2FSKDev476Async; - } - if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) { - return FuriHalSubGhzPresetMSK99_97KbAsync; - } - if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) { - return FuriHalSubGhzPresetMSK99_97KbAsync; - } - return FuriHalSubGhzPresetCustom; -} - -void subbrute_emit(SubBruteState* context) { - //FURI_LOG_D(TAG, string_get_cstr(context->flipper_format_string)); - - context->transmitter = - subghz_transmitter_alloc_init(context->environment, string_get_cstr(context->protocol)); - - subghz_transmitter_deserialize(context->transmitter, context->flipper_format); - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(str_to_preset(context->preset)); - - context->frequency_cal = furi_hal_subghz_set_frequency_and_path(context->frequency); - - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, context->transmitter); - while(!(furi_hal_subghz_is_async_tx_complete())) { - furi_delay_ms(1); - } - - furi_hal_subghz_stop_async_tx(); - subghz_transmitter_stop(context->transmitter); - furi_hal_subghz_idle(); - subghz_transmitter_free(context->transmitter); -} - -void prepare_emit(SubBruteState* context) { - UNUSED(context); - - furi_hal_subghz_init(); -} - -void clear_emit(SubBruteState* context) { - UNUSED(context); - - //furi_hal_subghz_stop_async_tx(); - //furi_hal_subghz_idle(); - furi_hal_subghz_sleep(); -} -/* -void subbrute_send_raw_packet(SubBruteState* context) { - string_reset(context->candidate); - - // Payload to padded binary string - int* binaryNum = (int*)malloc(sizeof(int) * context->bit); - uint32_t i = 0; - for(i = 0; i < context->bit; i++) { - binaryNum[i] = 0; - } - i = 0; - uint64_t counter = context->payload; - while(counter > 0) { - binaryNum[i] = counter % 2; - counter = counter / 2; - i++; - } - - // printing binary array in reverse order and build raw payload - for(uint32_t loop = 0; loop < context->repeat; loop++) { - for(int j = (int)context->bit - 1; j >= 0; j--) { - if(binaryNum[j] == 1) { - string_cat(context->candidate, context->subbrute_raw_one); - } else { - string_cat(context->candidate, context->subbrute_raw_zero); - } - } - string_cat(context->candidate, context->subbrute_raw_stop); - } - - free(binaryNum); - - string_init_printf( - context->flipper_format_string, - "Filetype: Flipper SubGhz RAW File\n" - "Version: 1\n" - "Frequency: %d\n" - "Preset: %s\n" - "Protocol: RAW\n" - "RAW_Data: %s", - context->frequency, - string_get_cstr(context->preset), - string_get_cstr(context->candidate)); - - subbrute_emit(context); -} -*/ -void subbrute_send_packet_parsed(SubBruteState* context) { - if(context->attack == SubBruteAttackLoadFile) { - snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)context->payload); - string_replace_at(context->candidate, context->str_index, 3, subbrute_payload_byte); - } else { - string_t buffer; - string_init(buffer); - string_init_printf(buffer, "%16X", context->payload); - int j = 0; - string_set_str(context->candidate, " "); - for(uint8_t i = 0; i < 16; i++) { - if(string_get_char(buffer, i) != ' ') { - string_set_char(context->candidate, i + j, string_get_char(buffer, i)); - } else { - string_set_char(context->candidate, i + j, '0'); - } - if(i % 2 != 0) { - j++; - } - } - string_clear(buffer); - } - if(strcmp(string_get_cstr(context->protocol), "Princeton") == 0) { - string_init_printf( - context->flipper_format_string, - "Filetype: Flipper SubGhz Key File\n" - "Version: 1\n" - "Frequency: %u\n" - "Preset: %s\n" - "Protocol: %s\n" - "Bit: %d\n" - "Key: %s\n" - "TE: %d\n", - context->frequency, - string_get_cstr(context->preset), - string_get_cstr(context->protocol), - context->bit, - string_get_cstr(context->candidate), - context->te); - } else { - string_init_printf( - context->flipper_format_string, - "Filetype: Flipper SubGhz Key File\n" - "Version: 1\n" - "Frequency: %u\n" - "Preset: %s\n" - "Protocol: %s\n" - "Bit: %d\n" - "Key: %s\n", - context->frequency, - string_get_cstr(context->preset), - string_get_cstr(context->protocol), - context->bit, - string_get_cstr(context->candidate)); - } - - stream_clean(context->stream); - stream_write_string(context->stream, context->flipper_format_string); -} - -void subbrute_send_packet(SubBruteState* context) { - ///if(string_cmp_str(context->protocol, "RAW") == 0) { - // subbrute_send_raw_packet(context); - //} else { - subbrute_send_packet_parsed(context); - subbrute_emit(context); - //} - string_clear(context->flipper_format_string); -} - -void subbrute_scene_run_attack_on_exit(SubBruteState* context) { - if(!toSave) { - clear_emit(context); - furi_thread_free(context->bruthread); - flipper_format_free(context->flipper_format); - subghz_receiver_free(context->receiver); - subghz_environment_free(context->environment); - } -} - -void subbrute_scene_run_attack_on_tick(SubBruteState* context) { - if(!context->is_attacking || locked) { - return; - } - //if(0 != subbrute_counter) { - locked = true; - subbrute_send_packet(context); - - if(context->payload == max_value) { - //context->payload = 0x00; - //subbrute_counter = 0; - context->is_attacking = false; - notification_message(context->notify, &sequence_blink_stop); - notification_message(context->notify, &sequence_single_vibro); - } else { - context->payload++; - } - locked = false; - //} - /*if(subbrute_counter > SUBBRUTE_DELAY) { - subbrute_counter = 0; - } else { - subbrute_counter++; - }*/ -} -void subbrute_run_timer(SubBruteState* context) { - while(true) { - if(!context->is_attacking) { - context->is_thread_running = false; - break; - } - //furi_delay_ms(10); - subbrute_scene_run_attack_on_tick(context); - } -} - -// entrypoint for worker -static int32_t subbrute_worker_thread(void* ctx) { - SubBruteState* app = ctx; - subbrute_run_timer(app); - return 0; -} - -void start_bruthread(SubBruteState* app) { - if(!app->is_thread_running) { - furi_thread_start(app->bruthread); - app->is_thread_running = true; - } -} - -void subbrute_scene_run_attack_on_enter(SubBruteState* context) { - if(!toSave) { - if(context->attack == SubBruteAttackLoadFile) { - max_value = 0xFF; - } else { - string_t max_value_s; - string_init(max_value_s); - for(uint8_t i = 0; i < context->bit; i++) { - string_cat_printf(max_value_s, "1"); - } - max_value = (uint64_t)strtol(string_get_cstr(max_value_s), NULL, 2); - string_clear(max_value_s); - } - context->str_index = (context->key_index * 3); - string_init_set(context->candidate, context->key); - context->flipper_format = flipper_format_string_alloc(); - context->stream = flipper_format_get_raw_stream(context->flipper_format); - context->environment = subghz_environment_alloc(); - context->receiver = subghz_receiver_alloc_init(context->environment); - subghz_receiver_set_filter(context->receiver, SubGhzProtocolFlag_Decodable); - - prepare_emit(context); - context->bruthread = furi_thread_alloc(); - furi_thread_set_name(context->bruthread, "SubBrute Worker"); - furi_thread_set_stack_size(context->bruthread, 2048); - furi_thread_set_context(context->bruthread, context); - furi_thread_set_callback(context->bruthread, subbrute_worker_thread); - } else { - toSave = false; - } -} - -void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context) { - if(event.evt_type == EventTypeKey) { - if(event.input_type == InputTypeShort) { - switch(event.key) { - case InputKeyDown: - break; - case InputKeyUp: - if(!context->is_attacking) { - subbrute_send_packet_parsed(context); - string_clear(context->flipper_format_string); - toSave = true; - context->current_scene = SceneSaveName; - } - break; - case InputKeyLeft: - if(!context->is_attacking && context->payload > 0x00) { - context->payload--; - subbrute_send_packet(context); - notification_message(context->notify, &sequence_blink_blue_10); - } else if(!context->is_attacking && context->payload == 0x00) { - context->payload = max_value; - subbrute_send_packet(context); - notification_message(context->notify, &sequence_blink_blue_10); - } - break; - case InputKeyRight: - if(!context->is_attacking && context->payload < max_value) { - context->payload++; - subbrute_send_packet(context); - notification_message(context->notify, &sequence_blink_blue_10); - } else if(!context->is_attacking && context->payload == max_value) { - context->payload = 0x00; - subbrute_send_packet(context); - notification_message(context->notify, &sequence_blink_blue_10); - } - break; - case InputKeyOk: - if(!context->is_attacking) { - if(context->payload == max_value) { - context->payload = 0x00; - //subbrute_counter = 0; - } - context->is_attacking = true; - start_bruthread(context); - notification_message(context->notify, &sequence_blink_start_blue); - } else { - context->is_attacking = false; - //context->close_thread_please = true; - if(context->is_thread_running && context->bruthread) { - furi_thread_join(context->bruthread); // wait until thread is finished - } - //context->close_thread_please = false; - notification_message(context->notify, &sequence_blink_stop); - notification_message(context->notify, &sequence_single_vibro); - } - break; - case InputKeyBack: - locked = false; - //context->close_thread_please = true; - context->is_attacking = false; - if(context->is_thread_running && context->bruthread) { - furi_thread_join(context->bruthread); // wait until thread is finished - } - //context->close_thread_please = false; - string_reset(context->notification_msg); - context->payload = 0x00; - //subbrute_counter = 0; - notification_message(context->notify, &sequence_blink_stop); - if(context->attack == SubBruteAttackLoadFile) { - context->current_scene = SceneSelectField; - } else { - context->current_scene = SceneEntryPoint; - } - break; - } - } - } -} - -void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context) { - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - // Frame - //canvas_draw_frame(canvas, 0, 0, 128, 64); - - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignTop, "Fire in the hole!"); - - char msg_index[26]; - snprintf( - msg_index, sizeof(msg_index), "< %04d / %04d >", (int)context->payload, (int)max_value); - - canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, msg_index); - - canvas_set_font(canvas, FontSecondary); - char start_stop_msg[20]; - snprintf(start_stop_msg, sizeof(start_stop_msg), " Press (^) to save "); - if(context->is_attacking) { - elements_button_center(canvas, "Stop"); - } else { - elements_button_center(canvas, "Start"); - } - canvas_draw_str_aligned(canvas, 64, 39, AlignCenter, AlignTop, start_stop_msg); -} diff --git a/applications/plugins/subbrute/scene/subbrute_scene_run_attack.h b/applications/plugins/subbrute/scene/subbrute_scene_run_attack.h deleted file mode 100644 index 1eb9637d0..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_run_attack.h +++ /dev/null @@ -1,8 +0,0 @@ -#include "../subbrute.h" - -void subbrute_scene_run_attack_on_enter(SubBruteState* context); -void subbrute_scene_run_attack_on_exit(SubBruteState* context); -void subbrute_scene_run_attack_on_tick(SubBruteState* context); -void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context); -void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context); -void send_packet(); \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_save_name.c b/applications/plugins/subbrute/scene/subbrute_scene_save_name.c deleted file mode 100644 index e79cf70ed..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_save_name.c +++ /dev/null @@ -1,222 +0,0 @@ -#include "../subbrute.h" -#include "m-string.h" -#include "subghz/types.h" -#include -#include -#include - -#define MAX_TEXT_INPUT_LEN 22 - -bool backpressed = false; - -bool subbrute_path_is_file(string_t path) { - return string_end_with_str_p(path, ".sub"); -} -// method modified from subghz_i.c -// https://github.com/flipperdevices/flipperzero-firmware/blob/b0daa601ad5b87427a45f9089c8b403a01f72c2a/applications/subghz/subghz_i.c#L417-L456 -bool subbrute_save_protocol_to_file(Stream* flipper_format_stream, const char* dev_file_name) { - furi_assert(dev_file_name); - - Storage* storage = furi_record_open(RECORD_STORAGE); - - bool saved = false; - string_t file_dir; - string_init(file_dir); - - path_extract_dirname(dev_file_name, file_dir); - do { - if(!storage_simply_mkdir(storage, string_get_cstr(file_dir))) { - FURI_LOG_E(TAG, "(save) Cannot mkdir"); - break; - } - - if(!storage_simply_remove(storage, dev_file_name)) { - FURI_LOG_E(TAG, "(save) Cannot remove"); - break; - } - - stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); - stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); - - saved = true; - FURI_LOG_D(TAG, "(save) OK Save"); - } while(0); - string_clear(file_dir); - furi_record_close(RECORD_STORAGE); - return saved; -} - -void custom_callback(SubBruteState* context) { - if(strcmp(context->file_name_tmp, "")) { - string_cat_printf(context->file_path, "/%s%s", context->file_name_tmp, ".sub"); - if(subbrute_path_is_file(context->file_path_tmp)) { - context->current_scene = SceneAttack; - return; //false; - - } else { - subbrute_save_protocol_to_file(context->stream, string_get_cstr(context->file_path)); - } - - string_set_str(context->file_path, EXT_PATH("subghz")); - string_reset(context->file_path_tmp); - - //scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); - context->current_scene = SceneAttack; - return; //true; - } else { - //error no file name - context->current_scene = SceneAttack; - return; //true; - } -} - -void subbrute_scene_save_name_text_input_callback(void* context) { - furi_assert(context); - SubBruteState* statee = context; - custom_callback(statee); -} - -void subbrute_scene_save_name_on_tick(SubBruteState* context) { - if(backpressed) { - void* validator_context = text_input_get_validator_callback_context(context->text_input); - text_input_set_validator(context->text_input, NULL, NULL); - validator_is_file_free(validator_context); - - // Clear view - text_input_reset(context->text_input); - - // TextInput - view_dispatcher_remove_view(context->view_dispatcher, 0); - text_input_free(context->text_input); - - // Popup - view_dispatcher_remove_view(context->view_dispatcher, 1); - popup_free(context->popup); - - context->current_scene = SceneAttack; - } -} - -bool subbrute_back_event_callback(void* context) { - UNUSED(context); - backpressed = true; - return true; -} - -void subbrute_scene_save_name_on_enter(SubBruteState* context) { - // Text Input - context->text_input = text_input_alloc(); - view_dispatcher_add_view( - context->view_dispatcher, 0, text_input_get_view(context->text_input)); - - // Popup - context->popup = popup_alloc(); - view_dispatcher_add_view(context->view_dispatcher, 1, popup_get_view(context->popup)); - - // Setup view - TextInput* text_input = context->text_input; - bool dev_name_empty = false; - - string_t file_name; - string_t dir_name; - string_init(file_name); - string_init(dir_name); - - if(!subbrute_path_is_file(context->file_path)) { - char file_name_buf[64] = {0}; - set_random_name(file_name_buf, 64); - string_set_str(file_name, file_name_buf); - string_set_str(context->file_path, EXT_PATH("subghz")); - //highlighting the entire filename by default - dev_name_empty = true; - } else { - string_set(context->file_path_tmp, context->file_path); - path_extract_dirname(string_get_cstr(context->file_path), dir_name); - path_extract_filename(context->file_path, file_name, true); - string_set(context->file_path, dir_name); - } - - strncpy(context->file_name_tmp, string_get_cstr(file_name), 64); - text_input_set_header_text(text_input, "Name signal"); - text_input_set_result_callback( - text_input, - subbrute_scene_save_name_text_input_callback, - context, - context->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size - dev_name_empty); - - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(string_get_cstr(context->file_path), ".sub", ""); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - string_clear(file_name); - string_clear(dir_name); - - view_dispatcher_set_navigation_event_callback( - context->view_dispatcher, subbrute_back_event_callback); - - view_dispatcher_switch_to_view(context->view_dispatcher, 0); -} - -void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context) { - UNUSED(context); - if(event.evt_type == EventTypeKey) { - if(event.input_type == InputTypeShort) { - switch(event.key) { - case InputKeyDown: - case InputKeyUp: - case InputKeyLeft: - case InputKeyRight: - case InputKeyOk: - break; - case InputKeyBack: - //context->current_scene = SceneAttack; - break; - } - } - } -} - -void subbrute_scene_save_name_on_exit(SubBruteState* context) { - if(!backpressed) { - // Clear validator - void* validator_context = text_input_get_validator_callback_context(context->text_input); - text_input_set_validator(context->text_input, NULL, NULL); - validator_is_file_free(validator_context); - - // Clear view - text_input_reset(context->text_input); - - // Setup view - Popup* popup = context->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, context); - popup_set_callback(popup, NULL); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(context->view_dispatcher, 1); - - furi_delay_ms(1050); - // Clear view - //Popup* popup = subghz->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - popup_set_callback(popup, NULL); - popup_set_context(popup, NULL); - popup_set_timeout(popup, 0); - popup_disable_timeout(popup); - - // TextInput - view_dispatcher_remove_view(context->view_dispatcher, 0); - text_input_free(context->text_input); - - // Popup - view_dispatcher_remove_view(context->view_dispatcher, 1); - popup_free(context->popup); - } else { - backpressed = false; - } -} \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_save_name.h b/applications/plugins/subbrute/scene/subbrute_scene_save_name.h deleted file mode 100644 index 18a931ad8..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_save_name.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "../subbrute.h" - -void subbrute_scene_save_name_on_enter(SubBruteState* context); -void subbrute_scene_save_name_on_exit(SubBruteState* context); -void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context); -void subbrute_scene_save_name_on_tick(SubBruteState* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/scene/subbrute_scene_select_field.c b/applications/plugins/subbrute/scene/subbrute_scene_select_field.c deleted file mode 100644 index c65cd1663..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_select_field.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "subbrute_scene_select_field.h" - -void center_displayed_key(SubBruteState* context, uint8_t index) { - const char* key_cstr = string_get_cstr(context->key); - uint8_t str_index = (index * 3); - - char display_menu[17] = { - 'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'}; - - if(index > 1) { - display_menu[0] = key_cstr[str_index - 6]; - display_menu[1] = key_cstr[str_index - 5]; - } else { - display_menu[0] = ' '; - display_menu[1] = ' '; - } - - if(index > 0) { - display_menu[3] = key_cstr[str_index - 3]; - display_menu[4] = key_cstr[str_index - 2]; - } else { - display_menu[3] = ' '; - display_menu[4] = ' '; - } - - display_menu[7] = key_cstr[str_index]; - display_menu[8] = key_cstr[str_index + 1]; - - if((str_index + 4) <= (uint8_t)strlen(key_cstr)) { - display_menu[11] = key_cstr[str_index + 3]; - display_menu[12] = key_cstr[str_index + 4]; - } else { - display_menu[11] = ' '; - display_menu[12] = ' '; - } - - if((str_index + 8) <= (uint8_t)strlen(key_cstr)) { - display_menu[14] = key_cstr[str_index + 6]; - display_menu[15] = key_cstr[str_index + 7]; - } else { - display_menu[14] = ' '; - display_menu[15] = ' '; - } - - string_reset(context->notification_msg); - string_set_str(context->notification_msg, display_menu); -} - -void subbrute_scene_select_field_on_enter(SubBruteState* context) { - string_clear(context->notification_msg); -} - -void subbrute_scene_select_field_on_exit(SubBruteState* context) { - UNUSED(context); -} - -void subbrute_scene_select_field_on_tick(SubBruteState* context) { - UNUSED(context); -} - -void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context) { - if(event.evt_type == EventTypeKey) { - if(event.input_type == InputTypeShort) { - //const char* key_cstr = string_get_cstr(context->key); - - // don't look, it's ugly but I'm a python dev so... - /*uint8_t nb_bytes = 0; - for(uint8_t i = 0; i < strlen(key_cstr); i++) { - if(' ' == key_cstr[i]) { - nb_bytes++; - } - }*/ - - switch(event.key) { - case InputKeyDown: - case InputKeyUp: - break; - case InputKeyLeft: - if(context->key_index > 0) { - context->key_index--; - } - break; - case InputKeyRight: - if(context->key_index < 7) { - context->key_index++; - } - break; - case InputKeyOk: - string_reset(context->notification_msg); - context->current_scene = SceneAttack; - break; - case InputKeyBack: - string_reset(context->notification_msg); - context->current_scene = SceneSelectFile; - break; - } - //FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes); - } - } -} - -void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context) { - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - // Frame - //canvas_draw_frame(canvas, 0, 0, 128, 64); - - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "use < > to select field"); - - char msg_index[18]; - snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index); - canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index); - - center_displayed_key(context, context->key_index); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg)); -} diff --git a/applications/plugins/subbrute/scene/subbrute_scene_select_field.h b/applications/plugins/subbrute/scene/subbrute_scene_select_field.h deleted file mode 100644 index e02a07ee0..000000000 --- a/applications/plugins/subbrute/scene/subbrute_scene_select_field.h +++ /dev/null @@ -1,8 +0,0 @@ -#include "../subbrute.h" - -void subbrute_scene_select_field_on_enter(SubBruteState* context); -void subbrute_scene_select_field_on_exit(SubBruteState* context); -void subbrute_scene_select_field_on_tick(SubBruteState* context); -void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context); -void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context); -void center_displayed_key(SubBruteState* context, uint8_t index); \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene.h b/applications/plugins/subbrute/scenes/subbrute_scene.h new file mode 100644 index 000000000..c048985e2 --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) SubBruteScene##id, +typedef enum { +#include "subbrute_scene_config.h" + SubBruteSceneNum, +} SubBruteScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers subbrute_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "subbrute_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "subbrute_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "subbrute_scene_config.h" +#undef ADD_SCENE diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_config.h b/applications/plugins/subbrute/scenes/subbrute_scene_config.h new file mode 100644 index 000000000..40806279f --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene_config.h @@ -0,0 +1,6 @@ +ADD_SCENE(subbrute, load_file, LoadFile) +ADD_SCENE(subbrute, run_attack, RunAttack) +ADD_SCENE(subbrute, save_name, SaveName) +ADD_SCENE(subbrute, save_success, SaveSuccess) +ADD_SCENE(subbrute, setup_attack, SetupAttack) +ADD_SCENE(subbrute, start, Start) \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c b/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c new file mode 100644 index 000000000..0fecb5b6e --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c @@ -0,0 +1,61 @@ +#include +#include "../subbrute_i.h" +#include "../subbrute_custom_event.h" +#include "../views/subbrute_main_view.h" + +//void subbrute_scene_load_file_callback(SubBruteCustomEvent event, void* context) { +//// furi_assert(context); +//// +//// SubBruteState* instance = (SubBruteState*)context; +//// view_dispatcher_send_custom_event(instance->view_dispatcher, event); +//} + +void subbrute_scene_load_file_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + string_t file_path; + string_init(file_path); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, SUBBRUTE_FILE_EXT, &I_sub1_10px); + + // Input events and views are managed by file_select + bool res = dialog_file_browser_show( + instance->dialogs, + instance->device->load_path, + instance->device->load_path, + &browser_options); + + if(res) { + SubBruteFileResult load_result = subbrute_device_load_protocol_from_file(instance->device); + if(load_result == SubBruteFileResultOk) { + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneSetupAttack); + } else { + string_t dialog_msg; + string_init(dialog_msg); + string_cat_printf( + dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result)); + dialog_message_show_storage_error(instance->dialogs, string_get_cstr(dialog_msg)); + string_clear(dialog_msg); + res = false; + } + } + + string_clear(file_path); + + if(!res) { + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneLoadFile); + } +} + +void subbrute_scene_load_file_on_exit(void* context) { + UNUSED(context); +} + +bool subbrute_scene_load_file_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c b/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c new file mode 100644 index 000000000..59c5b8ef0 --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c @@ -0,0 +1,158 @@ +#include "../subbrute_i.h" +#include "../subbrute_custom_event.h" +#include "../views/subbrute_attack_view.h" + +static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + view_dispatcher_send_custom_event(instance->view_dispatcher, event); +} + +void subbrute_scene_run_attack_on_exit(void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + notification_message(instance->notifications, &sequence_blink_stop); +} + +void subbrute_scene_run_attack_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView* view = instance->view_attack; + + instance->current_view = SubBruteViewAttack; + subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance); + view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); + + subbrute_attack_view_init_values( + view, + (uint8_t)instance->device->attack, + instance->device->max_value, + instance->device->key_index); + + // Start worker if not started + subbrute_attack_view_start_worker( + view, + instance->device->frequency, + instance->device->preset, + instance->device->protocol_name); +} + +bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView* view = instance->view_attack; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubBruteCustomEventTypeTransmitNotStarted || + event.event == SubBruteCustomEventTypeTransmitFinished || + event.event == SubBruteCustomEventTypeBackPressed) { + // Stop transmit + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeTick) { + if(subbrute_attack_view_can_send(view)) { + // Blink + notification_message(instance->notifications, &sequence_blink_yellow_100); + + if(subbrute_attack_view_transmit(view, instance->device->payload)) { + // Make payload for new iteration or exit + if(instance->device->key_index + 1 > instance->device->max_value) { + // End of list + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); + } else { + instance->device->key_index++; + subbrute_attack_view_set_current_step(view, instance->device->key_index); + subbrute_device_create_packet_parsed( + instance->device, instance->device->key_index); + } + } + + // Stop + notification_message(instance->notifications, &sequence_blink_stop); + } + + consumed = true; + } + + return consumed; + + // if(event.evt_type == EventTypeKey) { + // if(event.input_type == InputTypeShort) { + // switch(event.key) { + // case InputKeyDown: + // break; + // case InputKeyUp: + // if(!context->is_attacking) { + // subbrute_send_packet_parsed(context); + // string_clear(context->flipper_format_string); + // toSave = true; + // context->current_scene = SceneSaveName; + // } + // break; + // case InputKeyLeft: + // if(!context->is_attacking && context->payload > 0x00) { + // context->payload--; + // subbrute_send_packet(context); + // notification_message(context->notify, &sequence_blink_blue_10); + // } else if(!context->is_attacking && context->payload == 0x00) { + // context->payload = max_value; + // subbrute_send_packet(context); + // notification_message(context->notify, &sequence_blink_blue_10); + // } + // break; + // case InputKeyRight: + // if(!context->is_attacking && context->payload < max_value) { + // context->payload++; + // subbrute_send_packet(context); + // notification_message(context->notify, &sequence_blink_blue_10); + // } else if(!context->is_attacking && context->payload == max_value) { + // context->payload = 0x00; + // subbrute_send_packet(context); + // notification_message(context->notify, &sequence_blink_blue_10); + // } + // break; + // case InputKeyOk: + // if(!context->is_attacking) { + // if(context->payload == max_value) { + // context->payload = 0x00; + // //subbrute_counter = 0; + // } + // context->is_attacking = true; + // start_bruthread(context); + // notification_message(context->notify, &sequence_blink_start_blue); + // } else { + // context->is_attacking = false; + // //context->close_thread_please = true; + // if(context->is_thread_running && context->bruthread) { + // furi_thread_join(context->bruthread); // wait until thread is finished + // } + // //context->close_thread_please = false; + // notification_message(context->notify, &sequence_blink_stop); + // notification_message(context->notify, &sequence_single_vibro); + // } + // break; + // case InputKeyBack: + // locked = false; + // //context->close_thread_please = true; + // context->is_attacking = false; + // if(context->is_thread_running && context->bruthread) { + // furi_thread_join(context->bruthread); // wait until thread is finished + // } + // //context->close_thread_please = false; + // string_reset(context->notification_msg); + // context->payload = 0x00; + // //subbrute_counter = 0; + // notification_message(context->notify, &sequence_blink_stop); + // if(context->attack == SubBruteAttackLoadFile) { + // context->current_scene = SceneSelectField; + // } else { + // context->current_scene = SceneEntryPoint; + // } + // break; + // } + // } + // } +} diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_save_name.c b/applications/plugins/subbrute/scenes/subbrute_scene_save_name.c new file mode 100644 index 000000000..0400bbe5a --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene_save_name.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include + +#include "../subbrute_i.h" +#include "../subbrute_custom_event.h" +#include "../views/subbrute_attack_view.h" + +#define TAG "SubBruteSceneSaveFile" + +void subbrute_scene_save_name_on_enter(void* context) { + SubBruteState* instance = (SubBruteState*)context; + + // Setup view + TextInput* text_input = instance->text_input; + set_random_name(instance->device->text_store, sizeof(instance->device->text_store)); + + text_input_set_header_text(text_input, "Name of file"); + text_input_set_result_callback( + text_input, + subbrute_text_input_callback, + instance, + instance->device->text_store, + SUBBRUTE_MAX_LEN_NAME, + true); + + string_t folder_path; + string_init(folder_path); + + SubBruteDevice* device = instance->device; + if(string_end_with_str_p(device->load_path, SUBBRUTE_FILE_EXT)) { + path_extract_dirname(string_get_cstr(device->load_path), folder_path); + } else { + string_set_str(folder_path, SUBBRUTE_PATH); + } + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(string_get_cstr(folder_path), SUBBRUTE_FILE_EXT, TAG); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewTextInput); + + string_clear(folder_path); +} + +bool subbrute_scene_save_name_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom && + event.event == SubBruteCustomEventTypeTextEditDone) { + if(subbrute_device_save_file(instance->device, instance->device->text_store)) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveSuccess); + consumed = true; + } else { + dialog_message_show_storage_error(instance->dialogs, "Error during saving!"); + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneSetupAttack); + } + } + return consumed; +} + +void subbrute_scene_save_name_on_exit(void* context) { + SubBruteState* instance = (SubBruteState*)context; + + // Clear view + void* validator_context = text_input_get_validator_callback_context(instance->text_input); + text_input_set_validator(instance->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + text_input_reset(instance->text_input); +} diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c b/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c new file mode 100644 index 000000000..5f12c23c6 --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c @@ -0,0 +1,59 @@ +#include "../subbrute_i.h" +#include "../subbrute_custom_event.h" +#include "../views/subbrute_attack_view.h" + +void subbrute_scene_save_success_callback(void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeSaveSuccess); +} + +void subbrute_scene_save_success_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = context; + + // Setup view + Popup* popup = instance->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, instance); + popup_set_callback(popup, subbrute_scene_save_success_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewPopup); +} + +bool subbrute_scene_save_success_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + //SubBruteMainView* view = instance->view_main; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubBruteCustomEventTypeSaveSuccess) { + if(!scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, SubBruteSceneSetupAttack)) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); + } + return true; + } + } + return false; +} + +void subbrute_scene_save_success_on_exit(void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + + // Clear view + Popup* popup = instance->popup; + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + popup_set_callback(popup, NULL); + popup_set_context(popup, NULL); + popup_set_timeout(popup, 0); + popup_disable_timeout(popup); +} diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c b/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c new file mode 100644 index 000000000..cc764b6ec --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c @@ -0,0 +1,96 @@ +#include "../subbrute_i.h" +#include "../subbrute_custom_event.h" +#include "../views/subbrute_attack_view.h" + +static void subbrute_scene_setup_attack_callback(SubBruteCustomEvent event, void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + view_dispatcher_send_custom_event(instance->view_dispatcher, event); +} + +void subbrute_scene_setup_attack_on_enter(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView* view = instance->view_attack; + + instance->current_view = SubBruteViewAttack; + subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance); + view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); + + instance->device->key_index = subbrute_attack_view_get_current_step(view); + subbrute_attack_view_init_values( + view, + (uint8_t)instance->device->attack, + instance->device->max_value, + instance->device->key_index); + + // Run worker anyway + subbrute_attack_view_start_worker( + view, + instance->device->frequency, + instance->device->preset, + instance->device->protocol_name); +} + +void subbrute_scene_setup_attack_on_exit(void* context) { + furi_assert(context); + SubBruteState* instance = (SubBruteState*)context; + notification_message(instance->notifications, &sequence_blink_stop); +} + +bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + SubBruteAttackView * view = instance->view_attack; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubBruteCustomEventTypeTransmitStarted) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack); + } else if (event.event == SubBruteCustomEventTypeBackPressed) { + subbrute_attack_view_stop_worker(view); + scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); + } else if (event.event == SubBruteCustomEventTypeChangeStep) { + instance->device->key_index = subbrute_attack_view_get_current_step(view); + } else if(event.event == SubBruteCustomEventTypeTransmitCustom) { + if(subbrute_attack_view_can_send(view)) { + // Blink + notification_message(instance->notifications, &sequence_blink_green_100); + + subbrute_device_create_packet_parsed( + instance->device, instance->device->key_index); + subbrute_attack_view_transmit(view, instance->device->payload); + + // Stop + notification_message(instance->notifications, &sequence_blink_stop); + } + } + + consumed = true; + } + + // if(event.type == SceneManagerEventTypeCustom) { + // switch(event.event) { + // case SubBruteCustomEventTypeMenuSelected: + // with_view_model( + // view, (SubBruteMainViewModel * model) { + // instance->menu_index = model->index; + // return false; + // }); + // scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); + // consumed = true; + // break; + // case SubBruteCustomEventTypeLoadFile: + // with_view_model( + // view, (SubBruteMainViewModel * model) { + // instance->menu_index = model->index; + // return false; + // }); + // scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); + // consumed = true; + // break; + // } + // } + + return consumed; +} \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_start.c b/applications/plugins/subbrute/scenes/subbrute_scene_start.c new file mode 100644 index 000000000..ffc976c61 --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbrute_scene_start.c @@ -0,0 +1,50 @@ +#include "../subbrute_i.h" +#include "../subbrute_custom_event.h" +#include "../views/subbrute_main_view.h" + +void subbrute_scene_start_callback(SubBruteCustomEvent event, void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + view_dispatcher_send_custom_event(instance->view_dispatcher, event); +} + +void subbrute_scene_start_on_enter(void* context) { + furi_assert(context); + + SubBruteState* instance = (SubBruteState*)context; + SubBruteMainView* view = instance->view_main; + + instance->current_view = SubBruteViewMain; + subbrute_main_view_set_callback(view, + subbrute_scene_start_callback, + instance); + + view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); + subbrute_main_view_set_index(view, (uint8_t)instance->device->attack); +} + +void subbrute_scene_start_on_exit(void* context) { + UNUSED(context); +} + +bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) { + SubBruteState* instance = (SubBruteState*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom && event.event == SubBruteCustomEventTypeMenuSelected) { + //subbrute_device_attack_set + SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main); + + if (attack == SubBruteAttackLoadFile) { + scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); + } else { + subbrute_device_attack_set(instance->device, attack, NULL); + scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); + } + + consumed = true; + } + + return consumed; +} \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbute_scene.c b/applications/plugins/subbrute/scenes/subbute_scene.c new file mode 100644 index 000000000..6d9ba9799 --- /dev/null +++ b/applications/plugins/subbrute/scenes/subbute_scene.c @@ -0,0 +1,30 @@ +#include "subbrute_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const subbrute_on_enter_handlers[])(void*) = { +#include "subbrute_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const subbrute_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "subbrute_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const subbrute_on_exit_handlers[])(void* context) = { +#include "subbrute_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers subbrute_scene_handlers = { + .on_enter_handlers = subbrute_on_enter_handlers, + .on_event_handlers = subbrute_on_event_handlers, + .on_exit_handlers = subbrute_on_exit_handlers, + .scene_num = SubBruteSceneNum, +}; diff --git a/applications/plugins/subbrute/subbrute.c b/applications/plugins/subbrute/subbrute.c index e8f447c5e..e2f19916a 100644 --- a/applications/plugins/subbrute/subbrute.c +++ b/applications/plugins/subbrute/subbrute.c @@ -1,267 +1,239 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + #include "subbrute.h" +#include "subbrute_i.h" +#include "subbrute_custom_event.h" -#include "scene/subbrute_scene_load_file.h" -#include "scene/subbrute_scene_select_field.h" -#include "scene/subbrute_scene_run_attack.h" -#include "scene/subbrute_scene_entrypoint.h" -#include "scene/subbrute_scene_save_name.h" +#define TAG "SubBruteApp" -static void draw_callback(Canvas* const canvas, void* ctx) { - SubBruteState* subbrute_state = (SubBruteState*)acquire_mutex((ValueMutex*)ctx, 100); +static const char* subbrute_menu_names[] = { + [SubBruteAttackNone] = "None", + [SubBruteAttackCAME12bit307] = "CAME 12bit 307mhz", + [SubBruteAttackCAME12bit433] = "CAME 12bit 433mhz", + [SubBruteAttackCAME12bit868] = "CAME 12bit 868mhz", + [SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315mhz", + [SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390mhz", + [SubBruteAttackLinear10bit300] = "Linear 10bit 300mhz", + [SubBruteAttackLinear10bit310] = "Linear 10bit 310mhz", + [SubBruteAttackNICE12bit433] = "NICE 12bit 433mhz", + [SubBruteAttackNICE12bit868] = "NICE 12bit 868mhz", + [SubBruteAttackLoadFile] = "BF existing dump", + [SubBruteAttackTotalCount] = "Total Count", +}; - if(subbrute_state == NULL) { - return; - } - - // Draw correct Canvas - switch(subbrute_state->current_scene) { - case NoneScene: - case SceneSelectFile: - subbrute_scene_load_file_on_draw(canvas, subbrute_state); - break; - case SceneSelectField: - subbrute_scene_select_field_on_draw(canvas, subbrute_state); - break; - case SceneAttack: - subbrute_scene_run_attack_on_draw(canvas, subbrute_state); - break; - case SceneEntryPoint: - subbrute_scene_entrypoint_on_draw(canvas, subbrute_state); - break; - case SceneSaveName: - break; - } - - release_mutex((ValueMutex*)ctx, subbrute_state); +bool subbrute_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + SubBruteState* instance = context; + return scene_manager_handle_custom_event(instance->scene_manager, event); } -void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - SubBruteEvent event = { - .evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type}; - furi_message_queue_put(event_queue, &event, 100); +bool subbrute_back_event_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + return scene_manager_handle_back_event(instance->scene_manager); } -static void timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - SubBruteEvent event = { - .evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease}; - furi_message_queue_put(event_queue, &event, 100); +void subbrute_tick_event_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + scene_manager_handle_tick_event(instance->scene_manager); } SubBruteState* subbrute_alloc() { - SubBruteState* subbrute = malloc(sizeof(SubBruteState)); + SubBruteState* instance = malloc(sizeof(SubBruteState)); - string_init(subbrute->protocol); - string_init(subbrute->preset); - string_init(subbrute->file_path); - string_init(subbrute->file_path_tmp); - string_init_set(subbrute->notification_msg, ""); - string_init(subbrute->candidate); - string_init(subbrute->flipper_format_string); + instance->scene_manager = scene_manager_alloc(&subbrute_scene_handlers, instance); + instance->view_dispatcher = view_dispatcher_alloc(); - subbrute->previous_scene = NoneScene; - subbrute->current_scene = SceneSelectFile; - subbrute->is_running = true; - subbrute->is_attacking = false; - subbrute->key_index = 7; - subbrute->notify = furi_record_open(RECORD_NOTIFICATION); + view_dispatcher_enable_queue(instance->view_dispatcher); + view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); + view_dispatcher_set_custom_event_callback( + instance->view_dispatcher, subbrute_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + instance->view_dispatcher, subbrute_back_event_callback); + view_dispatcher_set_tick_event_callback( + instance->view_dispatcher, subbrute_tick_event_callback, 100); - subbrute->view_dispatcher = view_dispatcher_alloc(); + // Devices + instance->device = subbrute_device_alloc(); + + instance->gui = furi_record_open(RECORD_GUI); + instance->dialogs = furi_record_open(RECORD_DIALOGS); + instance->notifications = furi_record_open(RECORD_NOTIFICATION); + instance->view_dispatcher = view_dispatcher_alloc(); //Dialog - subbrute->dialogs = furi_record_open(RECORD_DIALOGS); + instance->dialogs = furi_record_open(RECORD_DIALOGS); - subbrute->preset_def = malloc(sizeof(SubGhzPresetDefinition)); + // TextInput + instance->text_input = text_input_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, SubBruteViewTextInput, text_input_get_view(instance->text_input)); + + // Custom Widget + instance->widget = widget_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, SubBruteViewWidget, widget_get_view(instance->widget)); - //subbrute->flipper_format = flipper_format_string_alloc(); - //subbrute->environment = subghz_environment_alloc(); + // Popup + instance->popup = popup_alloc(); + view_dispatcher_add_view(instance->view_dispatcher, SubBruteViewPopup, popup_get_view(instance->popup)); - return subbrute; + // ViewStack + instance->view_stack = view_stack_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, SubBruteViewStack, view_stack_get_view(instance->view_stack)); + + // SubBruteMainView + instance->view_main = subbrute_main_view_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, + SubBruteViewMain, + subbrute_main_view_get_view(instance->view_main)); + + // SubBruteAttackView + instance->view_attack = subbrute_attack_view_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, + SubBruteViewAttack, + subbrute_attack_view_get_view(instance->view_attack)); + + // Loading + instance->loading = loading_alloc(); + //instance->flipper_format = flipper_format_string_alloc(); + //instance->environment = subghz_environment_alloc(); + + return instance; } -void subbrute_free(SubBruteState* subbrute) { +void subbrute_free(SubBruteState* instance) { + furi_assert(instance); + + // Notifications + notification_message(instance->notifications, &sequence_blink_stop); + furi_record_close(RECORD_NOTIFICATION); + instance->notifications = NULL; + + // Loading + loading_free(instance->loading); + + // View Main + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewMain); + subbrute_main_view_free(instance->view_main); + + // View Attack + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewAttack); + subbrute_attack_view_free(instance->view_attack); + + // TextInput + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewTextInput); + text_input_free(instance->text_input); + + // Custom Widget + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewWidget); + widget_free(instance->widget); + + // Popup + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewPopup); + popup_free(instance->popup); + + // ViewStack + view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewStack); + view_stack_free(instance->view_stack); + //Dialog furi_record_close(RECORD_DIALOGS); - notification_message(subbrute->notify, &sequence_blink_stop); + // Scene manager + scene_manager_free(instance->scene_manager); - furi_record_close(RECORD_NOTIFICATION); + // View Dispatcher + view_dispatcher_free(instance->view_dispatcher); - view_dispatcher_free(subbrute->view_dispatcher); + // GUI + furi_record_close(RECORD_GUI); + instance->gui = NULL; - string_clear(subbrute->preset); - string_clear(subbrute->candidate); - - // Path strings - string_clear(subbrute->file_path); - string_clear(subbrute->file_path_tmp); - string_clear(subbrute->notification_msg); - string_clear(subbrute->candidate); - string_clear(subbrute->flipper_format_string); - - //flipper_format_free(subbrute->flipper_format); - //subghz_environment_free(subbrute->environment); - //subghz_receiver_free(subbrute->receiver); - - free(subbrute->preset_def); + // SubBruteDevice + subbrute_device_free(instance->device); // The rest - free(subbrute); + free(instance); +} + +void subbrute_show_loading_popup(void* context, bool show) { + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + SubBruteState* instance = context; + ViewStack* view_stack = instance->view_stack; + Loading* loading = instance->loading; + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_stack_add_view(view_stack, loading_get_view(loading)); + } else { + view_stack_remove_view(view_stack, loading_get_view(loading)); + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + +void subbrute_text_input_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + view_dispatcher_send_custom_event( + instance->view_dispatcher, SubBruteCustomEventTypeTextEditResult); +} + +void subbrute_popup_closed_callback(void* context) { + furi_assert(context); + SubBruteState* instance = context; + view_dispatcher_send_custom_event( + instance->view_dispatcher, SubBruteCustomEventTypePopupClosed); +} + +const char* subbrute_get_menu_name(SubBruteAttacks index) { + furi_assert(index < SubBruteAttackTotalCount - 1); + + return subbrute_menu_names[index]; } // ENTRYPOINT -int32_t subbrute_start(void* p) { +int32_t subbrute_app(void* p) { UNUSED(p); - // Input - FURI_LOG_I(TAG, "Initializing input"); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SubBruteEvent)); - SubBruteState* subbrute_state = subbrute_alloc(); - ValueMutex subbrute_state_mutex; - - // Mutex - FURI_LOG_I(TAG, "Initializing flipfrid mutex"); - if(!init_mutex(&subbrute_state_mutex, subbrute_state, sizeof(SubBruteState))) { - FURI_LOG_E(TAG, "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - subbrute_free(subbrute_state); - return 255; - } - - furi_hal_power_suppress_charge_enter(); - - // Configure view port - FURI_LOG_I(TAG, "Initializing viewport"); - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, draw_callback, &subbrute_state_mutex); - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Configure timer - FURI_LOG_I(TAG, "Initializing timer"); - FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second - - // Register view port in GUI - FURI_LOG_I(TAG, "Initializing gui"); - subbrute_state->gui = furi_record_open(RECORD_GUI); - gui_add_view_port(subbrute_state->gui, view_port, GuiLayerFullscreen); + SubBruteState* instance = subbrute_alloc(); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Starting subbrute_alloc done"); +#endif view_dispatcher_attach_to_gui( - subbrute_state->view_dispatcher, subbrute_state->gui, ViewDispatcherTypeFullscreen); - - subbrute_state->current_scene = SceneEntryPoint; - - // Init values - SubBruteEvent event; - while(subbrute_state->is_running) { - // Get next event - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25); - if(event_status == FuriStatusOk) { - if(event.evt_type == EventTypeKey) { - //Handle event key - FURI_LOG_D(TAG, "EVENT ###"); - switch(subbrute_state->current_scene) { - case SceneSelectFile: - subbrute_scene_load_file_on_event(event, subbrute_state); - break; - case SceneSelectField: - subbrute_scene_select_field_on_event(event, subbrute_state); - break; - case SceneSaveName: - subbrute_scene_save_name_on_event(event, subbrute_state); - break; - case SceneAttack: - subbrute_scene_run_attack_on_event(event, subbrute_state); - break; - case NoneScene: - case SceneEntryPoint: - subbrute_scene_entrypoint_on_event(event, subbrute_state); - break; - } - - } else if(event.evt_type == EventTypeTick) { - //Handle event tick - if(subbrute_state->current_scene != subbrute_state->previous_scene) { - // Trigger Exit Scene - switch(subbrute_state->previous_scene) { - case SceneSelectFile: - subbrute_scene_load_file_on_exit(subbrute_state); - break; - case SceneSelectField: - subbrute_scene_select_field_on_exit(subbrute_state); - break; - case SceneAttack: - subbrute_scene_run_attack_on_exit(subbrute_state); - break; - case SceneEntryPoint: - subbrute_scene_entrypoint_on_exit(subbrute_state); - break; - case SceneSaveName: - subbrute_scene_save_name_on_exit(subbrute_state); - break; - case NoneScene: - break; - } - - // Trigger Entry Scene - switch(subbrute_state->current_scene) { - case NoneScene: - case SceneSelectFile: - subbrute_scene_load_file_on_enter(subbrute_state); - break; - case SceneSelectField: - subbrute_scene_select_field_on_enter(subbrute_state); - break; - case SceneAttack: - subbrute_scene_run_attack_on_enter(subbrute_state); - break; - case SceneSaveName: - subbrute_scene_save_name_on_enter(subbrute_state); - break; - case SceneEntryPoint: - subbrute_scene_entrypoint_on_enter(subbrute_state); - break; - } - subbrute_state->previous_scene = subbrute_state->current_scene; - } - - // Trigger Tick Scene - switch(subbrute_state->current_scene) { - case NoneScene: - case SceneSelectFile: - subbrute_scene_load_file_on_tick(subbrute_state); - break; - case SceneSelectField: - subbrute_scene_select_field_on_tick(subbrute_state); - break; - case SceneAttack: - //subbrute_scene_run_attack_on_tick(subbrute_state); - break; - case SceneEntryPoint: - subbrute_scene_entrypoint_on_tick(subbrute_state); - break; - case SceneSaveName: - subbrute_scene_save_name_on_tick(subbrute_state); - break; - } - view_port_update(view_port); - } - } - } - - // Cleanup - furi_timer_stop(timer); - furi_timer_free(timer); - + instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); + scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "scene_manager_next_scene set"); +#endif + furi_hal_power_suppress_charge_enter(); +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "view_dispatcher_run"); +#endif + view_dispatcher_run(instance->view_dispatcher); furi_hal_power_suppress_charge_exit(); - FURI_LOG_I(TAG, "Cleaning up"); - gui_remove_view_port(subbrute_state->gui, view_port); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_record_close(RECORD_GUI); - subbrute_free(subbrute_state); + subbrute_free(instance); return 0; } \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute.h b/applications/plugins/subbrute/subbrute.h index 76dc45d4b..5fedb9158 100644 --- a/applications/plugins/subbrute/subbrute.h +++ b/applications/plugins/subbrute/subbrute.h @@ -1,110 +1,3 @@ #pragma once -#include -#include -#include -#include -#include "m-string.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TAG "SUBBRUTE" - -typedef enum { - NoneScene, - SceneSelectFile, - SceneSelectField, - SceneAttack, - SceneEntryPoint, - SceneSaveName -} SubBruteScene; - -typedef enum { - SubBruteAttackLoadFile, - SubBruteAttackCAME12bit307, - SubBruteAttackCAME12bit433, - SubBruteAttackCAME12bit868, - SubBruteAttackChamberlain9bit315, - SubBruteAttackChamberlain9bit390, - SubBruteAttackLinear10bit300, - SubBruteAttackLinear10bit310, - SubBruteAttackNICE12bit433, - SubBruteAttackNICE12bit868, -} SubBruteAttacks; - -typedef enum { - EventTypeTick, - EventTypeKey, - EventTypeCustom, -} EventType; - -typedef struct { - EventType evt_type; - InputKey key; - InputType input_type; -} SubBruteEvent; - -// STRUCTS -typedef struct { - // Application stuff - bool is_running; - bool is_attacking; - bool is_thread_running; - bool close_thread_please; - SubBruteScene current_scene; - SubBruteScene previous_scene; - NotificationApp* notify; - Gui* gui; - ViewDispatcher* view_dispatcher; - TextInput* text_input; - Popup* popup; - - // SubGhz Stuff - FuriThread* bruthread; - FlipperFormat* flipper_format; - SubGhzEnvironment* environment; - SubGhzTransmitter* transmitter; - SubGhzReceiver* receiver; - SubGhzProtocolDecoderBase* decoder_result; - SubGhzPresetDefinition* preset_def; - string_t preset; - Stream* stream; - string_t protocol; - uint32_t frequency; - uint32_t frequency_cal; - uint32_t repeat; - uint32_t bit; - string_t key; - uint32_t te; - - // Context Stuff - DialogsApp* dialogs; - char file_name_tmp[64]; - string_t file_path; - string_t file_path_tmp; - string_t notification_msg; - uint8_t key_index; - uint64_t payload; - string_t candidate; - uint8_t str_index; - string_t flipper_format_string; - - SubBruteAttacks attack; - - //Menu stuff - uint8_t menu_index; - - // RAW stuff - string_t subbrute_raw_one; - string_t subbrute_raw_zero; - string_t subbrute_raw_stop; - -} SubBruteState; \ No newline at end of file +typedef struct SubBruteState SubBruteState; \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_custom_event.h b/applications/plugins/subbrute/subbrute_custom_event.h new file mode 100644 index 000000000..6a5a9f08e --- /dev/null +++ b/applications/plugins/subbrute/subbrute_custom_event.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +typedef enum { + // Reserve first 100 events for button types and indexes, starting from 0 + SubBruteCustomEventTypeReserved = 100, + + SubBruteCustomEventTypeBackPressed, + SubBruteCustomEventTypeTextEditResult, + SubBruteCustomEventTypeTransmitStarted, + SubBruteCustomEventTypeTransmitFinished, + SubBruteCustomEventTypeTransmitNotStarted, + SubBruteCustomEventTypeTransmitCustom, + SubBruteCustomEventTypeSaveFile, + SubBruteCustomEventTypeSaveSuccess, + SubBruteCustomEventTypeChangeStep, + + SubBruteCustomEventTypeMenuSelected, + SubBruteCustomEventTypeTextEditDone, + SubBruteCustomEventTypePopupClosed, + + SubBruteCustomEventTypeLoadFile, +} SubBruteCustomEvent; \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_device.c b/applications/plugins/subbrute/subbrute_device.c new file mode 100644 index 000000000..df2a94cd7 --- /dev/null +++ b/applications/plugins/subbrute/subbrute_device.c @@ -0,0 +1,582 @@ +#include "subbrute_device.h" +#include "subbrute_i.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define TAG "SubBruteDevice" + +/** + * List of protocols + */ +static const char* protocol_came = "CAME"; +static const char* protocol_cham_code = "Cham_Code"; +static const char* protocol_linear = "Linear"; +static const char* protocol_nice_flo = "Nice FLO"; +static const char* protocol_princeton = "Princeton"; +static const char* protocol_raw = "RAW"; + +/** + * Values to not use less memory for packet parse operations + */ +static const char* subbrute_key_file_start = + "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\n"; +static const char* subbrute_key_file_key = "Key: %s\n"; +static const char* subbrute_key_file_princeton_end = "TE: %d\n"; + +// Why nobody set in as const in all codebase? +static const char* preset_ook270_async = "FuriHalSubGhzPresetOok270Async"; +static const char* preset_ook650_async = "FuriHalSubGhzPresetOok650Async"; +static const char* preset_2fsk_dev238_async = "FuriHalSubGhzPreset2FSKDev238Async"; +static const char* preset_2fsk_dev476_async = "FuriHalSubGhzPreset2FSKDev476Async"; +static const char* preset_msk99_97_kb_async = "FuriHalSubGhzPresetMSK99_97KbAsync"; +static const char* preset_gfs99_97_kb_async = "FuriHalSubGhzPresetGFS99_97KbAsync"; + +SubBruteDevice* subbrute_device_alloc() { + SubBruteDevice* instance = malloc(sizeof(SubBruteDevice)); + + instance->state = SubBruteDeviceStateIDLE; + instance->key_index = 0; + instance->dialogs = furi_record_open(RECORD_DIALOGS); + + string_init(instance->load_path); + + string_init(instance->payload); + string_init(instance->preset_name); + string_init(instance->protocol_name); + + subbrute_device_attack_set_default_values(instance); + + return instance; +} + +void subbrute_device_free(SubBruteDevice* instance) { + furi_assert(instance); + + furi_record_close(RECORD_DIALOGS); + + string_clear(instance->payload); + string_clear(instance->load_path); + string_clear(instance->preset_name); + string_clear(instance->protocol_name); + + string_clear(instance->load_path); + + free(instance); +} + +SubBruteFileResult subbrute_device_load_protocol_from_file(SubBruteDevice* instance) { + furi_assert(instance); + + // Input events and views are managed by file_browser + string_t app_directory; + string_init_set_str(app_directory, SUBBRUTE_PATH); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, SUBBRUTE_FILE_EXT, &I_sub1_10px); + + SubBruteFileResult load_result = SubBruteFileResultUnknown; + bool res = dialog_file_browser_show( + instance->dialogs, instance->load_path, app_directory, &browser_options); + + string_clear(app_directory); + if(res) { + load_result = subbrute_device_attack_set( + instance, SubBruteAttackLoadFile, string_get_cstr(instance->load_path)); + if(load_result == SubBruteFileResultOk) { + // Ready to run! + instance->state = SubBruteDeviceStateReady; + FURI_LOG_I(TAG, "Ready to run"); + } + } else { + FURI_LOG_I(TAG, "Returned error: %sd", load_result); + // res = false; + // + // char file_info_message[128]; + // snprintf( + // file_info_message, + // sizeof(file_info_message), + // "Can not load file\n%s", + // (char*)subbrute_device_error_get_desc(set_result)); + // dialog_message_show_storage_error(instance->dialogs, file_info_message); + } + + return load_result; +} + +bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) { + furi_assert(instance); + bool result = subbrute_device_create_packet_parsed(instance, instance->key_index); + + if(!result) { + //subbrute_device_notification_message(instance, &sequence_error); + return false; + } + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* stream = buffered_file_stream_alloc(storage); + + result = false; + do { + if(!buffered_file_stream_open(stream, dev_file_name, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) { + buffered_file_stream_close(stream); + break; + } + stream_write_string(stream, instance->payload); + + result = true; + } while(false); + + buffered_file_stream_close(stream); + stream_free(stream); + if(!result) { + //subbrute_device_notification_message(instance, &sequence_error); + } + + furi_record_close(RECORD_STORAGE); + + return result; +} + +const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) { + const char* result; + switch(error_id) { + case(SubBruteFileResultOk): + result = "OK"; + break; + case(SubBruteFileResultErrorOpenFile): + result = "invalid name/path"; + break; + case(SubBruteFileResultMissingOrIncorrectHeader): + result = "Missing or incorrect header"; + break; + case(SubBruteFileResultFrequencyNotAllowed): + result = "Invalid frequency!"; + break; + case(SubBruteFileResultMissingOrIncorrectFrequency): + result = "Missing or incorrect Frequency"; + break; + case(SubBruteFileResultPresetInvalid): + result = "Preset FAIL"; + break; + case(SubBruteFileResultMissingProtocol): + result = "Missing Protocol"; + break; + case(SubBruteFileResultProtocolNotSupported): + result = "RAW unsupported"; + break; + case(SubBruteFileResultDynamicProtocolNotValid): + result = "Dynamic protocol unsupported"; + break; + case(SubBruteFileResultProtocolNotFound): + result = "Protocol not found"; + break; + case(SubBruteFileResultMissingOrIncorrectBit): + result = "Missing or incorrect Bit"; + break; + case(SubBruteFileResultMissingOrIncorrectKey): + result = "Missing or incorrect Key"; + break; + case(SubBruteFileResultMissingOrIncorrectTe): + result = "Missing or incorrect TE"; + break; + case SubBruteFileResultUnknown: + default: + result = "Unknown error"; + break; + } + return result; +} + +bool subbrute_device_create_packet_parsed(SubBruteDevice* instance, uint8_t step) { + furi_assert(instance); + + char step_payload[SUBBRUTE_PAYLOAD_SIZE] = {0}; + string_reset(instance->payload); + + if(instance->attack == SubBruteAttackLoadFile) { + if(step >= sizeof(instance->file_key)) { + return false; + } + snprintf( + step_payload, sizeof(step_payload), "%02X", (uint8_t)instance->file_key[step]); + } else { + //snprintf(step_payload, sizeof(step_payload), "%16X", step); + snprintf(step_payload, sizeof(step_payload), "%02X", step); + } + + FURI_LOG_D(TAG, "step_payload: %s, step: %d", step_payload, step); + + if(instance->has_tail) { + string_init_printf( + instance->payload, + instance->file_template, + step_payload, + instance->te); + } else { + string_init_printf( + instance->payload, instance->file_template, step_payload); + } + + return true; +} + +SubBruteFileResult subbrute_device_attack_set( + SubBruteDevice* instance, + SubBruteAttacks type, + const char* file_path) { + furi_assert(instance); + subbrute_device_attack_set_default_values(instance); + uint8_t file_result; + + switch(type) { + case SubBruteAttackLoadFile: + file_result = subbrute_device_load_from_file(instance, file_path); + if(file_result != SubBruteFileResultOk) { + // Failed load file so failed to set attack type + return file_result; // RETURN + } + break; + case SubBruteAttackCAME12bit307: + case SubBruteAttackCAME12bit433: + case SubBruteAttackCAME12bit868: + if(type == SubBruteAttackCAME12bit307) { + instance->frequency = 307800000; + } else if(type == SubBruteAttackCAME12bit433) { + instance->frequency = 433920000; + } else /* ALWAYS TRUE if(type == SubBruteAttackCAME12bit868) */ { + instance->frequency = 868350000; + } + instance->bit = 12; + string_set_str(instance->protocol_name, protocol_came); + //string_set_str(instance->preset_name, preset_ook650_async); + break; + case SubBruteAttackChamberlain9bit315: + instance->frequency = 315000000; + instance->bit = 9; + string_set_str(instance->protocol_name, protocol_cham_code); + //string_set_str(instance->preset_name, preset_ook650_async); + break; + case SubBruteAttackChamberlain9bit390: + instance->frequency = 390000000; + instance->bit = 9; + string_set_str(instance->protocol_name, protocol_cham_code); + //string_set_str(instance->preset_name, preset_ook650_async); + break; + case SubBruteAttackLinear10bit300: + instance->frequency = 300000000; + instance->bit = 10; + string_set_str(instance->protocol_name, protocol_linear); + //string_set_str(instance->preset_name, preset_ook650_async); + break; + case SubBruteAttackLinear10bit310: + instance->frequency = 310000000; + instance->bit = 10; + string_set_str(instance->protocol_name, protocol_linear); + //string_set_str(instance->preset_name, preset_ook650_async); + break; + case SubBruteAttackNICE12bit433: + instance->frequency = 433920000; + instance->bit = 12; + string_set_str(instance->protocol_name, protocol_nice_flo); + //string_set_str(instance->preset_name, preset_ook650_async); + break; + case SubBruteAttackNICE12bit868: + instance->frequency = 868350000; + instance->bit = 12; + string_set_str(instance->protocol_name, protocol_nice_flo); + //string_set_str(instance->preset_name, preset_ook650_async); + break; + default: + FURI_LOG_E(TAG, "Unknown attack type: %d", type); + return SubBruteFileResultProtocolNotFound; // RETURN + } + + if(!furi_hal_subghz_is_tx_allowed(instance->frequency)) { + FURI_LOG_E(TAG, "Frequency invalid: %d", instance->frequency); + return SubBruteFileResultMissingOrIncorrectFrequency; // RETURN + } + + // For non-file types we didn't set SubGhzProtocolDecoderBase + instance->environment = subghz_environment_alloc(); + instance->receiver = subghz_receiver_alloc_init(instance->environment); + subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); + furi_hal_subghz_reset(); + + uint8_t protocol_check_result = SubBruteFileResultProtocolNotFound; + if(type != SubBruteAttackLoadFile) { + instance->decoder_result = subghz_receiver_search_decoder_base_by_name( + instance->receiver, string_get_cstr(instance->protocol_name)); + + if(!instance->decoder_result || + instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_E(TAG, "Can't load SubGhzProtocolDecoderBase in phase non-file decoder set"); + } else { + protocol_check_result = SubBruteFileResultOk; + } + } else { + // And here we need to set preset enum + instance->preset = subbrute_device_convert_preset(instance->preset_name); + protocol_check_result = SubBruteFileResultOk; + } + + subghz_environment_free(instance->environment); + subghz_receiver_free(instance->receiver); + + if(protocol_check_result != SubBruteFileResultOk) { + return SubBruteFileResultProtocolNotFound; + } + + if(strcmp(string_get_cstr(instance->protocol_name), protocol_princeton) == 0) { + instance->has_tail = true; + } + + // Calc max value + if(instance->attack == SubBruteAttackLoadFile) { + instance->max_value = 0xFF; + } else { + string_t max_value_s; + string_init(max_value_s); + for(uint8_t i = 0; i < instance->bit; i++) { + string_cat_printf(max_value_s, "1"); + } + instance->max_value = (uint64_t)strtol(string_get_cstr(max_value_s), NULL, 2); + string_clear(max_value_s); + } + + // Now we are ready to set file template for using in the future with snprintf + // for sending attack payload + snprintf( + instance->file_template, + sizeof(instance->file_template), + subbrute_key_file_start, + instance->frequency, + string_get_cstr(instance->preset_name), + string_get_cstr(instance->protocol_name), + instance->bit); + strncat( + instance->file_template, + subbrute_key_file_key, + sizeof(instance->file_template)); + if(instance->has_tail) { + strncat( + instance->file_template, + subbrute_key_file_princeton_end, + sizeof(instance->file_template)); + } + + return SubBruteFileResultOk; +} + +uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* file_path) { + furi_assert(instance); + + SubBruteFileResult result = SubBruteFileResultUnknown; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + + string_t temp_str; + string_init(temp_str); + uint32_t temp_data32; + + instance->environment = subghz_environment_alloc(); + instance->receiver = subghz_receiver_alloc_init(instance->environment); + subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable); + furi_hal_subghz_reset(); + + do { + if(!flipper_format_file_open_existing(fff_data_file, file_path)) { + FURI_LOG_E(TAG, "Error open file %s", file_path); + result = SubBruteFileResultErrorOpenFile; + break; + } + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + result = SubBruteFileResultMissingOrIncorrectHeader; + break; + } + + // Frequency + if(flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { + instance->frequency = temp_data32; + if(!furi_hal_subghz_is_tx_allowed(instance->frequency)) { + result = SubBruteFileResultFrequencyNotAllowed; + break; + } + } else { + FURI_LOG_E(TAG, "Missing or incorrect Frequency"); + result = SubBruteFileResultMissingOrIncorrectFrequency; + break; + } + // Preset + if(!flipper_format_read_string(fff_data_file, "Preset", instance->preset_name)) { + FURI_LOG_E(TAG, "Preset FAIL"); + result = SubBruteFileResultPresetInvalid; + } + // Protocol + if(!flipper_format_read_string( + fff_data_file, "Protocol", instance->protocol_name)) { + FURI_LOG_E(TAG, "Missing Protocol"); + result = SubBruteFileResultMissingProtocol; + break; + } +#ifdef FURI_DEBUG + else { + FURI_LOG_D(TAG, "Protocol: %s", string_get_cstr(instance->protocol_name)); + } +#endif + + instance->decoder_result = subghz_receiver_search_decoder_base_by_name( + instance->receiver, string_get_cstr(instance->protocol_name)); + + if(!instance->decoder_result || + strcmp(string_get_cstr(instance->protocol_name), "RAW") == 0) { + FURI_LOG_E(TAG, "RAW unsupported"); + result = SubBruteFileResultProtocolNotSupported; + break; + } + + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + FURI_LOG_E(TAG, "Protocol is dynamic - not supported"); + result = SubBruteFileResultDynamicProtocolNotValid; + break; + } +#ifdef FURI_DEBUG + else { + FURI_LOG_D(TAG, "Decoder: %s", instance->decoder_result->protocol->name); + } +#endif + + // instance->decoder_result = subghz_receiver_search_decoder_base_by_name( + // instance->receiver, string_get_cstr(instance->protocol_name)); + // + // if(!instance->decoder_result) { + // FURI_LOG_E(TAG, "Protocol not found"); + // result = SubBruteFileResultProtocolNotFound; + // break; + // } + + // Bit + if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) { + FURI_LOG_E(TAG, "Missing or incorrect Bit"); + result = SubBruteFileResultMissingOrIncorrectBit; + break; + } else { + instance->bit = temp_data32; + } + + // Key + if(!flipper_format_read_string(fff_data_file, "Key", temp_str)) { + FURI_LOG_E(TAG, "Missing or incorrect Key"); + result = SubBruteFileResultMissingOrIncorrectKey; + break; + } else { + snprintf( + instance->file_key, + sizeof(instance->file_key), + "%s", + string_get_cstr(temp_str)); + } + + // TE + if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) { + FURI_LOG_E(TAG, "Missing or incorrect TE"); + //result = SubBruteFileResultMissingOrIncorrectTe; + //break; + } else { + instance->te = temp_data32; + instance->has_tail = true; + } + + // Repeat + if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Repeat: %d", temp_data32); +#endif + instance->repeat = temp_data32; + } else { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Repeat: 3 (default)"); +#endif + instance->repeat = 3; + } + + result = SubBruteFileResultOk; + } while(0); + + string_clear(temp_str); + flipper_format_file_close(fff_data_file); + flipper_format_free(fff_data_file); + furi_record_close(RECORD_STORAGE); + + subghz_environment_free(instance->environment); + subghz_receiver_free(instance->receiver); + + if(result == SubBruteFileResultOk) { +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "Loaded successfully"); +#endif + } + + return result; +} + +void subbrute_device_attack_set_default_values(SubBruteDevice* instance) { + furi_assert(instance); + + instance->attack = SubBruteAttackNone; + instance->max_value = 0; + instance->key_index = 0; + + memset(instance->file_template, 0, sizeof(instance->file_template)); + memset(instance->current_key, 0, sizeof(instance->current_key)); + memset(instance->file_key, 0, sizeof(instance->file_key)); + + string_set_str(instance->protocol_name, protocol_raw); + + string_set_str(instance->preset_name, preset_ook650_async); + instance->preset = FuriHalSubGhzPresetOok650Async; + + string_reset(instance->payload); + + instance->repeat = 5; + instance->te = 0; + instance->has_tail = false; +} + +FuriHalSubGhzPreset subbrute_device_convert_preset(string_t preset) { + if(string_cmp_str(preset, preset_ook270_async) == 0) { + return FuriHalSubGhzPresetOok270Async; + } + if(string_cmp_str(preset, preset_ook650_async) == 0) { + return FuriHalSubGhzPresetOok650Async; + } + if(string_cmp_str(preset, preset_2fsk_dev238_async) == 0) { + return FuriHalSubGhzPreset2FSKDev238Async; + } + if(string_cmp_str(preset, preset_2fsk_dev476_async) == 0) { + return FuriHalSubGhzPreset2FSKDev476Async; + } + if(string_cmp_str(preset, preset_msk99_97_kb_async) == 0) { + return FuriHalSubGhzPresetMSK99_97KbAsync; + } + if(string_cmp_str(preset, preset_gfs99_97_kb_async) == 0) { + return FuriHalSubGhzPresetMSK99_97KbAsync; + } + return FuriHalSubGhzPresetCustom; +} diff --git a/applications/plugins/subbrute/subbrute_device.h b/applications/plugins/subbrute/subbrute_device.h new file mode 100644 index 000000000..fab750cc6 --- /dev/null +++ b/applications/plugins/subbrute/subbrute_device.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#define SUBBRUTE_TEXT_STORE_SIZE 128 + +#define SUBBRUTE_MAX_LEN_NAME 64 +#define SUBBRUTE_PATH EXT_PATH("subghz") +#define SUBBRUTE_FILE_EXT ".sub" + +#define SUBBRUTE_PAYLOAD_SIZE 8 + +typedef enum { + SubBruteAttackNone, + SubBruteAttackCAME12bit307, + SubBruteAttackCAME12bit433, + SubBruteAttackCAME12bit868, + SubBruteAttackChamberlain9bit315, + SubBruteAttackChamberlain9bit390, + SubBruteAttackLinear10bit300, + SubBruteAttackLinear10bit310, + SubBruteAttackNICE12bit433, + SubBruteAttackNICE12bit868, + SubBruteAttackLoadFile, + SubBruteAttackTotalCount, +} SubBruteAttacks; + +typedef enum { + SubBruteFileResultUnknown, + SubBruteFileResultOk, + SubBruteFileResultErrorOpenFile, + SubBruteFileResultMissingOrIncorrectHeader, + SubBruteFileResultFrequencyNotAllowed, + SubBruteFileResultMissingOrIncorrectFrequency, + SubBruteFileResultPresetInvalid, + SubBruteFileResultMissingProtocol, + SubBruteFileResultProtocolNotSupported, + SubBruteFileResultDynamicProtocolNotValid, + SubBruteFileResultProtocolNotFound, + SubBruteFileResultMissingOrIncorrectBit, + SubBruteFileResultMissingOrIncorrectKey, + SubBruteFileResultMissingOrIncorrectTe, +} SubBruteFileResult; + +typedef enum { + SubBruteDeviceStateIDLE, + SubBruteDeviceStateReady, + SubBruteDeviceStateTx, + SubBruteDeviceStateFinished, +} SubBruteDeviceState; + +typedef struct { + DialogsApp* dialogs; + SubBruteDeviceState state; + + // Current step + uint8_t key_index; + string_t load_path; + + SubGhzReceiver* receiver; + SubGhzProtocolDecoderBase* decoder_result; + SubGhzEnvironment* environment; + + // Attack state + SubBruteAttacks attack; + char file_template[SUBBRUTE_TEXT_STORE_SIZE]; + bool has_tail; + string_t payload; + uint8_t max_value; + + // Loaded info for attack type + FuriHalSubGhzPreset preset; + string_t preset_name; + string_t protocol_name; + uint32_t frequency; + uint32_t repeat; + uint32_t bit; + char current_key[SUBBRUTE_PAYLOAD_SIZE]; + uint32_t te; + + char file_key[SUBBRUTE_PAYLOAD_SIZE]; + char text_store[SUBBRUTE_PAYLOAD_SIZE]; +} SubBruteDevice; + +SubBruteDevice* subbrute_device_alloc(); +void subbrute_device_free(SubBruteDevice* instance); +SubBruteFileResult subbrute_device_load_protocol_from_file(SubBruteDevice* instance); +bool subbrute_device_save_file(SubBruteDevice* instance, const char* key_name); +const char* subbrute_device_error_get_desc(SubBruteFileResult error_id); +bool subbrute_device_create_packet_parsed(SubBruteDevice* context, uint8_t step); +SubBruteFileResult subbrute_device_attack_set( + SubBruteDevice* context, + SubBruteAttacks type, + const char* file_path); +uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path); +FuriHalSubGhzPreset subbrute_device_convert_preset(string_t preset); +void subbrute_device_attack_set_default_values(SubBruteDevice* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_i.h b/applications/plugins/subbrute/subbrute_i.h new file mode 100644 index 000000000..5d434738e --- /dev/null +++ b/applications/plugins/subbrute/subbrute_i.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include +#include + +#include "lib/toolbox/path.h" +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "subbrute_device.h" +#include "subbrute.h" +#include "scenes/subbrute_scene.h" +#include "views/subbrute_attack_view.h" +#include "views/subbrute_main_view.h" + +typedef enum { + SubBruteViewNone, + SubBruteViewMain, + SubBruteViewAttack, + SubBruteViewTextInput, + SubBruteViewDialogEx, + SubBruteViewPopup, + SubBruteViewWidget, + SubBruteViewStack, +} SubBruteView; + +struct SubBruteState { + // GUI elements + NotificationApp* notifications; + Gui* gui; + ViewDispatcher* view_dispatcher; + ViewStack* view_stack; + TextInput* text_input; + Popup* popup; + Widget* widget; + DialogsApp* dialogs; + Loading* loading; + + // Views + SubBruteMainView* view_main; + SubBruteAttackView* view_attack; + SubBruteView current_view; + + // Scene + SceneManager* scene_manager; + + SubBruteDevice* device; + + //Menu stuff + // TODO: Do we need it? + uint8_t menu_index; +}; + +void subbrute_show_loading_popup(void* context, bool show); +void subbrute_text_input_callback(void* context); +void subbrute_popup_closed_callback(void* context); +const char* subbrute_get_menu_name(uint8_t index); + +int32_t subbrute_app(void* p); +SubBruteState* subbrute_alloc(); +void subbrute_free(SubBruteState* instance); +bool subbrute_custom_event_callback(void* context, uint32_t event); +bool subbrute_back_event_callback(void* context); +void subbrute_tick_event_callback(void* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_utils.c b/applications/plugins/subbrute/subbrute_utils.c deleted file mode 100644 index 2aafc7175..000000000 --- a/applications/plugins/subbrute/subbrute_utils.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "subbrute_utils.h" - -bool subbrute_is_frequency_allowed(SubBruteState* context) { - // I know you don't like it but laws are laws - // It's opensource so do whatever you want, but remember the risks :) - // (Yes, this comment is the only purpose of this function) - bool r = furi_hal_subghz_is_tx_allowed(context->frequency); - if(!r) { - FURI_LOG_E(TAG, "Frequency %d is not allowed in your region", context->frequency); - notification_message(context->notify, &sequence_single_vibro); - } - return r; -} \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_utils.h b/applications/plugins/subbrute/subbrute_utils.h deleted file mode 100644 index 90f7c60ad..000000000 --- a/applications/plugins/subbrute/subbrute_utils.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "subbrute.h" - -bool subbrute_is_frequency_allowed(SubBruteState* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/views/subbrute_attack_view.c b/applications/plugins/subbrute/views/subbrute_attack_view.c new file mode 100644 index 000000000..f651bb4c6 --- /dev/null +++ b/applications/plugins/subbrute/views/subbrute_attack_view.c @@ -0,0 +1,321 @@ +#include "subbrute_attack_view.h" +#include "../subbrute_i.h" +#include "../helpers/subbrute_worker.h" + +#include "assets_icons.h" +#include "../../../services/gui/icon_i.h" +#include +#include +#include + +struct SubBruteAttackView { + View* view; + SubBruteAttackViewCallback callback; + void* context; + SubBruteWorker* worker; +}; + +typedef struct { + SubBruteAttacks index; + uint8_t max_value; + uint8_t current_step; + bool is_attacking; +} SubBruteAttackViewModel; + +void subbrute_attack_view_set_callback( + SubBruteAttackView* instance, + SubBruteAttackViewCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +bool subbrute_attack_view_input(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + + SubBruteAttackView* instance = context; + + if(event->key == InputKeyBack && event->type == InputTypeShort) { + instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); + return true; + } + + bool is_attacking = false; + + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + is_attacking = model->is_attacking; + return false; + }); + + // if(!is_attacking) { + // instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); + // } else { + // instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); + // } + + if(!is_attacking) { + if(event->key == InputKeyOk) { + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + model->is_attacking = true; + return true; + }); + instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); + // } else if(event->key == InputKeyBack) { + // if(previous_scene == SubBruteSceneLoadFile) { + // instance->callback(SubBruteCustomEventTypeLoadFile, instance->context); + // } else { + // instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); + // } + } else if(event->key == InputKeyUp) { + instance->callback(SubBruteCustomEventTypeSaveFile, instance->context); + } else if(event->key == InputKeyDown) { + instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context); + } else if(event->type == InputTypePress) { + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + if(event->key == InputKeyLeft) { + model->current_step = + ((model->current_step - 100) + model->max_value) % model->max_value; + } else if(event->key == InputKeyRight) { + model->current_step = (model->current_step + 100) % model->max_value; + } + return true; + }); + instance->callback(SubBruteCustomEventTypeChangeStep, instance->context); + } else if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + if(event->key == InputKeyLeft) { + model->current_step = + ((model->current_step - 1) + model->max_value) % model->max_value; + } else if(event->key == InputKeyRight) { + model->current_step = (model->current_step + 1) % model->max_value; + } + return true; + }); + instance->callback(SubBruteCustomEventTypeChangeStep, instance->context); + } + } else { + if((event->type == InputTypeShort || event->type == InputTypeRepeat) && + (event->key == InputKeyOk || event->key == InputKeyBack)) { + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + model->is_attacking = false; + return true; + }); + instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); + } + } + + return true; +} + +SubBruteAttackView* subbrute_attack_view_alloc() { + SubBruteAttackView* instance = malloc(sizeof(SubBruteAttackView)); + + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteAttackViewModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw); + view_set_input_callback(instance->view, subbrute_attack_view_input); + view_set_enter_callback(instance->view, subbrute_attack_view_enter); + view_set_exit_callback(instance->view, subbrute_attack_view_exit); + + instance->worker = subbrute_worker_alloc(); + + return instance; +} + +void subbrute_attack_view_enter(void* context) { + furi_assert(context); +} + +void subbrute_attack_view_free(SubBruteAttackView* instance) { + furi_assert(instance); + + subbrute_worker_free(instance->worker); + + view_free(instance->view); + free(instance); +} + +View* subbrute_attack_view_get_view(SubBruteAttackView* instance) { + furi_assert(instance); + return instance->view; +} + +void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint8_t current_step) { + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + model->current_step = current_step; + return true; + }); +} + +uint8_t subbrute_attack_view_get_current_step(SubBruteAttackView* instance) { + uint8_t current_step; + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + current_step = model->current_step; + return false; + }); + + return current_step; +} + +// We need to call init every time, because not every time we calls enter +// normally, call enter only once +void subbrute_attack_view_init_values( + SubBruteAttackView* instance, + uint8_t index, + uint8_t max_value, + uint8_t current_step) { + with_view_model( + instance->view, (SubBruteAttackViewModel * model) { + model->max_value = max_value; + model->index = index; + model->current_step = current_step; + return true; + }); +} + +void subbrute_attack_view_stop_worker(SubBruteAttackView* instance) { + furi_assert(instance); + subbrute_worker_stop(instance->worker); +} + +bool subbrute_attack_view_can_send(SubBruteAttackView* instance) { + furi_assert(instance); + + return subbrute_worker_can_transmit(instance->worker); +} + +void subbrute_attack_view_start_worker( + SubBruteAttackView* instance, + uint32_t frequency, + FuriHalSubGhzPreset preset, + string_t protocol_name) { + furi_assert(instance); + if(!subbrute_worker_is_running(instance->worker)) { + subbrute_worker_start(instance->worker, frequency, preset, protocol_name); + } +} + +bool subbrute_attack_view_transmit(SubBruteAttackView* instance, string_t payload) { + furi_assert(instance); + + return subbrute_worker_transmit(instance->worker, payload); +} + +bool subbrute_attack_view_is_worker_running(SubBruteAttackView* instance) { + furi_assert(instance); + + return subbrute_worker_is_running(instance->worker); +} + +void subbrute_attack_view_exit(void* context) { + furi_assert(context); + SubBruteAttackView* instance = context; + + // Just stop, make free in free method + subbrute_worker_stop(instance->worker); +} + +void elements_button_top_left(Canvas* canvas, const char* str) { + const Icon* icon = &I_ButtonUp_7x4; + + const uint8_t button_height = 12; + const uint8_t vertical_offset = 3; + const uint8_t horizontal_offset = 3; + const uint8_t string_width = canvas_string_width(canvas, str); + const uint8_t icon_h_offset = 3; + const uint8_t icon_width_with_offset = icon->width + icon_h_offset; + const uint8_t icon_v_offset = icon->height + vertical_offset; + const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; + + const uint8_t x = 0; + const uint8_t y = 0; + + canvas_draw_box(canvas, x, y - button_height, button_width, button_height); + canvas_draw_line(canvas, x + button_width - 0, y, x + button_width - 0, y + button_height - 0); + canvas_draw_line(canvas, x + button_width - 1, y, x + button_width - 1, y + button_height - 1); + canvas_draw_line(canvas, x + button_width - 2, y, x + button_width - 2, y + button_height - 2); + + canvas_invert_color(canvas); + canvas_draw_icon(canvas, x + horizontal_offset, y + icon_v_offset, icon); + canvas_draw_str( + canvas, x + horizontal_offset + icon_width_with_offset, y + vertical_offset, str); + canvas_invert_color(canvas); +} + +void elements_button_top_right(Canvas* canvas, const char* str) { + const Icon* icon = &I_ButtonDown_7x4; + + const uint8_t button_height = 12; + const uint8_t vertical_offset = 3; + const uint8_t horizontal_offset = 3; + const uint8_t string_width = canvas_string_width(canvas, str); + const uint8_t icon_h_offset = 3; + const uint8_t icon_width_with_offset = icon->width + icon_h_offset; + const uint8_t icon_v_offset = icon->height + vertical_offset; + const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; + + const uint8_t x = canvas_width(canvas); + const uint8_t y = 0; + + canvas_draw_box(canvas, x - button_width, y - button_height, button_width, button_height); + canvas_draw_line(canvas, x - button_width - 1, y, x + button_width + 1, y + button_height - 0); + canvas_draw_line(canvas, x - button_width - 2, y, x + button_width + 2, y + button_height - 1); + canvas_draw_line(canvas, x - button_width - 3, y, x + button_width + 3, y + button_height - 2); + + canvas_invert_color(canvas); + canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str); + canvas_draw_icon(canvas, x - horizontal_offset - icon->width, y - icon_v_offset, icon); + canvas_invert_color(canvas); +} + +void subbrute_attack_view_draw(Canvas* canvas, void* context) { + furi_assert(context); + SubBruteAttackViewModel* model = context; + //char buffer[64]; + + // Title + const char* attack_name = NULL; + attack_name = subbrute_get_menu_name(model->index); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 20, 8, attack_name ? attack_name : "Sub-GHz Bruteforcer"); + + // Progress bar + // Resolution: 128x64 px + float progress_value = model->max_value / model->current_step; + elements_progress_bar(canvas, 8, 30, 98, progress_value > 1 ? 1 : progress_value); + + // Selected attack type + // const char* attack_name = NULL; + // attack_name = subbrute_get_menu_name(model->index); + // + // canvas_set_font(canvas, FontSecondary); + // if(attack_name) { + // snprintf(buffer, sizeof(buffer), "%s", attack_name); + // } else { + // snprintf(buffer, sizeof(buffer), "%s", "Unknown"; + // } + // canvas_draw_str(canvas, 9, 42, buffer); + + if(!model->is_attacking) { + elements_button_left(canvas, "-1"); + elements_button_right(canvas, "+1"); + elements_button_center(canvas, "Start"); + elements_button_top_left(canvas, "Save"); + elements_button_top_right(canvas, "Repeat"); + } else { + elements_button_center(canvas, "Stop"); + } +} diff --git a/applications/plugins/subbrute/views/subbrute_attack_view.h b/applications/plugins/subbrute/views/subbrute_attack_view.h new file mode 100644 index 000000000..253b42adf --- /dev/null +++ b/applications/plugins/subbrute/views/subbrute_attack_view.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include "assets_icons.h" +#include +#include +#include +#include +#include "../subbrute_custom_event.h" + +typedef void (*SubBruteAttackViewCallback)(SubBruteCustomEvent event, void* context); +typedef struct SubBruteAttackView SubBruteAttackView; + +void subbrute_attack_view_set_callback( + SubBruteAttackView* instance, + SubBruteAttackViewCallback callback, + void* context); +SubBruteAttackView* subbrute_attack_view_alloc(); +void subbrute_attack_view_free(SubBruteAttackView* instance); +View* subbrute_attack_view_get_view(SubBruteAttackView* instance); +void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint8_t current_step); +uint8_t subbrute_attack_view_get_current_step(SubBruteAttackView* instance); +void subbrute_attack_view_init_values( + SubBruteAttackView* instance, + uint8_t index, + uint8_t max_value, + uint8_t current_step); +void subbrute_attack_view_stop_worker(SubBruteAttackView* instance); +bool subbrute_attack_view_can_send(SubBruteAttackView* instance); +void subbrute_attack_view_start_worker( + SubBruteAttackView* instance, + uint32_t frequency, + FuriHalSubGhzPreset preset, + string_t protocol_name); +bool subbrute_attack_view_transmit(SubBruteAttackView* instance, string_t payload); +bool subbrute_attack_view_is_worker_running(SubBruteAttackView* instance); \ No newline at end of file diff --git a/applications/plugins/subbrute/views/subbrute_main_view.c b/applications/plugins/subbrute/views/subbrute_main_view.c new file mode 100644 index 000000000..4f497fdb6 --- /dev/null +++ b/applications/plugins/subbrute/views/subbrute_main_view.c @@ -0,0 +1,152 @@ +#include "subbrute_main_view.h" +#include "../subbrute_i.h" + +#include +#include +#include + +#define STATUS_BAR_Y_SHIFT 13 + +struct SubBruteMainView { + View* view; + SubBruteMainViewCallback callback; + void* context; +}; + +typedef struct { + uint8_t index; +} SubBruteMainViewModel; + +void subbrute_main_view_set_callback( + SubBruteMainView* instance, + SubBruteMainViewCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { + SubBruteMainViewModel* m = model; + + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + + for(uint8_t i = 1; i < SubBruteAttackTotalCount - 1; ++i) { + const char* str = subbrute_get_menu_name(i); + canvas_draw_str_aligned( + canvas, 64, 9 + (i * 17) + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter, str); + + if(m->index == i) { + elements_frame(canvas, 15, 1 + (i * 17) + STATUS_BAR_Y_SHIFT, 98, 15); + } + } +} + +bool subbrute_main_view_input(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + + SubBruteMainView* instance = context; + const uint8_t min_value = SubBruteAttackNone + 1; + const uint8_t correct_total = SubBruteAttackTotalCount - 1; + //uint8_t idx = min_value; + bool consumed = false; + if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { + with_view_model( + instance->view, (SubBruteMainViewModel * model) { + bool ret = false; + if(event->key == InputKeyUp) { + if(model->index == min_value) { + model->index = correct_total; + } else { + model->index = CLAMP(model->index - 1, correct_total, min_value); + } + ret = true; + consumed = true; + } else if(event->key == InputKeyDown) { + if(model->index == correct_total) { + model->index = min_value; + } else { + model->index = CLAMP(model->index + 1, correct_total, min_value); + } + ret = true; + consumed = true; + } + if(ret) { + model->index++; + } + //idx = model->index; + return ret; + }); + } + + if(event->key == InputKeyOk && event->type == InputTypeShort) { + /*if(idx == SubBruteAttackLoadFile) { + instance->callback(SubBruteCustomEventTypeLoadFile, instance->context); + } else if(idx > SubBruteAttackNone && idx < SubBruteAttackLoadFile) {*/ + instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context); + /*}*/ + consumed = true; + } + + return consumed; +} + +void subbrute_main_view_enter(void* context) { + furi_assert(context); +} + +void subbrute_main_view_exit(void* context) { + furi_assert(context); +} + +SubBruteMainView* subbrute_main_view_alloc() { + SubBruteMainView* instance = malloc(sizeof(SubBruteMainView)); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteMainViewModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_main_view_draw); + view_set_input_callback(instance->view, subbrute_main_view_input); + view_set_enter_callback(instance->view, subbrute_main_view_enter); + view_set_exit_callback(instance->view, subbrute_main_view_exit); + + return instance; +} + +void subbrute_main_view_free(SubBruteMainView* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* subbrute_main_view_get_view(SubBruteMainView* instance) { + furi_assert(instance); + return instance->view; +} + +void subbrute_main_view_set_index(SubBruteMainView* instance, uint8_t idx) { + furi_assert(instance); + furi_assert(idx < SubBruteAttackTotalCount - 2); + with_view_model( + instance->view, (SubBruteMainViewModel * model) { + model->index = idx <= 0 ? 1 : idx; + return true; + }); +} + +SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) { + furi_assert(instance); + + uint8_t attack = 0; + with_view_model( + instance->view, (SubBruteMainViewModel * model) { + attack = model->index; + return false; + }); + + return attack; +} \ No newline at end of file diff --git a/applications/plugins/subbrute/views/subbrute_main_view.h b/applications/plugins/subbrute/views/subbrute_main_view.h new file mode 100644 index 000000000..bb0e30b00 --- /dev/null +++ b/applications/plugins/subbrute/views/subbrute_main_view.h @@ -0,0 +1,28 @@ +#pragma once + +#include "../subbrute_custom_event.h" +#include +#include "assets_icons.h" +#include +#include +#include + +typedef void (*SubBruteMainViewCallback)(SubBruteCustomEvent event, void* context); +typedef struct SubBruteMainView SubBruteMainView; + +void subbrute_main_view_set_callback( + SubBruteMainView* instance, + SubBruteMainViewCallback callback, + void* context); + +SubBruteMainView* subbrute_main_view_alloc(); +void subbrute_main_view_free(SubBruteMainView* instance); +View* subbrute_main_view_get_view(SubBruteMainView* instance); + +void subbrute_main_view_set_index(SubBruteMainView* instance, uint8_t idx); +uint8_t subbrute_main_view_get_index(SubBruteMainView* instance); + +void subbrute_attack_view_enter(void* context); +void subbrute_attack_view_exit(void* context); +bool subbrute_attack_view_input(InputEvent* event, void* context); +void subbrute_attack_view_draw(Canvas* canvas, void* context); \ No newline at end of file