Merge branch 'DarkFlippers:dev' into dev-master

This commit is contained in:
Der Skythe 2022-10-19 11:03:49 +04:00 committed by GitHub
commit c2e58f9633
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 5 additions and 3455 deletions

3
.gitmodules vendored
View file

@ -31,3 +31,6 @@
[submodule "lib/cxxheaderparser"]
path = lib/cxxheaderparser
url = https://github.com/robotpy/cxxheaderparser.git
[submodule "applications/plugins/subbrute"]
path = applications/plugins/subbrute
url = https://github.com/derskythe/flipperzero-subbrute.git

@ -0,0 +1 @@
Subproject commit 06ecd1aacbd65205bedbf04a3aa8dd6e7c3e4545

View file

@ -1,8 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* @G4N4P4T1 wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/

View file

@ -1,4 +0,0 @@
# FlipFrid
SubGhz Fuzzer
select your base message, the field to fuzz and let's get fuzzy !

View file

@ -1,12 +0,0 @@
App(
appid="SubGHz_Bruteforcer",
name="Sub-GHz Bruteforcer",
apptype=FlipperAppType.EXTERNAL,
entry_point="subbrute_app",
cdefines=["APP_SUB_BRUTE"],
requires=["gui","dialogs"],
stack_size=2 * 1024,
order=11,
fap_icon="subbrute_10px.png",
fap_category="Tools",
)

View file

