1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-13 13:09:49 +04:00

Compare commits

..

1 Commits

Author SHA1 Message Date
MX
fc6adcbeb1 WIP - Implement header(preambula) lookup
Bits = unknown
0 = unknown
1 = unknown
2023-02-15 00:42:28 +03:00
613 changed files with 8132 additions and 18341 deletions

View File

@@ -36,6 +36,13 @@ Min level: 1
Max level: 1
Weight: 3
Name: L1_Happy_holidays_128x64
Min butthurt: 0
Max butthurt: 14
Min level: 1
Max level: 3
Weight: 4
Name: L1_Read_books_128x64
Min butthurt: 0
Max butthurt: 8

View File

@@ -198,7 +198,7 @@ steps:
[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
[-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip)
[-Download latest extra apps pack-](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)
[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=release-cfw&version=${DRONE_TAG})
@@ -220,7 +220,7 @@ steps:
commands:
- wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh"
- chmod +x ./discord.sh
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
- name: "Send extra pack build to telegram"
image: appleboy/drone-telegram

View File

@@ -44,6 +44,3 @@
# Functions that always return the same error code
//-V:picopass_device_decrypt:1048
# Examples
//V_EXCLUDE_PATH applications/examples/

View File

@@ -11,10 +11,9 @@
"args": {
"useSingleResult": true,
"env": {
"PATH": "${workspaceFolder};${env:PATH}",
"FBT_QUIET": 1
"PATH": "${workspaceFolder};${env:PATH}"
},
"command": "fbt get_blackmagic",
"command": "./fbt get_blackmagic",
"description": "Get Blackmagic device",
}
}

View File

