diff --git a/applications/plugins/subbrute/application.fam b/applications/plugins/subbrute/application.fam index f17a04321..7b7b441d7 100644 --- a/applications/plugins/subbrute/application.fam +++ b/applications/plugins/subbrute/application.fam @@ -9,5 +9,5 @@ App( order=11, fap_icon="subbrute_10px.png", fap_category="Tools", - fap_icon_assets="icons", + fap_icon_assets="images", ) diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.c b/applications/plugins/subbrute/helpers/subbrute_worker.c index ac7435b71..1f84ac932 100644 --- a/applications/plugins/subbrute/helpers/subbrute_worker.c +++ b/applications/plugins/subbrute/helpers/subbrute_worker.c @@ -78,7 +78,8 @@ bool subbrute_worker_init_default_attack( SubBruteWorker* instance, SubBruteAttacks attack_type, uint64_t step, - const SubBruteProtocol* protocol) { + const SubBruteProtocol* protocol, + uint8_t extra_repeats) { furi_assert(instance); if(instance->worker_running) { @@ -93,7 +94,7 @@ bool subbrute_worker_init_default_attack( instance->step = step; instance->bits = protocol->bits; instance->te = protocol->te; - instance->repeat = protocol->repeat; + instance->repeat = protocol->repeat + extra_repeats; instance->load_index = 0; instance->file_key = NULL; instance->max_value = subbrute_protocol_calc_max_value(instance->attack, instance->bits); diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.h b/applications/plugins/subbrute/helpers/subbrute_worker.h index 3a514272b..a3a4930a8 100644 --- a/applications/plugins/subbrute/helpers/subbrute_worker.h +++ b/applications/plugins/subbrute/helpers/subbrute_worker.h @@ -22,7 +22,8 @@ bool subbrute_worker_init_default_attack( SubBruteWorker* instance, SubBruteAttacks attack_type, uint64_t step, - const SubBruteProtocol* protocol); + const SubBruteProtocol* protocol, + uint8_t extra_repeats); bool subbrute_worker_init_file_attack( SubBruteWorker* instance, uint64_t step, diff --git a/applications/plugins/subbrute/icons/DolphinNice_96x59.png b/applications/plugins/subbrute/icons/DolphinNice_96x59.png deleted file mode 100644 index b111196c7..000000000 Binary files a/applications/plugins/subbrute/icons/DolphinNice_96x59.png and /dev/null differ diff --git a/applications/plugins/subbrute/images/ButtonDown_7x4.png b/applications/plugins/subbrute/images/ButtonDown_7x4.png new file mode 100644 index 000000000..2954bb6a6 Binary files /dev/null and b/applications/plugins/subbrute/images/ButtonDown_7x4.png differ diff --git a/applications/plugins/subbrute/images/ButtonUp_7x4.png b/applications/plugins/subbrute/images/ButtonUp_7x4.png new file mode 100644 index 000000000..1be79328b Binary files /dev/null and b/applications/plugins/subbrute/images/ButtonUp_7x4.png differ diff --git a/applications/plugins/subbrute/images/DolphinNice_96x59.png b/applications/plugins/subbrute/images/DolphinNice_96x59.png new file mode 100644 index 000000000..a299d3630 Binary files /dev/null and b/applications/plugins/subbrute/images/DolphinNice_96x59.png differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_01.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_01.png new file mode 100644 index 000000000..52dc4ad21 Binary files /dev/null and b/applications/plugins/subbrute/images/Sub1ghz_14/frame_01.png differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_02.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_02.png new file mode 100644 index 000000000..2dff1c031 Binary files /dev/null and b/applications/plugins/subbrute/images/Sub1ghz_14/frame_02.png differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_03.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_03.png new file mode 100644 index 000000000..c1e438b01 Binary files /dev/null and b/applications/plugins/subbrute/images/Sub1ghz_14/frame_03.png differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_04.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_04.png new file mode 100644 index 000000000..169fb6147 Binary files /dev/null and b/applications/plugins/subbrute/images/Sub1ghz_14/frame_04.png differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_05.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_05.png new file mode 100644 index 000000000..79b2bc972 Binary files /dev/null and b/applications/plugins/subbrute/images/Sub1ghz_14/frame_05.png differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_06.png b/applications/plugins/subbrute/images/Sub1ghz_14/frame_06.png new file mode 100644 index 000000000..8fce0c44d Binary files /dev/null and b/applications/plugins/subbrute/images/Sub1ghz_14/frame_06.png differ diff --git a/applications/plugins/subbrute/images/Sub1ghz_14/frame_rate b/applications/plugins/subbrute/images/Sub1ghz_14/frame_rate new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/applications/plugins/subbrute/images/Sub1ghz_14/frame_rate @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/applications/plugins/subbrute/icons/sub1_10px.png b/applications/plugins/subbrute/images/sub1_10px.png similarity index 100% rename from applications/plugins/subbrute/icons/sub1_10px.png rename to applications/plugins/subbrute/images/sub1_10px.png diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c b/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c index 479284fae..b11ebc2f8 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c @@ -1,6 +1,5 @@ #include "../subbrute_i.h" #include "subbrute_scene.h" -#include "SubGHz_Bruteforcer_icons.h" #define TAG "SubBruteSceneLoadFile" @@ -38,7 +37,7 @@ void subbrute_scene_load_file_on_enter(void* context) { load_result = subbrute_device_load_from_file(instance->device, furi_string_get_cstr(load_path)); if(load_result == SubBruteFileResultOk) { - load_result = subbrute_device_attack_set(instance->device, SubBruteAttackLoadFile); + load_result = subbrute_device_attack_set(instance->device, SubBruteAttackLoadFile, 0); if(load_result == SubBruteFileResultOk) { if(!subbrute_worker_init_file_attack( instance->worker, diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c b/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c index ffef4fe89..20b1a0de4 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_save_success.c @@ -1,6 +1,5 @@ #include "../subbrute_i.h" #include "subbrute_scene.h" -#include "SubGHz_Bruteforcer_icons.h" void subbrute_scene_save_success_on_enter(void* context) { furi_assert(context); diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c b/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c index 801185e55..bdbe2eccd 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c @@ -45,7 +45,8 @@ void subbrute_scene_setup_attack_on_enter(void* context) { instance->device->attack, instance->device->max_value, instance->device->key_index, - false); + false, + instance->device->extra_repeats); instance->current_view = SubBruteViewAttack; subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance); @@ -70,7 +71,6 @@ bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubBruteCustomEventTypeTransmitStarted) { - subbrute_attack_view_set_worker_type(view, false); scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack); } else if(event.event == SubBruteCustomEventTypeSaveFile) { subbrute_attack_view_init_values( @@ -78,7 +78,8 @@ bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event instance->device->attack, instance->device->max_value, instance->device->key_index, - false); + false, + instance->device->extra_repeats); scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName); } else if(event.event == SubBruteCustomEventTypeBackPressed) { subbrute_attack_view_init_values( @@ -86,7 +87,8 @@ bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event instance->device->attack, instance->device->max_value, instance->device->key_index, - false); + false, + instance->device->extra_repeats); scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); } else if(event.event == SubBruteCustomEventTypeError) { notification_message(instance->notifications, &sequence_error); diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_start.c b/applications/plugins/subbrute/scenes/subbrute_scene_start.c index 677b1ef20..b993b922c 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_start.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_start.c @@ -50,19 +50,22 @@ bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) { #endif if(event.event == SubBruteCustomEventTypeMenuSelected) { SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main); + uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main); - if(subbrute_device_attack_set(instance->device, attack) != SubBruteFileResultOk || + if(subbrute_device_attack_set(instance->device, attack, extra_repeats) != SubBruteFileResultOk || !subbrute_worker_init_default_attack( instance->worker, attack, instance->device->key_index, - instance->device->protocol_info)) { + instance->device->protocol_info, + instance->device->extra_repeats)) { furi_crash("Invalid attack set!"); } scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); consumed = true; } else if(event.event == SubBruteCustomEventTypeLoadFile) { + instance->device->extra_repeats = 0; scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile); consumed = true; } diff --git a/applications/plugins/subbrute/subbrute_device.c b/applications/plugins/subbrute/subbrute_device.c index fcbd5f2d2..2847bc458 100644 --- a/applications/plugins/subbrute/subbrute_device.c +++ b/applications/plugins/subbrute/subbrute_device.c @@ -133,16 +133,20 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na return result; } -SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBruteAttacks type) { +SubBruteFileResult subbrute_device_attack_set( + SubBruteDevice* instance, + SubBruteAttacks type, + uint8_t extra_repeats) { furi_assert(instance); #ifdef FURI_DEBUG - FURI_LOG_D(TAG, "subbrute_device_attack_set: %d", type); + FURI_LOG_D(TAG, "subbrute_device_attack_set: %d, extra_repeats: %d", type, extra_repeats); #endif subbrute_device_attack_set_default_values(instance, type); if(type != SubBruteAttackLoadFile) { subbrute_device_free_protocol_info(instance); instance->protocol_info = subbrute_protocol(type); + instance->extra_repeats = extra_repeats; } // For non-file types we didn't set SubGhzProtocolDecoderBase @@ -175,7 +179,7 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute #ifdef FURI_DEBUG bits = instance->protocol_info->bits; te = instance->protocol_info->te; - repeat = instance->protocol_info->repeat; + repeat = instance->protocol_info->repeat + instance->extra_repeats; preset = instance->protocol_info->preset; file = instance->protocol_info->file; #endif @@ -189,7 +193,7 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute #ifdef FURI_DEBUG bits = instance->file_protocol_info->bits; te = instance->file_protocol_info->te; - repeat = instance->file_protocol_info->repeat; + repeat = instance->file_protocol_info->repeat + instance->extra_repeats; preset = instance->file_protocol_info->preset; file = instance->file_protocol_info->file; #endif @@ -390,6 +394,7 @@ void subbrute_device_attack_set_default_values( instance->attack = default_attack; instance->key_index = 0x00; instance->load_index = 0x00; + instance->extra_repeats = 0; memset(instance->current_key, 0, sizeof(instance->current_key)); if(default_attack != SubBruteAttackLoadFile) { diff --git a/applications/plugins/subbrute/subbrute_device.h b/applications/plugins/subbrute/subbrute_device.h index b0f136ad2..311b8a72b 100644 --- a/applications/plugins/subbrute/subbrute_device.h +++ b/applications/plugins/subbrute/subbrute_device.h @@ -48,6 +48,7 @@ typedef struct { // Attack state SubBruteAttacks attack; uint64_t max_value; + uint8_t extra_repeats; // Loaded info for attack type char current_key[SUBBRUTE_PAYLOAD_SIZE]; @@ -59,7 +60,10 @@ void subbrute_device_free(SubBruteDevice* instance); bool subbrute_device_save_file(SubBruteDevice* instance, const char* key_name); const char* subbrute_device_error_get_desc(SubBruteFileResult error_id); -SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* context, SubBruteAttacks type); +SubBruteFileResult subbrute_device_attack_set( + SubBruteDevice* context, + SubBruteAttacks type, + uint8_t extra_repeats); uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path); uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step); diff --git a/applications/plugins/subbrute/subbrute_i.h b/applications/plugins/subbrute/subbrute_i.h index edd87eb0f..7bb91dde8 100644 --- a/applications/plugins/subbrute/subbrute_i.h +++ b/applications/plugins/subbrute/subbrute_i.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include diff --git a/applications/plugins/subbrute/subbrute_protocols.c b/applications/plugins/subbrute/subbrute_protocols.c index 01d41e9c5..d75ff77e0 100644 --- a/applications/plugins/subbrute/subbrute_protocols.c +++ b/applications/plugins/subbrute/subbrute_protocols.c @@ -287,6 +287,10 @@ const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index) { return subbrute_protocol_registry[index]; } +uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index) { + return subbrute_protocol_registry[index]->repeat; +} + const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset) { return subbrute_protocol_presets[preset]; } @@ -338,7 +342,13 @@ void subbrute_protocol_default_payload( furi_string_free(buffer); #ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); + FURI_LOG_D( + TAG, + "candidate: %s, step: %lld, repeat: %d, te: %s", + furi_string_get_cstr(candidate), + step, + repeat, + te ? "true" : "false"); #endif stream_clean(stream); if(te) { @@ -372,7 +382,13 @@ void subbrute_protocol_file_payload( furi_string_replace_at(candidate, load_index * 3, 3, subbrute_payload_byte); #ifdef FURI_DEBUG - FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); + FURI_LOG_D( + TAG, + "candidate: %s, step: %lld, repeat: %d, te: %s", + furi_string_get_cstr(candidate), + step, + repeat, + te ? "true" : "false"); #endif stream_clean(stream); diff --git a/applications/plugins/subbrute/subbrute_protocols.h b/applications/plugins/subbrute/subbrute_protocols.h index 708c625bd..ead03dad7 100644 --- a/applications/plugins/subbrute/subbrute_protocols.h +++ b/applications/plugins/subbrute/subbrute_protocols.h @@ -4,15 +4,6 @@ #include #include #include -//typedef enum { -// FrequencyProtocolField, -// BitsProtocolField, -// HasTeProtocolField, -// RepeatProtocolField, -// PresetProtocolField, -// FileProtocolField, -// TotalProtocolFields -//} ProtocolFields; typedef enum { CAMEFileProtocol, @@ -61,6 +52,7 @@ const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset); const char* subbrute_protocol_file(SubBruteFileProtocol protocol); FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name); SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name); +uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index); const char* subbrute_protocol_name(SubBruteAttacks index); void subbrute_protocol_default_payload( diff --git a/applications/plugins/subbrute/views/subbrute_attack_view.c b/applications/plugins/subbrute/views/subbrute_attack_view.c index c3412de71..00a9e1b2a 100644 --- a/applications/plugins/subbrute/views/subbrute_attack_view.c +++ b/applications/plugins/subbrute/views/subbrute_attack_view.c @@ -14,14 +14,19 @@ struct SubBruteAttackView { View* view; SubBruteAttackViewCallback callback; void* context; -}; - -typedef struct { - SubBruteAttacks index; + SubBruteAttacks attack_type; uint64_t max_value; uint64_t current_step; bool is_attacking; - bool is_continuous_worker; + uint8_t extra_repeats; +}; + +typedef struct { + SubBruteAttacks attack_type; + uint64_t max_value; + uint64_t current_step; + uint8_t extra_repeats; + bool is_attacking; IconAnimation* icon; } SubBruteAttackViewModel; @@ -39,136 +44,87 @@ void subbrute_attack_view_set_callback( bool subbrute_attack_view_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); + SubBruteAttackView* instance = context; #ifdef FURI_DEBUG FURI_LOG_D(TAG, "InputKey: %d", event->key); #endif - SubBruteAttackView* instance = context; if(event->key == InputKeyBack && event->type == InputTypeShort) { - instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); + instance->is_attacking = false; with_view_model( instance->view, SubBruteAttackViewModel * model, - { - model->is_attacking = false; - model->is_continuous_worker = false; - }, + { model->is_attacking = false; }, true); + + instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); return true; } - bool is_attacking = false; + bool update = false; - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { is_attacking = model->is_attacking; }, - false); - - // if(!is_attacking) { - // instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); - // } else { - // instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); - // } - - if(!is_attacking) { + if(!instance->is_attacking) { if(event->type == InputTypeShort && event->key == InputKeyOk) { #ifdef FURI_DEBUG FURI_LOG_D(TAG, "InputKey: %d OK", event->key); #endif - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - model->is_attacking = true; - model->is_continuous_worker = false; - icon_animation_stop(model->icon); - icon_animation_start(model->icon); - }, - true); + instance->is_attacking = true; instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); - /*if(event->type == InputTypeRepeat && event->key == InputKeyOk) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d OK. SubBruteCustomEventTypeTransmitContinuousStarted", event->key); -#endif - with_view_model( - instance->view, (SubBruteAttackViewModel * model) { - model->is_attacking = true; - model->is_continuous_worker = true; - icon_animation_stop(model->icon); - icon_animation_start(model->icon); - return true; - }); - instance->callback(SubBruteCustomEventTypeTransmitContinuousStarted, instance->context); - } else if(event->type == InputTypeShort && event->key == InputKeyOk) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d OK", event->key); -#endif - with_view_model( - instance->view, (SubBruteAttackViewModel * model) { - model->is_attacking = true; - model->is_continuous_worker = false; - icon_animation_stop(model->icon); - icon_animation_start(model->icon); - return true; - }); - instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);*/ + update = true; } else if(event->key == InputKeyUp) { instance->callback(SubBruteCustomEventTypeSaveFile, instance->context); + update = true; } else if(event->key == InputKeyDown) { instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context); + update = true; } else if(event->type == InputTypeShort) { if(event->key == InputKeyLeft) { instance->callback(SubBruteCustomEventTypeChangeStepDown, instance->context); } else if(event->key == InputKeyRight) { instance->callback(SubBruteCustomEventTypeChangeStepUp, instance->context); } - // 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); + update = true; } else if(event->type == InputTypeRepeat) { if(event->key == InputKeyLeft) { instance->callback(SubBruteCustomEventTypeChangeStepDownMore, instance->context); } else if(event->key == InputKeyRight) { instance->callback(SubBruteCustomEventTypeChangeStepUpMore, instance->context); } - /*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);*/ + update = true; } } else { + // ATTACK Mode! if((event->type == InputTypeShort || event->type == InputTypeRepeat) && (event->key == InputKeyOk || event->key == InputKeyBack)) { - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { - model->is_attacking = false; - model->is_continuous_worker = false; - icon_animation_stop(model->icon); - icon_animation_start(model->icon); - }, - true); + instance->is_attacking = false; instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); + + update = true; } } + if(update) { + with_view_model( + instance->view, + SubBruteAttackViewModel * model, + { + if(model->is_attacking != instance->is_attacking) { + if(instance->is_attacking) { + icon_animation_stop(model->icon); + icon_animation_start(model->icon); + } else { + icon_animation_stop(model->icon); + } + } + + model->attack_type = instance->attack_type; + model->max_value = instance->max_value; + model->current_step = instance->current_step; + model->is_attacking = instance->is_attacking; + }, + true); + } + return true; } @@ -186,13 +142,18 @@ SubBruteAttackView* subbrute_attack_view_alloc() { model->icon = icon_animation_alloc(&A_Sub1ghz_14); view_tie_icon_animation(instance->view, model->icon); }, - false); + true); 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->attack_type = SubBruteAttackTotalCount; + instance->max_value = 0x00; + instance->current_step = 0; + instance->is_attacking = false; + return instance; } @@ -231,6 +192,7 @@ void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_ #ifdef FURI_DEBUG //FURI_LOG_D(TAG, "Set step: %d", current_step); #endif + instance->current_step = current_step; with_view_model( instance->view, SubBruteAttackViewModel * model, @@ -238,15 +200,6 @@ void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_ true); } -void subbrute_attack_view_set_worker_type(SubBruteAttackView* instance, bool is_continuous_worker) { - furi_assert(instance); - with_view_model( - instance->view, - SubBruteAttackViewModel * model, - { model->is_continuous_worker = is_continuous_worker; }, - true); -} - // 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( @@ -254,23 +207,32 @@ void subbrute_attack_view_init_values( uint8_t index, uint64_t max_value, uint64_t current_step, - bool is_attacking) { + bool is_attacking, + uint8_t extra_repeats) { #ifdef FURI_DEBUG - FURI_LOG_D( + FURI_LOG_I( TAG, - "init, index: %d, max_value: %lld, current_step: %lld", + "INIT, attack_type: %d, max_value: %lld, current_step: %lld, extra_repeats: %d", index, max_value, - current_step); + current_step, + extra_repeats); #endif + instance->attack_type = index; + instance->max_value = max_value; + instance->current_step = current_step; + instance->is_attacking = is_attacking; + instance->extra_repeats = extra_repeats; + with_view_model( instance->view, SubBruteAttackViewModel * model, { model->max_value = max_value; - model->index = index; + model->attack_type = index; model->current_step = current_step; model->is_attacking = is_attacking; + model->extra_repeats = extra_repeats; if(is_attacking) { icon_animation_start(model->icon); } else { @@ -313,10 +275,12 @@ void elements_button_top_left(Canvas* canvas, const char* str) { const uint8_t x = 0; const uint8_t y = 0 + button_height; - canvas_draw_box(canvas, x, y - button_height, button_width, button_height); - canvas_draw_line(canvas, x + button_width + 0, y - button_height, x + button_width + 0, y - 1); - canvas_draw_line(canvas, x + button_width + 1, y - button_height, x + button_width + 1, y - 2); - canvas_draw_line(canvas, x + button_width + 2, y - button_height, x + button_width + 2, y - 3); + uint8_t line_x = x + button_width; + uint8_t line_y = y - button_height; + canvas_draw_box(canvas, x, line_y, button_width, button_height); + canvas_draw_line(canvas, line_x + 0, line_y, line_x + 0, y - 1); + canvas_draw_line(canvas, line_x + 1, line_y, line_x + 1, y - 2); + canvas_draw_line(canvas, line_x + 2, line_y, line_x + 2, y - 3); canvas_invert_color(canvas); canvas_draw_icon(canvas, x + horizontal_offset, y - icon_v_offset, icon); @@ -345,10 +309,12 @@ void elements_button_top_right(Canvas* canvas, const char* str) { const uint8_t x = canvas_width(canvas); const uint8_t y = 0 + button_height; - canvas_draw_box(canvas, x - button_width, y - button_height, button_width, button_height); - canvas_draw_line(canvas, x - button_width - 1, y - button_height, x - button_width - 1, y - 1); - canvas_draw_line(canvas, x - button_width - 2, y - button_height, x - button_width - 2, y - 2); - canvas_draw_line(canvas, x - button_width - 3, y - button_height, x - button_width - 3, y - 3); + uint8_t line_x = x - button_width; + uint8_t line_y = y - button_height; + canvas_draw_box(canvas, line_x, line_y, button_width, button_height); + canvas_draw_line(canvas, line_x - 1, line_y, line_x - 1, y - 1); + canvas_draw_line(canvas, line_x - 2, line_y, line_x - 2, y - 2); + canvas_draw_line(canvas, line_x - 3, line_y, line_x - 3, y - 3); canvas_invert_color(canvas); canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str); @@ -360,36 +326,43 @@ void elements_button_top_right(Canvas* canvas, const char* str) { void subbrute_attack_view_draw(Canvas* canvas, void* context) { furi_assert(context); SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context; - char buffer[26]; + char buffer[64]; const char* attack_name = NULL; - attack_name = subbrute_protocol_name(model->index); + attack_name = subbrute_protocol_name(model->attack_type); + // Title if(model->is_attacking) { canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, attack_name); } - // Value + + // Current Step / Max value canvas_set_font(canvas, FontBigNumbers); snprintf(buffer, sizeof(buffer), "%04d/%04d", (int)model->current_step, (int)model->max_value); canvas_draw_str_aligned(canvas, 64, 17, AlignCenter, AlignTop, buffer); canvas_set_font(canvas, FontSecondary); + memset(buffer, 0, sizeof(buffer)); if(!model->is_attacking) { canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignBottom, attack_name); + snprintf( + buffer, + sizeof(buffer), + "x%d", + model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); + canvas_draw_str_aligned(canvas, 60, 6, AlignCenter, AlignCenter, buffer); + 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, "Resend"); } else { - if(model->is_continuous_worker) { - canvas_invert_color(canvas); - } // canvas_draw_icon_animation const uint8_t icon_h_offset = 0; const uint8_t icon_width_with_offset = @@ -404,9 +377,14 @@ void subbrute_attack_view_draw(Canvas* canvas, void* context) { float progress_value = (float)model->current_step / model->max_value; elements_progress_bar(canvas, 8, 37, 110, progress_value > 1 ? 1 : progress_value); + snprintf( + buffer, + sizeof(buffer), + "x%d", + model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type)); + canvas_draw_str(canvas, 4, y - 8, buffer); + canvas_draw_str(canvas, 4, y - 1, "repeats"); + elements_button_center(canvas, "Stop"); - if(model->is_continuous_worker) { - canvas_invert_color(canvas); - } } } diff --git a/applications/plugins/subbrute/views/subbrute_attack_view.h b/applications/plugins/subbrute/views/subbrute_attack_view.h index 1e25379e2..55e3a8222 100644 --- a/applications/plugins/subbrute/views/subbrute_attack_view.h +++ b/applications/plugins/subbrute/views/subbrute_attack_view.h @@ -16,10 +16,10 @@ 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, uint64_t current_step); -void subbrute_attack_view_set_worker_type(SubBruteAttackView* instance, bool is_continuous_worker); void subbrute_attack_view_init_values( SubBruteAttackView* instance, uint8_t index, uint64_t max_value, uint64_t current_step, - bool is_attacking); \ No newline at end of file + bool is_attacking, + uint8_t extra_repeats); \ 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 index af911f775..cb59c94b3 100644 --- a/applications/plugins/subbrute/views/subbrute_main_view.c +++ b/applications/plugins/subbrute/views/subbrute_main_view.c @@ -5,19 +5,26 @@ #include #include #include -#include #define STATUS_BAR_Y_SHIFT 14 #define TAG "SubBruteMainView" +#define ITEMS_ON_SCREEN 3 + struct SubBruteMainView { View* view; SubBruteMainViewCallback callback; void* context; + uint8_t index; + bool is_select_byte; + const char* key_field; + uint8_t extra_repeats; + uint8_t window_position; }; typedef struct { uint8_t index; + uint8_t extra_repeats; uint8_t window_position; bool is_select_byte; const char* key_field; @@ -80,26 +87,27 @@ FuriString* center_displayed_key(const char* key_cstr, uint8_t index) { } void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { - SubBruteMainViewModel* m = model; - // Title canvas_set_font(canvas, FontPrimary); canvas_draw_box(canvas, 0, 0, canvas_width(canvas), STATUS_BAR_Y_SHIFT); canvas_invert_color(canvas); - canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, "Sub-GHz BruteForcer 3.1"); + canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, "Sub-GHz BruteForcer 3.2"); canvas_invert_color(canvas); - if(m->is_select_byte) { + uint16_t screen_width = canvas_width(canvas); + uint16_t screen_height = canvas_height(canvas); + + if(model->is_select_byte) { #ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "key_field: %s", m->key_field); + //FURI_LOG_D(TAG, "key_field: %s", model->key_field); #endif char msg_index[18]; - snprintf(msg_index, sizeof(msg_index), "Field index : %d", m->index); + snprintf(msg_index, sizeof(msg_index), "Field index : %d", model->index); canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index); FuriString* menu_items; - menu_items = center_displayed_key(m->key_field, m->index); + menu_items = center_displayed_key(model->key_field, model->index); canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned( canvas, 64, 40, AlignCenter, AlignTop, furi_string_get_cstr(menu_items)); @@ -114,17 +122,16 @@ void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { // Menu canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - uint8_t items_on_screen = 3; const uint8_t item_height = 16; #ifdef FURI_DEBUG - //FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, m->index); + //FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, model->index); #endif for(uint8_t position = 0; position < SubBruteAttackTotalCount; ++position) { uint8_t item_position = position - model->window_position; - if(item_position < items_on_screen) { - if(m->index == position) { + if(item_position < ITEMS_ON_SCREEN) { + if(model->index == position) { canvas_draw_str_aligned( canvas, 4, @@ -132,6 +139,25 @@ void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { AlignLeft, AlignCenter, subbrute_protocol_name(position)); + + if(model->extra_repeats > 0) { + canvas_set_font(canvas, FontBatteryPercent); + char buffer[10]; + snprintf( + buffer, + sizeof(buffer), + "x%d", + model->extra_repeats + subbrute_protocol_repeats_count(model->index)); + canvas_draw_str_aligned( + canvas, + screen_width - 15, + 9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, + AlignLeft, + AlignCenter, + buffer); + canvas_set_font(canvas, FontSecondary); + } + elements_frame( canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15); } else { @@ -148,10 +174,10 @@ void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { elements_scrollbar_pos( canvas, - canvas_width(canvas), + screen_width, STATUS_BAR_Y_SHIFT + 2, - canvas_height(canvas) - STATUS_BAR_Y_SHIFT, - m->index, + screen_height - STATUS_BAR_Y_SHIFT, + model->index, SubBruteAttackTotalCount); } } @@ -159,124 +185,124 @@ void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) { bool subbrute_main_view_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "InputKey: %d", event->key); -#endif if(event->key == InputKeyBack && event->type == InputTypeShort) { +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "InputKey: BACK"); +#endif return false; } SubBruteMainView* instance = context; +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "InputKey: %d, extra_repeats: %d", event->key, instance->extra_repeats); +#endif const uint8_t min_value = 0; const uint8_t correct_total = SubBruteAttackTotalCount - 1; + uint8_t max_repeats = 9 - subbrute_protocol_repeats_count(instance->index); uint8_t index = 0; - bool is_select_byte = false; - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { is_select_byte = model->is_select_byte; }, - false); + bool updated = false; bool consumed = false; - if(!is_select_byte) { - if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { - bool ret = false; - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - uint8_t items_on_screen = 3; - 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->window_position = model->index; - if(model->window_position > 0) { - model->window_position -= 1; - } + bool is_short = (event->type == InputTypeShort) || (event->type == InputTypeRepeat); - if(SubBruteAttackTotalCount <= items_on_screen) { - model->window_position = 0; - } else { - if(model->window_position >= - (SubBruteAttackTotalCount - items_on_screen)) { - model->window_position = - (SubBruteAttackTotalCount - items_on_screen); - } - } - } - index = model->index; - }, - ret); - } - -#ifdef FURI_DEBUG - with_view_model( - instance->view, SubBruteMainViewModel * model, { index = model->index; }, false); - FURI_LOG_I(TAG, "Index: %d", index); -#endif - - if(event->key == InputKeyOk && event->type == InputTypeShort) { + if(!instance->is_select_byte) { + if(event->key == InputKeyUp && is_short) { + if(instance->index == min_value) { + instance->index = correct_total; + } else { + instance->index = CLAMP(instance->index - 1, correct_total, min_value); + } + instance->extra_repeats = 0; + updated = true; + consumed = true; + } else if(event->key == InputKeyDown && is_short) { + if(instance->index == correct_total) { + instance->index = min_value; + } else { + instance->index = CLAMP(instance->index + 1, correct_total, min_value); + } + instance->extra_repeats = 0; + updated = true; + consumed = true; + } else if(event->key == InputKeyLeft && is_short) { + instance->extra_repeats = CLAMP(instance->extra_repeats - 1, max_repeats, 0); + updated = true; + consumed = true; + } else if(event->key == InputKeyRight && is_short) { + instance->extra_repeats = CLAMP(instance->extra_repeats + 1, max_repeats, 0); + updated = true; + consumed = true; + } else if(event->key == InputKeyOk && is_short) { if(index == SubBruteAttackLoadFile) { instance->callback(SubBruteCustomEventTypeLoadFile, instance->context); } else { instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context); } consumed = true; + updated = true; + } + if(updated) { + instance->window_position = instance->index; + if(instance->window_position > 0) { + instance->window_position -= 1; + } + + if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { + instance->window_position = 0; + } else { + if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { + instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); + } + } } } else { - if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { - with_view_model( - instance->view, - SubBruteMainViewModel * model, - { - if(event->key == InputKeyLeft) { - if(model->index > 0) { - model->index--; - } - } else if(event->key == InputKeyRight) { - if(model->index < 7) { - model->index++; - } - } - - index = model->index; - }, - true); - } - -#ifdef FURI_DEBUG - with_view_model( - instance->view, SubBruteMainViewModel * model, { index = model->index; }, false); - FURI_LOG_I(TAG, "Index: %d", index); -#endif - - if(event->key == InputKeyOk && event->type == InputTypeShort) { + if(event->key == InputKeyLeft && is_short) { + if(instance->index > 0) { + instance->index--; + } + updated = true; + } else if(event->key == InputKeyRight && is_short) { + if(instance->index < 7) { + instance->index++; + } + updated = true; + } else if(event->key == InputKeyOk && is_short) { instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context); consumed = true; + updated = true; } } + if(updated) { + with_view_model( + instance->view, + SubBruteMainViewModel * model, + { + model->index = instance->index; + model->window_position = instance->window_position; + model->key_field = instance->key_field; + model->is_select_byte = instance->is_select_byte; + model->extra_repeats = instance->extra_repeats; + }, + true); + } + return consumed; } void subbrute_main_view_enter(void* context) { furi_assert(context); + SubBruteMainView* instance = context; + + with_view_model( + instance->view, + SubBruteMainViewModel * model, + { + model->key_field = NULL; + model->is_select_byte = false; + }, + true); #ifdef FURI_DEBUG FURI_LOG_D(TAG, "subbrute_main_view_enter"); @@ -309,9 +335,16 @@ SubBruteMainView* subbrute_main_view_alloc() { model->window_position = 0; model->key_field = NULL; model->is_select_byte = false; + model->extra_repeats = 0; }, true); + instance->index = 0; + instance->window_position = 0; + instance->key_field = NULL; + instance->is_select_byte = false; + instance->extra_repeats = 0; + return instance; } @@ -337,44 +370,44 @@ void subbrute_main_view_set_index( #ifdef FURI_DEBUG FURI_LOG_I(TAG, "Set index: %d", idx); #endif + instance->is_select_byte = is_select_byte; + instance->key_field = key_field; + instance->index = idx; + instance->window_position = idx; + + if(!is_select_byte) { + if(instance->window_position > 0) { + instance->window_position -= 1; + } + + if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) { + instance->window_position = 0; + } else { + if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) { + instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN); + } + } + } + with_view_model( instance->view, SubBruteMainViewModel * model, { - model->is_select_byte = is_select_byte; - model->key_field = key_field; - model->index = idx; - model->window_position = idx; - - if(!is_select_byte) { - uint8_t items_on_screen = 3; - - if(model->window_position > 0) { - model->window_position -= 1; - } - - if(SubBruteAttackTotalCount <= items_on_screen) { - model->window_position = 0; - } else { - if(model->window_position >= (SubBruteAttackTotalCount - items_on_screen)) { - model->window_position = (SubBruteAttackTotalCount - items_on_screen); - } - } - } + model->index = instance->index; + model->window_position = instance->window_position; + model->key_field = instance->key_field; + model->is_select_byte = instance->is_select_byte; + model->extra_repeats = instance->extra_repeats; }, true); } SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) { furi_assert(instance); + return instance->index; +} - uint8_t idx = 0; - with_view_model( - instance->view, SubBruteMainViewModel * model, { idx = model->index; }, false); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Get index: %d", idx); -#endif - - return idx; +uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance) { + furi_assert(instance); + return instance->extra_repeats; } \ 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 index 361dbc22b..6aa11cec8 100644 --- a/applications/plugins/subbrute/views/subbrute_main_view.h +++ b/applications/plugins/subbrute/views/subbrute_main_view.h @@ -1,6 +1,7 @@ #pragma once #include "../subbrute_custom_event.h" +#include "../subbrute_protocols.h" #include #include #include @@ -21,7 +22,8 @@ void subbrute_main_view_set_index( uint8_t idx, bool is_select_byte, const char* key_field); -uint8_t subbrute_main_view_get_index(SubBruteMainView* instance); +SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance); +uint8_t subbrute_main_view_get_extra_repeats(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);