@ -1,417 +0,0 @@
#include "subbrute_worker_private.h"
#include <string.h>
#include <toolbox/stream/stream.h>
#include <flipper_format.h>
#include <flipper_format_i.h>
#include <lib/subghz/protocols/protocol_items.h>
#define TAG "SubBruteWorker"
#define SUBBRUTE_TX_TIMEOUT 5
#define SUBBRUTE_MANUAL_TRANSMIT_INTERVAL 400
SubBruteWorker* subbrute_worker_alloc() {
SubBruteWorker* instance = malloc(sizeof(SubBruteWorker));
instance->state = SubBruteWorkerStateIDLE;
instance->step = 0;
instance->worker_running = false;
instance->initiated = false;
instance->last_time_tx_data = 0;
instance->load_index = 0;
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->context = NULL;
instance->callback = NULL;
instance->decoder_result = NULL;
instance->transmitter = NULL;
instance->environment = subghz_environment_alloc();
subghz_environment_set_protocol_registry(
instance->environment, (void*)&subghz_protocol_registry);
instance->transmit_mode = false;
return instance;
}
void subbrute_worker_free(SubBruteWorker* instance) {
furi_assert(instance);
// I don't know how to free this
instance->decoder_result = NULL;
if(instance->transmitter != NULL) {
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
}
subghz_environment_free(instance->environment);
instance->environment = NULL;
furi_thread_free(instance->thread);
free(instance);
}
uint64_t subbrute_worker_get_step(SubBruteWorker* instance) {
return instance->step;
}
bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step) {
furi_assert(instance);
if(!subbrute_worker_can_manual_transmit(instance)) {
FURI_LOG_W(TAG, "Cannot set step during running mode");
return false;
}
instance->step = step;
return true;
}
bool subbrute_worker_init_default_attack(
SubBruteWorker* instance,
SubBruteAttacks attack_type,
uint64_t step,
const SubBruteProtocol* protocol) {
furi_assert(instance);
if(instance->worker_running) {
FURI_LOG_W(TAG, "Init Worker when it's running");
subbrute_worker_stop(instance);
}
instance->attack = attack_type;
instance->frequency = protocol->frequency;
instance->preset = protocol->preset;
instance->file = protocol->file;
instance->step = step;
instance->bits = protocol->bits;
instance->te = protocol->te;
instance->repeat = protocol->repeat;
instance->load_index = 0;
instance->file_key = NULL;
instance->max_value = subbrute_protocol_calc_max_value(instance->attack, instance->bits);
instance->initiated = true;
instance->state = SubBruteWorkerStateReady;
subbrute_worker_send_callback(instance);
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"subbrute_worker_init_default_attack: %s, bits: %d, preset: %s, file: %s, te: %d, repeat: %d, max_value: %lld",
subbrute_protocol_name(instance->attack),
instance->bits,
subbrute_protocol_preset(instance->preset),
subbrute_protocol_file(instance->file),
instance->te,
instance->repeat,
instance->max_value);
#endif
return true;
}
bool subbrute_worker_init_file_attack(
SubBruteWorker* instance,
uint64_t step,
uint8_t load_index,
const char* file_key,
SubBruteProtocol* protocol) {
furi_assert(instance);
if(instance->worker_running) {
FURI_LOG_W(TAG, "Init Worker when it's running");
subbrute_worker_stop(instance);
}
instance->attack = SubBruteAttackLoadFile;
instance->frequency = protocol->frequency;
instance->preset = protocol->preset;
instance->file = protocol->file;
instance->step = step;
instance->bits = protocol->bits;
instance->te = protocol->te;
instance->load_index = load_index;
instance->repeat = protocol->repeat;
instance->file_key = file_key;
instance->max_value = subbrute_protocol_calc_max_value(instance->attack, instance->bits);
instance->initiated = true;
instance->state = SubBruteWorkerStateReady;
subbrute_worker_send_callback(instance);
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"subbrute_worker_init_file_attack: %s, bits: %d, preset: %s, file: %s, te: %d, repeat: %d, max_value: %lld",
subbrute_protocol_name(instance->attack),
instance->bits,
subbrute_protocol_preset(instance->preset),
subbrute_protocol_file(instance->file),
instance->te,
instance->repeat,
instance->max_value);
#endif
return true;
}
bool subbrute_worker_start(SubBruteWorker* instance) {
furi_assert(instance);
if(!instance->initiated) {
FURI_LOG_W(TAG, "Worker not init!");
return false;
}
if(instance->worker_running) {
FURI_LOG_W(TAG, "Worker is already running!");
return false;
}
if(instance->state != SubBruteWorkerStateReady &&
instance->state != SubBruteWorkerStateFinished) {
FURI_LOG_W(TAG, "Worker cannot start, invalid device state: %d", instance->state);
return false;
}
instance->worker_running = true;
furi_thread_start(instance->thread);
return true;
}
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_transmit_current_key(SubBruteWorker* instance, uint64_t step) {
furi_assert(instance);
if(!instance->initiated) {
FURI_LOG_W(TAG, "Worker not init!");
return false;
}
if(instance->worker_running) {
FURI_LOG_W(TAG, "Worker in running state!");
return false;
}
if(instance->state != SubBruteWorkerStateReady &&
instance->state != SubBruteWorkerStateFinished) {
FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state);
return false;
}
uint32_t ticks = furi_get_tick();
if((ticks - instance->last_time_tx_data) < SUBBRUTE_MANUAL_TRANSMIT_INTERVAL) {
#if FURI_DEBUG
FURI_LOG_D(TAG, "Need to wait, current: %ld", ticks - instance->last_time_tx_data);
#endif
return false;
}
instance->last_time_tx_data = ticks;
instance->step = step;
bool result;
instance->protocol_name = subbrute_protocol_file(instance->file);
FlipperFormat* flipper_format = flipper_format_string_alloc();
Stream* stream = flipper_format_get_raw_stream(flipper_format);
stream_clean(stream);
if(instance->attack == SubBruteAttackLoadFile) {
subbrute_protocol_file_payload(
stream,
step,
instance->bits,
instance->te,
instance->repeat,
instance->load_index,
instance->file_key);
} else {
subbrute_protocol_default_payload(
stream, step, instance->bits, instance->te, instance->repeat);
}
// size_t written = stream_write_string(stream, payload);
// if(written <= 0) {
// FURI_LOG_W(TAG, "Error creating packet! EXIT");
// result = false;
// } else {
subbrute_worker_subghz_transmit(instance, flipper_format);
result = true;
#if FURI_DEBUG
FURI_LOG_D(TAG, "Manual transmit done");
#endif
// }
flipper_format_free(flipper_format);
// furi_string_free(payload);
return result;
}
bool subbrute_worker_is_running(SubBruteWorker* instance) {
return instance->worker_running;
}
bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance) {
furi_assert(instance);
if(!instance->initiated) {
FURI_LOG_W(TAG, "Worker not init!");
return false;
}
return !instance->worker_running && instance->state != SubBruteWorkerStateIDLE &&
instance->state != SubBruteWorkerStateTx &&
((furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_MANUAL_TRANSMIT_INTERVAL);
}
void subbrute_worker_set_callback(
SubBruteWorker* instance,
SubBruteWorkerCallback callback,
void* context) {
furi_assert(instance);
instance->callback = callback;
instance->context = context;
}
void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format) {
while(instance->transmit_mode) {
furi_delay_ms(SUBBRUTE_TX_TIMEOUT);
}
instance->transmit_mode = true;
if(instance->transmitter != NULL) {
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
}
instance->transmitter =
subghz_transmitter_alloc_init(instance->environment, instance->protocol_name);
subghz_transmitter_deserialize(instance->transmitter, flipper_format);
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(instance->preset);
furi_hal_subghz_set_frequency_and_path(instance->frequency);
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, instance->transmitter);
while(!furi_hal_subghz_is_async_tx_complete()) {
furi_delay_ms(SUBBRUTE_TX_TIMEOUT);
}
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
furi_hal_subghz_sleep();
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
instance->transmit_mode = false;
}
void subbrute_worker_send_callback(SubBruteWorker* instance) {
if(instance->callback != NULL) {
instance->callback(instance->context, instance->state);
}
}
/**
* 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;
}
if(instance->state != SubBruteWorkerStateReady &&
instance->state != SubBruteWorkerStateFinished) {
FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state);
return -2;
}
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Worker start");
#endif
SubBruteWorkerState local_state = instance->state = SubBruteWorkerStateTx;
subbrute_worker_send_callback(instance);
instance->protocol_name = subbrute_protocol_file(instance->file);
FlipperFormat* flipper_format = flipper_format_string_alloc();
Stream* stream = flipper_format_get_raw_stream(flipper_format);
while(instance->worker_running) {
stream_clean(stream);
if(instance->attack == SubBruteAttackLoadFile) {
subbrute_protocol_file_payload(
stream,
instance->step,
instance->bits,
instance->te,
instance->repeat,
instance->load_index,
instance->file_key);
} else {
subbrute_protocol_default_payload(
stream, instance->step, instance->bits, instance->te, instance->repeat);
}
#ifdef FURI_DEBUG
//FURI_LOG_I(TAG, "Payload: %s", furi_string_get_cstr(payload));
//furi_delay_ms(SUBBRUTE_MANUAL_TRANSMIT_INTERVAL / 4);
#endif
// size_t written = stream_write_stream_write_string(stream, payload);
// if(written <= 0) {
// FURI_LOG_W(TAG, "Error creating packet! BREAK");
// instance->worker_running = false;
// local_state = SubBruteWorkerStateIDLE;
// furi_string_free(payload);
// break;
// }
subbrute_worker_subghz_transmit(instance, flipper_format);
if(instance->step + 1 > instance->max_value) {
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Worker finished to end");
#endif
local_state = SubBruteWorkerStateFinished;
// furi_string_free(payload);
break;
}
instance->step++;
// furi_string_free(payload);
furi_delay_ms(SUBBRUTE_TX_TIMEOUT);
}
flipper_format_free(flipper_format);
instance->worker_running = false; // Because we have error states
instance->state = local_state == SubBruteWorkerStateTx ? SubBruteWorkerStateReady :
local_state;
subbrute_worker_send_callback(instance);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Worker stop");
#endif
return 0;
}

View file

@ -1,39 +0,0 @@
#pragma once
#include "../subbrute_protocols.h"
typedef enum {
SubBruteWorkerStateIDLE,
SubBruteWorkerStateReady,
SubBruteWorkerStateTx,
SubBruteWorkerStateFinished
} SubBruteWorkerState;
typedef void (*SubBruteWorkerCallback)(void* context, SubBruteWorkerState state);
typedef struct SubBruteWorker SubBruteWorker;
SubBruteWorker* subbrute_worker_alloc();
void subbrute_worker_free(SubBruteWorker* instance);
uint64_t subbrute_worker_get_step(SubBruteWorker* instance);
bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step);
bool subbrute_worker_is_running(SubBruteWorker* instance);
bool subbrute_worker_init_default_attack(
SubBruteWorker* instance,
SubBruteAttacks attack_type,
uint64_t step,
const SubBruteProtocol* protocol);
bool subbrute_worker_init_file_attack(
SubBruteWorker* instance,
uint64_t step,
uint8_t load_index,
const char* file_key,
SubBruteProtocol* protocol);
bool subbrute_worker_start(SubBruteWorker* instance);
void subbrute_worker_stop(SubBruteWorker* instance);
bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step);
bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance);
void subbrute_worker_set_callback(
SubBruteWorker* instance,
SubBruteWorkerCallback callback,
void* context);

View file

@ -1,47 +0,0 @@
#pragma once
#include "subbrute_worker.h"
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/environment.h>
struct SubBruteWorker {
SubBruteWorkerState state;
volatile bool worker_running;
volatile bool initiated;
volatile bool transmit_mode;
// Current step
uint64_t step;
// SubGhz
FuriThread* thread;
SubGhzProtocolDecoderBase* decoder_result;
SubGhzEnvironment* environment;
SubGhzTransmitter* transmitter;
const char* protocol_name;
// Initiated values
SubBruteAttacks attack; // Attack state
uint32_t frequency;
FuriHalSubGhzPreset preset;
SubBruteFileProtocol file;
uint8_t bits;
uint8_t te;
uint8_t repeat;
uint8_t load_index; // Index of group to bruteforce in loaded file
const char* file_key;
uint64_t max_value; // Max step
// Manual transmit
uint32_t last_time_tx_data;
// Callback for changed states
SubBruteWorkerCallback callback;
void* context;
};
int32_t subbrute_worker_thread(void* context);
void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format);
void subbrute_worker_send_callback(SubBruteWorker* instance);

View file

@ -1,29 +0,0 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) 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

View file

@ -1,7 +0,0 @@
ADD_SCENE(subbrute, load_file, LoadFile)
ADD_SCENE(subbrute, load_select, LoadSelect)
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)

View file

@ -1,87 +0,0 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneLoadFile"
//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;
// Input events and views are managed by file_browser
FuriString* app_folder;
FuriString* load_path;
load_path = furi_string_alloc();
app_folder = furi_string_alloc_set(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, load_path, app_folder, &browser_options);
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"load_path: %s, app_folder: %s",
furi_string_get_cstr(load_path),
furi_string_get_cstr(app_folder));
#endif
if(res) {
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);
if(load_result == SubBruteFileResultOk) {
if(!subbrute_worker_init_file_attack(
instance->worker,
instance->device->key_index,
instance->device->load_index,
instance->device->file_key,
instance->device->file_protocol_info)) {
furi_crash("Invalid attack set!");
}
// Ready to run!
FURI_LOG_I(TAG, "Ready to run");
res = true;
}
}
if(load_result == SubBruteFileResultOk) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadSelect);
} else {
FURI_LOG_E(TAG, "Returned error: %d", load_result);
FuriString* dialog_msg;
dialog_msg = furi_string_alloc();
furi_string_cat_printf(
dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result));
dialog_message_show_storage_error(instance->dialogs, furi_string_get_cstr(dialog_msg));
furi_string_free(dialog_msg);
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneStart);
}
} else {
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneStart);
}
furi_string_free(app_folder);
furi_string_free(load_path);
}
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;
}

View file

@ -1,62 +0,0 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneStart"
void subbrute_scene_load_select_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_select_on_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_load_select_on_enter");
#endif
SubBruteState* instance = (SubBruteState*)context;
SubBruteMainView* view = instance->view_main;
instance->current_view = SubBruteViewMain;
subbrute_main_view_set_callback(view, subbrute_scene_load_select_callback, instance);
subbrute_main_view_set_index(view, 7, true, instance->device->file_key);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
}
void subbrute_scene_load_select_on_exit(void* context) {
UNUSED(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_load_select_on_exit");
#endif
}
bool subbrute_scene_load_select_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubBruteCustomEventTypeIndexSelected) {
instance->device->load_index = subbrute_main_view_get_index(instance->view_main);
if(!subbrute_worker_init_file_attack(
instance->worker,
instance->device->key_index,
instance->device->load_index,
instance->device->file_key,
instance->device->file_protocol_info)) {
furi_crash("Invalid attack set!");
}
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
if(!scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneStart)) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
}
consumed = true;
}
return consumed;
}

View file

@ -1,105 +0,0 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneRunAttack"
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);
}
static void
subbrute_scene_run_attack_device_state_changed(void* context, SubBruteWorkerState state) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
if(state == SubBruteWorkerStateIDLE) {
// Can't be IDLE on this step!
view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError);
} else if(state == SubBruteWorkerStateFinished) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished);
}
}
void subbrute_scene_run_attack_on_exit(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
subbrute_worker_stop(instance->worker);
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_worker_set_callback(
instance->worker, subbrute_scene_run_attack_device_state_changed, instance);
if(!subbrute_worker_is_running(instance->worker)) {
subbrute_worker_set_step(instance->worker, instance->device->key_index);
if(!subbrute_worker_start(instance->worker)) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypeError);
} else {
notification_message(instance->notifications, &sequence_single_vibro);
notification_message(instance->notifications, &sequence_blink_start_yellow);
}
}
}
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) {
uint64_t step = subbrute_worker_get_step(instance->worker);
instance->device->key_index = step;
subbrute_attack_view_set_current_step(view, step);
if(event.event == SubBruteCustomEventTypeTransmitFinished) {
notification_message(instance->notifications, &sequence_display_backlight_on);
notification_message(instance->notifications, &sequence_double_vibro);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
} else if(
event.event == SubBruteCustomEventTypeTransmitNotStarted ||
event.event == SubBruteCustomEventTypeBackPressed) {
if(subbrute_worker_is_running(instance->worker)) {
// Notify
notification_message(instance->notifications, &sequence_single_vibro);
}
// Stop transmit
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneSetupAttack);
} else if(event.event == SubBruteCustomEventTypeError) {
notification_message(instance->notifications, &sequence_error);
// Stop transmit
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneSetupAttack);
} else if(event.event == SubBruteCustomEventTypeUpdateView) {
//subbrute_attack_view_set_current_step(view, instance->device->key_index);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeTick) {
uint64_t step = subbrute_worker_get_step(instance->worker);
instance->device->key_index = step;
subbrute_attack_view_set_current_step(view, step);
consumed = true;
}
return consumed;
}

View file

@ -1,84 +0,0 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#include <lib/toolbox/random_name.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->text_store, sizeof(instance->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->text_store,
SUBBRUTE_MAX_LEN_NAME,
true);
furi_string_reset(instance->file_path);
furi_string_set_str(instance->file_path, SUBBRUTE_PATH);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
furi_string_get_cstr(instance->file_path), SUBBRUTE_FILE_EXT, "");
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewTextInput);
}
bool subbrute_scene_save_name_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
scene_manager_previous_scene(instance->scene_manager);
return true;
} else if(
event.type == SceneManagerEventTypeCustom &&
event.event == SubBruteCustomEventTypeTextEditDone) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Saving: %s", instance->text_store);
#endif
bool success = false;
if(strcmp(instance->text_store, "")) {
furi_string_reset(instance->file_path);
furi_string_cat_printf(
instance->file_path,
"%s/%s%s",
SUBBRUTE_PATH,
instance->text_store,
SUBBRUTE_FILE_EXT);
if(subbrute_device_save_file(
instance->device, furi_string_get_cstr(instance->file_path))) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveSuccess);
success = true;
consumed = true;
}
}
if(!success) {
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);
furi_string_reset(instance->file_path);
}

View file

@ -1,51 +0,0 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
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_popup_closed_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 == SubBruteCustomEventTypePopupClosed) {
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);
}

View file

@ -1,134 +0,0 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneSetupAttack"
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);
}
static void
subbrute_scene_setup_attack_device_state_changed(void* context, SubBruteWorkerState state) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
if(state == SubBruteWorkerStateIDLE) {
// Can't be IDLE on this step!
view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError);
}
}
void subbrute_scene_setup_attack_on_enter(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
SubBruteAttackView* view = instance->view_attack;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Enter Attack: %d", instance->device->attack);
#endif
subbrute_worker_set_callback(
instance->worker, subbrute_scene_setup_attack_device_state_changed, context);
if(subbrute_worker_is_running(instance->worker)) {
instance->device->key_index = subbrute_worker_get_step(instance->worker);
subbrute_worker_stop(instance->worker);
}
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->key_index,
false);
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);
}
void subbrute_scene_setup_attack_on_exit(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_scene_setup_attack_on_exit");
#endif
SubBruteState* instance = (SubBruteState*)context;
subbrute_worker_stop(instance->worker);
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) {
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(
view,
instance->device->attack,
instance->device->max_value,
instance->device->key_index,
false);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName);
} else if(event.event == SubBruteCustomEventTypeBackPressed) {
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->key_index,
false);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
} else if(event.event == SubBruteCustomEventTypeError) {
notification_message(instance->notifications, &sequence_error);
} else if(event.event == SubBruteCustomEventTypeTransmitCustom) {
// We can transmit only in not working states
if(subbrute_worker_can_manual_transmit(instance->worker)) {
// MANUAL Transmit!
// Blink
notification_message(instance->notifications, &sequence_blink_green_100);
subbrute_worker_transmit_current_key(
instance->worker, instance->device->key_index);
// Stop
notification_message(instance->notifications, &sequence_blink_stop);
}
} else if(event.event == SubBruteCustomEventTypeChangeStepUp) {
// +1
uint64_t step = subbrute_device_add_step(instance->device, 1);
subbrute_worker_set_step(instance->worker, step);
subbrute_attack_view_set_current_step(view, step);
} else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) {
// +50
uint64_t step = subbrute_device_add_step(instance->device, 50);
subbrute_worker_set_step(instance->worker, step);
subbrute_attack_view_set_current_step(view, step);
} else if(event.event == SubBruteCustomEventTypeChangeStepDown) {
// -1
uint64_t step = subbrute_device_add_step(instance->device, -1);
subbrute_worker_set_step(instance->worker, step);
subbrute_attack_view_set_current_step(view, step);
} else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) {
// -50
uint64_t step = subbrute_device_add_step(instance->device, -50);
subbrute_worker_set_step(instance->worker, step);
subbrute_attack_view_set_current_step(view, step);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeTick) {
if(subbrute_worker_is_running(instance->worker)) {
instance->device->key_index = subbrute_worker_get_step(instance->worker);
}
subbrute_attack_view_set_current_step(view, instance->device->key_index);
consumed = true;
}
return consumed;
}

View file

@ -1,77 +0,0 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneStart"
void subbrute_scene_start_callback(SubBruteCustomEvent event, void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_scene_start_callback");
#endif
view_dispatcher_send_custom_event(instance->view_dispatcher, event);
}
void subbrute_scene_start_on_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_start_on_enter");
#endif
SubBruteState* instance = (SubBruteState*)context;
SubBruteMainView* view = instance->view_main;
instance->current_view = SubBruteViewMain;
subbrute_main_view_set_callback(view, subbrute_scene_start_callback, instance);
subbrute_main_view_set_index(view, instance->device->attack, false, NULL);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
}
void subbrute_scene_start_on_exit(void* context) {
UNUSED(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_start_on_exit");
#endif
}
bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"Event: %ld, SubBruteCustomEventTypeMenuSelected: %s, SubBruteCustomEventTypeLoadFile: %s",
event.event,
event.event == SubBruteCustomEventTypeMenuSelected ? "true" : "false",
event.event == SubBruteCustomEventTypeLoadFile ? "true" : "false");
#endif
if(event.event == SubBruteCustomEventTypeMenuSelected) {
SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main);
if(subbrute_device_attack_set(instance->device, attack) != SubBruteFileResultOk ||
!subbrute_worker_init_default_attack(
instance->worker,
attack,
instance->device->key_index,
instance->device->protocol_info)) {
furi_crash("Invalid attack set!");
}
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true;
} else if(event.event == SubBruteCustomEventTypeLoadFile) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
//exit app
scene_manager_stop(instance->scene_manager);
view_dispatcher_stop(instance->view_dispatcher);
consumed = true;
}
return consumed;
}

View file

@ -1,30 +0,0 @@
#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,
};

View file

@ -1,188 +0,0 @@
#include "subbrute_i.h"
#include "subbrute_custom_event.h"
#include "scenes/subbrute_scene.h"
#define TAG "SubBruteApp"
static 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);
}
static bool subbrute_back_event_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
return scene_manager_handle_back_event(instance->scene_manager);
}
static 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* instance = malloc(sizeof(SubBruteState));
memset(instance->text_store, 0, sizeof(instance->text_store));
instance->file_path = furi_string_alloc();
instance->scene_manager = scene_manager_alloc(&subbrute_scene_handlers, instance);
instance->view_dispatcher = view_dispatcher_alloc();
instance->gui = furi_record_open(RECORD_GUI);
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);
//Dialog
instance->dialogs = furi_record_open(RECORD_DIALOGS);
// Notifications
instance->notifications = furi_record_open(RECORD_NOTIFICATION);
// Devices
instance->device = subbrute_device_alloc();
// SubBruteWorker
instance->worker = subbrute_worker_alloc();
// 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));
// Popup
instance->popup = popup_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, SubBruteViewPopup, popup_get_view(instance->popup));
// 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));
//instance->flipper_format = flipper_format_string_alloc();
//instance->environment = subghz_environment_alloc();
return instance;
}
void subbrute_free(SubBruteState* instance) {
furi_assert(instance);
// SubBruteWorker
subbrute_worker_stop(instance->worker);
subbrute_worker_free(instance->worker);
// SubBruteDevice
subbrute_device_free(instance->device);
// Notifications
notification_message(instance->notifications, &sequence_blink_stop);
furi_record_close(RECORD_NOTIFICATION);
instance->notifications = NULL;
// 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);
instance->dialogs = NULL;
// Scene manager
scene_manager_free(instance->scene_manager);
// View Dispatcher
view_dispatcher_free(instance->view_dispatcher);
// GUI
furi_record_close(RECORD_GUI);
instance->gui = NULL;
furi_string_free(instance->file_path);
// The rest
free(instance);
}
void subbrute_text_input_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypeTextEditDone);
}
void subbrute_popup_closed_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypePopupClosed);
}
// ENTRYPOINT
int32_t subbrute_app(void* p) {
UNUSED(p);
SubBruteState* instance = subbrute_alloc();
view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
furi_hal_power_suppress_charge_enter();
notification_message(instance->notifications, &sequence_display_backlight_on);
view_dispatcher_run(instance->view_dispatcher);
furi_hal_power_suppress_charge_exit();
subbrute_free(instance);
return 0;
}

View file

@ -1,3 +0,0 @@
#pragma once
typedef struct SubBruteState SubBruteState;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -1,26 +0,0 @@
#pragma once
typedef enum {
// Reserve first 100 events for button types and indexes, starting from 0
SubBruteCustomEventTypeReserved = 100,
SubBruteCustomEventTypeBackPressed,
SubBruteCustomEventTypeIndexSelected,
SubBruteCustomEventTypeTransmitStarted,
SubBruteCustomEventTypeError,
SubBruteCustomEventTypeTransmitFinished,
SubBruteCustomEventTypeTransmitNotStarted,
SubBruteCustomEventTypeTransmitCustom,
SubBruteCustomEventTypeSaveFile,
SubBruteCustomEventTypeUpdateView,
SubBruteCustomEventTypeChangeStepUp,
SubBruteCustomEventTypeChangeStepDown,
SubBruteCustomEventTypeChangeStepUpMore,
SubBruteCustomEventTypeChangeStepDownMore,
SubBruteCustomEventTypeMenuSelected,
SubBruteCustomEventTypeTextEditDone,
SubBruteCustomEventTypePopupClosed,
SubBruteCustomEventTypeLoadFile,
} SubBruteCustomEvent;

View file

@ -1,459 +0,0 @@
#include "subbrute_device.h"
#include <stdint.h>
#include <storage/storage.h>
#include <lib/toolbox/stream/stream.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/flipper_format/flipper_format_i.h>
#include <lib/subghz/protocols/protocol_items.h>
#define TAG "SubBruteDevice"
SubBruteDevice* subbrute_device_alloc() {
SubBruteDevice* instance = malloc(sizeof(SubBruteDevice));
instance->key_index = 0;
instance->protocol_info = NULL;
instance->file_protocol_info = NULL;
instance->decoder_result = NULL;
instance->receiver = NULL;
instance->environment = subghz_environment_alloc();
subghz_environment_set_protocol_registry(
instance->environment, (void*)&subghz_protocol_registry);
#ifdef FURI_DEBUG
subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit433);
#else
subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit433);
#endif
return instance;
}
void subbrute_device_free(SubBruteDevice* instance) {
furi_assert(instance);
// I don't know how to free this
instance->decoder_result = NULL;
if(instance->receiver != NULL) {
subghz_receiver_free(instance->receiver);
instance->receiver = NULL;
}
subghz_environment_free(instance->environment);
instance->environment = NULL;
subbrute_device_free_protocol_info(instance);
free(instance);
}
uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) {
if(step > 0) {
if((instance->key_index + step) - instance->max_value == 1) {
instance->key_index = 0x00;
} else {
uint64_t value = instance->key_index + step;
if(value == instance->max_value) {
instance->key_index = value;
} else {
instance->key_index = value % instance->max_value;
}
}
} else {
if(instance->key_index + step == 0) {
instance->key_index = 0x00;
} else if(instance->key_index == 0) {
instance->key_index = instance->max_value;
} else {
uint64_t value = ((instance->key_index + step) + instance->max_value);
if(value == instance->max_value) {
instance->key_index = value;
} else {
instance->key_index = value % instance->max_value;
}
}
}
return instance->key_index;
}
bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name);
#endif
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
bool result = false;
do {
if(!flipper_format_file_open_always(file, dev_file_name)) {
FURI_LOG_E(TAG, "Failed to open file: %s", dev_file_name);
break;
}
Stream* stream = flipper_format_get_raw_stream(file);
if(instance->attack == SubBruteAttackLoadFile) {
subbrute_protocol_file_generate_file(
stream,
instance->file_protocol_info->frequency,
instance->file_protocol_info->preset,
instance->file_protocol_info->file,
instance->key_index,
instance->file_protocol_info->bits,
instance->file_protocol_info->te,
instance->file_protocol_info->repeat,
instance->load_index,
instance->file_key);
} else {
subbrute_protocol_default_generate_file(
stream,
instance->protocol_info->frequency,
instance->protocol_info->preset,
instance->protocol_info->file,
instance->key_index,
instance->protocol_info->bits,
instance->protocol_info->te,
instance->protocol_info->repeat);
}
result = true;
} while(false);
if(!result) {
FURI_LOG_E(TAG, "subbrute_device_save_file failed!");
}
flipper_format_file_close(file);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBruteAttacks type) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_attack_set: %d", type);
#endif
subbrute_device_attack_set_default_values(instance, type);
if(type != SubBruteAttackLoadFile) {
subbrute_device_free_protocol_info(instance);
instance->protocol_info = subbrute_protocol(type);
}
// For non-file types we didn't set SubGhzProtocolDecoderBase
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;
#ifdef FURI_DEBUG
uint8_t bits;
uint8_t te;
uint8_t repeat;
FuriHalSubGhzPreset preset;
SubBruteFileProtocol file;
#endif
if(type != SubBruteAttackLoadFile) {
instance->decoder_result = subghz_receiver_search_decoder_base_by_name(
instance->receiver, subbrute_protocol_file(instance->protocol_info->file));
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;
// Calc max value
instance->max_value =
subbrute_protocol_calc_max_value(instance->attack, instance->protocol_info->bits);
}
#ifdef FURI_DEBUG
bits = instance->protocol_info->bits;
te = instance->protocol_info->te;
repeat = instance->protocol_info->repeat;
preset = instance->protocol_info->preset;
file = instance->protocol_info->file;
#endif
} else {
// And here we need to set preset enum
protocol_check_result = SubBruteFileResultOk;
// Calc max value
instance->max_value =
subbrute_protocol_calc_max_value(instance->attack, instance->file_protocol_info->bits);
#ifdef FURI_DEBUG
bits = instance->file_protocol_info->bits;
te = instance->file_protocol_info->te;
repeat = instance->file_protocol_info->repeat;
preset = instance->file_protocol_info->preset;
file = instance->file_protocol_info->file;
#endif
}
subghz_receiver_free(instance->receiver);
instance->receiver = NULL;
if(protocol_check_result != SubBruteFileResultOk) {
return SubBruteFileResultProtocolNotFound;
}
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"subbrute_device_attack_set: %s, bits: %d, preset: %s, file: %s, te: %d, repeat: %d, max_value: %lld",
subbrute_protocol_name(instance->attack),
bits,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
te,
repeat,
instance->max_value);
#endif
return SubBruteFileResultOk;
}
uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* file_path) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_load_from_file: %s", file_path);
#endif
SubBruteFileResult result = SubBruteFileResultUnknown;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
subbrute_device_free_protocol_info(instance);
instance->file_protocol_info = malloc(sizeof(SubBruteProtocol));
FuriString* temp_str;
temp_str = furi_string_alloc();
uint32_t temp_data32;
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->file_protocol_info->frequency = temp_data32;
if(!furi_hal_subghz_is_tx_allowed(instance->file_protocol_info->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", temp_str)) {
FURI_LOG_E(TAG, "Preset FAIL");
result = SubBruteFileResultPresetInvalid;
} else {
instance->file_protocol_info->preset = subbrute_protocol_convert_preset(temp_str);
}
const char* protocol_file = NULL;
// Protocol
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
FURI_LOG_E(TAG, "Missing Protocol");
result = SubBruteFileResultMissingProtocol;
break;
} else {
instance->file_protocol_info->file = subbrute_protocol_file_protocol_name(temp_str);
protocol_file = subbrute_protocol_file(instance->file_protocol_info->file);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Protocol: %s", protocol_file);
#endif
}
instance->decoder_result =
subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_file);
if(!instance->decoder_result || strcmp(protocol_file, "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
// 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->file_protocol_info->bits = temp_data32;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Bit: %d", instance->file_protocol_info->bits);
#endif
}
// 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",
furi_string_get_cstr(temp_str));
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Key: %s", instance->file_key);
#endif
}
// 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->file_protocol_info->te = temp_data32 != 0 ? temp_data32 : 0;
}
// Repeat
if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Repeat: %ld", temp_data32);
#endif
instance->file_protocol_info->repeat = (uint8_t)temp_data32;
} else {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Repeat: 3 (default)");
#endif
instance->file_protocol_info->repeat = 3;
}
result = SubBruteFileResultOk;
} while(0);
furi_string_free(temp_str);
flipper_format_file_close(fff_data_file);
flipper_format_free(fff_data_file);
furi_record_close(RECORD_STORAGE);
subghz_receiver_free(instance->receiver);
instance->decoder_result = NULL;
instance->receiver = NULL;
if(result == SubBruteFileResultOk) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Loaded successfully");
#endif
} else {
subbrute_device_free_protocol_info(instance);
}
return result;
}
void subbrute_device_attack_set_default_values(
SubBruteDevice* instance,
SubBruteAttacks default_attack) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_attack_set_default_values");
#endif
instance->attack = default_attack;
instance->key_index = 0x00;
instance->load_index = 0x00;
memset(instance->current_key, 0, sizeof(instance->current_key));
if(default_attack != SubBruteAttackLoadFile) {
memset(instance->file_key, 0, sizeof(instance->file_key));
instance->max_value = (uint64_t)0x00;
}
}
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;
}
void subbrute_device_free_protocol_info(SubBruteDevice* instance) {
furi_assert(instance);
instance->protocol_info = NULL;
if(instance->file_protocol_info) {
free(instance->file_protocol_info);
}
instance->file_protocol_info = NULL;
}

View file

@ -1,70 +0,0 @@
#pragma once
#include "subbrute_protocols.h"
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/environment.h>
#define SUBBRUTE_TEXT_STORE_SIZE 256
#define SUBBRUTE_MAX_LEN_NAME 64
#define SUBBRUTE_PATH EXT_PATH("subghz")
#define SUBBRUTE_FILE_EXT ".sub"
#define SUBBRUTE_PAYLOAD_SIZE 16
typedef enum {
SubBruteFileResultUnknown,
SubBruteFileResultOk,
SubBruteFileResultErrorOpenFile,
SubBruteFileResultMissingOrIncorrectHeader,
SubBruteFileResultFrequencyNotAllowed,
SubBruteFileResultMissingOrIncorrectFrequency,
SubBruteFileResultPresetInvalid,
SubBruteFileResultMissingProtocol,
SubBruteFileResultProtocolNotSupported,
SubBruteFileResultDynamicProtocolNotValid,
SubBruteFileResultProtocolNotFound,
SubBruteFileResultMissingOrIncorrectBit,
SubBruteFileResultMissingOrIncorrectKey,
SubBruteFileResultMissingOrIncorrectTe,
} SubBruteFileResult;
typedef struct {
const SubBruteProtocol* protocol_info;
SubBruteProtocol* file_protocol_info;
// Current step
uint64_t key_index;
// Index of group to bruteforce in loaded file
uint8_t load_index;
// SubGhz
SubGhzReceiver* receiver;
SubGhzProtocolDecoderBase* decoder_result;
SubGhzEnvironment* environment;
// Attack state
SubBruteAttacks attack;
uint64_t max_value;
// Loaded info for attack type
char current_key[SUBBRUTE_PAYLOAD_SIZE];
char file_key[SUBBRUTE_MAX_LEN_NAME];
} SubBruteDevice;
SubBruteDevice* subbrute_device_alloc();
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);
uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path);
uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step);
void subbrute_device_free_protocol_info(SubBruteDevice* instance);
void subbrute_device_attack_set_default_values(
SubBruteDevice* context,
SubBruteAttacks default_attack);

View file

@ -1,72 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/view_stack.h>
#include <gui/scene_manager.h>
#include <gui/modules/text_input.h>
#include <gui/modules/popup.h>
#include <gui/modules/widget.h>
#include <gui/modules/loading.h>
#include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include "subbrute.h"
#include "subbrute_device.h"
#include "helpers/subbrute_worker.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;
// Text store
char text_store[SUBBRUTE_MAX_LEN_NAME];
FuriString* file_path;
// Views
SubBruteMainView* view_main;
SubBruteAttackView* view_attack;
SubBruteView current_view;
// Scene
SceneManager* scene_manager;
// SubBruteDevice
SubBruteDevice* device;
// SubBruteWorker
SubBruteWorker* worker;
};
void subbrute_show_loading_popup(void* context, bool show);
void subbrute_text_input_callback(void* context);
void subbrute_popup_closed_callback(void* context);

View file

@ -1,500 +0,0 @@
#include "subbrute_protocols.h"
#include <string.h>
#define TAG "SubBruteProtocols"
/**
* CAME 12bit 303MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_303 = {
.frequency = 303875000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* CAME 12bit 307MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_307 = {
.frequency = 307800000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* CAME 12bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_433 = {
.frequency = 433920000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* CAME 12bit 868MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_868 = {
.frequency = 868350000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* NICE 12bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_nice_12bit_433 = {
.frequency = 433920000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = NICEFileProtocol};
/**
* NICE 12bit 868MHz
*/
const SubBruteProtocol subbrute_protocol_nice_12bit_868 = {
.frequency = 868350000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = NICEFileProtocol};
/**
* Chamberlain 9bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_300 = {
.frequency = 300000000,
.bits = 9,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 9bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_315 = {
.frequency = 315000000,
.bits = 9,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 9bit 390MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_390 = {
.frequency = 390000000,
.bits = 9,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 8bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_8bit_300 = {
.frequency = 300000000,
.bits = 8,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 8bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_8bit_315 = {
.frequency = 315000000,
.bits = 8,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 8bit 390MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_8bit_390 = {
.frequency = 390000000,
.bits = 8,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 7bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_7bit_300 = {
.frequency = 300000000,
.bits = 7,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 7bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_7bit_315 = {
.frequency = 315000000,
.bits = 7,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 7bit 390MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_7bit_390 = {
.frequency = 390000000,
.bits = 7,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Linear 10bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_linear_10bit_300 = {
.frequency = 300000000,
.bits = 10,
.te = 0,
.repeat = 5,
.preset = FuriHalSubGhzPresetOok650Async,
.file = LinearFileProtocol};
/**
* Linear 10bit 310MHz
*/
const SubBruteProtocol subbrute_protocol_linear_10bit_310 = {
.frequency = 310000000,
.bits = 10,
.te = 0,
.repeat = 5,
.preset = FuriHalSubGhzPresetOok650Async,
.file = LinearFileProtocol};
/**
* BF existing dump
*/
const SubBruteProtocol subbrute_protocol_load_file =
{0, 0, 0, 3, FuriHalSubGhzPresetOok650Async, RAWFileProtocol};
static const char* subbrute_protocol_names[] = {
[SubBruteAttackCAME12bit303] = "CAME 12bit 303MHz",
[SubBruteAttackCAME12bit307] = "CAME 12bit 307MHz",
[SubBruteAttackCAME12bit433] = "CAME 12bit 433MHz",
[SubBruteAttackCAME12bit868] = "CAME 12bit 868MHz",
[SubBruteAttackNICE12bit433] = "NICE 12bit 433MHz",
[SubBruteAttackNICE12bit868] = "NICE 12bit 868MHz",
[SubBruteAttackChamberlain9bit300] = "Chamberlain 9bit 300MHz",
[SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315MHz",
[SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390MHz",
[SubBruteAttackChamberlain8bit300] = "Chamberlain 8bit 300MHz",
[SubBruteAttackChamberlain8bit315] = "Chamberlain 8bit 315MHz",
[SubBruteAttackChamberlain8bit390] = "Chamberlain 8bit 390MHz",
[SubBruteAttackChamberlain7bit300] = "Chamberlain 7bit 300MHz",
[SubBruteAttackChamberlain7bit315] = "Chamberlain 7bit 315MHz",
[SubBruteAttackChamberlain7bit390] = "Chamberlain 7bit 390MHz",
[SubBruteAttackLinear10bit300] = "Linear 10bit 300MHz",
[SubBruteAttackLinear10bit310] = "Linear 10bit 310MHz",
[SubBruteAttackLoadFile] = "BF existing dump",
[SubBruteAttackTotalCount] = "Total Count",
};
static const char* subbrute_protocol_presets[] = {
[FuriHalSubGhzPresetIDLE] = "FuriHalSubGhzPresetIDLE",
[FuriHalSubGhzPresetOok270Async] = "FuriHalSubGhzPresetOok270Async",
[FuriHalSubGhzPresetOok650Async] = "FuriHalSubGhzPresetOok650Async",
[FuriHalSubGhzPreset2FSKDev238Async] = "FuriHalSubGhzPreset2FSKDev238Async",
[FuriHalSubGhzPreset2FSKDev476Async] = "FuriHalSubGhzPreset2FSKDev476Async",
[FuriHalSubGhzPresetMSK99_97KbAsync] = "FuriHalSubGhzPresetMSK99_97KbAsync",
[FuriHalSubGhzPresetGFSK9_99KbAsync] = "FuriHalSubGhzPresetGFSK9_99KbAsync",
};
const SubBruteProtocol* subbrute_protocol_registry[] = {
[SubBruteAttackCAME12bit303] = &subbrute_protocol_came_12bit_303,
[SubBruteAttackCAME12bit307] = &subbrute_protocol_came_12bit_307,
[SubBruteAttackCAME12bit433] = &subbrute_protocol_came_12bit_433,
[SubBruteAttackCAME12bit868] = &subbrute_protocol_came_12bit_868,
[SubBruteAttackNICE12bit433] = &subbrute_protocol_nice_12bit_433,
[SubBruteAttackNICE12bit868] = &subbrute_protocol_nice_12bit_868,
[SubBruteAttackChamberlain9bit300] = &subbrute_protocol_chamberlain_9bit_300,
[SubBruteAttackChamberlain9bit315] = &subbrute_protocol_chamberlain_9bit_315,
[SubBruteAttackChamberlain9bit390] = &subbrute_protocol_chamberlain_9bit_390,
[SubBruteAttackChamberlain8bit300] = &subbrute_protocol_chamberlain_8bit_300,
[SubBruteAttackChamberlain8bit315] = &subbrute_protocol_chamberlain_8bit_315,
[SubBruteAttackChamberlain8bit390] = &subbrute_protocol_chamberlain_8bit_390,
[SubBruteAttackChamberlain7bit300] = &subbrute_protocol_chamberlain_7bit_300,
[SubBruteAttackChamberlain7bit315] = &subbrute_protocol_chamberlain_7bit_315,
[SubBruteAttackChamberlain7bit390] = &subbrute_protocol_chamberlain_7bit_390,
[SubBruteAttackLinear10bit300] = &subbrute_protocol_linear_10bit_300,
[SubBruteAttackLinear10bit310] = &subbrute_protocol_linear_10bit_310,
[SubBruteAttackLoadFile] = &subbrute_protocol_load_file};
static const char* subbrute_protocol_file_types[] = {
[CAMEFileProtocol] = "CAME",
[NICEFileProtocol] = "Nice FLO",
[ChamberlainFileProtocol] = "Cham_Code",
[LinearFileProtocol] = "Linear",
[PrincetonFileProtocol] = "Princeton",
[RAWFileProtocol] = "RAW"};
/**
* Values to not use less memory for packet parse operations
*/
static const char* subbrute_key_file_start_no_tail =
"Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nRepeat: %d\n";
static const char* subbrute_key_file_start_with_tail =
"Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nTE: %d\nRepeat: %d\n";
static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\nRepeat: %d\n";
static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRepeat: %d\n";
const char* subbrute_protocol_name(SubBruteAttacks index) {
return subbrute_protocol_names[index];
}
const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index) {
return subbrute_protocol_registry[index];
}
const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset) {
return subbrute_protocol_presets[preset];
}
const char* subbrute_protocol_file(SubBruteFileProtocol protocol) {
return subbrute_protocol_file_types[protocol];
}
FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name) {
for(size_t i = FuriHalSubGhzPresetIDLE; i < FuriHalSubGhzPresetCustom; i++) {
if(furi_string_cmp_str(preset_name, subbrute_protocol_presets[i]) == 0) {
return i;
}
}
return FuriHalSubGhzPresetIDLE;
}
SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name) {
for(size_t i = CAMEFileProtocol; i < TotalFileProtocol - 1; i++) {
if(furi_string_cmp_str(name, subbrute_protocol_file_types[i]) == 0) {
return i;
}
}
return RAWFileProtocol;
}
void subbrute_protocol_default_payload(
Stream* stream,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat) {
FuriString* candidate = furi_string_alloc_set_str(" ");
FuriString* buffer = furi_string_alloc_printf("%16llX", step);
int j = 0;
for(uint8_t i = 0; i < 16; i++) {
if(furi_string_get_char(buffer, i) != ' ') {
furi_string_set_char(candidate, i + j, furi_string_get_char(buffer, i));
} else {
furi_string_set_char(candidate, i + j, '0');
}
if(i % 2 != 0) {
j++;
}
}
furi_string_free(buffer);
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
#endif
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_small_with_tail,
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat);
}
furi_string_free(candidate);
}
void subbrute_protocol_file_payload(
Stream* stream,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat,
uint8_t load_index,
const char* file_key) {
FuriString* candidate = furi_string_alloc();
char subbrute_payload_byte[4];
furi_string_set_str(candidate, file_key);
snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)step);
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);
#endif
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_small_with_tail,
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat);
}
furi_string_free(candidate);
}
void subbrute_protocol_default_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat) {
FuriString* candidate = furi_string_alloc_set_str(" ");
FuriString* buffer = furi_string_alloc_printf("%16llX", step);
int j = 0;
for(uint8_t i = 0; i < 16; i++) {
if(furi_string_get_char(buffer, i) != ' ') {
furi_string_set_char(candidate, i + j, furi_string_get_char(buffer, i));
} else {
furi_string_set_char(candidate, i + j, '0');
}
if(i % 2 != 0) {
j++;
}
}
furi_string_free(buffer);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
#endif
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_file_start_with_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream,
subbrute_key_file_start_no_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
repeat);
}
furi_string_free(candidate);
}
void subbrute_protocol_file_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat,
uint8_t load_index,
const char* file_key) {
FuriString* candidate = furi_string_alloc();
char subbrute_payload_byte[4];
furi_string_set_str(candidate, file_key);
snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)step);
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);
#endif
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_file_start_with_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream,
subbrute_key_file_start_no_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
repeat);
}
furi_string_free(candidate);
}
uint64_t subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits) {
uint64_t max_value;
if(attack_type == SubBruteAttackLoadFile) {
max_value = 0xFF;
} else {
FuriString* max_value_s;
max_value_s = furi_string_alloc();
for(uint8_t i = 0; i < bits; i++) {
furi_string_cat_printf(max_value_s, "1");
}
max_value = (uint64_t)strtol(furi_string_get_cstr(max_value_s), NULL, 2);
furi_string_free(max_value_s);
}
return max_value;
}