@@ -1,41 +1,14 @@
### New changes
* If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues!
* SubGHz: Default custom buttons layout for non standard remotes (for example your remote has broken buttons and transmit only 0xC, now you can use other buttons)
* SubGHz: Fix issues with external module 5v power (now all works automatically, enabling +5v manually not required) (**Only for modules that work with 5v->3.3v converter!!!!!**)
* SubGHz: Option to disable automatic 5v power for external modules - (5v is enabled by default, if you are using module without converter you can set this option to OFF)
* SubGHz: Fix and update subghz protocols to use new error system
* SubGHz: Fix default frequency being overwritten bug (Add manually fixes)
* SubGHz: Fix 464Mhz and (390MHz for external module only) was showing up in Frequency analyzer all the time due to noise
* iButton: Fix ibutton app - add manually - duplicate names
* Plugins: NFC Magic fix - reinit nfc at app start
* Plugins: Update **Unitemp - Temperature sensors reader** (DHT11/22, DS18B20, BMP280, HTU21x and more) [(by quen0n)](https://github.com/quen0n/unitemp-flipperzero)
* Plugins: Update **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe)
* Plugins: Massive plugins refactoring - not full refactoring, only small issues is fixed and moved all plugins to furi mutex instead of valuemutex
* Plugins: Many small issues was found and fixed due mutex upgrade
* Plugins: `Extra pack` updated and fixed (valuemutex to furi_mutex upgrade)
* Plugins: SubGHz playlist - rewind (skip or play previous file) [(by alvarotorijano)](https://github.com/alvarotorijano/playListMod/blob/main/playlistMod.c)
* Plugins: Properly rename unirf remix to subghz remote - And automatically migrate user files to new folder (unirf -> subghz_remote)
* Plugins: Fix unirf freeze (protocol deserialize status ok) (by @Willy-JL | PR #375)
* Plugins: Blackjack game: fix bug counting more than one ace (by @403-Fruit | PR #374)
* Plugins: Update POCSAG Pager app to new error system
* Plugins: Update iButton Fuzzer to new iButton system
* Infrared: Update universal remote assets (by @amec0e | PR #378)
* OFW: PicoPass: auth cleanup
* OFW: More UI fixes and improvements
* OFW: NFC: Support reading Mifare Classic key B from sector trailer, reading sector with B key where A key can't read block, Nfc Magic app not using NFC folder by default (in file select)
* OFW: Remove ValueMutex -> **Breaking API change, api was changed from 17.x to 18.x**
* OFW: Support reseting iCx cards
* OFW: Fixed picopass load save file overrun
* OFW: Fix SD card CID parsing
* OFW: Archive browser: update path on dir leave
* OFW: SubGhz: better and more verbose error handling in protocols, stricter CAME validation -> **Breaking API change, api was changed from 16.x to 17.x**
* OFW: iButton system and app refactoring (+new protocols) -> **Breaking API change, api was changed from 15.x to 16.x**
**(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)**
* SubGHz: **Nice ON2E (Nice One)** support (by @assasinfil | PR #335)
* SubGHz: Remove 467.75 From freq analyzer since it has too much noise (Frequency is still can be used, just excluded from FA to avoid false detections)
* Archive and FileBrowser: **Fixed more navigation issues** (by @Willy-JL | PR #334)
* Plugins -> SubGHz Bruteforcer: Fix Linear Delta 3 repeats (now its more stable and we will be sure signal is received correctly)
* Plugins: Updated TOTP (Authenticator) [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
* OFW: **Fix Cyfral & Metakom emulation (My temp fix removed and proper fix from OFW applied)**
* OFW: BadUSB: disable CDC mode, USB mode switch fix
* OFW: Updater visual fixes
* OFW: New pin reset splashscreen
* OFW: Getter for application data path
#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip)
#### [🎲 Download latest extra apps pack](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)
[-> How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)

View File

@@ -12,6 +12,8 @@
Our goal is to make all features possible on this device without any limitations!
Please help us implement emulation for all Sub-GHz dynamic (rolling code) protocols!
<br>
### This software is for experimental purposes only and is not meant for any illegal activity/purposes. <br> We do not condone illegal activity and strongly encourage keeping transmissions to legal/valid uses allowed by law. <br> Also, this software is made without any support from Flipper Devices and is in no way related to the official devs.
@@ -25,7 +27,7 @@ Our Discord Community:
<br>
<br>
## Dev builds (unstable)
## Dev builds
- https://dev.unleashedflip.com/
- https://t.me/kotnehleb
## Releases in Telegram
@@ -35,7 +37,7 @@ Our Discord Community:
* Sub-GHz regional TX restrictions removed
* Sub-GHz frequency 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 (keeloq secure with seed) manual creation
* 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 + all known working apps can be downloaded in extra pack in every release
@@ -43,30 +45,18 @@ Our Discord Community:
* Picopass/iClass plugin included in releases
* Recompiled IR TV Universal Remote for ALL buttons
* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.)
* BadUSB keyboard layouts
* Customizable Flipper name
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
- Sub-GHz -> External CC1101 module support - [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307)
- Sub-GHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
- Sub-GHz -> Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
* Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes
* Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu
* Sub-GHz -> External CC1101 module support
* SubGHz -> **Hold right in received signal list to delete selected signal**
* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis** - now you can use arrow buttons to send signal with different button code
* SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis)
* SubGHz -> Debug mode counter increase settings (+1 -> +5, +10, default: +1)
* SubGHz -> Debug PIN output settings for protocol development
* Infrared -> Debug TX PIN output settings
* Other small fixes and changes throughout
* See other changes in readme below
* See other changes in changelog and in readme below
Also check the changelog in releases for latest updates!
### Current modified and new Sub-GHz protocols list:
Thanks to Official team (to their SubGHz Developer, Skorp) for implementing decoders for these protocols.
Thanks to Official team (to thier SubGHz Developer, Skorp) for implementing decoders for these protocols.
Encoders/sending made by Eng1n33r & @xMasterX:
@@ -80,11 +70,10 @@ Encoders/sending made by Eng1n33r & @xMasterX:
- Keeloq: FAAC RC,XT
- Keeloq: Mutancode
- Keeloq: Normstahl
- Keeloq: Beninca
- CAME Atomo
- Nice Flor S
- FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: Nano#8998)]
- Keeloq: BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)]
- BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)]
- Security+ v1 & v2
- Star Line
@@ -129,6 +118,7 @@ You can support us by using links or addresses below:
- 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)
- USB Keyboard plugin [(by huuck)](https://github.com/huuck/FlipperZeroUSBKeyboard)
- WAV Player [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - Fixed and improved by [LTVA1](https://github.com/LTVA1/wav_player)
- Barcode generator plugin [(original by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - [EAN-8 and refactoring](https://github.com/DarkFlippers/unleashed-firmware/pull/154) by @msvsergey
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
@@ -152,7 +142,6 @@ You can support us by using links or addresses below:
- Text Viewer [(by kowalski7cc & kyhwana)](https://github.com/kowalski7cc/flipper-zero-text-viewer/tree/refactor-text-app)
- **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main)
- **ProtoView** [(by antirez)](https://github.com/antirez/protoview)
- **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe)
Games:
- DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)
@@ -168,6 +157,15 @@ Games:
- BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games)
- 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game)
### Other changes
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
- Sub-GHz -> External CC1101 module support - [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307)
- Sub-GHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
- Sub-GHz -> Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
# Instructions
## [- How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
@@ -180,20 +178,12 @@ Games:
## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md)
### **Sub-GHz**
## [- Transmission is blocked? - How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
### **Plugins**
## [- 🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/unleashed-extra-pack)
## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
## [- TOTP (Authenticator) config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md)
## [- Barcode Generator](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
@@ -228,12 +218,20 @@ Games:
## [- How to use: [GPIO] SentrySafe plugin](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md)
### **Sub-GHz**
## [- Transmission is blocked? - How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
<br>
<br>
# Where I can find IR, Sub-GHz, ... files, DBs, and other stuff?
## [UberGuidoZ Playground - Large collection of files - Github](https://github.com/UberGuidoZ/Flipper)
## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero)
## [CAME-12bit, NICE-12bit, Linear-10bit, PT-2240 - Sub-GHz fixed code bruteforce](https://github.com/tobiabocchi/flipperzero-bruteforce)
## [SMC5326, UNILARM - Sub-GHz fixed code bruteforce](https://github.com/Hong5489/flipperzero-gate-bruteforce)
<br>
<br>
@@ -241,9 +239,6 @@ Games:
# Links
* Unofficial Discord: [discord.unleashedflip.com](https://discord.unleashedflip.com)
* Hello world - plugin tutorial (English): [https://github.com/DroomOne/Flipper-Plugin-Tutorial](https://github.com/DroomOne/Flipper-Plugin-Tutorial)
* Hello world - plugin tutorial (in Russian): [https://yakovlev.me/hello-flipper-zero/](https://yakovlev.me/hello-flipper-zero/)
* CLion IDE - How to setup workspace for flipper firmware development: [https://krasovs.ky/2022/11/01/flipper-zero-clion.html](https://krasovs.ky/2022/11/01/flipper-zero-clion.html)
* Docs by atmanos / How to write your own app (outdated API): [https://flipper.atmanos.com/docs/overview/intro](https://flipper.atmanos.com/docs/overview/intro)
* Official Docs: [http://docs.flipperzero.one](http://docs.flipperzero.one)

View File

@@ -139,7 +139,7 @@ if GetOption("fullenv") or any(
basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"])
distenv.Default(basic_dist)
dist_dir = distenv.GetProjectDirName()
dist_dir = distenv.GetProjetDirName()
fap_dist = [
distenv.Install(
distenv.Dir(f"#/dist/{dist_dir}/apps/debug_elf"),

View File

@@ -11,7 +11,6 @@ typedef struct {
uint16_t left;
uint16_t right;
uint16_t ok;
FuriMutex* mutex;
} KeypadTestState;
static void keypad_test_reset_state(KeypadTestState* state) {
@@ -23,8 +22,7 @@ static void keypad_test_reset_state(KeypadTestState* state) {
}
static void keypad_test_render_callback(Canvas* canvas, void* ctx) {
KeypadTestState* state = ctx;
furi_mutex_acquire(state->mutex, FuriWaitForever);
KeypadTestState* state = (KeypadTestState*)acquire_mutex((ValueMutex*)ctx, 25);
canvas_clear(canvas);
char strings[5][20];
@@ -53,7 +51,7 @@ static void keypad_test_render_callback(Canvas* canvas, void* ctx) {
canvas_draw_str(canvas, 10, 63, "[back] - reset, hold to exit");
furi_mutex_release(state->mutex);
release_mutex((ValueMutex*)ctx, state);
}
static void keypad_test_input_callback(InputEvent* input_event, void* ctx) {
@@ -66,17 +64,17 @@ int32_t keypad_test_app(void* p) {
FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent));
furi_check(event_queue);
KeypadTestState state = {{false, false, false, false, false}, 0, 0, 0, 0, 0, NULL};
state.mutex = furi_mutex_alloc(FuriMutexTypeNormal);
KeypadTestState _state = {{false, false, false, false, false}, 0, 0, 0, 0, 0};
if(!state.mutex) {
ValueMutex state_mutex;
if(!init_mutex(&state_mutex, &_state, sizeof(KeypadTestState))) {
FURI_LOG_E(TAG, "cannot create mutex");
return 0;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, keypad_test_render_callback, &state);
view_port_draw_callback_set(view_port, keypad_test_render_callback, &state_mutex);
view_port_input_callback_set(view_port, keypad_test_input_callback, event_queue);
// Open GUI and register view_port
@@ -85,7 +83,7 @@ int32_t keypad_test_app(void* p) {
InputEvent event;
while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
furi_mutex_acquire(state.mutex, FuriWaitForever);
KeypadTestState* state = (KeypadTestState*)acquire_mutex_block(&state_mutex);
FURI_LOG_I(
TAG,
"key: %s type: %s",
@@ -94,54 +92,54 @@ int32_t keypad_test_app(void* p) {
if(event.key == InputKeyRight) {
if(event.type == InputTypePress) {
state.press[0] = true;
state->press[0] = true;
} else if(event.type == InputTypeRelease) {
state.press[0] = false;
state->press[0] = false;
} else if(event.type == InputTypeShort) {
++state.right;
++state->right;
}
} else if(event.key == InputKeyLeft) {
if(event.type == InputTypePress) {
state.press[1] = true;
state->press[1] = true;
} else if(event.type == InputTypeRelease) {
state.press[1] = false;
state->press[1] = false;
} else if(event.type == InputTypeShort) {
++state.left;
++state->left;
}
} else if(event.key == InputKeyUp) {
if(event.type == InputTypePress) {
state.press[2] = true;
state->press[2] = true;
} else if(event.type == InputTypeRelease) {
state.press[2] = false;
state->press[2] = false;
} else if(event.type == InputTypeShort) {
++state.up;
++state->up;
}
} else if(event.key == InputKeyDown) {
if(event.type == InputTypePress) {
state.press[3] = true;
state->press[3] = true;
} else if(event.type == InputTypeRelease) {
state.press[3] = false;
state->press[3] = false;
} else if(event.type == InputTypeShort) {
++state.down;
++state->down;
}
} else if(event.key == InputKeyOk) {
if(event.type == InputTypePress) {
state.press[4] = true;
state->press[4] = true;
} else if(event.type == InputTypeRelease) {
state.press[4] = false;
state->press[4] = false;
} else if(event.type == InputTypeShort) {
++state.ok;
++state->ok;
}
} else if(event.key == InputKeyBack) {
if(event.type == InputTypeLong) {
furi_mutex_release(state.mutex);
release_mutex(&state_mutex, state);
break;
} else if(event.type == InputTypeShort) {
keypad_test_reset_state(&state);
keypad_test_reset_state(state);
}
}
furi_mutex_release(state.mutex);
release_mutex(&state_mutex, state);
view_port_update(view_port);
}
@@ -149,7 +147,7 @@ int32_t keypad_test_app(void* p) {
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(state.mutex);
delete_mutex(&state_mutex);
furi_record_close(RECORD_GUI);

View File

@@ -53,17 +53,15 @@ static void (*text_box_test_render[])(Canvas* canvas) = {
typedef struct {
uint32_t idx;
FuriMutex* mutex;
} TextBoxTestState;
static void text_box_test_render_callback(Canvas* canvas, void* ctx) {
TextBoxTestState* state = ctx;
furi_mutex_acquire(state->mutex, FuriWaitForever);
TextBoxTestState* state = acquire_mutex((ValueMutex*)ctx, 25);
canvas_clear(canvas);
text_box_test_render[state->idx](canvas);
furi_mutex_release(state->mutex);
release_mutex((ValueMutex*)ctx, state);
}
static void text_box_test_input_callback(InputEvent* input_event, void* ctx) {
@@ -76,17 +74,17 @@ int32_t text_box_test_app(void* p) {
FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent));
furi_check(event_queue);
TextBoxTestState state = {.idx = 0, .mutex = NULL};
state.mutex = furi_mutex_alloc(FuriMutexTypeNormal);
TextBoxTestState _state = {.idx = 0};
if(!state.mutex) {
ValueMutex state_mutex;
if(!init_mutex(&state_mutex, &_state, sizeof(TextBoxTestState))) {
FURI_LOG_E(TAG, "Cannot create mutex");
return 0;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, text_box_test_render_callback, &state);
view_port_draw_callback_set(view_port, text_box_test_render_callback, &state_mutex);
view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue);
// Open GUI and register view_port
@@ -96,24 +94,24 @@ int32_t text_box_test_app(void* p) {
uint32_t test_renders_num = COUNT_OF(text_box_test_render);
InputEvent event;
while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
furi_mutex_acquire(state.mutex, FuriWaitForever);
TextBoxTestState* state = acquire_mutex_block(&state_mutex);
if(event.type == InputTypeShort) {
if(event.key == InputKeyRight) {
if(state.idx < test_renders_num - 1) {
state.idx++;
if(state->idx < test_renders_num - 1) {
state->idx++;
}
} else if(event.key == InputKeyLeft) {
if(state.idx > 0) {
state.idx--;
if(state->idx > 0) {
state->idx--;
}
} else if(event.key == InputKeyBack) {
furi_mutex_release(state.mutex);
release_mutex(&state_mutex, state);
break;
}
}
furi_mutex_release(state.mutex);
release_mutex(&state_mutex, state);
view_port_update(view_port);
}
@@ -121,7 +119,7 @@ int32_t text_box_test_app(void* p) {
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(state.mutex);
delete_mutex(&state_mutex);
furi_record_close(RECORD_GUI);

View File

@@ -5,6 +5,7 @@
// v2 tests
void test_furi_create_open();
void test_furi_valuemutex();
void test_furi_concurrent_access();
void test_furi_pubsub();
@@ -29,6 +30,10 @@ MU_TEST(mu_test_furi_create_open) {
test_furi_create_open();
}
MU_TEST(mu_test_furi_valuemutex) {
test_furi_valuemutex();
}
MU_TEST(mu_test_furi_pubsub) {
test_furi_pubsub();
}
@@ -46,6 +51,7 @@ MU_TEST_SUITE(test_suite) {
// v2 tests
MU_RUN_TEST(mu_test_furi_create_open);
MU_RUN_TEST(mu_test_furi_valuemutex);
MU_RUN_TEST(mu_test_furi_pubsub);
MU_RUN_TEST(mu_test_furi_memmgr);
}

View File

@@ -0,0 +1,41 @@
#include <stdio.h>
#include <string.h>
#include <furi.h>
#include "../minunit.h"
void test_furi_valuemutex() {
const int init_value = 0xdeadbeef;
const int changed_value = 0x12345678;
int value = init_value;
bool result;
ValueMutex valuemutex;
// init mutex case
result = init_mutex(&valuemutex, &value, sizeof(value));
mu_assert(result, "init mutex failed");
// acquire mutex case
int* value_pointer = acquire_mutex(&valuemutex, 100);
mu_assert_pointers_eq(value_pointer, &value);
// second acquire mutex case
int* value_pointer_second = acquire_mutex(&valuemutex, 100);
mu_assert_pointers_eq(value_pointer_second, NULL);
// change value case
*value_pointer = changed_value;
mu_assert_int_eq(value, changed_value);
// release mutex case
result = release_mutex(&valuemutex, &value);
mu_assert(result, "release mutex failed");
// TODO
//acquire mutex blocking case
//write mutex blocking case
//read mutex blocking case
mu_check(delete_mutex(&valuemutex));
}

View File

@@ -3,63 +3,56 @@
#include "../minunit.h"
static void power_test_deinit(void) {
// Try to reset to default charge voltage limit
furi_hal_power_set_battery_charge_voltage_limit(4.208f);
// Try to reset to default charging voltage
furi_hal_power_set_battery_charging_voltage(4.208f);
}
MU_TEST(test_power_charge_voltage_limit_exact) {
// Power of 16mV charge voltage limits get applied exactly
MU_TEST(test_power_charge_voltage_exact) {
// Power of 16mV charge voltages get applied exactly
// (bq25896 charge controller works in 16mV increments)
//
// This test may need adapted if other charge controllers are used in the future.
for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) {
float charge_volt = (float)charge_mv / 1000.0f;
furi_hal_power_set_battery_charge_voltage_limit(charge_volt);
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charging_voltage(charge_volt);
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charging_voltage());
}
}
MU_TEST(test_power_charge_voltage_limit_floating_imprecision) {
MU_TEST(test_power_charge_voltage_floating_imprecision) {
// 4.016f should act as 4.016 V, even with floating point imprecision
furi_hal_power_set_battery_charge_voltage_limit(4.016f);
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charging_voltage(4.016f);
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charging_voltage());
}
MU_TEST(test_power_charge_voltage_limit_inexact) {
// Charge voltage limits that are not power of 16mV get truncated down
furi_hal_power_set_battery_charge_voltage_limit(3.841f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
MU_TEST(test_power_charge_voltage_inexact) {
// Charge voltages that are not power of 16mV get truncated down
furi_hal_power_set_battery_charging_voltage(3.841f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
furi_hal_power_set_battery_charge_voltage_limit(3.900f);
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charging_voltage(3.900f);
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charging_voltage());
furi_hal_power_set_battery_charge_voltage_limit(4.200f);
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charging_voltage(4.200f);
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charging_voltage());
}
MU_TEST(test_power_charge_voltage_limit_invalid_clamped) {
// Out-of-range charge voltage limits get clamped to 3.840 V and 4.208 V
furi_hal_power_set_battery_charge_voltage_limit(3.808f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charge_voltage_limit(1.0f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
MU_TEST(test_power_charge_voltage_invalid_clamped) {
// Out-of-range charge voltages get clamped to 3.840 V and 4.208 V
furi_hal_power_set_battery_charging_voltage(3.808f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
// NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an
// unhappy battery if this fails.
furi_hal_power_set_battery_charge_voltage_limit(4.240f);
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
// Likewise, picking a number that the uint8_t wraparound in the driver would result in a
// VREG value under 23 if this test fails.
// E.g. (uint8_t)((8105-3840)/16) -> 10
furi_hal_power_set_battery_charge_voltage_limit(8.105f);
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charging_voltage(4.240f);
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charging_voltage());
}
MU_TEST_SUITE(test_power_suite) {
MU_RUN_TEST(test_power_charge_voltage_limit_exact);
MU_RUN_TEST(test_power_charge_voltage_limit_floating_imprecision);
MU_RUN_TEST(test_power_charge_voltage_limit_inexact);
MU_RUN_TEST(test_power_charge_voltage_limit_invalid_clamped);
MU_RUN_TEST(test_power_charge_voltage_exact);
MU_RUN_TEST(test_power_charge_voltage_floating_imprecision);
MU_RUN_TEST(test_power_charge_voltage_inexact);
MU_RUN_TEST(test_power_charge_voltage_invalid_clamped);
power_test_deinit();
}

View File

@@ -191,7 +191,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) {
size_t size = strlen(clean_dir) + strlen(name) + 1 + 1;
char* fullname = malloc(size);
snprintf(fullname, size, "%s/%s", clean_dir, name);
if(file_info_is_dir(&fileinfo)) {
if(fileinfo.flags & FSF_DIRECTORY) {
clean_directory(fs_api, fullname);
}
FS_Error error = storage_common_remove(fs_api, fullname);
@@ -608,8 +608,9 @@ static void test_rpc_storage_list_create_expected_list(
}
if(path_contains_only_ascii(name)) {
list->file[i].type = file_info_is_dir(&fileinfo) ? PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_FILE;
list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ?
PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_FILE;
list->file[i].size = fileinfo.size;
list->file[i].data = NULL;
/* memory free inside rpc_encode_and_send() -> pb_release() */
@@ -872,7 +873,7 @@ static void test_rpc_storage_stat_run(const char* path, uint32_t command_id) {
if(error == FSE_OK) {
response->which_content = PB_Main_storage_stat_response_tag;
response->content.storage_stat_response.has_file = true;
response->content.storage_stat_response.file.type = file_info_is_dir(&fileinfo) ?
response->content.storage_stat_response.file.type = (fileinfo.flags & FSF_DIRECTORY) ?
PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_FILE;
response->content.storage_stat_response.file.size = fileinfo.size;

View File

@@ -179,7 +179,7 @@ MU_TEST_1(test_dirwalk_full, Storage* storage) {
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
}
dir_walk_free(dir_walk);
@@ -204,7 +204,7 @@ MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) {
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
}
dir_walk_free(dir_walk);
@@ -219,7 +219,7 @@ static bool test_dirwalk_filter_no_folder_ext(const char* name, FileInfo* filein
UNUSED(ctx);
// only files
if(!file_info_is_dir(fileinfo)) {
if(!(fileinfo->flags & FSF_DIRECTORY)) {
// with ".test" in name
if(strstr(name, ".test") != NULL) {
return true;
@@ -243,7 +243,7 @@ MU_TEST_1(test_dirwalk_filter, Storage* storage) {
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
}
dir_walk_free(dir_walk);

View File

@@ -2,40 +2,9 @@
#include <furi.h>
#include <storage/storage.h>
// DO NOT USE THIS IN PRODUCTION CODE
// This is a hack to access internal storage functions and definitions
#include <storage/storage_i.h>
#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path)
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
#define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir")
static bool storage_file_create(Storage* storage, const char* path, const char* data) {
File* file = storage_file_alloc(storage);
bool result = false;
do {
if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_NEW)) {
break;
}
if(storage_file_write(file, data, strlen(data)) != strlen(data)) {
break;
}
if(!storage_file_close(file)) {
break;
}
result = true;
} while(0);
storage_file_free(file);
return result;
}
static void storage_file_open_lock_setup() {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
@@ -146,7 +115,7 @@ static int32_t storage_dir_locker(void* ctx) {
File* file = storage_file_alloc(storage);
furi_check(storage_dir_open(file, STORAGE_LOCKED_DIR));
furi_semaphore_release(semaphore);
furi_delay_ms(100);
furi_delay_ms(1000);
furi_check(storage_dir_close(file));
furi_record_close(RECORD_STORAGE);
@@ -183,21 +152,9 @@ MU_TEST(storage_dir_open_lock) {
mu_assert(result, "cannot open locked dir");
}
MU_TEST(storage_dir_exists_test) {
Storage* storage = furi_record_open(RECORD_STORAGE);
mu_check(!storage_dir_exists(storage, STORAGE_TEST_DIR));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, STORAGE_TEST_DIR));
mu_check(storage_dir_exists(storage, STORAGE_TEST_DIR));
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, STORAGE_TEST_DIR));
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(storage_dir) {
MU_RUN_TEST(storage_dir_open_close);
MU_RUN_TEST(storage_dir_open_lock);
MU_RUN_TEST(storage_dir_exists_test);
}
static const char* const storage_copy_test_paths[] = {
@@ -346,256 +303,9 @@ MU_TEST_SUITE(storage_rename) {
furi_record_close(RECORD_STORAGE);
}
#define APPSDATA_APP_PATH(path) APPS_DATA_PATH "/" path
static const char* storage_test_apps[] = {
"-_twilight_-",
"-_rainbow_-",
"-_pinkie_-",
"-_apple_-",
"-_flutter_-",
"-_rare_-",
};
static size_t storage_test_apps_count = COUNT_OF(storage_test_apps);
static int32_t storage_test_app(void* arg) {
UNUSED(arg);
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_remove(storage, "/app/test");
int32_t ret = storage_file_create(storage, "/app/test", "test");
furi_record_close(RECORD_STORAGE);
return ret;
}
MU_TEST(test_storage_data_path_apps) {
for(size_t i = 0; i < storage_test_apps_count; i++) {
FuriThread* thread =
furi_thread_alloc_ex(storage_test_apps[i], 1024, storage_test_app, NULL);
furi_thread_set_appid(thread, storage_test_apps[i]);
furi_thread_start(thread);
furi_thread_join(thread);
mu_assert_int_eq(true, furi_thread_get_return_code(thread));
// Check if app data dir and file exists
Storage* storage = furi_record_open(RECORD_STORAGE);
FuriString* expected = furi_string_alloc();
furi_string_printf(expected, APPSDATA_APP_PATH("%s"), storage_test_apps[i]);
mu_check(storage_dir_exists(storage, furi_string_get_cstr(expected)));
furi_string_cat(expected, "/test");
mu_check(storage_file_exists(storage, furi_string_get_cstr(expected)));
furi_string_printf(expected, APPSDATA_APP_PATH("%s"), storage_test_apps[i]);
storage_simply_remove_recursive(storage, furi_string_get_cstr(expected));
furi_record_close(RECORD_STORAGE);
furi_string_free(expected);
furi_thread_free(thread);
}
}
MU_TEST(test_storage_data_path) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
mu_check(storage_dir_open(file, "/app"));
mu_check(storage_dir_close(file));
storage_file_free(file);
// check that appsdata folder exists
mu_check(storage_dir_exists(storage, APPS_DATA_PATH));
// check that cli folder exists
mu_check(storage_dir_exists(storage, APPSDATA_APP_PATH("cli")));
storage_simply_remove(storage, APPSDATA_APP_PATH("cli"));
furi_record_close(RECORD_STORAGE);
}
MU_TEST(test_storage_common_migrate) {
Storage* storage = furi_record_open(RECORD_STORAGE);
// Setup test folders
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from non existing
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
// Test migration from existing folder to non existing
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file1"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file2.ext"), "test2"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file3.ext.ext"), "test3"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file1")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file2.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext.ext")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
// Test migration from existing folder to existing folder
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file1"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file2.ext"), "test2"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file3.ext.ext"), "test3"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file1")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file2.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file11")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file21.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext1.ext")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from empty folder to existing file
// Expected result: FSE_OK, folder removed, file untouched
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from empty folder to existing folder
// Expected result: FSE_OK, old folder removed, new folder untouched
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_new")));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from existing file to non existing, no extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from existing file to non existing, with extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old.file"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old.file"), UNIT_TESTS_PATH("migrate_new.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new.file")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old.file")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new.file"));
// Test migration from existing file to existing file, no extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new"), "test2"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1"));
// Test migration from existing file to existing file, with extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old.file"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new.file"), "test2"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old.file"), UNIT_TESTS_PATH("migrate_new.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new.file")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1.file")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1.file"));
// Test migration from existing file to existing folder
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_new")));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1"));
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(test_data_path) {
MU_RUN_TEST(test_storage_data_path);
MU_RUN_TEST(test_storage_data_path_apps);
}
MU_TEST_SUITE(test_storage_common) {
MU_RUN_TEST(test_storage_common_migrate);
}
int run_minunit_test_storage() {
MU_RUN_SUITE(storage_file);
MU_RUN_SUITE(storage_dir);
MU_RUN_SUITE(storage_rename);
MU_RUN_SUITE(test_data_path);
MU_RUN_SUITE(test_storage_common);
return MU_EXIT_CODE;
}

View File

@@ -1,18 +0,0 @@
# Apps Data folder Example
This example demonstrates how to utilize the Apps Data folder to store data that is not part of the app itself, such as user data, configuration files, and so forth.
## What is the Apps Data Folder?
The **Apps Data** folder is a folder used to store data for external apps that are not part of the main firmware.
The path to the current application folder is related to the `appid` of the app. The `appid` is used to identify the app in the app store and is stored in the `application.fam` file.
The Apps Data folder is located only on the external storage, the SD card.
For example, if the `appid` of the app is `snake_game`, the path to the Apps Data folder will be `/ext/apps_data/snake_game`. But using raw paths is not recommended, because the path to the Apps Data folder can change in the future. Use the `/app` alias instead.
## How to get the path to the Apps Data folder?
You can use `/app` alias to get the path to the current application data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `/app/config.txt`. But this way is not recommended, because even the `/app` alias can change in the future.
We recommend to use the `APP_DATA_PATH` macro to get the path to the Apps Data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `APP_DATA_PATH("config.txt")`.

View File

@@ -1,9 +0,0 @@
App(
appid="example_apps_data",
name="Example: Apps Data",
apptype=FlipperAppType.EXTERNAL,
entry_point="example_apps_data_main",
requires=["gui"],
stack_size=1 * 1024,
fap_category="Examples",
)

View File

@@ -1,40 +0,0 @@
#include <furi.h>
#include <storage/storage.h>
// Define log tag
#define TAG "example_apps_data"
// Application entry point
int32_t example_apps_data_main(void* p) {
// Mark argument as unused
UNUSED(p);
// Open storage
Storage* storage = furi_record_open(RECORD_STORAGE);
// Allocate file
File* file = storage_file_alloc(storage);
// Get the path to the current application data folder
// That is: /ext/apps_data/<app_name>
// And it will create folders in the path if they don't exist
// In this example it will create /ext/apps_data/example_apps_data
// And file will be /ext/apps_data/example_apps_data/test.txt
// Open file, write data and close it
if(!storage_file_open(file, APP_DATA_PATH("test.txt"), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
FURI_LOG_E(TAG, "Failed to open file");
}
if(!storage_file_write(file, "Hello World!", strlen("Hello World!"))) {
FURI_LOG_E(TAG, "Failed to write to file");
}
storage_file_close(file);
// Deallocate file
storage_file_free(file);
// Close storage
furi_record_close(RECORD_STORAGE);
return 0;
}

View File

@@ -14,7 +14,7 @@ App(
"fap_loader",
"archive",
"clock",
"subghz_remote",
"unirfremix",
],
)

View File

@@ -451,7 +451,7 @@ static bool archive_is_dir_exists(FuriString* path) {
FileInfo file_info;
Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) {
if(file_info_is_dir(&file_info)) {
if(file_info.flags & FSF_DIRECTORY) {
state = true;
}
}
@@ -532,16 +532,12 @@ void archive_enter_dir(ArchiveBrowserView* browser, FuriString* path) {
browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false);
furi_string_set(browser->path, path);
file_browser_worker_folder_enter(browser->worker, path, idx_temp);
}
void archive_leave_dir(ArchiveBrowserView* browser) {
furi_assert(browser);
size_t dirname_start = furi_string_search_rchar(browser->path, '/');
furi_string_left(browser->path, dirname_start);
file_browser_worker_folder_exit(browser->worker);
}

View File

@@ -160,7 +160,7 @@ bool archive_favorites_read(void* context) {
if(storage_file_exists(storage, furi_string_get_cstr(buffer))) {
storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info);
archive_add_file_item(
browser, file_info_is_dir(&file_info), furi_string_get_cstr(buffer));
browser, (file_info.flags & FSF_DIRECTORY), furi_string_get_cstr(buffer));
file_count++;
} else {
need_refresh = true;

View File

@@ -96,7 +96,7 @@ void archive_delete_file(void* context, const char* format, ...) {
bool res = false;
if(file_info_is_dir(&fileinfo)) {
if(fileinfo.flags & FSF_DIRECTORY) {
res = storage_simply_remove_recursive(fs_api, furi_string_get_cstr(filename));
} else {
res = (storage_common_remove(fs_api, furi_string_get_cstr(filename)) == FSE_OK);

View File

@@ -142,6 +142,10 @@ void bad_usb_app_free(BadUsbApp* app) {
app->bad_usb_script = NULL;
}
if(app->usb_if_prev) {
furi_check(furi_hal_usb_set_config(app->usb_if_prev, NULL));
}
// Views
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
bad_usb_free(app->bad_usb_view);
@@ -168,10 +172,6 @@ void bad_usb_app_free(BadUsbApp* app) {
furi_string_free(app->file_path);
furi_string_free(app->keyboard_layout);
if(app->usb_if_prev) {
furi_check(furi_hal_usb_set_config(app->usb_if_prev, NULL));
}
free(app);
}

View File

@@ -32,7 +32,6 @@ struct BadUsbScript {
FuriString* file_path;
uint32_t defdelay;
uint16_t layout[128];
uint32_t stringdelay;
FuriThread* thread;
uint8_t file_buf[FILE_BUFFER_LEN + 1];
uint8_t buf_start;
@@ -114,8 +113,6 @@ static const char ducky_cmd_delay[] = {"DELAY "};
static const char ducky_cmd_string[] = {"STRING "};
static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "};
static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "};
static const char ducky_cmd_stringdelay_1[] = {"STRINGDELAY "};
static const char ducky_cmd_stringdelay_2[] = {"STRING_DELAY "};
static const char ducky_cmd_repeat[] = {"REPEAT "};
static const char ducky_cmd_sysrq[] = {"SYSRQ "};
@@ -214,19 +211,14 @@ static bool ducky_altstring(const char* param) {
static bool ducky_string(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0;
while(param[i] != '\0') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]);
if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode);
if(bad_usb->stringdelay > 0) {
furi_delay_ms(bad_usb->stringdelay);
}
}
i++;
}
bad_usb->stringdelay = 0;
return true;
}
@@ -285,20 +277,6 @@ static int32_t
snprintf(error, error_len, "Invalid number %s", line_tmp);
}
return (state) ? (0) : SCRIPT_STATE_ERROR;
} else if(
(strncmp(line_tmp, ducky_cmd_stringdelay_1, strlen(ducky_cmd_stringdelay_1)) == 0) ||
(strncmp(line_tmp, ducky_cmd_stringdelay_2, strlen(ducky_cmd_stringdelay_2)) == 0)) {
//STRINGDELAY, finally it's here
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
state = ducky_get_number(line_tmp, &bad_usb->stringdelay);
if((state) && (bad_usb->stringdelay > 0)) {
return state;
}
if(error != NULL) {
snprintf(error, error_len, "Invalid number %s", line_tmp);
}
return SCRIPT_STATE_ERROR;
} else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
// STRING
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
@@ -506,19 +484,6 @@ static void bad_usb_hid_state_callback(bool state, void* context) {
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect);
}
static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) {
uint32_t flags = furi_thread_flags_get();
furi_check((flags & FuriFlagError) == 0);
if(flags == 0) {
flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
} else {
uint32_t state = furi_thread_flags_clear(flags);
furi_check((state & FuriFlagError) == 0);
}
return flags;
}
static int32_t bad_usb_worker(void* context) {
BadUsbScript* bad_usb = context;
@@ -555,9 +520,11 @@ static int32_t bad_usb_worker(void* context) {
bad_usb->st.state = worker_state;
} else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever);
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle,
FuriFlagWaitAny,
FuriWaitForever);
furi_check((flags & FuriFlagError) == 0);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) {
@@ -568,9 +535,11 @@ static int32_t bad_usb_worker(void* context) {
bad_usb->st.state = worker_state;
} else if(worker_state == BadUsbStateIdle) { // State: ready to start
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriWaitForever);
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect,
FuriFlagWaitAny,
FuriWaitForever);
furi_check((flags & FuriFlagError) == 0);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtToggle) { // Start executing script
@@ -579,7 +548,6 @@ static int32_t bad_usb_worker(void* context) {
bad_usb->buf_len = 0;
bad_usb->st.line_cur = 0;
bad_usb->defdelay = 0;
bad_usb->stringdelay = 0;
bad_usb->repeat_cnt = 0;
bad_usb->file_end = false;
storage_file_seek(script_file, 0, true);
@@ -590,9 +558,11 @@ static int32_t bad_usb_worker(void* context) {
bad_usb->st.state = worker_state;
} else if(worker_state == BadUsbStateWillRun) { // State: start on connection
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever);
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle,
FuriFlagWaitAny,
FuriWaitForever);
furi_check((flags & FuriFlagError) == 0);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) { // Start executing script
@@ -601,22 +571,12 @@ static int32_t bad_usb_worker(void* context) {
bad_usb->buf_len = 0;
bad_usb->st.line_cur = 0;
bad_usb->defdelay = 0;
bad_usb->stringdelay = 0;
bad_usb->repeat_cnt = 0;
bad_usb->file_end = false;
storage_file_seek(script_file, 0, true);
// extra time for PC to recognize Flipper as keyboard
flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtToggle,
FuriFlagWaitAny | FuriFlagNoClear,
1500);
if(flags == (unsigned)FuriFlagErrorTimeout) {
// If nothing happened - start script execution
worker_state = BadUsbStateRunning;
} else if(flags & WorkerEvtToggle) {
worker_state = BadUsbStateIdle;
furi_thread_flags_clear(WorkerEvtToggle);
}
furi_thread_flags_wait(0, FuriFlagWaitAny, 1500);
worker_state = BadUsbStateRunning;
} else if(flags & WorkerEvtToggle) { // Cancel scheduled execution
worker_state = BadUsbStateNotConnected;
}
@@ -626,7 +586,6 @@ static int32_t bad_usb_worker(void* context) {
uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur);
delay_val -= delay_cur;
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
@@ -670,9 +629,9 @@ static int32_t bad_usb_worker(void* context) {
} else if(
(worker_state == BadUsbStateFileError) ||
(worker_state == BadUsbStateScriptError)) { // State: error
uint32_t flags =
bad_usb_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd, FuriFlagWaitAny, FuriWaitForever); // Waiting for exit command
furi_check((flags & FuriFlagError) == 0);
if(flags & WorkerEvtEnd) {
break;
}

View File

@@ -17,7 +17,7 @@ void bad_usb_scene_config_on_enter(void* context) {
submenu_add_item(
submenu,
"Keyboard Layout",
"Keyboard layout",
SubmenuIndexKeyboardLayout,
bad_usb_scene_config_submenu_callback,
bad_usb);

View File

@@ -22,6 +22,7 @@ static bool bad_usb_file_select(BadUsbApp* bad_usb) {
void bad_usb_scene_file_select_on_enter(void* context) {
BadUsbApp* bad_usb = context;
furi_hal_usb_disable();
if(bad_usb->bad_usb_script) {
bad_usb_script_close(bad_usb->bad_usb_script);
bad_usb->bad_usb_script = NULL;
@@ -33,6 +34,7 @@ void bad_usb_scene_file_select_on_enter(void* context) {
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork);
} else {
furi_hal_usb_enable();
view_dispatcher_stop(bad_usb->view_dispatcher);
}
}

View File

@@ -16,9 +16,7 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InputKeyLeft) {
if(bad_usb_is_idle_state(app->bad_usb_view)) {
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
}
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
consumed = true;
} else if(event.event == InputKeyOk) {
bad_usb_script_toggle(app->bad_usb_script);

View File

@@ -48,13 +48,17 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) ||
(model->state.state == BadUsbStateNotConnected)) {
elements_button_center(canvas, "Run");
elements_button_left(canvas, "Config");
} else if((model->state.state == BadUsbStateRunning) || (model->state.state == BadUsbStateDelay)) {
elements_button_center(canvas, "Stop");
} else if(model->state.state == BadUsbStateWillRun) {
elements_button_center(canvas, "Cancel");
}
if((model->state.state == BadUsbStateNotConnected) ||
(model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone)) {
elements_button_left(canvas, "Config");
}
if(model->state.state == BadUsbStateNotConnected) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
@@ -199,7 +203,6 @@ void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
{ strlcpy(model->layout, layout, MAX_NAME_LEN); },
true);
}
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
furi_assert(st);
with_view_model(
@@ -211,19 +214,3 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
},
true);
}
bool bad_usb_is_idle_state(BadUsb* bad_usb) {
bool is_idle = false;
with_view_model(
bad_usb->view,
BadUsbModel * model,
{
if((model->state.state == BadUsbStateIdle) ||
(model->state.state == BadUsbStateDone) ||
(model->state.state == BadUsbStateNotConnected)) {
is_idle = true;
}
},
false);
return is_idle;
}

View File

@@ -19,5 +19,3 @@ void bad_usb_set_file_name(BadUsb* bad_usb, const char* name);
void bad_usb_set_layout(BadUsb* bad_usb, const char* layout);
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st);
bool bad_usb_is_idle_state(BadUsb* bad_usb);

View File

@@ -5,7 +5,6 @@
#include <storage/storage.h>
#include <gui/modules/loading.h>
#include <dialogs/dialogs.h>
#include <toolbox/path.h>
#include <flipper_application/flipper_application.h>
#include "elf_cpp/elf_hashtable.h"
#include "fap_loader_app.h"
@@ -106,12 +105,6 @@ static bool fap_loader_run_selected_app(FapLoader* loader) {
FURI_LOG_I(TAG, "FAP Loader is starting app");
FuriThread* thread = flipper_application_spawn(loader->app, NULL);
FuriString* app_name = furi_string_alloc();
path_extract_filename_no_ext(furi_string_get_cstr(loader->fap_path), app_name);
furi_thread_set_appid(thread, furi_string_get_cstr(app_name));
furi_string_free(app_name);
furi_thread_start(thread);
furi_thread_join(thread);

View File

@@ -1,6 +1,10 @@
#include "ibutton.h"
#include "assets_icons.h"
#include "ibutton_i.h"
#include "ibutton/scenes/ibutton_scene.h"
#include <toolbox/path.h>
#include <flipper_format/flipper_format.h>
#include <rpc/rpc_app.h>
#include <dolphin/dolphin.h>
#define TAG "iButtonApp"
@@ -30,13 +34,50 @@ static const NotificationSequence* ibutton_notification_sequences[] = {
};
static void ibutton_make_app_folder(iButton* ibutton) {
Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(storage, IBUTTON_APP_FOLDER)) {
if(!storage_simply_mkdir(ibutton->storage, IBUTTON_APP_FOLDER)) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot create\napp folder");
}
}
furi_record_close(RECORD_STORAGE);
bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog) {
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
bool result = false;
FuriString* data;
data = furi_string_alloc();
do {
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(key_path))) break;
// header
uint32_t version;
if(!flipper_format_read_header(file, data, &version)) break;
if(furi_string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break;
if(version != 1) break;
// key type
iButtonKeyType type;
if(!flipper_format_read_string(file, "Key type", data)) break;
if(!ibutton_key_get_type_by_string(furi_string_get_cstr(data), &type)) break;
// key data
uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0};
if(!flipper_format_read_hex(file, "Data", key_data, ibutton_key_get_size_by_type(type)))
break;
ibutton_key_set_type(ibutton->key, type);
ibutton_key_set_data(ibutton->key, key_data, IBUTTON_KEY_DATA_SIZE);
result = true;
} while(false);
flipper_format_free(file);
furi_string_free(data);
if((!result) && (show_dialog)) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
}
return result;
}
static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) {
@@ -46,14 +87,14 @@ static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context)
if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event(
ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose);
rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
ibutton->rpc = NULL;
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
ibutton->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit);
} else if(event == RpcAppEventLoadFile) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoad);
} else {
rpc_system_app_confirm(ibutton->rpc, event, false);
rpc_system_app_confirm(ibutton->rpc_ctx, event, false);
}
}
@@ -94,13 +135,13 @@ iButton* ibutton_alloc() {
ibutton->gui = furi_record_open(RECORD_GUI);
ibutton->storage = furi_record_open(RECORD_STORAGE);
ibutton->dialogs = furi_record_open(RECORD_DIALOGS);
ibutton->notifications = furi_record_open(RECORD_NOTIFICATION);
ibutton->protocols = ibutton_protocols_alloc();
ibutton->key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(ibutton->protocols));
ibutton->worker = ibutton_worker_alloc(ibutton->protocols);
ibutton_worker_start_thread(ibutton->worker);
ibutton->key = ibutton_key_alloc();
ibutton->key_worker = ibutton_worker_alloc();
ibutton_worker_start_thread(ibutton->key_worker);
ibutton->submenu = submenu_alloc();
view_dispatcher_add_view(
@@ -122,9 +163,9 @@ iButton* ibutton_alloc() {
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewWidget, widget_get_view(ibutton->widget));
ibutton->loading = loading_alloc();
ibutton->dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewLoading, loading_get_view(ibutton->loading));
ibutton->view_dispatcher, iButtonViewDialogEx, dialog_ex_get_view(ibutton->dialog_ex));
return ibutton;
}
@@ -132,8 +173,8 @@ iButton* ibutton_alloc() {
void ibutton_free(iButton* ibutton) {
furi_assert(ibutton);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewLoading);
loading_free(ibutton->loading);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewDialogEx);
dialog_ex_free(ibutton->dialog_ex);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewWidget);
widget_free(ibutton->widget);
@@ -153,6 +194,9 @@ void ibutton_free(iButton* ibutton) {
view_dispatcher_free(ibutton->view_dispatcher);
scene_manager_free(ibutton->scene_manager);
furi_record_close(RECORD_STORAGE);
ibutton->storage = NULL;
furi_record_close(RECORD_NOTIFICATION);
ibutton->notifications = NULL;
@@ -162,83 +206,103 @@ void ibutton_free(iButton* ibutton) {
furi_record_close(RECORD_GUI);
ibutton->gui = NULL;
ibutton_worker_stop_thread(ibutton->worker);
ibutton_worker_free(ibutton->worker);
ibutton_worker_stop_thread(ibutton->key_worker);
ibutton_worker_free(ibutton->key_worker);
ibutton_key_free(ibutton->key);
ibutton_protocols_free(ibutton->protocols);
furi_string_free(ibutton->file_path);
free(ibutton);
}
bool ibutton_load_key(iButton* ibutton) {
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
const bool success = ibutton_protocols_load(
ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path));
if(!success) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
} else {
FuriString* tmp = furi_string_alloc();
path_extract_filename(ibutton->file_path, tmp, true);
strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE);
furi_string_free(tmp);
}
return success;
}
bool ibutton_select_and_load_key(iButton* ibutton) {
bool ibutton_file_select(iButton* ibutton) {
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px);
browser_options.base_path = IBUTTON_APP_FOLDER;
if(furi_string_empty(ibutton->file_path)) {
furi_string_set(ibutton->file_path, browser_options.base_path);
}
bool success = dialog_file_browser_show(
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options);
return dialog_file_browser_show(
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options) &&
ibutton_load_key(ibutton);
}
bool ibutton_save_key(iButton* ibutton) {
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
ibutton_make_app_folder(ibutton);
iButtonKey* key = ibutton->key;
const bool success =
ibutton_protocols_save(ibutton->protocols, key, furi_string_get_cstr(ibutton->file_path));
if(!success) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file");
if(success) {
success = ibutton_load_key_data(ibutton, ibutton->file_path, true);
}
return success;
}
bool ibutton_delete_key(iButton* ibutton) {
bool ibutton_save_key(iButton* ibutton, const char* key_name) {
// Create ibutton directory if necessary
ibutton_make_app_folder(ibutton);
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
iButtonKey* key = ibutton->key;
bool result = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
result = storage_simply_remove(storage, furi_string_get_cstr(ibutton->file_path));
furi_record_close(RECORD_STORAGE);
do {
// Check if we has old key
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
// First remove old key
ibutton_delete_key(ibutton);
ibutton_reset_key(ibutton);
// Remove old key name from path
size_t filename_start = furi_string_search_rchar(ibutton->file_path, '/');
furi_string_left(ibutton->file_path, filename_start);
}
furi_string_cat_printf(ibutton->file_path, "/%s%s", key_name, IBUTTON_APP_EXTENSION);
// Open file for write
if(!flipper_format_file_open_always(file, furi_string_get_cstr(ibutton->file_path))) break;
// Write header
if(!flipper_format_write_header_cstr(file, IBUTTON_APP_FILE_TYPE, 1)) break;
// Write key type
if(!flipper_format_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom"))
break;
const char* key_type = ibutton_key_get_string_by_type(ibutton_key_get_type(key));
if(!flipper_format_write_string_cstr(file, "Key type", key_type)) break;
// Write data
if(!flipper_format_write_comment_cstr(
file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8"))
break;
if(!flipper_format_write_hex(
file, "Data", ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)))
break;
result = true;
} while(false);
flipper_format_free(file);
if(!result) { //-V547
dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file");
}
return result;
}
void ibutton_reset_key(iButton* ibutton) {
memset(ibutton->key_name, 0, IBUTTON_KEY_NAME_SIZE + 1);
furi_string_reset(ibutton->file_path);
ibutton_key_reset(ibutton->key);
bool ibutton_delete_key(iButton* ibutton) {
bool result = false;
result = storage_simply_remove(ibutton->storage, furi_string_get_cstr(ibutton->file_path));
return result;
}
void ibutton_text_store_set(iButton* ibutton, const char* text, ...) {
va_list args;
va_start(args, text);
vsnprintf(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE, text, args);
va_end(args);
}
void ibutton_text_store_clear(iButton* ibutton) {
memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE + 1);
}
void ibutton_notification_message(iButton* ibutton, uint32_t message) {
@@ -246,44 +310,36 @@ void ibutton_notification_message(iButton* ibutton, uint32_t message) {
notification_message(ibutton->notifications, ibutton_notification_sequences[message]);
}
void ibutton_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_widget_callback(GuiButtonType result, InputType type, void* context) {
iButton* ibutton = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
}
int32_t ibutton_app(void* arg) {
int32_t ibutton_app(void* p) {
iButton* ibutton = ibutton_alloc();
ibutton_make_app_folder(ibutton);
bool key_loaded = false;
bool rpc_mode = false;
if((arg != NULL) && (strlen(arg) != 0)) {
if(sscanf(arg, "RPC %lX", (uint32_t*)&ibutton->rpc) == 1) {
if(p && strlen(p)) {
uint32_t rpc_ctx = 0;
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
FURI_LOG_D(TAG, "Running in RPC mode");
rpc_system_app_set_callback(ibutton->rpc, ibutton_rpc_command_callback, ibutton);
rpc_system_app_send_started(ibutton->rpc);
ibutton->rpc_ctx = (void*)rpc_ctx;
rpc_mode = true;
rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton);
rpc_system_app_send_started(ibutton->rpc_ctx);
} else {
furi_string_set(ibutton->file_path, (const char*)arg);
key_loaded = ibutton_load_key(ibutton);
furi_string_set(ibutton->file_path, (const char*)p);
if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) {
key_loaded = true;
// TODO: Display an error if the key from p could not be loaded
}
}
}
if(ibutton->rpc != NULL) {
if(rpc_mode) {
view_dispatcher_attach_to_gui(
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else {
view_dispatcher_attach_to_gui(
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
@@ -297,9 +353,9 @@ int32_t ibutton_app(void* arg) {
view_dispatcher_run(ibutton->view_dispatcher);
if(ibutton->rpc) {
rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
rpc_system_app_send_exited(ibutton->rpc);
if(ibutton->rpc_ctx) {
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
rpc_system_app_send_exited(ibutton->rpc_ctx);
}
ibutton_free(ibutton);
return 0;

View File

@@ -1,14 +1,10 @@
#include <furi.h>
#include <furi_hal.h>
#include <stdarg.h>
#include <cli/cli.h>
#include <toolbox/args.h>
#include <one_wire/one_wire_host.h>
#include <one_wire/ibutton/ibutton_key.h>
#include <lib/toolbox/args.h>
#include <one_wire/ibutton/ibutton_worker.h>
#include <one_wire/ibutton/ibutton_protocols.h>
#include <one_wire/one_wire_host.h>
static void ibutton_cli(Cli* cli, FuriString* args, void* context);
static void onewire_cli(Cli* cli, FuriString* args, void* context);
@@ -26,7 +22,7 @@ void ibutton_on_system_start() {
#endif
}
static void ibutton_cli_print_usage() {
void ibutton_cli_print_usage() {
printf("Usage:\r\n");
printf("ikey read\r\n");
printf("ikey emulate <key_type> <key_data>\r\n");
@@ -38,52 +34,30 @@ static void ibutton_cli_print_usage() {
printf("\t<key_data> are hex-formatted\r\n");
};
static bool ibutton_cli_parse_key(iButtonProtocols* protocols, iButtonKey* key, FuriString* args) {
bool ibutton_cli_get_key_type(FuriString* data, iButtonKeyType* type) {
bool result = false;
FuriString* name = furi_string_alloc();
do {
// Read protocol name
if(!args_read_string_and_trim(args, name)) break;
// Make the protocol name uppercase
const char first = furi_string_get_char(name, 0);
furi_string_set_char(name, 0, toupper((int)first));
const iButtonProtocolId id =
ibutton_protocols_get_id_by_name(protocols, furi_string_get_cstr(name));
if(id == iButtonProtocolIdInvalid) break;
ibutton_key_set_protocol_id(key, id);
// Get the data pointer
iButtonEditableData data;
ibutton_protocols_get_editable_data(protocols, key, &data);
// Read data
if(!args_read_hex_bytes(args, data.ptr, data.size)) break;
if(furi_string_cmp_str(data, "Dallas") == 0 || furi_string_cmp_str(data, "dallas") == 0) {
result = true;
} while(false);
*type = iButtonKeyDS1990;
} else if(furi_string_cmp_str(data, "Cyfral") == 0 || furi_string_cmp_str(data, "cyfral") == 0) {
result = true;
*type = iButtonKeyCyfral;
} else if(furi_string_cmp_str(data, "Metakom") == 0 || furi_string_cmp_str(data, "metakom") == 0) {
result = true;
*type = iButtonKeyMetakom;
}
furi_string_free(name);
return result;
}
static void ibutton_cli_print_key(iButtonProtocols* protocols, iButtonKey* key) {
const char* name = ibutton_protocols_get_name(protocols, ibutton_key_get_protocol_id(key));
void ibutton_cli_print_key_data(iButtonKey* key) {
const uint8_t* key_data = ibutton_key_get_data_p(key);
iButtonKeyType type = ibutton_key_get_type(key);
if(strncmp(name, "DS", 2) == 0) {
name = "Dallas";
}
printf("%s ", name);
iButtonEditableData data;
ibutton_protocols_get_editable_data(protocols, key, &data);
for(size_t i = 0; i < data.size; i++) {
printf("%02X", data.ptr[i]);
printf("%s ", ibutton_key_get_string_by_type(type));
for(size_t i = 0; i < ibutton_key_get_size_by_type(type); i++) {
printf("%02X", key_data[i]);
}
printf("\r\n");
@@ -97,10 +71,9 @@ static void ibutton_cli_worker_read_cb(void* context) {
furi_event_flag_set(event, EVENT_FLAG_IBUTTON_COMPLETE);
}
static void ibutton_cli_read(Cli* cli) {
iButtonProtocols* protocols = ibutton_protocols_alloc();
iButtonWorker* worker = ibutton_worker_alloc(protocols);
iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols));
void ibutton_cli_read(Cli* cli) {
iButtonKey* key = ibutton_key_alloc();
iButtonWorker* worker = ibutton_worker_alloc();
FuriEventFlag* event = furi_event_flag_alloc();
ibutton_worker_start_thread(worker);
@@ -108,25 +81,32 @@ static void ibutton_cli_read(Cli* cli) {
printf("Reading iButton...\r\nPress Ctrl+C to abort\r\n");
ibutton_worker_read_start(worker, key);
while(true) {
uint32_t flags =
furi_event_flag_wait(event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100);
if(flags & EVENT_FLAG_IBUTTON_COMPLETE) {
ibutton_cli_print_key(protocols, key);
ibutton_cli_print_key_data(key);
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
if(!ibutton_key_dallas_crc_is_valid(key)) {
printf("Warning: invalid CRC\r\n");
}
if(!ibutton_key_dallas_is_1990_key(key)) {
printf("Warning: not a key\r\n");
}
}
break;
}
if(cli_cmd_interrupt_received(cli)) break;
}
ibutton_worker_stop(worker);
ibutton_worker_stop_thread(worker);
ibutton_key_free(key);
ibutton_worker_stop_thread(worker);
ibutton_worker_free(worker);
ibutton_protocols_free(protocols);
ibutton_key_free(key);
furi_event_flag_free(event);
};
@@ -144,33 +124,48 @@ static void ibutton_cli_worker_write_cb(void* context, iButtonWorkerWriteResult
}
void ibutton_cli_write(Cli* cli, FuriString* args) {
iButtonProtocols* protocols = ibutton_protocols_alloc();
iButtonWorker* worker = ibutton_worker_alloc(protocols);
iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols));
iButtonKey* key = ibutton_key_alloc();
iButtonWorker* worker = ibutton_worker_alloc();
iButtonKeyType type;
iButtonWriteContext write_context;
uint8_t key_data[IBUTTON_KEY_DATA_SIZE];
FuriString* data;
write_context.event = furi_event_flag_alloc();
data = furi_string_alloc();
ibutton_worker_start_thread(worker);
ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context);
do {
if(!ibutton_cli_parse_key(protocols, key, args)) {
if(!args_read_string_and_trim(args, data)) {
ibutton_cli_print_usage();
break;
}
if(!(ibutton_protocols_get_features(protocols, ibutton_key_get_protocol_id(key)) &
iButtonProtocolFeatureWriteBlank)) {
if(!ibutton_cli_get_key_type(data, &type)) {
ibutton_cli_print_usage();
break;
}
if(type != iButtonKeyDS1990) {
ibutton_cli_print_usage();
break;
}
if(!args_read_hex_bytes(args, key_data, ibutton_key_get_size_by_type(type))) {
ibutton_cli_print_usage();
break;
}
ibutton_key_set_type(key, type);
ibutton_key_set_data(key, key_data, ibutton_key_get_size_by_type(type));
printf("Writing key ");
ibutton_cli_print_key(protocols, key);
ibutton_cli_print_key_data(key);
printf("Press Ctrl+C to abort\r\n");
ibutton_worker_write_blank_start(worker, key);
ibutton_worker_write_start(worker, key);
while(true) {
uint32_t flags = furi_event_flag_wait(
write_context.event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100);
@@ -188,53 +183,64 @@ void ibutton_cli_write(Cli* cli, FuriString* args) {
if(cli_cmd_interrupt_received(cli)) break;
}
ibutton_worker_stop(worker);
} while(false);
ibutton_worker_stop(worker);
furi_string_free(data);
ibutton_worker_stop_thread(worker);
ibutton_key_free(key);
ibutton_worker_free(worker);
ibutton_protocols_free(protocols);
ibutton_key_free(key);
furi_event_flag_free(write_context.event);
}
};
void ibutton_cli_emulate(Cli* cli, FuriString* args) {
iButtonProtocols* protocols = ibutton_protocols_alloc();
iButtonWorker* worker = ibutton_worker_alloc(protocols);
iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols));
iButtonKey* key = ibutton_key_alloc();
iButtonWorker* worker = ibutton_worker_alloc();
iButtonKeyType type;
uint8_t key_data[IBUTTON_KEY_DATA_SIZE];
FuriString* data;
data = furi_string_alloc();
ibutton_worker_start_thread(worker);
do {
if(!ibutton_cli_parse_key(protocols, key, args)) {
if(!args_read_string_and_trim(args, data)) {
ibutton_cli_print_usage();
break;
}
if(!ibutton_cli_get_key_type(data, &type)) {
ibutton_cli_print_usage();
break;
}
if(!args_read_hex_bytes(args, key_data, ibutton_key_get_size_by_type(type))) {
ibutton_cli_print_usage();
break;
}
ibutton_key_set_type(key, type);
ibutton_key_set_data(key, key_data, ibutton_key_get_size_by_type(type));
printf("Emulating key ");
ibutton_cli_print_key(protocols, key);
ibutton_cli_print_key_data(key);
printf("Press Ctrl+C to abort\r\n");
ibutton_worker_emulate_start(worker, key);
while(!cli_cmd_interrupt_received(cli)) {
furi_delay_ms(100);
};
ibutton_worker_stop(worker);
} while(false);
ibutton_worker_stop(worker);
furi_string_free(data);
ibutton_worker_stop_thread(worker);
ibutton_key_free(key);
ibutton_worker_free(worker);
ibutton_protocols_free(protocols);
ibutton_key_free(key);
};
void ibutton_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
static void ibutton_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(context);
FuriString* cmd;
cmd = furi_string_alloc();
@@ -258,7 +264,7 @@ void ibutton_cli(Cli* cli, FuriString* args, void* context) {
furi_string_free(cmd);
}
static void onewire_cli_print_usage() {
void onewire_cli_print_usage() {
printf("Usage:\r\n");
printf("onewire search\r\n");
};
@@ -275,7 +281,7 @@ static void onewire_cli_search(Cli* cli) {
furi_hal_power_enable_otg();
while(!done) {
if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) {
if(onewire_host_search(onewire, address, NORMAL_SEARCH) != 1) {
printf("Search finished\r\n");
onewire_host_reset_search(onewire);
done = true;

View File

@@ -6,7 +6,6 @@ enum iButtonCustomEvent {
iButtonCustomEventBack,
iButtonCustomEventTextEditResult,
iButtonCustomEventByteEditChanged,
iButtonCustomEventByteEditResult,
iButtonCustomEventWorkerEmulated,
iButtonCustomEventWorkerRead,

View File

@@ -4,40 +4,31 @@
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/scene_manager.h>
#include <assets_icons.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <notification/notification_messages.h>
#include <one_wire/ibutton/ibutton_worker.h>
#include <one_wire/ibutton/ibutton_protocols.h>
#include <rpc/rpc_app.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <gui/modules/widget.h>
#include <gui/modules/loading.h>
#include <assets_icons.h>
#include "ibutton_custom_event.h"
#include "scenes/ibutton_scene.h"
#define IBUTTON_FILE_NAME_SIZE 100
#define IBUTTON_TEXT_STORE_SIZE 128
#define IBUTTON_APP_FOLDER ANY_PATH("ibutton")
#define IBUTTON_APP_EXTENSION ".ibtn"
#define IBUTTON_KEY_NAME_SIZE 22
typedef enum {
iButtonWriteModeInvalid,
iButtonWriteModeBlank,
iButtonWriteModeCopy,
} iButtonWriteMode;
#define IBUTTON_APP_FILE_TYPE "Flipper iButton key"
struct iButton {
SceneManager* scene_manager;
@@ -47,22 +38,21 @@ struct iButton {
Storage* storage;
DialogsApp* dialogs;
NotificationApp* notifications;
RpcAppSystem* rpc;
iButtonWorker* key_worker;
iButtonKey* key;
iButtonWorker* worker;
iButtonProtocols* protocols;
iButtonWriteMode write_mode;
FuriString* file_path;
char key_name[IBUTTON_KEY_NAME_SIZE + 1];
char text_store[IBUTTON_TEXT_STORE_SIZE + 1];
Submenu* submenu;
ByteInput* byte_input;
TextInput* text_input;
Popup* popup;
Widget* widget;
Loading* loading;
DialogEx* dialog_ex;
void* rpc_ctx;
};
typedef enum {
@@ -71,7 +61,7 @@ typedef enum {
iButtonViewTextInput,
iButtonViewPopup,
iButtonViewWidget,
iButtonViewLoading,
iButtonViewDialogEx,
} iButtonView;
typedef enum {
@@ -88,12 +78,10 @@ typedef enum {
iButtonNotificationMessageBlinkStop,
} iButtonNotificationMessage;
bool ibutton_select_and_load_key(iButton* ibutton);
bool ibutton_load_key(iButton* ibutton);
bool ibutton_save_key(iButton* ibutton);
bool ibutton_file_select(iButton* ibutton);
bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog);
bool ibutton_save_key(iButton* ibutton, const char* key_name);
bool ibutton_delete_key(iButton* ibutton);
void ibutton_reset_key(iButton* ibutton);
void ibutton_text_store_set(iButton* ibutton, const char* text, ...);
void ibutton_text_store_clear(iButton* ibutton);
void ibutton_notification_message(iButton* ibutton, uint32_t message);
void ibutton_submenu_callback(void* context, uint32_t index);
void ibutton_widget_callback(GuiButtonType result, InputType type, void* context);

View File

@@ -1,57 +1,54 @@
#include "../ibutton_i.h"
enum SubmenuIndex {
SubmenuIndexCyfral,
SubmenuIndexDallas,
SubmenuIndexMetakom,
};
void ibutton_scene_add_type_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_add_type_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
FuriString* tmp = furi_string_alloc();
submenu_add_item(
submenu, "Cyfral", SubmenuIndexCyfral, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_add_item(
submenu, "Dallas", SubmenuIndexDallas, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_add_item(
submenu, "Metakom", SubmenuIndexMetakom, ibutton_scene_add_type_submenu_callback, ibutton);
for(uint32_t protocol_id = 0; protocol_id < ibutton_protocols_get_protocol_count();
++protocol_id) {
if((strcmp(
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id),
ibutton_protocols_get_name(ibutton->protocols, protocol_id)) != 0) &&
(strcmp(ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), "N/A") !=
0)) {
furi_string_printf(
tmp,
"%s %s",
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id),
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
} else {
furi_string_printf(
tmp, "%s", ibutton_protocols_get_name(ibutton->protocols, protocol_id));
}
submenu_add_item(
submenu, furi_string_get_cstr(tmp), protocol_id, ibutton_submenu_callback, context);
}
const uint32_t prev_protocol_id =
scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddType);
submenu_set_selected_item(submenu, prev_protocol_id);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddType));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
furi_string_free(tmp);
}
bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
const iButtonProtocolId protocol_id = event.event;
ibutton_key_reset(key);
ibutton_key_set_protocol_id(key, protocol_id);
ibutton_protocols_apply_edits(ibutton->protocols, key);
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneAddType, protocol_id);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue);
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneAddType, event.event);
consumed = true;
if(event.event == SubmenuIndexCyfral) {
ibutton_key_set_type(key, iButtonKeyCyfral);
} else if(event.event == SubmenuIndexDallas) {
ibutton_key_set_type(key, iButtonKeyDS1990);
} else if(event.event == SubmenuIndexMetakom) {
ibutton_key_set_type(key, iButtonKeyMetakom);
} else {
furi_crash("Unknown key type");
}
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
ibutton_key_clear_data(key);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue);
}
return consumed;

View File

@@ -1,52 +1,42 @@
#include "../ibutton_i.h"
static void ibutton_scene_add_type_byte_input_callback(void* context) {
void ibutton_scene_add_type_byte_input_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult);
}
static void ibutton_scene_add_type_byte_changed_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditChanged);
}
void ibutton_scene_add_value_on_enter(void* context) {
iButton* ibutton = context;
byte_input_set_header_text(ibutton->byte_input, "Enter the key");
iButtonKey* key = ibutton->key;
uint8_t* new_key_data = malloc(IBUTTON_KEY_DATA_SIZE);
iButtonEditableData editable_data;
ibutton_protocols_get_editable_data(ibutton->protocols, ibutton->key, &editable_data);
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneAddValue, (uint32_t)new_key_data);
memcpy(new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key));
byte_input_set_result_callback(
ibutton->byte_input,
ibutton_scene_add_type_byte_input_callback,
ibutton_scene_add_type_byte_changed_callback,
context,
editable_data.ptr,
editable_data.size);
NULL,
ibutton,
new_key_data,
ibutton_key_get_data_size(key));
byte_input_set_header_text(ibutton->byte_input, "Enter the key");
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewByteInput);
}
bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
uint8_t* new_key_data =
(uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventByteEditResult) {
scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
} else if(event.event == iButtonCustomEventByteEditChanged) {
ibutton_protocols_apply_edits(ibutton->protocols, ibutton->key);
}
} else if(event.type == SceneManagerEventTypeBack) {
// User cancelled editing, reload the key from storage
if(scene_manager_has_previous_scene(scene_manager, iButtonSceneSavedKeyMenu)) {
if(!ibutton_load_key(ibutton)) {
consumed = scene_manager_search_and_switch_to_previous_scene(
scene_manager, iButtonSceneStart);
}
ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName);
}
}
@@ -55,7 +45,10 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_add_value_on_exit(void* context) {
iButton* ibutton = context;
uint8_t* new_key_data =
(uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue);
byte_input_set_result_callback(ibutton->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(ibutton->byte_input, NULL);
free(new_key_data);
}

View File

@@ -6,7 +6,8 @@ ADD_SCENE(ibutton, info, Info)
ADD_SCENE(ibutton, read, Read)
ADD_SCENE(ibutton, read_key_menu, ReadKeyMenu)
ADD_SCENE(ibutton, read_success, ReadSuccess)
ADD_SCENE(ibutton, read_error, ReadError)
ADD_SCENE(ibutton, read_crc_error, ReadCRCError)
ADD_SCENE(ibutton, read_not_key_error, ReadNotKeyError)
ADD_SCENE(ibutton, select_key, SelectKey)
ADD_SCENE(ibutton, add_type, AddType)
ADD_SCENE(ibutton, add_value, AddValue)
@@ -17,5 +18,4 @@ ADD_SCENE(ibutton, delete_confirm, DeleteConfirm)
ADD_SCENE(ibutton, delete_success, DeleteSuccess)
ADD_SCENE(ibutton, retry_confirm, RetryConfirm)
ADD_SCENE(ibutton, exit_confirm, ExitConfirm)
ADD_SCENE(ibutton, view_data, ViewData)
ADD_SCENE(ibutton, rpc, Rpc)

View File

@@ -1,29 +1,74 @@
#include "../ibutton_i.h"
#include <toolbox/path.h>
static void ibutton_scene_delete_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
iButton* ibutton = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
}
void ibutton_scene_delete_confirm_on_enter(void* context) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
FuriString* tmp = furi_string_alloc();
FuriString* key_name;
key_name = furi_string_alloc();
path_extract_filename(ibutton->file_path, key_name, true);
widget_add_button_element(widget, GuiButtonTypeLeft, "Back", ibutton_widget_callback, context);
ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", furi_string_get_cstr(key_name));
widget_add_text_box_element(
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, true);
widget_add_button_element(
widget, GuiButtonTypeRight, "Delete", ibutton_widget_callback, context);
widget, GuiButtonTypeLeft, "Cancel", ibutton_scene_delete_confirm_widget_callback, ibutton);
widget_add_button_element(
widget,
GuiButtonTypeRight,
"Delete",
ibutton_scene_delete_confirm_widget_callback,
ibutton);
furi_string_printf(tmp, "Delete %s?", ibutton->key_name);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
widget_add_string_element(
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Dallas");
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
widget_add_string_element(
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
widget_add_string_element(
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Metakom");
break;
}
widget_add_string_element(
widget, 128 / 2, 0, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
furi_string_reset(tmp);
ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp);
widget_add_string_multiline_element(
widget, 128 / 2, 16, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
widget, 64, 46, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
furi_string_free(key_name);
}
bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
@@ -36,10 +81,8 @@ bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent even
if(event.event == GuiButtonTypeRight) {
if(ibutton_delete_key(ibutton)) {
scene_manager_next_scene(scene_manager, iButtonSceneDeleteSuccess);
} else {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot delete\nkey file");
scene_manager_previous_scene(scene_manager);
}
//TODO: What if the key could not be deleted?
} else if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager);
}
@@ -50,5 +93,6 @@ bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent even
void ibutton_scene_delete_confirm_on_exit(void* context) {
iButton* ibutton = context;
ibutton_text_store_clear(ibutton);
widget_reset(ibutton->widget);
}

View File

@@ -14,32 +14,61 @@ static void ibutton_scene_emulate_callback(void* context, bool emulated) {
void ibutton_scene_emulate_on_enter(void* context) {
iButton* ibutton = context;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
FuriString* tmp = furi_string_alloc();
const uint8_t* key_data = ibutton_key_get_data_p(key);
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
FuriString* key_name;
key_name = furi_string_alloc();
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
furi_string_printf(
tmp,
"%s\n[%s]",
furi_string_empty(ibutton->file_path) ? "Unsaved Key" : ibutton->key_name,
ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key)));
widget_add_text_box_element(
widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
// check that stored key has name
if(!furi_string_empty(key_name)) {
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
} else {
// if not, show key data
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
break;
}
}
widget_add_string_multiline_element(
widget, 88, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating");
widget, 90, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating");
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
widget_add_text_box_element(
widget, 54, 39, 75, 22, AlignCenter, AlignCenter, ibutton->text_store, true);
ibutton_worker_emulate_set_callback(ibutton->worker, ibutton_scene_emulate_callback, ibutton);
ibutton_worker_emulate_start(ibutton->worker, key);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
ibutton_worker_emulate_set_callback(
ibutton->key_worker, ibutton_scene_emulate_callback, ibutton);
ibutton_worker_emulate_start(ibutton->key_worker, key);
furi_string_free(key_name);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
}
bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
@@ -49,7 +78,8 @@ bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeTick) {
uint32_t cnt = scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneEmulate);
if(cnt > 0) {
if(--cnt == 0) {
cnt--;
if(cnt == 0) {
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateBlink);
}
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneEmulate, cnt);
@@ -71,7 +101,7 @@ bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_emulate_on_exit(void* context) {
iButton* ibutton = context;
ibutton_worker_stop(ibutton->worker);
ibutton_worker_stop(ibutton->key_worker);
widget_reset(ibutton->widget);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
}

View File

@@ -19,7 +19,7 @@ void ibutton_scene_exit_confirm_on_enter(void* context) {
widget_add_button_element(
widget, GuiButtonTypeRight, "Stay", ibutton_scene_exit_confirm_widget_callback, ibutton);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton Menu?");
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?");
widget_add_string_element(
widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");

View File

@@ -1,54 +1,66 @@
#include "../ibutton_i.h"
#include <toolbox/path.h>
void ibutton_scene_info_on_enter(void* context) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key;
const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key);
const uint8_t* key_data = ibutton_key_get_data_p(key);
FuriString* tmp = furi_string_alloc();
furi_string_printf(
tmp,
"\e#%s [%s]\e#",
ibutton->key_name,
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
FuriString* key_name;
key_name = furi_string_alloc();
path_extract_filename(ibutton->file_path, key_name, true);
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
widget_add_text_box_element(
widget, 0, 2, 128, 12, AlignLeft, AlignTop, furi_string_get_cstr(tmp), true);
widget, 0, 0, 128, 23, AlignCenter, AlignCenter, ibutton->text_store, true);
furi_string_reset(tmp);
ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
widget_add_string_element(widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Dallas");
break;
widget_add_string_multiline_element(
widget, 0, 16, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
widget_add_string_element(
widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Metakom");
break;
if(ibutton_protocols_get_features(ibutton->protocols, protocol_id) &
iButtonProtocolFeatureExtData) {
widget_add_button_element(
widget, GuiButtonTypeRight, "More", ibutton_widget_callback, context);
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
widget_add_string_element(widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Cyfral");
break;
}
widget_add_string_element(
widget, 64, 50, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
furi_string_free(key_name);
}
bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneViewData);
}
}
return consumed;
UNUSED(context);
UNUSED(event);
return false;
}
void ibutton_scene_info_on_exit(void* context) {
iButton* ibutton = context;
ibutton_text_store_clear(ibutton);
widget_reset(ibutton->widget);
}

View File

@@ -10,13 +10,14 @@ void ibutton_scene_read_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
iButtonKey* key = ibutton->key;
iButtonWorker* worker = ibutton->worker;
iButtonWorker* worker = ibutton->key_worker;
popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom);
popup_set_text(popup, "Apply key to\nFlipper's back", 95, 30, AlignCenter, AlignTop);
popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton);
ibutton_worker_read_start(worker, key);
@@ -34,14 +35,25 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) {
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventWorkerRead) {
if(ibutton_protocols_is_valid(ibutton->protocols, ibutton->key)) {
bool success = false;
iButtonKey* key = ibutton->key;
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
if(!ibutton_key_dallas_crc_is_valid(key)) {
scene_manager_next_scene(scene_manager, iButtonSceneReadCRCError);
} else if(!ibutton_key_dallas_is_1990_key(key)) {
scene_manager_next_scene(scene_manager, iButtonSceneReadNotKeyError);
} else {
success = true;
}
} else {
success = true;
}
if(success) {
ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess);
scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess);
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
} else {
scene_manager_next_scene(scene_manager, iButtonSceneReadError);
}
}
}
@@ -52,7 +64,7 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_read_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
ibutton_worker_stop(ibutton->worker);
ibutton_worker_stop(ibutton->key_worker);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);

