Rename plugins to external
21
applications/external/subghz_bruteforcer/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Der Skythe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
13
applications/external/subghz_bruteforcer/application.fam
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
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="images/subbrute_10px.png",
|
||||
fap_category="Sub-GHz",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
59
applications/external/subghz_bruteforcer/helpers/gui_top_buttons.c
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "gui_top_buttons.h"
|
||||
|
||||
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;
|
||||
|
||||
uint8_t line_x = x + button_width;
|
||||
uint8_t line_y = y - button_height;
|
||||
canvas_draw_box(canvas, x, line_y, button_width, button_height);
|
||||
canvas_draw_line(canvas, line_x + 0, line_y, line_x + 0, y - 1);
|
||||
canvas_draw_line(canvas, line_x + 1, line_y, line_x + 1, y - 2);
|
||||
canvas_draw_line(canvas, line_x + 2, line_y, line_x + 2, y - 3);
|
||||
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_icon(canvas, x + horizontal_offset, y - icon_v_offset, icon);
|
||||
canvas_draw_str(
|
||||
canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str);
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
void elements_button_top_right(Canvas* canvas, const char* str) {
|
||||
const Icon* icon = &I_ButtonDown_7x4;
|
||||
|
||||
const uint8_t button_height = 12;
|
||||
const uint8_t vertical_offset = 3;
|
||||
const uint8_t horizontal_offset = 3;
|
||||
const uint8_t string_width = canvas_string_width(canvas, str);
|
||||
const uint8_t icon_h_offset = 3;
|
||||
const uint8_t icon_width_with_offset = icon_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;
|
||||
|
||||
uint8_t line_x = x - button_width;
|
||||
uint8_t line_y = y - button_height;
|
||||
canvas_draw_box(canvas, line_x, line_y, button_width, button_height);
|
||||
canvas_draw_line(canvas, line_x - 1, line_y, line_x - 1, y - 1);
|
||||
canvas_draw_line(canvas, line_x - 2, line_y, line_x - 2, y - 2);
|
||||
canvas_draw_line(canvas, line_x - 3, line_y, line_x - 3, y - 3);
|
||||
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str);
|
||||
canvas_draw_icon(
|
||||
canvas, x - horizontal_offset - icon_get_width(icon), y - icon_v_offset, icon);
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
21
applications/external/subghz_bruteforcer/helpers/gui_top_buttons.h
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/icon.h>
|
||||
#include <gui/icon_animation.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
/**
|
||||
* Thanks to the author of metronome
|
||||
* @param canvas
|
||||
* @param str
|
||||
*/
|
||||
void elements_button_top_left(Canvas* canvas, const char* str);
|
||||
|
||||
/**
|
||||
* Thanks to the author of metronome
|
||||
* @param canvas
|
||||
* @param str
|
||||
*/
|
||||
void elements_button_top_right(Canvas* canvas, const char* str);
|
||||
437
applications/external/subghz_bruteforcer/helpers/subbrute_worker.c
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
#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,
|
||||
uint8_t extra_repeats) {
|
||||
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 + extra_repeats;
|
||||
instance->load_index = 0;
|
||||
instance->file_key = 0;
|
||||
instance->two_bytes = false;
|
||||
|
||||
instance->max_value =
|
||||
subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes);
|
||||
|
||||
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: %ld, 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,
|
||||
uint64_t file_key,
|
||||
SubBruteProtocol* protocol,
|
||||
uint8_t extra_repeats,
|
||||
bool two_bytes) {
|
||||
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 + extra_repeats;
|
||||
instance->file_key = file_key;
|
||||
instance->two_bytes = two_bytes;
|
||||
|
||||
instance->max_value =
|
||||
subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes);
|
||||
|
||||
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: %ld, repeat: %d, max_value: %lld, key: %llX",
|
||||
subbrute_protocol_name(instance->attack),
|
||||
instance->bits,
|
||||
subbrute_protocol_preset(instance->preset),
|
||||
subbrute_protocol_file(instance->file),
|
||||
instance->te,
|
||||
instance->repeat,
|
||||
instance->max_value,
|
||||
instance->file_key);
|
||||
#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);
|
||||
|
||||
if(!instance->worker_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
instance->two_bytes);
|
||||
} else {
|
||||
subbrute_protocol_default_payload(
|
||||
stream, instance->file, 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,
|
||||
instance->two_bytes);
|
||||
} else {
|
||||
subbrute_protocol_default_payload(
|
||||
stream,
|
||||
instance->file,
|
||||
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;
|
||||
}
|
||||
42
applications/external/subghz_bruteforcer/helpers/subbrute_worker.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
#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,
|
||||
uint8_t extra_repeats);
|
||||
bool subbrute_worker_init_file_attack(
|
||||
SubBruteWorker* instance,
|
||||
uint64_t step,
|
||||
uint8_t load_index,
|
||||
uint64_t file_key,
|
||||
SubBruteProtocol* protocol,
|
||||
uint8_t extra_repeats,
|
||||
bool two_bytes);
|
||||
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);
|
||||
48
applications/external/subghz_bruteforcer/helpers/subbrute_worker_private.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
#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;
|
||||
uint32_t te;
|
||||
uint8_t repeat;
|
||||
uint8_t load_index; // Index of group to bruteforce in loaded file
|
||||
uint64_t file_key;
|
||||
uint64_t max_value; // Max step
|
||||
bool two_bytes;
|
||||
|
||||
// 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);
|
||||
BIN
applications/external/subghz_bruteforcer/images/ButtonDown_7x4.png
vendored
Normal file
|
After Width: | Height: | Size: 102 B |
BIN
applications/external/subghz_bruteforcer/images/ButtonUp_7x4.png
vendored
Normal file
|
After Width: | Height: | Size: 102 B |
BIN
applications/external/subghz_bruteforcer/images/DolphinNice_96x59.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
applications/external/subghz_bruteforcer/images/Sub1ghz_14/frame_01.png
vendored
Normal file
|
After Width: | Height: | Size: 97 B |
BIN
applications/external/subghz_bruteforcer/images/Sub1ghz_14/frame_02.png
vendored
Normal file
|
After Width: | Height: | Size: 96 B |
BIN
applications/external/subghz_bruteforcer/images/Sub1ghz_14/frame_03.png
vendored
Normal file
|
After Width: | Height: | Size: 90 B |
BIN
applications/external/subghz_bruteforcer/images/Sub1ghz_14/frame_04.png
vendored
Normal file
|
After Width: | Height: | Size: 76 B |
BIN
applications/external/subghz_bruteforcer/images/Sub1ghz_14/frame_05.png
vendored
Normal file
|
After Width: | Height: | Size: 79 B |
BIN
applications/external/subghz_bruteforcer/images/Sub1ghz_14/frame_06.png
vendored
Normal file
|
After Width: | Height: | Size: 90 B |
1
applications/external/subghz_bruteforcer/images/Sub1ghz_14/frame_rate
vendored
Normal file
@@ -0,0 +1 @@
|
||||
3
|
||||
BIN
applications/external/subghz_bruteforcer/images/sub1_10px.png
vendored
Normal file
|
After Width: | Height: | Size: 299 B |
BIN
applications/external/subghz_bruteforcer/images/subbrute_10px.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
29
applications/external/subghz_bruteforcer/scenes/subbrute_scene.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
#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
|
||||
7
applications/external/subghz_bruteforcer/scenes/subbrute_scene_config.h
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
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)
|
||||
91
applications/external/subghz_bruteforcer/scenes/subbrute_scene_load_file.c
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "../subbrute_i.h"
|
||||
#include "subbrute_scene.h"
|
||||
|
||||
#define TAG "SubBruteSceneLoadFile"
|
||||
|
||||
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;
|
||||
// TODO: DELETE IT
|
||||
#ifdef SUBBRUTE_FAST_TRACK
|
||||
bool res = true;
|
||||
furi_string_printf(load_path, "%s", "/ext/subghz/princeton.sub");
|
||||
#else
|
||||
bool res =
|
||||
dialog_file_browser_show(instance->dialogs, load_path, app_folder, &browser_options);
|
||||
#endif
|
||||
#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) {
|
||||
uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
|
||||
|
||||
load_result = subbrute_device_attack_set(
|
||||
instance->device, SubBruteAttackLoadFile, extra_repeats);
|
||||
if(load_result == SubBruteFileResultOk) {
|
||||
if(!subbrute_worker_init_file_attack(
|
||||
instance->worker,
|
||||
instance->device->current_step,
|
||||
instance->device->bit_index,
|
||||
instance->device->key_from_file,
|
||||
instance->device->file_protocol_info,
|
||||
extra_repeats,
|
||||
instance->device->two_bytes)) {
|
||||
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;
|
||||
}
|
||||
82
applications/external/subghz_bruteforcer/scenes/subbrute_scene_load_select.c
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
#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->two_bytes, instance->device->key_from_file);
|
||||
|
||||
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) {
|
||||
/*#ifdef FURI_DEBUG && !SUBBRUTE_FAST_TRACK
|
||||
view_dispatcher_stop(instance->view_dispatcher);
|
||||
consumed = true;
|
||||
#else*/
|
||||
instance->device->current_step = 0;
|
||||
instance->device->bit_index = subbrute_main_view_get_index(instance->view_main);
|
||||
instance->device->two_bytes = subbrute_main_view_get_two_bytes(instance->view_main);
|
||||
uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
|
||||
instance->device->max_value = subbrute_protocol_calc_max_value(
|
||||
instance->device->attack,
|
||||
instance->device->bit_index,
|
||||
instance->device->two_bytes);
|
||||
|
||||
if(!subbrute_worker_init_file_attack(
|
||||
instance->worker,
|
||||
instance->device->current_step,
|
||||
instance->device->bit_index,
|
||||
instance->device->key_from_file,
|
||||
instance->device->file_protocol_info,
|
||||
extra_repeats,
|
||||
instance->device->two_bytes)) {
|
||||
furi_crash("Invalid attack set!");
|
||||
}
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
|
||||
/*#endif*/
|
||||
consumed = true;
|
||||
} /* else if(event.event == SubBruteCustomEventTypeChangeStepUp) {
|
||||
instance->device->two_bytes = true;
|
||||
} else if(event.event == SubBruteCustomEventTypeChangeStepDown) {
|
||||
instance->device->two_bytes = false;
|
||||
}*/
|
||||
} 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;
|
||||
}
|
||||
104
applications/external/subghz_bruteforcer/scenes/subbrute_scene_run_attack.c
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
#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;
|
||||
|
||||
notification_message(instance->notifications, &sequence_blink_stop);
|
||||
subbrute_worker_stop(instance->worker);
|
||||
}
|
||||
|
||||
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->current_step);
|
||||
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->current_step = 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->current_step);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
uint64_t step = subbrute_worker_get_step(instance->worker);
|
||||
instance->device->current_step = step;
|
||||
subbrute_attack_view_set_current_step(view, step);
|
||||
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
84
applications/external/subghz_bruteforcer/scenes/subbrute_scene_save_name.c
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
#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);
|
||||
}
|
||||
51
applications/external/subghz_bruteforcer/scenes/subbrute_scene_save_success.c
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
#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);
|
||||
}
|
||||
138
applications/external/subghz_bruteforcer/scenes/subbrute_scene_setup_attack.c
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
#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;
|
||||
|
||||
notification_message(instance->notifications, &sequence_reset_vibro);
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "Enter Attack: %s", subbrute_protocol_name(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)) {
|
||||
subbrute_worker_stop(instance->worker);
|
||||
instance->device->current_step = subbrute_worker_get_step(instance->worker);
|
||||
}
|
||||
|
||||
subbrute_attack_view_init_values(
|
||||
view,
|
||||
instance->device->attack,
|
||||
instance->device->max_value,
|
||||
instance->device->current_step,
|
||||
false,
|
||||
instance->device->extra_repeats);
|
||||
|
||||
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);
|
||||
notification_message(instance->notifications, &sequence_reset_vibro);
|
||||
}
|
||||
|
||||
bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event) {
|
||||
SubBruteState* instance = (SubBruteState*)context;
|
||||
SubBruteAttackView* view = instance->view_attack;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubBruteCustomEventTypeTransmitStarted) {
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack);
|
||||
} else if(event.event == SubBruteCustomEventTypeSaveFile) {
|
||||
subbrute_attack_view_init_values(
|
||||
view,
|
||||
instance->device->attack,
|
||||
instance->device->max_value,
|
||||
instance->device->current_step,
|
||||
false,
|
||||
instance->device->extra_repeats);
|
||||
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->current_step,
|
||||
false,
|
||||
instance->device->extra_repeats);
|
||||
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->current_step);
|
||||
// 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->current_step = subbrute_worker_get_step(instance->worker);
|
||||
}
|
||||
subbrute_attack_view_set_current_step(view, instance->device->current_step);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
89
applications/external/subghz_bruteforcer/scenes/subbrute_scene_start.c
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
#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, instance->device->two_bytes, 0);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
|
||||
|
||||
// TODO: DELETE IT
|
||||
#ifdef SUBBRUTE_FAST_TRACK
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile);
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
|
||||
|
||||
if((subbrute_device_attack_set(instance->device, attack, extra_repeats) !=
|
||||
SubBruteFileResultOk) ||
|
||||
(!subbrute_worker_init_default_attack(
|
||||
instance->worker,
|
||||
attack,
|
||||
instance->device->current_step,
|
||||
instance->device->protocol_info,
|
||||
instance->device->extra_repeats))) {
|
||||
furi_crash("Invalid attack set!");
|
||||
}
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
|
||||
|
||||
consumed = true;
|
||||
} else if(event.event == SubBruteCustomEventTypeLoadFile) {
|
||||
//uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
|
||||
|
||||
//instance->device->extra_repeats = extra_repeats;
|
||||
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;
|
||||
}
|
||||
30
applications/external/subghz_bruteforcer/scenes/subbute_scene.c
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "subbrute_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const subbrute_on_enter_handlers[])(void*) = {
|
||||
#include "subbrute_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const subbrute_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "subbrute_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const subbrute_on_exit_handlers[])(void* context) = {
|
||||
#include "subbrute_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers subbrute_scene_handlers = {
|
||||
.on_enter_handlers = subbrute_on_enter_handlers,
|
||||
.on_event_handlers = subbrute_on_event_handlers,
|
||||
.on_exit_handlers = subbrute_on_exit_handlers,
|
||||
.scene_num = SubBruteSceneNum,
|
||||
};
|
||||
199
applications/external/subghz_bruteforcer/subbrute.c
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
#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);
|
||||
|
||||
// Enable power for External CC1101 if it is connected
|
||||
furi_hal_subghz_enable_ext_power();
|
||||
// Auto switch to internal radio if external radio is not available
|
||||
if(!furi_hal_subghz_check_radio()) {
|
||||
furi_hal_subghz_set_radio_type(SubGhzRadioInternal);
|
||||
}
|
||||
|
||||
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();
|
||||
// Disable power for External CC1101 if it was enabled and module is connected
|
||||
furi_hal_subghz_disable_ext_power();
|
||||
|
||||
subbrute_free(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
applications/external/subghz_bruteforcer/subbrute.h
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct SubBruteState SubBruteState;
|
||||
26
applications/external/subghz_bruteforcer/subbrute_custom_event.h
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
#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;
|
||||
460
applications/external/subghz_bruteforcer/subbrute_device.c
vendored
Normal file
@@ -0,0 +1,460 @@
|
||||
#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->current_step = 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, SubBruteAttackLoadFile);
|
||||
#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->current_step + step) - instance->max_value == 1) {
|
||||
instance->current_step = 0x00;
|
||||
} else {
|
||||
uint64_t value = instance->current_step + step;
|
||||
if(value == instance->max_value) {
|
||||
instance->current_step = value;
|
||||
} else {
|
||||
instance->current_step = value % instance->max_value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(instance->current_step + step == 0) {
|
||||
instance->current_step = 0x00;
|
||||
} else if(instance->current_step == 0) {
|
||||
instance->current_step = instance->max_value;
|
||||
} else {
|
||||
uint64_t value = ((instance->current_step + step) + instance->max_value);
|
||||
if(value == instance->max_value) {
|
||||
instance->current_step = value;
|
||||
} else {
|
||||
instance->current_step = value % instance->max_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instance->current_step;
|
||||
}
|
||||
|
||||
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->current_step,
|
||||
instance->file_protocol_info->bits,
|
||||
instance->file_protocol_info->te,
|
||||
instance->file_protocol_info->repeat,
|
||||
instance->bit_index,
|
||||
instance->key_from_file,
|
||||
instance->two_bytes);
|
||||
} else {
|
||||
subbrute_protocol_default_generate_file(
|
||||
stream,
|
||||
instance->protocol_info->frequency,
|
||||
instance->protocol_info->preset,
|
||||
instance->protocol_info->file,
|
||||
instance->current_step,
|
||||
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,
|
||||
uint8_t extra_repeats) {
|
||||
furi_assert(instance);
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "subbrute_device_attack_set: %d, extra_repeats: %d", type, extra_repeats);
|
||||
#endif
|
||||
subbrute_device_attack_set_default_values(instance, type);
|
||||
|
||||
if(type != SubBruteAttackLoadFile) {
|
||||
subbrute_device_free_protocol_info(instance);
|
||||
instance->protocol_info = subbrute_protocol(type);
|
||||
}
|
||||
|
||||
instance->extra_repeats = extra_repeats;
|
||||
|
||||
// For non-file types we didn't set SubGhzProtocolDecoderBase
|
||||
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;
|
||||
uint32_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, instance->two_bytes);
|
||||
}
|
||||
#ifdef FURI_DEBUG
|
||||
bits = instance->protocol_info->bits;
|
||||
te = instance->protocol_info->te;
|
||||
repeat = instance->protocol_info->repeat + instance->extra_repeats;
|
||||
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, instance->two_bytes);
|
||||
#ifdef FURI_DEBUG
|
||||
bits = instance->file_protocol_info->bits;
|
||||
te = instance->file_protocol_info->te;
|
||||
repeat = instance->file_protocol_info->repeat + instance->extra_repeats;
|
||||
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: %ld, 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)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Frequency");
|
||||
result = SubBruteFileResultMissingOrIncorrectFrequency;
|
||||
break;
|
||||
}
|
||||
instance->file_protocol_info->frequency = temp_data32;
|
||||
if(!furi_hal_subghz_is_tx_allowed(instance->file_protocol_info->frequency)) {
|
||||
result = SubBruteFileResultFrequencyNotAllowed;
|
||||
break;
|
||||
}
|
||||
|
||||
// Preset
|
||||
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Preset FAIL");
|
||||
result = SubBruteFileResultPresetInvalid;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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, furi_string_get_cstr(temp_str));
|
||||
|
||||
if((!instance->decoder_result) || (strcmp(protocol_file, "RAW") == 0) ||
|
||||
(strcmp(protocol_file, "Unknown") == 0)) {
|
||||
FURI_LOG_E(TAG, "Protocol 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
|
||||
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;
|
||||
}
|
||||
instance->file_protocol_info->bits = temp_data32;
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "Bit: %d", instance->file_protocol_info->bits);
|
||||
#endif
|
||||
|
||||
uint8_t key_data[sizeof(uint64_t)] = {0};
|
||||
if(!flipper_format_read_hex(fff_data_file, "Key", key_data, sizeof(uint64_t))) {
|
||||
FURI_LOG_E(TAG, "Missing Key");
|
||||
result = SubBruteFileResultMissingOrIncorrectKey;
|
||||
break;
|
||||
}
|
||||
uint64_t data = 0;
|
||||
for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
|
||||
data = (data << 8) | key_data[i];
|
||||
}
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "Key: %.16llX", data);
|
||||
#endif
|
||||
instance->key_from_file = data;
|
||||
|
||||
// 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->current_step = 0x00;
|
||||
instance->bit_index = 0x00;
|
||||
instance->extra_repeats = 0;
|
||||
instance->two_bytes = false;
|
||||
|
||||
if(default_attack != SubBruteAttackLoadFile) {
|
||||
instance->max_value = subbrute_protocol_calc_max_value(
|
||||
instance->attack, instance->bit_index, instance->two_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
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 = "Protocol 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;
|
||||
}
|
||||
75
applications/external/subghz_bruteforcer/subbrute_device.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
#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 current_step;
|
||||
|
||||
// SubGhz
|
||||
SubGhzReceiver* receiver;
|
||||
SubGhzProtocolDecoderBase* decoder_result;
|
||||
SubGhzEnvironment* environment;
|
||||
|
||||
// Attack state
|
||||
SubBruteAttacks attack;
|
||||
uint64_t max_value;
|
||||
uint8_t extra_repeats;
|
||||
|
||||
// Loaded info for attack type
|
||||
uint64_t key_from_file;
|
||||
uint64_t current_key_from_file;
|
||||
bool two_bytes;
|
||||
// Index of group to bruteforce in loaded file
|
||||
uint8_t bit_index;
|
||||
} 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 extra_repeats);
|
||||
uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path);
|
||||
|
||||
uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step);
|
||||
|
||||
void subbrute_device_free_protocol_info(SubBruteDevice* instance);
|
||||
void subbrute_device_attack_set_default_values(
|
||||
SubBruteDevice* context,
|
||||
SubBruteAttacks default_attack);
|
||||
80
applications/external/subghz_bruteforcer/subbrute_i.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
#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 "SubGHz_Bruteforcer_icons.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"
|
||||
|
||||
#define SUBBRUTEFORCER_VER "Sub-GHz BruteForcer 3.5"
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
//#define SUBBRUTE_FAST_TRACK false
|
||||
#endif
|
||||
|
||||
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);
|
||||
881
applications/external/subghz_bruteforcer/subbrute_protocols.c
vendored
Normal file
@@ -0,0 +1,881 @@
|
||||
#include "subbrute_protocols.h"
|
||||
#include "math.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 315MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_came_12bit_315 = {
|
||||
.frequency = 315000000,
|
||||
.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};
|
||||
|
||||
/**
|
||||
* Ansonic 12bit 433.075MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_ansonic_12bit_433075 = {
|
||||
.frequency = 433075000,
|
||||
.bits = 12,
|
||||
.te = 0,
|
||||
.repeat = 3,
|
||||
.preset = FuriHalSubGhzPreset2FSKDev238Async,
|
||||
.file = AnsonicFileProtocol};
|
||||
|
||||
/**
|
||||
* Ansonic 12bit 433.92MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_ansonic_12bit_433 = {
|
||||
.frequency = 433920000,
|
||||
.bits = 12,
|
||||
.te = 0,
|
||||
.repeat = 3,
|
||||
.preset = FuriHalSubGhzPreset2FSKDev238Async,
|
||||
.file = AnsonicFileProtocol};
|
||||
|
||||
/**
|
||||
* Ansonic 12bit 434.075MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_ansonic_12bit_434 = {
|
||||
.frequency = 434075000,
|
||||
.bits = 12,
|
||||
.te = 0,
|
||||
.repeat = 3,
|
||||
.preset = FuriHalSubGhzPreset2FSKDev238Async,
|
||||
.file = AnsonicFileProtocol};
|
||||
|
||||
/**
|
||||
* 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 9bit 433MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_433 = {
|
||||
.frequency = 433920000,
|
||||
.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};
|
||||
|
||||
/**
|
||||
* Linear Delta 3 8bit 310MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_linear_delta_8bit_310 = {
|
||||
.frequency = 310000000,
|
||||
.bits = 8,
|
||||
.te = 0,
|
||||
.repeat = 5,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = LinearDeltaFileProtocol};
|
||||
|
||||
/**
|
||||
* UNILARM 24bit 330MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_unilarm_24bit_330 = {
|
||||
.frequency = 330000000,
|
||||
.bits = 25,
|
||||
.te = 209,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = UNILARMFileProtocol};
|
||||
|
||||
/**
|
||||
* UNILARM 24bit 433MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_unilarm_24bit_433 = {
|
||||
.frequency = 433920000,
|
||||
.bits = 25,
|
||||
.te = 209,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = UNILARMFileProtocol};
|
||||
|
||||
/**
|
||||
* SMC5326 24bit 330MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_smc5326_24bit_330 = {
|
||||
.frequency = 330000000,
|
||||
.bits = 25,
|
||||
.te = 320,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = SMC5326FileProtocol};
|
||||
|
||||
/**
|
||||
* SMC5326 24bit 433MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_smc5326_24bit_433 = {
|
||||
.frequency = 433920000,
|
||||
.bits = 25,
|
||||
.te = 320,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = SMC5326FileProtocol};
|
||||
|
||||
/**
|
||||
* PT2260 (Princeton) 24bit 315MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_pt2260_24bit_315 = {
|
||||
.frequency = 315000000,
|
||||
.bits = 24,
|
||||
.te = 286,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = PT2260FileProtocol};
|
||||
|
||||
/**
|
||||
* PT2260 (Princeton) 24bit 330MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_pt2260_24bit_330 = {
|
||||
.frequency = 330000000,
|
||||
.bits = 24,
|
||||
.te = 286,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = PT2260FileProtocol};
|
||||
|
||||
/**
|
||||
* PT2260 (Princeton) 24bit 390MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_pt2260_24bit_390 = {
|
||||
.frequency = 390000000,
|
||||
.bits = 24,
|
||||
.te = 286,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = PT2260FileProtocol};
|
||||
|
||||
/**
|
||||
* PT2260 (Princeton) 24bit 433MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_pt2260_24bit_433 = {
|
||||
.frequency = 433920000,
|
||||
.bits = 24,
|
||||
.te = 286,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = PT2260FileProtocol};
|
||||
|
||||
/**
|
||||
* Holtek FM 12bit 433MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_holtek_12bit_433 = {
|
||||
.frequency = 433920000,
|
||||
.bits = 12,
|
||||
.te = 204,
|
||||
.repeat = 4,
|
||||
.preset = FuriHalSubGhzPreset2FSKDev476Async,
|
||||
.file = HoltekFileProtocol};
|
||||
|
||||
/**
|
||||
* Holtek AM 12bit 433MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_433 = {
|
||||
.frequency = 433920000,
|
||||
.bits = 12,
|
||||
.te = 433,
|
||||
.repeat = 3,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = HoltekFileProtocol};
|
||||
|
||||
/**
|
||||
* Holtek AM 12bit 315MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_315 = {
|
||||
.frequency = 315000000,
|
||||
.bits = 12,
|
||||
.te = 433,
|
||||
.repeat = 3,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = HoltekFileProtocol};
|
||||
|
||||
/**
|
||||
* Holtek AM 12bit 868MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_868 = {
|
||||
.frequency = 868350000,
|
||||
.bits = 12,
|
||||
.te = 433,
|
||||
.repeat = 3,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = HoltekFileProtocol};
|
||||
|
||||
/**
|
||||
* Holtek AM 12bit 915MHz
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_915 = {
|
||||
.frequency = 915000000,
|
||||
.bits = 12,
|
||||
.te = 433,
|
||||
.repeat = 3,
|
||||
.preset = FuriHalSubGhzPresetOok650Async,
|
||||
.file = HoltekFileProtocol};
|
||||
|
||||
/**
|
||||
* BF existing dump
|
||||
*/
|
||||
const SubBruteProtocol subbrute_protocol_load_file =
|
||||
{0, 0, 0, 3, FuriHalSubGhzPresetOok650Async, UnknownFileProtocol};
|
||||
|
||||
static const char* subbrute_protocol_names[] = {
|
||||
[SubBruteAttackCAME12bit303] = "CAME 12bit 303MHz",
|
||||
[SubBruteAttackCAME12bit307] = "CAME 12bit 307MHz",
|
||||
[SubBruteAttackCAME12bit315] = "CAME 12bit 315MHz",
|
||||
[SubBruteAttackCAME12bit433] = "CAME 12bit 433MHz",
|
||||
[SubBruteAttackCAME12bit868] = "CAME 12bit 868MHz",
|
||||
[SubBruteAttackNICE12bit433] = "NICE 12bit 433MHz",
|
||||
[SubBruteAttackNICE12bit868] = "NICE 12bit 868MHz",
|
||||
[SubBruteAttackAnsonic12bit433075] = "Ansonic 12bit 433.07MHz",
|
||||
[SubBruteAttackAnsonic12bit433] = "Ansonic 12bit 433.92MHz",
|
||||
[SubBruteAttackAnsonic12bit434] = "Ansonic 12bit 434.07MHz",
|
||||
[SubBruteAttackHoltek12bitFM433] = "Holtek FM 12bit 433MHz",
|
||||
[SubBruteAttackHoltek12bitAM433] = "Holtek AM 12bit 433MHz",
|
||||
[SubBruteAttackHoltek12bitAM315] = "Holtek AM 12bit 315MHz",
|
||||
[SubBruteAttackHoltek12bitAM868] = "Holtek AM 12bit 868MHz",
|
||||
[SubBruteAttackHoltek12bitAM915] = "Holtek AM 12bit 915MHz",
|
||||
[SubBruteAttackChamberlain9bit300] = "Chamberlain 9bit 300MHz",
|
||||
[SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315MHz",
|
||||
[SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390MHz",
|
||||
[SubBruteAttackChamberlain9bit433] = "Chamberlain 9bit 433MHz",
|
||||
[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",
|
||||
[SubBruteAttackLinearDelta8bit310] = "LinearDelta3 8bit 310MHz",
|
||||
[SubBruteAttackUNILARM24bit330] = "UNILARM 25bit 330MHz",
|
||||
[SubBruteAttackUNILARM24bit433] = "UNILARM 25bit 433MHz",
|
||||
[SubBruteAttackSMC532624bit330] = "SMC5326 25bit 330MHz",
|
||||
[SubBruteAttackSMC532624bit433] = "SMC5326 25bit 433MHz",
|
||||
[SubBruteAttackPT226024bit315] = "PT2260 24bit 315MHz",
|
||||
[SubBruteAttackPT226024bit330] = "PT2260 24bit 330MHz",
|
||||
[SubBruteAttackPT226024bit390] = "PT2260 24bit 390MHz",
|
||||
[SubBruteAttackPT226024bit433] = "PT2260 24bit 433MHz",
|
||||
[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,
|
||||
[SubBruteAttackCAME12bit315] = &subbrute_protocol_came_12bit_315,
|
||||
[SubBruteAttackCAME12bit433] = &subbrute_protocol_came_12bit_433,
|
||||
[SubBruteAttackCAME12bit868] = &subbrute_protocol_came_12bit_868,
|
||||
[SubBruteAttackNICE12bit433] = &subbrute_protocol_nice_12bit_433,
|
||||
[SubBruteAttackNICE12bit868] = &subbrute_protocol_nice_12bit_868,
|
||||
[SubBruteAttackAnsonic12bit433075] = &subbrute_protocol_ansonic_12bit_433075,
|
||||
[SubBruteAttackAnsonic12bit433] = &subbrute_protocol_ansonic_12bit_433,
|
||||
[SubBruteAttackAnsonic12bit434] = &subbrute_protocol_ansonic_12bit_434,
|
||||
[SubBruteAttackHoltek12bitFM433] = &subbrute_protocol_holtek_12bit_433,
|
||||
[SubBruteAttackHoltek12bitAM433] = &subbrute_protocol_holtek_12bit_am_433,
|
||||
[SubBruteAttackHoltek12bitAM315] = &subbrute_protocol_holtek_12bit_am_315,
|
||||
[SubBruteAttackHoltek12bitAM868] = &subbrute_protocol_holtek_12bit_am_868,
|
||||
[SubBruteAttackHoltek12bitAM915] = &subbrute_protocol_holtek_12bit_am_915,
|
||||
[SubBruteAttackChamberlain9bit300] = &subbrute_protocol_chamberlain_9bit_300,
|
||||
[SubBruteAttackChamberlain9bit315] = &subbrute_protocol_chamberlain_9bit_315,
|
||||
[SubBruteAttackChamberlain9bit390] = &subbrute_protocol_chamberlain_9bit_390,
|
||||
[SubBruteAttackChamberlain9bit433] = &subbrute_protocol_chamberlain_9bit_433,
|
||||
[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,
|
||||
[SubBruteAttackLinearDelta8bit310] = &subbrute_protocol_linear_delta_8bit_310,
|
||||
[SubBruteAttackUNILARM24bit330] = &subbrute_protocol_unilarm_24bit_330,
|
||||
[SubBruteAttackUNILARM24bit433] = &subbrute_protocol_unilarm_24bit_433,
|
||||
[SubBruteAttackSMC532624bit330] = &subbrute_protocol_smc5326_24bit_330,
|
||||
[SubBruteAttackSMC532624bit433] = &subbrute_protocol_smc5326_24bit_433,
|
||||
[SubBruteAttackPT226024bit315] = &subbrute_protocol_pt2260_24bit_315,
|
||||
[SubBruteAttackPT226024bit330] = &subbrute_protocol_pt2260_24bit_330,
|
||||
[SubBruteAttackPT226024bit390] = &subbrute_protocol_pt2260_24bit_390,
|
||||
[SubBruteAttackPT226024bit433] = &subbrute_protocol_pt2260_24bit_433,
|
||||
[SubBruteAttackLoadFile] = &subbrute_protocol_load_file};
|
||||
|
||||
static const char* subbrute_protocol_file_types[] = {
|
||||
[CAMEFileProtocol] = "CAME",
|
||||
[NICEFileProtocol] = "Nice FLO",
|
||||
[ChamberlainFileProtocol] = "Cham_Code",
|
||||
[LinearFileProtocol] = "Linear",
|
||||
[LinearDeltaFileProtocol] = "LinearDelta3",
|
||||
[PrincetonFileProtocol] = "Princeton",
|
||||
[RAWFileProtocol] = "RAW",
|
||||
[BETTFileProtocol] = "BETT",
|
||||
[ClemsaFileProtocol] = "Clemsa",
|
||||
[DoitrandFileProtocol] = "Doitrand",
|
||||
[GateTXFileProtocol] = "GateTX",
|
||||
[MagellanFileProtocol] = "Magellan",
|
||||
[IntertechnoV3FileProtocol] = "Intertechno_V3",
|
||||
[AnsonicFileProtocol] = "Ansonic",
|
||||
[SMC5326FileProtocol] = "SMC5326",
|
||||
[UNILARMFileProtocol] = "SMC5326",
|
||||
[PT2260FileProtocol] = "Princeton",
|
||||
[HoneywellFileProtocol] = "Honeywell",
|
||||
[HoltekFileProtocol] = "Holtek_HT12X",
|
||||
[UnknownFileProtocol] = "Unknown"};
|
||||
|
||||
/**
|
||||
* 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_raw =
|
||||
// "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %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];
|
||||
}
|
||||
|
||||
uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index) {
|
||||
return subbrute_protocol_registry[index]->repeat;
|
||||
}
|
||||
|
||||
const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset) {
|
||||
return subbrute_protocol_presets[preset];
|
||||
}
|
||||
|
||||
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 UnknownFileProtocol;
|
||||
}
|
||||
|
||||
void subbrute_protocol_create_candidate_for_existing_file(
|
||||
FuriString* candidate,
|
||||
uint64_t step,
|
||||
uint8_t bit_index,
|
||||
uint64_t file_key,
|
||||
bool two_bytes) {
|
||||
uint8_t p[8];
|
||||
for(int i = 0; i < 8; i++) {
|
||||
p[i] = (uint8_t)(file_key >> 8 * (7 - i)) & 0xFF;
|
||||
}
|
||||
uint8_t low_byte = step & (0xff);
|
||||
uint8_t high_byte = (step >> 8) & 0xff;
|
||||
|
||||
size_t size = sizeof(uint64_t);
|
||||
for(uint8_t i = 0; i < size; i++) {
|
||||
if(i == bit_index - 1 && two_bytes) {
|
||||
furi_string_cat_printf(candidate, "%02X %02X", high_byte, low_byte);
|
||||
i++;
|
||||
} else if(i == bit_index) {
|
||||
furi_string_cat_printf(candidate, "%02X", low_byte);
|
||||
} else if(p[i] != 0) {
|
||||
furi_string_cat_printf(candidate, "%02X", p[i]);
|
||||
} else {
|
||||
furi_string_cat_printf(candidate, "%s", "00");
|
||||
}
|
||||
|
||||
if(i < size - 1) {
|
||||
furi_string_push_back(candidate, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "file candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
|
||||
#endif
|
||||
}
|
||||
|
||||
void subbrute_protocol_create_candidate_for_default(
|
||||
FuriString* candidate,
|
||||
SubBruteFileProtocol file,
|
||||
uint64_t step) {
|
||||
uint8_t p[8];
|
||||
if(file == SMC5326FileProtocol) {
|
||||
const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11
|
||||
const uint64_t gate1 = 0x01D5; // 111010101
|
||||
//const uint8_t gate2 = 0x0175; // 101110101
|
||||
|
||||
uint64_t total = 0;
|
||||
for(size_t j = 0; j < 8; j++) {
|
||||
total |= lut[step % 3] << (2 * j);
|
||||
double sub_step = step / 3;
|
||||
step = (uint64_t)floor(sub_step);
|
||||
}
|
||||
total <<= 9;
|
||||
total |= gate1;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
|
||||
}
|
||||
} else if(file == UNILARMFileProtocol) {
|
||||
const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11
|
||||
const uint64_t gate1 = 3 << 7;
|
||||
//const uint8_t gate2 = 3 << 5;
|
||||
|
||||
uint64_t total = 0;
|
||||
for(size_t j = 0; j < 8; j++) {
|
||||
total |= lut[step % 3] << (2 * j);
|
||||
double sub_step = step / 3;
|
||||
step = (uint64_t)floor(sub_step);
|
||||
}
|
||||
total <<= 9;
|
||||
total |= gate1;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
|
||||
}
|
||||
} else if(file == PT2260FileProtocol) {
|
||||
const uint8_t lut[] = {0x00, 0x01, 0x03}; // 00, 01, 11
|
||||
const uint64_t button_open = 0x03; // 11
|
||||
//const uint8_t button_lock = 0x0C; // 1100
|
||||
//const uint8_t button_stop = 0x30; // 110000
|
||||
//const uint8_t button_close = 0xC0; // 11000000
|
||||
|
||||
uint64_t total = 0;
|
||||
for(size_t j = 0; j < 8; j++) {
|
||||
total |= lut[step % 3] << (2 * j);
|
||||
double sub_step = step / 3;
|
||||
step = (uint64_t)floor(sub_step);
|
||||
}
|
||||
total <<= 8;
|
||||
total |= button_open;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
p[i] = (uint8_t)(step >> 8 * (7 - i)) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size = sizeof(uint64_t);
|
||||
for(uint8_t i = 0; i < size; i++) {
|
||||
if(p[i] != 0) {
|
||||
furi_string_cat_printf(candidate, "%02X", p[i]);
|
||||
} else {
|
||||
furi_string_cat_printf(candidate, "%s", "00");
|
||||
}
|
||||
|
||||
if(i < size - 1) {
|
||||
furi_string_push_back(candidate, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
|
||||
#endif
|
||||
}
|
||||
|
||||
void subbrute_protocol_default_payload(
|
||||
Stream* stream,
|
||||
SubBruteFileProtocol file,
|
||||
uint64_t step,
|
||||
uint8_t bits,
|
||||
uint32_t te,
|
||||
uint8_t repeat) {
|
||||
FuriString* candidate = furi_string_alloc();
|
||||
subbrute_protocol_create_candidate_for_default(candidate, file, step);
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"candidate: %s, step: %lld, repeat: %d, te: %s",
|
||||
furi_string_get_cstr(candidate),
|
||||
step,
|
||||
repeat,
|
||||
te ? "true" : "false");
|
||||
#endif
|
||||
stream_clean(stream);
|
||||
if(te) {
|
||||
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,
|
||||
uint32_t te,
|
||||
uint8_t repeat,
|
||||
uint8_t bit_index,
|
||||
uint64_t file_key,
|
||||
bool two_bytes) {
|
||||
FuriString* candidate = furi_string_alloc();
|
||||
subbrute_protocol_create_candidate_for_existing_file(
|
||||
candidate, step, bit_index, file_key, two_bytes);
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"candidate: %s, step: %lld, repeat: %d, te: %s",
|
||||
furi_string_get_cstr(candidate),
|
||||
step,
|
||||
repeat,
|
||||
te ? "true" : "false");
|
||||
#endif
|
||||
stream_clean(stream);
|
||||
|
||||
if(te) {
|
||||
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,
|
||||
uint32_t te,
|
||||
uint8_t repeat) {
|
||||
FuriString* candidate = furi_string_alloc();
|
||||
subbrute_protocol_create_candidate_for_default(candidate, file, step);
|
||||
|
||||
#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,
|
||||
uint32_t te,
|
||||
uint8_t repeat,
|
||||
uint8_t bit_index,
|
||||
uint64_t file_key,
|
||||
bool two_bytes) {
|
||||
FuriString* candidate = furi_string_alloc();
|
||||
// char subbrute_payload_byte[8];
|
||||
//furi_string_set_str(candidate, file_key);
|
||||
subbrute_protocol_create_candidate_for_existing_file(
|
||||
candidate, step, bit_index, file_key, two_bytes);
|
||||
|
||||
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, bool two_bytes) {
|
||||
uint64_t max_value;
|
||||
if(attack_type == SubBruteAttackLoadFile) {
|
||||
max_value = two_bytes ? 0xFFFF : 0xFF;
|
||||
} else if(
|
||||
attack_type == SubBruteAttackSMC532624bit330 ||
|
||||
attack_type == SubBruteAttackSMC532624bit433 ||
|
||||
attack_type == SubBruteAttackUNILARM24bit330 ||
|
||||
attack_type == SubBruteAttackUNILARM24bit433 ||
|
||||
attack_type == SubBruteAttackPT226024bit315 ||
|
||||
attack_type == SubBruteAttackPT226024bit330 ||
|
||||
attack_type == SubBruteAttackPT226024bit390 ||
|
||||
attack_type == SubBruteAttackPT226024bit433) {
|
||||
max_value = 6561;
|
||||
} 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;
|
||||
}
|
||||
128
applications/external/subghz_bruteforcer/subbrute_protocols.h
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal_subghz.h>
|
||||
#include <core/string.h>
|
||||
#include <toolbox/stream/stream.h>
|
||||
|
||||
typedef enum {
|
||||
CAMEFileProtocol,
|
||||
NICEFileProtocol,
|
||||
ChamberlainFileProtocol,
|
||||
LinearFileProtocol,
|
||||
LinearDeltaFileProtocol,
|
||||
PrincetonFileProtocol,
|
||||
RAWFileProtocol,
|
||||
BETTFileProtocol,
|
||||
ClemsaFileProtocol,
|
||||
DoitrandFileProtocol,
|
||||
GateTXFileProtocol,
|
||||
MagellanFileProtocol,
|
||||
IntertechnoV3FileProtocol,
|
||||
AnsonicFileProtocol,
|
||||
SMC5326FileProtocol,
|
||||
UNILARMFileProtocol,
|
||||
PT2260FileProtocol,
|
||||
HoneywellFileProtocol,
|
||||
HoltekFileProtocol,
|
||||
UnknownFileProtocol,
|
||||
TotalFileProtocol,
|
||||
} SubBruteFileProtocol;
|
||||
|
||||
typedef enum {
|
||||
SubBruteAttackCAME12bit303,
|
||||
SubBruteAttackCAME12bit307,
|
||||
SubBruteAttackCAME12bit315,
|
||||
SubBruteAttackCAME12bit433,
|
||||
SubBruteAttackCAME12bit868,
|
||||
SubBruteAttackNICE12bit433,
|
||||
SubBruteAttackNICE12bit868,
|
||||
SubBruteAttackAnsonic12bit433075,
|
||||
SubBruteAttackAnsonic12bit433,
|
||||
SubBruteAttackAnsonic12bit434,
|
||||
SubBruteAttackHoltek12bitFM433,
|
||||
SubBruteAttackHoltek12bitAM433,
|
||||
SubBruteAttackHoltek12bitAM315,
|
||||
SubBruteAttackHoltek12bitAM868,
|
||||
SubBruteAttackHoltek12bitAM915,
|
||||
SubBruteAttackChamberlain9bit300,
|
||||
SubBruteAttackChamberlain9bit315,
|
||||
SubBruteAttackChamberlain9bit390,
|
||||
SubBruteAttackChamberlain9bit433,
|
||||
SubBruteAttackChamberlain8bit300,
|
||||
SubBruteAttackChamberlain8bit315,
|
||||
SubBruteAttackChamberlain8bit390,
|
||||
SubBruteAttackChamberlain7bit300,
|
||||
SubBruteAttackChamberlain7bit315,
|
||||
SubBruteAttackChamberlain7bit390,
|
||||
SubBruteAttackLinear10bit300,
|
||||
SubBruteAttackLinear10bit310,
|
||||
SubBruteAttackLinearDelta8bit310,
|
||||
SubBruteAttackUNILARM24bit330,
|
||||
SubBruteAttackUNILARM24bit433,
|
||||
SubBruteAttackSMC532624bit330,
|
||||
SubBruteAttackSMC532624bit433,
|
||||
SubBruteAttackPT226024bit315,
|
||||
SubBruteAttackPT226024bit330,
|
||||
SubBruteAttackPT226024bit390,
|
||||
SubBruteAttackPT226024bit433,
|
||||
SubBruteAttackLoadFile,
|
||||
SubBruteAttackTotalCount,
|
||||
} SubBruteAttacks;
|
||||
|
||||
typedef struct {
|
||||
uint32_t frequency;
|
||||
uint8_t bits;
|
||||
uint32_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);
|
||||
uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index);
|
||||
const char* subbrute_protocol_name(SubBruteAttacks index);
|
||||
|
||||
void subbrute_protocol_default_payload(
|
||||
Stream* stream,
|
||||
SubBruteFileProtocol file,
|
||||
uint64_t step,
|
||||
uint8_t bits,
|
||||
uint32_t te,
|
||||
uint8_t repeat);
|
||||
void subbrute_protocol_file_payload(
|
||||
Stream* stream,
|
||||
uint64_t step,
|
||||
uint8_t bits,
|
||||
uint32_t te,
|
||||
uint8_t repeat,
|
||||
uint8_t bit_index,
|
||||
uint64_t file_key,
|
||||
bool two_bytes);
|
||||
void subbrute_protocol_default_generate_file(
|
||||
Stream* stream,
|
||||
uint32_t frequency,
|
||||
FuriHalSubGhzPreset preset,
|
||||
SubBruteFileProtocol file,
|
||||
uint64_t step,
|
||||
uint8_t bits,
|
||||
uint32_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,
|
||||
uint32_t te,
|
||||
uint8_t repeat,
|
||||
uint8_t bit_index,
|
||||
uint64_t file_key,
|
||||
bool two_bytes);
|
||||
uint64_t
|
||||
subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes);
|
||||
341
applications/external/subghz_bruteforcer/views/subbrute_attack_view.c
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
#include "subbrute_attack_view.h"
|
||||
#include "../subbrute_i.h"
|
||||
#include "../subbrute_protocols.h"
|
||||
#include "../helpers/gui_top_buttons.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;
|
||||
SubBruteAttacks attack_type;
|
||||
uint64_t max_value;
|
||||
uint64_t current_step;
|
||||
bool is_attacking;
|
||||
uint8_t extra_repeats;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SubBruteAttacks attack_type;
|
||||
uint64_t max_value;
|
||||
uint64_t current_step;
|
||||
uint8_t extra_repeats;
|
||||
bool is_attacking;
|
||||
IconAnimation* icon;
|
||||
} SubBruteAttackViewModel;
|
||||
|
||||
void subbrute_attack_view_set_callback(
|
||||
SubBruteAttackView* instance,
|
||||
SubBruteAttackViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
bool subbrute_attack_view_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
SubBruteAttackView* instance = context;
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "InputKey: %d", event->key);
|
||||
#endif
|
||||
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
instance->is_attacking = false;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubBruteAttackViewModel * model,
|
||||
{ model->is_attacking = false; },
|
||||
true);
|
||||
|
||||
instance->callback(SubBruteCustomEventTypeBackPressed, instance->context);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update = false;
|
||||
|
||||
if(!instance->is_attacking) {
|
||||
if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "InputKey: %d OK", event->key);
|
||||
#endif
|
||||
instance->is_attacking = true;
|
||||
instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);
|
||||
update = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
instance->callback(SubBruteCustomEventTypeSaveFile, instance->context);
|
||||
update = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context);
|
||||
update = true;
|
||||
} else if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyLeft) {
|
||||
instance->callback(SubBruteCustomEventTypeChangeStepDown, instance->context);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
instance->callback(SubBruteCustomEventTypeChangeStepUp, instance->context);
|
||||
}
|
||||
update = true;
|
||||
} else if(event->type == InputTypeRepeat) {
|
||||
if(event->key == InputKeyLeft) {
|
||||
instance->callback(SubBruteCustomEventTypeChangeStepDownMore, instance->context);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
instance->callback(SubBruteCustomEventTypeChangeStepUpMore, instance->context);
|
||||
}
|
||||
update = true;
|
||||
}
|
||||
} else {
|
||||
// ATTACK Mode!
|
||||
if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
|
||||
(event->key == InputKeyOk || event->key == InputKeyBack)) {
|
||||
instance->is_attacking = false;
|
||||
instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context);
|
||||
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(update) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubBruteAttackViewModel * model,
|
||||
{
|
||||
if(model->is_attacking != instance->is_attacking) {
|
||||
if(instance->is_attacking) {
|
||||
icon_animation_stop(model->icon);
|
||||
icon_animation_start(model->icon);
|
||||
} else {
|
||||
icon_animation_stop(model->icon);
|
||||
}
|
||||
}
|
||||
|
||||
model->attack_type = instance->attack_type;
|
||||
model->max_value = instance->max_value;
|
||||
model->current_step = instance->current_step;
|
||||
model->is_attacking = instance->is_attacking;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
},
|
||||
true);
|
||||
|
||||
view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw);
|
||||
view_set_input_callback(instance->view, subbrute_attack_view_input);
|
||||
view_set_enter_callback(instance->view, subbrute_attack_view_enter);
|
||||
view_set_exit_callback(instance->view, subbrute_attack_view_exit);
|
||||
|
||||
instance->attack_type = SubBruteAttackTotalCount;
|
||||
instance->max_value = 0x00;
|
||||
instance->current_step = 0;
|
||||
instance->is_attacking = false;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
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
|
||||
instance->current_step = current_step;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubBruteAttackViewModel * model,
|
||||
{ model->current_step = current_step; },
|
||||
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,
|
||||
uint8_t extra_repeats) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"INIT, attack_type: %d, max_value: %lld, current_step: %lld, extra_repeats: %d",
|
||||
index,
|
||||
max_value,
|
||||
current_step,
|
||||
extra_repeats);
|
||||
#endif
|
||||
instance->attack_type = index;
|
||||
instance->max_value = max_value;
|
||||
instance->current_step = current_step;
|
||||
instance->is_attacking = is_attacking;
|
||||
instance->extra_repeats = extra_repeats;
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubBruteAttackViewModel * model,
|
||||
{
|
||||
model->max_value = max_value;
|
||||
model->attack_type = index;
|
||||
model->current_step = current_step;
|
||||
model->is_attacking = is_attacking;
|
||||
model->extra_repeats = extra_repeats;
|
||||
if(is_attacking) {
|
||||
icon_animation_start(model->icon);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
void subbrute_attack_view_draw(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context;
|
||||
char buffer[64];
|
||||
|
||||
const char* attack_name = NULL;
|
||||
attack_name = subbrute_protocol_name(model->attack_type);
|
||||
|
||||
// Title
|
||||
if(model->is_attacking) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, attack_name);
|
||||
}
|
||||
|
||||
// Current Step / Max value
|
||||
const uint8_t y_frequency = 17;
|
||||
if(model->max_value > 9999) {
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
snprintf(buffer, sizeof(buffer), "%05d/", (int)model->current_step);
|
||||
canvas_draw_str_aligned(canvas, 5, y_frequency, AlignLeft, AlignTop, buffer);
|
||||
|
||||
// Second part with another font, because BigNumber is out of screen bounds
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(buffer, sizeof(buffer), "%05d", (int)model->max_value);
|
||||
canvas_draw_str_aligned(canvas, 107, y_frequency + 13, AlignRight, AlignBottom, buffer);
|
||||
} else if(model->max_value <= 0xFF) {
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
snprintf(
|
||||
buffer, sizeof(buffer), "%03d/%03d", (int)model->current_step, (int)model->max_value);
|
||||
canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer);
|
||||
} else {
|
||||
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, y_frequency, AlignCenter, AlignTop, buffer);
|
||||
}
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
if(!model->is_attacking) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignBottom, attack_name);
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"x%d",
|
||||
model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type));
|
||||
canvas_draw_str_aligned(canvas, 60, 6, AlignCenter, AlignCenter, buffer);
|
||||
|
||||
elements_button_left(canvas, "-1");
|
||||
elements_button_right(canvas, "+1");
|
||||
elements_button_center(canvas, "Start");
|
||||
elements_button_top_left(canvas, "Save");
|
||||
elements_button_top_right(canvas, "Resend");
|
||||
} else {
|
||||
// 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);
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"x%d",
|
||||
model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type));
|
||||
canvas_draw_str(canvas, 4, y - 8, buffer);
|
||||
canvas_draw_str(canvas, 4, y - 1, "repeats");
|
||||
|
||||
elements_button_center(canvas, "Stop");
|
||||
}
|
||||
}
|
||||
25
applications/external/subghz_bruteforcer/views/subbrute_attack_view.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#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_init_values(
|
||||
SubBruteAttackView* instance,
|
||||
uint8_t index,
|
||||
uint64_t max_value,
|
||||
uint64_t current_step,
|
||||
bool is_attacking,
|
||||
uint8_t extra_repeats);
|
||||
463
applications/external/subghz_bruteforcer/views/subbrute_main_view.c
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
#include "subbrute_main_view.h"
|
||||
#include "../subbrute_i.h"
|
||||
#include "../subbrute_protocols.h"
|
||||
#include "../helpers/gui_top_buttons.h"
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/icon.h>
|
||||
|
||||
#define STATUS_BAR_Y_SHIFT 14
|
||||
#define TAG "SubBruteMainView"
|
||||
|
||||
#define ITEMS_ON_SCREEN 3
|
||||
#define ITEMS_INTERVAL 1
|
||||
#define ITEM_WIDTH 14
|
||||
#define ITEM_Y 27
|
||||
#define ITEM_HEIGHT 13
|
||||
#define TEXT_X 6
|
||||
#define TEXT_Y 37
|
||||
#define TEXT_INTERVAL 3
|
||||
#define TEXT_WIDTH 12
|
||||
#define ITEM_FRAME_RADIUS 2
|
||||
|
||||
struct SubBruteMainView {
|
||||
View* view;
|
||||
SubBruteMainViewCallback callback;
|
||||
void* context;
|
||||
uint8_t index;
|
||||
bool is_select_byte;
|
||||
bool two_bytes;
|
||||
uint64_t key_from_file;
|
||||
uint8_t extra_repeats;
|
||||
uint8_t window_position;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t index;
|
||||
uint8_t extra_repeats;
|
||||
uint8_t window_position;
|
||||
bool is_select_byte;
|
||||
bool two_bytes;
|
||||
uint64_t key_from_file;
|
||||
} SubBruteMainViewModel;
|
||||
|
||||
void subbrute_main_view_set_callback(
|
||||
SubBruteMainView* instance,
|
||||
SubBruteMainViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void subbrute_main_view_center_displayed_key(
|
||||
Canvas* canvas,
|
||||
uint64_t key,
|
||||
uint8_t index,
|
||||
bool two_bytes) {
|
||||
uint8_t text_x = TEXT_X;
|
||||
uint8_t item_x = TEXT_X - ITEMS_INTERVAL;
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
char current_value[3] = {0};
|
||||
uint8_t byte_value = (uint8_t)(key >> 8 * (7 - i)) & 0xFF;
|
||||
snprintf(current_value, sizeof(current_value), "%02X", byte_value);
|
||||
|
||||
// For two bytes we need to select prev location
|
||||
if(!two_bytes && i == index) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_rbox(
|
||||
canvas, item_x - 1, ITEM_Y, ITEM_WIDTH + 1, ITEM_HEIGHT, ITEM_FRAME_RADIUS);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
|
||||
} else if(two_bytes && (i == index || i == index - 1)) {
|
||||
if(i == index) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_rbox(
|
||||
canvas,
|
||||
item_x - ITEMS_INTERVAL - ITEM_WIDTH - 1,
|
||||
ITEM_Y,
|
||||
ITEM_WIDTH * 2 + ITEMS_INTERVAL * 2 + 1,
|
||||
ITEM_HEIGHT,
|
||||
ITEM_FRAME_RADIUS);
|
||||
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
|
||||
|
||||
// Redraw prev element with white
|
||||
memset(current_value, 0, sizeof(current_value));
|
||||
byte_value = (uint8_t)(key >> 8 * (7 - i + 1)) & 0xFF;
|
||||
snprintf(current_value, sizeof(current_value), "%02X", byte_value);
|
||||
canvas_draw_str(
|
||||
canvas, text_x - (TEXT_WIDTH + TEXT_INTERVAL), TEXT_Y, current_value);
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
|
||||
}
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
|
||||
}
|
||||
text_x = text_x + TEXT_WIDTH + TEXT_INTERVAL;
|
||||
item_x = item_x + ITEM_WIDTH + ITEMS_INTERVAL;
|
||||
}
|
||||
|
||||
// Return normal color
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) {
|
||||
uint16_t screen_width = canvas_width(canvas);
|
||||
uint16_t screen_height = canvas_height(canvas);
|
||||
|
||||
if(model->is_select_byte) {
|
||||
#ifdef FURI_DEBUG
|
||||
//FURI_LOG_D(TAG, "key_from_file: %s", model->key_from_file);
|
||||
#endif
|
||||
//char msg_index[18];
|
||||
//snprintf(msg_index, sizeof(msg_index), "Field index: %d", model->index);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 17, AlignCenter, AlignTop, "Please select values to calc:");
|
||||
|
||||
subbrute_main_view_center_displayed_key(
|
||||
canvas, model->key_from_file, model->index, model->two_bytes);
|
||||
//const char* line = furi_string_get_cstr(menu_items);
|
||||
//canvas_set_font(canvas, FontSecondary);
|
||||
//canvas_draw_str_aligned(
|
||||
// canvas, 64, 37, AlignCenter, AlignTop, furi_string_get_cstr(menu_items));
|
||||
|
||||
elements_button_center(canvas, "Select");
|
||||
if(model->index > 0) {
|
||||
elements_button_left(canvas, " ");
|
||||
}
|
||||
if(model->index < 7) {
|
||||
elements_button_right(canvas, " ");
|
||||
}
|
||||
// Switch to another mode
|
||||
if(model->two_bytes) {
|
||||
elements_button_top_left(canvas, "One byte");
|
||||
} else {
|
||||
elements_button_top_left(canvas, "Two bytes");
|
||||
}
|
||||
} else {
|
||||
// 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, SUBBRUTEFORCER_VER);
|
||||
canvas_invert_color(canvas);
|
||||
|
||||
// Menu
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
const uint8_t item_height = 16;
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
//FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, model->index);
|
||||
#endif
|
||||
for(uint8_t position = 0; position < SubBruteAttackTotalCount; ++position) {
|
||||
uint8_t item_position = position - model->window_position;
|
||||
|
||||
if(item_position < ITEMS_ON_SCREEN) {
|
||||
if(model->index == position) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
4,
|
||||
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
|
||||
AlignLeft,
|
||||
AlignCenter,
|
||||
subbrute_protocol_name(position));
|
||||
|
||||
if(model->extra_repeats > 0) {
|
||||
canvas_set_font(canvas, FontBatteryPercent);
|
||||
char buffer[10];
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"x%d",
|
||||
model->extra_repeats + subbrute_protocol_repeats_count(model->index));
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
screen_width - 15,
|
||||
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
|
||||
AlignLeft,
|
||||
AlignCenter,
|
||||
buffer);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
}
|
||||
|
||||
elements_frame(
|
||||
canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15);
|
||||
} else {
|
||||
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,
|
||||
screen_width,
|
||||
STATUS_BAR_Y_SHIFT + 2,
|
||||
screen_height - STATUS_BAR_Y_SHIFT,
|
||||
model->index,
|
||||
SubBruteAttackTotalCount);
|
||||
}
|
||||
}
|
||||
|
||||
bool subbrute_main_view_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "InputKey: BACK");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
SubBruteMainView* instance = context;
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "InputKey: %d, extra_repeats: %d", event->key, instance->extra_repeats);
|
||||
#endif
|
||||
const uint8_t min_value = 0;
|
||||
const uint8_t correct_total = SubBruteAttackTotalCount - 1;
|
||||
uint8_t max_repeats = 9 - subbrute_protocol_repeats_count(instance->index);
|
||||
|
||||
bool updated = false;
|
||||
bool consumed = false;
|
||||
bool is_short = (event->type == InputTypeShort) || (event->type == InputTypeRepeat);
|
||||
|
||||
if(!instance->is_select_byte) {
|
||||
if(event->key == InputKeyUp && is_short) {
|
||||
if(instance->index == min_value) {
|
||||
instance->index = correct_total;
|
||||
} else {
|
||||
instance->index = CLAMP(instance->index - 1, correct_total, min_value);
|
||||
}
|
||||
instance->extra_repeats = 0;
|
||||
updated = true;
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown && is_short) {
|
||||
if(instance->index == correct_total) {
|
||||
instance->index = min_value;
|
||||
} else {
|
||||
instance->index = CLAMP(instance->index + 1, correct_total, min_value);
|
||||
}
|
||||
instance->extra_repeats = 0;
|
||||
updated = true;
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyLeft && is_short) {
|
||||
instance->extra_repeats = CLAMP(instance->extra_repeats - 1, max_repeats, 0);
|
||||
|
||||
updated = true;
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyRight && is_short) {
|
||||
instance->extra_repeats = CLAMP(instance->extra_repeats + 1, max_repeats, 0);
|
||||
|
||||
updated = true;
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyOk && is_short) {
|
||||
if(instance->index == SubBruteAttackLoadFile) {
|
||||
instance->callback(SubBruteCustomEventTypeLoadFile, instance->context);
|
||||
} else {
|
||||
instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context);
|
||||
}
|
||||
consumed = true;
|
||||
updated = true;
|
||||
}
|
||||
if(updated) {
|
||||
instance->window_position = instance->index;
|
||||
if(instance->window_position > 0) {
|
||||
instance->window_position -= 1;
|
||||
}
|
||||
|
||||
if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) {
|
||||
instance->window_position = 0;
|
||||
} else {
|
||||
if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) {
|
||||
instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(is_short) {
|
||||
if(event->key == InputKeyLeft) {
|
||||
if((instance->index > 0 && !instance->two_bytes) ||
|
||||
(instance->two_bytes && instance->index > 1)) {
|
||||
instance->index--;
|
||||
}
|
||||
updated = true;
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
if(instance->index < 7) {
|
||||
instance->index++;
|
||||
}
|
||||
updated = true;
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
instance->two_bytes = !instance->two_bytes;
|
||||
// Because index is changing
|
||||
if(instance->two_bytes && instance->index < 7) {
|
||||
instance->index++;
|
||||
}
|
||||
// instance->callback(
|
||||
// instance->two_bytes ? SubBruteCustomEventTypeChangeStepUp :
|
||||
// SubBruteCustomEventTypeChangeStepDown,
|
||||
// instance->context);
|
||||
|
||||
updated = true;
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyOk) {
|
||||
instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context);
|
||||
consumed = true;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(updated) {
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubBruteMainViewModel * model,
|
||||
{
|
||||
model->index = instance->index;
|
||||
model->window_position = instance->window_position;
|
||||
model->key_from_file = instance->key_from_file;
|
||||
model->is_select_byte = instance->is_select_byte;
|
||||
model->two_bytes = instance->two_bytes;
|
||||
model->extra_repeats = instance->extra_repeats;
|
||||
},
|
||||
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);
|
||||
|
||||
instance->index = 0;
|
||||
instance->window_position = 0;
|
||||
instance->key_from_file = 0;
|
||||
instance->is_select_byte = false;
|
||||
instance->two_bytes = false;
|
||||
instance->extra_repeats = 0;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubBruteMainViewModel * model,
|
||||
{
|
||||
model->index = instance->index;
|
||||
model->window_position = instance->window_position;
|
||||
model->key_from_file = instance->key_from_file;
|
||||
model->is_select_byte = instance->is_select_byte;
|
||||
model->two_bytes = instance->two_bytes;
|
||||
model->extra_repeats = instance->extra_repeats;
|
||||
},
|
||||
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,
|
||||
bool two_bytes,
|
||||
uint64_t key_from_file) {
|
||||
furi_assert(instance);
|
||||
furi_assert(idx < SubBruteAttackTotalCount);
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Set index: %d, is_select_byte: %d", idx, is_select_byte);
|
||||
#endif
|
||||
instance->is_select_byte = is_select_byte;
|
||||
instance->two_bytes = two_bytes;
|
||||
instance->key_from_file = key_from_file;
|
||||
instance->index = idx;
|
||||
instance->window_position = idx;
|
||||
|
||||
if(!is_select_byte) {
|
||||
if(instance->window_position > 0) {
|
||||
instance->window_position -= 1;
|
||||
}
|
||||
|
||||
if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) {
|
||||
instance->window_position = 0;
|
||||
} else {
|
||||
if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) {
|
||||
instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubBruteMainViewModel * model,
|
||||
{
|
||||
model->index = instance->index;
|
||||
model->window_position = instance->window_position;
|
||||
model->key_from_file = instance->key_from_file;
|
||||
model->is_select_byte = instance->is_select_byte;
|
||||
model->two_bytes = instance->two_bytes;
|
||||
model->extra_repeats = instance->extra_repeats;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->index;
|
||||
}
|
||||
|
||||
uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->extra_repeats;
|
||||
}
|
||||
|
||||
bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->two_bytes;
|
||||
}
|
||||
32
applications/external/subghz_bruteforcer/views/subbrute_main_view.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "../subbrute_custom_event.h"
|
||||
#include "../subbrute_protocols.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,
|
||||
bool two_bytes,
|
||||
uint64_t file_key);
|
||||
SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance);
|
||||
uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance);
|
||||
bool subbrute_main_view_get_two_bytes(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);
|
||||