View file

@ -1,99 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal_subghz.h>
#include <core/string.h>
#include <toolbox/stream/stream.h>
//typedef enum {
// FrequencyProtocolField,
// BitsProtocolField,
// HasTeProtocolField,
// RepeatProtocolField,
// PresetProtocolField,
// FileProtocolField,
// TotalProtocolFields
//} ProtocolFields;
typedef enum {
CAMEFileProtocol,
NICEFileProtocol,
ChamberlainFileProtocol,
LinearFileProtocol,
PrincetonFileProtocol,
RAWFileProtocol,
TotalFileProtocol,
} SubBruteFileProtocol;
typedef enum {
SubBruteAttackCAME12bit303,
SubBruteAttackCAME12bit307,
SubBruteAttackCAME12bit433,
SubBruteAttackCAME12bit868,
SubBruteAttackNICE12bit433,
SubBruteAttackNICE12bit868,
SubBruteAttackChamberlain9bit300,
SubBruteAttackChamberlain9bit315,
SubBruteAttackChamberlain9bit390,
SubBruteAttackChamberlain8bit300,
SubBruteAttackChamberlain8bit315,
SubBruteAttackChamberlain8bit390,
SubBruteAttackChamberlain7bit300,
SubBruteAttackChamberlain7bit315,
SubBruteAttackChamberlain7bit390,
SubBruteAttackLinear10bit300,
SubBruteAttackLinear10bit310,
SubBruteAttackLoadFile,
SubBruteAttackTotalCount,
} SubBruteAttacks;
typedef struct {
uint32_t frequency;
uint8_t bits;
uint8_t te;
uint8_t repeat;
FuriHalSubGhzPreset preset;
SubBruteFileProtocol file;
} SubBruteProtocol;
const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index);
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);
const char* subbrute_protocol_name(SubBruteAttacks index);
void subbrute_protocol_default_payload(
Stream* stream,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat);
void subbrute_protocol_file_payload(
Stream* stream,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat,
uint8_t load_index,
const char* file_key);
void subbrute_protocol_default_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat);
void subbrute_protocol_file_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint8_t te,
uint8_t repeat,
uint8_t load_index,
const char* file_key);
uint64_t subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits);