View File

@@ -0,0 +1,70 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
static void ibutton_scene_read_crc_error_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_crc_error_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X\nExpected CRC: %X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7],
maxim_crc8(key_data, 7, MAXIM_CRC8_INIT));
dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_crc_error_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
}
bool ibutton_scene_read_crc_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_read_crc_error_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@@ -1,58 +0,0 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
void ibutton_scene_read_error_on_enter(void* context) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
FuriString* tmp = furi_string_alloc();
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", ibutton_widget_callback, context);
widget_add_button_element(
widget, GuiButtonTypeRight, "More", ibutton_widget_callback, context);
widget_add_string_element(
widget, 128 / 2, 2, AlignCenter, AlignTop, FontPrimary, "Read Error");
ibutton_protocols_render_error(ibutton->protocols, key, tmp);
widget_add_string_multiline_element(
widget, 128 / 2, 16, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
}
bool ibutton_scene_read_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
}
}
return consumed;
}
void ibutton_scene_read_error_on_exit(void* context) {
iButton* ibutton = context;
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
widget_reset(ibutton->widget);
}

View File

@@ -4,9 +4,7 @@
typedef enum {
SubmenuIndexSave,
SubmenuIndexEmulate,
SubmenuIndexViewData,
SubmenuIndexWriteBlank,
SubmenuIndexWriteCopy,
SubmenuIndexWrite,
} SubmenuIndex;
void ibutton_scene_read_key_menu_submenu_callback(void* context, uint32_t index) {
@@ -18,9 +16,6 @@ void ibutton_scene_read_key_menu_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(ibutton->key);
const uint32_t features = ibutton_protocols_get_features(ibutton->protocols, protocol_id);
submenu_add_item(
submenu, "Save", SubmenuIndexSave, ibutton_scene_read_key_menu_submenu_callback, ibutton);
submenu_add_item(
@@ -29,66 +24,36 @@ void ibutton_scene_read_key_menu_on_enter(void* context) {
SubmenuIndexEmulate,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
if(features & iButtonProtocolFeatureExtData) {
if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) {
submenu_add_item(
submenu,
"View Data",
SubmenuIndexViewData,
"Write",
SubmenuIndexWrite,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
}
if(features & iButtonProtocolFeatureWriteBlank) {
submenu_add_item(
submenu,
"Write Blank",
SubmenuIndexWriteBlank,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
}
if(features & iButtonProtocolFeatureWriteCopy) {
submenu_add_item(
submenu,
"Write Copy",
SubmenuIndexWriteCopy,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
}
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneReadKeyMenu));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
}
bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(scene_manager, iButtonSceneReadKeyMenu, event.event);
consumed = true;
if(event.event == SubmenuIndexSave) {
scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else if(event.event == SubmenuIndexViewData) {
scene_manager_next_scene(scene_manager, iButtonSceneViewData);
} else if(event.event == SubmenuIndexWriteBlank) {
ibutton->write_mode = iButtonWriteModeBlank;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexWriteCopy) {
ibutton->write_mode = iButtonWriteModeCopy;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
}
} else if(event.event == SceneManagerEventTypeBack) {
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneReadKeyMenu, SubmenuIndexSave);
// Event is not consumed
ibutton->scene_manager, iButtonSceneReadKeyMenu, event.event);
consumed = true;
if(event.event == SubmenuIndexSave) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName);
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite);
}
}
return consumed;

