mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-18 00:38:10 -07:00
Merge branch 'dev' of github.com:Eng1n33r/flipperzero-firmware into feat/playlist
This commit is contained in:
+4
-3
@@ -36,6 +36,7 @@ steps:
|
||||
- mkdir -p sd-card/nfc/assets
|
||||
- mkdir -p sd-card/infrared/assets
|
||||
- mkdir -p sd-card/unirf
|
||||
- mkdir -p sd-card/rfidfuzzer
|
||||
- mkdir -p sd-card/badusb/layouts
|
||||
- cp assets/resources/badusb/layouts/* sd-card/badusb/layouts/
|
||||
- cp assets/resources/subghz/assets/dangerous_settings sd-card/subghz/assets/dangerous_settings
|
||||
@@ -44,9 +45,11 @@ steps:
|
||||
- cp assets/resources/nfc/assets/mf_classic_dict.nfc sd-card/nfc/assets/mf_classic_dict.nfc
|
||||
- cp assets/resources/infrared/assets/tv.ir sd-card/infrared/assets/tv.ir
|
||||
- cp assets/resources/infrared/assets/ac.ir sd-card/infrared/assets/ac.ir
|
||||
- cp assets/resources/infrared/assets/fans.ir sd-card/infrared/assets/fans.ir
|
||||
- cp assets/resources/infrared/assets/projectors.ir sd-card/infrared/assets/projectors.ir
|
||||
- cp assets/resources/infrared/assets/audio.ir sd-card/infrared/assets/audio.ir
|
||||
- cp assets/resources/unirf/unirf_map_example.txt sd-card/unirf/unirf_map_example.txt
|
||||
- cp assets/resources/rfidfuzzer/example_uids.txt sd-card/rfidfuzzer/example_uids.txt
|
||||
- cp assets/resources/Manifest sd-card/Manifest
|
||||
- zip -r artifacts-default/sd-card-${DRONE_TAG}.zip sd-card
|
||||
- rm -rf sd-card
|
||||
@@ -115,9 +118,7 @@ steps:
|
||||
|
||||
[-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})"
|
||||
document:
|
||||
- artifacts-default/flipper-z-f7-full-${DRONE_TAG}.dfu
|
||||
- artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip
|
||||
- artifacts-default/sd-card-${DRONE_TAG}.zip
|
||||
- artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz
|
||||
|
||||
- name: "Send discord notification"
|
||||
image: appleboy/drone-discord
|
||||
|
||||
+4
-18
@@ -1,24 +1,10 @@
|
||||
### New changes
|
||||
* New universal remote for projectors
|
||||
* OFW: New LF-RFID subsystem (New protocols, Animal tags support)
|
||||
* Updated universal remote assets (by @Amec0e)
|
||||
* Renamed UniRF Remix -> Sub-GHz Remote
|
||||
* Replaced Hex/Dec converter with Multi Converter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
|
||||
* New update screen, readme pictures (by @Svaarich)
|
||||
* Fixed crash if Center button is pressed on the "update success" screen via screensharing
|
||||
* Temporary disabled one log call in picopass plugin to fix crash/freeze on Read screen
|
||||
* OFW: Picopass load/info/delete
|
||||
* OFW: SubGhz: add protocol Magellen
|
||||
* OFW: Fix mifare ultralight/ntag unlock
|
||||
* OFW: Dolphin level thresholds update
|
||||
* OFW: Add MFC 1/4K 4/7bUID to "Add Manually"
|
||||
* OFW: Other fixes and changes
|
||||
* Actually fix universal tv remote
|
||||
* bt and lfrfid tune debug apps excluded from releases
|
||||
|
||||
**Note: Prefer installing using web updater or by self update package, all needed assets will be installed**
|
||||
**Note: To avoid issues prefer installing using web updater or by self update package, all needed assets will be installed**
|
||||
|
||||
**Build naming has been changed - all same as before but `cg - codegrabber` changed to `un - unleashed`**
|
||||
|
||||
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip`
|
||||
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app
|
||||
|
||||
DFU for update using qFlipper - `flipper-z-f7-full-(version).dfu`
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
Welcome to Flipper Zero's Custom Firmware repo!
|
||||
### Welcome to Flipper Zero Unleashed Firmware repo!
|
||||
Our goal is to make any features possible in this device without any limitations!
|
||||
|
||||
Please help us implement emulation for all subghz dynamic (rolling code) protocols and static code brute-force app!
|
||||
Please help us implement emulation for all subghz dynamic (rolling code) protocols!
|
||||
|
||||
<br>
|
||||
|
||||
@@ -27,25 +27,26 @@ Our Discord Community:
|
||||
* SubGHz frequecy range can be extended in settings file (Warning: It can damage flipper's hardware)
|
||||
* Many rolling code protocols now have the ability to save & send captured signals
|
||||
* FAAC SLH (Spa) & BFT Mitto (secure with seed) manual creation
|
||||
* Sub-GHz static code brute-force plugin
|
||||
* LFRFID Fuzzer plugin
|
||||
* Custom community plugins and games added
|
||||
* Extra SubGHz frequencies + extra Mifare Classic keys
|
||||
* Picopass/iClass plugin included in releases
|
||||
* Recompiled IR TV Universal Remote for ALL buttons
|
||||
* Universal A/C and Audio(soundbars, etc.) remote
|
||||
* Universal remote for Projectors
|
||||
* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.)
|
||||
* BadUSB keyboard layouts
|
||||
* Customizable Flipper name
|
||||
* Other small fixes and changes throughout
|
||||
|
||||
See changelog in releases for latest updates!
|
||||
|
||||
### Current modified and new SubGhz protocols list:
|
||||
### Current modified and new SubGHz protocols list:
|
||||
- HCS101
|
||||
- An-Motors
|
||||
- CAME Atomo
|
||||
- FAAC SLH (Spa) [if cloning existing remote - external seed calculation required]
|
||||
- BFT Mitto [if cloning existing remote - external seed calculation required]
|
||||
- Keeloq (+ proper manufacturer codes selection) [Not ALL systems supported yet!]
|
||||
- FAAC SLH (Spa) [External seed calculation required]
|
||||
- BFT Mitto [External seed calculation required]
|
||||
- Keeloq [Not ALL systems supported yet!]
|
||||
- Nice Flor S
|
||||
- Security+ v1 & v2
|
||||
- Star Line
|
||||
@@ -56,10 +57,10 @@ See changelog in releases for latest updates!
|
||||
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
|
||||
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
|
||||
|
||||
**Big thanks to all sponsors!**
|
||||
|
||||
### Community apps included:
|
||||
|
||||
- RFID Fuzzer plugin [(by Ganapati)](https://github.com/Eng1n33r/flipperzero-firmware/pull/54) with some changes by xMasterX
|
||||
- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/Eng1n33r/flipperzero-firmware/pull/57)
|
||||
- ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module)
|
||||
- WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module)
|
||||
- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
|
||||
@@ -68,8 +69,8 @@ See changelog in releases for latest updates!
|
||||
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
|
||||
- ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion)
|
||||
- NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker)
|
||||
- Simple Clock (fixed) !! New version WIP, wait for updates !! [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
|
||||
- UniversalRF Remix (with changes)(only RAW subghz files) [(by ESurge)(Original UniversalRF by jimilinuxguy)](https://github.com/ESurge/flipperzero-firmware-unirfremix)
|
||||
- Simple Clock (fixed) [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
|
||||
- UniversalRF Remix / Sub-GHz Remote [(by ESurge)](https://github.com/ESurge/flipperzero-firmware-unirfremix)[(updated and all protocol support added by darmiel & xMasterX)](https://github.com/darmiel/flipper-playlist/tree/feat/unirf-protocols)
|
||||
- Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game)
|
||||
- Spectrum Analyzer (with changes) [(by jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman)
|
||||
- Arkanoid (with fixes) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Main Fipper Build System entry point
|
||||
# Main Flipper Build System entry point
|
||||
#
|
||||
# This file is evaluated by scons (the build system) every time fbt is invoked.
|
||||
# Scons constructs all referenced environments & their targets' dependency
|
||||
@@ -15,7 +15,7 @@ DefaultEnvironment(tools=[])
|
||||
# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15)
|
||||
|
||||
|
||||
# This environment is created only for loading options & validating file/dir existance
|
||||
# This environment is created only for loading options & validating file/dir existence
|
||||
fbt_variables = SConscript("site_scons/commandline.scons")
|
||||
cmd_environment = Environment(tools=[], variables=fbt_variables)
|
||||
Help(fbt_variables.GenerateHelpText(cmd_environment))
|
||||
|
||||
Executable → Regular
@@ -11,7 +11,7 @@ App(
|
||||
provides=[
|
||||
"bt_start",
|
||||
"bt_settings",
|
||||
"bt_debug",
|
||||
#"bt_debug",
|
||||
],
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -281,6 +281,9 @@ void cli_command_free(Cli* cli, string_t args, void* context) {
|
||||
printf("Total heap size: %d\r\n", memmgr_get_total_heap());
|
||||
printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap());
|
||||
printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block());
|
||||
|
||||
printf("Pool free: %d\r\n", memmgr_pool_get_free());
|
||||
printf("Maximum pool block: %d\r\n", memmgr_pool_get_max_block());
|
||||
}
|
||||
|
||||
void cli_command_free_blocks(Cli* cli, string_t args, void* context) {
|
||||
|
||||
Executable → Regular
@@ -15,6 +15,16 @@ App(
|
||||
],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="debug_apps_lite",
|
||||
name="Basic debug apps bundle",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"usb_mouse",
|
||||
"uart_echo",
|
||||
],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="blink_test",
|
||||
name="Blink Test",
|
||||
|
||||
@@ -46,4 +46,5 @@ typedef struct {
|
||||
PinCode pin_code;
|
||||
uint8_t is_locked;
|
||||
uint32_t auto_lock_delay_ms;
|
||||
uint8_t displayBatteryPercentage;
|
||||
} DesktopSettings;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define SCENE_EVENT_SELECT_FAVORITE_SECONDARY 1
|
||||
#define SCENE_EVENT_SELECT_PIN_SETUP 2
|
||||
#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 3
|
||||
#define SCENE_EVENT_SELECT_BATTERY_DISPLAY 4
|
||||
|
||||
#define AUTO_LOCK_DELAY_COUNT 9
|
||||
const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
|
||||
@@ -25,11 +26,31 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
|
||||
const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] =
|
||||
{0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000};
|
||||
|
||||
#define BATTERY_VIEW_COUNT 5
|
||||
|
||||
const char* const battery_view_count_text[BATTERY_VIEW_COUNT] = {
|
||||
"Bar",
|
||||
"%",
|
||||
"Inv. %",
|
||||
"Retro 3",
|
||||
"Retro 5",
|
||||
};
|
||||
|
||||
const uint32_t displayBatteryPercentage_value[BATTERY_VIEW_COUNT] = {0, 1, 2, 3, 4};
|
||||
|
||||
static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void desktop_settings_scene_start_battery_view_changed(VariableItem* item) {
|
||||
DesktopSettingsApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, battery_view_count_text[index]);
|
||||
app->settings.displayBatteryPercentage = index;
|
||||
}
|
||||
|
||||
static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) {
|
||||
DesktopSettingsApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
@@ -65,6 +86,20 @@ void desktop_settings_scene_start_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Battery View",
|
||||
BATTERY_VIEW_COUNT,
|
||||
desktop_settings_scene_start_battery_view_changed,
|
||||
app);
|
||||
|
||||
value_index = value_index_uint32(
|
||||
app->settings.displayBatteryPercentage,
|
||||
displayBatteryPercentage_value,
|
||||
BATTERY_VIEW_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, battery_view_count_text[value_index]);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
|
||||
}
|
||||
|
||||
@@ -91,6 +126,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
|
||||
case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY:
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_SELECT_BATTERY_DISPLAY:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
|
||||
@@ -16,7 +16,7 @@ struct DesktopMainView {
|
||||
TimerHandle_t poweroff_timer;
|
||||
};
|
||||
|
||||
#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 3000
|
||||
#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 2000
|
||||
|
||||
static void desktop_main_poweroff_timer_callback(TimerHandle_t timer) {
|
||||
DesktopMainView* main_view = pvTimerGetTimerID(timer);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -0,0 +1,21 @@
|
||||
# Flipfrid
|
||||
|
||||
Basic EM4100 Fuzzer
|
||||
|
||||
## Why
|
||||
|
||||
Flipfrid is a simple Rfid fuzzer using EM4100 protocol (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.
|
||||
|
||||
## How
|
||||
|
||||
There is 4 modes :
|
||||
- Default key loop over 16 factory/default keys and emulate each one after one ;
|
||||
- BF customer id. just an iteration from 0X00 to 0XFF on the first byte ;
|
||||
- Load Dump file : Load an existing EM4100 dump generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF;
|
||||
- Uids list: loop over a text file (one uid per line)
|
||||
|
||||
TODO :
|
||||
- blank screen on back press
|
||||
@@ -0,0 +1,10 @@
|
||||
App(
|
||||
appid="flipfrid",
|
||||
name="RFID Fuzzer",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="flipfrid_start",
|
||||
cdefines=["APP_FLIP_FRID"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=13,
|
||||
)
|
||||
@@ -0,0 +1,258 @@
|
||||
#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) {
|
||||
FlipFridState* flipfrid_state = (FlipFridState*)acquire_mutex((ValueMutex*)ctx, 100);
|
||||
|
||||
if(flipfrid_state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
release_mutex((ValueMutex*)ctx, flipfrid_state);
|
||||
}
|
||||
|
||||
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));
|
||||
string_init(flipfrid->notification_msg);
|
||||
string_init(flipfrid->attack_name);
|
||||
|
||||
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->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->payload[0] = 0x00;
|
||||
flipfrid->payload[1] = 0x00;
|
||||
flipfrid->payload[2] = 0x00;
|
||||
flipfrid->payload[3] = 0x00;
|
||||
flipfrid->payload[4] = 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
|
||||
string_clear(flipfrid->notification_msg);
|
||||
string_clear(flipfrid->attack_name);
|
||||
|
||||
free(flipfrid->data);
|
||||
free(flipfrid->payload);
|
||||
|
||||
// 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();
|
||||
ValueMutex flipfrid_state_mutex;
|
||||
|
||||
// Mutex
|
||||
FURI_LOG_I(TAG, "Initializing flipfrid mutex");
|
||||
if(!init_mutex(&flipfrid_state_mutex, flipfrid_state, sizeof(FlipFridState))) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
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_mutex);
|
||||
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);
|
||||
flipfrid_free(flipfrid_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <input/input.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include "m-string.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 <lib/lfrfid/lfrfid_worker.h>
|
||||
#include <lfrfid/protocols/lfrfid_protocols.h>
|
||||
|
||||
#define TAG "FlipFrid"
|
||||
|
||||
typedef enum {
|
||||
FlipFridAttackDefaultValues,
|
||||
FlipFridAttackBfCustomerId,
|
||||
FlipFridAttackLoadFile,
|
||||
FlipFridAttackLoadFileCustomUids,
|
||||
} FlipFridAttacks;
|
||||
|
||||
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 {
|
||||
bool is_running;
|
||||
bool is_attacking;
|
||||
FlipFridScene current_scene;
|
||||
FlipFridScene previous_scene;
|
||||
NotificationApp* notify;
|
||||
u_int8_t menu_index;
|
||||
|
||||
string_t data_str;
|
||||
uint8_t data[5];
|
||||
uint8_t payload[5];
|
||||
uint8_t attack_step;
|
||||
FlipFridAttacks attack;
|
||||
string_t attack_name;
|
||||
|
||||
DialogsApp* dialogs;
|
||||
string_t notification_msg;
|
||||
uint8_t key_index;
|
||||
LFRFIDWorker* worker;
|
||||
ProtocolDict* dict;
|
||||
ProtocolId protocol;
|
||||
|
||||
// Used for custom dictionnary
|
||||
Stream* uids_stream;
|
||||
} FlipFridState;
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
string_t menu_items[4];
|
||||
|
||||
void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t index) {
|
||||
switch(index) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
context->attack = FlipFridAttackDefaultValues;
|
||||
context->current_scene = SceneAttack;
|
||||
string_set_str(context->attack_name, "Default Values");
|
||||
break;
|
||||
case FlipFridAttackBfCustomerId:
|
||||
context->attack = FlipFridAttackBfCustomerId;
|
||||
context->current_scene = SceneAttack;
|
||||
string_set_str(context->attack_name, "Bad Customer ID");
|
||||
break;
|
||||
case FlipFridAttackLoadFile:
|
||||
context->attack = FlipFridAttackLoadFile;
|
||||
context->current_scene = SceneSelectFile;
|
||||
string_set_str(context->attack_name, "Load File");
|
||||
break;
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
context->attack = FlipFridAttackLoadFileCustomUids;
|
||||
context->current_scene = SceneLoadCustomUids;
|
||||
string_set_str(context->attack_name, "Load Custom UIDs");
|
||||
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->menu_index = 0;
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
string_init(menu_items[i]);
|
||||
}
|
||||
|
||||
string_set(menu_items[0], "Default Values");
|
||||
string_set(menu_items[1], "BF Customer ID");
|
||||
string_set(menu_items[2], "Load File");
|
||||
string_set(menu_items[3], "Load uids from file");
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
string_clear(menu_items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
case InputKeyRight:
|
||||
break;
|
||||
case InputKeyOk:
|
||||
flipfrid_scene_entrypoint_menu_callback(context, context->menu_index);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "RFID Fuzzer");
|
||||
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(menu_items[context->menu_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 36, AlignCenter, AlignTop, string_get_cstr(menu_items[context->menu_index]));
|
||||
|
||||
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(menu_items[context->menu_index + 1]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#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);
|
||||
@@ -0,0 +1,79 @@
|
||||
#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
|
||||
string_t uid_path;
|
||||
string_init(uid_path);
|
||||
string_set_str(uid_path, RFIDFUZZER_APP_PATH_FOLDER);
|
||||
|
||||
bool res = dialog_file_browser_show(
|
||||
context->dialogs, uid_path, uid_path, LFRFID_UIDS_EXTENSION, true, &I_125_10px, false);
|
||||
|
||||
if(res) {
|
||||
res = flipfrid_load_uids(context, string_get_cstr(uid_path));
|
||||
}
|
||||
|
||||
string_clear(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#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);
|
||||
@@ -0,0 +1,146 @@
|
||||
#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);
|
||||
string_t temp_str;
|
||||
string_init(temp_str);
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Error open file %s", file_path);
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Error open file");
|
||||
break;
|
||||
}
|
||||
|
||||
// FileType
|
||||
if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Filetype");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Missing or incorrect Filetypes");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Filetype: %s", 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");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Missing or incorrect Key type");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key type: %s", string_get_cstr(temp_str));
|
||||
if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(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");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Missing or incorrect Key");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", string_get_cstr(context->data_str));
|
||||
|
||||
// Check data size
|
||||
if(string_size(context->data_str) != 14) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = 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);
|
||||
string_clear(temp_str);
|
||||
flipper_format_free(fff_data_file);
|
||||
if(result) {
|
||||
FURI_LOG_I(TAG, "Loaded successfully");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
|
||||
bool flipfrid_load_protocol_from_file(FlipFridState* context) {
|
||||
string_t user_file_path;
|
||||
string_init(user_file_path);
|
||||
string_set_str(user_file_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,
|
||||
LFRFID_APP_EXTENSION,
|
||||
true,
|
||||
&I_125_10px,
|
||||
true);
|
||||
|
||||
if(res) {
|
||||
res = flipfrid_load(context, string_get_cstr(user_file_path));
|
||||
}
|
||||
|
||||
string_clear(user_file_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#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);
|
||||
@@ -0,0 +1,214 @@
|
||||
#include "flipfrid_scene_run_attack.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
uint8_t counter = 0;
|
||||
#define TIME_BETWEEN_CARDS 5
|
||||
uint8_t id_list[16][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
|
||||
{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
|
||||
};
|
||||
|
||||
void flipfrid_scene_run_attack_on_enter(FlipFridState* context) {
|
||||
context->attack_step = 0;
|
||||
context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
context->worker = lfrfid_worker_alloc(context->dict);
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100");
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_exit(FlipFridState* context) {
|
||||
lfrfid_worker_stop(context->worker);
|
||||
lfrfid_worker_stop_thread(context->worker);
|
||||
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, 5);
|
||||
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);
|
||||
} else if(0 == counter) {
|
||||
lfrfid_worker_stop(context->worker);
|
||||
lfrfid_worker_stop_thread(context->worker);
|
||||
switch(context->attack) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
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 == 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 FlipFridAttackBfCustomerId:
|
||||
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;
|
||||
case FlipFridAttackLoadFile:
|
||||
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;
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
while(true) {
|
||||
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);
|
||||
break;
|
||||
};
|
||||
if(string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(string_size(context->data_str) != 11) continue;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, string_get_cstr(context->data_str));
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = 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 > 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:
|
||||
case InputKeyUp:
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
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:
|
||||
if(context->attack == FlipFridAttackLoadFileCustomUids) {
|
||||
buffered_file_stream_close(context->uids_stream);
|
||||
}
|
||||
|
||||
context->attack_step = 0;
|
||||
context->is_attacking = false;
|
||||
string_reset(context->notification_msg);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
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, 8, AlignCenter, AlignTop, string_get_cstr(context->attack_name));
|
||||
|
||||
char uid[16];
|
||||
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, 24, AlignCenter, AlignTop, uid);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
//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");
|
||||
}
|
||||
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#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);
|
||||
@@ -0,0 +1,121 @@
|
||||
#include "flipfrid_scene_select_field.h"
|
||||
|
||||
void flipfrid_center_displayed_key(FlipFridState* context, uint8_t index) {
|
||||
const char* key_cstr = string_get_cstr(context->data_str);
|
||||
uint8_t str_index = (index * 3);
|
||||
|
||||
char display_menu[17] = {
|
||||
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
|
||||
|
||||
if(index > 1) {
|
||||
display_menu[0] = key_cstr[str_index - 6];
|
||||
display_menu[1] = key_cstr[str_index - 5];
|
||||
} else {
|
||||
display_menu[0] = ' ';
|
||||
display_menu[1] = ' ';
|
||||
}
|
||||
|
||||
if(index > 0) {
|
||||
display_menu[3] = key_cstr[str_index - 3];
|
||||
display_menu[4] = key_cstr[str_index - 2];
|
||||
} else {
|
||||
display_menu[3] = ' ';
|
||||
display_menu[4] = ' ';
|
||||
}
|
||||
|
||||
display_menu[7] = key_cstr[str_index];
|
||||
display_menu[8] = key_cstr[str_index + 1];
|
||||
|
||||
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[11] = key_cstr[str_index + 3];
|
||||
display_menu[12] = key_cstr[str_index + 4];
|
||||
} else {
|
||||
display_menu[11] = ' ';
|
||||
display_menu[12] = ' ';
|
||||
}
|
||||
|
||||
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[14] = key_cstr[str_index + 6];
|
||||
display_menu[15] = key_cstr[str_index + 7];
|
||||
} else {
|
||||
display_menu[14] = ' ';
|
||||
display_menu[15] = ' ';
|
||||
}
|
||||
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, display_menu);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_enter(FlipFridState* context) {
|
||||
string_clear(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 = string_get_cstr(context->data_str);
|
||||
|
||||
// don't look, it's ugly but I'm a python dev so...
|
||||
uint8_t nb_bytes = 0;
|
||||
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
|
||||
if(' ' == key_cstr[i]) {
|
||||
nb_bytes++;
|
||||
}
|
||||
}
|
||||
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->key_index > 0) {
|
||||
context->key_index = context->key_index - 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->key_index < nb_bytes) {
|
||||
context->key_index = context->key_index + 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
string_reset(context->notification_msg);
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case InputKeyBack:
|
||||
string_reset(context->notification_msg);
|
||||
context->current_scene = SceneSelectFile;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void 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);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "Use < > to select byte.");
|
||||
|
||||
char msg_index[18];
|
||||
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
|
||||
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index);
|
||||
|
||||
flipfrid_center_displayed_key(context, context->key_index);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg));
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#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);
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
@@ -12,6 +12,7 @@ const CanvasFontParameters canvas_font_params[FontTotalNumber] = {
|
||||
[FontSecondary] = {.leading_default = 11, .leading_min = 9, .height = 7, .descender = 2},
|
||||
[FontKeyboard] = {.leading_default = 11, .leading_min = 9, .height = 7, .descender = 2},
|
||||
[FontBigNumbers] = {.leading_default = 18, .leading_min = 16, .height = 15, .descender = 0},
|
||||
[FontBatteryPercent] = {.leading_default = 11, .leading_min = 9, .height = 6, .descender = 0},
|
||||
};
|
||||
|
||||
Canvas* canvas_init() {
|
||||
@@ -132,6 +133,8 @@ void canvas_set_font(Canvas* canvas, Font font) {
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_profont11_mr);
|
||||
} else if(font == FontBigNumbers) {
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_profont22_tn);
|
||||
} else if(font == FontBatteryPercent) {
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_5x7_tf); //u8g2_font_micro_tr);
|
||||
} else {
|
||||
furi_crash(NULL);
|
||||
}
|
||||
|
||||
Executable → Regular
+1
@@ -25,6 +25,7 @@ typedef enum {
|
||||
FontSecondary,
|
||||
FontKeyboard,
|
||||
FontBigNumbers,
|
||||
FontBatteryPercent,
|
||||
|
||||
// Keep last for fonts number calculation
|
||||
FontTotalNumber,
|
||||
|
||||
@@ -83,6 +83,15 @@ ButtonPanel* button_panel_alloc() {
|
||||
return button_panel;
|
||||
}
|
||||
|
||||
void button_panel_reset_selection(ButtonPanel* button_panel) {
|
||||
with_view_model(
|
||||
button_panel->view, (ButtonPanelModel * model) {
|
||||
model->selected_item_x = 0;
|
||||
model->selected_item_y = 0;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y) {
|
||||
furi_check(reserve_x > 0);
|
||||
furi_check(reserve_y > 0);
|
||||
|
||||
@@ -35,6 +35,12 @@ void button_panel_free(ButtonPanel* button_panel);
|
||||
*/
|
||||
void button_panel_reset(ButtonPanel* button_panel);
|
||||
|
||||
/** Resets selected_item_x and selected_item_y.
|
||||
*
|
||||
* @param button_panel ButtonPanel instance
|
||||
*/
|
||||
void button_panel_reset_selection(ButtonPanel* button_panel);
|
||||
|
||||
/** Reserve space for adding items.
|
||||
*
|
||||
* One does not simply use button_panel_add_item() without this function. It
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -463,8 +463,6 @@ void text_input_free(TextInput* text_input) {
|
||||
|
||||
// Send stop command
|
||||
furi_timer_stop(text_input->timer);
|
||||
// Wait till timer stop
|
||||
while(furi_timer_is_running(text_input->timer)) furi_delay_tick(1);
|
||||
// Release allocated memory
|
||||
furi_timer_free(text_input->timer);
|
||||
|
||||
|
||||
@@ -42,7 +42,9 @@ ValidatorIsFile* validator_is_file_alloc_init(
|
||||
|
||||
instance->app_path_folder = strdup(app_path_folder);
|
||||
instance->app_extension = app_extension;
|
||||
instance->current_name = strdup(current_name);
|
||||
if(current_name != NULL) {
|
||||
instance->current_name = strdup(current_name);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -35,6 +35,10 @@ InfraredBruteForce* infrared_brute_force_alloc() {
|
||||
return brute_force;
|
||||
}
|
||||
|
||||
void infrared_brute_force_clear_records(InfraredBruteForce* brute_force) {
|
||||
InfraredBruteForceRecordDict_reset(brute_force->records);
|
||||
}
|
||||
|
||||
void infrared_brute_force_free(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->ff);
|
||||
InfraredBruteForceRecordDict_clear(brute_force->records);
|
||||
|
||||
@@ -16,6 +16,7 @@ bool infrared_brute_force_start(
|
||||
bool infrared_brute_force_is_started(InfraredBruteForce* brute_force);
|
||||
void infrared_brute_force_stop(InfraredBruteForce* brute_force);
|
||||
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force);
|
||||
void infrared_brute_force_clear_records(InfraredBruteForce* brute_force);
|
||||
void infrared_brute_force_add_record(
|
||||
InfraredBruteForce* brute_force,
|
||||
uint32_t index,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <infrared.h>
|
||||
#include <infrared_worker.h>
|
||||
#include <furi_hal_infrared.h>
|
||||
#include <flipper_format.h>
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#include "infrared_signal.h"
|
||||
|
||||
@@ -10,6 +12,7 @@
|
||||
|
||||
static void infrared_cli_start_ir_rx(Cli* cli, string_t args);
|
||||
static void infrared_cli_start_ir_tx(Cli* cli, string_t args);
|
||||
static void infrared_cli_process_decode(Cli* cli, string_t args);
|
||||
|
||||
static const struct {
|
||||
const char* cmd;
|
||||
@@ -17,6 +20,7 @@ static const struct {
|
||||
} infrared_cli_commands[] = {
|
||||
{.cmd = "rx", .process_function = infrared_cli_start_ir_rx},
|
||||
{.cmd = "tx", .process_function = infrared_cli_start_ir_tx},
|
||||
{.cmd = "decode", .process_function = infrared_cli_process_decode},
|
||||
};
|
||||
|
||||
static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
|
||||
@@ -86,6 +90,7 @@ static void infrared_cli_print_usage(void) {
|
||||
"\tFrequency (%d - %d), Duty cycle (0 - 100), max 512 samples\r\n",
|
||||
INFRARED_MIN_FREQUENCY,
|
||||
INFRARED_MAX_FREQUENCY);
|
||||
printf("\tir decode <input_file> [<output_file>]\r\n");
|
||||
}
|
||||
|
||||
static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) {
|
||||
@@ -162,6 +167,160 @@ static void infrared_cli_start_ir_tx(Cli* cli, string_t args) {
|
||||
infrared_signal_free(signal);
|
||||
}
|
||||
|
||||
static bool
|
||||
infrared_cli_save_signal(InfraredSignal* signal, FlipperFormat* file, const char* name) {
|
||||
bool ret = infrared_signal_save(signal, file, name);
|
||||
if(!ret) {
|
||||
printf("Failed to save signal: \"%s\"\r\n", name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool infrared_cli_decode_raw_signal(
|
||||
InfraredRawSignal* raw_signal,
|
||||
InfraredDecoderHandler* decoder,
|
||||
FlipperFormat* output_file,
|
||||
const char* signal_name) {
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
bool ret = false, level = true, is_decoded = false;
|
||||
|
||||
size_t i;
|
||||
for(i = 0; i < raw_signal->timings_size; ++i) {
|
||||
// TODO: Any infrared_check_decoder_ready() magic?
|
||||
const InfraredMessage* message = infrared_decode(decoder, level, raw_signal->timings[i]);
|
||||
|
||||
if(message) {
|
||||
is_decoded = true;
|
||||
printf(
|
||||
"Protocol: %s address: 0x%lX command: 0x%lX %s\r\n",
|
||||
infrared_get_protocol_name(message->protocol),
|
||||
message->address,
|
||||
message->command,
|
||||
(message->repeat ? "R" : ""));
|
||||
if(output_file && !message->repeat) {
|
||||
infrared_signal_set_message(signal, message);
|
||||
if(!infrared_cli_save_signal(signal, output_file, signal_name)) break;
|
||||
}
|
||||
}
|
||||
|
||||
level = !level;
|
||||
}
|
||||
|
||||
if(i == raw_signal->timings_size) {
|
||||
if(!is_decoded && output_file) {
|
||||
infrared_signal_set_raw_signal(
|
||||
signal,
|
||||
raw_signal->timings,
|
||||
raw_signal->timings_size,
|
||||
raw_signal->frequency,
|
||||
raw_signal->duty_cycle);
|
||||
ret = infrared_cli_save_signal(signal, output_file, signal_name);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
infrared_reset_decoder(decoder);
|
||||
infrared_signal_free(signal);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* output_file) {
|
||||
bool ret = false;
|
||||
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
InfraredDecoderHandler* decoder = infrared_alloc_decoder();
|
||||
|
||||
string_t tmp;
|
||||
string_init(tmp);
|
||||
|
||||
while(infrared_signal_read(signal, input_file, tmp)) {
|
||||
ret = false;
|
||||
if(!infrared_signal_is_valid(signal)) {
|
||||
printf("Invalid signal\r\n");
|
||||
break;
|
||||
}
|
||||
if(!infrared_signal_is_raw(signal)) {
|
||||
if(output_file &&
|
||||
!infrared_cli_save_signal(signal, output_file, string_get_cstr(tmp))) {
|
||||
break;
|
||||
} else {
|
||||
printf("Skipping decoded signal\r\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal);
|
||||
printf("Raw signal: %s, %u samples\r\n", string_get_cstr(tmp), raw_signal->timings_size);
|
||||
if(!infrared_cli_decode_raw_signal(raw_signal, decoder, output_file, string_get_cstr(tmp)))
|
||||
break;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
infrared_free_decoder(decoder);
|
||||
infrared_signal_free(signal);
|
||||
string_clear(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void infrared_cli_process_decode(Cli* cli, string_t args) {
|
||||
UNUSED(cli);
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* input_file = flipper_format_buffered_file_alloc(storage);
|
||||
FlipperFormat* output_file = NULL;
|
||||
|
||||
uint32_t version;
|
||||
string_t tmp, header, input_path, output_path;
|
||||
string_init(tmp);
|
||||
string_init(header);
|
||||
string_init(input_path);
|
||||
string_init(output_path);
|
||||
|
||||
do {
|
||||
if(!args_read_probably_quoted_string_and_trim(args, input_path)) {
|
||||
printf("Wrong arguments.\r\n");
|
||||
infrared_cli_print_usage();
|
||||
break;
|
||||
}
|
||||
args_read_probably_quoted_string_and_trim(args, output_path);
|
||||
if(!flipper_format_buffered_file_open_existing(input_file, string_get_cstr(input_path))) {
|
||||
printf("Failed to open file for reading: \"%s\"\r\n", string_get_cstr(input_path));
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_read_header(input_file, header, &version) ||
|
||||
(!string_start_with_str_p(header, "IR")) || version != 1) {
|
||||
printf("Invalid or corrupted input file: \"%s\"\r\n", string_get_cstr(input_path));
|
||||
break;
|
||||
}
|
||||
if(!string_empty_p(output_path)) {
|
||||
printf("Writing output to file: \"%s\"\r\n", string_get_cstr(output_path));
|
||||
output_file = flipper_format_file_alloc(storage);
|
||||
}
|
||||
if(output_file &&
|
||||
!flipper_format_file_open_always(output_file, string_get_cstr(output_path))) {
|
||||
printf("Failed to open file for writing: \"%s\"\r\n", string_get_cstr(output_path));
|
||||
break;
|
||||
}
|
||||
if(output_file && !flipper_format_write_header(output_file, header, version)) {
|
||||
printf("Failed to write to the output file: \"%s\"\r\n", string_get_cstr(output_path));
|
||||
break;
|
||||
}
|
||||
if(!infrared_cli_decode_file(input_file, output_file)) {
|
||||
break;
|
||||
}
|
||||
printf("File successfully decoded.\r\n");
|
||||
} while(false);
|
||||
|
||||
string_clear(tmp);
|
||||
string_clear(header);
|
||||
string_clear(input_path);
|
||||
string_clear(output_path);
|
||||
|
||||
flipper_format_free(input_file);
|
||||
if(output_file) flipper_format_free(output_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
UNUSED(context);
|
||||
if(furi_hal_infrared_is_busy()) {
|
||||
@@ -169,18 +328,15 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
return;
|
||||
}
|
||||
|
||||
string_t command;
|
||||
string_init(command);
|
||||
args_read_string_and_trim(args, command);
|
||||
|
||||
size_t i = 0;
|
||||
for(; i < COUNT_OF(infrared_cli_commands); ++i) {
|
||||
size_t size = strlen(infrared_cli_commands[i].cmd);
|
||||
bool cmd_found = !strncmp(string_get_cstr(args), infrared_cli_commands[i].cmd, size);
|
||||
if(cmd_found) {
|
||||
if(string_size(args) == size) {
|
||||
break;
|
||||
}
|
||||
if(string_get_cstr(args)[size] == ' ') {
|
||||
string_right(args, size + 1);
|
||||
break;
|
||||
}
|
||||
size_t cmd_len = strlen(infrared_cli_commands[i].cmd);
|
||||
if(!strncmp(string_get_cstr(command), infrared_cli_commands[i].cmd, cmd_len)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +345,8 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
} else {
|
||||
infrared_cli_print_usage();
|
||||
}
|
||||
|
||||
string_clear(command);
|
||||
}
|
||||
void infrared_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
|
||||
@@ -33,6 +33,8 @@ static void infrared_scene_universal_common_hide_popup(Infrared* infrared) {
|
||||
|
||||
void infrared_scene_universal_common_on_enter(void* context) {
|
||||
Infrared* infrared = context;
|
||||
infrared_brute_force_clear_records(infrared->brute_force);
|
||||
button_panel_reset_selection(infrared->button_panel);
|
||||
view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ ADD_SCENE(infrared, remote_list, RemoteList)
|
||||
ADD_SCENE(infrared, universal, Universal)
|
||||
ADD_SCENE(infrared, universal_tv, UniversalTV)
|
||||
ADD_SCENE(infrared, universal_ac, UniversalAC)
|
||||
ADD_SCENE(infrared, universal_fan, UniversalFan)
|
||||
ADD_SCENE(infrared, universal_audio, UniversalAudio)
|
||||
ADD_SCENE(infrared, universal_projector, UniversalProjector)
|
||||
ADD_SCENE(infrared, debug, Debug)
|
||||
|
||||
@@ -25,7 +25,6 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == InfraredCustomEventTypeSignalReceived) {
|
||||
infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess);
|
||||
scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess);
|
||||
consumed = true;
|
||||
@@ -38,6 +37,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) {
|
||||
void infrared_scene_learn_on_exit(void* context) {
|
||||
Infrared* infrared = context;
|
||||
Popup* popup = infrared->popup;
|
||||
infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL);
|
||||
infrared_worker_rx_stop(infrared->worker);
|
||||
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
|
||||
@@ -4,6 +4,7 @@ typedef enum {
|
||||
SubmenuIndexUniversalTV,
|
||||
SubmenuIndexUniversalAudio,
|
||||
SubmenuIndexUniversalProjector,
|
||||
SubmenuIndexUniversalFan,
|
||||
SubmenuIndexUniversalAirConditioner,
|
||||
} SubmenuIndex;
|
||||
|
||||
@@ -38,6 +39,13 @@ void infrared_scene_universal_on_enter(void* context) {
|
||||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Fans",
|
||||
SubmenuIndexUniversalFan,
|
||||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"ACs",
|
||||
@@ -63,6 +71,9 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
|
||||
} else if(event.event == SubmenuIndexUniversalProjector) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalProjector);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexUniversalFan) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalFan);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexUniversalAirConditioner) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
|
||||
consumed = true;
|
||||
|
||||
@@ -12,7 +12,7 @@ void infrared_scene_universal_ac_on_enter(void* context) {
|
||||
infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/ac.ir"));
|
||||
|
||||
//TODO Improve A/C universal remote
|
||||
button_panel_reserve(button_panel, 2, 2);
|
||||
button_panel_reserve(button_panel, 2, 3);
|
||||
uint32_t i = 0;
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
@@ -44,7 +44,7 @@ void infrared_scene_universal_ac_on_enter(void* context) {
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
69,
|
||||
66,
|
||||
&I_Vol_up_25x27,
|
||||
&I_Vol_up_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
@@ -56,15 +56,39 @@ void infrared_scene_universal_ac_on_enter(void* context) {
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
69,
|
||||
66,
|
||||
&I_Vol_down_25x27,
|
||||
&I_Vol_down_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "TEMP-");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
98,
|
||||
&I_Swing_25x27,
|
||||
&I_Swing_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "SWING");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
2,
|
||||
36,
|
||||
98,
|
||||
&I_Timer_25x27,
|
||||
&I_Timer_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "TIMER");
|
||||
|
||||
button_panel_add_label(button_panel, 6, 11, FontPrimary, "AC remote");
|
||||
button_panel_add_label(button_panel, 20, 66, FontSecondary, "Temp");
|
||||
button_panel_add_label(button_panel, 20, 63, FontSecondary, "Temp");
|
||||
button_panel_add_label(button_panel, 8, 23, FontSecondary, "Pwr");
|
||||
button_panel_add_label(button_panel, 40, 23, FontSecondary, "Mod");
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "../infrared_i.h"
|
||||
|
||||
#include "common/infrared_scene_universal_common.h"
|
||||
|
||||
void infrared_scene_universal_fan_on_enter(void* context) {
|
||||
infrared_scene_universal_common_on_enter(context);
|
||||
|
||||
Infrared* infrared = context;
|
||||
ButtonPanel* button_panel = infrared->button_panel;
|
||||
InfraredBruteForce* brute_force = infrared->brute_force;
|
||||
|
||||
infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/fans.ir"));
|
||||
|
||||
//TODO Improve Fan universal remote
|
||||
button_panel_reserve(button_panel, 2, 3);
|
||||
uint32_t i = 0;
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
24,
|
||||
&I_Power_25x27,
|
||||
&I_Power_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "POWER");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
36,
|
||||
24,
|
||||
&I_Mode_25x27,
|
||||
&I_Mode_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "MODE");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
66,
|
||||
&I_Vol_up_25x27,
|
||||
&I_Vol_up_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "SPEED+");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
66,
|
||||
&I_Vol_down_25x27,
|
||||
&I_Vol_down_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "SPEED-");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
98,
|
||||
&I_Rotate_25x27,
|
||||
&I_Rotate_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "ROTATE");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
2,
|
||||
36,
|
||||
98,
|
||||
&I_Timer_25x27,
|
||||
&I_Timer_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "TIMER");
|
||||
|
||||
button_panel_add_label(button_panel, 5, 11, FontPrimary, "Fan remote");
|
||||
button_panel_add_label(button_panel, 20, 63, FontSecondary, "Speed");
|
||||
button_panel_add_label(button_panel, 8, 23, FontSecondary, "Pwr");
|
||||
button_panel_add_label(button_panel, 40, 23, FontSecondary, "Mod");
|
||||
|
||||
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||
|
||||
infrared_show_loading_popup(infrared, true);
|
||||
bool success = infrared_brute_force_calculate_messages(brute_force);
|
||||
infrared_show_loading_popup(infrared, false);
|
||||
|
||||
if(!success) {
|
||||
scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases);
|
||||
}
|
||||
}
|
||||
|
||||
bool infrared_scene_universal_fan_on_event(void* context, SceneManagerEvent event) {
|
||||
return infrared_scene_universal_common_on_event(context, event);
|
||||
}
|
||||
|
||||
void infrared_scene_universal_fan_on_exit(void* context) {
|
||||
infrared_scene_universal_common_on_exit(context);
|
||||
}
|
||||
@@ -10,7 +10,7 @@ App(
|
||||
],
|
||||
provides=[
|
||||
"lfrfid_start",
|
||||
"lfrfid_debug",
|
||||
#"lfrfid_debug",
|
||||
],
|
||||
icon="A_125khz_14",
|
||||
stack_size=2 * 1024,
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
#include "lfrfid_i.h"
|
||||
|
||||
static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
LfRfid* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool lfrfid_debug_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
LfRfid* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
|
||||
furi_assert(context);
|
||||
LfRfid* app = (LfRfid*)context;
|
||||
|
||||
if(rpc_event == RpcAppEventSessionClose) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcSessionClose);
|
||||
// Detach RPC
|
||||
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
|
||||
app->rpc_ctx = NULL;
|
||||
} else if(rpc_event == RpcAppEventAppExit) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventExit);
|
||||
} else if(rpc_event == RpcAppEventLoadFile) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcLoadFile);
|
||||
} else {
|
||||
rpc_system_app_confirm(app->rpc_ctx, rpc_event, false);
|
||||
}
|
||||
}
|
||||
|
||||
static LfRfid* lfrfid_alloc() {
|
||||
LfRfid* lfrfid = malloc(sizeof(LfRfid));
|
||||
|
||||
lfrfid->storage = furi_record_open(RECORD_STORAGE);
|
||||
lfrfid->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
string_init(lfrfid->file_name);
|
||||
string_init(lfrfid->raw_file_name);
|
||||
string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER);
|
||||
|
||||
lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
|
||||
size_t size = protocol_dict_get_max_data_size(lfrfid->dict);
|
||||
lfrfid->new_key_data = (uint8_t*)malloc(size);
|
||||
lfrfid->old_key_data = (uint8_t*)malloc(size);
|
||||
|
||||
lfrfid->lfworker = lfrfid_worker_alloc(lfrfid->dict);
|
||||
|
||||
lfrfid->view_dispatcher = view_dispatcher_alloc();
|
||||
lfrfid->scene_manager = scene_manager_alloc(&lfrfid_scene_handlers, lfrfid);
|
||||
view_dispatcher_enable_queue(lfrfid->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(lfrfid->view_dispatcher, lfrfid);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
lfrfid->view_dispatcher, lfrfid_debug_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
lfrfid->view_dispatcher, lfrfid_debug_back_event_callback);
|
||||
|
||||
// Open GUI record
|
||||
lfrfid->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// Open Notification record
|
||||
lfrfid->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// Submenu
|
||||
lfrfid->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
lfrfid->view_dispatcher, LfRfidViewSubmenu, submenu_get_view(lfrfid->submenu));
|
||||
|
||||
// Dialog
|
||||
lfrfid->dialog_ex = dialog_ex_alloc();
|
||||
view_dispatcher_add_view(
|
||||
lfrfid->view_dispatcher, LfRfidViewDialogEx, dialog_ex_get_view(lfrfid->dialog_ex));
|
||||
|
||||
// Popup
|
||||
lfrfid->popup = popup_alloc();
|
||||
view_dispatcher_add_view(
|
||||
lfrfid->view_dispatcher, LfRfidViewPopup, popup_get_view(lfrfid->popup));
|
||||
|
||||
// Widget
|
||||
lfrfid->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
lfrfid->view_dispatcher, LfRfidViewWidget, widget_get_view(lfrfid->widget));
|
||||
|
||||
// Text Input
|
||||
lfrfid->text_input = text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
lfrfid->view_dispatcher, LfRfidViewTextInput, text_input_get_view(lfrfid->text_input));
|
||||
|
||||
// Byte Input
|
||||
lfrfid->byte_input = byte_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
lfrfid->view_dispatcher, LfRfidViewByteInput, byte_input_get_view(lfrfid->byte_input));
|
||||
|
||||
// Read custom view
|
||||
lfrfid->read_view = lfrfid_view_read_alloc();
|
||||
view_dispatcher_add_view(
|
||||
lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view));
|
||||
|
||||
return lfrfid;
|
||||
}
|
||||
|
||||
static void lfrfid_free(LfRfid* lfrfid) {
|
||||
furi_assert(lfrfid);
|
||||
|
||||
string_clear(lfrfid->raw_file_name);
|
||||
string_clear(lfrfid->file_name);
|
||||
string_clear(lfrfid->file_path);
|
||||
protocol_dict_free(lfrfid->dict);
|
||||
|
||||
lfrfid_worker_free(lfrfid->lfworker);
|
||||
|
||||
if(lfrfid->rpc_ctx) {
|
||||
rpc_system_app_set_callback(lfrfid->rpc_ctx, NULL, NULL);
|
||||
rpc_system_app_send_exited(lfrfid->rpc_ctx);
|
||||
}
|
||||
|
||||
free(lfrfid->new_key_data);
|
||||
free(lfrfid->old_key_data);
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewSubmenu);
|
||||
submenu_free(lfrfid->submenu);
|
||||
|
||||
// DialogEx
|
||||
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewDialogEx);
|
||||
dialog_ex_free(lfrfid->dialog_ex);
|
||||
|
||||
// Popup
|
||||
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewPopup);
|
||||
popup_free(lfrfid->popup);
|
||||
|
||||
// Widget
|
||||
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewWidget);
|
||||
widget_free(lfrfid->widget);
|
||||
|
||||
// TextInput
|
||||
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewTextInput);
|
||||
text_input_free(lfrfid->text_input);
|
||||
|
||||
// ByteInput
|
||||
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewByteInput);
|
||||
byte_input_free(lfrfid->byte_input);
|
||||
|
||||
// Read custom view
|
||||
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewRead);
|
||||
lfrfid_view_read_free(lfrfid->read_view);
|
||||
|
||||
// View Dispatcher
|
||||
view_dispatcher_free(lfrfid->view_dispatcher);
|
||||
|
||||
// Scene Manager
|
||||
scene_manager_free(lfrfid->scene_manager);
|
||||
|
||||
// GUI
|
||||
furi_record_close(RECORD_GUI);
|
||||
lfrfid->gui = NULL;
|
||||
|
||||
// Notifications
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
lfrfid->notifications = NULL;
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
free(lfrfid);
|
||||
}
|
||||
|
||||
int32_t lfrfid_app(void* p) {
|
||||
LfRfid* app = lfrfid_alloc();
|
||||
char* args = p;
|
||||
|
||||
lfrfid_make_app_folder(app);
|
||||
|
||||
if(args && strlen(args)) {
|
||||
uint32_t rpc_ctx_ptr = 0;
|
||||
if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
|
||||
app->rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
|
||||
rpc_system_app_set_callback(app->rpc_ctx, rpc_command_callback, app);
|
||||
rpc_system_app_send_started(app->rpc_ctx);
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc);
|
||||
} else {
|
||||
string_set_str(app->file_path, args);
|
||||
lfrfid_load_key_data(app, app->file_path, true);
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||
}
|
||||
|
||||
} else {
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneStart);
|
||||
}
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
lfrfid_free(app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool lfrfid_save_key(LfRfid* app) {
|
||||
furi_assert(app);
|
||||
|
||||
bool result = false;
|
||||
|
||||
lfrfid_make_app_folder(app);
|
||||
|
||||
if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) {
|
||||
size_t filename_start = string_search_rchar(app->file_path, '/');
|
||||
string_left(app->file_path, filename_start);
|
||||
}
|
||||
|
||||
string_cat_printf(
|
||||
app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION);
|
||||
|
||||
result = lfrfid_save_key_data(app, app->file_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lfrfid_load_key_from_file_select(LfRfid* app) {
|
||||
furi_assert(app);
|
||||
|
||||
bool result = dialog_file_browser_show(
|
||||
app->dialogs,
|
||||
app->file_path,
|
||||
app->file_path,
|
||||
LFRFID_APP_EXTENSION,
|
||||
true,
|
||||
&I_125_10px,
|
||||
true);
|
||||
|
||||
if(result) {
|
||||
result = lfrfid_load_key_data(app, app->file_path, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lfrfid_delete_key(LfRfid* app) {
|
||||
furi_assert(app);
|
||||
|
||||
return storage_simply_remove(app->storage, string_get_cstr(app->file_path));
|
||||
}
|
||||
|
||||
bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) {
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
app->protocol_id = lfrfid_dict_file_load(app->dict, string_get_cstr(path));
|
||||
if(app->protocol_id == PROTOCOL_NO) break;
|
||||
|
||||
path_extract_filename(path, app->file_name, true);
|
||||
result = true;
|
||||
} while(0);
|
||||
|
||||
if((!result) && (show_dialog)) {
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot load\nkey file");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lfrfid_save_key_data(LfRfid* app, string_t path) {
|
||||
bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path));
|
||||
|
||||
if(!result) {
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void lfrfid_make_app_folder(LfRfid* app) {
|
||||
furi_assert(app);
|
||||
|
||||
if(!storage_simply_mkdir(app->storage, LFRFID_APP_FOLDER)) {
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
|
||||
}
|
||||
}
|
||||
|
||||
void lfrfid_text_store_set(LfRfid* app, const char* text, ...) {
|
||||
furi_assert(app);
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
|
||||
vsnprintf(app->text_store, LFRFID_TEXT_STORE_SIZE, text, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void lfrfid_text_store_clear(LfRfid* app) {
|
||||
furi_assert(app);
|
||||
memset(app->text_store, 0, sizeof(app->text_store));
|
||||
}
|
||||
|
||||
void lfrfid_popup_timeout_callback(void* context) {
|
||||
LfRfid* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventPopupClosed);
|
||||
}
|
||||
|
||||
void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
LfRfid* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void lfrfid_text_input_callback(void* context) {
|
||||
LfRfid* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventNext);
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
#include "lfrfid_app.h"
|
||||
#include "assets_icons.h"
|
||||
#include <core/common_defines.h>
|
||||
#include "m-string.h"
|
||||
#include "scene/lfrfid_app_scene_start.h"
|
||||
#include "scene/lfrfid_app_scene_read.h"
|
||||
#include "scene/lfrfid_app_scene_read_success.h"
|
||||
#include "scene/lfrfid_app_scene_retry_confirm.h"
|
||||
#include "scene/lfrfid_app_scene_exit_confirm.h"
|
||||
#include "scene/lfrfid_app_scene_read_menu.h"
|
||||
#include "scene/lfrfid_app_scene_write.h"
|
||||
#include "scene/lfrfid_app_scene_write_success.h"
|
||||
#include "scene/lfrfid_app_scene_emulate.h"
|
||||
#include "scene/lfrfid_app_scene_save_name.h"
|
||||
#include "scene/lfrfid_app_scene_save_success.h"
|
||||
#include "scene/lfrfid_app_scene_select_key.h"
|
||||
#include "scene/lfrfid_app_scene_saved_key_menu.h"
|
||||
#include "scene/lfrfid_app_scene_save_data.h"
|
||||
#include "scene/lfrfid_app_scene_save_type.h"
|
||||
#include "scene/lfrfid_app_scene_saved_info.h"
|
||||
#include "scene/lfrfid_app_scene_delete_confirm.h"
|
||||
#include "scene/lfrfid_app_scene_delete_success.h"
|
||||
#include "scene/lfrfid_app_scene_rpc.h"
|
||||
#include "scene/lfrfid_app_scene_extra_actions.h"
|
||||
#include "scene/lfrfid_app_scene_raw_info.h"
|
||||
#include "scene/lfrfid_app_scene_raw_name.h"
|
||||
#include "scene/lfrfid_app_scene_raw_read.h"
|
||||
#include "scene/lfrfid_app_scene_raw_success.h"
|
||||
|
||||
#include <toolbox/path.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
#include <rpc/rpc_app.h>
|
||||
|
||||
const char* LfRfidApp::app_folder = ANY_PATH("lfrfid");
|
||||
const char* LfRfidApp::app_sd_folder = EXT_PATH("lfrfid");
|
||||
const char* LfRfidApp::app_extension = ".rfid";
|
||||
const char* LfRfidApp::app_filetype = "Flipper RFID key";
|
||||
|
||||
LfRfidApp::LfRfidApp()
|
||||
: scene_controller{this}
|
||||
, notification{RECORD_NOTIFICATION}
|
||||
, storage{RECORD_STORAGE}
|
||||
, dialogs{RECORD_DIALOGS}
|
||||
, text_store(40) {
|
||||
string_init(file_name);
|
||||
string_init(raw_file_name);
|
||||
string_init_set_str(file_path, app_folder);
|
||||
|
||||
dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
|
||||
size_t size = protocol_dict_get_max_data_size(dict);
|
||||
new_key_data = (uint8_t*)malloc(size);
|
||||
old_key_data = (uint8_t*)malloc(size);
|
||||
|
||||
lfworker = lfrfid_worker_alloc(dict);
|
||||
}
|
||||
|
||||
LfRfidApp::~LfRfidApp() {
|
||||
string_clear(raw_file_name);
|
||||
string_clear(file_name);
|
||||
string_clear(file_path);
|
||||
protocol_dict_free(dict);
|
||||
|
||||
lfrfid_worker_free(lfworker);
|
||||
|
||||
if(rpc_ctx) {
|
||||
rpc_system_app_set_callback(rpc_ctx, NULL, NULL);
|
||||
rpc_system_app_send_exited(rpc_ctx);
|
||||
}
|
||||
|
||||
free(new_key_data);
|
||||
free(old_key_data);
|
||||
}
|
||||
|
||||
static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
|
||||
furi_assert(context);
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
|
||||
if(rpc_event == RpcAppEventSessionClose) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::RpcSessionClose;
|
||||
app->view_controller.send_event(&event);
|
||||
// Detach RPC
|
||||
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
|
||||
app->rpc_ctx = NULL;
|
||||
} else if(rpc_event == RpcAppEventAppExit) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Exit;
|
||||
app->view_controller.send_event(&event);
|
||||
} else if(rpc_event == RpcAppEventLoadFile) {
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::RpcLoadFile;
|
||||
app->view_controller.send_event(&event);
|
||||
} else {
|
||||
rpc_system_app_confirm(app->rpc_ctx, rpc_event, false);
|
||||
}
|
||||
}
|
||||
|
||||
void LfRfidApp::run(void* _args) {
|
||||
const char* args = reinterpret_cast<const char*>(_args);
|
||||
|
||||
make_app_folder();
|
||||
|
||||
if(args && strlen(args)) {
|
||||
uint32_t rpc_ctx_ptr = 0;
|
||||
if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
|
||||
rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
|
||||
rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this);
|
||||
rpc_system_app_send_started(rpc_ctx);
|
||||
view_controller.attach_to_gui(ViewDispatcherTypeDesktop);
|
||||
scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc());
|
||||
scene_controller.process(100, SceneType::Rpc);
|
||||
} else {
|
||||
string_set_str(file_path, args);
|
||||
load_key_data(file_path, true);
|
||||
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
|
||||
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
|
||||
scene_controller.process(100, SceneType::Emulate);
|
||||
}
|
||||
|
||||
} else {
|
||||
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
|
||||
scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart());
|
||||
scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead());
|
||||
scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm());
|
||||
scene_controller.add_scene(SceneType::ExitConfirm, new LfRfidAppSceneExitConfirm());
|
||||
scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess());
|
||||
scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu());
|
||||
scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite());
|
||||
scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess());
|
||||
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
|
||||
scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName());
|
||||
scene_controller.add_scene(SceneType::SaveSuccess, new LfRfidAppSceneSaveSuccess());
|
||||
scene_controller.add_scene(SceneType::SelectKey, new LfRfidAppSceneSelectKey());
|
||||
scene_controller.add_scene(SceneType::SavedKeyMenu, new LfRfidAppSceneSavedKeyMenu());
|
||||
scene_controller.add_scene(SceneType::SaveData, new LfRfidAppSceneSaveData());
|
||||
scene_controller.add_scene(SceneType::SaveType, new LfRfidAppSceneSaveType());
|
||||
scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo());
|
||||
scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm());
|
||||
scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess());
|
||||
scene_controller.add_scene(SceneType::ExtraActions, new LfRfidAppSceneExtraActions());
|
||||
scene_controller.add_scene(SceneType::RawInfo, new LfRfidAppSceneRawInfo());
|
||||
scene_controller.add_scene(SceneType::RawName, new LfRfidAppSceneRawName());
|
||||
scene_controller.add_scene(SceneType::RawRead, new LfRfidAppSceneRawRead());
|
||||
scene_controller.add_scene(SceneType::RawSuccess, new LfRfidAppSceneRawSuccess());
|
||||
scene_controller.process(100);
|
||||
}
|
||||
}
|
||||
|
||||
bool LfRfidApp::save_key() {
|
||||
bool result = false;
|
||||
|
||||
make_app_folder();
|
||||
|
||||
if(string_end_with_str_p(file_path, app_extension)) {
|
||||
size_t filename_start = string_search_rchar(file_path, '/');
|
||||
string_left(file_path, filename_start);
|
||||
}
|
||||
|
||||
string_cat_printf(file_path, "/%s%s", string_get_cstr(file_name), app_extension);
|
||||
|
||||
result = save_key_data(file_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LfRfidApp::load_key_from_file_select(bool need_restore) {
|
||||
if(!need_restore) {
|
||||
string_set_str(file_path, app_folder);
|
||||
}
|
||||
|
||||
bool result = dialog_file_browser_show(
|
||||
dialogs, file_path, file_path, app_extension, true, &I_125_10px, true);
|
||||
|
||||
if(result) {
|
||||
result = load_key_data(file_path, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LfRfidApp::delete_key() {
|
||||
return storage_simply_remove(storage, string_get_cstr(file_path));
|
||||
}
|
||||
|
||||
bool LfRfidApp::load_key_data(string_t path, bool show_dialog) {
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
protocol_id = lfrfid_dict_file_load(dict, string_get_cstr(path));
|
||||
if(protocol_id == PROTOCOL_NO) break;
|
||||
|
||||
path_extract_filename(path, file_name, true);
|
||||
result = true;
|
||||
} while(0);
|
||||
|
||||
if((!result) && (show_dialog)) {
|
||||
dialog_message_show_storage_error(dialogs, "Cannot load\nkey file");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LfRfidApp::save_key_data(string_t path) {
|
||||
bool result = lfrfid_dict_file_save(dict, protocol_id, string_get_cstr(path));
|
||||
|
||||
if(!result) {
|
||||
dialog_message_show_storage_error(dialogs, "Cannot save\nkey file");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LfRfidApp::make_app_folder() {
|
||||
if(!storage_simply_mkdir(storage, app_folder)) {
|
||||
dialog_message_show_storage_error(dialogs, "Cannot create\napp folder");
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
#pragma once
|
||||
#include "m-string.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <generic_scene.hpp>
|
||||
#include <scene_controller.hpp>
|
||||
#include <view_controller.hpp>
|
||||
#include <record_controller.hpp>
|
||||
#include <text_store.h>
|
||||
|
||||
#include <view_modules/submenu_vm.h>
|
||||
#include <view_modules/popup_vm.h>
|
||||
#include <view_modules/dialog_ex_vm.h>
|
||||
#include <view_modules/text_input_vm.h>
|
||||
#include <view_modules/byte_input_vm.h>
|
||||
#include "view/container_vm.h"
|
||||
|
||||
#include <notification/notification_messages.h>
|
||||
#include <storage/storage.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
|
||||
#include "rpc/rpc_app.h"
|
||||
|
||||
#include <toolbox/protocols/protocol_dict.h>
|
||||
#include <lfrfid/lfrfid_dict_file.h>
|
||||
#include <lfrfid/protocols/lfrfid_protocols.h>
|
||||
#include <lfrfid/lfrfid_worker.h>
|
||||
|
||||
#define LFRFID_KEY_NAME_SIZE 22
|
||||
|
||||
class LfRfidApp {
|
||||
public:
|
||||
enum class EventType : uint8_t {
|
||||
GENERIC_EVENT_ENUM_VALUES,
|
||||
Next,
|
||||
MenuSelected,
|
||||
Stay,
|
||||
Retry,
|
||||
Exit,
|
||||
ReadEventSenseStart,
|
||||
ReadEventSenseEnd,
|
||||
ReadEventSenseCardStart,
|
||||
ReadEventSenseCardEnd,
|
||||
ReadEventStartASK,
|
||||
ReadEventStartPSK,
|
||||
ReadEventDone,
|
||||
ReadEventOverrun,
|
||||
ReadEventError,
|
||||
WriteEventOK,
|
||||
WriteEventProtocolCannotBeWritten,
|
||||
WriteEventFobCannotBeWritten,
|
||||
WriteEventTooLongToWrite,
|
||||
RpcLoadFile,
|
||||
RpcSessionClose,
|
||||
};
|
||||
|
||||
enum class SceneType : uint8_t {
|
||||
GENERIC_SCENE_ENUM_VALUES,
|
||||
Read,
|
||||
ReadSuccess,
|
||||
RetryConfirm,
|
||||
ExitConfirm,
|
||||
ReadKeyMenu,
|
||||
Write,
|
||||
WriteSuccess,
|
||||
Emulate,
|
||||
SaveName,
|
||||
SaveSuccess,
|
||||
SelectKey,
|
||||
SavedKeyMenu,
|
||||
SaveData,
|
||||
SaveType,
|
||||
SavedInfo,
|
||||
DeleteConfirm,
|
||||
DeleteSuccess,
|
||||
Rpc,
|
||||
ExtraActions,
|
||||
RawInfo,
|
||||
RawName,
|
||||
RawRead,
|
||||
RawSuccess,
|
||||
};
|
||||
|
||||
class Event {
|
||||
public:
|
||||
union {
|
||||
int32_t signed_int;
|
||||
} payload;
|
||||
|
||||
EventType type;
|
||||
};
|
||||
|
||||
SceneController<GenericScene<LfRfidApp>, LfRfidApp> scene_controller;
|
||||
ViewController<LfRfidApp, SubmenuVM, PopupVM, DialogExVM, TextInputVM, ByteInputVM, ContainerVM>
|
||||
view_controller;
|
||||
|
||||
~LfRfidApp();
|
||||
LfRfidApp();
|
||||
|
||||
RecordController<NotificationApp> notification;
|
||||
RecordController<Storage> storage;
|
||||
RecordController<DialogsApp> dialogs;
|
||||
|
||||
TextStore text_store;
|
||||
|
||||
string_t file_path;
|
||||
|
||||
RpcAppSystem* rpc_ctx;
|
||||
|
||||
void run(void* args);
|
||||
|
||||
static const char* app_folder;
|
||||
static const char* app_sd_folder;
|
||||
static const char* app_extension;
|
||||
static const char* app_filetype;
|
||||
|
||||
bool save_key();
|
||||
bool load_key_from_file_select(bool need_restore);
|
||||
bool delete_key();
|
||||
|
||||
bool load_key_data(string_t path, bool show_dialog);
|
||||
bool save_key_data(string_t path);
|
||||
|
||||
void make_app_folder();
|
||||
|
||||
ProtocolDict* dict;
|
||||
LFRFIDWorker* lfworker;
|
||||
string_t file_name;
|
||||
ProtocolId protocol_id;
|
||||
LFRFIDWorkerReadType read_type;
|
||||
|
||||
uint8_t* old_key_data;
|
||||
uint8_t* new_key_data;
|
||||
|
||||
string_t raw_file_name;
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "lfrfid_app.h"
|
||||
|
||||
// app enter function
|
||||
extern "C" int32_t lfrfid_app(void* args) {
|
||||
LfRfidApp* app = new LfRfidApp();
|
||||
app->run(args);
|
||||
delete app;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ static void lfrfid_cli_read(Cli* cli, string_t args) {
|
||||
string_t info;
|
||||
string_init(info);
|
||||
protocol_dict_render_data(dict, info, context.protocol);
|
||||
if(string_size(info) > 0) {
|
||||
if(!string_empty_p(info)) {
|
||||
printf("%s\r\n", string_get_cstr(info));
|
||||
}
|
||||
string_clear(info);
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
|
||||
#include "m-string.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <cli/cli.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include <gui/modules/widget.h>
|
||||
|
||||
#include <lfrfid/views/lfrfid_view_read.h>
|
||||
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <storage/storage.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
#include <rpc/rpc_app.h>
|
||||
|
||||
#include <toolbox/protocols/protocol_dict.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <lfrfid/lfrfid_dict_file.h>
|
||||
#include <lfrfid/protocols/lfrfid_protocols.h>
|
||||
#include <lfrfid/lfrfid_worker.h>
|
||||
|
||||
#include <lfrfid/scenes/lfrfid_scene.h>
|
||||
|
||||
#define LFRFID_KEY_NAME_SIZE 22
|
||||
#define LFRFID_TEXT_STORE_SIZE 40
|
||||
|
||||
#define LFRFID_APP_FOLDER ANY_PATH("lfrfid")
|
||||
#define LFRFID_SD_FOLDER EXT_PATH("lfrfid")
|
||||
#define LFRFID_APP_EXTENSION ".rfid"
|
||||
#define LFRFID_APP_SHADOW_EXTENSION ".shd"
|
||||
|
||||
#define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw"
|
||||
#define LFRFID_APP_RAW_PSK_EXTENSION ".psk.raw"
|
||||
|
||||
enum LfRfidCustomEvent {
|
||||
LfRfidEventNext = 100,
|
||||
LfRfidEventExit,
|
||||
LfRfidEventPopupClosed,
|
||||
LfRfidEventReadSenseStart,
|
||||
LfRfidEventReadSenseEnd,
|
||||
LfRfidEventReadSenseCardStart,
|
||||
LfRfidEventReadSenseCardEnd,
|
||||
LfRfidEventReadStartASK,
|
||||
LfRfidEventReadStartPSK,
|
||||
LfRfidEventReadDone,
|
||||
LfRfidEventReadOverrun,
|
||||
LfRfidEventReadError,
|
||||
LfRfidEventWriteOK,
|
||||
LfRfidEventWriteProtocolCannotBeWritten,
|
||||
LfRfidEventWriteFobCannotBeWritten,
|
||||
LfRfidEventWriteTooLongToWrite,
|
||||
LfRfidEventRpcLoadFile,
|
||||
LfRfidEventRpcSessionClose,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LfRfidRpcStateIdle,
|
||||
LfRfidRpcStateEmulating,
|
||||
} LfRfidRpcState;
|
||||
|
||||
typedef struct LfRfid LfRfid;
|
||||
|
||||
struct LfRfid {
|
||||
LFRFIDWorker* lfworker;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
NotificationApp* notifications;
|
||||
SceneManager* scene_manager;
|
||||
Storage* storage;
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
|
||||
char text_store[LFRFID_TEXT_STORE_SIZE + 1];
|
||||
string_t file_path;
|
||||
string_t file_name;
|
||||
string_t raw_file_name;
|
||||
|
||||
ProtocolDict* dict;
|
||||
ProtocolId protocol_id;
|
||||
ProtocolId protocol_id_next;
|
||||
LFRFIDWorkerReadType read_type;
|
||||
|
||||
uint8_t* old_key_data;
|
||||
uint8_t* new_key_data;
|
||||
|
||||
RpcAppSystem* rpc_ctx;
|
||||
LfRfidRpcState rpc_state;
|
||||
|
||||
// Common Views
|
||||
Submenu* submenu;
|
||||
DialogEx* dialog_ex;
|
||||
Popup* popup;
|
||||
TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
|
||||
// Custom views
|
||||
LfRfidReadView* read_view;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LfRfidViewSubmenu,
|
||||
LfRfidViewDialogEx,
|
||||
LfRfidViewPopup,
|
||||
LfRfidViewWidget,
|
||||
LfRfidViewTextInput,
|
||||
LfRfidViewByteInput,
|
||||
LfRfidViewRead,
|
||||
} LfRfidView;
|
||||
|
||||
bool lfrfid_save_key(LfRfid* app);
|
||||
|
||||
bool lfrfid_load_key_from_file_select(LfRfid* app);
|
||||
|
||||
bool lfrfid_delete_key(LfRfid* app);
|
||||
|
||||
bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog);
|
||||
|
||||
bool lfrfid_save_key_data(LfRfid* app, string_t path);
|
||||
|
||||
void lfrfid_make_app_folder(LfRfid* app);
|
||||
|
||||
void lfrfid_text_store_set(LfRfid* app, const char* text, ...);
|
||||
|
||||
void lfrfid_text_store_clear(LfRfid* app);
|
||||
|
||||
void lfrfid_popup_timeout_callback(void* context);
|
||||
|
||||
void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context);
|
||||
|
||||
void lfrfid_text_input_callback(void* context);
|
||||
@@ -1,88 +0,0 @@
|
||||
#include "lfrfid_app_scene_delete_confirm.h"
|
||||
#include "../view/elements/button_element.h"
|
||||
#include "../view/elements/icon_element.h"
|
||||
#include "../view/elements/string_element.h"
|
||||
|
||||
void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
string_init(string_data);
|
||||
string_init(string_header);
|
||||
|
||||
auto container = app->view_controller.get<ContainerVM>();
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Left, "Back");
|
||||
button->set_callback(app, LfRfidAppSceneDeleteConfirm::back_callback);
|
||||
|
||||
button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Right, "Delete");
|
||||
button->set_callback(app, LfRfidAppSceneDeleteConfirm::delete_callback);
|
||||
|
||||
auto line_1 = container->add<StringElement>();
|
||||
auto line_2 = container->add<StringElement>();
|
||||
auto line_3 = container->add<StringElement>();
|
||||
|
||||
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
protocol_dict_get_data(app->dict, app->protocol_id, data, size);
|
||||
for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) {
|
||||
if(i != 0) {
|
||||
string_cat_printf(string_data, " ");
|
||||
}
|
||||
|
||||
string_cat_printf(string_data, "%02X", data[i]);
|
||||
}
|
||||
free(data);
|
||||
|
||||
string_printf(string_header, "Delete %s?", string_get_cstr(app->file_name));
|
||||
line_1->set_text(
|
||||
string_get_cstr(string_header), 64, 0, 128 - 2, AlignCenter, AlignTop, FontPrimary);
|
||||
line_2->set_text(
|
||||
string_get_cstr(string_data), 64, 19, 0, AlignCenter, AlignTop, FontSecondary);
|
||||
line_3->set_text(
|
||||
protocol_dict_get_name(app->dict, app->protocol_id),
|
||||
64,
|
||||
49,
|
||||
0,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
FontSecondary);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->delete_key();
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess);
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Stay) {
|
||||
app->scene_controller.switch_to_previous_scene();
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<ContainerVM>()->clean();
|
||||
string_clear(string_data);
|
||||
string_clear(string_header);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneDeleteConfirm::back_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Stay;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneDeleteConfirm::delete_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneDeleteConfirm : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void back_callback(void* context);
|
||||
static void delete_callback(void* context);
|
||||
|
||||
string_t string_header;
|
||||
string_t string_data;
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "lfrfid_app_scene_delete_success.h"
|
||||
|
||||
void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
|
||||
popup->set_icon(0, 2, &I_DolphinMafia_115x62);
|
||||
popup->set_header("Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
popup->set_context(app);
|
||||
popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback);
|
||||
popup->set_timeout(1500);
|
||||
popup->enable_timeout();
|
||||
|
||||
app->view_controller.switch_to<PopupVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneDeleteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::SelectKey});
|
||||
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneDeleteSuccess::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<PopupVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneDeleteSuccess::timeout_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Back;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneDeleteSuccess : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void timeout_callback(void* context);
|
||||
};
|
||||
@@ -1,36 +0,0 @@
|
||||
#include "lfrfid_app_scene_emulate.h"
|
||||
#include <core/common_defines.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
|
||||
popup->set_header("Emulating", 89, 30, AlignCenter, AlignTop);
|
||||
if(string_size(app->file_name)) {
|
||||
popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
|
||||
} else {
|
||||
popup->set_text(
|
||||
protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop);
|
||||
}
|
||||
popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61);
|
||||
|
||||
app->view_controller.switch_to<PopupVM>();
|
||||
lfrfid_worker_start_thread(app->lfworker);
|
||||
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
|
||||
notification_message(app->notification, &sequence_blink_start_magenta);
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneEmulate::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
UNUSED(app);
|
||||
UNUSED(event);
|
||||
bool consumed = false;
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<PopupVM>()->clean();
|
||||
lfrfid_worker_stop(app->lfworker);
|
||||
lfrfid_worker_stop_thread(app->lfworker);
|
||||
notification_message(app->notification, &sequence_blink_stop);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneEmulate : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
#include "lfrfid_app_scene_exit_confirm.h"
|
||||
#include "../view/elements/button_element.h"
|
||||
#include "../view/elements/icon_element.h"
|
||||
#include "../view/elements/string_element.h"
|
||||
|
||||
void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
auto container = app->view_controller.get<ContainerVM>();
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Left, "Exit");
|
||||
button->set_callback(app, LfRfidAppSceneExitConfirm::exit_callback);
|
||||
|
||||
button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Right, "Stay");
|
||||
button->set_callback(app, LfRfidAppSceneExitConfirm::stay_callback);
|
||||
|
||||
auto line_1 = container->add<StringElement>();
|
||||
auto line_2 = container->add<StringElement>();
|
||||
|
||||
line_1->set_text("Exit to RFID Menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
|
||||
line_2->set_text(
|
||||
"All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneExitConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start});
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Stay) {
|
||||
app->scene_controller.switch_to_previous_scene();
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExitConfirm::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<ContainerVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExitConfirm::exit_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExitConfirm::stay_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Stay;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneExitConfirm : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void exit_callback(void* context);
|
||||
static void stay_callback(void* context);
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
#include "lfrfid_app_scene_extra_actions.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuASK,
|
||||
SubmenuPSK,
|
||||
SubmenuRAW,
|
||||
} SubmenuIndex;
|
||||
|
||||
void LfRfidAppSceneExtraActions::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
auto submenu = app->view_controller.get<SubmenuVM>();
|
||||
|
||||
submenu->add_item("Read ASK (Animal, Ordinary Card)", SubmenuASK, submenu_callback, app);
|
||||
submenu->add_item("Read PSK (Indala)", SubmenuPSK, submenu_callback, app);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
submenu->add_item("Read RAW RFID data", SubmenuRAW, submenu_callback, app);
|
||||
}
|
||||
|
||||
if(need_restore) {
|
||||
submenu->set_selected_item(submenu_item_selected);
|
||||
}
|
||||
|
||||
app->view_controller.switch_to<SubmenuVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneExtraActions::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::MenuSelected) {
|
||||
submenu_item_selected = event->payload.signed_int;
|
||||
switch(event->payload.signed_int) {
|
||||
case SubmenuASK:
|
||||
app->read_type = LFRFIDWorkerReadTypeASKOnly;
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
|
||||
break;
|
||||
case SubmenuPSK:
|
||||
app->read_type = LFRFIDWorkerReadTypePSKOnly;
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
|
||||
break;
|
||||
case SubmenuRAW:
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawName);
|
||||
break;
|
||||
}
|
||||
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExtraActions::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<SubmenuVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneExtraActions::submenu_callback(void* context, uint32_t index) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
|
||||
event.type = LfRfidApp::EventType::MenuSelected;
|
||||
event.payload.signed_int = index;
|
||||
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneExtraActions : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void submenu_callback(void* context, uint32_t index);
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
@@ -1,77 +0,0 @@
|
||||
#include "lfrfid_app_scene_raw_info.h"
|
||||
#include "../view/elements/button_element.h"
|
||||
#include "../view/elements/icon_element.h"
|
||||
#include "../view/elements/string_element.h"
|
||||
|
||||
static void ok_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
static void back_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Back;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawInfo::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
string_init(string_info);
|
||||
|
||||
auto container = app->view_controller.get<ContainerVM>();
|
||||
|
||||
bool sd_exist = storage_sd_status(app->storage) == FSE_OK;
|
||||
if(!sd_exist) {
|
||||
auto icon = container->add<IconElement>();
|
||||
icon->set_icon(0, 0, &I_SDQuestion_35x43);
|
||||
auto line = container->add<StringElement>();
|
||||
line->set_text(
|
||||
"No SD card found.\nThis function will not\nwork without\nSD card.",
|
||||
81,
|
||||
4,
|
||||
0,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
FontSecondary);
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Left, "Back");
|
||||
button->set_callback(app, back_callback);
|
||||
} else {
|
||||
string_printf(
|
||||
string_info,
|
||||
"RAW RFID data reader\r\n"
|
||||
"1) Put the Flipper on your card\r\n"
|
||||
"2) Press OK\r\n"
|
||||
"3) Wait until data is read");
|
||||
|
||||
auto line = container->add<StringElement>();
|
||||
line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Center, "OK");
|
||||
button->set_callback(app, ok_callback);
|
||||
}
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneRawInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->scene_controller.switch_to_scene({LfRfidApp::SceneType::RawRead});
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ExtraActions});
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawInfo::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<ContainerVM>()->clean();
|
||||
string_clear(string_info);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneRawInfo : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
string_t string_info;
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
|
||||
#include "lfrfid_app_scene_raw_name.h"
|
||||
#include "m-string.h"
|
||||
#include <lib/toolbox/random_name.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
void LfRfidAppSceneRawName::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
const char* key_name = string_get_cstr(app->raw_file_name);
|
||||
|
||||
bool key_name_empty = (string_size(app->raw_file_name) == 0);
|
||||
if(key_name_empty) {
|
||||
app->text_store.set("RfidRecord");
|
||||
} else {
|
||||
app->text_store.set("%s", key_name);
|
||||
}
|
||||
|
||||
auto text_input = app->view_controller.get<TextInputVM>();
|
||||
text_input->set_header_text("Name the raw file");
|
||||
|
||||
text_input->set_result_callback(
|
||||
save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty);
|
||||
|
||||
app->view_controller.switch_to<TextInputVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneRawName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
string_set_str(app->raw_file_name, app->text_store.text);
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawInfo);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawName::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<TextInputVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawName::save_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneRawName : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void save_callback(void* context);
|
||||
};
|
||||
@@ -1,107 +0,0 @@
|
||||
#include "lfrfid_app_scene_raw_read.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define RAW_READ_TIME 5000
|
||||
|
||||
static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* ctx) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
|
||||
LfRfidApp::Event event;
|
||||
|
||||
switch(result) {
|
||||
case LFRFIDWorkerReadRawFileError:
|
||||
event.type = LfRfidApp::EventType::ReadEventError;
|
||||
break;
|
||||
case LFRFIDWorkerReadRawOverrun:
|
||||
event.type = LfRfidApp::EventType::ReadEventOverrun;
|
||||
break;
|
||||
}
|
||||
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
static void timer_callback(void* ctx) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::ReadEventDone;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawRead::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
string_init(string_file_name);
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
app->view_controller.switch_to<PopupVM>();
|
||||
lfrfid_worker_start_thread(app->lfworker);
|
||||
app->make_app_folder();
|
||||
|
||||
timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app);
|
||||
furi_timer_start(timer, RAW_READ_TIME);
|
||||
string_printf(
|
||||
string_file_name, "%s/%s.ask.raw", app->app_sd_folder, string_get_cstr(app->raw_file_name));
|
||||
popup->set_header("Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop);
|
||||
lfrfid_worker_read_raw_start(
|
||||
app->lfworker,
|
||||
string_get_cstr(string_file_name),
|
||||
LFRFIDWorkerReadTypeASKOnly,
|
||||
lfrfid_read_callback,
|
||||
app);
|
||||
|
||||
notification_message(app->notification, &sequence_blink_start_cyan);
|
||||
|
||||
is_psk = false;
|
||||
error = false;
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneRawRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
UNUSED(app);
|
||||
bool consumed = true;
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
|
||||
switch(event->type) {
|
||||
case LfRfidApp::EventType::ReadEventError:
|
||||
error = true;
|
||||
popup->set_header("Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop);
|
||||
notification_message(app->notification, &sequence_blink_start_red);
|
||||
furi_timer_stop(timer);
|
||||
break;
|
||||
case LfRfidApp::EventType::ReadEventDone:
|
||||
if(!error) {
|
||||
if(is_psk) {
|
||||
notification_message(app->notification, &sequence_success);
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawSuccess);
|
||||
} else {
|
||||
popup->set_header("Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop);
|
||||
notification_message(app->notification, &sequence_blink_start_yellow);
|
||||
lfrfid_worker_stop(app->lfworker);
|
||||
string_printf(
|
||||
string_file_name,
|
||||
"%s/%s.psk.raw",
|
||||
app->app_sd_folder,
|
||||
string_get_cstr(app->raw_file_name));
|
||||
lfrfid_worker_read_raw_start(
|
||||
app->lfworker,
|
||||
string_get_cstr(string_file_name),
|
||||
LFRFIDWorkerReadTypePSKOnly,
|
||||
lfrfid_read_callback,
|
||||
app);
|
||||
furi_timer_start(timer, RAW_READ_TIME);
|
||||
is_psk = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawRead::on_exit(LfRfidApp* app) {
|
||||
notification_message(app->notification, &sequence_blink_stop);
|
||||
app->view_controller.get<PopupVM>()->clean();
|
||||
lfrfid_worker_stop(app->lfworker);
|
||||
lfrfid_worker_stop_thread(app->lfworker);
|
||||
furi_timer_free(timer);
|
||||
string_clear(string_file_name);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneRawRead : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
string_t string_file_name;
|
||||
FuriTimer* timer;
|
||||
bool is_psk;
|
||||
bool error;
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "lfrfid_app_scene_raw_success.h"
|
||||
#include "../view/elements/button_element.h"
|
||||
#include "../view/elements/icon_element.h"
|
||||
#include "../view/elements/string_element.h"
|
||||
|
||||
void LfRfidAppSceneRawSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
string_init(string_info);
|
||||
|
||||
string_printf(string_info, "RAW RFID read success!\r\n");
|
||||
string_cat_printf(string_info, "Now you can analyze files\r\n");
|
||||
string_cat_printf(string_info, "Or send them to developers");
|
||||
|
||||
auto container = app->view_controller.get<ContainerVM>();
|
||||
|
||||
auto line = container->add<StringElement>();
|
||||
line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Center, "OK");
|
||||
button->set_callback(app, LfRfidAppSceneRawSuccess::ok_callback);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneRawSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ExtraActions});
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawSuccess::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<ContainerVM>()->clean();
|
||||
string_clear(string_info);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRawSuccess::ok_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneRawSuccess : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
string_t string_info;
|
||||
static void ok_callback(void* context);
|
||||
};
|
||||
@@ -1,100 +0,0 @@
|
||||
#include "lfrfid_app_scene_read.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
static void lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* ctx) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
|
||||
LfRfidApp::Event event;
|
||||
|
||||
switch(result) {
|
||||
case LFRFIDWorkerReadSenseStart:
|
||||
event.type = LfRfidApp::EventType::ReadEventSenseStart;
|
||||
break;
|
||||
case LFRFIDWorkerReadSenseEnd:
|
||||
event.type = LfRfidApp::EventType::ReadEventSenseEnd;
|
||||
break;
|
||||
case LFRFIDWorkerReadSenseCardStart:
|
||||
event.type = LfRfidApp::EventType::ReadEventSenseCardStart;
|
||||
break;
|
||||
case LFRFIDWorkerReadSenseCardEnd:
|
||||
event.type = LfRfidApp::EventType::ReadEventSenseCardEnd;
|
||||
break;
|
||||
case LFRFIDWorkerReadDone:
|
||||
event.type = LfRfidApp::EventType::ReadEventDone;
|
||||
break;
|
||||
case LFRFIDWorkerReadStartASK:
|
||||
event.type = LfRfidApp::EventType::ReadEventStartASK;
|
||||
break;
|
||||
case LFRFIDWorkerReadStartPSK:
|
||||
event.type = LfRfidApp::EventType::ReadEventStartPSK;
|
||||
break;
|
||||
}
|
||||
|
||||
event.payload.signed_int = protocol;
|
||||
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedRfidRead);
|
||||
if(app->read_type == LFRFIDWorkerReadTypePSKOnly) {
|
||||
popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop);
|
||||
} else {
|
||||
popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop);
|
||||
}
|
||||
|
||||
popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
app->view_controller.switch_to<PopupVM>();
|
||||
lfrfid_worker_start_thread(app->lfworker);
|
||||
lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app);
|
||||
|
||||
notification_message(app->notification, &sequence_blink_start_cyan);
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = true;
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
|
||||
switch(event->type) {
|
||||
case LfRfidApp::EventType::ReadEventSenseStart:
|
||||
notification_message(app->notification, &sequence_blink_stop);
|
||||
notification_message(app->notification, &sequence_blink_start_yellow);
|
||||
break;
|
||||
case LfRfidApp::EventType::ReadEventSenseCardStart:
|
||||
notification_message(app->notification, &sequence_blink_stop);
|
||||
notification_message(app->notification, &sequence_blink_start_green);
|
||||
break;
|
||||
case LfRfidApp::EventType::ReadEventSenseEnd:
|
||||
case LfRfidApp::EventType::ReadEventSenseCardEnd:
|
||||
notification_message(app->notification, &sequence_blink_stop);
|
||||
notification_message(app->notification, &sequence_blink_start_cyan);
|
||||
break;
|
||||
case LfRfidApp::EventType::ReadEventDone:
|
||||
app->protocol_id = event->payload.signed_int;
|
||||
DOLPHIN_DEED(DolphinDeedRfidReadSuccess);
|
||||
notification_message(app->notification, &sequence_success);
|
||||
string_reset(app->file_name);
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess);
|
||||
break;
|
||||
case LfRfidApp::EventType::ReadEventStartPSK:
|
||||
popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop);
|
||||
break;
|
||||
case LfRfidApp::EventType::ReadEventStartASK:
|
||||
popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop);
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneRead::on_exit(LfRfidApp* app) {
|
||||
notification_message(app->notification, &sequence_blink_stop);
|
||||
app->view_controller.get<PopupVM>()->clean();
|
||||
lfrfid_worker_stop(app->lfworker);
|
||||
lfrfid_worker_stop_thread(app->lfworker);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneRead : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
#include "lfrfid_app_scene_read_menu.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuSave,
|
||||
SubmenuEmulate,
|
||||
SubmenuWrite,
|
||||
} SubmenuIndex;
|
||||
|
||||
void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
auto submenu = app->view_controller.get<SubmenuVM>();
|
||||
|
||||
submenu->add_item("Save", SubmenuSave, submenu_callback, app);
|
||||
submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app);
|
||||
submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
|
||||
|
||||
if(need_restore) {
|
||||
submenu->set_selected_item(submenu_item_selected);
|
||||
}
|
||||
|
||||
app->view_controller.switch_to<SubmenuVM>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::MenuSelected) {
|
||||
submenu_item_selected = event->payload.signed_int;
|
||||
switch(event->payload.signed_int) {
|
||||
case SubmenuWrite:
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write);
|
||||
break;
|
||||
case SubmenuSave:
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName);
|
||||
break;
|
||||
case SubmenuEmulate:
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate);
|
||||
break;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.switch_to_previous_scene();
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) {
|
||||
app->view_controller.get<SubmenuVM>()->clean();
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
|
||||
event.type = LfRfidApp::EventType::MenuSelected;
|
||||
event.payload.signed_int = index;
|
||||
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneReadKeyMenu : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void submenu_callback(void* context, uint32_t index);
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
@@ -1,96 +0,0 @@
|
||||
#include "lfrfid_app_scene_read_success.h"
|
||||
#include "../view/elements/button_element.h"
|
||||
#include "../view/elements/icon_element.h"
|
||||
#include "../view/elements/string_element.h"
|
||||
|
||||
void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
|
||||
string_init(string_info);
|
||||
string_init(string_header);
|
||||
|
||||
string_init_printf(
|
||||
string_header,
|
||||
"%s[%s]",
|
||||
protocol_dict_get_name(app->dict, app->protocol_id),
|
||||
protocol_dict_get_manufacturer(app->dict, app->protocol_id));
|
||||
|
||||
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
protocol_dict_get_data(app->dict, app->protocol_id, data, size);
|
||||
for(uint8_t i = 0; i < size; i++) {
|
||||
if(i != 0) {
|
||||
string_cat_printf(string_info, " ");
|
||||
}
|
||||
|
||||
if(i >= 9) {
|
||||
string_cat_printf(string_info, "...");
|
||||
break;
|
||||
} else {
|
||||
string_cat_printf(string_info, "%02X", data[i]);
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
|
||||
string_t render_data;
|
||||
string_init(render_data);
|
||||
protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id);
|
||||
string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data));
|
||||
string_clear(render_data);
|
||||
|
||||
auto container = app->view_controller.get<ContainerVM>();
|
||||
|
||||
auto button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Left, "Retry");
|
||||
button->set_callback(app, LfRfidAppSceneReadSuccess::back_callback);
|
||||
|
||||
button = container->add<ButtonElement>();
|
||||
button->set_type(ButtonElement::Type::Right, "More");
|
||||
button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback);
|
||||
|
||||
auto header = container->add<StringElement>();
|
||||
header->set_text(string_get_cstr(string_header), 0, 2, 0, AlignLeft, AlignTop, FontPrimary);
|
||||
|
||||
auto text = container->add<StringElement>();
|
||||
text->set_text(string_get_cstr(string_info), 0, 16, 0, AlignLeft, AlignTop, FontSecondary);
|
||||
|
||||
app->view_controller.switch_to<ContainerVM>();
|
||||
|
||||
notification_message_block(app->notification, &sequence_set_green_255);
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Next) {
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadKeyMenu);
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Retry) {
|
||||
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::RetryConfirm});
|
||||
consumed = true;
|
||||
} else if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::ExitConfirm});
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) {
|
||||
notification_message_block(app->notification, &sequence_reset_green);
|
||||
app->view_controller.get<ContainerVM>()->clean();
|
||||
string_clear(string_info);
|
||||
string_clear(string_header);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadSuccess::back_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Retry;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadSuccess::more_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Next;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneReadSuccess : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
void on_exit(LfRfidApp* app) final;
|
||||
|
||||
private:
|
||||
static void back_callback(void* context);
|
||||
static void more_callback(void* context);
|
||||
|
||||
string_t string_header;
|
||||
string_t string_info;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user