View file

@ -1,412 +0,0 @@
#include "subbrute_attack_view.h"
#include "../subbrute_i.h"
#include "../subbrute_protocols.h"
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon.h>
#include <gui/icon_animation.h>
#include <assets_icons.h>
#define TAG "SubBruteAttackView"
struct SubBruteAttackView {
View* view;
SubBruteAttackViewCallback callback;
void* context;
};
typedef struct {
SubBruteAttacks index;
uint64_t max_value;
uint64_t current_step;
bool is_attacking;
bool is_continuous_worker;
IconAnimation* icon;
} 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);
#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);
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{
model->is_attacking = false;
model->is_continuous_worker = false;
},
true);
return true;
}
bool is_attacking = 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(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->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);*/
} else if(event->key == InputKeyUp) {
instance->callback(SubBruteCustomEventTypeSaveFile, instance->context);
} else if(event->key == InputKeyDown) {
instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context);
} 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);
} 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);*/
}
} 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;
model->is_continuous_worker = false;
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
},
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);
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{
model->icon = icon_animation_alloc(&A_Sub1ghz_14);
view_tie_icon_animation(instance->view, model->icon);
},
false);
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);
return instance;
}
void subbrute_attack_view_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_attack_view_enter");
#endif
}
void subbrute_attack_view_free(SubBruteAttackView* instance) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_attack_view_free");
#endif
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{ icon_animation_free(model->icon); },
false);
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, uint64_t current_step) {
furi_assert(instance);
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "Set step: %d", current_step);
#endif
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{ model->current_step = current_step; },
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(
SubBruteAttackView* instance,
uint8_t index,
uint64_t max_value,
uint64_t current_step,
bool is_attacking) {
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"init, index: %d, max_value: %lld, current_step: %lld",
index,
max_value,
current_step);
#endif
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{
model->max_value = max_value;
model->index = index;
model->current_step = current_step;
model->is_attacking = is_attacking;
if(is_attacking) {
icon_animation_start(model->icon);
} else {
icon_animation_stop(model->icon);
}
},
true);
}
void subbrute_attack_view_exit(void* context) {
furi_assert(context);
SubBruteAttackView* instance = context;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_attack_view_exit");
#endif
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{ icon_animation_stop(model->icon); },
false);
}
/**
* Thanks to the author of metronome
* @param canvas
* @param str
*/
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_get_width(icon) + icon_h_offset;
const uint8_t icon_v_offset = icon_get_height(icon) + 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 + 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);
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);
}
/**
* Thanks to the author of metronome
* @param canvas
* @param str
*/
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_get_width(icon) + icon_h_offset;
const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset + 1;
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 + 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);
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_get_width(icon), y - icon_v_offset, icon);
canvas_invert_color(canvas);
}
void subbrute_attack_view_draw(Canvas* canvas, void* context) {
furi_assert(context);
SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context;
char buffer[26];
const char* attack_name = NULL;
attack_name = subbrute_protocol_name(model->index);
// 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
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);
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);
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 =
icon_animation_get_width(model->icon) + icon_h_offset;
const uint8_t icon_v_offset = icon_animation_get_height(model->icon); // + vertical_offset;
const uint8_t x = canvas_width(canvas);
const uint8_t y = canvas_height(canvas);
canvas_draw_icon_animation(
canvas, x - icon_width_with_offset, y - icon_v_offset, model->icon);
// Progress bar
// Resolution: 128x64 px
float progress_value = (float)model->current_step / model->max_value;
elements_progress_bar(canvas, 8, 37, 110, progress_value > 1 ? 1 : progress_value);
elements_button_center(canvas, "Stop");
if(model->is_continuous_worker) {
canvas_invert_color(canvas);
}
}
}