View File

@@ -0,0 +1,71 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
static void
ibutton_scene_read_not_key_error_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_not_key_error_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
ibutton_text_store_set(
ibutton,
"THIS IS NOT A KEY\n%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7],
maxim_crc8(key_data, 7, MAXIM_CRC8_INIT));
dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_not_key_error_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
}
bool ibutton_scene_read_not_key_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_read_not_key_error_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@@ -1,40 +1,55 @@
#include "../ibutton_i.h"
#include <dolphin/dolphin.h>
static void ibutton_scene_read_success_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_success_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
const uint8_t* key_data = ibutton_key_get_data_p(key);
FuriString* tmp = furi_string_alloc();
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"Dallas\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "Cyfral\n%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton,
"Metakom\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3]);
break;
}
const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key);
dialog_ex_set_text(dialog_ex, ibutton->text_store, 95, 30, AlignCenter, AlignCenter);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63);
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_success_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", ibutton_widget_callback, context);
widget_add_button_element(
widget, GuiButtonTypeRight, "More", ibutton_widget_callback, context);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
furi_string_printf(
tmp,
"%s[%s]",
ibutton_protocols_get_name(ibutton->protocols, protocol_id),
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id));
widget_add_string_element(
widget, 0, 2, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
furi_string_reset(tmp);
ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp);
widget_add_string_multiline_element(
widget, 0, 16, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn);
furi_string_free(tmp);
}
bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event) {
@@ -47,9 +62,9 @@ bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event)
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeRight) {
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == GuiButtonTypeLeft) {
} else if(event.event == DialogExResultLeft) {
scene_manager_next_scene(scene_manager, iButtonSceneRetryConfirm);
}
}
@@ -59,8 +74,11 @@ bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event)
void ibutton_scene_read_success_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
widget_reset(ibutton->widget);
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff);
}

