Merge branch 'dev' into fix/subghz-notifies
@@ -120,6 +120,13 @@ Min level: 2
|
||||
Max level: 2
|
||||
Weight: 3
|
||||
|
||||
Name: L2_Dj_128x64
|
||||
Min butthurt: 0
|
||||
Max butthurt: 8
|
||||
Min level: 2
|
||||
Max level: 3
|
||||
Weight: 4
|
||||
|
||||
Name: L3_Furippa3_128x64
|
||||
Min butthurt: 0
|
||||
Max butthurt: 6
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c
|
||||
index f91a73f32..b559a79ad 100644
|
||||
index 2f947fe..03c4c76 100644
|
||||
--- a/applications/services/notification/notification_app.c
|
||||
+++ b/applications/services/notification/notification_app.c
|
||||
@@ -6,6 +6,7 @@
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "notification.h"
|
||||
#include "notification_messages.h"
|
||||
#include "notification_app.h"
|
||||
@@ -10,7 +10,7 @@ index f91a73f32..b559a79ad 100644
|
||||
|
||||
#define TAG "NotificationSrv"
|
||||
|
||||
@@ -564,6 +565,7 @@ int32_t notification_srv(void* p) {
|
||||
@@ -579,6 +580,7 @@ int32_t notification_srv(void* p) {
|
||||
break;
|
||||
case SaveSettingsMessage:
|
||||
notification_save_settings(app);
|
||||
@@ -19,7 +19,7 @@ index f91a73f32..b559a79ad 100644
|
||||
}
|
||||
|
||||
diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c
|
||||
index f5d7a82ca..930c0bd1f 100644
|
||||
index 565d4f1..bae9299 100644
|
||||
--- a/applications/settings/notification_settings/notification_settings_app.c
|
||||
+++ b/applications/settings/notification_settings/notification_settings_app.c
|
||||
@@ -3,6 +3,7 @@
|
||||
@@ -30,15 +30,7 @@ index f5d7a82ca..930c0bd1f 100644
|
||||
|
||||
#define MAX_NOTIFICATION_SETTINGS 4
|
||||
|
||||
@@ -73,7 +74,6 @@ const bool vibro_value[VIBRO_COUNT] = {false, true};
|
||||
static void backlight_changed(VariableItem* item) {
|
||||
NotificationAppSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
-
|
||||
variable_item_set_current_value_text(item, backlight_text[index]);
|
||||
app->notification->settings.display_brightness = backlight_value[index];
|
||||
notification_message(app->notification, &sequence_display_backlight_on);
|
||||
@@ -125,6 +125,14 @@ static void vibro_changed(VariableItem* item) {
|
||||
@@ -162,6 +163,14 @@ static void vibro_changed(VariableItem* item) {
|
||||
notification_message(app->notification, &sequence_single_vibro);
|
||||
}
|
||||
|
||||
@@ -53,8 +45,8 @@ index f5d7a82ca..930c0bd1f 100644
|
||||
static uint32_t notification_app_settings_exit(void* context) {
|
||||
UNUSED(context);
|
||||
return VIEW_NONE;
|
||||
@@ -143,7 +151,13 @@ static NotificationAppSettings* alloc_settings() {
|
||||
uint8_t value_index;
|
||||
@@ -187,7 +196,13 @@ static NotificationAppSettings* alloc_settings() {
|
||||
variable_item_set_current_value_text(item, contrast_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
- app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
|
||||
@@ -68,17 +60,9 @@ index f5d7a82ca..930c0bd1f 100644
|
||||
value_index = value_index_float(
|
||||
app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
@@ -215,6 +229,7 @@ int32_t notification_settings_app(void* p) {
|
||||
NotificationAppSettings* app = alloc_settings();
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
notification_message_save_settings(app->notification);
|
||||
+
|
||||
free_settings(app);
|
||||
return 0;
|
||||
}
|
||||
diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c
|
||||
new file mode 100644
|
||||
index 000000000..269b544ae
|
||||
index 0000000..269b544
|
||||
--- /dev/null
|
||||
+++ b/applications/settings/notification_settings/rgb_backlight.c
|
||||
@@ -0,0 +1,171 @@
|
||||
@@ -255,7 +239,7 @@ index 000000000..269b544ae
|
||||
+}
|
||||
diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h
|
||||
new file mode 100644
|
||||
index 000000000..b63d223e6
|
||||
index 0000000..b63d223
|
||||
--- /dev/null
|
||||
+++ b/applications/settings/notification_settings/rgb_backlight.h
|
||||
@@ -0,0 +1,79 @@
|
||||
@@ -340,7 +324,7 @@ index 000000000..b63d223e6
|
||||
+const char* rgb_backlight_get_color_text(uint8_t index);
|
||||
\ No newline at end of file
|
||||
diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/firmware/targets/f7/furi_hal/furi_hal_light.c
|
||||
index 83e1603b7..cad5b86cb 100644
|
||||
index 83e1603..cad5b86 100644
|
||||
--- a/firmware/targets/f7/furi_hal/furi_hal_light.c
|
||||
+++ b/firmware/targets/f7/furi_hal/furi_hal_light.c
|
||||
@@ -3,6 +3,7 @@
|
||||
@@ -389,7 +373,7 @@ index 83e1603b7..cad5b86cb 100644
|
||||
void furi_hal_light_blink_start(Light light, uint8_t brightness, uint16_t on_time, uint16_t period) {
|
||||
diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c
|
||||
new file mode 100644
|
||||
index 000000000..572e1df97
|
||||
index 0000000..572e1df
|
||||
--- /dev/null
|
||||
+++ b/lib/drivers/SK6805.c
|
||||
@@ -0,0 +1,101 @@
|
||||
@@ -496,7 +480,7 @@ index 000000000..572e1df97
|
||||
+}
|
||||
diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h
|
||||
new file mode 100644
|
||||
index 000000000..7c58956fa
|
||||
index 0000000..7c58956
|
||||
--- /dev/null
|
||||
+++ b/lib/drivers/SK6805.h
|
||||
@@ -0,0 +1,51 @@
|
||||
@@ -552,5 +536,3 @@ index 000000000..7c58956fa
|
||||
+
|
||||
+#endif /* SK6805_H_ */
|
||||
\ No newline at end of file
|
||||
|
||||
\ No newline at end of file
|
||||
|
||||
@@ -96,7 +96,7 @@ Encoders or sending made by @Eng1n33r(first implementation in Q2 2022) & @xMaste
|
||||
- CAME Atomo -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- Nice Flor S -> How to create new remote - [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: Nano#8998)]
|
||||
- Keeloq: BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)] -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- Keeloq: BFT Mitto -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- Star Line
|
||||
- Security+ v1 & v2 (encoders was made in OFW)
|
||||
|
||||
@@ -134,7 +134,8 @@ You can support us by using links or addresses below:
|
||||
|
||||
### Community apps included:
|
||||
|
||||
- **RFID Fuzzer** [(by Ganapati & @xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/54) & New protocols by @mvanzanten
|
||||
- **RFID Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/unleashed-firmware/pull/507) (original by Ganapati & xMasterX)
|
||||
- **iButton Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/unleashed-firmware/pull/507) (original by xMasterX)
|
||||
- **Sub-GHz bruteforcer** [(by @derskythe & xMasterX)](https://github.com/derskythe/flipperzero-subbrute) [(original by Ganapati & xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/57)
|
||||
- **Sub-GHz playlist** [(by darmiel)](https://github.com/DarkFlippers/unleashed-firmware/pull/62)
|
||||
- ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module)
|
||||
@@ -157,7 +158,6 @@ You can support us by using links or addresses below:
|
||||
- Morse Code [(by wh00hw)](https://github.com/wh00hw/MorseCodeFAP)
|
||||
- **Unitemp - Temperature sensors reader** (DHT11/22, DS18B20, BMP280, HTU21x and more) [(by quen0n)](https://github.com/quen0n/unitemp-flipperzero)
|
||||
- BH1750 - Lightmeter [(by oleksiikutuzov)](https://github.com/oleksiikutuzov/flipperzero-lightmeter)
|
||||
- **iButton Fuzzer** [(by xMasterX)](https://github.com/xMasterX/ibutton-fuzzer)
|
||||
- HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipper-zero-hex-viewer)
|
||||
- POCSAG Pager [(by xMasterX & Shmuma)](https://github.com/xMasterX/flipper-pager)
|
||||
- Text Viewer [(by kowalski7cc & kyhwana)](https://github.com/kowalski7cc/flipper-zero-text-viewer/tree/refactor-text-app)
|
||||
|
||||
@@ -171,7 +171,7 @@ distenv.Depends(firmware_env["FW_RESOURCES"], external_apps_artifacts.resources_
|
||||
|
||||
fap_deploy = distenv.PhonyTarget(
|
||||
"fap_deploy",
|
||||
"${PYTHON3} ${ROOT_DIR}/scripts/storage.py send ${SOURCE} /ext/apps",
|
||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send ${SOURCE} /ext/apps",
|
||||
source=Dir("#/assets/resources/apps"),
|
||||
)
|
||||
|
||||
@@ -323,7 +323,9 @@ distenv.PhonyTarget(
|
||||
)
|
||||
|
||||
# Start Flipper CLI via PySerial's miniterm
|
||||
distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py")
|
||||
distenv.PhonyTarget(
|
||||
"cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}"
|
||||
)
|
||||
|
||||
|
||||
# Find blackmagic probe
|
||||
|
||||
@@ -399,7 +399,7 @@ int32_t arkanoid_game_app(void* p) {
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
|
||||
4
applications/external/blackjack/blackjack.c
vendored
@@ -276,7 +276,7 @@ void dealer_tick(GameState* game_state) {
|
||||
|
||||
if(dealer_score >= DEALER_MAX) {
|
||||
if(dealer_score > 21 || dealer_score < player_score) {
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
dolphin_deed(DolphinDeedPluginGameWin);
|
||||
enqueue(
|
||||
&(game_state->queue_state),
|
||||
game_state,
|
||||
@@ -571,7 +571,7 @@ int32_t blackjack_app(void* p) {
|
||||
AppEvent event;
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
@@ -383,7 +383,7 @@ int32_t bomberduck_app(void* p) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
// Создаем новый view port
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
// Создаем callback отрисовки, без контекста
|
||||
@@ -458,7 +458,7 @@ int32_t bomberduck_app(void* p) {
|
||||
world.running = 0;
|
||||
world.level += 1;
|
||||
if(world.level % 5 == 0) {
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
dolphin_deed(DolphinDeedPluginGameWin);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < world.bombs_count; i++) {
|
||||
|
||||
2
applications/external/doom/doom.c
vendored
@@ -991,7 +991,7 @@ int32_t doom_app() {
|
||||
music_player_worker_start(plugin_state->music_instance->worker);
|
||||
#endif
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
@@ -309,7 +309,7 @@ int32_t flappy_game_app(void* p) {
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
|
||||
8
applications/external/flipfrid/LICENSE.md
vendored
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* @G4N4P4T1 wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
36
applications/external/flipfrid/README.md
vendored
@@ -1,36 +0,0 @@
|
||||
# Flipfrid
|
||||
|
||||
Basic LFRFID Fuzzer.
|
||||
|
||||
## Why
|
||||
|
||||
Flipfrid is a simple Rfid fuzzer using lfrfid protocols (125khz).
|
||||
Objective is to provide a simple to use fuzzer to test readers by emulating various cards.
|
||||
|
||||
- EM4100 cards use a 1 byte customer id and 4 bytes card id.
|
||||
- HIDProx cards use a 2 byte customer id and 3 byte card id.
|
||||
|
||||
## How
|
||||
|
||||
1) Select the Protocol with the left and right arrows
|
||||
2) Select the Mode with the up and down arrows
|
||||
3) Set TD (Time delay) between ID switch if you need, or left it as is
|
||||
4) Click Start
|
||||
|
||||
### Info
|
||||
|
||||
There are 4 Protocols:
|
||||
- EM4100
|
||||
- HIDProx
|
||||
- PAC/Stanley
|
||||
- H10301
|
||||
|
||||
There are 4 modes:
|
||||
- Default Values: Try factory/default keys and emulate one after the other.
|
||||
- BF customer id: An iteration from 0X00 to 0XFF on the first byte.
|
||||
- Load Dump file: Load an existing dump (.rfid) generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF;
|
||||
- Uids list: Iterate over an input text file (one uid per line) and emulate one after the other.
|
||||
|
||||
|
||||
TODO :
|
||||
- Add second byte test to `BF customer id`
|
||||
12
applications/external/flipfrid/application.fam
vendored
@@ -1,12 +0,0 @@
|
||||
App(
|
||||
appid="rfid_fuzzer",
|
||||
name="RFID Fuzzer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flipfrid_start",
|
||||
requires=["gui", "storage", "dialogs", "input", "notification"],
|
||||
stack_size=2 * 1024,
|
||||
order=15,
|
||||
fap_icon="rfid_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
276
applications/external/flipfrid/flipfrid.c
vendored
@@ -1,276 +0,0 @@
|
||||
#include "flipfrid.h"
|
||||
|
||||
#include "scene/flipfrid_scene_entrypoint.h"
|
||||
#include "scene/flipfrid_scene_load_file.h"
|
||||
#include "scene/flipfrid_scene_select_field.h"
|
||||
#include "scene/flipfrid_scene_run_attack.h"
|
||||
#include "scene/flipfrid_scene_load_custom_uids.h"
|
||||
|
||||
#define RFIDFUZZER_APP_FOLDER "/ext/rfidfuzzer"
|
||||
|
||||
static void flipfrid_draw_callback(Canvas* const canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
FlipFridState* flipfrid_state = ctx;
|
||||
furi_mutex_acquire(flipfrid_state->mutex, FuriWaitForever);
|
||||
|
||||
// Draw correct Canvas
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
}
|
||||
|
||||
furi_mutex_release(flipfrid_state->mutex);
|
||||
}
|
||||
|
||||
void flipfrid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
FlipFridEvent event = {
|
||||
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
|
||||
furi_message_queue_put(event_queue, &event, 25);
|
||||
}
|
||||
|
||||
static void flipfrid_timer_callback(FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
FlipFridEvent event = {
|
||||
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
|
||||
furi_message_queue_put(event_queue, &event, 25);
|
||||
}
|
||||
|
||||
FlipFridState* flipfrid_alloc() {
|
||||
FlipFridState* flipfrid = malloc(sizeof(FlipFridState));
|
||||
flipfrid->notification_msg = furi_string_alloc();
|
||||
flipfrid->attack_name = furi_string_alloc();
|
||||
flipfrid->proto_name = furi_string_alloc();
|
||||
flipfrid->data_str = furi_string_alloc();
|
||||
|
||||
flipfrid->main_menu_items[0] = furi_string_alloc_set("Default Values");
|
||||
flipfrid->main_menu_items[1] = furi_string_alloc_set("BF Customer ID");
|
||||
flipfrid->main_menu_items[2] = furi_string_alloc_set("Load File");
|
||||
flipfrid->main_menu_items[3] = furi_string_alloc_set("Load UIDs from file");
|
||||
|
||||
flipfrid->main_menu_proto_items[0] = furi_string_alloc_set("EM4100");
|
||||
flipfrid->main_menu_proto_items[1] = furi_string_alloc_set("HIDProx");
|
||||
flipfrid->main_menu_proto_items[2] = furi_string_alloc_set("PAC/Stanley");
|
||||
flipfrid->main_menu_proto_items[3] = furi_string_alloc_set("H10301");
|
||||
|
||||
flipfrid->previous_scene = NoneScene;
|
||||
flipfrid->current_scene = SceneEntryPoint;
|
||||
flipfrid->is_running = true;
|
||||
flipfrid->is_attacking = false;
|
||||
flipfrid->key_index = 0;
|
||||
flipfrid->menu_index = 0;
|
||||
flipfrid->menu_proto_index = 0;
|
||||
|
||||
flipfrid->attack = FlipFridAttackDefaultValues;
|
||||
flipfrid->notify = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
flipfrid->data[0] = 0x00;
|
||||
flipfrid->data[1] = 0x00;
|
||||
flipfrid->data[2] = 0x00;
|
||||
flipfrid->data[3] = 0x00;
|
||||
flipfrid->data[4] = 0x00;
|
||||
flipfrid->data[5] = 0x00;
|
||||
|
||||
flipfrid->payload[0] = 0x00;
|
||||
flipfrid->payload[1] = 0x00;
|
||||
flipfrid->payload[2] = 0x00;
|
||||
flipfrid->payload[3] = 0x00;
|
||||
flipfrid->payload[4] = 0x00;
|
||||
flipfrid->payload[5] = 0x00;
|
||||
|
||||
//Dialog
|
||||
flipfrid->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
return flipfrid;
|
||||
}
|
||||
|
||||
void flipfrid_free(FlipFridState* flipfrid) {
|
||||
//Dialog
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
notification_message(flipfrid->notify, &sequence_blink_stop);
|
||||
|
||||
// Strings
|
||||
furi_string_free(flipfrid->notification_msg);
|
||||
furi_string_free(flipfrid->attack_name);
|
||||
furi_string_free(flipfrid->proto_name);
|
||||
furi_string_free(flipfrid->data_str);
|
||||
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(flipfrid->main_menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(flipfrid->main_menu_proto_items[i]);
|
||||
}
|
||||
|
||||
// The rest
|
||||
free(flipfrid);
|
||||
}
|
||||
|
||||
// ENTRYPOINT
|
||||
int32_t flipfrid_start(void* p) {
|
||||
UNUSED(p);
|
||||
// Input
|
||||
FURI_LOG_I(TAG, "Initializing input");
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(FlipFridEvent));
|
||||
FlipFridState* flipfrid_state = flipfrid_alloc();
|
||||
|
||||
flipfrid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(!flipfrid_state->mutex) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
flipfrid_free(flipfrid_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
if(!storage_simply_mkdir(storage, RFIDFUZZER_APP_FOLDER)) {
|
||||
FURI_LOG_E(TAG, "Could not create folder %s", RFIDFUZZER_APP_FOLDER);
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
// Configure view port
|
||||
FURI_LOG_I(TAG, "Initializing viewport");
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, flipfrid_draw_callback, flipfrid_state);
|
||||
view_port_input_callback_set(view_port, flipfrid_input_callback, event_queue);
|
||||
|
||||
// Configure timer
|
||||
FURI_LOG_I(TAG, "Initializing timer");
|
||||
FuriTimer* timer =
|
||||
furi_timer_alloc(flipfrid_timer_callback, FuriTimerTypePeriodic, event_queue);
|
||||
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second
|
||||
|
||||
// Register view port in GUI
|
||||
FURI_LOG_I(TAG, "Initializing gui");
|
||||
Gui* gui = (Gui*)furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Init values
|
||||
FlipFridEvent event;
|
||||
while(flipfrid_state->is_running) {
|
||||
// Get next event
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
//Handle event key
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_event(event, flipfrid_state);
|
||||
break;
|
||||
}
|
||||
|
||||
} else if(event.evt_type == EventTypeTick) {
|
||||
//Handle event tick
|
||||
if(flipfrid_state->current_scene != flipfrid_state->previous_scene) {
|
||||
// Trigger Exit Scene
|
||||
switch(flipfrid_state->previous_scene) {
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_exit(flipfrid_state);
|
||||
break;
|
||||
case NoneScene:
|
||||
break;
|
||||
}
|
||||
|
||||
// Trigger Entry Scene
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_enter(flipfrid_state);
|
||||
break;
|
||||
}
|
||||
flipfrid_state->previous_scene = flipfrid_state->current_scene;
|
||||
}
|
||||
|
||||
// Trigger Tick Scene
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_tick(flipfrid_state);
|
||||
break;
|
||||
}
|
||||
view_port_update(view_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
furi_timer_stop(timer);
|
||||
furi_timer_free(timer);
|
||||
|
||||
FURI_LOG_I(TAG, "Cleaning up");
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_mutex_free(flipfrid_state->mutex);
|
||||
flipfrid_free(flipfrid_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
applications/external/flipfrid/flipfrid.h
vendored
@@ -1,94 +0,0 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <input/input.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <toolbox/stream/string_stream.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
|
||||
#include <rfid_fuzzer_icons.h>
|
||||
|
||||
#include <lib/lfrfid/lfrfid_worker.h>
|
||||
#include <lfrfid/protocols/lfrfid_protocols.h>
|
||||
|
||||
#define TAG "FlipFrid"
|
||||
|
||||
typedef enum {
|
||||
FlipFridAttackDefaultValues,
|
||||
FlipFridAttackBfCustomerId,
|
||||
FlipFridAttackLoadFile,
|
||||
FlipFridAttackLoadFileCustomUids,
|
||||
} FlipFridAttacks;
|
||||
|
||||
typedef enum {
|
||||
EM4100,
|
||||
HIDProx,
|
||||
PAC,
|
||||
H10301,
|
||||
} FlipFridProtos;
|
||||
|
||||
typedef enum {
|
||||
NoneScene,
|
||||
SceneEntryPoint,
|
||||
SceneSelectFile,
|
||||
SceneSelectField,
|
||||
SceneAttack,
|
||||
SceneLoadCustomUids,
|
||||
} FlipFridScene;
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
EventType evt_type;
|
||||
InputKey key;
|
||||
InputType input_type;
|
||||
} FlipFridEvent;
|
||||
|
||||
// STRUCTS
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
bool is_running;
|
||||
bool is_attacking;
|
||||
FlipFridScene current_scene;
|
||||
FlipFridScene previous_scene;
|
||||
NotificationApp* notify;
|
||||
u_int8_t menu_index;
|
||||
u_int8_t menu_proto_index;
|
||||
|
||||
FuriString* data_str;
|
||||
uint8_t data[6];
|
||||
uint8_t payload[6];
|
||||
uint8_t attack_step;
|
||||
FlipFridAttacks attack;
|
||||
FlipFridProtos proto;
|
||||
FuriString* attack_name;
|
||||
FuriString* proto_name;
|
||||
FuriString* main_menu_items[4];
|
||||
FuriString* main_menu_proto_items[4];
|
||||
|
||||
DialogsApp* dialogs;
|
||||
FuriString* notification_msg;
|
||||
uint8_t key_index;
|
||||
LFRFIDWorker* worker;
|
||||
ProtocolDict* dict;
|
||||
ProtocolId protocol;
|
||||
bool workr_rund;
|
||||
bool attack_stop_called;
|
||||
|
||||
uint8_t time_between_cards;
|
||||
|
||||
// Used for custom dictionnary
|
||||
Stream* uids_stream;
|
||||
} FlipFridState;
|
||||
@@ -1,201 +0,0 @@
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
void flipfrid_scene_entrypoint_menu_callback(
|
||||
FlipFridState* context,
|
||||
uint32_t index,
|
||||
uint32_t proto_index) {
|
||||
switch(index) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
context->attack = FlipFridAttackDefaultValues;
|
||||
context->current_scene = SceneAttack;
|
||||
furi_string_set(context->attack_name, "Default Values");
|
||||
break;
|
||||
case FlipFridAttackBfCustomerId:
|
||||
context->attack = FlipFridAttackBfCustomerId;
|
||||
context->current_scene = SceneAttack;
|
||||
furi_string_set(context->attack_name, "Bad Customer ID");
|
||||
break;
|
||||
case FlipFridAttackLoadFile:
|
||||
context->attack = FlipFridAttackLoadFile;
|
||||
context->current_scene = SceneSelectFile;
|
||||
furi_string_set(context->attack_name, "Load File");
|
||||
break;
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
context->attack = FlipFridAttackLoadFileCustomUids;
|
||||
context->current_scene = SceneLoadCustomUids;
|
||||
furi_string_set(context->attack_name, "Load Custom UIDs");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(proto_index) {
|
||||
case EM4100:
|
||||
context->proto = EM4100;
|
||||
furi_string_set(context->proto_name, "EM4100");
|
||||
break;
|
||||
case HIDProx:
|
||||
context->proto = HIDProx;
|
||||
furi_string_set(context->proto_name, "HIDProx");
|
||||
break;
|
||||
case PAC:
|
||||
context->proto = PAC;
|
||||
furi_string_set(context->proto_name, "PAC/Stanley");
|
||||
break;
|
||||
case H10301:
|
||||
context->proto = H10301;
|
||||
furi_string_set(context->proto_name, "H10301");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
|
||||
// Clear the previous payload
|
||||
context->payload[0] = 0x00;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
context->payload[5] = 0x00;
|
||||
|
||||
context->menu_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
context->menu_proto_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_proto_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||
context->menu_index++;
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
context->menu_index--;
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
context->menu_proto_index--;
|
||||
} else if(context->menu_proto_index == EM4100) {
|
||||
context->menu_proto_index = H10301;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->menu_proto_index < H10301) {
|
||||
context->menu_proto_index++;
|
||||
} else if(context->menu_proto_index == H10301) {
|
||||
context->menu_proto_index = EM4100;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
flipfrid_scene_entrypoint_menu_callback(
|
||||
context, context->menu_index, context->menu_proto_index);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(context->main_menu_items != NULL) {
|
||||
if(context->main_menu_items[context->menu_index] != NULL) {
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index]));
|
||||
|
||||
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_proto_items[context->menu_proto_index]));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
if(context->menu_proto_index < H10301) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
@@ -1,85 +0,0 @@
|
||||
#include "flipfrid_scene_load_custom_uids.h"
|
||||
#include "flipfrid_scene_run_attack.h"
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
#define LFRFID_UIDS_EXTENSION ".txt"
|
||||
#define RFIDFUZZER_APP_PATH_FOLDER "/ext/rfidfuzzer"
|
||||
|
||||
bool flipfrid_load_uids(FlipFridState* context, const char* file_path) {
|
||||
bool result = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
context->uids_stream = buffered_file_stream_alloc(storage);
|
||||
result =
|
||||
buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
// Close if loading fails
|
||||
if(!result) {
|
||||
buffered_file_stream_close(context->uids_stream);
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool flipfrid_load_custom_uids_from_file(FlipFridState* context) {
|
||||
// Input events and views are managed by file_select
|
||||
FuriString* uid_path;
|
||||
uid_path = furi_string_alloc();
|
||||
furi_string_set(uid_path, RFIDFUZZER_APP_PATH_FOLDER);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, LFRFID_UIDS_EXTENSION, &I_125_10px);
|
||||
browser_options.base_path = RFIDFUZZER_APP_PATH_FOLDER;
|
||||
browser_options.hide_ext = false;
|
||||
|
||||
bool res = dialog_file_browser_show(context->dialogs, uid_path, uid_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
res = flipfrid_load_uids(context, furi_string_get_cstr(uid_path));
|
||||
}
|
||||
|
||||
furi_string_free(uid_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context) {
|
||||
if(flipfrid_load_custom_uids_from_file(context)) {
|
||||
// Force context loading
|
||||
flipfrid_scene_run_attack_on_enter(context);
|
||||
context->current_scene = SceneAttack;
|
||||
} else {
|
||||
flipfrid_scene_entrypoint_on_enter(context);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
case InputKeyOk:
|
||||
case InputKeyBack:
|
||||
context->current_scene = SceneEntryPoint;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
bool flipfrid_load_custom_uids_from_file(FlipFridState* context);
|
||||
@@ -1,193 +0,0 @@
|
||||
#include "flipfrid_scene_load_file.h"
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
#define LFRFID_APP_EXTENSION ".rfid"
|
||||
#define LFRFID_APP_PATH_FOLDER "/ext/lfrfid"
|
||||
|
||||
bool flipfrid_load(FlipFridState* context, const char* file_path) {
|
||||
bool result = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
FuriString* temp_str;
|
||||
temp_str = furi_string_alloc();
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Error open file %s", file_path);
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Error open file");
|
||||
break;
|
||||
}
|
||||
|
||||
// FileType
|
||||
if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Filetype");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Filetypes");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Filetype: %s", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
// Key type
|
||||
if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Key type");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key type: %s", furi_string_get_cstr(temp_str));
|
||||
|
||||
if(context->proto == EM4100) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "EM4100") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == PAC) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "PAC/Stanley") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == H10301) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "H10301") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "HIDProx") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Data
|
||||
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Data");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Key");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
|
||||
|
||||
if(context->proto == EM4100) {
|
||||
if(furi_string_size(context->data_str) != 14) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == PAC) {
|
||||
if(furi_string_size(context->data_str) != 11) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == H10301) {
|
||||
if(furi_string_size(context->data_str) != 8) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(furi_string_size(context->data_str) != 17) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 6; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
|
||||
temp_str2[2] = '\0';
|
||||
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
} while(0);
|
||||
furi_string_free(temp_str);
|
||||
flipper_format_free(fff_data_file);
|
||||
if(result) {
|
||||
FURI_LOG_I(TAG, "Loaded successfully");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Source loaded.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_enter(FlipFridState* context) {
|
||||
if(flipfrid_load_protocol_from_file(context)) {
|
||||
context->current_scene = SceneSelectField;
|
||||
} else {
|
||||
flipfrid_scene_entrypoint_on_enter(context);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
case InputKeyOk:
|
||||
case InputKeyBack:
|
||||
context->current_scene = SceneEntryPoint;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
|
||||
bool flipfrid_load_protocol_from_file(FlipFridState* context) {
|
||||
FuriString* user_file_path;
|
||||
user_file_path = furi_string_alloc();
|
||||
furi_string_set(user_file_path, LFRFID_APP_PATH_FOLDER);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px);
|
||||
browser_options.base_path = LFRFID_APP_PATH_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
bool res = dialog_file_browser_show(
|
||||
context->dialogs, user_file_path, user_file_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
res = flipfrid_load(context, furi_string_get_cstr(user_file_path));
|
||||
}
|
||||
|
||||
furi_string_free(user_file_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_load_file_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
bool flipfrid_load_protocol_from_file(FlipFridState* context);
|
||||
@@ -1,666 +0,0 @@
|
||||
#include "flipfrid_scene_run_attack.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
uint8_t counter = 0;
|
||||
|
||||
uint8_t id_list[17][5] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha
|
||||
{0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha
|
||||
{0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
uint8_t id_list_hid[14][6] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, // Incremental UID
|
||||
{0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
uint8_t id_list_pac[17][4] = {
|
||||
{0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d}, // From arha
|
||||
{0x34, 0x00, 0x29, 0x3d}, // From arha
|
||||
{0x04, 0xdf, 0x00, 0x00}, // From arha
|
||||
{0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
uint8_t id_list_h[14][3] = {
|
||||
{0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56}, // Incremental UID
|
||||
{0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
void flipfrid_scene_run_attack_on_enter(FlipFridState* context) {
|
||||
context->time_between_cards = 10;
|
||||
context->attack_step = 0;
|
||||
context->attack_stop_called = false;
|
||||
context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
context->worker = lfrfid_worker_alloc(context->dict);
|
||||
if(context->proto == HIDProx) {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx");
|
||||
} else if(context->proto == PAC) {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "PAC/Stanley");
|
||||
} else if(context->proto == H10301) {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "H10301");
|
||||
} else {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100");
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_exit(FlipFridState* context) {
|
||||
if(context->workr_rund) {
|
||||
lfrfid_worker_stop(context->worker);
|
||||
lfrfid_worker_stop_thread(context->worker);
|
||||
context->workr_rund = false;
|
||||
}
|
||||
lfrfid_worker_free(context->worker);
|
||||
protocol_dict_free(context->dict);
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_tick(FlipFridState* context) {
|
||||
if(context->is_attacking) {
|
||||
if(1 == counter) {
|
||||
protocol_dict_set_data(context->dict, context->protocol, context->payload, 6);
|
||||
lfrfid_worker_free(context->worker);
|
||||
context->worker = lfrfid_worker_alloc(context->dict);
|
||||
lfrfid_worker_start_thread(context->worker);
|
||||
lfrfid_worker_emulate_start(context->worker, context->protocol);
|
||||
context->workr_rund = true;
|
||||
} else if(0 == counter) {
|
||||
if(context->workr_rund) {
|
||||
lfrfid_worker_stop(context->worker);
|
||||
lfrfid_worker_stop_thread(context->worker);
|
||||
context->workr_rund = false;
|
||||
furi_delay_ms(200);
|
||||
}
|
||||
switch(context->attack) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = id_list[context->attack_step][0];
|
||||
context->payload[1] = id_list[context->attack_step][1];
|
||||
context->payload[2] = id_list[context->attack_step][2];
|
||||
context->payload[3] = id_list[context->attack_step][3];
|
||||
context->payload[4] = id_list[context->attack_step][4];
|
||||
|
||||
if(context->attack_step == 16) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
context->payload[0] = id_list_pac[context->attack_step][0];
|
||||
context->payload[1] = id_list_pac[context->attack_step][1];
|
||||
context->payload[2] = id_list_pac[context->attack_step][2];
|
||||
context->payload[3] = id_list_pac[context->attack_step][3];
|
||||
|
||||
if(context->attack_step == 16) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
context->payload[0] = id_list_h[context->attack_step][0];
|
||||
context->payload[1] = id_list_h[context->attack_step][1];
|
||||
context->payload[2] = id_list_h[context->attack_step][2];
|
||||
|
||||
if(context->attack_step == 13) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = id_list_hid[context->attack_step][0];
|
||||
context->payload[1] = id_list_hid[context->attack_step][1];
|
||||
context->payload[2] = id_list_hid[context->attack_step][2];
|
||||
context->payload[3] = id_list_hid[context->attack_step][3];
|
||||
context->payload[4] = id_list_hid[context->attack_step][4];
|
||||
context->payload[5] = id_list_hid[context->attack_step][5];
|
||||
|
||||
if(context->attack_step == 13) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipFridAttackBfCustomerId:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
context->payload[5] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipFridAttackLoadFile:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
context->payload[5] = context->data[5];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
if(context->proto == EM4100) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 11) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 11) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 9) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 9) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 7) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 7) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 13) break;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(end_of_list) break;
|
||||
if(furi_string_size(context->data_str) != 13) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 6; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(counter > context->time_between_cards) {
|
||||
counter = 0;
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards > 5) {
|
||||
context->time_between_cards--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards < 70) {
|
||||
context->time_between_cards++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
counter = 0;
|
||||
if(!context->is_attacking) {
|
||||
notification_message(context->notify, &sequence_blink_start_blue);
|
||||
context->is_attacking = true;
|
||||
} else {
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_attacking = false;
|
||||
counter = 0;
|
||||
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
if(context->attack_stop_called) {
|
||||
context->attack_stop_called = false;
|
||||
context->attack_step = 0;
|
||||
if(context->attack == FlipFridAttackLoadFileCustomUids) {
|
||||
furi_string_reset(context->data_str);
|
||||
stream_rewind(context->uids_stream);
|
||||
buffered_file_stream_close(context->uids_stream);
|
||||
}
|
||||
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
|
||||
context->attack_stop_called = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(event.input_type == InputTypeLong) {
|
||||
switch(event.key) {
|
||||
case InputKeyLeft:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards > 0) {
|
||||
if((context->time_between_cards - 10) > 5) {
|
||||
context->time_between_cards -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards < 70) {
|
||||
context->time_between_cards += 10;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 2, AlignCenter, AlignTop, furi_string_get_cstr(context->attack_name));
|
||||
|
||||
char uid[18];
|
||||
char speed[16];
|
||||
if(context->proto == HIDProx) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4],
|
||||
context->payload[5]);
|
||||
} else if(context->proto == PAC) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3]);
|
||||
} else if(context->proto == H10301) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2]);
|
||||
} else {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4]);
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignTop, uid);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 26, AlignCenter, AlignTop, furi_string_get_cstr(context->proto_name));
|
||||
|
||||
snprintf(speed, sizeof(speed), "Time delay: %d", context->time_between_cards);
|
||||
|
||||
//canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, "Speed:");
|
||||
canvas_draw_str_aligned(canvas, 64, 14, AlignCenter, AlignTop, speed);
|
||||
//char start_stop_msg[20];
|
||||
if(context->is_attacking) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
//snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
|
||||
} else {
|
||||
elements_button_center(canvas, "Start");
|
||||
elements_button_left(canvas, "TD -");
|
||||
elements_button_right(canvas, "+ TD");
|
||||
}
|
||||
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_run_attack_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
@@ -1,160 +0,0 @@
|
||||
#include "flipfrid_scene_select_field.h"
|
||||
|
||||
void flipfrid_center_displayed_key(FlipFridState* context, uint8_t index) {
|
||||
char key_cstr[18];
|
||||
uint8_t key_len = 18;
|
||||
uint8_t str_index = (index * 3);
|
||||
int data_len = sizeof(context->data) / sizeof(context->data[0]);
|
||||
int key_index = 0;
|
||||
|
||||
if(context->proto == EM4100) {
|
||||
key_len = 16;
|
||||
}
|
||||
if(context->proto == PAC) {
|
||||
key_len = 13;
|
||||
}
|
||||
if(context->proto == H10301) {
|
||||
key_len = 10;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->data[i] < 9) {
|
||||
key_index +=
|
||||
snprintf(&key_cstr[key_index], key_len - key_index, "0%X ", context->data[i]);
|
||||
} else {
|
||||
key_index +=
|
||||
snprintf(&key_cstr[key_index], key_len - key_index, "%X ", context->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char display_menu[17] = {
|
||||
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
|
||||
|
||||
if(index > 1) {
|
||||
display_menu[0] = key_cstr[str_index - 6];
|
||||
display_menu[1] = key_cstr[str_index - 5];
|
||||
} else {
|
||||
display_menu[0] = ' ';
|
||||
display_menu[1] = ' ';
|
||||
}
|
||||
|
||||
if(index > 0) {
|
||||
display_menu[3] = key_cstr[str_index - 3];
|
||||
display_menu[4] = key_cstr[str_index - 2];
|
||||
} else {
|
||||
display_menu[3] = ' ';
|
||||
display_menu[4] = ' ';
|
||||
}
|
||||
|
||||
display_menu[7] = key_cstr[str_index];
|
||||
display_menu[8] = key_cstr[str_index + 1];
|
||||
|
||||
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[11] = key_cstr[str_index + 3];
|
||||
display_menu[12] = key_cstr[str_index + 4];
|
||||
} else {
|
||||
display_menu[11] = ' ';
|
||||
display_menu[12] = ' ';
|
||||
}
|
||||
|
||||
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[14] = key_cstr[str_index + 6];
|
||||
display_menu[15] = key_cstr[str_index + 7];
|
||||
} else {
|
||||
display_menu[14] = ' ';
|
||||
display_menu[15] = ' ';
|
||||
}
|
||||
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, display_menu);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_enter(FlipFridState* context) {
|
||||
furi_string_reset(context->notification_msg);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
const char* key_cstr = furi_string_get_cstr(context->data_str);
|
||||
int data_len = sizeof(context->data) / sizeof(context->data[0]);
|
||||
|
||||
// don't look, it's ugly but I'm a python dev so...
|
||||
uint8_t nb_bytes = 0;
|
||||
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
|
||||
if(' ' == key_cstr[i]) {
|
||||
nb_bytes++;
|
||||
}
|
||||
}
|
||||
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->key_index == i) {
|
||||
context->data[i] = (context->data[i] - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->key_index == i) {
|
||||
context->data[i] = (context->data[i] + 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->key_index > 0) {
|
||||
context->key_index = context->key_index - 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->key_index < nb_bytes) {
|
||||
context->key_index = context->key_index + 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->key_index = 0;
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneSelectFile;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 12, 5, AlignLeft, AlignTop, "Left and right: select byte");
|
||||
canvas_draw_str_aligned(canvas, 12, 15, AlignLeft, AlignTop, "Up and down: adjust byte");
|
||||
|
||||
char msg_index[18];
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
|
||||
canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignTop, msg_index);
|
||||
|
||||
flipfrid_center_displayed_key(context, context->key_index);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 45, AlignCenter, AlignTop, furi_string_get_cstr(context->notification_msg));
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_select_field_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
void center_displayed_key(FlipFridState* context, uint8_t index);
|
||||
2
applications/external/game15/game15.c
vendored
@@ -464,7 +464,7 @@ int32_t game15_app() {
|
||||
FPS, (SandboxRenderCallback)render_callback, (SandboxEventHandler)game_event_handler);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
sandbox_loop();
|
||||
sandbox_free();
|
||||
|
||||
2
applications/external/game_2048/game_2048.c
vendored
@@ -401,7 +401,7 @@ int32_t game_2048_app() {
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
bool is_finished = false;
|
||||
while(!is_finished) {
|
||||
|
||||
@@ -535,7 +535,7 @@ int32_t heap_defence_app(void* p) {
|
||||
game->animation = AnimationPause;
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event = {0};
|
||||
while(event.input.key != InputKeyBack) {
|
||||
|
||||
4
applications/external/hid_app/hid.c
vendored
@@ -414,7 +414,7 @@ int32_t hid_usb_app(void* p) {
|
||||
|
||||
bt_hid_connection_status_changed_callback(BtStatusConnected, app);
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedPluginStart);
|
||||
dolphin_deed(DolphinDeedPluginStart);
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
@@ -454,7 +454,7 @@ int32_t hid_ble_app(void* p) {
|
||||
furi_hal_bt_start_advertising();
|
||||
bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app);
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedPluginStart);
|
||||
dolphin_deed(DolphinDeedPluginStart);
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
|
||||
8
applications/external/ibtn_fuzzer/LICENSE.md
vendored
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* @xMasterX and @G4N4P4T1(made original version) wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1,12 +0,0 @@
|
||||
App(
|
||||
appid="ibtn_fuzzer",
|
||||
name="iButton Fuzzer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="ibtnfuzzer_start",
|
||||
requires=["gui", "storage", "dialogs", "input", "notification"],
|
||||
stack_size=1 * 1024,
|
||||
order=15,
|
||||
fap_icon="ibutt_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
280
applications/external/ibtn_fuzzer/ibtnfuzzer.c
vendored
@@ -1,280 +0,0 @@
|
||||
#include "ibtnfuzzer.h"
|
||||
|
||||
#include "scene/ibtnfuzzer_scene_entrypoint.h"
|
||||
#include "scene/ibtnfuzzer_scene_load_file.h"
|
||||
#include "scene/ibtnfuzzer_scene_select_field.h"
|
||||
#include "scene/ibtnfuzzer_scene_run_attack.h"
|
||||
#include "scene/ibtnfuzzer_scene_load_custom_uids.h"
|
||||
|
||||
#define IBTNFUZZER_APP_FOLDER "/ext/ibtnfuzzer"
|
||||
|
||||
static void ibtnfuzzer_draw_callback(Canvas* const canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
iBtnFuzzerState* ibtnfuzzer_state = ctx;
|
||||
furi_mutex_acquire(ibtnfuzzer_state->mutex, FuriWaitForever);
|
||||
|
||||
// Draw correct Canvas
|
||||
switch(ibtnfuzzer_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
ibtnfuzzer_scene_entrypoint_on_draw(canvas, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
ibtnfuzzer_scene_load_file_on_draw(canvas, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
ibtnfuzzer_scene_select_field_on_draw(canvas, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
ibtnfuzzer_scene_run_attack_on_draw(canvas, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
ibtnfuzzer_scene_load_custom_uids_on_draw(canvas, ibtnfuzzer_state);
|
||||
break;
|
||||
}
|
||||
|
||||
furi_mutex_release(ibtnfuzzer_state->mutex);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
iBtnFuzzerEvent event = {
|
||||
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
|
||||
furi_message_queue_put(event_queue, &event, 25);
|
||||
}
|
||||
|
||||
static void ibtnfuzzer_timer_callback(FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
iBtnFuzzerEvent event = {
|
||||
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
|
||||
furi_message_queue_put(event_queue, &event, 25);
|
||||
}
|
||||
|
||||
iBtnFuzzerState* ibtnfuzzer_alloc() {
|
||||
iBtnFuzzerState* ibtnfuzzer = malloc(sizeof(iBtnFuzzerState));
|
||||
ibtnfuzzer->notification_msg = furi_string_alloc();
|
||||
ibtnfuzzer->attack_name = furi_string_alloc();
|
||||
ibtnfuzzer->proto_name = furi_string_alloc();
|
||||
ibtnfuzzer->data_str = furi_string_alloc();
|
||||
|
||||
ibtnfuzzer->main_menu_items[0] = furi_string_alloc_set("Default Values");
|
||||
ibtnfuzzer->main_menu_items[1] = furi_string_alloc_set("Load File");
|
||||
ibtnfuzzer->main_menu_items[2] = furi_string_alloc_set("Load UIDs from file");
|
||||
|
||||
ibtnfuzzer->main_menu_proto_items[0] = furi_string_alloc_set("DS1990");
|
||||
ibtnfuzzer->main_menu_proto_items[1] = furi_string_alloc_set("Metakom");
|
||||
ibtnfuzzer->main_menu_proto_items[2] = furi_string_alloc_set("Cyfral");
|
||||
|
||||
ibtnfuzzer->previous_scene = NoneScene;
|
||||
ibtnfuzzer->current_scene = SceneEntryPoint;
|
||||
ibtnfuzzer->is_running = true;
|
||||
ibtnfuzzer->is_attacking = false;
|
||||
ibtnfuzzer->key_index = 0;
|
||||
ibtnfuzzer->menu_index = 0;
|
||||
ibtnfuzzer->menu_proto_index = 0;
|
||||
|
||||
ibtnfuzzer->attack = iBtnFuzzerAttackDefaultValues;
|
||||
ibtnfuzzer->notify = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
ibtnfuzzer->data[0] = 0x00;
|
||||
ibtnfuzzer->data[1] = 0x00;
|
||||
ibtnfuzzer->data[2] = 0x00;
|
||||
ibtnfuzzer->data[3] = 0x00;
|
||||
ibtnfuzzer->data[4] = 0x00;
|
||||
ibtnfuzzer->data[5] = 0x00;
|
||||
ibtnfuzzer->data[6] = 0x00;
|
||||
ibtnfuzzer->data[7] = 0x00;
|
||||
|
||||
ibtnfuzzer->payload[0] = 0x00;
|
||||
ibtnfuzzer->payload[1] = 0x00;
|
||||
ibtnfuzzer->payload[2] = 0x00;
|
||||
ibtnfuzzer->payload[3] = 0x00;
|
||||
ibtnfuzzer->payload[4] = 0x00;
|
||||
ibtnfuzzer->payload[5] = 0x00;
|
||||
ibtnfuzzer->payload[6] = 0x00;
|
||||
ibtnfuzzer->payload[7] = 0x00;
|
||||
|
||||
//Dialog
|
||||
ibtnfuzzer->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
return ibtnfuzzer;
|
||||
}
|
||||
|
||||
void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) {
|
||||
//Dialog
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
notification_message(ibtnfuzzer->notify, &sequence_blink_stop);
|
||||
|
||||
// Strings
|
||||
furi_string_free(ibtnfuzzer->notification_msg);
|
||||
furi_string_free(ibtnfuzzer->attack_name);
|
||||
furi_string_free(ibtnfuzzer->proto_name);
|
||||
furi_string_free(ibtnfuzzer->data_str);
|
||||
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
furi_string_free(ibtnfuzzer->main_menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
furi_string_free(ibtnfuzzer->main_menu_proto_items[i]);
|
||||
}
|
||||
|
||||
// The rest
|
||||
free(ibtnfuzzer);
|
||||
}
|
||||
|
||||
// ENTRYPOINT
|
||||
int32_t ibtnfuzzer_start(void* p) {
|
||||
UNUSED(p);
|
||||
// Input
|
||||
FURI_LOG_I(TAG, "Initializing input");
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(iBtnFuzzerEvent));
|
||||
iBtnFuzzerState* ibtnfuzzer_state = ibtnfuzzer_alloc();
|
||||
|
||||
ibtnfuzzer_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(!ibtnfuzzer_state->mutex) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
ibtnfuzzer_free(ibtnfuzzer_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
if(!storage_simply_mkdir(storage, IBTNFUZZER_APP_FOLDER)) {
|
||||
FURI_LOG_E(TAG, "Could not create folder %s", IBTNFUZZER_APP_FOLDER);
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
// Configure view port
|
||||
FURI_LOG_I(TAG, "Initializing viewport");
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, ibtnfuzzer_draw_callback, ibtnfuzzer_state);
|
||||
view_port_input_callback_set(view_port, ibtnfuzzer_input_callback, event_queue);
|
||||
|
||||
// Configure timer
|
||||
FURI_LOG_I(TAG, "Initializing timer");
|
||||
FuriTimer* timer =
|
||||
furi_timer_alloc(ibtnfuzzer_timer_callback, FuriTimerTypePeriodic, event_queue);
|
||||
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second
|
||||
|
||||
// Register view port in GUI
|
||||
FURI_LOG_I(TAG, "Initializing gui");
|
||||
Gui* gui = (Gui*)furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Init values
|
||||
iBtnFuzzerEvent event;
|
||||
while(ibtnfuzzer_state->is_running) {
|
||||
// Get next event
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
|
||||
//furi_mutex_acquire(ibtnfuzzer_state->mutex, FuriWaitForever);
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
//Handle event key
|
||||
switch(ibtnfuzzer_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
ibtnfuzzer_scene_entrypoint_on_event(event, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
ibtnfuzzer_scene_load_file_on_event(event, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
ibtnfuzzer_scene_select_field_on_event(event, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
ibtnfuzzer_scene_run_attack_on_event(event, ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
ibtnfuzzer_scene_load_custom_uids_on_event(event, ibtnfuzzer_state);
|
||||
break;
|
||||
}
|
||||
|
||||
} else if(event.evt_type == EventTypeTick) {
|
||||
//Handle event tick
|
||||
if(ibtnfuzzer_state->current_scene != ibtnfuzzer_state->previous_scene) {
|
||||
// Trigger Exit Scene
|
||||
switch(ibtnfuzzer_state->previous_scene) {
|
||||
case SceneEntryPoint:
|
||||
ibtnfuzzer_scene_entrypoint_on_exit(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
ibtnfuzzer_scene_load_file_on_exit(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
ibtnfuzzer_scene_select_field_on_exit(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
ibtnfuzzer_scene_run_attack_on_exit(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
ibtnfuzzer_scene_load_custom_uids_on_exit(ibtnfuzzer_state);
|
||||
break;
|
||||
case NoneScene:
|
||||
break;
|
||||
}
|
||||
|
||||
// Trigger Entry Scene
|
||||
switch(ibtnfuzzer_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
ibtnfuzzer_scene_entrypoint_on_enter(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
ibtnfuzzer_scene_load_file_on_enter(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
ibtnfuzzer_scene_select_field_on_enter(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
ibtnfuzzer_scene_run_attack_on_enter(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
ibtnfuzzer_scene_load_custom_uids_on_enter(ibtnfuzzer_state);
|
||||
break;
|
||||
}
|
||||
ibtnfuzzer_state->previous_scene = ibtnfuzzer_state->current_scene;
|
||||
}
|
||||
|
||||
// Trigger Tick Scene
|
||||
switch(ibtnfuzzer_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
ibtnfuzzer_scene_entrypoint_on_tick(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
ibtnfuzzer_scene_load_file_on_tick(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
ibtnfuzzer_scene_select_field_on_tick(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
ibtnfuzzer_scene_run_attack_on_tick(ibtnfuzzer_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
ibtnfuzzer_scene_load_custom_uids_on_tick(ibtnfuzzer_state);
|
||||
break;
|
||||
}
|
||||
view_port_update(view_port);
|
||||
}
|
||||
}
|
||||
//furi_mutex_release(ibtnfuzzer_state->mutex);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
furi_timer_stop(timer);
|
||||
furi_timer_free(timer);
|
||||
|
||||
FURI_LOG_I(TAG, "Cleaning up");
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_mutex_free(ibtnfuzzer_state->mutex);
|
||||
ibtnfuzzer_free(ibtnfuzzer_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
applications/external/ibtn_fuzzer/ibtnfuzzer.h
vendored
@@ -1,94 +0,0 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <input/input.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <toolbox/stream/string_stream.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
|
||||
#include <ibtn_fuzzer_icons.h>
|
||||
|
||||
#include <lib/ibutton/ibutton_worker.h>
|
||||
#include <lib/ibutton/ibutton_key.h>
|
||||
|
||||
#define TAG "iBtnFuzzer"
|
||||
|
||||
typedef enum {
|
||||
iBtnFuzzerAttackDefaultValues,
|
||||
iBtnFuzzerAttackLoadFile,
|
||||
iBtnFuzzerAttackLoadFileCustomUids,
|
||||
} iBtnFuzzerAttacks;
|
||||
|
||||
typedef enum {
|
||||
DS1990,
|
||||
Metakom,
|
||||
Cyfral,
|
||||
} iBtnFuzzerProtos;
|
||||
|
||||
typedef enum {
|
||||
NoneScene,
|
||||
SceneEntryPoint,
|
||||
SceneSelectFile,
|
||||
SceneSelectField,
|
||||
SceneAttack,
|
||||
SceneLoadCustomUids,
|
||||
} iBtnFuzzerScene;
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
EventType evt_type;
|
||||
InputKey key;
|
||||
InputType input_type;
|
||||
} iBtnFuzzerEvent;
|
||||
|
||||
// STRUCTS
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
bool is_running;
|
||||
bool is_attacking;
|
||||
iBtnFuzzerScene current_scene;
|
||||
iBtnFuzzerScene previous_scene;
|
||||
NotificationApp* notify;
|
||||
u_int8_t menu_index;
|
||||
u_int8_t menu_proto_index;
|
||||
|
||||
FuriString* data_str;
|
||||
uint8_t data[8];
|
||||
uint8_t payload[8];
|
||||
uint8_t attack_step;
|
||||
iBtnFuzzerAttacks attack;
|
||||
iBtnFuzzerProtos proto;
|
||||
FuriString* attack_name;
|
||||
FuriString* proto_name;
|
||||
FuriString* main_menu_items[3];
|
||||
FuriString* main_menu_proto_items[3];
|
||||
|
||||
DialogsApp* dialogs;
|
||||
FuriString* notification_msg;
|
||||
uint8_t key_index;
|
||||
iButtonWorker* worker;
|
||||
iButtonKey* key;
|
||||
iButtonProtocolId keytype;
|
||||
iButtonProtocols* protocols;
|
||||
bool workr_rund;
|
||||
bool enter_rerun;
|
||||
bool attack_stop_called;
|
||||
|
||||
uint8_t time_between_cards;
|
||||
|
||||
// Used for custom dictionnary
|
||||
Stream* uids_stream;
|
||||
} iBtnFuzzerState;
|
||||
|
Before Width: | Height: | Size: 304 B |
@@ -1,201 +0,0 @@
|
||||
#include "ibtnfuzzer_scene_entrypoint.h"
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_menu_callback(
|
||||
iBtnFuzzerState* context,
|
||||
uint32_t index,
|
||||
uint32_t proto_index) {
|
||||
switch(index) {
|
||||
case iBtnFuzzerAttackDefaultValues:
|
||||
context->attack = iBtnFuzzerAttackDefaultValues;
|
||||
context->current_scene = SceneAttack;
|
||||
furi_string_set(context->attack_name, "Default Values");
|
||||
break;
|
||||
case iBtnFuzzerAttackLoadFile:
|
||||
context->attack = iBtnFuzzerAttackLoadFile;
|
||||
context->current_scene = SceneSelectFile;
|
||||
furi_string_set(context->attack_name, "Load File");
|
||||
break;
|
||||
case iBtnFuzzerAttackLoadFileCustomUids:
|
||||
context->attack = iBtnFuzzerAttackLoadFileCustomUids;
|
||||
context->current_scene = SceneLoadCustomUids;
|
||||
furi_string_set(context->attack_name, "Load Custom UIDs");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(proto_index) {
|
||||
case DS1990:
|
||||
context->proto = DS1990;
|
||||
furi_string_set(context->proto_name, "DS1990");
|
||||
break;
|
||||
case Metakom:
|
||||
context->proto = Metakom;
|
||||
furi_string_set(context->proto_name, "Metakom");
|
||||
break;
|
||||
case Cyfral:
|
||||
context->proto = Cyfral;
|
||||
furi_string_set(context->proto_name, "Cyfral");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_enter(iBtnFuzzerState* context) {
|
||||
// Clear the previous payload
|
||||
context->payload[0] = 0x00;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
context->payload[5] = 0x00;
|
||||
context->payload[6] = 0x00;
|
||||
context->payload[7] = 0x00;
|
||||
|
||||
context->menu_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
context->menu_proto_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_proto_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_exit(iBtnFuzzerState* context) {
|
||||
context->enter_rerun = false;
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_tick(iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) {
|
||||
context->menu_index++;
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
if(context->menu_index > iBtnFuzzerAttackDefaultValues) {
|
||||
context->menu_index--;
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->menu_proto_index > DS1990) {
|
||||
context->menu_proto_index--;
|
||||
} else if(context->menu_proto_index == DS1990) {
|
||||
context->menu_proto_index = Cyfral;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->menu_proto_index < Cyfral) {
|
||||
context->menu_proto_index++;
|
||||
} else if(context->menu_proto_index == Cyfral) {
|
||||
context->menu_proto_index = DS1990;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
ibtnfuzzer_scene_entrypoint_menu_callback(
|
||||
context, context->menu_index, context->menu_proto_index);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
|
||||
if(!context->enter_rerun) {
|
||||
ibtnfuzzer_scene_entrypoint_on_enter(context);
|
||||
context->enter_rerun = true;
|
||||
}
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(context->main_menu_items != NULL) {
|
||||
if(context->main_menu_items[context->menu_index] != NULL) {
|
||||
if(context->menu_index > iBtnFuzzerAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index]));
|
||||
|
||||
if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(context->main_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
|
||||
if(context->menu_proto_index > DS1990) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
if(context->main_menu_proto_items[context->menu_proto_index] != NULL) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index]));
|
||||
}
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
if(context->menu_proto_index < Cyfral) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(
|
||||
context->main_menu_proto_items[context->menu_proto_index + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "../ibtnfuzzer.h"
|
||||
|
||||
void ibtnfuzzer_scene_entrypoint_on_enter(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_entrypoint_on_exit(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_entrypoint_on_tick(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_entrypoint_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_entrypoint_on_draw(Canvas* canvas, iBtnFuzzerState* context);
|
||||
@@ -1,86 +0,0 @@
|
||||
#include "ibtnfuzzer_scene_load_custom_uids.h"
|
||||
#include "ibtnfuzzer_scene_run_attack.h"
|
||||
#include "ibtnfuzzer_scene_entrypoint.h"
|
||||
|
||||
#define IBTNFUZZER_UIDS_EXTENSION ".txt"
|
||||
#define IBTNFUZZER_APP_PATH_FOLDER "/ext/ibtnfuzzer"
|
||||
|
||||
bool ibtnfuzzer_load_uids(iBtnFuzzerState* context, const char* file_path) {
|
||||
bool result = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
context->uids_stream = buffered_file_stream_alloc(storage);
|
||||
result =
|
||||
buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
// Close if loading fails
|
||||
if(!result) {
|
||||
buffered_file_stream_close(context->uids_stream);
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ibtnfuzzer_load_custom_uids_from_file(iBtnFuzzerState* context) {
|
||||
// Input events and views are managed by file_select
|
||||
FuriString* uid_path;
|
||||
uid_path = furi_string_alloc();
|
||||
furi_string_set(uid_path, IBTNFUZZER_APP_PATH_FOLDER);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, IBTNFUZZER_UIDS_EXTENSION, &I_ibutt_10px);
|
||||
browser_options.base_path = IBTNFUZZER_APP_PATH_FOLDER;
|
||||
browser_options.hide_ext = false;
|
||||
|
||||
bool res = dialog_file_browser_show(context->dialogs, uid_path, uid_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
res = ibtnfuzzer_load_uids(context, furi_string_get_cstr(uid_path));
|
||||
}
|
||||
|
||||
furi_string_free(uid_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_enter(iBtnFuzzerState* context) {
|
||||
if(ibtnfuzzer_load_custom_uids_from_file(context)) {
|
||||
// Force context loading
|
||||
ibtnfuzzer_scene_run_attack_on_enter(context);
|
||||
context->current_scene = SceneAttack;
|
||||
} else {
|
||||
ibtnfuzzer_scene_entrypoint_on_enter(context);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_exit(iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_tick(iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
case InputKeyOk:
|
||||
case InputKeyBack:
|
||||
context->current_scene = SceneEntryPoint;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../ibtnfuzzer.h"
|
||||
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_enter(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_exit(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_tick(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_custom_uids_on_draw(Canvas* canvas, iBtnFuzzerState* context);
|
||||
bool ibtnfuzzer_load_custom_uids_from_file(iBtnFuzzerState* context);
|
||||
@@ -1,293 +0,0 @@
|
||||
#include "ibtnfuzzer_scene_load_file.h"
|
||||
#include "ibtnfuzzer_scene_entrypoint.h"
|
||||
|
||||
#define IBUTTON_FUZZER_APP_EXTENSION ".ibtn"
|
||||
#define IBUTTON_FUZZER_APP_PATH_FOLDER "/ext/ibutton"
|
||||
|
||||
bool ibtnfuzzer_load(iBtnFuzzerState* context, const char* file_path) {
|
||||
bool result = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
FuriString* temp_str;
|
||||
temp_str = furi_string_alloc();
|
||||
bool key_v2 = false;
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Error open file %s", file_path);
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Error open file");
|
||||
break;
|
||||
}
|
||||
|
||||
// FileType
|
||||
if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Filetype");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Filetypes");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Filetype: %s", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
// Key type
|
||||
if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Key type, checking for typ2..");
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
FURI_LOG_E(TAG, "Failed to rewind file");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(
|
||||
context->notification_msg, "Missing or incorrect Protocol or Key type");
|
||||
break;
|
||||
}
|
||||
FURI_LOG_I(TAG, "Key type V2: %s", furi_string_get_cstr(temp_str));
|
||||
key_v2 = true;
|
||||
|
||||
if(context->proto == DS1990) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "DS1990") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == Cyfral) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "Cyfral") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "Metakom") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key type: %s", furi_string_get_cstr(temp_str));
|
||||
|
||||
if(context->proto == DS1990) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "Dallas") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == Cyfral) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "Cyfral") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "Metakom") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!key_v2) {
|
||||
// Data
|
||||
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Data");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Key");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
|
||||
|
||||
if(context->proto == DS1990) {
|
||||
if(furi_string_size(context->data_str) != 23) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == Cyfral) {
|
||||
if(furi_string_size(context->data_str) != 5) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(furi_string_size(context->data_str) != 11) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
|
||||
temp_str2[2] = '\0';
|
||||
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Data
|
||||
if(context->proto == DS1990) {
|
||||
if(!flipper_format_read_string(fff_data_file, "Rom Data", context->data_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Rom Data");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Rom Data");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
|
||||
|
||||
if(furi_string_size(context->data_str) != 23) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
|
||||
temp_str2[2] = '\0';
|
||||
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
|
||||
}
|
||||
}
|
||||
} else if(context->proto == Cyfral) {
|
||||
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Data");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Data");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
|
||||
|
||||
if(furi_string_size(context->data_str) != 5) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
|
||||
temp_str2[2] = '\0';
|
||||
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Data");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Data");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
|
||||
|
||||
if(furi_string_size(context->data_str) != 11) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
|
||||
temp_str2[2] = '\0';
|
||||
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
} while(0);
|
||||
furi_string_free(temp_str);
|
||||
flipper_format_free(fff_data_file);
|
||||
if(result) {
|
||||
FURI_LOG_I(TAG, "Loaded successfully");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Source loaded.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_file_on_enter(iBtnFuzzerState* context) {
|
||||
if(ibtnfuzzer_load_protocol_from_file(context)) {
|
||||
context->current_scene = SceneSelectField;
|
||||
} else {
|
||||
ibtnfuzzer_scene_entrypoint_on_enter(context);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_file_on_exit(iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_file_on_tick(iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_file_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
case InputKeyOk:
|
||||
case InputKeyBack:
|
||||
context->current_scene = SceneEntryPoint;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_load_file_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
|
||||
bool ibtnfuzzer_load_protocol_from_file(iBtnFuzzerState* context) {
|
||||
FuriString* user_file_path;
|
||||
user_file_path = furi_string_alloc();
|
||||
furi_string_set(user_file_path, IBUTTON_FUZZER_APP_PATH_FOLDER);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, IBUTTON_FUZZER_APP_EXTENSION, &I_ibutt_10px);
|
||||
browser_options.base_path = IBUTTON_FUZZER_APP_PATH_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
bool res = dialog_file_browser_show(
|
||||
context->dialogs, user_file_path, user_file_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
res = ibtnfuzzer_load(context, furi_string_get_cstr(user_file_path));
|
||||
}
|
||||
|
||||
furi_string_free(user_file_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../ibtnfuzzer.h"
|
||||
|
||||
void ibtnfuzzer_scene_load_file_on_enter(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_file_on_exit(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_file_on_tick(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_file_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_load_file_on_draw(Canvas* canvas, iBtnFuzzerState* context);
|
||||
bool ibtnfuzzer_load_protocol_from_file(iBtnFuzzerState* context);
|
||||
@@ -1,501 +0,0 @@
|
||||
#include "ibtnfuzzer_scene_run_attack.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
uint8_t counter = 0;
|
||||
|
||||
uint8_t id_list_ds1990[18][8] = {
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0xE1}, //– код универсального ключа, для Vizit
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x56, 0x00, 0xBB}, //- проверен работает
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x00, 0x00, 0x00, 0x77}, //- проверен работает
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x0A, 0x00, 0x00, 0x1D}, //- проверен работает Визит иногда КЕЙМАНЫ
|
||||
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F}, //- проверен(метаком, цифрал, ВИЗИТ).
|
||||
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x9B}, //- проверен Визит, Метакомы, КОНДОР
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, //???-Открываает 98% Метаком и некоторые Цифрал
|
||||
{0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x19, 0xFF}, //???-Отлично работает на старых домофонах
|
||||
{0x01, 0x6F, 0x2E, 0x88, 0x8A, 0x00, 0x00, 0x4D}, //???-Открывать что-то должен
|
||||
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x7E, 0x88}, //???-Cyfral, Metakom
|
||||
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x00, 0x6F}, //???-домофоны Визит (Vizit) - до 99%
|
||||
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D}, //???-домофоны Cyfral CCD-20 - до 70%
|
||||
{0x01, 0x00, 0xBE, 0x11, 0xAA, 0x00, 0x00, 0xFB}, //???-домофоны Кейман (KEYMAN)
|
||||
{0x01, 0x76, 0xB8, 0x2E, 0x0F, 0x00, 0x00, 0x5C}, //???-домофоны Форвард
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, // Only FF
|
||||
{0x01, 0x78, 0x00, 0x48, 0xFD, 0xFF, 0xFF, 0xD1}, // StarNew Uni5
|
||||
{0x01, 0xA9, 0xE4, 0x3C, 0x09, 0x00, 0x00, 0xE6}, // Eltis Uni
|
||||
};
|
||||
|
||||
uint8_t id_list_metakom[17][4] = {
|
||||
{0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d}, // ??
|
||||
{0x34, 0x00, 0x29, 0x3d}, // ??
|
||||
{0x04, 0xdf, 0x00, 0x00}, // ??
|
||||
{0xCA, 0xCA, 0xCA, 0xCA}, // ??
|
||||
};
|
||||
|
||||
uint8_t id_list_cyfral[16][2] = {
|
||||
{0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34}, // Incremental UID
|
||||
{0x56, 0x34}, // Decremental UID
|
||||
{0xCA, 0xCA}, // ??
|
||||
{0x8E, 0xC9}, // Elevator code
|
||||
{0x6A, 0x50}, // VERY fresh code from smartkey
|
||||
};
|
||||
|
||||
void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context) {
|
||||
context->time_between_cards = 8;
|
||||
context->attack_step = 0;
|
||||
context->attack_stop_called = false;
|
||||
context->protocols = ibutton_protocols_alloc();
|
||||
context->key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(context->protocols));
|
||||
context->worker = ibutton_worker_alloc(context->protocols);
|
||||
if(context->proto == Metakom) {
|
||||
context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "Metakom");
|
||||
} else if(context->proto == Cyfral) {
|
||||
context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "Cyfral");
|
||||
} else {
|
||||
context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "DS1990");
|
||||
}
|
||||
context->workr_rund = false;
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_run_attack_on_exit(iBtnFuzzerState* context) {
|
||||
if(context->workr_rund) {
|
||||
ibutton_worker_stop(context->worker);
|
||||
ibutton_worker_stop_thread(context->worker);
|
||||
context->workr_rund = false;
|
||||
}
|
||||
ibutton_key_free(context->key);
|
||||
ibutton_worker_free(context->worker);
|
||||
ibutton_protocols_free(context->protocols);
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) {
|
||||
if(context->is_attacking) {
|
||||
if(1 == counter) {
|
||||
ibutton_worker_start_thread(context->worker);
|
||||
ibutton_key_set_protocol_id(context->key, context->keytype);
|
||||
iButtonEditableData data;
|
||||
ibutton_protocols_get_editable_data(context->protocols, context->key, &data);
|
||||
data.size = sizeof(context->payload);
|
||||
for(size_t i = 0; i < data.size; i++) {
|
||||
data.ptr[i] = context->payload[i];
|
||||
}
|
||||
|
||||
ibutton_worker_emulate_start(context->worker, context->key);
|
||||
context->workr_rund = true;
|
||||
} else if(0 == counter) {
|
||||
if(context->workr_rund) {
|
||||
ibutton_worker_stop(context->worker);
|
||||
ibutton_worker_stop_thread(context->worker);
|
||||
context->workr_rund = false;
|
||||
furi_delay_ms(500);
|
||||
}
|
||||
switch(context->attack) {
|
||||
case iBtnFuzzerAttackDefaultValues:
|
||||
if(context->proto == DS1990) {
|
||||
context->payload[0] = id_list_ds1990[context->attack_step][0];
|
||||
context->payload[1] = id_list_ds1990[context->attack_step][1];
|
||||
context->payload[2] = id_list_ds1990[context->attack_step][2];
|
||||
context->payload[3] = id_list_ds1990[context->attack_step][3];
|
||||
context->payload[4] = id_list_ds1990[context->attack_step][4];
|
||||
context->payload[5] = id_list_ds1990[context->attack_step][5];
|
||||
context->payload[6] = id_list_ds1990[context->attack_step][6];
|
||||
context->payload[7] = id_list_ds1990[context->attack_step][7];
|
||||
|
||||
if(context->attack_step == 17) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == Metakom) {
|
||||
context->payload[0] = id_list_metakom[context->attack_step][0];
|
||||
context->payload[1] = id_list_metakom[context->attack_step][1];
|
||||
context->payload[2] = id_list_metakom[context->attack_step][2];
|
||||
context->payload[3] = id_list_metakom[context->attack_step][3];
|
||||
|
||||
if(context->attack_step == 16) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = id_list_cyfral[context->attack_step][0];
|
||||
context->payload[1] = id_list_cyfral[context->attack_step][1];
|
||||
|
||||
if(context->attack_step == 15) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case iBtnFuzzerAttackLoadFile:
|
||||
if(context->proto == DS1990) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
context->payload[5] = context->data[5];
|
||||
context->payload[6] = context->data[6];
|
||||
context->payload[7] = context->data[7];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == Cyfral) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case iBtnFuzzerAttackLoadFileCustomUids:
|
||||
if(context->proto == DS1990) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 17) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 17) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == Cyfral) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 5) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 5) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 2; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 9) break;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(end_of_list) break;
|
||||
if(furi_string_size(context->data_str) != 9) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(counter > context->time_between_cards) {
|
||||
counter = 0;
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_run_attack_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards > 4) {
|
||||
context->time_between_cards--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards < 80) {
|
||||
context->time_between_cards++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
counter = 0;
|
||||
if(!context->is_attacking) {
|
||||
notification_message(context->notify, &sequence_blink_start_blue);
|
||||
context->is_attacking = true;
|
||||
} else {
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_attacking = false;
|
||||
counter = 0;
|
||||
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
if(context->attack_stop_called) {
|
||||
context->attack_stop_called = false;
|
||||
context->attack_step = 0;
|
||||
if(context->attack == iBtnFuzzerAttackLoadFileCustomUids) {
|
||||
furi_string_reset(context->data_str);
|
||||
stream_rewind(context->uids_stream);
|
||||
buffered_file_stream_close(context->uids_stream);
|
||||
}
|
||||
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
|
||||
context->attack_stop_called = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(event.input_type == InputTypeLong) {
|
||||
switch(event.key) {
|
||||
case InputKeyLeft:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards > 4) {
|
||||
if((context->time_between_cards - 10) > 4) {
|
||||
context->time_between_cards -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards < 80) {
|
||||
context->time_between_cards += 10;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_run_attack_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 2, AlignCenter, AlignTop, furi_string_get_cstr(context->attack_name));
|
||||
|
||||
char uid[25];
|
||||
char speed[16];
|
||||
if(context->proto == Metakom) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3]);
|
||||
} else if(context->proto == Cyfral) {
|
||||
snprintf(uid, sizeof(uid), "%02X:%02X", context->payload[0], context->payload[1]);
|
||||
} else {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4],
|
||||
context->payload[5],
|
||||
context->payload[6],
|
||||
context->payload[7]);
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignTop, uid);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 26, AlignCenter, AlignTop, furi_string_get_cstr(context->proto_name));
|
||||
|
||||
snprintf(speed, sizeof(speed), "Time delay: %d", context->time_between_cards);
|
||||
|
||||
//canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, "Speed:");
|
||||
canvas_draw_str_aligned(canvas, 64, 14, AlignCenter, AlignTop, speed);
|
||||
//char start_stop_msg[20];
|
||||
if(context->is_attacking) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
//snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
|
||||
} else {
|
||||
elements_button_center(canvas, "Start");
|
||||
elements_button_left(canvas, "TD -");
|
||||
elements_button_right(canvas, "+ TD");
|
||||
}
|
||||
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "../ibtnfuzzer.h"
|
||||
|
||||
void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_run_attack_on_exit(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_run_attack_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_run_attack_on_draw(Canvas* canvas, iBtnFuzzerState* context);
|
||||
@@ -1,160 +0,0 @@
|
||||
#include "ibtnfuzzer_scene_select_field.h"
|
||||
|
||||
void ibtnfuzzer_center_displayed_key(iBtnFuzzerState* context, uint8_t index) {
|
||||
char key_cstr[25];
|
||||
uint8_t key_len = 25;
|
||||
uint8_t str_index = (index * 3);
|
||||
int data_len = sizeof(context->data) / sizeof(context->data[0]);
|
||||
int key_index = 0;
|
||||
|
||||
if(context->proto == DS1990) {
|
||||
key_len = 25;
|
||||
}
|
||||
if(context->proto == Metakom) {
|
||||
key_len = 13;
|
||||
}
|
||||
if(context->proto == Cyfral) {
|
||||
key_len = 7;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->data[i] < 9) {
|
||||
key_index +=
|
||||
snprintf(&key_cstr[key_index], key_len - key_index, "0%X ", context->data[i]);
|
||||
} else {
|
||||
key_index +=
|
||||
snprintf(&key_cstr[key_index], key_len - key_index, "%X ", context->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char display_menu[17] = {
|
||||
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
|
||||
|
||||
if(index > 1) {
|
||||
display_menu[0] = key_cstr[str_index - 6];
|
||||
display_menu[1] = key_cstr[str_index - 5];
|
||||
} else {
|
||||
display_menu[0] = ' ';
|
||||
display_menu[1] = ' ';
|
||||
}
|
||||
|
||||
if(index > 0) {
|
||||
display_menu[3] = key_cstr[str_index - 3];
|
||||
display_menu[4] = key_cstr[str_index - 2];
|
||||
} else {
|
||||
display_menu[3] = ' ';
|
||||
display_menu[4] = ' ';
|
||||
}
|
||||
|
||||
display_menu[7] = key_cstr[str_index];
|
||||
display_menu[8] = key_cstr[str_index + 1];
|
||||
|
||||
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[11] = key_cstr[str_index + 3];
|
||||
display_menu[12] = key_cstr[str_index + 4];
|
||||
} else {
|
||||
display_menu[11] = ' ';
|
||||
display_menu[12] = ' ';
|
||||
}
|
||||
|
||||
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[14] = key_cstr[str_index + 6];
|
||||
display_menu[15] = key_cstr[str_index + 7];
|
||||
} else {
|
||||
display_menu[14] = ' ';
|
||||
display_menu[15] = ' ';
|
||||
}
|
||||
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, display_menu);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_select_field_on_enter(iBtnFuzzerState* context) {
|
||||
furi_string_reset(context->notification_msg);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_select_field_on_exit(iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_select_field_on_tick(iBtnFuzzerState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_select_field_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
const char* key_cstr = furi_string_get_cstr(context->data_str);
|
||||
int data_len = sizeof(context->data) / sizeof(context->data[0]);
|
||||
|
||||
// don't look, it's ugly but I'm a python dev so...
|
||||
uint8_t nb_bytes = 0;
|
||||
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
|
||||
if(' ' == key_cstr[i]) {
|
||||
nb_bytes++;
|
||||
}
|
||||
}
|
||||
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->key_index == i) {
|
||||
context->data[i] = (context->data[i] - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->key_index == i) {
|
||||
context->data[i] = (context->data[i] + 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->key_index > 0) {
|
||||
context->key_index = context->key_index - 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->key_index < nb_bytes) {
|
||||
context->key_index = context->key_index + 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->key_index = 0;
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneSelectFile;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibtnfuzzer_scene_select_field_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 12, 5, AlignLeft, AlignTop, "Left and right: select byte");
|
||||
canvas_draw_str_aligned(canvas, 12, 15, AlignLeft, AlignTop, "Up and down: adjust byte");
|
||||
|
||||
char msg_index[18];
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
|
||||
canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignTop, msg_index);
|
||||
|
||||
ibtnfuzzer_center_displayed_key(context, context->key_index);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 45, AlignCenter, AlignTop, furi_string_get_cstr(context->notification_msg));
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../ibtnfuzzer.h"
|
||||
|
||||
void ibtnfuzzer_scene_select_field_on_enter(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_select_field_on_exit(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_select_field_on_tick(iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_select_field_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
|
||||
void ibtnfuzzer_scene_select_field_on_draw(Canvas* canvas, iBtnFuzzerState* context);
|
||||
void center_displayed_key(iBtnFuzzerState* context, uint8_t index);
|
||||
2
applications/external/mfkey32/mfkey32.c
vendored
@@ -1112,7 +1112,7 @@ void mfkey32(ProgramState* program_state) {
|
||||
}
|
||||
if(keyarray_size > 0) {
|
||||
// TODO: Should we use DolphinDeedNfcMfcAdd?
|
||||
DOLPHIN_DEED(DolphinDeedNfcMfcAdd);
|
||||
dolphin_deed(DolphinDeedNfcMfcAdd);
|
||||
}
|
||||
napi_mf_classic_nonce_array_free(nonce_arr);
|
||||
napi_mf_classic_dict_free(user_dict);
|
||||
|
||||
@@ -240,7 +240,7 @@ static bool game_won(Minesweeper* minesweeper_state) {
|
||||
dialog_message_set_buttons(message, NULL, "Play again", NULL);
|
||||
|
||||
// Call dolphin deed when we win the game
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
dolphin_deed(DolphinDeedPluginGameWin);
|
||||
|
||||
DialogMessageButton choice = dialog_message_show(minesweeper_state->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
@@ -397,7 +397,7 @@ int32_t minesweeper_app(void* p) {
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
PluginEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
|
||||
49
applications/external/multi_fuzzer/application.fam
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
App(
|
||||
appid="fuzzer_ibtn",
|
||||
name="iButton Fuzzer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="fuzzer_start_ibtn",
|
||||
requires=[
|
||||
"gui",
|
||||
"storage",
|
||||
"dialogs",
|
||||
"input",
|
||||
"notification",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
fap_icon="icons/ibutt_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_private_libs=[
|
||||
Lib(
|
||||
name="worker",
|
||||
cdefines=["IBUTTON_PROTOCOL"],
|
||||
),
|
||||
],
|
||||
fap_icon_assets="icons",
|
||||
fap_icon_assets_symbol="fuzzer",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="fuzzer_rfid",
|
||||
name="RFID Fuzzer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="fuzzer_start_rfid",
|
||||
requires=[
|
||||
"gui",
|
||||
"storage",
|
||||
"dialogs",
|
||||
"input",
|
||||
"notification",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
fap_icon="icons/rfid_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_private_libs=[
|
||||
Lib(
|
||||
name="worker",
|
||||
cdefines=["RFID_125_PROTOCOL"],
|
||||
),
|
||||
],
|
||||
fap_icon_assets="icons",
|
||||
fap_icon_assets_symbol="fuzzer",
|
||||
)
|
||||
160
applications/external/multi_fuzzer/fuzzer.c
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
#include "fuzzer_i.h"
|
||||
#include "helpers/fuzzer_types.h"
|
||||
|
||||
static bool fuzzer_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool fuzzer_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void fuzzer_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
PacsFuzzerApp* fuzzer_app_alloc() {
|
||||
PacsFuzzerApp* app = malloc(sizeof(PacsFuzzerApp));
|
||||
|
||||
app->fuzzer_state.menu_index = 0;
|
||||
app->fuzzer_state.proto_index = 0;
|
||||
|
||||
app->worker = fuzzer_worker_alloc();
|
||||
app->payload = fuzzer_payload_alloc();
|
||||
|
||||
app->file_path = furi_string_alloc();
|
||||
|
||||
// GUI
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// Dialog
|
||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
// Open Notification record
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// View Dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
|
||||
// Popup
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, FuzzerViewIDPopup, popup_get_view(app->popup));
|
||||
|
||||
// Main view
|
||||
app->main_view = fuzzer_view_main_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, FuzzerViewIDMain, fuzzer_view_main_get_view(app->main_view));
|
||||
|
||||
// Attack view
|
||||
app->attack_view = fuzzer_view_attack_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, FuzzerViewIDAttack, fuzzer_view_attack_get_view(app->attack_view));
|
||||
|
||||
// FieldEditor view
|
||||
app->field_editor_view = fuzzer_view_field_editor_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
FuzzerViewIDFieldEditor,
|
||||
fuzzer_view_field_editor_get_view(app->field_editor_view));
|
||||
|
||||
app->scene_manager = scene_manager_alloc(&fuzzer_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, fuzzer_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, fuzzer_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, fuzzer_app_tick_event_callback, 100);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, FuzzerSceneMain);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void fuzzer_app_free(PacsFuzzerApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Remote view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDMain);
|
||||
fuzzer_view_main_free(app->main_view);
|
||||
|
||||
// Attack view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDAttack);
|
||||
fuzzer_view_attack_free(app->attack_view);
|
||||
|
||||
// FieldEditor view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDFieldEditor);
|
||||
fuzzer_view_field_editor_free(app->field_editor_view);
|
||||
|
||||
// Popup
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
scene_manager_free(app->scene_manager);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
// Dialog
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
// Notifications
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
app->notifications = NULL;
|
||||
|
||||
furi_string_free(app->file_path);
|
||||
|
||||
fuzzer_payload_free(app->payload);
|
||||
fuzzer_worker_free(app->worker);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t fuzzer_start_ibtn(void* p) {
|
||||
UNUSED(p);
|
||||
PacsFuzzerApp* fuzzer_app = fuzzer_app_alloc();
|
||||
|
||||
FuzzerConsts app_const = {
|
||||
.custom_dict_folder = "/ext/ibtnfuzzer",
|
||||
.custom_dict_extension = ".txt",
|
||||
.key_extension = ".ibtn",
|
||||
.path_key_folder = "/ext/ibutton",
|
||||
.key_icon = &I_ibutt_10px,
|
||||
};
|
||||
fuzzer_app->fuzzer_const = &app_const;
|
||||
|
||||
view_dispatcher_run(fuzzer_app->view_dispatcher);
|
||||
|
||||
fuzzer_app_free(fuzzer_app);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t fuzzer_start_rfid(void* p) {
|
||||
UNUSED(p);
|
||||
PacsFuzzerApp* fuzzer_app = fuzzer_app_alloc();
|
||||
|
||||
FuzzerConsts app_const = {
|
||||
.custom_dict_folder = "/ext/rfidfuzzer",
|
||||
.custom_dict_extension = ".txt",
|
||||
.key_extension = ".rfid",
|
||||
.path_key_folder = "/ext/lfrfid",
|
||||
.key_icon = &I_125_10px,
|
||||
};
|
||||
fuzzer_app->fuzzer_const = &app_const;
|
||||
|
||||
view_dispatcher_run(fuzzer_app->view_dispatcher);
|
||||
|
||||
fuzzer_app_free(fuzzer_app);
|
||||
return 0;
|
||||
}
|
||||
55
applications/external/multi_fuzzer/fuzzer_i.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#include "scenes/fuzzer_scene.h"
|
||||
#include "views/main_menu.h"
|
||||
#include "views/attack.h"
|
||||
#include "views/field_editor.h"
|
||||
|
||||
#include "helpers/fuzzer_types.h"
|
||||
#include "lib/worker/fake_worker.h"
|
||||
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include "fuzzer_icons.h"
|
||||
|
||||
#define FUZZ_TIME_DELAY_MAX (80)
|
||||
|
||||
typedef struct {
|
||||
const char* custom_dict_extension;
|
||||
const char* custom_dict_folder;
|
||||
const char* key_extension;
|
||||
const char* path_key_folder;
|
||||
const Icon* key_icon;
|
||||
} FuzzerConsts;
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
NotificationApp* notifications;
|
||||
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
|
||||
Popup* popup;
|
||||
DialogsApp* dialogs;
|
||||
FuzzerViewMain* main_view;
|
||||
FuzzerViewAttack* attack_view;
|
||||
FuzzerViewFieldEditor* field_editor_view;
|
||||
|
||||
FuriString* file_path;
|
||||
|
||||
FuzzerState fuzzer_state;
|
||||
FuzzerConsts* fuzzer_const;
|
||||
|
||||
FuzzerWorker* worker;
|
||||
FuzzerPayload* payload;
|
||||
} PacsFuzzerApp;
|
||||
17
applications/external/multi_fuzzer/helpers/fuzzer_custom_event.h
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
|
||||
// FuzzerCustomEvent
|
||||
FuzzerCustomEventViewMainBack = 100,
|
||||
FuzzerCustomEventViewMainOk,
|
||||
FuzzerCustomEventViewMainPopupErr,
|
||||
|
||||
FuzzerCustomEventViewAttackBack,
|
||||
FuzzerCustomEventViewAttackOk,
|
||||
// FuzzerCustomEventViewAttackTick, // now not use
|
||||
FuzzerCustomEventViewAttackEnd,
|
||||
|
||||
FuzzerCustomEventViewFieldEditorBack,
|
||||
FuzzerCustomEventViewFieldEditorOk,
|
||||
} FuzzerCustomEvent;
|
||||
30
applications/external/multi_fuzzer/helpers/fuzzer_types.h
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t menu_index;
|
||||
uint8_t proto_index;
|
||||
} FuzzerState;
|
||||
|
||||
typedef enum {
|
||||
FuzzerAttackStateOff = 0,
|
||||
FuzzerAttackStateIdle,
|
||||
FuzzerAttackStateRunning,
|
||||
FuzzerAttackStateEnd,
|
||||
|
||||
} FuzzerAttackState;
|
||||
|
||||
typedef enum {
|
||||
FuzzerFieldEditorStateEditingOn = 0,
|
||||
FuzzerFieldEditorStateEditingOff,
|
||||
|
||||
} FuzzerFieldEditorState;
|
||||
|
||||
typedef enum {
|
||||
FuzzerViewIDPopup,
|
||||
|
||||
FuzzerViewIDMain,
|
||||
FuzzerViewIDAttack,
|
||||
FuzzerViewIDFieldEditor,
|
||||
} FuzzerViewID;
|
||||
|
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 308 B |
BIN
applications/external/multi_fuzzer/icons/ButtonLeft_4x7.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
applications/external/multi_fuzzer/icons/ButtonRight_4x7.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/multi_fuzzer/icons/Ok_btn_9x9.png
vendored
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
applications/external/multi_fuzzer/icons/Pin_back_arrow_10x8.png
vendored
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 304 B After Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
485
applications/external/multi_fuzzer/lib/worker/fake_worker.c
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
#include "fake_worker.h"
|
||||
#include "protocol_i.h"
|
||||
|
||||
#include <timer.h>
|
||||
|
||||
#include <lib/toolbox/hex.h>
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
|
||||
#define TAG "Fuzzer worker"
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
|
||||
#include <lib/lfrfid/lfrfid_dict_file.h>
|
||||
#include <lib/lfrfid/lfrfid_worker.h>
|
||||
#include <lfrfid/protocols/lfrfid_protocols.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <lib/ibutton/ibutton_worker.h>
|
||||
#include <lib/ibutton/ibutton_key.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <toolbox/stream/stream.h>
|
||||
|
||||
struct FuzzerWorker {
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
LFRFIDWorker* proto_worker;
|
||||
ProtocolId protocol_id;
|
||||
ProtocolDict* protocols_items;
|
||||
#else
|
||||
iButtonWorker* proto_worker;
|
||||
iButtonProtocolId protocol_id; // TODO
|
||||
iButtonProtocols* protocols_items;
|
||||
iButtonKey* key;
|
||||
#endif
|
||||
|
||||
const FuzzerProtocol* protocol;
|
||||
FuzzerWorkerAttackType attack_type;
|
||||
uint16_t timer_idle_time_ms;
|
||||
uint16_t timer_emu_time_ms;
|
||||
|
||||
uint8_t payload[MAX_PAYLOAD_SIZE];
|
||||
Stream* uids_stream;
|
||||
uint16_t index;
|
||||
uint8_t chusen_byte;
|
||||
|
||||
bool treead_running;
|
||||
bool in_emu_phase;
|
||||
FuriTimer* timer;
|
||||
|
||||
FuzzerWorkerUidChagedCallback tick_callback;
|
||||
void* tick_context;
|
||||
|
||||
FuzzerWorkerEndCallback end_callback;
|
||||
void* end_context;
|
||||
};
|
||||
|
||||
static bool fuzzer_worker_load_key(FuzzerWorker* instance, bool next) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->protocol);
|
||||
bool res = false;
|
||||
|
||||
const FuzzerProtocol* protocol = instance->protocol;
|
||||
|
||||
switch(instance->attack_type) {
|
||||
case FuzzerWorkerAttackTypeDefaultDict:
|
||||
if(next) {
|
||||
instance->index++;
|
||||
}
|
||||
if(instance->index < protocol->dict.len) {
|
||||
memcpy(
|
||||
instance->payload,
|
||||
&protocol->dict.val[instance->index * protocol->data_size],
|
||||
protocol->data_size);
|
||||
res = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case FuzzerWorkerAttackTypeLoadFileCustomUids: {
|
||||
if(next) {
|
||||
instance->index++;
|
||||
}
|
||||
uint8_t str_len = protocol->data_size * 2 + 1;
|
||||
FuriString* data_str = furi_string_alloc();
|
||||
while(true) {
|
||||
furi_string_reset(data_str);
|
||||
if(!stream_read_line(instance->uids_stream, data_str)) {
|
||||
stream_rewind(instance->uids_stream);
|
||||
// TODO Check empty file & close stream and storage
|
||||
break;
|
||||
} else if(furi_string_get_char(data_str, 0) == '#') {
|
||||
// Skip comment string
|
||||
continue;
|
||||
} else if(furi_string_size(data_str) != str_len) {
|
||||
// Ignore strin with bad length
|
||||
FURI_LOG_W(TAG, "Bad string length");
|
||||
continue;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Uid candidate: \"%s\"", furi_string_get_cstr(data_str));
|
||||
bool parse_ok = true;
|
||||
for(uint8_t i = 0; i < protocol->data_size; i++) {
|
||||
if(!hex_char_to_uint8(
|
||||
furi_string_get_cstr(data_str)[i * 2],
|
||||
furi_string_get_cstr(data_str)[i * 2 + 1],
|
||||
&instance->payload[i])) {
|
||||
parse_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
res = parse_ok;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FuzzerWorkerAttackTypeLoadFile:
|
||||
if(instance->payload[instance->index] != 0xFF) {
|
||||
instance->payload[instance->index]++;
|
||||
res = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
protocol_dict_set_data(
|
||||
instance->protocols_items, instance->protocol_id, instance->payload, MAX_PAYLOAD_SIZE);
|
||||
#else
|
||||
ibutton_key_set_protocol_id(instance->key, instance->protocol_id);
|
||||
iButtonEditableData data;
|
||||
ibutton_protocols_get_editable_data(instance->protocols_items, instance->key, &data);
|
||||
|
||||
// TODO check data.size logic
|
||||
data.size = MAX_PAYLOAD_SIZE;
|
||||
memcpy(data.ptr, instance->payload, MAX_PAYLOAD_SIZE); // data.size);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
static void fuzzer_worker_on_tick_callback(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
FuzzerWorker* instance = context;
|
||||
|
||||
if(instance->in_emu_phase) {
|
||||
if(instance->treead_running) {
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
lfrfid_worker_stop(instance->proto_worker);
|
||||
#else
|
||||
ibutton_worker_stop(instance->proto_worker);
|
||||
#endif
|
||||
}
|
||||
instance->in_emu_phase = false;
|
||||
furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_idle_time_ms));
|
||||
} else {
|
||||
if(!fuzzer_worker_load_key(instance, true)) {
|
||||
fuzzer_worker_pause(instance); // XXX
|
||||
if(instance->end_callback) {
|
||||
instance->end_callback(instance->end_context);
|
||||
}
|
||||
} else {
|
||||
if(instance->treead_running) {
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
lfrfid_worker_emulate_start(instance->proto_worker, instance->protocol_id);
|
||||
#else
|
||||
ibutton_worker_emulate_start(instance->proto_worker, instance->key);
|
||||
#endif
|
||||
}
|
||||
instance->in_emu_phase = true;
|
||||
furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_emu_time_ms));
|
||||
if(instance->tick_callback) {
|
||||
instance->tick_callback(instance->tick_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fuzzer_worker_get_current_key(FuzzerWorker* instance, FuzzerPayload* output_key) {
|
||||
furi_assert(instance);
|
||||
furi_assert(output_key);
|
||||
furi_assert(instance->protocol);
|
||||
|
||||
output_key->data_size = instance->protocol->data_size;
|
||||
memcpy(output_key->data, instance->payload, instance->protocol->data_size);
|
||||
}
|
||||
|
||||
static void fuzzer_worker_set_protocol(FuzzerWorker* instance, FuzzerProtocolsID protocol_index) {
|
||||
instance->protocol = &fuzzer_proto_items[protocol_index];
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
instance->protocol_id =
|
||||
protocol_dict_get_protocol_by_name(instance->protocols_items, instance->protocol->name);
|
||||
#else
|
||||
// TODO iButtonProtocolIdInvalid check
|
||||
instance->protocol_id =
|
||||
ibutton_protocols_get_id_by_name(instance->protocols_items, instance->protocol->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fuzzer_worker_init_attack_dict(FuzzerWorker* instance, FuzzerProtocolsID protocol_index) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool res = false;
|
||||
fuzzer_worker_set_protocol(instance, protocol_index);
|
||||
|
||||
instance->attack_type = FuzzerWorkerAttackTypeDefaultDict;
|
||||
instance->index = 0;
|
||||
|
||||
if(!fuzzer_worker_load_key(instance, false)) {
|
||||
instance->attack_type = FuzzerWorkerAttackTypeMax;
|
||||
} else {
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool fuzzer_worker_init_attack_file_dict(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerProtocolsID protocol_index,
|
||||
FuriString* file_path) {
|
||||
furi_assert(instance);
|
||||
furi_assert(file_path);
|
||||
|
||||
bool res = false;
|
||||
fuzzer_worker_set_protocol(instance, protocol_index);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->uids_stream = buffered_file_stream_alloc(storage);
|
||||
|
||||
if(!buffered_file_stream_open(
|
||||
instance->uids_stream, furi_string_get_cstr(file_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
buffered_file_stream_close(instance->uids_stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
instance->attack_type = FuzzerWorkerAttackTypeLoadFileCustomUids;
|
||||
instance->index = 0;
|
||||
|
||||
if(!fuzzer_worker_load_key(instance, false)) {
|
||||
instance->attack_type = FuzzerWorkerAttackTypeMax;
|
||||
buffered_file_stream_close(instance->uids_stream);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
} else {
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool fuzzer_worker_init_attack_bf_byte(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerProtocolsID protocol_index,
|
||||
const FuzzerPayload* new_uid,
|
||||
uint8_t chusen) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool res = false;
|
||||
fuzzer_worker_set_protocol(instance, protocol_index);
|
||||
|
||||
instance->attack_type = FuzzerWorkerAttackTypeLoadFile;
|
||||
instance->index = chusen;
|
||||
|
||||
memcpy(instance->payload, new_uid->data, instance->protocol->data_size);
|
||||
|
||||
res = true;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// TODO make it protocol independent
|
||||
bool fuzzer_worker_load_key_from_file(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerProtocolsID protocol_index,
|
||||
const char* filename) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool res = false;
|
||||
fuzzer_worker_set_protocol(instance, protocol_index);
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
ProtocolId loaded_proto_id = lfrfid_dict_file_load(instance->protocols_items, filename);
|
||||
if(loaded_proto_id == PROTOCOL_NO) {
|
||||
// Err Cant load file
|
||||
FURI_LOG_W(TAG, "Cant load file");
|
||||
} else if(instance->protocol_id != loaded_proto_id) { // Err wrong protocol
|
||||
FURI_LOG_W(TAG, "Wrong protocol");
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Selected: %s Loaded: %s",
|
||||
instance->protocol->name,
|
||||
protocol_dict_get_name(instance->protocols_items, loaded_proto_id));
|
||||
} else {
|
||||
protocol_dict_get_data(
|
||||
instance->protocols_items, instance->protocol_id, instance->payload, MAX_PAYLOAD_SIZE);
|
||||
res = true;
|
||||
}
|
||||
#else
|
||||
if(!ibutton_protocols_load(instance->protocols_items, instance->key, filename)) {
|
||||
// Err Cant load file
|
||||
FURI_LOG_W(TAG, "Cant load file");
|
||||
} else {
|
||||
if(instance->protocol_id != ibutton_key_get_protocol_id(instance->key)) {
|
||||
// Err wrong protocol
|
||||
FURI_LOG_W(TAG, "Wrong protocol");
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Selected: %s Loaded: %s",
|
||||
instance->protocol->name,
|
||||
ibutton_protocols_get_name(
|
||||
instance->protocols_items, ibutton_key_get_protocol_id(instance->key)));
|
||||
} else {
|
||||
iButtonEditableData data;
|
||||
ibutton_protocols_get_editable_data(instance->protocols_items, instance->key, &data);
|
||||
memcpy(instance->payload, data.ptr, data.size);
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
FuzzerWorker* fuzzer_worker_alloc() {
|
||||
FuzzerWorker* instance = malloc(sizeof(FuzzerWorker));
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
instance->protocols_items = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
|
||||
instance->proto_worker = lfrfid_worker_alloc(instance->protocols_items);
|
||||
#else
|
||||
instance->protocols_items = ibutton_protocols_alloc();
|
||||
instance->key =
|
||||
ibutton_key_alloc(ibutton_protocols_get_max_data_size(instance->protocols_items));
|
||||
|
||||
instance->proto_worker = ibutton_worker_alloc(instance->protocols_items);
|
||||
#endif
|
||||
instance->attack_type = FuzzerWorkerAttackTypeMax;
|
||||
instance->index = 0;
|
||||
instance->treead_running = false;
|
||||
instance->in_emu_phase = false;
|
||||
|
||||
memset(instance->payload, 0x00, sizeof(instance->payload));
|
||||
|
||||
instance->timer_idle_time_ms = PROTOCOL_DEF_IDLE_TIME * 100;
|
||||
instance->timer_emu_time_ms = PROTOCOL_DEF_EMU_TIME * 100;
|
||||
|
||||
instance->timer =
|
||||
furi_timer_alloc(fuzzer_worker_on_tick_callback, FuriTimerTypeOnce, instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void fuzzer_worker_free(FuzzerWorker* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
fuzzer_worker_stop(instance);
|
||||
|
||||
furi_timer_free(instance->timer);
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
lfrfid_worker_free(instance->proto_worker);
|
||||
|
||||
protocol_dict_free(instance->protocols_items);
|
||||
#else
|
||||
ibutton_worker_free(instance->proto_worker);
|
||||
|
||||
ibutton_key_free(instance->key);
|
||||
ibutton_protocols_free(instance->protocols_items);
|
||||
#endif
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
bool fuzzer_worker_start(FuzzerWorker* instance, uint8_t idle_time, uint8_t emu_time) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(instance->attack_type < FuzzerWorkerAttackTypeMax) {
|
||||
if(idle_time == 0) {
|
||||
instance->timer_idle_time_ms = 10;
|
||||
} else {
|
||||
instance->timer_idle_time_ms = idle_time * 100;
|
||||
}
|
||||
if(emu_time == 0) {
|
||||
instance->timer_emu_time_ms = 10;
|
||||
} else {
|
||||
instance->timer_emu_time_ms = emu_time * 100;
|
||||
}
|
||||
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Emu_time %u ms Idle_time %u ms",
|
||||
instance->timer_emu_time_ms,
|
||||
instance->timer_idle_time_ms);
|
||||
|
||||
if(!instance->treead_running) {
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
lfrfid_worker_start_thread(instance->proto_worker);
|
||||
#else
|
||||
ibutton_worker_start_thread(instance->proto_worker);
|
||||
#endif
|
||||
FURI_LOG_D(TAG, "Worker Starting");
|
||||
instance->treead_running = true;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Worker UnPaused");
|
||||
}
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
// lfrfid_worker_start_thread(instance->proto_worker);
|
||||
lfrfid_worker_emulate_start(instance->proto_worker, instance->protocol_id);
|
||||
#else
|
||||
// ibutton_worker_start_thread(instance->proto_worker);
|
||||
ibutton_worker_emulate_start(instance->proto_worker, instance->key);
|
||||
#endif
|
||||
instance->in_emu_phase = true;
|
||||
furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_emu_time_ms));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void fuzzer_worker_pause(FuzzerWorker* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
furi_timer_stop(instance->timer);
|
||||
|
||||
if(instance->treead_running) {
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
lfrfid_worker_stop(instance->proto_worker);
|
||||
#else
|
||||
ibutton_worker_stop(instance->proto_worker);
|
||||
#endif
|
||||
FURI_LOG_D(TAG, "Worker Paused");
|
||||
}
|
||||
}
|
||||
|
||||
void fuzzer_worker_stop(FuzzerWorker* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
furi_timer_stop(instance->timer);
|
||||
|
||||
if(instance->treead_running) {
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
lfrfid_worker_stop(instance->proto_worker);
|
||||
lfrfid_worker_stop_thread(instance->proto_worker);
|
||||
#else
|
||||
ibutton_worker_stop(instance->proto_worker);
|
||||
ibutton_worker_stop_thread(instance->proto_worker);
|
||||
#endif
|
||||
FURI_LOG_D(TAG, "Worker Stopping");
|
||||
instance->treead_running = false;
|
||||
}
|
||||
|
||||
if(instance->attack_type == FuzzerWorkerAttackTypeLoadFileCustomUids) {
|
||||
buffered_file_stream_close(instance->uids_stream);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
instance->attack_type = FuzzerWorkerAttackTypeMax;
|
||||
}
|
||||
|
||||
// TODO anything else
|
||||
}
|
||||
|
||||
void fuzzer_worker_set_uid_chaged_callback(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerWorkerUidChagedCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
instance->tick_callback = callback;
|
||||
instance->tick_context = context;
|
||||
}
|
||||
|
||||
void fuzzer_worker_set_end_callback(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerWorkerEndCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
instance->end_callback = callback;
|
||||
instance->end_context = context;
|
||||
}
|
||||
138
applications/external/multi_fuzzer/lib/worker/fake_worker.h
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#include "protocol.h"
|
||||
|
||||
typedef enum {
|
||||
FuzzerWorkerAttackTypeDefaultDict = 0,
|
||||
FuzzerWorkerAttackTypeLoadFile,
|
||||
FuzzerWorkerAttackTypeLoadFileCustomUids,
|
||||
|
||||
FuzzerWorkerAttackTypeMax,
|
||||
} FuzzerWorkerAttackType;
|
||||
|
||||
typedef void (*FuzzerWorkerUidChagedCallback)(void* context);
|
||||
typedef void (*FuzzerWorkerEndCallback)(void* context);
|
||||
|
||||
typedef struct FuzzerWorker FuzzerWorker;
|
||||
|
||||
/**
|
||||
* Allocate FuzzerWorker
|
||||
*
|
||||
* @return FuzzerWorker* pointer to FuzzerWorker
|
||||
*/
|
||||
FuzzerWorker* fuzzer_worker_alloc();
|
||||
|
||||
/**
|
||||
* Free FuzzerWorker
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
*/
|
||||
void fuzzer_worker_free(FuzzerWorker* instance);
|
||||
|
||||
/**
|
||||
* Start or continue emulation
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param idle_time Delay between emulations in tenths of a second
|
||||
* @param emu_time Emulation time of one UID in tenths of a second
|
||||
* @return bool True if emulation has started
|
||||
*/
|
||||
bool fuzzer_worker_start(FuzzerWorker* instance, uint8_t idle_time, uint8_t emu_time);
|
||||
|
||||
/**
|
||||
* Stop emulation and deinit worker
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
*/
|
||||
void fuzzer_worker_stop(FuzzerWorker* instance);
|
||||
|
||||
/**
|
||||
* Suspend emulation
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
*/
|
||||
void fuzzer_worker_pause(FuzzerWorker* instance);
|
||||
|
||||
/**
|
||||
* Init attack by default dictionary
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param protocol_index index of the selected protocol
|
||||
* @return bool True if initialization is successful
|
||||
*/
|
||||
bool fuzzer_worker_init_attack_dict(FuzzerWorker* instance, FuzzerProtocolsID protocol_index);
|
||||
|
||||
/**
|
||||
* Init attack by custom dictionary
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param protocol_index index of the selected protocol
|
||||
* @param file_path file path to the dictionary
|
||||
* @return bool True if initialization is successful
|
||||
*/
|
||||
bool fuzzer_worker_init_attack_file_dict(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerProtocolsID protocol_index,
|
||||
FuriString* file_path);
|
||||
|
||||
/**
|
||||
* Init attack brute force one of byte
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param protocol_index index of the selected protocol
|
||||
* @param new_uid Pointer to a FuzzerPayload with UID for brute force
|
||||
* @param chosen index of chusen byte
|
||||
* @return bool True if initialization is successful
|
||||
*/
|
||||
bool fuzzer_worker_init_attack_bf_byte(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerProtocolsID protocol_index,
|
||||
const FuzzerPayload* new_uid,
|
||||
uint8_t chusen);
|
||||
|
||||
/**
|
||||
* Get current UID
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param output_key Pointer to a FuzzerPayload
|
||||
*/
|
||||
void fuzzer_worker_get_current_key(FuzzerWorker* instance, FuzzerPayload* output_key);
|
||||
|
||||
/**
|
||||
* Load UID from Flipper Format Key file
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param protocol_index index of the selected protocol
|
||||
* @param filename file path to the key file
|
||||
* @return bool True if loading is successful
|
||||
*/
|
||||
bool fuzzer_worker_load_key_from_file(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerProtocolsID protocol_index,
|
||||
const char* filename);
|
||||
|
||||
/**
|
||||
* Set callback for uid changed
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param callback Callback for uid changed
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void fuzzer_worker_set_uid_chaged_callback(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerWorkerUidChagedCallback callback,
|
||||
void* context);
|
||||
|
||||
/**
|
||||
* Set callback for end of emulation
|
||||
*
|
||||
* @param instance Pointer to a FuzzerWorker
|
||||
* @param callback Callback for end of emulation
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void fuzzer_worker_set_end_callback(
|
||||
FuzzerWorker* instance,
|
||||
FuzzerWorkerEndCallback callback,
|
||||
void* context);
|
||||
291
applications/external/multi_fuzzer/lib/worker/protocol.c
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
#include "protocol_i.h"
|
||||
#include "furi.h"
|
||||
|
||||
// #######################
|
||||
// ## Ibutton Protocols ##
|
||||
// #######################
|
||||
#define DS1990_DATA_SIZE (8)
|
||||
#define Metakom_DATA_SIZE (4)
|
||||
#define Cyfral_DATA_SIZE (2)
|
||||
|
||||
const uint8_t uid_list_ds1990[][DS1990_DATA_SIZE] = {
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0xE1}, //– код универсального ключа, для Vizit
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x56, 0x00, 0xBB}, //- проверен работает
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x00, 0x00, 0x00, 0x77}, //- проверен работает
|
||||
{0x01, 0xBE, 0x40, 0x11, 0x0A, 0x00, 0x00, 0x1D}, //- проверен работает Визит иногда КЕЙМАНЫ
|
||||
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F}, //- проверен(метаком, цифрал, ВИЗИТ).
|
||||
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x9B}, //- проверен Визит, Метакомы, КОНДОР
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, //???-Открываает 98% Метаком и некоторые Цифрал
|
||||
{0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x19, 0xFF}, //???-Отлично работает на старых домофонах
|
||||
{0x01, 0x6F, 0x2E, 0x88, 0x8A, 0x00, 0x00, 0x4D}, //???-Открывать что-то должен
|
||||
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x7E, 0x88}, //???-Cyfral, Metakom
|
||||
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x00, 0x6F}, //???-домофоны Визит (Vizit) - до 99%
|
||||
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D}, //???-домофоны Cyfral CCD-20 - до 70%
|
||||
{0x01, 0x00, 0xBE, 0x11, 0xAA, 0x00, 0x00, 0xFB}, //???-домофоны Кейман (KEYMAN)
|
||||
{0x01, 0x76, 0xB8, 0x2E, 0x0F, 0x00, 0x00, 0x5C}, //???-домофоны Форвард
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, // Only FF
|
||||
{0x01, 0x78, 0x00, 0x48, 0xFD, 0xFF, 0xFF, 0xD1}, // StarNew Uni5
|
||||
{0x01, 0xA9, 0xE4, 0x3C, 0x09, 0x00, 0x00, 0xE6}, // Eltis Uni
|
||||
};
|
||||
|
||||
const uint8_t uid_list_metakom[][Metakom_DATA_SIZE] = {
|
||||
{0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d}, // ??
|
||||
{0x34, 0x00, 0x29, 0x3d}, // ??
|
||||
{0x04, 0xdf, 0x00, 0x00}, // ??
|
||||
{0xCA, 0xCA, 0xCA, 0xCA}, // ??
|
||||
};
|
||||
|
||||
const uint8_t uid_list_cyfral[][Cyfral_DATA_SIZE] = {
|
||||
{0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34}, // Incremental UID
|
||||
{0x56, 0x34}, // Decremental UID
|
||||
{0xCA, 0xCA}, // ??
|
||||
{0x8E, 0xC9}, // Elevator code
|
||||
{0x6A, 0x50}, // VERY fresh code from smartkey
|
||||
};
|
||||
|
||||
// ###########################
|
||||
// ## Rfid_125khz Protocols ##
|
||||
// ###########################
|
||||
#define EM4100_DATA_SIZE (5)
|
||||
#define HIDProx_DATA_SIZE (6)
|
||||
#define PAC_DATA_SIZE (4)
|
||||
#define H10301_DATA_SIZE (3)
|
||||
|
||||
const uint8_t uid_list_em4100[][EM4100_DATA_SIZE] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha
|
||||
{0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha
|
||||
{0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
const uint8_t uid_list_hid[][HIDProx_DATA_SIZE] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, // Incremental UID
|
||||
{0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
const uint8_t uid_list_pac[][PAC_DATA_SIZE] = {
|
||||
{0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d}, // From arha
|
||||
{0x34, 0x00, 0x29, 0x3d}, // From arha
|
||||
{0x04, 0xdf, 0x00, 0x00}, // From arha
|
||||
{0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
const uint8_t uid_list_h10301[][H10301_DATA_SIZE] = {
|
||||
{0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56}, // Incremental UID
|
||||
{0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
const FuzzerProtocol fuzzer_proto_items[] = {
|
||||
[EM4100] =
|
||||
{
|
||||
.name = "EM4100",
|
||||
.data_size = EM4100_DATA_SIZE,
|
||||
.dict =
|
||||
{
|
||||
.val = (const uint8_t*)&uid_list_em4100,
|
||||
.len = COUNT_OF(uid_list_em4100),
|
||||
},
|
||||
},
|
||||
[HIDProx] =
|
||||
{
|
||||
.name = "HIDProx",
|
||||
.data_size = HIDProx_DATA_SIZE,
|
||||
.dict =
|
||||
{
|
||||
.val = (const uint8_t*)&uid_list_hid,
|
||||
.len = COUNT_OF(uid_list_hid),
|
||||
},
|
||||
},
|
||||
[PAC] =
|
||||
{
|
||||
.name = "PAC/Stanley",
|
||||
.data_size = PAC_DATA_SIZE,
|
||||
.dict =
|
||||
{
|
||||
.val = (const uint8_t*)&uid_list_pac,
|
||||
.len = COUNT_OF(uid_list_pac),
|
||||
},
|
||||
},
|
||||
[H10301] =
|
||||
{
|
||||
.name = "H10301",
|
||||
.data_size = H10301_DATA_SIZE,
|
||||
.dict =
|
||||
{
|
||||
.val = (const uint8_t*)&uid_list_h10301,
|
||||
.len = COUNT_OF(uid_list_h10301),
|
||||
},
|
||||
},
|
||||
};
|
||||
#else
|
||||
const FuzzerProtocol fuzzer_proto_items[] = {
|
||||
[DS1990] =
|
||||
{
|
||||
.name = "DS1990",
|
||||
.data_size = DS1990_DATA_SIZE,
|
||||
.dict =
|
||||
{
|
||||
.val = (const uint8_t*)&uid_list_ds1990,
|
||||
.len = COUNT_OF(uid_list_ds1990),
|
||||
},
|
||||
},
|
||||
[Metakom] =
|
||||
{
|
||||
.name = "Metakom",
|
||||
.data_size = Metakom_DATA_SIZE,
|
||||
.dict =
|
||||
{
|
||||
.val = (const uint8_t*)&uid_list_metakom,
|
||||
.len = COUNT_OF(uid_list_metakom),
|
||||
},
|
||||
},
|
||||
[Cyfral] =
|
||||
{
|
||||
.name = "Cyfral",
|
||||
.data_size = Cyfral_DATA_SIZE,
|
||||
.dict =
|
||||
{
|
||||
.val = (const uint8_t*)&uid_list_cyfral,
|
||||
.len = COUNT_OF(uid_list_cyfral),
|
||||
},
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
const char* menu_label;
|
||||
FuzzerAttackId attack_id;
|
||||
} FuzzerMenuItems;
|
||||
|
||||
const FuzzerMenuItems fuzzer_menu_items[] = {
|
||||
{"Default Values", FuzzerAttackIdDefaultValues},
|
||||
#ifdef RFID_125_PROTOCOL
|
||||
{"BF Customer ID", FuzzerAttackIdBFCustomerID},
|
||||
#endif
|
||||
{"Load File", FuzzerAttackIdLoadFile},
|
||||
{"Load UIDs from file", FuzzerAttackIdLoadFileCustomUids},
|
||||
};
|
||||
|
||||
FuzzerPayload* fuzzer_payload_alloc() {
|
||||
FuzzerPayload* payload = malloc(sizeof(FuzzerPayload));
|
||||
payload->data = malloc(sizeof(payload->data[0]) * MAX_PAYLOAD_SIZE);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
void fuzzer_payload_free(FuzzerPayload* payload) {
|
||||
furi_assert(payload);
|
||||
|
||||
if(payload->data) {
|
||||
free(payload->data);
|
||||
}
|
||||
free(payload);
|
||||
}
|
||||
|
||||
const char* fuzzer_proto_get_name(FuzzerProtocolsID index) {
|
||||
return fuzzer_proto_items[index].name;
|
||||
}
|
||||
|
||||
uint8_t fuzzer_proto_get_count_of_protocols() {
|
||||
return COUNT_OF(fuzzer_proto_items);
|
||||
}
|
||||
|
||||
uint8_t fuzzer_proto_get_max_data_size() {
|
||||
return MAX_PAYLOAD_SIZE;
|
||||
}
|
||||
|
||||
uint8_t fuzzer_proto_get_def_emu_time() {
|
||||
return PROTOCOL_DEF_EMU_TIME;
|
||||
}
|
||||
|
||||
uint8_t fuzzer_proto_get_def_idle_time() {
|
||||
return PROTOCOL_DEF_IDLE_TIME;
|
||||
}
|
||||
|
||||
const char* fuzzer_proto_get_menu_label(uint8_t index) {
|
||||
return fuzzer_menu_items[index].menu_label;
|
||||
}
|
||||
|
||||
FuzzerAttackId fuzzer_proto_get_attack_id_by_index(uint8_t index) {
|
||||
return fuzzer_menu_items[index].attack_id;
|
||||
}
|
||||
|
||||
uint8_t fuzzer_proto_get_count_of_menu_items() {
|
||||
return COUNT_OF(fuzzer_menu_items);
|
||||
}
|
||||
89
applications/external/multi_fuzzer/lib/worker/protocol.h
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// #define RFID_125_PROTOCOL
|
||||
|
||||
typedef struct FuzzerPayload FuzzerPayload;
|
||||
|
||||
typedef enum {
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
EM4100,
|
||||
HIDProx,
|
||||
PAC,
|
||||
H10301,
|
||||
#else
|
||||
DS1990,
|
||||
Metakom,
|
||||
Cyfral,
|
||||
#endif
|
||||
} FuzzerProtocolsID;
|
||||
|
||||
typedef enum {
|
||||
FuzzerAttackIdDefaultValues = 0,
|
||||
FuzzerAttackIdLoadFile,
|
||||
FuzzerAttackIdLoadFileCustomUids,
|
||||
FuzzerAttackIdBFCustomerID,
|
||||
} FuzzerAttackId;
|
||||
|
||||
struct FuzzerPayload {
|
||||
uint8_t* data;
|
||||
uint8_t data_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate FuzzerPayload
|
||||
*
|
||||
* @return FuzzerPayload* pointer to FuzzerPayload
|
||||
*/
|
||||
FuzzerPayload* fuzzer_payload_alloc();
|
||||
|
||||
/**
|
||||
* Free FuzzerPayload
|
||||
*
|
||||
* @param instance Pointer to a FuzzerPayload
|
||||
*/
|
||||
void fuzzer_payload_free(FuzzerPayload*);
|
||||
|
||||
/**
|
||||
* Get maximum length of UID among all supported protocols
|
||||
* @return Maximum length of UID
|
||||
*/
|
||||
uint8_t fuzzer_proto_get_max_data_size();
|
||||
|
||||
// TODO add description
|
||||
uint8_t fuzzer_proto_get_def_emu_time();
|
||||
uint8_t fuzzer_proto_get_def_idle_time();
|
||||
|
||||
/**
|
||||
* Get protocol name based on its index
|
||||
* @param index protocol index
|
||||
* @return pointer to a string containing the name
|
||||
*/
|
||||
const char* fuzzer_proto_get_name(FuzzerProtocolsID index);
|
||||
|
||||
/**
|
||||
* Get number of protocols
|
||||
* @return number of protocols
|
||||
*/
|
||||
uint8_t fuzzer_proto_get_count_of_protocols();
|
||||
|
||||
/**
|
||||
* Get menu label based on its index
|
||||
* @param index menu index
|
||||
* @return pointer to a string containing the menu label
|
||||
*/
|
||||
const char* fuzzer_proto_get_menu_label(uint8_t index);
|
||||
|
||||
/**
|
||||
* Get FuzzerAttackId based on its index
|
||||
* @param index menu index
|
||||
* @return FuzzerAttackId
|
||||
*/
|
||||
FuzzerAttackId fuzzer_proto_get_attack_id_by_index(uint8_t index);
|
||||
|
||||
/**
|
||||
* Get number of menu items
|
||||
* @return number of menu items
|
||||
*/
|
||||
uint8_t fuzzer_proto_get_count_of_menu_items();
|
||||
43
applications/external/multi_fuzzer/lib/worker/protocol_i.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "protocol.h"
|
||||
|
||||
#if defined(RFID_125_PROTOCOL)
|
||||
#define MAX_PAYLOAD_SIZE (6)
|
||||
#define PROTOCOL_DEF_IDLE_TIME (4)
|
||||
#define PROTOCOL_DEF_EMU_TIME (5)
|
||||
#define PROTOCOL_TIME_DELAY_MIN PROTOCOL_DEF_IDLE_TIME + PROTOCOL_DEF_EMU_TIME
|
||||
#else
|
||||
#define MAX_PAYLOAD_SIZE (8)
|
||||
#define PROTOCOL_DEF_IDLE_TIME (2)
|
||||
#define PROTOCOL_DEF_EMU_TIME (2)
|
||||
#define PROTOCOL_TIME_DELAY_MIN PROTOCOL_DEF_IDLE_TIME + PROTOCOL_DEF_EMU_TIME
|
||||
#endif
|
||||
|
||||
typedef struct ProtoDict ProtoDict;
|
||||
typedef struct FuzzerProtocol FuzzerProtocol;
|
||||
|
||||
struct ProtoDict {
|
||||
const uint8_t* val;
|
||||
const uint8_t len;
|
||||
};
|
||||
|
||||
struct FuzzerProtocol {
|
||||
const char* name;
|
||||
const uint8_t data_size;
|
||||
const ProtoDict dict;
|
||||
};
|
||||
|
||||
// #define MAX_PAYLOAD_SIZE 6
|
||||
|
||||
// #define FUZZ_TIME_DELAY_MIN (5)
|
||||
// #define FUZZ_TIME_DELAY_DEFAULT (10)
|
||||
// #define FUZZ_TIME_DELAY_MAX (70)
|
||||
|
||||
// #define MAX_PAYLOAD_SIZE 8
|
||||
|
||||
// #define FUZZ_TIME_DELAY_MIN (4)
|
||||
// #define FUZZ_TIME_DELAY_DEFAULT (8)
|
||||
// #define FUZZ_TIME_DELAY_MAX (80)
|
||||
|
||||
extern const FuzzerProtocol fuzzer_proto_items[];
|
||||
30
applications/external/multi_fuzzer/scenes/fuzzer_scene.c
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "fuzzer_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const fuzzer_scene_on_enter_handlers[])(void*) = {
|
||||
#include "fuzzer_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 fuzzer_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "fuzzer_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 fuzzer_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "fuzzer_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers fuzzer_scene_handlers = {
|
||||
.on_enter_handlers = fuzzer_scene_on_enter_handlers,
|
||||
.on_event_handlers = fuzzer_scene_on_event_handlers,
|
||||
.on_exit_handlers = fuzzer_scene_on_exit_handlers,
|
||||
.scene_num = FuzzerSceneNum,
|
||||
};
|
||||
29
applications/external/multi_fuzzer/scenes/fuzzer_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) FuzzerScene##id,
|
||||
typedef enum {
|
||||
#include "fuzzer_scene_config.h"
|
||||
FuzzerSceneNum,
|
||||
} FuzzerScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers fuzzer_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "fuzzer_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 "fuzzer_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 "fuzzer_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
162
applications/external/multi_fuzzer/scenes/fuzzer_scene_attack.c
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "../fuzzer_i.h"
|
||||
#include "../helpers/fuzzer_custom_event.h"
|
||||
|
||||
const NotificationSequence sequence_one_green_50_on_blink_blue = {
|
||||
&message_red_255,
|
||||
&message_delay_50,
|
||||
&message_red_0,
|
||||
&message_blink_start_10,
|
||||
&message_blink_set_color_blue,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void fuzzer_scene_attack_update_uid(PacsFuzzerApp* app) {
|
||||
furi_assert(app);
|
||||
furi_assert(app->worker);
|
||||
furi_assert(app->attack_view);
|
||||
|
||||
fuzzer_worker_get_current_key(app->worker, app->payload);
|
||||
|
||||
fuzzer_view_attack_set_uid(app->attack_view, app->payload);
|
||||
}
|
||||
|
||||
static void fuzzer_scene_attack_set_state(PacsFuzzerApp* app, FuzzerAttackState state) {
|
||||
furi_assert(app);
|
||||
|
||||
scene_manager_set_scene_state(app->scene_manager, FuzzerSceneAttack, state);
|
||||
switch(state) {
|
||||
case FuzzerAttackStateIdle:
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
fuzzer_view_attack_pause(app->attack_view);
|
||||
break;
|
||||
|
||||
case FuzzerAttackStateRunning:
|
||||
notification_message(app->notifications, &sequence_blink_start_blue);
|
||||
fuzzer_view_attack_start(app->attack_view);
|
||||
break;
|
||||
|
||||
case FuzzerAttackStateEnd:
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
notification_message(app->notifications, &sequence_single_vibro);
|
||||
fuzzer_view_attack_end(app->attack_view);
|
||||
break;
|
||||
|
||||
case FuzzerAttackStateOff:
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
fuzzer_view_attack_stop(app->attack_view);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void fuzzer_scene_attack_worker_tick_callback(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
|
||||
notification_message(app->notifications, &sequence_one_green_50_on_blink_blue);
|
||||
fuzzer_scene_attack_update_uid(app);
|
||||
|
||||
// view_dispatcher_send_custom_event(app->view_dispatcher, FuzzerCustomEventViewAttackTick);
|
||||
}
|
||||
|
||||
void fuzzer_scene_attack_worker_end_callback(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, FuzzerCustomEventViewAttackEnd);
|
||||
}
|
||||
|
||||
void fuzzer_scene_attack_callback(FuzzerCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void fuzzer_scene_attack_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
|
||||
fuzzer_view_attack_set_callback(app->attack_view, fuzzer_scene_attack_callback, app);
|
||||
|
||||
fuzzer_worker_set_uid_chaged_callback(
|
||||
app->worker, fuzzer_scene_attack_worker_tick_callback, app);
|
||||
|
||||
fuzzer_worker_set_end_callback(app->worker, fuzzer_scene_attack_worker_end_callback, app);
|
||||
|
||||
fuzzer_view_attack_reset_data(
|
||||
app->attack_view,
|
||||
fuzzer_proto_get_menu_label(app->fuzzer_state.menu_index),
|
||||
fuzzer_proto_get_name(app->fuzzer_state.proto_index));
|
||||
|
||||
fuzzer_scene_attack_update_uid(app);
|
||||
|
||||
scene_manager_set_scene_state(app->scene_manager, FuzzerSceneAttack, FuzzerAttackStateIdle);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDAttack);
|
||||
}
|
||||
|
||||
bool fuzzer_scene_attack_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == FuzzerCustomEventViewAttackBack) {
|
||||
if(scene_manager_get_scene_state(app->scene_manager, FuzzerSceneAttack) ==
|
||||
FuzzerAttackStateRunning) {
|
||||
// Pause if attack running
|
||||
fuzzer_worker_pause(app->worker);
|
||||
|
||||
fuzzer_scene_attack_set_state(app, FuzzerAttackStateIdle);
|
||||
} else {
|
||||
// Exit
|
||||
fuzzer_worker_stop(app->worker);
|
||||
|
||||
fuzzer_scene_attack_set_state(app, FuzzerAttackStateOff);
|
||||
if(!scene_manager_previous_scene(app->scene_manager)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == FuzzerCustomEventViewAttackOk) {
|
||||
if(scene_manager_get_scene_state(app->scene_manager, FuzzerSceneAttack) ==
|
||||
FuzzerAttackStateIdle) {
|
||||
// Start or Continue Attack
|
||||
if(fuzzer_worker_start(
|
||||
app->worker,
|
||||
fuzzer_view_attack_get_time_delay(app->attack_view),
|
||||
fuzzer_view_attack_get_emu_time(app->attack_view))) {
|
||||
fuzzer_scene_attack_set_state(app, FuzzerAttackStateRunning);
|
||||
} else {
|
||||
// Error?
|
||||
}
|
||||
} else if(
|
||||
scene_manager_get_scene_state(app->scene_manager, FuzzerSceneAttack) ==
|
||||
FuzzerAttackStateRunning) {
|
||||
// Pause if attack running
|
||||
fuzzer_worker_pause(app->worker);
|
||||
|
||||
fuzzer_scene_attack_set_state(app, FuzzerAttackStateIdle);
|
||||
}
|
||||
consumed = true;
|
||||
// } else if(event.event == FuzzerCustomEventViewAttackTick) {
|
||||
// consumed = true;
|
||||
} else if(event.event == FuzzerCustomEventViewAttackEnd) {
|
||||
fuzzer_scene_attack_set_state(app, FuzzerAttackStateEnd);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void fuzzer_scene_attack_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
|
||||
// XXX the scene has no descendants, and the return will be processed in on_event
|
||||
// fuzzer_worker_stop();
|
||||
|
||||
fuzzer_worker_set_uid_chaged_callback(app->worker, NULL, NULL);
|
||||
fuzzer_worker_set_end_callback(app->worker, NULL, NULL);
|
||||
}
|
||||
3
applications/external/multi_fuzzer/scenes/fuzzer_scene_config.h
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
ADD_SCENE(fuzzer, main, Main)
|
||||
ADD_SCENE(fuzzer, attack, Attack)
|
||||
ADD_SCENE(fuzzer, field_editor, FieldEditor)
|
||||
66
applications/external/multi_fuzzer/scenes/fuzzer_scene_field_editor.c
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "../fuzzer_i.h"
|
||||
#include "../helpers/fuzzer_custom_event.h"
|
||||
|
||||
void fuzzer_scene_field_editor_callback(FuzzerCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void fuzzer_scene_field_editor_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
|
||||
fuzzer_view_field_editor_set_callback(
|
||||
app->field_editor_view, fuzzer_scene_field_editor_callback, app);
|
||||
|
||||
fuzzer_worker_get_current_key(app->worker, app->payload);
|
||||
|
||||
switch(scene_manager_get_scene_state(app->scene_manager, FuzzerSceneFieldEditor)) {
|
||||
case FuzzerFieldEditorStateEditingOn:
|
||||
fuzzer_view_field_editor_reset_data(app->field_editor_view, app->payload, true);
|
||||
break;
|
||||
|
||||
case FuzzerFieldEditorStateEditingOff:
|
||||
fuzzer_view_field_editor_reset_data(app->field_editor_view, app->payload, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDFieldEditor);
|
||||
}
|
||||
|
||||
bool fuzzer_scene_field_editor_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == FuzzerCustomEventViewFieldEditorBack) {
|
||||
if(!scene_manager_previous_scene(app->scene_manager)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == FuzzerCustomEventViewFieldEditorOk) {
|
||||
fuzzer_view_field_editor_get_uid(app->field_editor_view, app->payload);
|
||||
if(fuzzer_worker_init_attack_bf_byte(
|
||||
app->worker,
|
||||
app->fuzzer_state.proto_index,
|
||||
app->payload,
|
||||
fuzzer_view_field_editor_get_index(app->field_editor_view))) {
|
||||
scene_manager_next_scene(app->scene_manager, FuzzerSceneAttack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void fuzzer_scene_field_editor_on_exit(void* context) {
|
||||
// furi_assert(context);
|
||||
// PacsFuzzerApp* app = context;
|
||||
UNUSED(context);
|
||||
}
|
||||
189
applications/external/multi_fuzzer/scenes/fuzzer_scene_main.c
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
#include "../fuzzer_i.h"
|
||||
#include "../helpers/fuzzer_custom_event.h"
|
||||
|
||||
#include "../lib/worker/protocol.h"
|
||||
|
||||
void fuzzer_scene_main_callback(FuzzerCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void fuzzer_scene_main_error_popup_callback(void* context) {
|
||||
PacsFuzzerApp* app = context;
|
||||
notification_message(app->notifications, &sequence_reset_rgb);
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, FuzzerCustomEventViewMainPopupErr);
|
||||
}
|
||||
|
||||
static bool fuzzer_scene_main_load_custom_dict(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
|
||||
FuzzerConsts* consts = app->fuzzer_const;
|
||||
|
||||
furi_string_set_str(app->file_path, consts->custom_dict_folder);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, consts->custom_dict_extension, &I_rfid_10px);
|
||||
browser_options.base_path = consts->custom_dict_folder;
|
||||
browser_options.hide_ext = false;
|
||||
|
||||
bool res =
|
||||
dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool fuzzer_scene_main_load_key(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
|
||||
FuzzerConsts* consts = app->fuzzer_const;
|
||||
|
||||
furi_string_set_str(app->file_path, consts->path_key_folder);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, consts->key_extension, consts->key_icon);
|
||||
browser_options.base_path = consts->path_key_folder;
|
||||
browser_options.hide_ext = true;
|
||||
|
||||
bool res =
|
||||
dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void fuzzer_scene_main_show_error(void* context, const char* erre_str) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
popup_set_header(app->popup, erre_str, 64, 20, AlignCenter, AlignTop);
|
||||
notification_message(app->notifications, &sequence_set_red_255);
|
||||
notification_message(app->notifications, &sequence_double_vibro);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDPopup);
|
||||
}
|
||||
|
||||
void fuzzer_scene_main_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
|
||||
fuzzer_view_main_set_callback(app->main_view, fuzzer_scene_main_callback, app);
|
||||
|
||||
fuzzer_view_main_update_data(app->main_view, app->fuzzer_state);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = app->popup;
|
||||
// popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
|
||||
popup_set_timeout(popup, 2500);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, fuzzer_scene_main_error_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDMain);
|
||||
}
|
||||
|
||||
bool fuzzer_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
PacsFuzzerApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == FuzzerCustomEventViewMainBack) {
|
||||
if(!scene_manager_previous_scene(app->scene_manager)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == FuzzerCustomEventViewMainPopupErr) {
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDMain);
|
||||
consumed = true;
|
||||
} else if(event.event == FuzzerCustomEventViewMainOk) {
|
||||
fuzzer_view_main_get_state(app->main_view, &app->fuzzer_state);
|
||||
|
||||
// TODO error logic
|
||||
bool loading_ok = false;
|
||||
|
||||
switch(fuzzer_proto_get_attack_id_by_index(app->fuzzer_state.menu_index)) {
|
||||
case FuzzerAttackIdDefaultValues:
|
||||
loading_ok =
|
||||
fuzzer_worker_init_attack_dict(app->worker, app->fuzzer_state.proto_index);
|
||||
|
||||
if(!loading_ok) {
|
||||
// error
|
||||
fuzzer_scene_main_show_error(app, "Default dictionary\nis empty");
|
||||
}
|
||||
break;
|
||||
|
||||
case FuzzerAttackIdBFCustomerID:
|
||||
// TODO
|
||||
app->payload->data_size = fuzzer_proto_get_max_data_size();
|
||||
memset(app->payload->data, 0x00, app->payload->data_size);
|
||||
|
||||
if(fuzzer_worker_init_attack_bf_byte(
|
||||
app->worker, app->fuzzer_state.proto_index, app->payload, 0)) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
FuzzerSceneFieldEditor,
|
||||
FuzzerFieldEditorStateEditingOff);
|
||||
scene_manager_next_scene(app->scene_manager, FuzzerSceneFieldEditor);
|
||||
|
||||
} else {
|
||||
// error
|
||||
}
|
||||
break;
|
||||
|
||||
case FuzzerAttackIdLoadFile:
|
||||
if(!fuzzer_scene_main_load_key(app)) {
|
||||
break;
|
||||
} else {
|
||||
if(fuzzer_worker_load_key_from_file(
|
||||
app->worker,
|
||||
app->fuzzer_state.proto_index,
|
||||
furi_string_get_cstr(app->file_path))) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
FuzzerSceneFieldEditor,
|
||||
FuzzerFieldEditorStateEditingOn);
|
||||
scene_manager_next_scene(app->scene_manager, FuzzerSceneFieldEditor);
|
||||
FURI_LOG_I("Scene", "Load ok");
|
||||
} else {
|
||||
fuzzer_scene_main_show_error(app, "Unsupported protocol\nor broken file");
|
||||
FURI_LOG_W("Scene", "Load err");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FuzzerAttackIdLoadFileCustomUids:
|
||||
if(!fuzzer_scene_main_load_custom_dict(app)) {
|
||||
break;
|
||||
} else {
|
||||
loading_ok = fuzzer_worker_init_attack_file_dict(
|
||||
app->worker, app->fuzzer_state.proto_index, app->file_path);
|
||||
if(!loading_ok) {
|
||||
fuzzer_scene_main_show_error(app, "Incorrect key format\nor length");
|
||||
// error
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fuzzer_scene_main_show_error(app, "Unsuported attack");
|
||||
break;
|
||||
}
|
||||
|
||||
if(loading_ok) {
|
||||
scene_manager_next_scene(app->scene_manager, FuzzerSceneAttack);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void fuzzer_scene_main_on_exit(void* context) {
|
||||
// furi_assert(context);
|
||||
// PacsFuzzerApp* app = context;
|
||||
UNUSED(context);
|
||||
}
|
||||
44
applications/external/multi_fuzzer/todo.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
## Working Improvement
|
||||
|
||||
#### Quality of life
|
||||
|
||||
- [ ] Make the "Load File" independent of the current protocol
|
||||
- [x] Add pause
|
||||
- [ ] Switching UIDs if possible
|
||||
- [x] Led and sound Notification
|
||||
- [x] Led
|
||||
- [x] Vibro
|
||||
- [ ] Sound?
|
||||
- [x] Error Notification
|
||||
- [x] Custom UIDs dict loading
|
||||
- [x] Key file loading
|
||||
- [ ] Anything else
|
||||
|
||||
#### App functionality
|
||||
|
||||
- [x] Add `BFCustomerID` attack
|
||||
- [x] Add the ability to select index
|
||||
- [ ] Save key logic
|
||||
|
||||
## Code Improvement
|
||||
|
||||
- [ ] GUI
|
||||
- [x] Rewrite `gui_const` logic
|
||||
- [x] Icon in dialog
|
||||
- [x] Description and buttons in `field_editor` view
|
||||
- [ ] Protocol carousel in `main_menu`
|
||||
- [x] prototype
|
||||
- [x] Add the ability to edit emulation time and downtime separately
|
||||
- [x] Decide on the display
|
||||
- [x] UID
|
||||
- [x] Simplify the storage and exchange of `uids.data` `uid.data_size` in `views`
|
||||
- [x] Using `FuzzerPayload` to store the uid
|
||||
- [x] `UID_MAX_SIZE`
|
||||
- [x] Add pause
|
||||
- [x] Fix `Custom dict` attack when ended
|
||||
- [ ] Pause V2
|
||||
- [ ] Save logic
|
||||
- [ ] Switching UIDs if possible
|
||||
- [ ] Worker
|
||||
- [ ] Use `prtocol_id` instead of protocol name
|
||||
- [x] this can be simplified `fuzzer_proto_items`
|
||||
384
applications/external/multi_fuzzer/views/attack.c
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
#include "attack.h"
|
||||
#include "../fuzzer_i.h"
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define ATTACK_SCENE_MAX_UID_LENGTH 25
|
||||
#define UID_MAX_DISPLAYED_LEN (8U)
|
||||
#define LIFT_RIGHT_OFFSET (3)
|
||||
|
||||
struct FuzzerViewAttack {
|
||||
View* view;
|
||||
FuzzerViewAttackCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t time_delay; // 1 = 100ms
|
||||
uint8_t time_delay_min; // 1 = 100ms
|
||||
uint8_t emu_time; // 1 = 100ms
|
||||
uint8_t emu_time_min; // 1 = 100ms
|
||||
bool td_emt_cursor; // false - time_delay, true - emu_time
|
||||
const char* attack_name;
|
||||
const char* protocol_name;
|
||||
FuzzerAttackState attack_state;
|
||||
FuriString* uid_str;
|
||||
} FuzzerViewAttackModel;
|
||||
|
||||
void fuzzer_view_attack_reset_data(
|
||||
FuzzerViewAttack* view,
|
||||
const char* attack_name,
|
||||
const char* protocol_name) {
|
||||
furi_assert(view);
|
||||
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{
|
||||
model->attack_name = attack_name;
|
||||
model->protocol_name = protocol_name;
|
||||
model->attack_state = FuzzerAttackStateIdle;
|
||||
furi_string_set_str(model->uid_str, "Not_set");
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_set_uid(FuzzerViewAttack* view, const FuzzerPayload* uid) {
|
||||
furi_assert(view);
|
||||
furi_assert(uid->data);
|
||||
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{
|
||||
furi_string_printf(model->uid_str, "%02X", uid->data[0]);
|
||||
for(uint8_t i = 1; i < uid->data_size; i++) {
|
||||
furi_string_cat_printf(model->uid_str, ":%02X", uid->data[i]);
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_start(FuzzerViewAttack* view) {
|
||||
furi_assert(view);
|
||||
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{ model->attack_state = FuzzerAttackStateRunning; },
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_stop(FuzzerViewAttack* view) {
|
||||
furi_assert(view);
|
||||
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{ model->attack_state = FuzzerAttackStateOff; },
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_pause(FuzzerViewAttack* view) {
|
||||
furi_assert(view);
|
||||
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{ model->attack_state = FuzzerAttackStateIdle; },
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_end(FuzzerViewAttack* view) {
|
||||
furi_assert(view);
|
||||
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{ model->attack_state = FuzzerAttackStateEnd; },
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_set_callback(
|
||||
FuzzerViewAttack* view_attack,
|
||||
FuzzerViewAttackCallback callback,
|
||||
void* context) {
|
||||
furi_assert(view_attack);
|
||||
|
||||
view_attack->callback = callback;
|
||||
view_attack->context = context;
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_draw(Canvas* canvas, FuzzerViewAttackModel* model) {
|
||||
char temp_str[50];
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, model->attack_name);
|
||||
|
||||
uint16_t crt;
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
if(!model->td_emt_cursor) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(temp_str, sizeof(temp_str), "Time delay:");
|
||||
canvas_draw_str_aligned(canvas, LIFT_RIGHT_OFFSET, 21, AlignLeft, AlignBottom, temp_str);
|
||||
crt = canvas_string_width(canvas, temp_str);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(
|
||||
temp_str, sizeof(temp_str), "%d.%d", model->time_delay / 10, model->time_delay % 10);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, crt + LIFT_RIGHT_OFFSET + 3, 21, AlignLeft, AlignBottom, temp_str);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(
|
||||
temp_str, sizeof(temp_str), "EmT: %d.%d", model->emu_time / 10, model->emu_time % 10);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 128 - LIFT_RIGHT_OFFSET, 21, AlignRight, AlignBottom, temp_str);
|
||||
} else {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(
|
||||
temp_str,
|
||||
sizeof(temp_str),
|
||||
"TD: %d.%d",
|
||||
model->time_delay / 10,
|
||||
model->time_delay % 10);
|
||||
|
||||
canvas_draw_str_aligned(canvas, LIFT_RIGHT_OFFSET, 21, AlignLeft, AlignBottom, temp_str);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(temp_str, sizeof(temp_str), "%d.%d", model->emu_time / 10, model->emu_time % 10);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 128 - LIFT_RIGHT_OFFSET, 21, AlignRight, AlignBottom, temp_str);
|
||||
crt = canvas_string_width(canvas, temp_str);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(temp_str, sizeof(temp_str), "Emulation time:");
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 128 - LIFT_RIGHT_OFFSET - crt - 3, 21, AlignRight, AlignBottom, temp_str);
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, model->protocol_name);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
if(128 < canvas_string_width(canvas, furi_string_get_cstr(model->uid_str))) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
}
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 38, AlignCenter, AlignTop, furi_string_get_cstr(model->uid_str));
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(model->attack_state == FuzzerAttackStateRunning) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
} else if(model->attack_state == FuzzerAttackStateIdle) {
|
||||
if(model->td_emt_cursor) {
|
||||
elements_button_center(canvas, "Start");
|
||||
elements_button_left(canvas, "EmT -");
|
||||
elements_button_right(canvas, "+ EmT");
|
||||
} else {
|
||||
elements_button_center(canvas, "Start");
|
||||
elements_button_left(canvas, "TD -");
|
||||
elements_button_right(canvas, "+ TD");
|
||||
}
|
||||
|
||||
} else if(model->attack_state == FuzzerAttackStateEnd) {
|
||||
// elements_button_center(canvas, "Restart"); // Reset
|
||||
elements_button_left(canvas, "Exit");
|
||||
}
|
||||
}
|
||||
|
||||
bool fuzzer_view_attack_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
FuzzerViewAttack* view_attack = context;
|
||||
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
view_attack->callback(FuzzerCustomEventViewAttackBack, view_attack->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
view_attack->callback(FuzzerCustomEventViewAttackOk, view_attack->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
with_view_model(
|
||||
view_attack->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{
|
||||
if(model->attack_state == FuzzerAttackStateIdle) {
|
||||
if(!model->td_emt_cursor) {
|
||||
// TimeDelay --
|
||||
if(event->type == InputTypeShort) {
|
||||
if(model->time_delay > model->time_delay_min) {
|
||||
model->time_delay--;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
if((model->time_delay - 10) >= model->time_delay_min) {
|
||||
model->time_delay -= 10;
|
||||
} else {
|
||||
model->time_delay = model->time_delay_min;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// EmuTime --
|
||||
if(event->type == InputTypeShort) {
|
||||
if(model->emu_time > model->emu_time_min) {
|
||||
model->emu_time--;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
if((model->emu_time - 10) >= model->emu_time_min) {
|
||||
model->emu_time -= 10;
|
||||
} else {
|
||||
model->emu_time = model->emu_time_min;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(
|
||||
(model->attack_state == FuzzerAttackStateEnd) &&
|
||||
(event->type == InputTypeShort)) {
|
||||
// Exit if Ended
|
||||
view_attack->callback(FuzzerCustomEventViewAttackBack, view_attack->context);
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
with_view_model(
|
||||
view_attack->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{
|
||||
if(model->attack_state == FuzzerAttackStateIdle) {
|
||||
if(!model->td_emt_cursor) {
|
||||
// TimeDelay ++
|
||||
if(event->type == InputTypeShort) {
|
||||
if(model->time_delay < FUZZ_TIME_DELAY_MAX) {
|
||||
model->time_delay++;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
model->time_delay += 10;
|
||||
if(model->time_delay > FUZZ_TIME_DELAY_MAX) {
|
||||
model->time_delay = FUZZ_TIME_DELAY_MAX;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// EmuTime ++
|
||||
if(event->type == InputTypeShort) {
|
||||
if(model->emu_time < FUZZ_TIME_DELAY_MAX) {
|
||||
model->emu_time++;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
model->emu_time += 10;
|
||||
if(model->emu_time > FUZZ_TIME_DELAY_MAX) {
|
||||
model->emu_time = FUZZ_TIME_DELAY_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Nothing
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(
|
||||
(event->key == InputKeyUp || event->key == InputKeyDown) &&
|
||||
event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
view_attack->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{ model->td_emt_cursor = !model->td_emt_cursor; },
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_exit(void* context) {
|
||||
furi_assert(context);
|
||||
FuzzerViewAttack* view_attack = context;
|
||||
with_view_model(
|
||||
view_attack->view, FuzzerViewAttackModel * model, { model->td_emt_cursor = false; }, true);
|
||||
}
|
||||
|
||||
FuzzerViewAttack* fuzzer_view_attack_alloc() {
|
||||
if(fuzzer_proto_get_max_data_size() > UID_MAX_DISPLAYED_LEN) {
|
||||
furi_crash("Maximum of displayed bytes exceeded");
|
||||
}
|
||||
|
||||
FuzzerViewAttack* view_attack = malloc(sizeof(FuzzerViewAttack));
|
||||
|
||||
// View allocation and configuration
|
||||
view_attack->view = view_alloc();
|
||||
view_allocate_model(view_attack->view, ViewModelTypeLocking, sizeof(FuzzerViewAttackModel));
|
||||
view_set_context(view_attack->view, view_attack);
|
||||
view_set_draw_callback(view_attack->view, (ViewDrawCallback)fuzzer_view_attack_draw);
|
||||
view_set_input_callback(view_attack->view, fuzzer_view_attack_input);
|
||||
view_set_enter_callback(view_attack->view, fuzzer_view_attack_enter);
|
||||
view_set_exit_callback(view_attack->view, fuzzer_view_attack_exit);
|
||||
|
||||
with_view_model(
|
||||
view_attack->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{
|
||||
model->time_delay = fuzzer_proto_get_def_idle_time();
|
||||
model->time_delay_min = 0; // model->time_delay;
|
||||
|
||||
model->emu_time = fuzzer_proto_get_def_emu_time();
|
||||
|
||||
model->emu_time_min = 2; // model->emu_time;
|
||||
|
||||
model->uid_str = furi_string_alloc_set_str("Not_set");
|
||||
// malloc(ATTACK_SCENE_MAX_UID_LENGTH + 1);
|
||||
model->attack_state = FuzzerAttackStateOff;
|
||||
model->td_emt_cursor = false;
|
||||
|
||||
// strcpy(model->uid_str, "Not_set");
|
||||
model->attack_name = "Not_set";
|
||||
model->protocol_name = "Not_set";
|
||||
},
|
||||
true);
|
||||
return view_attack;
|
||||
}
|
||||
|
||||
void fuzzer_view_attack_free(FuzzerViewAttack* view_attack) {
|
||||
furi_assert(view_attack);
|
||||
|
||||
with_view_model(
|
||||
view_attack->view,
|
||||
FuzzerViewAttackModel * model,
|
||||
{ furi_string_free(model->uid_str); },
|
||||
true);
|
||||
view_free(view_attack->view);
|
||||
free(view_attack);
|
||||
}
|
||||
|
||||
View* fuzzer_view_attack_get_view(FuzzerViewAttack* view_attack) {
|
||||
furi_assert(view_attack);
|
||||
return view_attack->view;
|
||||
}
|
||||
|
||||
uint8_t fuzzer_view_attack_get_time_delay(FuzzerViewAttack* view) {
|
||||
furi_assert(view);
|
||||
uint8_t time_delay;
|
||||
|
||||
with_view_model(
|
||||
view->view, FuzzerViewAttackModel * model, { time_delay = model->time_delay; }, false);
|
||||
|
||||
return time_delay;
|
||||
}
|
||||
|
||||
uint8_t fuzzer_view_attack_get_emu_time(FuzzerViewAttack* view) {
|
||||
furi_assert(view);
|
||||
uint8_t emu_time;
|
||||
|
||||
with_view_model(
|
||||
view->view, FuzzerViewAttackModel * model, { emu_time = model->emu_time; }, false);
|
||||
|
||||
return emu_time;
|
||||
}
|
||||
42
applications/external/multi_fuzzer/views/attack.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#include "../helpers/fuzzer_custom_event.h"
|
||||
#include "../helpers/fuzzer_types.h"
|
||||
|
||||
#include "../lib/worker/protocol.h"
|
||||
|
||||
typedef struct FuzzerViewAttack FuzzerViewAttack;
|
||||
|
||||
typedef void (*FuzzerViewAttackCallback)(FuzzerCustomEvent event, void* context);
|
||||
|
||||
void fuzzer_view_attack_set_callback(
|
||||
FuzzerViewAttack* view_attack,
|
||||
FuzzerViewAttackCallback callback,
|
||||
void* context);
|
||||
|
||||
FuzzerViewAttack* fuzzer_view_attack_alloc();
|
||||
|
||||
void fuzzer_view_attack_free(FuzzerViewAttack* view_attack);
|
||||
|
||||
View* fuzzer_view_attack_get_view(FuzzerViewAttack* view_attack);
|
||||
|
||||
void fuzzer_view_attack_reset_data(
|
||||
FuzzerViewAttack* view,
|
||||
const char* attack_name,
|
||||
const char* protocol_name);
|
||||
|
||||
void fuzzer_view_attack_set_uid(FuzzerViewAttack* view, const FuzzerPayload* uid);
|
||||
|
||||
void fuzzer_view_attack_start(FuzzerViewAttack* view);
|
||||
|
||||
void fuzzer_view_attack_stop(FuzzerViewAttack* view);
|
||||
|
||||
void fuzzer_view_attack_pause(FuzzerViewAttack* view);
|
||||
|
||||
void fuzzer_view_attack_end(FuzzerViewAttack* view);
|
||||
|
||||
uint8_t fuzzer_view_attack_get_time_delay(FuzzerViewAttack* view);
|
||||
|
||||
uint8_t fuzzer_view_attack_get_emu_time(FuzzerViewAttack* view);
|
||||
358
applications/external/multi_fuzzer/views/field_editor.c
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
#include "field_editor.h"
|
||||
#include "../fuzzer_i.h"
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
#include <toolbox/hex.h>
|
||||
|
||||
#define FIELD_EDITOR_V2
|
||||
|
||||
#define GUI_DISPLAY_WIDTH 128
|
||||
#define GUI_DISPLAY_HEIGHT 64
|
||||
|
||||
#define GUI_DISPLAY_HORIZONTAL_CENTER 64
|
||||
#define GUI_DISPLAY_VERTICAL_CENTER 32
|
||||
|
||||
#define UID_STR_LENGTH 25
|
||||
|
||||
#ifdef FIELD_EDITOR_V2
|
||||
#define EDITOR_STRING_Y 38
|
||||
#else
|
||||
#define EDITOR_STRING_Y 50
|
||||
#endif
|
||||
|
||||
struct FuzzerViewFieldEditor {
|
||||
View* view;
|
||||
FuzzerViewFieldEditorCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t* uid;
|
||||
uint8_t uid_size;
|
||||
|
||||
FuriString* uid_str;
|
||||
|
||||
uint8_t index;
|
||||
bool lo;
|
||||
bool allow_edit;
|
||||
} FuzzerViewFieldEditorModel;
|
||||
|
||||
void fuzzer_view_field_editor_set_callback(
|
||||
FuzzerViewFieldEditor* view_edit,
|
||||
FuzzerViewFieldEditorCallback callback,
|
||||
void* context) {
|
||||
furi_assert(view_edit);
|
||||
|
||||
view_edit->callback = callback;
|
||||
view_edit->context = context;
|
||||
}
|
||||
|
||||
void fuzzer_view_field_editor_reset_data(
|
||||
FuzzerViewFieldEditor* view_edit,
|
||||
const FuzzerPayload* new_uid,
|
||||
bool allow_edit) {
|
||||
furi_assert(view_edit);
|
||||
furi_assert(new_uid->data);
|
||||
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
memcpy(model->uid, new_uid->data, new_uid->data_size);
|
||||
model->index = 0;
|
||||
model->lo = false;
|
||||
model->uid_size = new_uid->data_size;
|
||||
model->allow_edit = allow_edit;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_field_editor_get_uid(FuzzerViewFieldEditor* view_edit, FuzzerPayload* output_uid) {
|
||||
furi_assert(view_edit);
|
||||
furi_assert(output_uid);
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
output_uid->data_size = model->uid_size;
|
||||
memcpy(output_uid->data, model->uid, model->uid_size);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
uint8_t fuzzer_view_field_editor_get_index(FuzzerViewFieldEditor* view_edit) {
|
||||
furi_assert(view_edit);
|
||||
uint8_t index;
|
||||
with_view_model(
|
||||
view_edit->view, FuzzerViewFieldEditorModel * model, { index = model->index; }, true);
|
||||
return index;
|
||||
}
|
||||
|
||||
void fuzzer_view_field_editor_draw(Canvas* canvas, FuzzerViewFieldEditorModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
#ifdef FIELD_EDITOR_V2
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(model->allow_edit) {
|
||||
canvas_draw_icon(canvas, 2, 4, &I_ButtonLeft_4x7);
|
||||
canvas_draw_icon(canvas, 8, 4, &I_ButtonRight_4x7);
|
||||
|
||||
canvas_draw_icon_ex(canvas, 62, 3, &I_Pin_arrow_up_7x9, IconRotation180);
|
||||
canvas_draw_icon(canvas, 69, 3, &I_Pin_arrow_up_7x9);
|
||||
|
||||
canvas_draw_str(canvas, 14, 10, "select byte");
|
||||
canvas_draw_str(canvas, 79, 10, "adjust byte");
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 35, 4, &I_ButtonLeft_4x7);
|
||||
canvas_draw_icon(canvas, 41, 4, &I_ButtonRight_4x7);
|
||||
canvas_draw_str(canvas, 49, 10, "select byte");
|
||||
}
|
||||
|
||||
char msg_index[18];
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(msg_index, sizeof(msg_index), "Field index : %d", model->index);
|
||||
|
||||
canvas_draw_str_aligned(
|
||||
canvas, GUI_DISPLAY_HORIZONTAL_CENTER, 24, AlignCenter, AlignBottom, msg_index);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_icon(canvas, 4, 52, &I_Pin_back_arrow_10x8);
|
||||
canvas_draw_icon(canvas, 85, 52, &I_Ok_btn_9x9);
|
||||
|
||||
canvas_draw_str(canvas, 16, 60, "Back");
|
||||
canvas_draw_str(canvas, 96, 60, "Attack");
|
||||
#else
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
GUI_DISPLAY_HORIZONTAL_CENTER,
|
||||
5,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
"Left and right: select byte");
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
GUI_DISPLAY_HORIZONTAL_CENTER,
|
||||
15,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
"Up and down: adjust byte");
|
||||
|
||||
char msg_index[18];
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(msg_index, sizeof(msg_index), "Field index : %d", model->index);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, GUI_DISPLAY_HORIZONTAL_CENTER, 28, AlignCenter, AlignTop, msg_index);
|
||||
#endif
|
||||
// ####### Editor #######
|
||||
FuriString* temp_s = model->uid_str;
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
furi_string_reset(temp_s);
|
||||
for(int i = -3; i != 0; i++) {
|
||||
if(0 <= (model->index + i)) {
|
||||
furi_string_cat_printf(temp_s, "%02X ", model->uid[model->index + i]);
|
||||
}
|
||||
}
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 52, EDITOR_STRING_Y, AlignRight, AlignBottom, furi_string_get_cstr(temp_s));
|
||||
|
||||
furi_string_reset(temp_s);
|
||||
for(int i = 1; i != 4; i++) {
|
||||
if((model->index + i) < model->uid_size) {
|
||||
furi_string_cat_printf(temp_s, " %02X", model->uid[model->index + i]);
|
||||
}
|
||||
}
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 77, EDITOR_STRING_Y, AlignLeft, AlignBottom, furi_string_get_cstr(temp_s));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
furi_string_reset(temp_s);
|
||||
furi_string_cat_printf(temp_s, "<%02X>", model->uid[model->index]);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
GUI_DISPLAY_HORIZONTAL_CENTER,
|
||||
EDITOR_STRING_Y,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
furi_string_get_cstr(temp_s));
|
||||
|
||||
uint16_t w = canvas_string_width(canvas, furi_string_get_cstr(temp_s));
|
||||
w -= 11; // '<' & '>'
|
||||
w /= 2;
|
||||
|
||||
if(model->allow_edit) {
|
||||
if(model->lo) {
|
||||
canvas_draw_line(
|
||||
canvas,
|
||||
GUI_DISPLAY_HORIZONTAL_CENTER + 1,
|
||||
EDITOR_STRING_Y + 2,
|
||||
GUI_DISPLAY_HORIZONTAL_CENTER + w,
|
||||
EDITOR_STRING_Y + 2);
|
||||
} else {
|
||||
canvas_draw_line(
|
||||
canvas,
|
||||
GUI_DISPLAY_HORIZONTAL_CENTER - w,
|
||||
EDITOR_STRING_Y + 2,
|
||||
GUI_DISPLAY_HORIZONTAL_CENTER - 1,
|
||||
EDITOR_STRING_Y + 2);
|
||||
}
|
||||
} else {
|
||||
// canvas_draw_line(
|
||||
// canvas,
|
||||
// GUI_DISPLAY_HORIZONTAL_CENTER - w,
|
||||
// EDITOR_STRING_Y + 2,
|
||||
// GUI_DISPLAY_HORIZONTAL_CENTER + w,
|
||||
// EDITOR_STRING_Y + 2);
|
||||
}
|
||||
// ####### Editor #######
|
||||
}
|
||||
|
||||
bool fuzzer_view_field_editor_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
FuzzerViewFieldEditor* view_edit = context;
|
||||
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
view_edit->callback(FuzzerCustomEventViewFieldEditorBack, view_edit->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
view_edit->callback(FuzzerCustomEventViewFieldEditorOk, view_edit->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
if(event->type == InputTypeShort) {
|
||||
if(!model->allow_edit) {
|
||||
model->lo = false;
|
||||
}
|
||||
if(model->index > 0 || model->lo) {
|
||||
if(!model->lo) {
|
||||
model->index--;
|
||||
}
|
||||
model->lo = !model->lo;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
model->index = 0;
|
||||
model->lo = false;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
if(event->type == InputTypeShort) {
|
||||
if(!model->allow_edit) {
|
||||
model->lo = true;
|
||||
}
|
||||
if(model->index < (model->uid_size - 1) || !model->lo) {
|
||||
if(model->lo) {
|
||||
model->index++;
|
||||
}
|
||||
model->lo = !model->lo;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
model->index = model->uid_size - 1;
|
||||
model->lo = true;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
if(event->type == InputTypeShort && model->allow_edit) {
|
||||
if(model->lo) {
|
||||
model->uid[model->index] = (model->uid[model->index] & 0xF0) |
|
||||
((model->uid[model->index] + 1) & 0x0F);
|
||||
} else {
|
||||
model->uid[model->index] = ((model->uid[model->index] + 0x10) & 0xF0) |
|
||||
(model->uid[model->index] & 0x0F);
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
if(event->type == InputTypeShort && model->allow_edit) {
|
||||
if(model->lo) {
|
||||
model->uid[model->index] = (model->uid[model->index] & 0xF0) |
|
||||
((model->uid[model->index] - 1) & 0x0F);
|
||||
} else {
|
||||
model->uid[model->index] = ((model->uid[model->index] - 0x10) & 0xF0) |
|
||||
(model->uid[model->index] & 0x0F);
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fuzzer_view_field_editor_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void fuzzer_view_field_editor_exit(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
FuzzerViewFieldEditor* fuzzer_view_field_editor_alloc() {
|
||||
FuzzerViewFieldEditor* view_edit = malloc(sizeof(FuzzerViewFieldEditor));
|
||||
|
||||
// View allocation and configuration
|
||||
view_edit->view = view_alloc();
|
||||
view_allocate_model(view_edit->view, ViewModelTypeLocking, sizeof(FuzzerViewFieldEditorModel));
|
||||
view_set_context(view_edit->view, view_edit);
|
||||
view_set_draw_callback(view_edit->view, (ViewDrawCallback)fuzzer_view_field_editor_draw);
|
||||
view_set_input_callback(view_edit->view, fuzzer_view_field_editor_input);
|
||||
view_set_enter_callback(view_edit->view, fuzzer_view_field_editor_enter);
|
||||
view_set_exit_callback(view_edit->view, fuzzer_view_field_editor_exit);
|
||||
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
model->uid_str = furi_string_alloc();
|
||||
model->uid = malloc(fuzzer_proto_get_max_data_size());
|
||||
},
|
||||
true);
|
||||
|
||||
return view_edit;
|
||||
}
|
||||
|
||||
void fuzzer_view_field_editor_free(FuzzerViewFieldEditor* view_edit) {
|
||||
furi_assert(view_edit);
|
||||
|
||||
with_view_model(
|
||||
view_edit->view,
|
||||
FuzzerViewFieldEditorModel * model,
|
||||
{
|
||||
furi_string_free(model->uid_str);
|
||||
free(model->uid);
|
||||
},
|
||||
true);
|
||||
view_free(view_edit->view);
|
||||
free(view_edit);
|
||||
}
|
||||
|
||||
View* fuzzer_view_field_editor_get_view(FuzzerViewFieldEditor* view_edit) {
|
||||
furi_assert(view_edit);
|
||||
return view_edit->view;
|
||||
}
|
||||
29
applications/external/multi_fuzzer/views/field_editor.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/fuzzer_custom_event.h"
|
||||
#include "../lib/worker/protocol.h"
|
||||
|
||||
typedef struct FuzzerViewFieldEditor FuzzerViewFieldEditor;
|
||||
|
||||
typedef void (*FuzzerViewFieldEditorCallback)(FuzzerCustomEvent event, void* context);
|
||||
|
||||
void fuzzer_view_field_editor_set_callback(
|
||||
FuzzerViewFieldEditor* view_attack,
|
||||
FuzzerViewFieldEditorCallback callback,
|
||||
void* context);
|
||||
|
||||
FuzzerViewFieldEditor* fuzzer_view_field_editor_alloc();
|
||||
|
||||
void fuzzer_view_field_editor_free(FuzzerViewFieldEditor* view_attack);
|
||||
|
||||
View* fuzzer_view_field_editor_get_view(FuzzerViewFieldEditor* view_attack);
|
||||
|
||||
void fuzzer_view_field_editor_reset_data(
|
||||
FuzzerViewFieldEditor* view_edit,
|
||||
const FuzzerPayload* new_uid,
|
||||
bool allow_edit);
|
||||
|
||||
void fuzzer_view_field_editor_get_uid(FuzzerViewFieldEditor* view_edit, FuzzerPayload* output_uid);
|
||||
|
||||
uint8_t fuzzer_view_field_editor_get_index(FuzzerViewFieldEditor* view_edit);
|
||||
235
applications/external/multi_fuzzer/views/main_menu.c
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
#include "main_menu.h"
|
||||
#include "../fuzzer_i.h"
|
||||
|
||||
#include <input/input.h>
|
||||
|
||||
#include "../lib/worker/protocol.h"
|
||||
|
||||
#define PROTOCOL_NAME_Y 12
|
||||
// #define PROTOCOL_CAROUSEL
|
||||
|
||||
struct FuzzerViewMain {
|
||||
View* view;
|
||||
FuzzerViewMainCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t proto_index;
|
||||
uint8_t menu_index;
|
||||
uint8_t proto_max;
|
||||
uint8_t menu_max;
|
||||
} FuzzerViewMainModel;
|
||||
|
||||
void fuzzer_view_main_update_data(FuzzerViewMain* view, FuzzerState state) {
|
||||
furi_assert(view);
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewMainModel * model,
|
||||
{
|
||||
model->proto_index = state.proto_index;
|
||||
model->menu_index = state.menu_index;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_main_get_state(FuzzerViewMain* view, FuzzerState* state) {
|
||||
furi_assert(view);
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewMainModel * model,
|
||||
{
|
||||
state->proto_index = model->proto_index;
|
||||
state->menu_index = model->menu_index;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void fuzzer_view_main_set_callback(
|
||||
FuzzerViewMain* view,
|
||||
FuzzerViewMainCallback callback,
|
||||
void* context) {
|
||||
furi_assert(view);
|
||||
|
||||
view->callback = callback;
|
||||
view->context = context;
|
||||
}
|
||||
|
||||
void fuzzer_view_main_draw(Canvas* canvas, FuzzerViewMainModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(model->menu_index > 0) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
fuzzer_proto_get_menu_label(model->menu_index - 1));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 36, AlignCenter, AlignTop, fuzzer_proto_get_menu_label(model->menu_index));
|
||||
|
||||
if(model->menu_index < (model->menu_max - 1)) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
fuzzer_proto_get_menu_label(model->menu_index + 1));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, PROTOCOL_NAME_Y, AlignCenter, AlignBottom, "<");
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
PROTOCOL_NAME_Y,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
fuzzer_proto_get_name(model->proto_index));
|
||||
canvas_draw_str_aligned(canvas, 101, PROTOCOL_NAME_Y, AlignCenter, AlignBottom, ">");
|
||||
|
||||
#ifdef PROTOCOL_CAROUSEL
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
20,
|
||||
PROTOCOL_NAME_Y,
|
||||
AlignRight,
|
||||
AlignBottom,
|
||||
(model->proto_index > 0) ? fuzzer_proto_get_name(model->proto_index - 1) :
|
||||
fuzzer_proto_get_name((model->proto_max - 1)));
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
108,
|
||||
PROTOCOL_NAME_Y,
|
||||
AlignLeft,
|
||||
AlignBottom,
|
||||
(model->proto_index < (model->proto_max - 1)) ?
|
||||
fuzzer_proto_get_name(model->proto_index + 1) :
|
||||
fuzzer_proto_get_name(0));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fuzzer_view_main_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
FuzzerViewMain* view = context;
|
||||
|
||||
if(event->key == InputKeyBack &&
|
||||
(event->type == InputTypeLong || event->type == InputTypeShort)) {
|
||||
view->callback(FuzzerCustomEventViewMainBack, view->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
view->callback(FuzzerCustomEventViewMainOk, view->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyDown && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewMainModel * model,
|
||||
{
|
||||
if(model->menu_index < (model->menu_max - 1)) {
|
||||
model->menu_index++;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(event->key == InputKeyUp && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewMainModel * model,
|
||||
{
|
||||
if(model->menu_index != 0) {
|
||||
model->menu_index--;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewMainModel * model,
|
||||
{
|
||||
if(model->proto_index != 0) {
|
||||
model->proto_index--;
|
||||
} else {
|
||||
model->proto_index = (model->proto_max - 1);
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewMainModel * model,
|
||||
{
|
||||
if(model->proto_index == (model->proto_max - 1)) {
|
||||
model->proto_index = 0;
|
||||
} else {
|
||||
model->proto_index++;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fuzzer_view_main_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void fuzzer_view_main_exit(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
FuzzerViewMain* fuzzer_view_main_alloc() {
|
||||
FuzzerViewMain* view = malloc(sizeof(FuzzerViewMain));
|
||||
|
||||
// View allocation and configuration
|
||||
view->view = view_alloc();
|
||||
view_allocate_model(view->view, ViewModelTypeLocking, sizeof(FuzzerViewMainModel));
|
||||
view_set_context(view->view, view);
|
||||
view_set_draw_callback(view->view, (ViewDrawCallback)fuzzer_view_main_draw);
|
||||
view_set_input_callback(view->view, fuzzer_view_main_input);
|
||||
view_set_enter_callback(view->view, fuzzer_view_main_enter);
|
||||
view_set_exit_callback(view->view, fuzzer_view_main_exit);
|
||||
|
||||
with_view_model(
|
||||
view->view,
|
||||
FuzzerViewMainModel * model,
|
||||
{
|
||||
model->proto_index = 0;
|
||||
model->proto_max = fuzzer_proto_get_count_of_protocols();
|
||||
model->menu_index = 0;
|
||||
model->menu_max = fuzzer_proto_get_count_of_menu_items();
|
||||
},
|
||||
true);
|
||||
return view;
|
||||
}
|
||||
|
||||
void fuzzer_view_main_free(FuzzerViewMain* view) {
|
||||
furi_assert(view);
|
||||
|
||||
// with_view_model(
|
||||
// view->view,
|
||||
// FuzzerViewMainModel * model,
|
||||
// {
|
||||
|
||||
// },
|
||||
// true);
|
||||
view_free(view->view);
|
||||
free(view);
|
||||
}
|
||||
|
||||
View* fuzzer_view_main_get_view(FuzzerViewMain* view) {
|
||||
furi_assert(view);
|
||||
return view->view;
|
||||
}
|
||||
23
applications/external/multi_fuzzer/views/main_menu.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/fuzzer_custom_event.h"
|
||||
#include "../helpers/fuzzer_types.h"
|
||||
|
||||
typedef struct FuzzerViewMain FuzzerViewMain;
|
||||
|
||||
typedef void (*FuzzerViewMainCallback)(FuzzerCustomEvent event, void* context);
|
||||
|
||||
void fuzzer_view_main_set_callback(
|
||||
FuzzerViewMain* fuzzer_view_main,
|
||||
FuzzerViewMainCallback callback,
|
||||
void* context);
|
||||
|
||||
FuzzerViewMain* fuzzer_view_main_alloc();
|
||||
|
||||
void fuzzer_view_main_free(FuzzerViewMain* view);
|
||||
|
||||
View* fuzzer_view_main_get_view(FuzzerViewMain* view);
|
||||
|
||||
void fuzzer_view_main_update_data(FuzzerViewMain* view, FuzzerState state);
|
||||
void fuzzer_view_main_get_state(FuzzerViewMain* view, FuzzerState* state);
|
||||
@@ -19,7 +19,7 @@ void picopass_scene_device_info_on_enter(void* context) {
|
||||
FuriString* wiegand_str = furi_string_alloc();
|
||||
FuriString* sio_str = furi_string_alloc();
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Setup view
|
||||
PicopassBlock* AA1 = picopass->dev->dev_data.AA1;
|
||||
|
||||
@@ -10,7 +10,7 @@ void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context
|
||||
|
||||
void picopass_scene_read_card_on_enter(void* context) {
|
||||
Picopass* picopass = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
dolphin_deed(DolphinDeedNfcRead);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = picopass->popup;
|
||||
|
||||
@@ -21,7 +21,7 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
||||
FuriString* wiegand_str = furi_string_alloc();
|
||||
FuriString* sio_str = furi_string_alloc();
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Send notification
|
||||
notification_message(picopass->notifications, &sequence_success);
|
||||
|
||||
@@ -19,7 +19,7 @@ void picopass_scene_read_factory_success_on_enter(void* context) {
|
||||
FuriString* title = furi_string_alloc_set("Factory Default");
|
||||
FuriString* subtitle = furi_string_alloc_set("");
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Send notification
|
||||
notification_message(picopass->notifications, &sequence_success);
|
||||
|
||||
@@ -8,7 +8,7 @@ void picopass_scene_save_success_popup_callback(void* context) {
|
||||
|
||||
void picopass_scene_save_success_on_enter(void* context) {
|
||||
Picopass* picopass = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
||||
dolphin_deed(DolphinDeedNfcSave);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = picopass->popup;
|
||||
|
||||
@@ -9,7 +9,7 @@ void picopass_write_card_worker_callback(PicopassWorkerEvent event, void* contex
|
||||
|
||||
void picopass_scene_write_card_on_enter(void* context) {
|
||||
Picopass* picopass = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
||||
dolphin_deed(DolphinDeedNfcSave);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = picopass->popup;
|
||||
|
||||
@@ -18,7 +18,7 @@ void picopass_scene_write_card_success_on_enter(void* context) {
|
||||
Widget* widget = picopass->widget;
|
||||
FuriString* str = furi_string_alloc_set("Write Success!");
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Send notification
|
||||
notification_message(picopass->notifications, &sequence_success);
|
||||
|
||||
@@ -9,7 +9,7 @@ void picopass_write_key_worker_callback(PicopassWorkerEvent event, void* context
|
||||
|
||||
void picopass_scene_write_key_on_enter(void* context) {
|
||||
Picopass* picopass = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
||||
dolphin_deed(DolphinDeedNfcSave);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = picopass->popup;
|
||||
|
||||
@@ -48,8 +48,9 @@ bool save_signal(ProtoViewApp* app, const char* filename) {
|
||||
for(int j = 0; regs[j]; j += 2) {
|
||||
furi_string_cat_printf(custom, "%02X %02X ", (int)regs[j], (int)regs[j + 1]);
|
||||
}
|
||||
size_t len = furi_string_size(file_content);
|
||||
furi_string_set_char(custom, len - 1, '\n');
|
||||
//size_t len = furi_string_size(file_content);
|
||||
//furi_string_set_char(custom, len - 1, '\n');
|
||||
furi_string_cat(custom, "\n");
|
||||
furi_string_cat(file_content, custom);
|
||||
furi_string_free(custom);
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ int32_t snake_game_app(void* p) {
|
||||
|
||||
notification_message_block(notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
SnakeEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
|
||||
4
applications/external/solitaire/solitaire.c
vendored
@@ -276,7 +276,7 @@ void tick(GameState* game_state, NotificationApp* notification) {
|
||||
if(game_state->state == GameStatePlay) {
|
||||
if(game_state->top_cards[0].character == 11 && game_state->top_cards[1].character == 11 &&
|
||||
game_state->top_cards[2].character == 11 && game_state->top_cards[3].character == 11) {
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
dolphin_deed(DolphinDeedPluginGameWin);
|
||||
game_state->state = GameStateAnimate;
|
||||
return;
|
||||
}
|
||||
@@ -492,7 +492,7 @@ int32_t solitaire_app(void* p) {
|
||||
AppEvent event;
|
||||
|
||||
// Call Dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 150);
|
||||
|
||||
2
applications/external/subbrute
vendored
@@ -3130,7 +3130,7 @@ int32_t swd_probe_app_main(void* p) {
|
||||
DBGS("swd_execute_script");
|
||||
swd_execute_script(app, ANY_PATH("swd_scripts/startup.swd"));
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
DBGS("processing");
|
||||
for(bool processing = true; processing;) {
|
||||
|
||||
@@ -389,7 +389,7 @@ int32_t tetris_game_app() {
|
||||
uint8_t downRepeatCounter = 0;
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
// This 10U implicitly sets the game loop speed. downRepeatCounter relies on this value
|
||||
|
||||
@@ -333,7 +333,7 @@ int32_t tictactoe_game_app(void* p) {
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
|
||||
2
applications/external/totp/totp_app.c
vendored
@@ -173,7 +173,7 @@ int32_t totp_app() {
|
||||
}
|
||||
|
||||
// Affecting dolphin level
|
||||
DOLPHIN_DEED(DolphinDeedPluginStart);
|
||||
dolphin_deed(DolphinDeedPluginStart);
|
||||
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
3
applications/external/unitemp/Sensors.c
vendored
@@ -78,7 +78,8 @@ const Interface SPI = {
|
||||
static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT20, &DHT21, &DHT22,
|
||||
&Dallas, &AM2320_SW, &AM2320_I2C, &HTU21x, &AHT10,
|
||||
&SHT30, &GXHT30, &LM75, &HDC1080, &BMP180,
|
||||
&BMP280, &BME280, &BME680, &MAX31855, &MAX6675};
|
||||
&BMP280, &BME280, &BME680, &MAX31855, &MAX6675,
|
||||
&SCD30};
|
||||
|
||||
const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) {
|
||||
if(index > SENSOR_TYPES_COUNT) return NULL;
|
||||
|
||||
5
applications/external/unitemp/Sensors.h
vendored
@@ -24,6 +24,7 @@
|
||||
#define UT_TEMPERATURE 0b00000001
|
||||
#define UT_HUMIDITY 0b00000010
|
||||
#define UT_PRESSURE 0b00000100
|
||||
#define UT_CO2 0b00001000
|
||||
|
||||
//Статусы опроса датчика
|
||||
typedef enum {
|
||||
@@ -31,6 +32,7 @@ typedef enum {
|
||||
UT_DATA_TYPE_TEMP_HUM = UT_TEMPERATURE | UT_HUMIDITY,
|
||||
UT_DATA_TYPE_TEMP_PRESS = UT_TEMPERATURE | UT_PRESSURE,
|
||||
UT_DATA_TYPE_TEMP_HUM_PRESS = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE,
|
||||
UT_DATA_TYPE_TEMP_HUM_CO2 = UT_TEMPERATURE | UT_HUMIDITY | UT_CO2,
|
||||
} SensorDataType;
|
||||
|
||||
//Типы возвращаемых данных
|
||||
@@ -121,6 +123,8 @@ typedef struct Sensor {
|
||||
float hum;
|
||||
//Атмосферное давление
|
||||
float pressure;
|
||||
// Концентрация CO2
|
||||
float co2;
|
||||
//Тип датчика
|
||||
const SensorType* type;
|
||||
//Статус последнего опроса датчика
|
||||
@@ -329,4 +333,5 @@ const GPIO*
|
||||
#include "./sensors/HDC1080.h"
|
||||
#include "./sensors/MAX31855.h"
|
||||
#include "./sensors/MAX6675.h"
|
||||
#include "./sensors/SCD30.h"
|
||||
#endif
|
||||
|
||||
BIN
applications/external/unitemp/assets/co2_11x14.png
vendored
Normal file
|
After Width: | Height: | Size: 176 B |
438
applications/external/unitemp/sensors/SCD30.c
vendored
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
Unitemp - Universal temperature reader
|
||||
Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
|
||||
Contributed by divinebird (https://github.com/divinebird)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Some information may be seen on https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
|
||||
|
||||
#include "SCD30.h"
|
||||
#include "../interfaces/I2CSensor.h"
|
||||
//#include <3rdparty/everest/include/everest/kremlin/c_endianness.h>
|
||||
|
||||
inline static uint16_t load16(uint8_t* b) {
|
||||
uint16_t x;
|
||||
memcpy(&x, b, 2);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline static uint32_t load32(uint8_t* b) {
|
||||
uint32_t x;
|
||||
memcpy(&x, b, 4);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline static void store16(uint8_t* b, uint16_t i) {
|
||||
memcpy(b, &i, 2);
|
||||
}
|
||||
|
||||
inline static void store32(uint8_t* b, uint32_t i) {
|
||||
memcpy(b, &i, 4);
|
||||
}
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define htobe16(x) (x)
|
||||
#define htobe32(x) (x)
|
||||
#define htole16(x) __builtin_bswap16(x)
|
||||
#define htole32(x) __builtin_bswap32(x)
|
||||
#define be16toh(x) (x)
|
||||
#define be32toh(x) (x)
|
||||
#define le16toh(x) __builtin_bswap16(x)
|
||||
#define le32toh(x) __builtin_bswap32(x)
|
||||
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define htobe16(x) __builtin_bswap16(x)
|
||||
#define htobe32(x) __builtin_bswap32(x)
|
||||
#define htole16(x) (x)
|
||||
#define htole32(x) (x)
|
||||
#define be16toh(x) __builtin_bswap16(x)
|
||||
#define be32toh(x) __builtin_bswap32(x)
|
||||
#define le16toh(x) (x)
|
||||
#define le32toh(x) (x)
|
||||
#else
|
||||
#error "What kind of system is this?"
|
||||
#endif
|
||||
|
||||
#define load16_le(b) (le16toh(load16(b)))
|
||||
#define load32_le(b) (le32toh(load32(b)))
|
||||
#define store16_le(b, i) (store16(b, htole16(i)))
|
||||
#define store32_le(b, i) (store32(b, htole32(i)))
|
||||
|
||||
#define load16_be(b) (be16toh(load16(b)))
|
||||
#define load32_be(b) (be32toh(load32(b)))
|
||||
#define store16_be(b, i) (store16(b, htobe16(i)))
|
||||
#define store32_be(b, i) (store32(b, htobe32(i)))
|
||||
|
||||
typedef union {
|
||||
uint16_t array16[2];
|
||||
uint8_t array8[4];
|
||||
float value;
|
||||
} ByteToFl;
|
||||
|
||||
bool unitemp_SCD30_alloc(Sensor* sensor, char* args);
|
||||
bool unitemp_SCD30_init(Sensor* sensor);
|
||||
bool unitemp_SCD30_deinit(Sensor* sensor);
|
||||
UnitempStatus unitemp_SCD30_update(Sensor* sensor);
|
||||
bool unitemp_SCD30_free(Sensor* sensor);
|
||||
|
||||
const SensorType SCD30 = {
|
||||
.typename = "SCD30",
|
||||
.interface = &I2C,
|
||||
.datatype = UT_DATA_TYPE_TEMP_HUM_CO2,
|
||||
.pollingInterval = 2000,
|
||||
.allocator = unitemp_SCD30_alloc,
|
||||
.mem_releaser = unitemp_SCD30_free,
|
||||
.initializer = unitemp_SCD30_init,
|
||||
.deinitializer = unitemp_SCD30_deinit,
|
||||
.updater = unitemp_SCD30_update};
|
||||
|
||||
#define SCD30_ID 0x61
|
||||
|
||||
#define COMMAND_CONTINUOUS_MEASUREMENT 0x0010
|
||||
#define COMMAND_SET_MEASUREMENT_INTERVAL 0x4600
|
||||
#define COMMAND_GET_DATA_READY 0x0202
|
||||
#define COMMAND_READ_MEASUREMENT 0x0300
|
||||
#define COMMAND_AUTOMATIC_SELF_CALIBRATION 0x5306
|
||||
#define COMMAND_SET_FORCED_RECALIBRATION_FACTOR 0x5204
|
||||
#define COMMAND_SET_TEMPERATURE_OFFSET 0x5403
|
||||
#define COMMAND_SET_ALTITUDE_COMPENSATION 0x5102
|
||||
#define COMMAND_RESET 0xD304 // Soft reset
|
||||
#define COMMAND_STOP_MEAS 0x0104
|
||||
#define COMMAND_READ_FW_VER 0xD100
|
||||
|
||||
static bool dataAvailable(Sensor* sensor) __attribute__((unused));
|
||||
static bool readMeasurement(Sensor* sensor) __attribute__((unused));
|
||||
static void reset(Sensor* sensor) __attribute__((unused));
|
||||
|
||||
static bool setAutoSelfCalibration(Sensor* sensor, bool enable) __attribute__((unused));
|
||||
static bool getAutoSelfCalibration(Sensor* sensor) __attribute__((unused));
|
||||
|
||||
static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) __attribute__((unused));
|
||||
|
||||
static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration)
|
||||
__attribute__((unused));
|
||||
static uint16_t getAltitudeCompensation(Sensor* sensor) __attribute__((unused));
|
||||
static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) __attribute__((unused));
|
||||
static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) __attribute__((unused));
|
||||
|
||||
static float getTemperatureOffset(Sensor* sensor) __attribute__((unused));
|
||||
static bool setTemperatureOffset(Sensor* sensor, float tempOffset) __attribute__((unused));
|
||||
|
||||
static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset)
|
||||
__attribute__((unused));
|
||||
static bool beginMeasuring(Sensor* sensor) __attribute__((unused));
|
||||
static bool stopMeasurement(Sensor* sensor) __attribute__((unused));
|
||||
|
||||
static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) __attribute__((unused));
|
||||
static uint16_t getMeasurementInterval(Sensor* sensor) __attribute__((unused));
|
||||
|
||||
bool unitemp_SCD30_alloc(Sensor* sensor, char* args) {
|
||||
UNUSED(args);
|
||||
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
|
||||
|
||||
i2c_sensor->minI2CAdr = SCD30_ID << 1;
|
||||
i2c_sensor->maxI2CAdr = SCD30_ID << 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unitemp_SCD30_free(Sensor* sensor) {
|
||||
//Нечего высвобождать, так как ничего не было выделено
|
||||
UNUSED(sensor);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unitemp_SCD30_init(Sensor* sensor) {
|
||||
if(beginMeasuring(sensor) == true) { // Start continuous measurements
|
||||
setMeasurementInterval(sensor, SCD30.pollingInterval / 1000);
|
||||
setAutoSelfCalibration(sensor, true);
|
||||
setAmbientPressure(sensor, 0);
|
||||
} else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unitemp_SCD30_deinit(Sensor* sensor) {
|
||||
return stopMeasurement(sensor);
|
||||
}
|
||||
|
||||
UnitempStatus unitemp_SCD30_update(Sensor* sensor) {
|
||||
readMeasurement(sensor);
|
||||
return UT_SENSORSTATUS_OK;
|
||||
}
|
||||
|
||||
static uint8_t computeCRC8(uint8_t* message, uint8_t len) {
|
||||
uint8_t crc = 0xFF; // Init with 0xFF
|
||||
for(uint8_t x = 0; x < len; x++) {
|
||||
crc ^= message[x]; // XOR-in the next input byte
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
if((crc & 0x80) != 0)
|
||||
crc = (uint8_t)((crc << 1) ^ 0x31);
|
||||
else
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
return crc; // No output reflection
|
||||
}
|
||||
|
||||
// Sends a command along with arguments and CRC
|
||||
static bool sendCommandWithCRC(Sensor* sensor, uint16_t command, uint16_t arguments) {
|
||||
static const uint8_t cmdSize = 5;
|
||||
|
||||
uint8_t bytes[cmdSize];
|
||||
uint8_t* pointer = bytes;
|
||||
store16_be(pointer, command);
|
||||
pointer += 2;
|
||||
uint8_t* argPos = pointer;
|
||||
store16_be(pointer, arguments);
|
||||
pointer += 2;
|
||||
*pointer = computeCRC8(argPos, pointer - argPos);
|
||||
|
||||
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
|
||||
return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes);
|
||||
}
|
||||
|
||||
// Sends just a command, no arguments, no CRC
|
||||
static bool sendCommand(Sensor* sensor, uint16_t command) {
|
||||
static const uint8_t cmdSize = 2;
|
||||
|
||||
uint8_t bytes[cmdSize];
|
||||
store16_be(bytes, command);
|
||||
|
||||
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
|
||||
return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes);
|
||||
}
|
||||
|
||||
static uint16_t readRegister(Sensor* sensor, uint16_t registerAddress) {
|
||||
static const uint8_t regSize = 2;
|
||||
|
||||
if(!sendCommand(sensor, registerAddress)) return 0; // Sensor did not ACK
|
||||
|
||||
furi_delay_ms(3);
|
||||
|
||||
uint8_t bytes[regSize];
|
||||
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
|
||||
if(!unitemp_i2c_readArray(i2c_sensor, regSize, bytes)) return 0;
|
||||
|
||||
return load16_be(bytes);
|
||||
}
|
||||
|
||||
static bool loadWord(uint8_t* buff, uint16_t* val) {
|
||||
uint16_t tmp = load16_be(buff);
|
||||
uint8_t expectedCRC = computeCRC8(buff, 2);
|
||||
if(buff[2] != expectedCRC) return false;
|
||||
*val = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getSettingValue(Sensor* sensor, uint16_t registerAddress, uint16_t* val) {
|
||||
static const uint8_t respSize = 3;
|
||||
|
||||
if(!sendCommand(sensor, registerAddress)) return false; // Sensor did not ACK
|
||||
|
||||
furi_delay_ms(3);
|
||||
|
||||
uint8_t bytes[respSize];
|
||||
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
|
||||
if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) return false;
|
||||
|
||||
return loadWord(bytes, val);
|
||||
}
|
||||
|
||||
static bool loadFloat(uint8_t* buff, float* val) {
|
||||
// ByteToFl tmp;
|
||||
size_t cntr = 0;
|
||||
uint8_t floatBuff[4];
|
||||
for(size_t i = 0; i < 2; i++) {
|
||||
floatBuff[cntr++] = buff[0];
|
||||
floatBuff[cntr++] = buff[1];
|
||||
uint8_t expectedCRC = computeCRC8(buff, 2);
|
||||
if(buff[2] != expectedCRC) return false;
|
||||
buff += 3;
|
||||
}
|
||||
uint32_t tmpVal = load32_be(floatBuff);
|
||||
memcpy(val, &tmpVal, sizeof(float));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get 18 bytes from SCD30
|
||||
// Updates global variables with floats
|
||||
// Returns true if success
|
||||
static bool readMeasurement(Sensor* sensor) {
|
||||
// Verify we have data from the sensor
|
||||
if(!dataAvailable(sensor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) {
|
||||
FURI_LOG_E(APP_NAME, "Sensor did not ACK");
|
||||
return false; // Sensor did not ACK
|
||||
}
|
||||
|
||||
float tempCO2 = 0;
|
||||
float tempHumidity = 0;
|
||||
float tempTemperature = 0;
|
||||
|
||||
furi_delay_ms(3);
|
||||
|
||||
static const uint8_t respSize = 18;
|
||||
uint8_t buff[respSize];
|
||||
uint8_t* bytes = buff;
|
||||
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
|
||||
if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) {
|
||||
FURI_LOG_E(APP_NAME, "Error while read measures");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
if(loadFloat(bytes, &tempCO2)) {
|
||||
sensor->co2 = tempCO2;
|
||||
} else {
|
||||
FURI_LOG_E(APP_NAME, "Error while parsing CO2");
|
||||
error = true;
|
||||
}
|
||||
|
||||
bytes += 6;
|
||||
if(loadFloat(bytes, &tempTemperature)) {
|
||||
sensor->temp = tempTemperature;
|
||||
} else {
|
||||
FURI_LOG_E(APP_NAME, "Error while parsing temp");
|
||||
error = true;
|
||||
}
|
||||
|
||||
bytes += 6;
|
||||
if(loadFloat(bytes, &tempHumidity)) {
|
||||
sensor->hum = tempHumidity;
|
||||
} else {
|
||||
FURI_LOG_E(APP_NAME, "Error while parsing humidity");
|
||||
error = true;
|
||||
}
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
static void reset(Sensor* sensor) {
|
||||
sendCommand(sensor, COMMAND_RESET);
|
||||
}
|
||||
|
||||
static bool setAutoSelfCalibration(Sensor* sensor, bool enable) {
|
||||
return sendCommandWithCRC(
|
||||
sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION, enable); // Activate continuous ASC
|
||||
}
|
||||
|
||||
// Get the current ASC setting
|
||||
static bool getAutoSelfCalibration(Sensor* sensor) {
|
||||
return 1 == readRegister(sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION);
|
||||
}
|
||||
|
||||
static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) {
|
||||
return getSettingValue(sensor, COMMAND_READ_FW_VER, val);
|
||||
}
|
||||
|
||||
// Set the forced recalibration factor. See 1.3.7.
|
||||
// The reference CO2 concentration has to be within the range 400 ppm ≤ cref(CO2) ≤ 2000 ppm.
|
||||
static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration) {
|
||||
if(concentration < 400 || concentration > 2000) {
|
||||
return false; // Error check.
|
||||
}
|
||||
return sendCommandWithCRC(sensor, COMMAND_SET_FORCED_RECALIBRATION_FACTOR, concentration);
|
||||
}
|
||||
|
||||
// Get the temperature offset. See 1.3.8.
|
||||
static float getTemperatureOffset(Sensor* sensor) {
|
||||
union {
|
||||
int16_t signed16;
|
||||
uint16_t unsigned16;
|
||||
} signedUnsigned; // Avoid any ambiguity casting int16_t to uint16_t
|
||||
signedUnsigned.unsigned16 = readRegister(sensor, COMMAND_SET_TEMPERATURE_OFFSET);
|
||||
|
||||
return ((float)signedUnsigned.signed16) / 100.0;
|
||||
}
|
||||
|
||||
static bool setTemperatureOffset(Sensor* sensor, float tempOffset) {
|
||||
// Temp offset is only positive. See: https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/issues/27#issuecomment-971986826
|
||||
//"The SCD30 offset temperature is obtained by subtracting the reference temperature from the SCD30 output temperature"
|
||||
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD30_Low_Power_Mode.pdf
|
||||
|
||||
if(tempOffset < 0.0) return false;
|
||||
|
||||
uint16_t value = tempOffset * 100;
|
||||
|
||||
return sendCommandWithCRC(sensor, COMMAND_SET_TEMPERATURE_OFFSET, value);
|
||||
}
|
||||
|
||||
// Get the altitude compenstation. See 1.3.9.
|
||||
static uint16_t getAltitudeCompensation(Sensor* sensor) {
|
||||
return readRegister(sensor, COMMAND_SET_ALTITUDE_COMPENSATION);
|
||||
}
|
||||
|
||||
// Set the altitude compenstation. See 1.3.9.
|
||||
static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) {
|
||||
return sendCommandWithCRC(sensor, COMMAND_SET_ALTITUDE_COMPENSATION, altitude);
|
||||
}
|
||||
|
||||
// Set the pressure compenstation. This is passed during measurement startup.
|
||||
// mbar can be 700 to 1200
|
||||
static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) {
|
||||
if(pressure_mbar != 0 || pressure_mbar < 700 || pressure_mbar > 1200) {
|
||||
return false;
|
||||
}
|
||||
return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressure_mbar);
|
||||
}
|
||||
|
||||
// Begins continuous measurements
|
||||
// Continuous measurement status is saved in non-volatile memory. When the sensor
|
||||
// is powered down while continuous measurement mode is active SCD30 will measure
|
||||
// continuously after repowering without sending the measurement command.
|
||||
// Returns true if successful
|
||||
static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset) {
|
||||
return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressureOffset);
|
||||
}
|
||||
|
||||
// Overload - no pressureOffset
|
||||
static bool beginMeasuring(Sensor* sensor) {
|
||||
return beginMeasuringWithSettings(sensor, 0);
|
||||
}
|
||||
|
||||
// Stop continuous measurement
|
||||
static bool stopMeasurement(Sensor* sensor) {
|
||||
return sendCommand(sensor, COMMAND_STOP_MEAS);
|
||||
}
|
||||
|
||||
// Sets interval between measurements
|
||||
// 2 seconds to 1800 seconds (30 minutes)
|
||||
static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) {
|
||||
if(interval < 2 || interval > 1800) return false;
|
||||
if(!sendCommandWithCRC(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, interval)) return false;
|
||||
uint16_t verInterval = readRegister(sensor, COMMAND_SET_MEASUREMENT_INTERVAL);
|
||||
if(verInterval != interval) {
|
||||
FURI_LOG_E(APP_NAME, "Measure interval wrong! Val: %02x", verInterval);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gets interval between measurements
|
||||
// 2 seconds to 1800 seconds (30 minutes)
|
||||
static uint16_t getMeasurementInterval(Sensor* sensor) {
|
||||
uint16_t interval = 0;
|
||||
getSettingValue(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, &interval);
|
||||
return interval;
|
||||
}
|
||||
|
||||
// Returns true when data is available
|
||||
static bool dataAvailable(Sensor* sensor) {
|
||||
return 1 == readRegister(sensor, COMMAND_GET_DATA_READY);
|
||||
}
|
||||
59
applications/external/unitemp/sensors/SCD30.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Unitemp - Universal temperature reader
|
||||
Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
|
||||
Contributed by divinebird (https://github.com/divinebird)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef UNITEMP_SCD30
|
||||
#define UNITEMP_SCD30
|
||||
|
||||
#include "../unitemp.h"
|
||||
#include "../Sensors.h"
|
||||
|
||||
extern const SensorType SCD30;
|
||||
/**
|
||||
* @brief Выделение памяти и установка начальных значений датчика SCD30
|
||||
* @param sensor Указатель на создаваемый датчик
|
||||
* @return Истина при успехе
|
||||
*/
|
||||
bool unitemp_SCD30_alloc(Sensor* sensor, char* args);
|
||||
|
||||
/**
|
||||
* @brief Инициализации датчика SCD30
|
||||
* @param sensor Указатель на датчик
|
||||
* @return Истина если инициализация упспешная
|
||||
*/
|
||||
bool unitemp_SCD30_init(Sensor* sensor);
|
||||
|
||||
/**
|
||||
* @brief Деинициализация датчика
|
||||
* @param sensor Указатель на датчик
|
||||
*/
|
||||
bool unitemp_SCD30_deinit(Sensor* sensor);
|
||||
|
||||
/**
|
||||
* @brief Обновление значений из датчика
|
||||
* @param sensor Указатель на датчик
|
||||
* @return Статус опроса датчика
|
||||
*/
|
||||
UnitempStatus unitemp_SCD30_update(Sensor* sensor);
|
||||
|
||||
/**
|
||||
* @brief Высвободить память датчика
|
||||
* @param sensor Указатель на датчик
|
||||
*/
|
||||
bool unitemp_SCD30_free(Sensor* sensor);
|
||||
|
||||
#endif
|
||||
2
applications/external/unitemp/unitemp.h
vendored
@@ -40,7 +40,7 @@
|
||||
//Имя приложения
|
||||
#define APP_NAME "Unitemp"
|
||||
//Версия приложения
|
||||
#define UNITEMP_APP_VER "1.2"
|
||||
#define UNITEMP_APP_VER "1.3"
|
||||
//Путь хранения файлов плагина
|
||||
#define APP_PATH_FOLDER "/ext/unitemp"
|
||||
//Имя файла с настройками
|
||||
|
||||
@@ -162,6 +162,35 @@ static void _draw_pressure(Canvas* canvas, Sensor* sensor) {
|
||||
}
|
||||
}
|
||||
|
||||
static void _draw_co2(Canvas* canvas, Sensor* sensor, Color color) {
|
||||
const uint8_t x = 29, y = 39;
|
||||
//Рисование рамки
|
||||
canvas_draw_rframe(canvas, x, y, 75, 20, 3);
|
||||
if(color == ColorBlack) {
|
||||
canvas_draw_rbox(canvas, x, y, 75, 19, 3);
|
||||
canvas_invert_color(canvas);
|
||||
} else {
|
||||
canvas_draw_rframe(canvas, x, y, 75, 19, 3);
|
||||
}
|
||||
|
||||
//Рисование иконки
|
||||
canvas_draw_icon(canvas, x + 3, y + 3, &I_co2_11x14);
|
||||
|
||||
int16_t concentration_int = sensor->co2;
|
||||
// int8_t concentration_dec = (int16_t)(sensor->co2 * 10) % 10;
|
||||
|
||||
//Целая часть
|
||||
if(concentration_int > 9999) {
|
||||
snprintf(app->buff, BUFF_SIZE, "MAX ");
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
} else {
|
||||
snprintf(app->buff, BUFF_SIZE, "%d", concentration_int);
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, x + 70, y + 10, AlignRight, AlignCenter, app->buff);
|
||||
}
|
||||
|
||||
static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
@@ -320,6 +349,17 @@ static void _draw_carousel_values(Canvas* canvas) {
|
||||
canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
|
||||
_draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
|
||||
break;
|
||||
case UT_DATA_TYPE_TEMP_HUM_CO2:
|
||||
_draw_temperature(
|
||||
canvas,
|
||||
unitemp_sensor_getActive(generalview_sensor_index),
|
||||
temp_positions[2][0],
|
||||
temp_positions[2][1],
|
||||
ColorWhite);
|
||||
_draw_humidity(
|
||||
canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
|
||||
_draw_co2(canvas, unitemp_sensor_getActive(generalview_sensor_index), ColorWhite);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
365
applications/external/weather_station/protocols/oregon3.c
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
#include "oregon3.h"
|
||||
|
||||
#include <lib/subghz/blocks/const.h>
|
||||
#include <lib/subghz/blocks/decoder.h>
|
||||
#include <lib/subghz/blocks/encoder.h>
|
||||
#include <lib/subghz/blocks/math.h>
|
||||
#include "ws_generic.h"
|
||||
|
||||
#include <lib/toolbox/manchester_decoder.h>
|
||||
#include <lib/flipper_format/flipper_format_i.h>
|
||||
|
||||
#define TAG "WSProtocolOregon3"
|
||||
|
||||
static const SubGhzBlockConst ws_oregon3_const = {
|
||||
.te_long = 1100,
|
||||
.te_short = 500,
|
||||
.te_delta = 300,
|
||||
.min_count_bit_for_found = 32,
|
||||
};
|
||||
|
||||
#define OREGON3_PREAMBLE_BITS 28
|
||||
#define OREGON3_PREAMBLE_MASK 0b1111111111111111111111111111
|
||||
// 24 ones + 0101 (inverted A)
|
||||
#define OREGON3_PREAMBLE 0b1111111111111111111111110101
|
||||
|
||||
// Fixed part contains:
|
||||
// - Sensor type: 16 bits
|
||||
// - Channel: 4 bits
|
||||
// - ID (changes when batteries are changed): 8 bits
|
||||
// - Battery status: 4 bits
|
||||
#define OREGON3_FIXED_PART_BITS (16 + 4 + 8 + 4)
|
||||
#define OREGON3_SENSOR_ID(d) (((d) >> 16) & 0xFFFF)
|
||||
#define OREGON3_CHECKSUM_BITS 8
|
||||
|
||||
// bit indicating the low battery
|
||||
#define OREGON3_FLAG_BAT_LOW 0x4
|
||||
|
||||
/// Documentation for Oregon Scientific protocols can be found here:
|
||||
/// https://www.osengr.org/Articles/OS-RF-Protocols-IV.pdf
|
||||
// Sensors ID
|
||||
#define ID_THGR221 0xf824
|
||||
|
||||
struct WSProtocolDecoderOregon3 {
|
||||
SubGhzProtocolDecoderBase base;
|
||||
|
||||
SubGhzBlockDecoder decoder;
|
||||
WSBlockGeneric generic;
|
||||
ManchesterState manchester_state;
|
||||
bool prev_bit;
|
||||
|
||||
uint8_t var_bits;
|
||||
uint64_t var_data;
|
||||
};
|
||||
|
||||
typedef struct WSProtocolDecoderOregon3 WSProtocolDecoderOregon3;
|
||||
|
||||
typedef enum {
|
||||
Oregon3DecoderStepReset = 0,
|
||||
Oregon3DecoderStepFoundPreamble,
|
||||
Oregon3DecoderStepVarData,
|
||||
} Oregon3DecoderStep;
|
||||
|
||||
void* ws_protocol_decoder_oregon3_alloc(SubGhzEnvironment* environment) {
|
||||
UNUSED(environment);
|
||||
WSProtocolDecoderOregon3* instance = malloc(sizeof(WSProtocolDecoderOregon3));
|
||||
instance->base.protocol = &ws_protocol_oregon3;
|
||||
instance->generic.protocol_name = instance->base.protocol->name;
|
||||
instance->generic.humidity = WS_NO_HUMIDITY;
|
||||
instance->generic.temp = WS_NO_TEMPERATURE;
|
||||
instance->generic.btn = WS_NO_BTN;
|
||||
instance->generic.channel = WS_NO_CHANNEL;
|
||||
instance->generic.battery_low = WS_NO_BATT;
|
||||
instance->generic.id = WS_NO_ID;
|
||||
instance->prev_bit = false;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ws_protocol_decoder_oregon3_free(void* context) {
|
||||
furi_assert(context);
|
||||
WSProtocolDecoderOregon3* instance = context;
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void ws_protocol_decoder_oregon3_reset(void* context) {
|
||||
furi_assert(context);
|
||||
WSProtocolDecoderOregon3* instance = context;
|
||||
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||
instance->decoder.decode_data = 0UL;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
manchester_advance(
|
||||
instance->manchester_state, ManchesterEventReset, &instance->manchester_state, NULL);
|
||||
instance->prev_bit = false;
|
||||
instance->var_data = 0;
|
||||
instance->var_bits = 0;
|
||||
}
|
||||
|
||||
static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) {
|
||||
bool is_long = false;
|
||||
|
||||
if(DURATION_DIFF(duration, ws_oregon3_const.te_long) < ws_oregon3_const.te_delta) {
|
||||
is_long = true;
|
||||
} else if(DURATION_DIFF(duration, ws_oregon3_const.te_short) < ws_oregon3_const.te_delta) {
|
||||
is_long = false;
|
||||
} else {
|
||||
return ManchesterEventReset;
|
||||
}
|
||||
|
||||
if(level)
|
||||
return is_long ? ManchesterEventLongHigh : ManchesterEventShortHigh;
|
||||
else
|
||||
return is_long ? ManchesterEventLongLow : ManchesterEventShortLow;
|
||||
}
|
||||
|
||||
// From sensor id code return amount of bits in variable section
|
||||
// https://temofeev.ru/info/articles/o-dekodirovanii-protokola-pogodnykh-datchikov-oregon-scientific
|
||||
static uint8_t oregon3_sensor_id_var_bits(uint16_t sensor_id) {
|
||||
switch(sensor_id) {
|
||||
case ID_THGR221:
|
||||
default:
|
||||
// nibbles: temp + hum + '0'
|
||||
return (4 + 2 + 1) * 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void ws_oregon3_decode_const_data(WSBlockGeneric* ws_block) {
|
||||
ws_block->id = OREGON3_SENSOR_ID(ws_block->data);
|
||||
ws_block->channel = (ws_block->data >> 12) & 0xF;
|
||||
ws_block->battery_low = (ws_block->data & OREGON3_FLAG_BAT_LOW) ? 1 : 0;
|
||||
}
|
||||
|
||||
static uint16_t ws_oregon3_bcd_decode_short(uint32_t data) {
|
||||
return (data & 0xF) * 10 + ((data >> 4) & 0xF);
|
||||
}
|
||||
|
||||
static float ws_oregon3_decode_temp(uint32_t data) {
|
||||
int32_t temp_val;
|
||||
temp_val = ws_oregon3_bcd_decode_short(data >> 4);
|
||||
temp_val *= 10;
|
||||
temp_val += (data >> 12) & 0xF;
|
||||
if(data & 0xF) temp_val = -temp_val;
|
||||
return (float)temp_val / 10.0;
|
||||
}
|
||||
|
||||
static void ws_oregon3_decode_var_data(WSBlockGeneric* ws_b, uint16_t sensor_id, uint32_t data) {
|
||||
switch(sensor_id) {
|
||||
case ID_THGR221:
|
||||
default:
|
||||
ws_b->humidity = ws_oregon3_bcd_decode_short(data >> 4);
|
||||
ws_b->temp = ws_oregon3_decode_temp(data >> 12);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ws_protocol_decoder_oregon3_feed(void* context, bool level, uint32_t duration) {
|
||||
furi_assert(context);
|
||||
WSProtocolDecoderOregon3* instance = context;
|
||||
// Oregon v3.0 protocol is inverted
|
||||
ManchesterEvent event = level_and_duration_to_event(!level, duration);
|
||||
|
||||
// low-level bit sequence decoding
|
||||
if(event == ManchesterEventReset) {
|
||||
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||
instance->prev_bit = false;
|
||||
instance->decoder.decode_data = 0UL;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
}
|
||||
if(manchester_advance(
|
||||
instance->manchester_state, event, &instance->manchester_state, &instance->prev_bit)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, instance->prev_bit);
|
||||
}
|
||||
|
||||
switch(instance->decoder.parser_step) {
|
||||
case Oregon3DecoderStepReset:
|
||||
// waiting for fixed oregon3 preamble
|
||||
if(instance->decoder.decode_count_bit >= OREGON3_PREAMBLE_BITS &&
|
||||
((instance->decoder.decode_data & OREGON3_PREAMBLE_MASK) == OREGON3_PREAMBLE)) {
|
||||
instance->decoder.parser_step = Oregon3DecoderStepFoundPreamble;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
instance->decoder.decode_data = 0UL;
|
||||
}
|
||||
break;
|
||||
case Oregon3DecoderStepFoundPreamble:
|
||||
// waiting for fixed oregon3 data
|
||||
if(instance->decoder.decode_count_bit == OREGON3_FIXED_PART_BITS) {
|
||||
instance->generic.data = instance->decoder.decode_data;
|
||||
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
|
||||
instance->decoder.decode_data = 0UL;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
|
||||
// reverse nibbles in decoded data as oregon v3.0 is LSB first
|
||||
instance->generic.data = (instance->generic.data & 0x55555555) << 1 |
|
||||
(instance->generic.data & 0xAAAAAAAA) >> 1;
|
||||
instance->generic.data = (instance->generic.data & 0x33333333) << 2 |
|
||||
(instance->generic.data & 0xCCCCCCCC) >> 2;
|
||||
|
||||
ws_oregon3_decode_const_data(&instance->generic);
|
||||
instance->var_bits =
|
||||
oregon3_sensor_id_var_bits(OREGON3_SENSOR_ID(instance->generic.data));
|
||||
|
||||
if(!instance->var_bits) {
|
||||
// sensor is not supported, stop decoding, but showing the decoded fixed part
|
||||
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||
if(instance->base.callback)
|
||||
instance->base.callback(&instance->base, instance->base.context);
|
||||
} else {
|
||||
instance->decoder.parser_step = Oregon3DecoderStepVarData;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Oregon3DecoderStepVarData:
|
||||
// waiting for variable (sensor-specific data)
|
||||
if(instance->decoder.decode_count_bit == instance->var_bits + OREGON3_CHECKSUM_BITS) {
|
||||
instance->var_data = instance->decoder.decode_data & 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
// reverse nibbles in var data
|
||||
instance->var_data = (instance->var_data & 0x5555555555555555) << 1 |
|
||||
(instance->var_data & 0xAAAAAAAAAAAAAAAA) >> 1;
|
||||
instance->var_data = (instance->var_data & 0x3333333333333333) << 2 |
|
||||
(instance->var_data & 0xCCCCCCCCCCCCCCCC) >> 2;
|
||||
|
||||
ws_oregon3_decode_var_data(
|
||||
&instance->generic,
|
||||
OREGON3_SENSOR_ID(instance->generic.data),
|
||||
instance->var_data >> OREGON3_CHECKSUM_BITS);
|
||||
|
||||
instance->decoder.parser_step = Oregon3DecoderStepReset;
|
||||
if(instance->base.callback)
|
||||
instance->base.callback(&instance->base, instance->base.context);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ws_protocol_decoder_oregon3_get_hash_data(void* context) {
|
||||
furi_assert(context);
|
||||
WSProtocolDecoderOregon3* instance = context;
|
||||
return subghz_protocol_blocks_get_hash_data(
|
||||
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
|
||||
}
|
||||
|
||||
SubGhzProtocolStatus ws_protocol_decoder_oregon3_serialize(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
SubGhzRadioPreset* preset) {
|
||||
furi_assert(context);
|
||||
WSProtocolDecoderOregon3* instance = context;
|
||||
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
|
||||
ret = ws_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||
if(ret != SubGhzProtocolStatusOk) return ret;
|
||||
uint32_t temp = instance->var_bits;
|
||||
if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) {
|
||||
FURI_LOG_E(TAG, "Error adding VarBits");
|
||||
return SubGhzProtocolStatusErrorParserOthers;
|
||||
}
|
||||
if(!flipper_format_write_hex(
|
||||
flipper_format,
|
||||
"VarData",
|
||||
(const uint8_t*)&instance->var_data,
|
||||
sizeof(instance->var_data))) {
|
||||
FURI_LOG_E(TAG, "Error adding VarData");
|
||||
return SubGhzProtocolStatusErrorParserOthers;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SubGhzProtocolStatus
|
||||
ws_protocol_decoder_oregon3_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||
furi_assert(context);
|
||||
WSProtocolDecoderOregon3* instance = context;
|
||||
uint32_t temp_data;
|
||||
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
|
||||
do {
|
||||
ret = ws_block_generic_deserialize(&instance->generic, flipper_format);
|
||||
if(ret != SubGhzProtocolStatusOk) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) {
|
||||
FURI_LOG_E(TAG, "Missing VarLen");
|
||||
ret = SubGhzProtocolStatusErrorParserOthers;
|
||||
break;
|
||||
}
|
||||
instance->var_bits = (uint8_t)temp_data;
|
||||
if(!flipper_format_read_hex(
|
||||
flipper_format,
|
||||
"VarData",
|
||||
(uint8_t*)&instance->var_data,
|
||||
sizeof(instance->var_data))) { //-V1051
|
||||
FURI_LOG_E(TAG, "Missing VarData");
|
||||
ret = SubGhzProtocolStatusErrorParserOthers;
|
||||
break;
|
||||
}
|
||||
if(instance->generic.data_count_bit != ws_oregon3_const.min_count_bit_for_found) {
|
||||
FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit);
|
||||
ret = SubGhzProtocolStatusErrorValueBitCount;
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void oregon3_append_check_sum(uint32_t fix_data, uint64_t var_data, FuriString* output) {
|
||||
uint8_t sum = fix_data & 0xF;
|
||||
uint8_t ref_sum = var_data & 0xFF;
|
||||
var_data >>= 4;
|
||||
|
||||
for(uint8_t i = 1; i < 8; i++) {
|
||||
fix_data >>= 4;
|
||||
var_data >>= 4;
|
||||
sum += (fix_data & 0xF) + (var_data & 0xF);
|
||||
}
|
||||
|
||||
// swap calculated sum nibbles
|
||||
sum = (((sum >> 4) & 0xF) | (sum << 4)) & 0xFF;
|
||||
if(sum == ref_sum)
|
||||
furi_string_cat_printf(output, "Sum ok: 0x%hhX", ref_sum);
|
||||
else
|
||||
furi_string_cat_printf(output, "Sum err: 0x%hhX vs 0x%hhX", ref_sum, sum);
|
||||
}
|
||||
|
||||
void ws_protocol_decoder_oregon3_get_string(void* context, FuriString* output) {
|
||||
furi_assert(context);
|
||||
WSProtocolDecoderOregon3* instance = context;
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"%s\r\n"
|
||||
"ID: 0x%04lX, ch: %d, bat: %d, rc: 0x%02lX\r\n",
|
||||
instance->generic.protocol_name,
|
||||
instance->generic.id,
|
||||
instance->generic.channel,
|
||||
instance->generic.battery_low,
|
||||
(uint32_t)(instance->generic.data >> 4) & 0xFF);
|
||||
|
||||
if(instance->var_bits > 0) {
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"Temp:%d.%d C Hum:%d%%",
|
||||
(int16_t)instance->generic.temp,
|
||||
abs(
|
||||
((int16_t)(instance->generic.temp * 10) -
|
||||
(((int16_t)instance->generic.temp) * 10))),
|
||||
instance->generic.humidity);
|
||||
oregon3_append_check_sum((uint32_t)instance->generic.data, instance->var_data, output);
|
||||
}
|
||||
}
|
||||
|
||||
const SubGhzProtocolDecoder ws_protocol_oregon3_decoder = {
|
||||
.alloc = ws_protocol_decoder_oregon3_alloc,
|
||||
.free = ws_protocol_decoder_oregon3_free,
|
||||
|
||||
.feed = ws_protocol_decoder_oregon3_feed,
|
||||
.reset = ws_protocol_decoder_oregon3_reset,
|
||||
|
||||
.get_hash_data = ws_protocol_decoder_oregon3_get_hash_data,
|
||||
.serialize = ws_protocol_decoder_oregon3_serialize,
|
||||
.deserialize = ws_protocol_decoder_oregon3_deserialize,
|
||||
.get_string = ws_protocol_decoder_oregon3_get_string,
|
||||
};
|
||||
|
||||
const SubGhzProtocol ws_protocol_oregon3 = {
|
||||
.name = WS_PROTOCOL_OREGON3_NAME,
|
||||
.type = SubGhzProtocolWeatherStation,
|
||||
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
|
||||
|
||||
.decoder = &ws_protocol_oregon3_decoder,
|
||||
};
|
||||