View file

@ -1,25 +0,0 @@
#pragma once
#include "../subbrute_custom_event.h"
#include <gui/view.h>
#include <input/input.h>
#include <gui/elements.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, 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);

View file

@ -1,380 +0,0 @@
#include "subbrute_main_view.h"
#include "../subbrute_i.h"
#include "../subbrute_protocols.h"
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon.h>
#include <assets_icons.h>
#define STATUS_BAR_Y_SHIFT 14
#define TAG "SubBruteMainView"
struct SubBruteMainView {
View* view;
SubBruteMainViewCallback callback;
void* context;
};
typedef struct {
uint8_t index;
uint8_t window_position;
bool is_select_byte;
const char* key_field;
} 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;
}
FuriString* center_displayed_key(const char* key_cstr, uint8_t index) {
uint8_t str_index = (index * 3);
char display_menu[] = {
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
if(key_cstr != NULL) {
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] = ' ';
}
}
return furi_string_alloc_set(display_menu);
}
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 v3");
canvas_invert_color(canvas);
if(m->is_select_byte) {
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "key_field: %s", m->key_field);
#endif
char msg_index[18];
snprintf(msg_index, sizeof(msg_index), "Field index : %d", m->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);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 40, AlignCenter, AlignTop, furi_string_get_cstr(menu_items));
elements_button_center(canvas, "Select");
elements_button_left(canvas, "<");
elements_button_right(canvas, ">");
furi_string_reset(menu_items);
furi_string_free(menu_items);
} else {
// 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);
#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) {
canvas_draw_str_aligned(
canvas,
4,
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
AlignLeft,
AlignCenter,
subbrute_protocol_name(position));
elements_frame(
canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15);
} else {
canvas_draw_str_aligned(
canvas,
4,
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
AlignLeft,
AlignCenter,
subbrute_protocol_name(position));
}
}
}
elements_scrollbar_pos(
canvas,
canvas_width(canvas),
STATUS_BAR_Y_SHIFT + 2,
canvas_height(canvas) - STATUS_BAR_Y_SHIFT,
m->index,
SubBruteAttackTotalCount);
}
}
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) {
return false;
}
SubBruteMainView* instance = context;
const uint8_t min_value = 0;
const uint8_t correct_total = SubBruteAttackTotalCount - 1;
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 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;
}
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(index == SubBruteAttackLoadFile) {
instance->callback(SubBruteCustomEventTypeLoadFile, instance->context);
} else {
instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context);
}
consumed = true;
}
} 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) {
instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context);
consumed = true;
}
}
return consumed;
}
void subbrute_main_view_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_main_view_enter");
#endif
}
void subbrute_main_view_exit(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_main_view_exit");
#endif
}
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);
with_view_model(
instance->view,
SubBruteMainViewModel * model,
{
model->index = 0;
model->window_position = 0;
model->key_field = NULL;
model->is_select_byte = false;
},
true);
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,
bool is_select_byte,
const char* key_field) {
furi_assert(instance);
furi_assert(idx < SubBruteAttackTotalCount);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Set index: %d", idx);
#endif
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);
}
}
}
},
true);
}
SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) {
furi_assert(instance);
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;
}

View file

@ -1,28 +0,0 @@
#pragma once
#include "../subbrute_custom_event.h"
#include <gui/view.h>
#include <input/input.h>
#include <gui/elements.h>
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,
bool is_select_byte,
const char* key_field);
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);

View file

@ -39,6 +39,7 @@ Frequency: 433657070
Frequency: 433889000
Frequency: 433920000
Frequency: 434176948
Frequency: 434190000
Frequency: 434420000
Frequency: 434775000
Frequency: 438900000