View File

@@ -19,7 +19,7 @@ void ibutton_scene_retry_confirm_on_enter(void* context) {
widget_add_button_element(
widget, GuiButtonTypeRight, "Stay", ibutton_scene_retry_confirm_widget_callback, ibutton);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Retry Reading?");
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?");
widget_add_string_element(
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");

View File

@@ -1,4 +1,6 @@
#include "../ibutton_i.h"
#include <toolbox/path.h>
#include <rpc/rpc_app.h>
void ibutton_scene_rpc_on_enter(void* context) {
iButton* ibutton = context;
@@ -15,6 +17,8 @@ void ibutton_scene_rpc_on_enter(void* context) {
}
bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
iButton* ibutton = context;
Popup* popup = ibutton->popup;
@@ -22,32 +26,40 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventRpcLoad) {
const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
bool result = false;
const char* file_path = rpc_system_app_get_data(ibutton->rpc);
if(arg && (furi_string_empty(ibutton->file_path))) {
furi_string_set(ibutton->file_path, arg);
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
FuriString* key_name;
key_name = furi_string_alloc();
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
if(file_path && (furi_string_empty(ibutton->file_path))) {
furi_string_set(ibutton->file_path, file_path);
if(ibutton_load_key(ibutton)) {
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
if(!furi_string_empty(key_name)) {
ibutton_text_store_set(
ibutton, "emulating\n%s", furi_string_get_cstr(key_name));
} else {
ibutton_text_store_set(ibutton, "emulating");
}
popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
ibutton_worker_emulate_start(ibutton->worker, ibutton->key);
furi_string_free(key_name);
result = true;
} else {
furi_string_reset(ibutton->file_path);
}
}
rpc_system_app_confirm(ibutton->rpc, RpcAppEventLoadFile, result);
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
} else if(event.event == iButtonCustomEventRpcExit) {
rpc_system_app_confirm(ibutton->rpc, RpcAppEventAppExit, true);
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true);
scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher);
} else if(event.event == iButtonCustomEventRpcSessionClose) {
scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher);

View File

@@ -1,8 +1,6 @@
#include "../ibutton_i.h"
#include <toolbox/random_name.h>
#include <lib/toolbox/random_name.h>
#include <toolbox/path.h>
#include <dolphin/dolphin.h>
static void ibutton_scene_save_name_text_input_callback(void* context) {
@@ -14,10 +12,17 @@ void ibutton_scene_save_name_on_enter(void* context) {
iButton* ibutton = context;
TextInput* text_input = ibutton->text_input;
const bool is_new_file = furi_string_empty(ibutton->file_path);
FuriString* key_name;
key_name = furi_string_alloc();
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
if(is_new_file) {
set_random_name(ibutton->key_name, IBUTTON_KEY_NAME_SIZE);
const bool key_name_is_empty = furi_string_empty(key_name);
if(key_name_is_empty) {
set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE);
} else {
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
}
text_input_set_header_text(text_input, "Name the key");
@@ -25,15 +30,23 @@ void ibutton_scene_save_name_on_enter(void* context) {
text_input,
ibutton_scene_save_name_text_input_callback,
ibutton,
ibutton->key_name,
ibutton->text_store,
IBUTTON_KEY_NAME_SIZE,
is_new_file);
key_name_is_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(IBUTTON_APP_FOLDER, IBUTTON_APP_EXTENSION, ibutton->key_name);
FuriString* folder_path;
folder_path = furi_string_alloc();
path_extract_dirname(furi_string_get_cstr(ibutton->file_path), folder_path);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
furi_string_get_cstr(folder_path), IBUTTON_APP_EXTENSION, furi_string_get_cstr(key_name));
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput);
furi_string_free(key_name);
furi_string_free(folder_path);
}
bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
@@ -43,16 +56,8 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventTextEditResult) {
furi_string_printf(
ibutton->file_path,
"%s/%s%s",
IBUTTON_APP_FOLDER,
ibutton->key_name,
IBUTTON_APP_EXTENSION);
if(ibutton_save_key(ibutton)) {
if(ibutton_save_key(ibutton, ibutton->text_store)) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess);
if(scene_manager_has_previous_scene(
ibutton->scene_manager, iButtonSceneSavedKeyMenu)) {
// Nothing, do not count editing as saving
@@ -62,7 +67,6 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
} else {
DOLPHIN_DEED(DolphinDeedIbuttonSave);
}
} else {
const uint32_t possible_scenes[] = {
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};

View File

@@ -3,70 +3,72 @@
enum SubmenuIndex {
SubmenuIndexEmulate,
SubmenuIndexWriteBlank,
SubmenuIndexWriteCopy,
SubmenuIndexWrite,
SubmenuIndexEdit,
SubmenuIndexDelete,
SubmenuIndexInfo,
};
void ibutton_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_saved_key_menu_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
const uint32_t features = ibutton_protocols_get_features(
ibutton->protocols, ibutton_key_get_protocol_id(ibutton->key));
submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, ibutton_submenu_callback, ibutton);
if(features & iButtonProtocolFeatureWriteBlank) {
submenu_add_item(
submenu,
"Emulate",
SubmenuIndexEmulate,
ibutton_scene_saved_key_menu_submenu_callback,
ibutton);
if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) {
submenu_add_item(
submenu, "Write Blank", SubmenuIndexWriteBlank, ibutton_submenu_callback, ibutton);
submenu,
"Write",
SubmenuIndexWrite,
ibutton_scene_saved_key_menu_submenu_callback,
ibutton);
}
if(features & iButtonProtocolFeatureWriteCopy) {
submenu_add_item(
submenu, "Write Copy", SubmenuIndexWriteCopy, ibutton_submenu_callback, ibutton);
}
submenu_add_item(submenu, "Edit", SubmenuIndexEdit, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Delete", SubmenuIndexDelete, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Info", SubmenuIndexInfo, ibutton_submenu_callback, ibutton);
submenu_add_item(
submenu, "Edit", SubmenuIndexEdit, ibutton_scene_saved_key_menu_submenu_callback, ibutton);
submenu_add_item(
submenu,
"Delete",
SubmenuIndexDelete,
ibutton_scene_saved_key_menu_submenu_callback,
ibutton);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, ibutton_scene_saved_key_menu_submenu_callback, ibutton);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneSavedKeyMenu));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
}
bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(scene_manager, iButtonSceneSavedKeyMenu, event.event);
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneSavedKeyMenu, event.event);
consumed = true;
if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else if(event.event == SubmenuIndexWriteBlank) {
ibutton->write_mode = iButtonWriteModeBlank;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexWriteCopy) {
ibutton->write_mode = iButtonWriteModeCopy;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(scene_manager, iButtonSceneAddValue);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue);
} else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(scene_manager, iButtonSceneDeleteConfirm);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneDeleteConfirm);
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(scene_manager, iButtonSceneInfo);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneInfo);
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_set_scene_state(
scene_manager, iButtonSceneSavedKeyMenu, SubmenuIndexEmulate);
// Event is not consumed
}
return consumed;

View File

@@ -3,11 +3,11 @@
void ibutton_scene_select_key_on_enter(void* context) {
iButton* ibutton = context;
if(ibutton_select_and_load_key(ibutton)) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSavedKeyMenu);
} else {
if(!ibutton_file_select(ibutton)) {
scene_manager_search_and_switch_to_previous_scene(
ibutton->scene_manager, iButtonSceneStart);
} else {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSavedKeyMenu);
}
}

View File

@@ -8,15 +8,21 @@ enum SubmenuIndex {
SubmenuIndexAdd,
};
void ibutton_scene_start_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_start_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
ibutton_reset_key(ibutton);
submenu_add_item(submenu, "Read", SubmenuIndexRead, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Add Manually", SubmenuIndexAdd, ibutton_submenu_callback, ibutton);
submenu_add_item(
submenu, "Read", SubmenuIndexRead, ibutton_scene_start_submenu_callback, ibutton);
submenu_add_item(
submenu, "Saved", SubmenuIndexSaved, ibutton_scene_start_submenu_callback, ibutton);
submenu_add_item(
submenu, "Add Manually", SubmenuIndexAdd, ibutton_scene_start_submenu_callback, ibutton);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneStart));
@@ -35,6 +41,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
DOLPHIN_DEED(DolphinDeedIbuttonRead);
} else if(event.event == SubmenuIndexSaved) {
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
} else if(event.event == SubmenuIndexAdd) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType);

View File

@@ -1,26 +0,0 @@
#include "../ibutton_i.h"
void ibutton_scene_view_data_on_enter(void* context) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
FuriString* tmp = furi_string_alloc();
ibutton_protocols_render_data(ibutton->protocols, key, tmp);
widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(tmp));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
}
bool ibutton_scene_view_data_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void ibutton_scene_view_data_on_exit(void* context) {
iButton* ibutton = context;
widget_reset(ibutton->widget);
}

View File

@@ -1,4 +1,5 @@
#include "../ibutton_i.h"
#include "toolbox/path.h"
typedef enum {
iButtonSceneWriteStateDefault,
@@ -12,46 +13,61 @@ static void ibutton_scene_write_callback(void* context, iButtonWorkerWriteResult
void ibutton_scene_write_on_enter(void* context) {
iButton* ibutton = context;
furi_assert(ibutton->write_mode != iButtonWriteModeInvalid);
iButtonKey* key = ibutton->key;
iButtonWorker* worker = ibutton->worker;
const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key);
Widget* widget = ibutton->widget;
FuriString* tmp = furi_string_alloc();
iButtonWorker* worker = ibutton->key_worker;
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
const uint8_t* key_data = ibutton_key_get_data_p(key);
furi_string_printf(
tmp,
"%s\n[%s]",
ibutton->key_name,
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
FuriString* key_name;
key_name = furi_string_alloc();
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
widget_add_text_box_element(
widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
furi_string_set(tmp, "iButton\nwriting ");
if(ibutton->write_mode == iButtonWriteModeBlank) {
furi_string_cat(tmp, "Blank");
ibutton_worker_write_blank_start(worker, key);
} else if(ibutton->write_mode == iButtonWriteModeCopy) {
furi_string_cat(tmp, "Copy");
ibutton_worker_write_copy_start(worker, key);
// check that stored key has name
if(!furi_string_empty(key_name)) {
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
} else {
// if not, show key data
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
break;
}
}
widget_add_string_multiline_element(
widget, 88, 10, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
widget, 90, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nwriting");
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
widget_add_text_box_element(
widget, 54, 39, 75, 22, AlignCenter, AlignCenter, ibutton->text_store, true);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
ibutton_worker_write_start(worker, key);
furi_string_free(key_name);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
}
bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) {
@@ -78,9 +94,7 @@ bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_write_on_exit(void* context) {
iButton* ibutton = context;
ibutton->write_mode = iButtonWriteModeInvalid;
ibutton_worker_stop(ibutton->worker);
ibutton_worker_stop(ibutton->key_worker);
widget_reset(ibutton->widget);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);

View File

@@ -3,8 +3,6 @@
#include <string.h>
#include <dolphin/dolphin.h>
#define INFRARED_TX_MIN_INTERVAL_MS 50U
static const NotificationSequence* infrared_notification_sequences[] = {
&sequence_success,
&sequence_set_only_green_255,
@@ -150,12 +148,6 @@ static Infrared* infrared_alloc() {
view_dispatcher_add_view(
view_dispatcher, InfraredViewTextInput, text_input_get_view(infrared->text_input));
infrared->variable_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
infrared->view_dispatcher,
InfraredViewVariableItemList,
variable_item_list_get_view(infrared->variable_item_list));
infrared->dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
view_dispatcher, InfraredViewDialogEx, dialog_ex_get_view(infrared->dialog_ex));
@@ -203,9 +195,6 @@ static void infrared_free(Infrared* infrared) {
view_dispatcher_remove_view(view_dispatcher, InfraredViewTextInput);
text_input_free(infrared->text_input);
view_dispatcher_remove_view(infrared->view_dispatcher, InfraredViewVariableItemList);
variable_item_list_free(infrared->variable_item_list);
view_dispatcher_remove_view(view_dispatcher, InfraredViewDialogEx);
dialog_ex_free(infrared->dialog_ex);
@@ -310,13 +299,10 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) {
void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
if(infrared->app_state.is_transmitting) {
FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already active");
return;
}
const uint32_t time_elapsed = furi_get_tick() - infrared->app_state.last_transmit_time;
if(time_elapsed < INFRARED_TX_MIN_INTERVAL_MS) {
return;
} else {
infrared->app_state.is_transmitting = true;
}
if(infrared_signal_is_raw(signal)) {
@@ -333,8 +319,6 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
infrared_worker_tx_start(infrared->worker);
infrared->app_state.is_transmitting = true;
}
void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) {
@@ -344,24 +328,26 @@ void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) {
InfraredSignal* signal = infrared_remote_button_get_signal(button);
infrared_tx_start_signal(infrared, signal);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
}
void infrared_tx_start_received(Infrared* infrared) {
infrared_tx_start_signal(infrared, infrared->received_signal);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
}
void infrared_tx_stop(Infrared* infrared) {
if(!infrared->app_state.is_transmitting) {
FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already stopped");
return;
} else {
infrared->app_state.is_transmitting = false;
}
infrared_worker_tx_stop(infrared->worker);
infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
infrared->app_state.is_transmitting = false;
infrared->app_state.last_transmit_time = furi_get_tick();
}
void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) {

View File

@@ -10,7 +10,6 @@
#include <gui/modules/popup.h>
#include <gui/modules/loading.h>
#include <gui/modules/submenu.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/text_input.h>
#include <gui/modules/button_menu.h>
@@ -70,7 +69,6 @@ typedef struct {
InfraredEditTarget edit_target : 8;
InfraredEditMode edit_mode : 8;
int32_t current_button_index;
uint32_t last_transmit_time;
} InfraredAppState;
struct Infrared {
@@ -88,7 +86,6 @@ struct Infrared {
Submenu* submenu;
TextInput* text_input;
VariableItemList* variable_item_list;
DialogEx* dialog_ex;
ButtonMenu* button_menu;
Popup* popup;
@@ -110,7 +107,6 @@ struct Infrared {
typedef enum {
InfraredViewSubmenu,
InfraredViewTextInput,
InfraredViewVariableItemList,
InfraredViewDialogEx,
InfraredViewButtonMenu,
InfraredViewPopup,

View File

@@ -10,13 +10,13 @@ void infrared_scene_ask_back_on_enter(void* context) {
DialogEx* dialog_ex = infrared->dialog_ex;
if(infrared->app_state.is_learning_new_remote) {
dialog_ex_set_header(dialog_ex, "Exit to Infrared Menu?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Exit to Infrared Menu?", 64, 0, AlignCenter, AlignTop);
} else {
dialog_ex_set_header(dialog_ex, "Exit to Remote Menu?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Exit to Remote Menu?", 64, 0, AlignCenter, AlignTop);
}
dialog_ex_set_text(
dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop);
dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, "Exit");
dialog_ex_set_center_button_text(dialog_ex, NULL);

View File

@@ -9,9 +9,9 @@ void infrared_scene_ask_retry_on_enter(void* context) {
Infrared* infrared = context;
DialogEx* dialog_ex = infrared->dialog_ex;
dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Return to Reading?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop);
dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, "Exit");
dialog_ex_set_center_button_text(dialog_ex, NULL);

View File

@@ -21,5 +21,4 @@ ADD_SCENE(infrared, universal_audio, UniversalAudio)
ADD_SCENE(infrared, universal_projector, UniversalProjector)
ADD_SCENE(infrared, debug, Debug)
ADD_SCENE(infrared, error_databases, ErrorDatabases)
ADD_SCENE(infrared, debug_settings, DebugSettings)
ADD_SCENE(infrared, rpc, Rpc)

View File

@@ -1,59 +0,0 @@
#include "../infrared_i.h"
#include <furi_hal_infrared.h>
uint8_t value_index_ir;
#define DEB_PINS_COUNT (sizeof(infrared_debug_cfg_variables_text) / sizeof(char* const))
const char* const infrared_debug_cfg_variables_text[] = {
"Internal",
"2 (A7)",
};
static void infrared_scene_debug_settings_changed(VariableItem* item) {
Infrared* infrared = variable_item_get_context(item);
value_index_ir = variable_item_get_current_value_index(item);
UNUSED(infrared);
variable_item_set_current_value_text(item, infrared_debug_cfg_variables_text[value_index_ir]);
furi_hal_infrared_set_debug_out(value_index_ir);
}
static void infrared_debug_settings_start_var_list_enter_callback(void* context, uint32_t index) {
Infrared* infrared = context;
view_dispatcher_send_custom_event(infrared->view_dispatcher, index);
}
void infrared_scene_debug_settings_on_enter(void* context) {
Infrared* infrared = context;
VariableItemList* variable_item_list = infrared->variable_item_list;
value_index_ir = furi_hal_infrared_get_debug_out_status();
VariableItem* item = variable_item_list_add(
variable_item_list,
"Send signal to",
DEB_PINS_COUNT,
infrared_scene_debug_settings_changed,
infrared);
variable_item_list_set_enter_callback(
variable_item_list, infrared_debug_settings_start_var_list_enter_callback, infrared);
variable_item_set_current_value_index(item, value_index_ir);
variable_item_set_current_value_text(item, infrared_debug_cfg_variables_text[value_index_ir]);
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewVariableItemList);
}
bool infrared_scene_debug_settings_on_event(void* context, SceneManagerEvent event) {
Infrared* infrared = context;
UNUSED(infrared);
UNUSED(event);
return false;
}
void infrared_scene_debug_settings_on_exit(void* context) {
Infrared* infrared = context;
variable_item_list_reset(infrared->variable_item_list);
}

View File

@@ -5,8 +5,7 @@ enum SubmenuIndex {
SubmenuIndexLearnNewRemote,
SubmenuIndexLearnNewRemoteRaw,
SubmenuIndexSavedRemotes,
SubmenuIndexDebug,
SubmenuIndexDebugSettings
SubmenuIndexDebug
};
static void infrared_scene_start_submenu_callback(void* context, uint32_t index) {
@@ -46,17 +45,7 @@ void infrared_scene_start_on_enter(void* context) {
infrared_scene_start_submenu_callback,
infrared);
submenu_add_item(
submenu,
"Debug RX",
SubmenuIndexDebug,
infrared_scene_start_submenu_callback,
infrared);
submenu_add_item(
submenu,
"Debug Settings",
SubmenuIndexDebugSettings,
infrared_scene_start_submenu_callback,
infrared);
submenu, "Debug", SubmenuIndexDebug, infrared_scene_start_submenu_callback, infrared);
}
const uint32_t submenu_index =
@@ -97,9 +86,6 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) {
} else if(submenu_index == SubmenuIndexDebug) {
scene_manager_next_scene(scene_manager, InfraredSceneDebug);
consumed = true;
} else if(submenu_index == SubmenuIndexDebugSettings) {
scene_manager_next_scene(scene_manager, InfraredSceneDebugSettings);
consumed = true;
}
}

View File

@@ -10,7 +10,7 @@
extern "C" {
#endif
/** Anonymous instance */
/** Anonumous instance */
typedef struct InfraredProgressView InfraredProgressView;
/** Callback for back button handling */

View File

@@ -14,7 +14,7 @@ static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) {
T55xxTiming* t55xxtiming = malloc(sizeof(T55xxTiming));
Popup* popup = app->popup;
char curr_buf[32] = {};
//TODO: use .txt file in resources for passwords.
//TODO: use .txt file in resourses for passwords.
const uint32_t default_passwords[] = {
0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F,
0x89A69E60, 0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752,

View File

@@ -7,7 +7,7 @@ void lfrfid_scene_retry_confirm_on_enter(void* context) {
widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Retry Reading?");
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?");
widget_add_string_element(
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");

View File

@@ -9,7 +9,7 @@
* @param aid - AID number array
* @param aid_len - AID length
* @param aid_name - string to keep AID name
* @return - true if AID found, false otherwise
* @return - true if AID found, false otherwies
*/
bool nfc_emv_parser_get_aid_name(
Storage* storage,
@@ -21,7 +21,7 @@ bool nfc_emv_parser_get_aid_name(
* @param storage Storage instance
* @param country_code - ISO 3166 country code
* @param country_name - string to keep country name
* @return - true if country found, false otherwise
* @return - true if country found, false otherwies
*/
bool nfc_emv_parser_get_country_name(
Storage* storage,
@@ -32,7 +32,7 @@ bool nfc_emv_parser_get_country_name(
* @param storage Storage instance
* @param currency_code - ISO 3166 currency code
* @param currency_name - string to keep currency name
* @return - true if currency found, false otherwise
* @return - true if currency found, false otherwies
*/
bool nfc_emv_parser_get_currency_name(
Storage* storage,

View File

@@ -32,7 +32,7 @@ static void nfc_cli_detect(Cli* cli, FuriString* args) {
while(!cmd_exit) {
cmd_exit |= cli_cmd_interrupt_received(cli);
if(furi_hal_nfc_detect(&dev_data, 400)) {
printf("Found: %s ", nfc_get_dev_type(dev_data.type));
printf("found: %s ", nfc_get_dev_type(dev_data.type));
printf("UID length: %d, UID:", dev_data.uid_len);
for(size_t i = 0; i < dev_data.uid_len; i++) {
printf("%02X", dev_data.uid[i]);

View File

@@ -29,7 +29,6 @@ ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu)
ADD_SCENE(nfc, mf_desfire_data, MfDesfireData)
ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp)
ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess)
ADD_SCENE(nfc, mf_classic_data, MfClassicData)
ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu)
ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate)
ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys)

View File

@@ -1,106 +0,0 @@
#include "../nfc_i.h"
void nfc_scene_mf_classic_data_on_enter(void* context) {
Nfc* nfc = context;
MfClassicType type = nfc->dev->dev_data.mf_classic_data.type;
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
TextBox* text_box = nfc->text_box;
text_box_set_font(text_box, TextBoxFontHex);
int card_blocks = 0;
if(type == MfClassicType1k) {
card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4;
} else if(type == MfClassicType4k) {
// 16 sectors of 4 blocks each plus 8 sectors of 16 blocks each
card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4 + 8 * 16;
} else if(type == MfClassicTypeMini) {
card_blocks = MF_MINI_TOTAL_SECTORS_NUM * 4;
}
int bytes_written = 0;
for(int block_num = 0; block_num < card_blocks; block_num++) {
bool is_sec_trailer = mf_classic_is_sector_trailer(block_num);
if(is_sec_trailer) {
uint8_t sector_num = mf_classic_get_sector_by_block(block_num);
MfClassicSectorTrailer* sec_tr =
mf_classic_get_sector_trailer_by_sector(data, sector_num);
// Key A
for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) {
if((bytes_written % 8 == 0) && (bytes_written != 0)) {
furi_string_push_back(nfc->text_box_store, '\n');
}
if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) {
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]);
} else {
furi_string_cat_printf(nfc->text_box_store, "???? ");
}
bytes_written += 2;
}
// Access bytes
for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i += 2) {
if((bytes_written % 8 == 0) && (bytes_written != 0)) {
furi_string_push_back(nfc->text_box_store, '\n');
}
if(mf_classic_is_block_read(data, block_num)) {
furi_string_cat_printf(
nfc->text_box_store,
"%02X%02X ",
sec_tr->access_bits[i],
sec_tr->access_bits[i + 1]);
} else {
furi_string_cat_printf(nfc->text_box_store, "???? ");
}
bytes_written += 2;
}
// Key B
for(size_t i = 0; i < sizeof(sec_tr->key_b); i += 2) {
if((bytes_written % 8 == 0) && (bytes_written != 0)) {
furi_string_push_back(nfc->text_box_store, '\n');
}
if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) {
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]);
} else {
furi_string_cat_printf(nfc->text_box_store, "???? ");
}
bytes_written += 2;
}
} else {
// Write data block
for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i += 2) {
if((bytes_written % 8 == 0) && (bytes_written != 0)) {
furi_string_push_back(nfc->text_box_store, '\n');
}
if(mf_classic_is_block_read(data, block_num)) {
furi_string_cat_printf(
nfc->text_box_store,
"%02X%02X ",
data->block[block_num].value[i],
data->block[block_num].value[i + 1]);
} else {
furi_string_cat_printf(nfc->text_box_store, "???? ");
}
bytes_written += 2;
}
}
}
text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
}
bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void nfc_scene_mf_classic_data_on_exit(void* context) {
Nfc* nfc = context;
// Clean view
text_box_reset(nfc->text_box);
furi_string_reset(nfc->text_box_store);
}

View File

@@ -25,7 +25,7 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) {
if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) {
submenu_add_item(
submenu,
"Detect Reader",
"Detect reader",
SubmenuIndexDetectReader,
nfc_scene_mf_classic_menu_submenu_callback,
nfc);

View File

@@ -14,8 +14,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
NfcDeviceData* dev_data = &nfc->dev->dev_data;
NfcProtocol protocol = dev_data->protocol;
uint8_t text_scroll_height = 0;
if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) ||
(protocol == NfcDeviceProtocolMifareClassic)) {
if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)) {
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc);
text_scroll_height = 52;
@@ -137,9 +136,6 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) {
} else if(protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData);
consumed = true;
} else if(protocol == NfcDeviceProtocolMifareClassic) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData);
consumed = true;
}
}
}

View File

@@ -46,9 +46,6 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed =
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
}
return consumed;
}

View File

@@ -14,7 +14,7 @@ void nfc_scene_retry_confirm_on_enter(void* context) {
dialog_ex_set_right_button_text(dialog_ex, "Stay");
dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop);
dialog_ex, "All unsaved data will be\nlost!", 64, 25, AlignCenter, AlignTop);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback);

View File

@@ -52,20 +52,20 @@ void nfc_scene_saved_menu_on_enter(void* context) {
if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) {
submenu_add_item(
submenu,
"Detect Reader",
"Detect reader",
SubmenuIndexDetectReader,
nfc_scene_saved_menu_submenu_callback,
nfc);
}
submenu_add_item(
submenu,
"Write to Initial Card",
"Write To Initial Card",
SubmenuIndexWrite,
nfc_scene_saved_menu_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Update from Initial Card",
"Update From Initial Card",
SubmenuIndexUpdate,
nfc_scene_saved_menu_submenu_callback,
nfc);
@@ -76,13 +76,13 @@ void nfc_scene_saved_menu_on_enter(void* context) {
!mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) {
submenu_add_item(
submenu,
"Unlock with Reader",
"Unlock With Reader",
SubmenuIndexMfUlUnlockByReader,
nfc_scene_saved_menu_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Unlock with Password",
"Unlock With Password",
SubmenuIndexMfUlUnlockByPassword,
nfc_scene_saved_menu_submenu_callback,
nfc);
@@ -151,8 +151,6 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
application_info_present = nfc_supported_card_verify_and_parse(dev_data);
}
FURI_LOG_I("nfc", "application_info_present: %d", application_info_present);
if(application_info_present) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
} else {

View File

@@ -9,7 +9,7 @@ struct SubGhzChatWorker {
SubGhzTxRxWorker* subghz_txrx;
volatile bool worker_running;
volatile bool worker_stopping;
volatile bool worker_stoping;
FuriMessageQueue* event_queue;
uint32_t last_time_rx_data;

View File

@@ -8,14 +8,11 @@ typedef enum {
//SubmenuIndex
SubmenuIndexFaacSLH_433,
SubmenuIndexFaacSLH_868,
SubmenuIndexBFTClone,
SubmenuIndexBFTMitto,
SubmenuIndexSomfyTelis,
SubmenuIndexBFT,
SubmenuIndexPricenton,
SubmenuIndexNiceFlo12bit,
SubmenuIndexNiceFlo24bit,
SubmenuIndexNiceFlorS_433_92,
SubmenuIndexNiceOne_433_92,
SubmenuIndexNiceSmilo_433_92,
SubmenuIndexCAME12bit,
SubmenuIndexCAME24bit,
@@ -67,7 +64,6 @@ typedef enum {
SubGhzCustomEventViewReceiverBack,
SubGhzCustomEventViewReceiverOffDisplay,
SubGhzCustomEventViewReceiverUnlock,
SubGhzCustomEventViewReceiverDeleteItem,
SubGhzCustomEventViewReadRAWBack,
SubGhzCustomEventViewReadRAWIDLE,

View File

@@ -117,17 +117,15 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
// First stage: coarse scan
for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) {
uint32_t current_frequency = subghz_setting_get_frequency(instance->setting, i);
if(furi_hal_subghz_is_frequency_valid(current_frequency) &&
(current_frequency != 467750000) && (current_frequency != 464000000) &&
uint32_t current_frequnecy = subghz_setting_get_frequency(instance->setting, i);
if(furi_hal_subghz_is_frequency_valid(current_frequnecy) &&
(current_frequnecy != 467750000) &&
!((furi_hal_subghz.radio_type == SubGhzRadioExternal) &&
((current_frequency == 390000000) || (current_frequency == 312000000) ||
(current_frequency == 312100000) || (current_frequency == 312200000) ||
(current_frequency == 440175000)))) {
(current_frequnecy >= 311900000 && current_frequnecy <= 312200000))) {
furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle);
cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle);
frequency =
cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequency);
cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequnecy);
cc1101_calibrate(furi_hal_subghz.spi_bus_handle);
do {
@@ -332,4 +330,4 @@ void subghz_frequency_analyzer_worker_set_trigger_level(
float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance) {
return instance->trigger_level;
}
}

View File

@@ -23,7 +23,7 @@ typedef enum {
/** SubGhzHopperState state */
typedef enum {
SubGhzHopperStateOFF,
SubGhzHopperStateRunning,
SubGhzHopperStateRunnig,
SubGhzHopperStatePause,
SubGhzHopperStateRSSITimeOut,
} SubGhzHopperState;
@@ -54,7 +54,6 @@ typedef enum {
SubGhzLoadKeyStateOK,
SubGhzLoadKeyStateParseErr,
SubGhzLoadKeyStateOnlyRx,
SubGhzLoadKeyStateProtocolDescriptionErr,
} SubGhzLoadKeyState;
/** SubGhzLock */

View File

@@ -1,10 +1,8 @@
#include "../subghz_i.h"
#include "../helpers/subghz_custom_event.h"
uint8_t value_index_exm;
uint8_t value_index_dpin;
uint8_t value_index_cnt;
uint8_t value_index_pwr;
uint8_t value_index;
uint8_t value_index2;
#define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const))
const char* const radio_modules_variables_text[] = {
@@ -12,34 +10,18 @@ const char* const radio_modules_variables_text[] = {
"External",
};
#define EXT_MOD_POWER_COUNT 2
const char* const ext_mod_power_text[EXT_MOD_POWER_COUNT] = {
"ON",
"OFF",
};
#define DEBUG_P_COUNT 2
const char* const debug_pin_text[DEBUG_P_COUNT] = {
"OFF",
"17(1W)",
};
#define DEBUG_COUNTER_COUNT 6
const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = {
"+1",
"+2",
"+3",
"+4",
"+5",
"+10",
};
static void subghz_scene_ext_module_changed(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
value_index_exm = variable_item_get_current_value_index(item);
value_index = variable_item_get_current_value_index(item);
UNUSED(subghz);
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]);
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]);
}
static void subghz_ext_module_start_var_list_enter_callback(void* context, uint32_t index) {
SubGhz* subghz = context;
@@ -55,114 +37,31 @@ static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) {
subghz->txrx->debug_pin_state = index == 1;
}
static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) {
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, debug_counter_text[index]);
switch(index) {
case 0:
furi_hal_subghz_set_rolling_counter_mult(1);
break;
case 1:
furi_hal_subghz_set_rolling_counter_mult(2);
break;
case 2:
furi_hal_subghz_set_rolling_counter_mult(3);
break;
case 3:
furi_hal_subghz_set_rolling_counter_mult(4);
break;
case 4:
furi_hal_subghz_set_rolling_counter_mult(5);
break;
case 5:
furi_hal_subghz_set_rolling_counter_mult(10);
break;
default:
break;
}
}
static void subghz_scene_receiver_config_set_ext_mod_power(VariableItem* item) {
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, ext_mod_power_text[index]);
furi_hal_subghz_set_external_power_disable(index == 1);
if(index == 1) {
furi_hal_subghz_disable_ext_power();
} else {
furi_hal_subghz_enable_ext_power();
}
}
void subghz_scene_ext_module_settings_on_enter(void* context) {
SubGhz* subghz = context;
VariableItemList* variable_item_list = subghz->variable_item_list;
value_index_exm = furi_hal_subghz.radio_type;
value_index = furi_hal_subghz.radio_type;
VariableItem* item = variable_item_list_add(
variable_item_list, "Module", EXT_MODULES_COUNT, subghz_scene_ext_module_changed, subghz);
variable_item_list_set_enter_callback(
variable_item_list, subghz_ext_module_start_var_list_enter_callback, subghz);
variable_item_set_current_value_index(item, value_index_exm);
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]);
item = variable_item_list_add(
subghz->variable_item_list,
"Ext Radio 5v",
EXT_MOD_POWER_COUNT,
subghz_scene_receiver_config_set_ext_mod_power,
subghz);
value_index_pwr = furi_hal_subghz_get_external_power_disable();
variable_item_set_current_value_index(item, value_index_pwr);
variable_item_set_current_value_text(item, ext_mod_power_text[value_index_pwr]);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
item = variable_item_list_add(
subghz->variable_item_list,
"Debug Pin",
"Debug Pin:",
DEBUG_P_COUNT,
subghz_scene_receiver_config_set_debug_pin,
subghz);
value_index_dpin = subghz->txrx->debug_pin_state;
variable_item_set_current_value_index(item, value_index_dpin);
variable_item_set_current_value_text(item, debug_pin_text[value_index_dpin]);
item = variable_item_list_add(
subghz->variable_item_list,
"Counter incr.",
DEBUG_COUNTER_COUNT,
subghz_scene_receiver_config_set_debug_counter,
subghz);
switch(furi_hal_subghz_get_rolling_counter_mult()) {
case 1:
value_index_cnt = 0;
break;
case 2:
value_index_cnt = 1;
break;
case 3:
value_index_cnt = 2;
break;
case 4:
value_index_cnt = 3;
break;
case 5:
value_index_cnt = 4;
break;
case 10:
value_index_cnt = 5;
break;
default:
break;
}
variable_item_set_current_value_index(item, value_index_cnt);
variable_item_set_current_value_text(item, debug_counter_text[value_index_cnt]);
value_index2 = subghz->txrx->debug_pin_state;
variable_item_set_current_value_index(item, value_index2);
variable_item_set_current_value_text(item, debug_pin_text[value_index2]);
}
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
@@ -174,14 +73,12 @@ bool subghz_scene_ext_module_settings_on_event(void* context, SceneManagerEvent
UNUSED(event);
// Set selected radio module
furi_hal_subghz_set_radio_type(value_index_exm);
furi_hal_subghz_enable_ext_power();
furi_hal_subghz_set_radio_type(value_index);
// Check if module is present, if no -> show error
if(!furi_hal_subghz_check_radio()) {
value_index_exm = 0;
furi_hal_subghz_set_radio_type(value_index_exm);
value_index = 0;
furi_hal_subghz_set_radio_type(value_index);
furi_string_set(subghz->error_str, "Please connect\nexternal radio");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
}

View File

@@ -16,7 +16,7 @@ void subghz_scene_need_saving_on_enter(void* context) {
SubGhz* subghz = context;
widget_add_string_multiline_element(
subghz->widget, 64, 13, AlignCenter, AlignCenter, FontPrimary, "Exit to Sub-GHz Menu?");
subghz->widget, 64, 13, AlignCenter, AlignCenter, FontPrimary, "Exit to Sub-GHz menu?");
widget_add_string_multiline_element(
subghz->widget,
64,
@@ -24,7 +24,7 @@ void subghz_scene_need_saving_on_enter(void* context) {
AlignCenter,
AlignCenter,
FontSecondary,
"All unsaved data\nwill be lost!");
"All unsaved will be\nlost.");
widget_add_button_element(
subghz->widget, GuiButtonTypeRight, "Stay", subghz_scene_need_saving_callback, subghz);

View File

@@ -368,7 +368,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
float rssi = furi_hal_subghz_get_rssi();
if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) {
if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) {
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
subghz_protocol_raw_save_to_file_pause(
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
@@ -421,4 +421,4 @@ void subghz_scene_read_raw_on_exit(void* context) {
//filter restoration
subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
}
}

View File

@@ -204,16 +204,6 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
consumed = true;
break;
case SubGhzCustomEventViewReceiverDeleteItem:
subghz->txrx->idx_menu_chosen =
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
subghz_history_delete_item(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
subghz_view_receiver_delete_element_callback(subghz->subghz_receiver);
subghz_scene_receiver_update_statusbar(subghz);
consumed = true;
break;
case SubGhzCustomEventViewReceiverConfig:
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz->txrx->idx_menu_chosen =

View File

@@ -8,11 +8,11 @@ enum SubGhzSettingIndex {
SubGhzSettingIndexBinRAW,
SubGhzSettingIndexSound,
SubGhzSettingIndexLock,
SubGhzSettingIndexRAWThresholdRSSI,
SubGhzSettingIndexRAWThesholdRSSI,
};
#define RAW_THRESHOLD_RSSI_COUNT 11
const char* const raw_threshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = {
const char* const raw_theshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = {
"-----",
"-85.0",
"-80.0",
@@ -26,7 +26,7 @@ const char* const raw_threshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = {
"-40.0",
};
const float raw_threshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = {
const float raw_theshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = {
-90.0f,
-85.0f,
-80.0f,
@@ -47,7 +47,7 @@ const char* const hopping_text[HOPPING_COUNT] = {
};
const uint32_t hopping_value[HOPPING_COUNT] = {
SubGhzHopperStateOFF,
SubGhzHopperStateRunning,
SubGhzHopperStateRunnig,
};
#define SPEAKER_COUNT 2
@@ -213,8 +213,8 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, raw_threshold_rssi_text[index]);
subghz->txrx->raw_threshold_rssi = raw_threshold_rssi_value[index];
variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]);
subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index];
}
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
@@ -320,9 +320,9 @@ void subghz_scene_receiver_config_on_enter(void* context) {
subghz_scene_receiver_config_set_raw_threshold_rssi,
subghz);
value_index = value_index_float(
subghz->txrx->raw_threshold_rssi, raw_threshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT);
subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, raw_threshold_rssi_text[value_index]);
variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]);
}
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
}

View File

@@ -2,9 +2,6 @@
#include "../helpers/subghz_custom_event.h"
#include <lib/subghz/protocols/keeloq.h>
#include <lib/subghz/protocols/star_line.h>
#include <lib/subghz/protocols/alutech_at_4n.h>
#include <lib/subghz/protocols/nice_flor_s.h>
#include <lib/subghz/protocols/somfy_telis.h>
void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
@@ -27,9 +24,8 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
subghz->txrx->receiver,
subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
if(subghz->txrx->decoder_result) {
//todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
// In this case flipper format was changed to short file content
subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result,
subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
@@ -139,6 +135,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
subghz,
subghz_history_get_raw_data(
subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz);
}
@@ -151,7 +148,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
subghz_rx(subghz, subghz->txrx->preset->frequency);
}
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
subghz->txrx->hopper_state = SubGhzHopperStateRunning;
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
}
subghz->state_notifications = SubGhzNotificationStateRx;
} else {
@@ -178,7 +175,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
subghz_rx(subghz, subghz->txrx->preset->frequency);
}
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
subghz->txrx->hopper_state = SubGhzHopperStateRunning;
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
}
subghz->state_notifications = SubGhzNotificationStateRx;
}
@@ -236,10 +233,6 @@ void subghz_scene_receiver_info_on_exit(void* context) {
widget_reset(subghz->widget);
keeloq_reset_mfname();
keeloq_reset_kl_type();
keeloq_reset_original_btn();
alutech_reset_original_btn();
nice_flors_reset_original_btn();
somfy_telis_reset_original_btn();
star_line_reset_mfname();
star_line_reset_kl_type();
}

View File

@@ -1,9 +1,6 @@
#include "../subghz_i.h"
#include <lib/subghz/protocols/keeloq.h>
#include <lib/subghz/protocols/star_line.h>
#include <lib/subghz/protocols/alutech_at_4n.h>
#include <lib/subghz/protocols/nice_flor_s.h>
#include <lib/subghz/protocols/somfy_telis.h>
typedef enum {
SubGhzRpcStateIdle,
@@ -113,10 +110,6 @@ void subghz_scene_rpc_on_exit(void* context) {
keeloq_reset_mfname();
keeloq_reset_kl_type();
keeloq_reset_original_btn();
alutech_reset_original_btn();
nice_flors_reset_original_btn();
somfy_telis_reset_original_btn();
star_line_reset_mfname();
star_line_reset_kl_type();
}

View File

@@ -14,7 +14,7 @@ void subghz_scene_set_seed_bft_on_enter(void* context) {
SubGhz* subghz = context;
// Setup view
// RogueMaster don't steal!!!
// roguemaster don't steal!!!
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter SEED in hex");
byte_input_set_result_callback(

View File

@@ -65,7 +65,7 @@ bool subghz_scene_set_seed_faac_on_event(void* context, SceneManagerEvent event)
seed,
"FAAC_SLH",
subghz->txrx->preset);
// RogueMaster dont steal!
// rogueemaster dont steal!
uint8_t seed_data[sizeof(uint32_t)] = {0};
for(size_t i = 0; i < sizeof(uint32_t); i++) {
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;

View File

@@ -36,9 +36,8 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
do {
Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
stream_clean(fff_data_stream);
if(subghz_protocol_decoder_base_serialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) !=
SubGhzProtocolStatusOk) {
if(!subghz_protocol_decoder_base_serialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset)) {
FURI_LOG_E(TAG, "Unable to serialize");
break;
}
@@ -80,22 +79,10 @@ void subghz_scene_set_type_on_enter(void* context) {
SubmenuIndexFaacSLH_433,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"BFT [Manual] 433MHz",
SubmenuIndexBFTClone,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"BFT Mitto 433MHz",
SubmenuIndexBFTMitto,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"Somfy Telis 433MHz",
SubmenuIndexSomfyTelis,
SubmenuIndexBFT,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
@@ -128,12 +115,6 @@ void subghz_scene_set_type_on_enter(void* context) {
SubmenuIndexNiceFlorS_433_92,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"Nice One 433MHz",
SubmenuIndexNiceOne_433_92,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"CAME 12bit 433MHz",
@@ -249,7 +230,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexFaacSLH_433:
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac);
break;
case SubmenuIndexBFTClone:
case SubmenuIndexBFT:
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft);
break;
case SubmenuIndexPricenton:
@@ -325,69 +306,11 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
generated_protocol = true;
}
break;
case SubmenuIndexBFTMitto:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_keeloq_bft_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
subghz->txrx->fff_data,
key & 0x000FFFFF,
0x2,
0x0002,
key & 0x000FFFFF,
"BFT",
subghz->txrx->preset);
uint8_t seed_data[sizeof(uint32_t)] = {0};
for(size_t i = 0; i < sizeof(uint32_t); i++) {
seed_data[sizeof(uint32_t) - i - 1] = ((key & 0x000FFFFF) >> i * 8) & 0xFF;
}
flipper_format_write_hex(
subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT");
generated_protocol = true;
} else {
generated_protocol = false;
}
subghz_transmitter_free(subghz->txrx->transmitter);
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexSomfyTelis:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_somfy_telis_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
subghz->txrx->fff_data,
key & 0x00FFFFFF,
0x2,
0x0003,
subghz->txrx->preset);
generated_protocol = true;
} else {
generated_protocol = false;
}
subghz_transmitter_free(subghz->txrx->transmitter);
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexDoorHan_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz_preset_init(
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_keeloq_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
@@ -435,7 +358,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexNiceFlorS_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz_preset_init(
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_nice_flor_s_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
@@ -443,32 +367,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
key & 0x0FFFFFFF,
0x1,
0x0003,
subghz->txrx->preset,
false);
generated_protocol = true;
} else {
generated_protocol = false;
}
subghz_transmitter_free(subghz->txrx->transmitter);
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexNiceOne_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_nice_flor_s_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
subghz->txrx->fff_data,
key & 0x0FFFFFFF,
0x1,
0x0003,
subghz->txrx->preset,
true);
subghz->txrx->preset);
generated_protocol = true;
} else {
generated_protocol = false;
@@ -483,7 +382,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexNiceSmilo_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz_preset_init(
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_keeloq_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),

View File

@@ -75,46 +75,43 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexExtSettings);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneExtModuleSettings);
return true;
} else if(!furi_hal_subghz_check_radio()) {
furi_string_set(subghz->error_str, "Please connect\nexternal radio");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
return true;
} else if(event.event == SubmenuIndexReadRAW) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
return true;
} else if(event.event == SubmenuIndexRead) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
return true;
} else if(event.event == SubmenuIndexSaved) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexSaved);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
return true;
} else if(event.event == SubmenuIndexAddManually) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManually);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType);
return true;
} else {
furi_hal_subghz_enable_ext_power();
if(!furi_hal_subghz_check_radio()) {
furi_string_set(subghz->error_str, "Please connect\nexternal radio");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
return true;
} else if(event.event == SubmenuIndexReadRAW) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
return true;
} else if(event.event == SubmenuIndexRead) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
return true;
} else if(event.event == SubmenuIndexSaved) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexSaved);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
return true;
} else if(event.event == SubmenuIndexFrequencyAnalyzer) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer);
DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer);
return true;
} else if(event.event == SubmenuIndexTest) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTest);
return true;
}
} else if(event.event == SubmenuIndexFrequencyAnalyzer) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer);
DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer);
return true;
} else if(event.event == SubmenuIndexTest) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTest);
return true;
}
}
return false;

View File

@@ -2,10 +2,7 @@
#include "../views/transmitter.h"
#include <dolphin/dolphin.h>
#include <lib/subghz/protocols/keeloq.h>
#include <lib/subghz/protocols/alutech_at_4n.h>
#include <lib/subghz/protocols/star_line.h>
#include <lib/subghz/protocols/nice_flor_s.h>
#include <lib/subghz/protocols/somfy_telis.h>
void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
furi_assert(context);
@@ -14,8 +11,9 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
}
bool subghz_scene_transmitter_update_data_show(void* context) {
//ToDo Fix
SubGhz* subghz = context;
bool ret = false;
if(subghz->txrx->decoder_result) {
FuriString* key_str;
FuriString* frequency_str;
@@ -26,29 +24,30 @@ bool subghz_scene_transmitter_update_data_show(void* context) {
modulation_str = furi_string_alloc();
uint8_t show_button = 0;
if(subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) {
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str);
subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data);
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str);
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
SubGhzProtocolFlag_Send) {
show_button = 1;
}
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
subghz_view_transmitter_add_data_to_show(
subghz->subghz_transmitter,
furi_string_get_cstr(key_str),
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
show_button);
ret = true;
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
SubGhzProtocolFlag_Send) {
show_button = 1;
}
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
subghz_view_transmitter_add_data_to_show(
subghz->subghz_transmitter,
furi_string_get_cstr(key_str),
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
show_button);
furi_string_free(frequency_str);
furi_string_free(modulation_str);
furi_string_free(key_str);
return true;
}
return ret;
return false;
}
void subghz_scene_transmitter_on_enter(void* context) {
@@ -90,27 +89,6 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
subghz_tx_stop(subghz);
subghz_sleep(subghz);
}
if(keeloq_get_custom_btn() != 0) {
keeloq_set_btn(0);
alutech_set_btn(0);
nice_flors_set_btn(0);
somfy_telis_set_btn(0);
uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult();
furi_hal_subghz_set_rolling_counter_mult(0);
// Calling restore!
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz);
}
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
}
}
subghz_tx_stop(subghz);
subghz_sleep(subghz);
furi_hal_subghz_set_rolling_counter_mult(tmp_counter);
}
return true;
} else if(event.event == SubGhzCustomEventViewTransmitterBack) {
subghz->state_notifications = SubGhzNotificationStateIDLE;
@@ -135,10 +113,6 @@ void subghz_scene_transmitter_on_exit(void* context) {
subghz->state_notifications = SubGhzNotificationStateIDLE;
keeloq_reset_mfname();
keeloq_reset_kl_type();
keeloq_reset_original_btn();
alutech_reset_original_btn();
nice_flors_reset_original_btn();
somfy_telis_reset_original_btn();
star_line_reset_mfname();
star_line_reset_kl_type();
}

View File

@@ -275,7 +275,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
subghz->txrx->history = subghz_history_alloc();
}
subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN;
subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN;
subghz->txrx->worker = subghz_worker_alloc();
subghz->txrx->fff_data = flipper_format_string_alloc();
@@ -421,9 +421,6 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) {
// The rest
free(subghz);
// Disable power for External CC1101 if it was enabled and module is connected
furi_hal_subghz_disable_ext_power();
}
int32_t subghz_app(void* p) {

View File

@@ -88,28 +88,6 @@ void subghz_history_reset(SubGhzHistory* instance) {
instance->code_last_hash_data = 0;
}
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id) {
furi_assert(instance);
SubGhzHistoryItemArray_it_t it;
//SubGhzHistoryItem* target_item = SubGhzHistoryItemArray_get(instance->history->data, item_id);
SubGhzHistoryItemArray_it_last(it, instance->history->data);
while(!SubGhzHistoryItemArray_end_p(it)) {
SubGhzHistoryItem* item = SubGhzHistoryItemArray_ref(it);
if(it->index == (size_t)(item_id)) {
furi_string_free(item->item_str);
furi_string_free(item->preset->name);
free(item->preset);
flipper_format_free(item->flipper_string);
item->type = 0;
SubGhzHistoryItemArray_remove(instance->history->data, it);
}
SubGhzHistoryItemArray_previous(it);
}
instance->last_index_write--;
}
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
furi_assert(instance);
return instance->last_index_write;

View File

@@ -27,8 +27,6 @@ void subghz_history_free(SubGhzHistory* instance);
*/
void subghz_history_reset(SubGhzHistory* instance);
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id);
/** Get frequency to history[idx]
*
* @param instance - SubGhzHistory instance
@@ -82,7 +80,7 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* outp
*
* @param instance - SubGhzHistory instance
* @param output - FuriString* output
* @return bool - is FULL
* @return bool - is FUUL
*/
bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output);

View File

@@ -92,7 +92,7 @@ uint32_t subghz_history_rand_range(uint32_t min, uint32_t max);
*
* @param file - Stream*
* @param is_negative_start - first value is negative or positive?
* @param current_position - 0 if started from beginning
* @param current_position - 0 if started from begining
* @param empty_line - add RAW_Data to this line
* @return true
* @return false
@@ -160,4 +160,4 @@ bool subghz_history_stream_seek_to_key(Stream* stream, const char* key, bool str
* @return true
* @return false
*/
bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last);
bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last);

View File

@@ -154,6 +154,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
FURI_LOG_E(TAG, "Missing Protocol");
break;
}
//ToDo FIX
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
FURI_LOG_E(TAG, "Unable Repeat");
break;
@@ -163,8 +164,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
subghz->txrx->environment, furi_string_get_cstr(temp_str));
if(subghz->txrx->transmitter) {
if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) ==
SubGhzProtocolStatusOk) {
if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) {
if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) {
subghz_begin(
subghz,
@@ -187,12 +187,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
//Start TX
furi_hal_subghz_start_async_tx(
subghz_transmitter_yield, subghz->txrx->transmitter);
} else {
subghz_dialog_message_show_only_rx(subghz);
}
} else {
dialog_message_show_storage_error(
subghz->dialogs, "Error in protocol\nparameters\ndescription");
}
}
if(!ret) {
@@ -340,10 +335,8 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
subghz->txrx->receiver, furi_string_get_cstr(temp_str));
if(subghz->txrx->decoder_result) {
SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data);
if(status != SubGhzProtocolStatusOk) {
load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
if(!subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data)) {
break;
}
} else {
@@ -364,12 +357,6 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile");
}
return false;
case SubGhzLoadKeyStateProtocolDescriptionErr:
if(show_dialog) {
dialog_message_show_storage_error(
subghz->dialogs, "Error in protocol\nparameters\ndescription");
}
return false;
case SubGhzLoadKeyStateOnlyRx:
if(show_dialog) {
@@ -588,7 +575,7 @@ void subghz_hopper_update(SubGhz* subghz) {
return;
}
} else {
subghz->txrx->hopper_state = SubGhzHopperStateRunning;
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
}
// Select next frequency
if(subghz->txrx->hopper_idx_frequency <

View File

@@ -12,7 +12,7 @@
#define MENU_ITEMS 4u
#define UNLOCK_CNT 3
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
typedef struct {
FuriString* item_str;
@@ -80,10 +80,10 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) {
instance->view,
SubGhzViewReceiverModel * model,
{
if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
model->u_rssi = 0;
} else {
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
}
},
true);
@@ -427,34 +427,6 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
true);
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context);
} else if(event->key == InputKeyRight && event->type == InputTypeLong) {
with_view_model(
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
if(model->history_item != 0) {
SubGhzReceiverMenuItemArray_it_t it;
// SubGhzReceiverMenuItem* target_item =
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
if(it->index == (size_t)(model->idx)) {
furi_string_free(item->item_str);
item->type = 0;
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
}
SubGhzReceiverMenuItemArray_previous(it);
}
// Callback
subghz_receiver->callback(
SubGhzCustomEventViewReceiverDeleteItem, subghz_receiver->context);
}
},
true);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
subghz_receiver->view,
@@ -568,34 +540,12 @@ View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver) {
uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
uint16_t idx = 0;
uint32_t idx = 0;
with_view_model(
subghz_receiver->view, SubGhzViewReceiverModel * model, { idx = model->idx; }, false);
return idx;
}
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
if(model->history_item == 5) {
if(model->idx >= 2) {
model->idx = model->history_item - 1;
}
}
model->history_item--;
if(model->idx != 0) {
model->idx--;
}
},
true);
furi_delay_ms(200);
}
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
furi_assert(subghz_receiver);
with_view_model(

View File

@@ -46,6 +46,4 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver);
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver);
void subghz_view_receiver_exit(void* context);

View File

@@ -23,7 +23,7 @@ typedef struct {
FuriString* sample_write;
FuriString* file_name;
uint8_t* rssi_history;
uint8_t rssi_current;
uint8_t rssi_curret;
bool rssi_history_end;
uint8_t ind_write;
uint8_t ind_sin;
@@ -62,17 +62,17 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra
furi_assert(instance);
uint8_t u_rssi = 0;
if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
u_rssi = 0;
} else {
u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
}
with_view_model(
instance->view,
SubGhzReadRAWModel * model,
{
model->rssi_current = u_rssi;
model->rssi_curret = u_rssi;
if(trace) {
model->rssi_history[model->ind_write++] = u_rssi;
} else {
@@ -206,10 +206,10 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) {
canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[i]);
}
canvas_draw_line(
canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_current);
canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_curret);
if(model->ind_write > 3) {
canvas_draw_line(
canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_current);
canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_curret);
for(uint8_t i = 13; i < 47; i += width * 2) {
canvas_draw_line(canvas, model->ind_write, i, model->ind_write, i + width);
@@ -231,13 +231,13 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) {
SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1,
47,
SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1,
47 - model->rssi_current);
47 - model->rssi_curret);
canvas_draw_line(
canvas,
SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1,
47,
SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1,
47 - model->rssi_current);
47 - model->rssi_curret);
for(uint8_t i = 13; i < 47; i += width * 2) {
canvas_draw_line(
@@ -266,9 +266,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod
uint8_t x = 118;
uint8_t y = 48;
if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) {
if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) {
uint8_t x = 118;
y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
uint8_t width = 3;
for(uint8_t i = 0; i < x; i += width * 2) {

View File

@@ -3,7 +3,7 @@
#include <gui/view.h>
#include "../helpers/subghz_custom_event.h"
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
typedef struct SubGhzReadRAW SubGhzReadRAW;

View File

@@ -4,11 +4,6 @@
#include <input/input.h>
#include <gui/elements.h>
#include <lib/subghz/protocols/keeloq.h>
#include <lib/subghz/protocols/alutech_at_4n.h>
#include <lib/subghz/protocols/nice_flor_s.h>
#include <lib/subghz/protocols/somfy_telis.h>
struct SubGhzViewTransmitter {
View* view;
SubGhzViewTransmitterCallback callback;
@@ -20,8 +15,6 @@ typedef struct {
FuriString* preset_str;
FuriString* key_str;
uint8_t show_button;
FuriString* temp_button_id;
bool draw_temp_button;
} SubGhzViewTransmitterModel;
void subghz_view_transmitter_set_callback(
@@ -96,12 +89,6 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo
canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str));
if(model->draw_temp_button) {
canvas_set_font(canvas, FontBatteryPercent);
canvas_draw_str(canvas, 117, 40, furi_string_get_cstr(model->temp_button_id));
canvas_set_font(canvas, FontSecondary);
}
if(model->show_button) {
canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int");
subghz_view_transmitter_button_right(canvas, "Send");
@@ -121,9 +108,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
furi_string_reset(model->frequency_str);
furi_string_reset(model->preset_str);
furi_string_reset(model->key_str);
furi_string_reset(model->temp_button_id);
model->show_button = 0;
model->draw_temp_button = false;
},
false);
return false;
@@ -140,14 +125,6 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
true);
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
model->draw_temp_button = false;
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
@@ -157,141 +134,6 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
return true;
}
// Temp Buttons (UP)
if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) {
keeloq_set_btn(1);
alutech_set_btn(1);
nice_flors_set_btn(1);
somfy_telis_set_btn(1);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(keeloq_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
model->draw_temp_button = true;
} else if(alutech_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
model->draw_temp_button = true;
} else if(nice_flors_get_original_btn() != 0) {
furi_string_printf(
model->temp_button_id, "%01X", nice_flors_get_original_btn());
model->draw_temp_button = true;
} else if(somfy_telis_get_original_btn() != 0) {
furi_string_printf(
model->temp_button_id, "%01X", somfy_telis_get_original_btn());
model->draw_temp_button = true;
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Down
if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) {
keeloq_set_btn(2);
alutech_set_btn(2);
nice_flors_set_btn(2);
somfy_telis_set_btn(2);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(keeloq_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
model->draw_temp_button = true;
} else if(alutech_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
model->draw_temp_button = true;
} else if(nice_flors_get_original_btn() != 0) {
furi_string_printf(
model->temp_button_id, "%01X", nice_flors_get_original_btn());
model->draw_temp_button = true;
} else if(somfy_telis_get_original_btn() != 0) {
furi_string_printf(
model->temp_button_id, "%01X", somfy_telis_get_original_btn());
model->draw_temp_button = true;
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Left
if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) {
keeloq_set_btn(3);
alutech_set_btn(3);
nice_flors_set_btn(3);
somfy_telis_set_btn(3);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(keeloq_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
model->draw_temp_button = true;
} else if(alutech_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
model->draw_temp_button = true;
} else if(nice_flors_get_original_btn() != 0) {
furi_string_printf(
model->temp_button_id, "%01X", nice_flors_get_original_btn());
model->draw_temp_button = true;
} else if(somfy_telis_get_original_btn() != 0) {
furi_string_printf(
model->temp_button_id, "%01X", somfy_telis_get_original_btn());
model->draw_temp_button = true;
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Right
if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) {
keeloq_set_btn(4);
alutech_set_btn(4);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(keeloq_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
model->draw_temp_button = true;
} else if(alutech_get_original_btn() != 0) {
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
model->draw_temp_button = true;
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
return true;
}
@@ -324,7 +166,6 @@ SubGhzViewTransmitter* subghz_view_transmitter_alloc() {
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->key_str = furi_string_alloc();
model->temp_button_id = furi_string_alloc();
},
true);
return subghz_transmitter;
@@ -340,7 +181,6 @@ void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter) {
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->key_str);
furi_string_free(model->temp_button_id);
},
true);
view_free(subghz_transmitter->view);

Some files were not shown because too many files have changed in this diff Show More