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

Merge branch 'DarkFlippers:dev' into subbrute-rev3

This commit is contained in:
Der Skythe
2022-10-09 21:39:58 +04:00
committed by GitHub
83 changed files with 2850 additions and 1224 deletions

View File

@@ -85,7 +85,7 @@ steps:
Version: {{build.tag}}
[-Github-](https://github.com/Eng1n33r/flipperzero-firmware/releases/tag/${DRONE_TAG})
[-Github-](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/${DRONE_TAG})
[-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})"
@@ -105,7 +105,7 @@ steps:
Version: {{build.tag}}
[[Github]](https://github.com/Eng1n33r/flipperzero-firmware/releases/tag/${DRONE_TAG})
[[Github]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/${DRONE_TAG})
[-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})"

View File

@@ -1,22 +1,43 @@
### New changes
* Add 312.2 MHz to subghz user config
* PR: Add CAME 12bit 303MHz to SubGHz Bruteforcer (by @derskythe | PR #87)
* PR: Added norwegian keyboard layout for badusb (by @jd-raymaker | PR #88)
* Adapted all plugins and other code to new FuriString, fixed archive menu issues with new string type
* SubGHz: Fix double click after delete scene, fix rename bug
* Issues with hopping in subghz are fixed in this release
* OFW PR: Desktop: Set external apps as favorites (OFW PR 1816 by @djsime1) (and fixed forgotten furi_record_close)
* PR -> Plugins: Add CAME 12bit 303MHz to SubGHz Bruteforcer (by @derskythe | PR #87)
* PR -> BadUSB: Added Norwegian keyboard layout for BadUSB (by @jd-raymaker | PR #88)
* PR -> Plugins: Feature: allow to set ball speed in Arkanoid (by @an4tur0r | PR #92)
* Add USB Keyboard (& Mouse) plugin, replacing default USB Mouse demo included (plugin by @huuck) [Link to original](https://github.com/huuck/FlipperZeroUSBKeyboard)
* Fix USB Keyboard plugin wrong icon in mouse screen, rewrite view models to new type
* Updated universal remote assets (by @Amec0e)
* Plugins: SubGHz Bruteforcer - Fix wrong max value in BF existing dump
* API 3.0 -> 3.1 (all previous compiled apps still compatible)
* API 3.0 -> 3.2 (all previous compiled apps still compatible)
* Add 312.2 MHz to subghz user config
* SubGHz: Fix double click after delete scene, fix rename bug
* SubGHz: proper free of rainbow tables
* SubGHz: Fixed stability issues with Came atomo, Nice Flor S, limited max history items to 60 (was 65)
* SubGHz: Fix Read screen GUI (still bugged in OFW)
* Adapted all plugins and other code to new FuriString, fixed all new issues with new string type
* Adapted all plugins to new printf format
* Adapted all plugins to new view model format (aka Removing lambdas)
* Adapted all plugins to new furi_stream
* OFW: Elf loader: do not load .ARM.* sections
* OFW: Removing lambdas
* OFW: BadUSB: add SYSRQ keys
* OFW: Gui: fix memory leak in file browser module
* OFW: music_player: Return to browser instead of exiting on back button
* OFW: More correct elf loader
* OFW: Furi stream buffer
* OFW: Printf function attributes
* OFW: App name in CLI loader command, RFID data edit fix
* OFW: Show in-app icons & names in archive browser
* OFW: M*LIB: non-inlined strings, FuriString primitive
* OFW PR: Remove string_push_uint64 (OFW PR 1832 by Astrrra)
* OFW: Remove string_push_uint64
* OFW: Mifare Classic read improvements
* OFW PR: updated icon names (OFW PR 1829 by nminaylov)
#### [🎲 Download extra apps pack](https://download-directory.github.io/?url=https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed)
[-> How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
[-> How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
[-> Download qFlipper 1.2.0 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0/)
[-> Download qFlipper 1.2.1 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.1/)
## Please support development of the project
* ETH/BSC/ERC20-Tokens: `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`
@@ -28,5 +49,5 @@
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or download `.tgz` for iOS mobile app / qFlipper
Update using qFlipper (1.2.0) is now possible with `.tgz` update package! Also you can use Web Updater or self-update package.
Update using qFlipper (1.2.0+) is now possible with `.tgz` update package! Also you can use Web Updater or self-update package.

View File

@@ -1,5 +1,5 @@
<h3 align="center">
<a href="https://github.com/Eng1n33r/flipperzero-firmware">
<a href="https://github.com/DarkFlippers/unleashed-firmware">
<img src="https://user-images.githubusercontent.com/10697207/186202043-26947e28-b1cc-459a-8f20-ffcc7fc0c71c.png" align="center" alt="fzCUSTOM" border="0">
</a>
</h3>
@@ -62,12 +62,13 @@ Also check changelog in releases for latest updates!
### Community apps included:
- RFID Fuzzer plugin [(by Ganapati)](https://github.com/Eng1n33r/flipperzero-firmware/pull/54) with changes by @xMasterX & New protocols by @mvanzanten
- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/Eng1n33r/flipperzero-firmware/pull/57) & Refactored by @derskythe
- Sub-GHz playlist plugin [(by darmiel)](https://github.com/Eng1n33r/flipperzero-firmware/pull/62)
- RFID Fuzzer plugin [(by Ganapati)](https://github.com/DarkFlippers/unleashed-firmware/pull/54) with changes by @xMasterX & New protocols by @mvanzanten
- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/57) & Refactored by @derskythe
- Sub-GHz playlist plugin [(by darmiel)](https://github.com/DarkFlippers/unleashed-firmware/pull/62)
- 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 plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player)
- UPC-A Barcode generator plugin [(by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator)
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
@@ -88,30 +89,30 @@ Games:
### Other changes
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
- SubGHz -> New frequency analyzer - [(by ClusterM)](https://github.com/Eng1n33r/flipperzero-firmware/pull/43)
- SubGHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
- SubGHz -> Detect RAW feature - [(by perspecdev)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/152)
- SubGHz -> Save last used frequency and moduluation [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/77)
- SubGHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/77)
* SubGHz -> Long press OK button in SubGHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/79)
- SubGHz -> Save last used frequency and moduluation [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- SubGHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
* SubGHz -> Long press OK button in SubGHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
# Instructions
## [- How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
## [- How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
## [- How to build firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToBuild.md)
## [- How to build firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md)
## [- BadUSB: how to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl)
## [- How to change Flipper name](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/CustomFlipperName.md)
## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md)
### **Plugins**
## [- 🎲 Download Extra plugins for Unleashed](https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed)
## [- Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md)
## [- Barcode Generator](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
## [- Multi Converter](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/MultiConverter.md)
## [- Multi Converter](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md)
## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
@@ -119,7 +120,7 @@ Games:
### **Plugins that works with external hardware**
## [- How to use: [NRF24] plugins](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/NRF24.md)
## [- How to use: [NRF24] plugins](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md)
## [- How to use: [WiFi] Scanner](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module#readme)
@@ -133,13 +134,13 @@ Games:
## [- Windows: How to Upload .bin to ESP32/ESP8266](https://github.com/SequoiaSan/Guide-How-To-Upload-bin-to-ESP8266-ESP32)
## [- How to use: [GPIO] SentrySafe plugin](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SentrySafe.md)
## [- How to use: [GPIO] SentrySafe plugin](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md)
### **SubGHz**
## [- Transmission is blocked? - How to extend SubGHz frequency range](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/DangerousSettings.md)
## [- Transmission is blocked? - How to extend SubGHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
## [- How to add extra SubGHz frequencies](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzSettings.md)
## [- How to add extra SubGHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
<br>
<br>

View File

@@ -154,7 +154,9 @@ static bool bt_test_input_callback(InputEvent* event, void* context) {
void bt_test_process_up(BtTest* bt_test) {
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
uint8_t params_on_screen = 3;
if(model->position > 0) {
model->position--;
@@ -168,13 +170,15 @@ void bt_test_process_up(BtTest* bt_test) {
model->window_position = model->position - (params_on_screen - 1);
}
}
return true;
});
},
true);
}
void bt_test_process_down(BtTest* bt_test) {
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
uint8_t params_on_screen = 3;
if(model->position < (BtTestParamArray_size(model->params) - 1)) {
model->position++;
@@ -187,8 +191,8 @@ void bt_test_process_down(BtTest* bt_test) {
model->position = 0;
model->window_position = 0;
}
return true;
});
},
true);
}
BtTestParam* bt_test_get_selected_param(BtTestModel* model) {
@@ -213,7 +217,9 @@ BtTestParam* bt_test_get_selected_param(BtTestModel* model) {
void bt_test_process_left(BtTest* bt_test) {
BtTestParam* param;
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
param = bt_test_get_selected_param(model);
if(param->current_value_index > 0) {
param->current_value_index--;
@@ -225,8 +231,8 @@ void bt_test_process_left(BtTest* bt_test) {
model->packets_num_tx = 0;
}
}
return true;
});
},
true);
if(param->change_callback) {
param->change_callback(param);
}
@@ -235,7 +241,9 @@ void bt_test_process_left(BtTest* bt_test) {
void bt_test_process_right(BtTest* bt_test) {
BtTestParam* param;
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
param = bt_test_get_selected_param(model);
if(param->current_value_index < (param->values_count - 1)) {
param->current_value_index++;
@@ -247,8 +255,8 @@ void bt_test_process_right(BtTest* bt_test) {
model->packets_num_tx = 0;
}
}
return true;
});
},
true);
if(param->change_callback) {
param->change_callback(param);
}
@@ -257,7 +265,9 @@ void bt_test_process_right(BtTest* bt_test) {
void bt_test_process_ok(BtTest* bt_test) {
BtTestState state;
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
if(model->state == BtTestStateStarted) {
model->state = BtTestStateStopped;
model->message = BT_TEST_START_MESSAGE;
@@ -269,8 +279,8 @@ void bt_test_process_ok(BtTest* bt_test) {
model->message = BT_TEST_STOP_MESSAGE;
}
state = model->state;
return true;
});
},
true);
if(bt_test->change_state_callback) {
bt_test->change_state_callback(state, bt_test->context);
}
@@ -278,13 +288,15 @@ void bt_test_process_ok(BtTest* bt_test) {
void bt_test_process_back(BtTest* bt_test) {
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
model->state = BtTestStateStopped;
model->rssi = 0.0f;
model->packets_num_rx = 0;
model->packets_num_tx = 0;
return false;
});
},
false);
if(bt_test->back_callback) {
bt_test->back_callback(bt_test->context);
}
@@ -299,7 +311,9 @@ BtTest* bt_test_alloc() {
view_set_input_callback(bt_test->view, bt_test_input_callback);
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
model->state = BtTestStateStopped;
model->message = "Ok - Start";
BtTestParamArray_init(model->params);
@@ -308,8 +322,8 @@ BtTest* bt_test_alloc() {
model->rssi = 0.0f;
model->packets_num_tx = 0;
model->packets_num_rx = 0;
return true;
});
},
true);
return bt_test;
}
@@ -318,15 +332,17 @@ void bt_test_free(BtTest* bt_test) {
furi_assert(bt_test);
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
BtTestParamArray_it_t it;
for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it);
BtTestParamArray_next(it)) {
furi_string_free(BtTestParamArray_ref(it)->current_value_text);
}
BtTestParamArray_clear(model->params);
return false;
});
},
false);
view_free(bt_test->view);
free(bt_test);
}
@@ -347,7 +363,9 @@ BtTestParam* bt_test_param_add(
furi_assert(bt_test);
with_view_model(
bt_test->view, (BtTestModel * model) {
bt_test->view,
BtTestModel * model,
{
param = BtTestParamArray_push_new(model->params);
param->label = label;
param->values_count = values_count;
@@ -355,8 +373,8 @@ BtTestParam* bt_test_param_add(
param->context = context;
param->current_value_index = 0;
param->current_value_text = furi_string_alloc();
return true;
});
},
true);
return param;
}
@@ -364,28 +382,19 @@ BtTestParam* bt_test_param_add(
void bt_test_set_rssi(BtTest* bt_test, float rssi) {
furi_assert(bt_test);
with_view_model(
bt_test->view, (BtTestModel * model) {
model->rssi = rssi;
return true;
});
bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
}
void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) {
furi_assert(bt_test);
with_view_model(
bt_test->view, (BtTestModel * model) {
model->packets_num_tx = packets_num;
return true;
});
bt_test->view, BtTestModel * model, { model->packets_num_tx = packets_num; }, true);
}
void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num) {
furi_assert(bt_test);
with_view_model(
bt_test->view, (BtTestModel * model) {
model->packets_num_rx = packets_num;
return true;
});
bt_test->view, BtTestModel * model, { model->packets_num_rx = packets_num; }, true);
}
void bt_test_set_change_state_callback(BtTest* bt_test, BtTestChangeStateCallback callback) {

View File

@@ -110,7 +110,9 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) {
bool consumed = false;
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
with_view_model(
instance->view, (ViewDisplayTestModel * model) {
instance->view,
ViewDisplayTestModel * model,
{
if(event->key == InputKeyLeft && model->test > 0) {
model->test--;
consumed = true;
@@ -129,8 +131,8 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) {
model->flip_flop = !model->flip_flop;
consumed = true;
}
return consumed;
});
},
consumed);
}
return consumed;
@@ -149,10 +151,7 @@ static void view_display_test_exit(void* context) {
static void view_display_test_timer_callback(void* context) {
ViewDisplayTest* instance = context;
with_view_model(
instance->view, (ViewDisplayTestModel * model) {
model->counter++;
return true;
});
instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
}
ViewDisplayTest* view_display_test_alloc() {

View File

@@ -52,23 +52,29 @@ static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) {
static void lfrfid_debug_view_tune_button_up(LfRfidTuneView* tune_view) {
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
tune_view->view,
LfRfidTuneViewModel * model,
{
if(model->pos > 0) model->pos--;
return true;
});
},
true);
}
static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) {
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
tune_view->view,
LfRfidTuneViewModel * model,
{
if(model->pos < 1) model->pos++;
return true;
});
},
true);
}
static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) {
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
tune_view->view,
LfRfidTuneViewModel * model,
{
if(model->pos == 0) {
if(model->fine) {
model->ARR -= 1;
@@ -84,13 +90,15 @@ static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) {
}
model->dirty = true;
return true;
});
},
true);
}
static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) {
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
tune_view->view,
LfRfidTuneViewModel * model,
{
if(model->pos == 0) {
if(model->fine) {
model->ARR += 1;
@@ -106,16 +114,13 @@ static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) {
}
model->dirty = true;
return true;
});
},
true);
}
static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) {
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
model->fine = !model->fine;
return true;
});
tune_view->view, LfRfidTuneViewModel * model, { model->fine = !model->fine; }, true);
}
static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* context) {
@@ -158,14 +163,16 @@ LfRfidTuneView* lfrfid_debug_view_tune_alloc() {
view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel));
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
tune_view->view,
LfRfidTuneViewModel * model,
{
model->dirty = true;
model->fine = false;
model->ARR = 511;
model->CCR = 255;
model->pos = 0;
return true;
});
},
true);
view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback);
view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback);
@@ -184,24 +191,28 @@ View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view) {
void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) {
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
tune_view->view,
LfRfidTuneViewModel * model,
{
model->dirty = true;
model->fine = false;
model->ARR = 511;
model->CCR = 255;
model->pos = 0;
return true;
});
},
true);
}
bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) {
bool result = false;
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
tune_view->view,
LfRfidTuneViewModel * model,
{
result = model->dirty;
model->dirty = false;
return false;
});
},
false);
return result;
}
@@ -209,10 +220,7 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) {
uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) {
uint32_t result = false;
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
result = model->ARR;
return false;
});
tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
return result;
}
@@ -220,10 +228,7 @@ uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) {
uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) {
uint32_t result = false;
with_view_model(
tune_view->view, (LfRfidTuneViewModel * model) {
result = model->CCR;
return false;
});
tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
return result;
}

View File

@@ -159,21 +159,20 @@ static int32_t uart_echo_worker(void* context) {
if(length > 0) {
furi_hal_uart_tx(FuriHalUartIdUSART1, data, length);
with_view_model(
app->view, (UartDumpModel * model) {
app->view,
UartDumpModel * model,
{
for(size_t i = 0; i < length; i++) {
uart_echo_push_to_list(model, data[i]);
}
return false;
});
},
false);
}
} while(length > 0);
notification_message(app->notification, &sequence_notification);
with_view_model(
app->view, (UartDumpModel * model) {
UNUSED(model);
return true;
});
app->view, UartDumpModel * model, { UNUSED(model); }, true);
}
}
@@ -200,15 +199,17 @@ static UartEchoApp* uart_echo_app_alloc() {
view_set_input_callback(app->view, uart_echo_view_input_callback);
view_allocate_model(app->view, ViewModelTypeLocking, sizeof(UartDumpModel));
with_view_model(
app->view, (UartDumpModel * model) {
app->view,
UartDumpModel * model,
{
for(size_t i = 0; i < LINES_ON_SCREEN; i++) {
model->line = 0;
model->escape = false;
model->list[i] = malloc(sizeof(ListElement));
model->list[i]->text = furi_string_alloc();
}
return true;
});
},
true);
view_set_previous_callback(app->view, uart_echo_exit);
view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
@@ -242,13 +243,15 @@ static void uart_echo_app_free(UartEchoApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, 0);
with_view_model(
app->view, (UartDumpModel * model) {
app->view,
UartDumpModel * model,
{
for(size_t i = 0; i < LINES_ON_SCREEN; i++) {
furi_string_free(model->list[i]->text);
free(model->list[i]);
}
return true;
});
},
true);
view_free(app->view);
view_dispatcher_free(app->view_dispatcher);

View File

@@ -1,12 +1,12 @@
App(
appid="USB_Mouse",
name="USB Mouse",
apptype=FlipperAppType.PLUGIN,
apptype=FlipperAppType.DEBUG,
entry_point="usb_mouse_app",
cdefines=["APP_USB_MOUSE"],
requires=["gui"],
stack_size=1 * 1024,
order=60,
fap_icon="../../plugins/mousejacker/mouse_10px.png",
fap_category="Misc",
fap_category="Debug",
)

View File

@@ -21,7 +21,9 @@ static void
archive_switch_tab(browser, browser->last_tab_switch_dir);
} else if(!furi_string_start_with_str(browser->path, "/app:")) {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
files_array_reset(model->files);
model->item_cnt = item_cnt;
model->item_idx = (file_idx > 0) ? file_idx : 0;
@@ -31,8 +33,8 @@ static void
model->list_offset = 0;
model->list_loading = true;
model->folder_loading = false;
return false;
});
},
false);
archive_update_offset(browser);
file_browser_worker_load(browser->worker, load_offset, FILE_LIST_BUF_LEN);
@@ -44,11 +46,13 @@ static void archive_list_load_cb(void* context, uint32_t list_load_offset) {
ArchiveBrowserView* browser = (ArchiveBrowserView*)context;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
files_array_reset(model->files);
model->array_offset = list_load_offset;
return false;
});
},
false);
}
static void
@@ -60,10 +64,7 @@ static void
archive_add_file_item(browser, is_folder, furi_string_get_cstr(item_path));
} else {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
model->list_loading = false;
return true;
});
browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true);
}
}
@@ -72,10 +73,7 @@ static void archive_long_load_cb(void* context) {
ArchiveBrowserView* browser = (ArchiveBrowserView*)context;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
model->folder_loading = true;
return true;
});
browser->view, ArchiveBrowserViewModel * model, { model->folder_loading = true; }, true);
}
static void archive_file_browser_set_path(
@@ -113,7 +111,9 @@ void archive_update_offset(ArchiveBrowserView* browser) {
furi_assert(browser);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
uint16_t bounds = model->item_cnt > 3 ? 2 : model->item_cnt;
if((model->item_cnt > 3u) && (model->item_idx >= ((int32_t)model->item_cnt - 1))) {
@@ -125,9 +125,8 @@ void archive_update_offset(ArchiveBrowserView* browser) {
model->list_offset =
CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0);
}
return true;
});
},
true);
}
void archive_update_focus(ArchiveBrowserView* browser, const char* target) {
@@ -140,7 +139,9 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) {
archive_switch_tab(browser, TAB_RIGHT);
} else {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
uint16_t idx = 0;
while(idx < files_array_size(model->files)) {
ArchiveFile_t* current = files_array_get(model->files, idx);
@@ -150,8 +151,8 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) {
}
++idx;
}
return false;
});
},
false);
archive_update_offset(browser);
}
@@ -162,10 +163,10 @@ size_t archive_file_get_array_size(ArchiveBrowserView* browser) {
uint16_t size = 0;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
size = files_array_size(model->files);
return false;
});
browser->view,
ArchiveBrowserViewModel * model,
{ size = files_array_size(model->files); },
false);
return size;
}
@@ -173,11 +174,13 @@ void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count) {
furi_assert(browser);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
model->item_cnt = count;
model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0);
return false;
});
},
false);
archive_update_offset(browser);
}
@@ -186,7 +189,9 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) {
uint32_t items_cnt = 0;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
files_array_remove_v(
model->files,
model->item_idx - model->array_offset,
@@ -194,8 +199,8 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) {
model->item_cnt--;
model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0);
items_cnt = model->item_cnt;
return false;
});
},
false);
if((items_cnt == 0) && (archive_is_home(browser))) {
archive_switch_tab(browser, TAB_RIGHT);
@@ -208,7 +213,9 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) {
furi_assert(browser);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
ArchiveFile_t temp;
size_t array_size = files_array_size(model->files) - 1;
uint8_t swap_idx = CLAMP((size_t)(model->item_idx + dir), array_size, 0u);
@@ -226,18 +233,18 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) {
} else {
files_array_swap_at(model->files, model->item_idx, swap_idx);
}
return false;
});
},
false);
}
void archive_file_array_rm_all(ArchiveBrowserView* browser) {
furi_assert(browser);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
files_array_reset(model->files);
return false;
});
browser->view,
ArchiveBrowserViewModel * model,
{ files_array_reset(model->files); },
false);
}
void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
@@ -246,7 +253,9 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
int32_t offset_new = 0;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
if(model->item_cnt > FILE_LIST_BUF_LEN) {
if(dir < 0) {
offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 3;
@@ -262,8 +271,8 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
offset_new = 0;
}
}
return false;
});
},
false);
file_browser_worker_load(browser->worker, offset_new, FILE_LIST_BUF_LEN);
}
@@ -273,12 +282,14 @@ ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) {
ArchiveFile_t* selected = NULL;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
selected = files_array_size(model->files) ?
files_array_get(model->files, model->item_idx - model->array_offset) :
NULL;
return false;
});
},
false);
return selected;
}
@@ -288,11 +299,13 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) {
ArchiveFile_t* selected = NULL;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
idx = CLAMP(idx - model->array_offset, files_array_size(model->files), 0u);
selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL;
return false;
});
},
false);
return selected;
}
@@ -301,10 +314,7 @@ ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) {
ArchiveTabEnum tab_id = 0;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
tab_id = model->tab_idx;
return false;
});
browser->view, ArchiveBrowserViewModel * model, { tab_id = model->tab_idx; }, false);
return tab_id;
}
@@ -328,10 +338,7 @@ void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) {
furi_assert(browser);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
model->tab_idx = tab;
return false;
});
browser->view, ArchiveBrowserViewModel * model, { model->tab_idx = tab; }, false);
}
void archive_add_app_item(ArchiveBrowserView* browser, const char* name) {
@@ -344,11 +351,13 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) {
archive_set_file_type(&item, name, false, true);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
files_array_push_back(model->files, item);
model->item_cnt = files_array_size(model->files);
return false;
});
},
false);
ArchiveFile_t_clear(&item);
}
@@ -379,17 +388,19 @@ void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const ch
}
}
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
files_array_push_back(model->files, item);
return false;
});
browser->view,
ArchiveBrowserViewModel * model,
{ files_array_push_back(model->files, item); },
false);
ArchiveFile_t_clear(&item);
}
void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
furi_assert(browser);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
if(show) {
if(archive_is_item_in_array(model, model->item_idx)) {
model->menu = true;
@@ -404,19 +415,15 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
model->menu = false;
model->menu_idx = 0;
}
return true;
});
},
true);
}
void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) {
furi_assert(browser);
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
model->move_fav = active;
return true;
});
browser->view, ArchiveBrowserViewModel * model, { model->move_fav = active; }, true);
}
static bool archive_is_dir_exists(FuriString* path) {
@@ -477,11 +484,13 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
archive_switch_tab(browser, key);
} else {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
model->item_idx = 0;
model->array_offset = 0;
return false;
});
},
false);
archive_get_items(browser, furi_string_get_cstr(browser->path));
archive_update_offset(browser);
}
@@ -494,10 +503,7 @@ void archive_enter_dir(ArchiveBrowserView* browser, FuriString* path) {
int32_t idx_temp = 0;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
idx_temp = model->item_idx;
return false;
});
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);
@@ -515,9 +521,6 @@ void archive_refresh_dir(ArchiveBrowserView* browser) {
int32_t idx_temp = 0;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
idx_temp = model->item_idx;
return false;
});
browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false);
file_browser_worker_folder_refresh(browser->worker, idx_temp);
}

View File

@@ -358,11 +358,13 @@ static bool archive_view_input(InputEvent* event, void* context) {
bool in_menu;
bool move_fav_mode;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
in_menu = model->menu;
move_fav_mode = model->move_fav;
return false;
});
},
false);
if(in_menu) {
if(event->type != InputTypeShort) {
@@ -370,24 +372,28 @@ static bool archive_view_input(InputEvent* event, void* context) {
}
if(event->key == InputKeyUp || event->key == InputKeyDown) {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
size_t size_menu = menu_array_size(model->context_menu);
if(event->key == InputKeyUp) {
model->menu_idx = ((model->menu_idx - 1) + size_menu) % size_menu;
} else if(event->key == InputKeyDown) {
model->menu_idx = (model->menu_idx + 1) % size_menu;
}
return true;
});
},
true);
} else if(event->key == InputKeyOk) {
uint32_t idx;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
ArchiveContextMenuItem_t* current =
menu_array_get(model->context_menu, model->menu_idx);
idx = current->event;
return false;
});
},
false);
browser->callback(idx, browser->context);
} else if(event->key == InputKeyBack) {
browser->callback(ArchiveBrowserEventFileMenuClose, browser->context);
@@ -409,7 +415,9 @@ static bool archive_view_input(InputEvent* event, void* context) {
if((event->key == InputKeyUp || event->key == InputKeyDown) &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
if(event->key == InputKeyUp) {
model->item_idx =
((model->item_idx - 1) + model->item_cnt) % model->item_cnt;
@@ -430,9 +438,8 @@ static bool archive_view_input(InputEvent* event, void* context) {
browser->callback(ArchiveBrowserEventFavMoveDown, browser->context);
}
}
return true;
});
},
true);
archive_update_offset(browser);
}
@@ -480,12 +487,14 @@ ArchiveBrowserView* browser_alloc() {
browser->path = furi_string_alloc_set(archive_get_default_path(TAB_DEFAULT));
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
files_array_init(model->files);
menu_array_init(model->context_menu);
model->tab_idx = TAB_DEFAULT;
return true;
});
},
true);
return browser;
}
@@ -498,11 +507,13 @@ void browser_free(ArchiveBrowserView* browser) {
}
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser->view,
ArchiveBrowserViewModel * model,
{
files_array_clear(model->files);
menu_array_clear(model->context_menu);
return false;
});
},
false);
furi_string_free(browser->path);

View File

@@ -113,6 +113,7 @@ 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_repeat[] = {"REPEAT "};
static const char ducky_cmd_sysrq[] = {"SYSRQ "};
static const char ducky_cmd_altchar[] = {"ALTCHAR "};
static const char ducky_cmd_altstr_1[] = {"ALTSTRING "};
@@ -301,6 +302,14 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) {
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt);
return (state) ? (0) : SCRIPT_STATE_ERROR;
} else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) {
// SYSRQ
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true);
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release_all();
return (0);
} else {
// Special keys + modifiers
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false);

View File

@@ -166,37 +166,41 @@ void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback,
furi_assert(bad_usb);
furi_assert(callback);
with_view_model(
bad_usb->view, (BadUsbModel * model) {
bad_usb->view,
BadUsbModel * model,
{
UNUSED(model);
bad_usb->callback = callback;
bad_usb->context = context;
return true;
});
},
true);
}
void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
furi_assert(name);
with_view_model(
bad_usb->view, (BadUsbModel * model) {
strlcpy(model->file_name, name, MAX_NAME_LEN);
return true;
});
bad_usb->view,
BadUsbModel * model,
{ strlcpy(model->file_name, name, MAX_NAME_LEN); },
true);
}
void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
furi_assert(layout);
with_view_model(
bad_usb->view, (BadUsbModel * model) {
strlcpy(model->layout, layout, MAX_NAME_LEN);
return true;
});
bad_usb->view,
BadUsbModel * model,
{ strlcpy(model->layout, layout, MAX_NAME_LEN); },
true);
}
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
furi_assert(st);
with_view_model(
bad_usb->view, (BadUsbModel * model) {
bad_usb->view,
BadUsbModel * model,
{
memcpy(&(model->state), st, sizeof(BadUsbState));
model->anim_frame ^= 1;
return true;
});
},
true);
}

View File

@@ -182,6 +182,7 @@ int32_t fap_loader_app(void* p) {
FapLoader* loader;
if(p) {
loader = fap_loader_alloc((const char*)p);
view_dispatcher_switch_to_view(loader->view_dispatcher, 0);
fap_loader_run_selected_app(loader);
} else {
loader = fap_loader_alloc(EXT_PATH("apps"));

View File

@@ -48,23 +48,27 @@ static bool gpio_test_input_callback(InputEvent* event, void* context) {
static bool gpio_test_process_left(GpioTest* gpio_test) {
with_view_model(
gpio_test->view, (GpioTestModel * model) {
gpio_test->view,
GpioTestModel * model,
{
if(model->pin_idx) {
model->pin_idx--;
}
return true;
});
},
true);
return true;
}
static bool gpio_test_process_right(GpioTest* gpio_test) {
with_view_model(
gpio_test->view, (GpioTestModel * model) {
gpio_test->view,
GpioTestModel * model,
{
if(model->pin_idx < GPIO_ITEM_COUNT) {
model->pin_idx++;
}
return true;
});
},
true);
return true;
}
@@ -72,7 +76,9 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
bool consumed = false;
with_view_model(
gpio_test->view, (GpioTestModel * model) {
gpio_test->view,
GpioTestModel * model,
{
if(event->type == InputTypePress) {
if(model->pin_idx < GPIO_ITEM_COUNT) {
gpio_item_set_pin(model->pin_idx, true);
@@ -89,8 +95,8 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
consumed = true;
}
gpio_test->callback(event->type, gpio_test->context);
return true;
});
},
true);
return consumed;
}
@@ -122,10 +128,12 @@ void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback,
furi_assert(gpio_test);
furi_assert(callback);
with_view_model(
gpio_test->view, (GpioTestModel * model) {
gpio_test->view,
GpioTestModel * model,
{
UNUSED(model);
gpio_test->callback = callback;
gpio_test->context = context;
return false;
});
},
false);
}

View File

@@ -129,12 +129,14 @@ void gpio_usb_uart_set_callback(GpioUsbUart* usb_uart, GpioUsbUartCallback callb
furi_assert(callback);
with_view_model(
usb_uart->view, (GpioUsbUartModel * model) {
usb_uart->view,
GpioUsbUartModel * model,
{
UNUSED(model);
usb_uart->callback = callback;
usb_uart->context = context;
return false;
});
},
false);
}
void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUartState* st) {
@@ -143,7 +145,9 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa
furi_assert(st);
with_view_model(
instance->view, (GpioUsbUartModel * model) {
instance->view,
GpioUsbUartModel * model,
{
model->baudrate = st->baudrate_cur;
model->vcp_port = cfg->vcp_ch;
model->tx_pin = (cfg->uart_ch == 0) ? (13) : (15);
@@ -152,6 +156,6 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa
model->rx_active = (model->rx_cnt != st->rx_cnt);
model->tx_cnt = st->tx_cnt;
model->rx_cnt = st->rx_cnt;
return true;
});
},
true);
}

View File

@@ -56,19 +56,13 @@ static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) {
void lfrfid_view_read_enter(void* context) {
LfRfidReadView* read_view = context;
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
icon_animation_start(model->icon);
return true;
});
read_view->view, LfRfidReadViewModel * model, { icon_animation_start(model->icon); }, true);
}
void lfrfid_view_read_exit(void* context) {
LfRfidReadView* read_view = context;
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
icon_animation_stop(model->icon);
return false;
});
read_view->view, LfRfidReadViewModel * model, { icon_animation_stop(model->icon); }, false);
}
LfRfidReadView* lfrfid_view_read_alloc() {
@@ -78,11 +72,13 @@ LfRfidReadView* lfrfid_view_read_alloc() {
view_allocate_model(read_view->view, ViewModelTypeLocking, sizeof(LfRfidReadViewModel));
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
read_view->view,
LfRfidReadViewModel * model,
{
model->icon = icon_animation_alloc(&A_Round_loader_8x8);
view_tie_icon_animation(read_view->view, model->icon);
return false;
});
},
false);
view_set_draw_callback(read_view->view, lfrfid_view_read_draw_callback);
view_set_enter_callback(read_view->view, lfrfid_view_read_enter);
@@ -93,10 +89,7 @@ LfRfidReadView* lfrfid_view_read_alloc() {
void lfrfid_view_read_free(LfRfidReadView* read_view) {
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
icon_animation_free(model->icon);
return false;
});
read_view->view, LfRfidReadViewModel * model, { icon_animation_free(model->icon); }, false);
view_free(read_view->view);
free(read_view);
@@ -108,10 +101,12 @@ View* lfrfid_view_read_get_view(LfRfidReadView* read_view) {
void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode) {
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
read_view->view,
LfRfidReadViewModel * model,
{
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
model->read_mode = mode;
return true;
});
},
true);
}

View File

@@ -64,10 +64,7 @@ static bool detect_reader_input_callback(InputEvent* event, void* context) {
uint8_t nonces = 0;
with_view_model(
detect_reader->view, (DetectReaderViewModel * model) {
nonces = model->nonces;
return false;
});
detect_reader->view, DetectReaderViewModel * model, { nonces = model->nonces; }, false);
if(event->type == InputTypeShort) {
if(event->key == InputKeyOk) {
@@ -103,12 +100,14 @@ void detect_reader_reset(DetectReader* detect_reader) {
furi_assert(detect_reader);
with_view_model(
detect_reader->view, (DetectReaderViewModel * model) {
detect_reader->view,
DetectReaderViewModel * model,
{
model->nonces = 0;
model->nonces_max = 0;
model->state = DetectReaderStateStart;
return false;
});
},
false);
}
View* detect_reader_get_view(DetectReader* detect_reader) {
@@ -132,27 +131,24 @@ void detect_reader_set_nonces_max(DetectReader* detect_reader, uint16_t nonces_m
furi_assert(detect_reader);
with_view_model(
detect_reader->view, (DetectReaderViewModel * model) {
model->nonces_max = nonces_max;
return false;
});
detect_reader->view,
DetectReaderViewModel * model,
{ model->nonces_max = nonces_max; },
false);
}
void detect_reader_set_nonces_collected(DetectReader* detect_reader, uint16_t nonces_collected) {
furi_assert(detect_reader);
with_view_model(
detect_reader->view, (DetectReaderViewModel * model) {
model->nonces = nonces_collected;
return false;
});
detect_reader->view,
DetectReaderViewModel * model,
{ model->nonces = nonces_collected; },
false);
}
void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState state) {
furi_assert(detect_reader);
with_view_model(
detect_reader->view, (DetectReaderViewModel * model) {
model->state = state;
return true;
});
detect_reader->view, DetectReaderViewModel * model, { model->state = state; }, true);
}

View File

@@ -80,20 +80,20 @@ DictAttack* dict_attack_alloc() {
view_set_input_callback(dict_attack->view, dict_attack_input_callback);
view_set_context(dict_attack->view, dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
model->header = furi_string_alloc();
return false;
});
dict_attack->view,
DictAttackViewModel * model,
{ model->header = furi_string_alloc(); },
false);
return dict_attack;
}
void dict_attack_free(DictAttack* dict_attack) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
furi_string_free(model->header);
return false;
});
dict_attack->view,
DictAttackViewModel * model,
{ furi_string_free(model->header); },
false);
view_free(dict_attack->view);
free(dict_attack);
}
@@ -101,7 +101,9 @@ void dict_attack_free(DictAttack* dict_attack) {
void dict_attack_reset(DictAttack* dict_attack) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
dict_attack->view,
DictAttackViewModel * model,
{
model->state = DictAttackStateRead;
model->type = MfClassicType1k;
model->sectors_total = 0;
@@ -112,8 +114,8 @@ void dict_attack_reset(DictAttack* dict_attack) {
model->dict_keys_total = 0;
model->dict_keys_current = 0;
furi_string_reset(model->header);
return false;
});
},
false);
}
View* dict_attack_get_view(DictAttack* dict_attack) {
@@ -133,99 +135,103 @@ void dict_attack_set_header(DictAttack* dict_attack, const char* header) {
furi_assert(header);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
furi_string_set(model->header, header);
return true;
});
dict_attack->view,
DictAttackViewModel * model,
{ furi_string_set(model->header, header); },
true);
}
void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
dict_attack->view,
DictAttackViewModel * model,
{
model->state = DictAttackStateRead;
model->sectors_total = mf_classic_get_total_sectors_num(type);
model->keys_total = model->sectors_total * 2;
return true;
});
},
true);
}
void dict_attack_set_card_removed(DictAttack* dict_attack) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
model->state = DictAttackStateCardRemoved;
return true;
});
dict_attack->view,
DictAttackViewModel * model,
{ model->state = DictAttackStateCardRemoved; },
true);
}
void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
model->sectors_read = sec_read;
return true;
});
dict_attack->view, DictAttackViewModel * model, { model->sectors_read = sec_read; }, true);
}
void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
model->keys_found = keys_found;
return true;
});
dict_attack->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true);
}
void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
dict_attack->view,
DictAttackViewModel * model,
{
model->sector_current = curr_sec;
model->dict_keys_current = 0;
return true;
});
},
true);
}
void dict_attack_inc_current_sector(DictAttack* dict_attack) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
dict_attack->view,
DictAttackViewModel * model,
{
if(model->sector_current < model->sectors_total) {
model->sector_current++;
model->dict_keys_current = 0;
}
return true;
});
},
true);
}
void dict_attack_inc_keys_found(DictAttack* dict_attack) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
dict_attack->view,
DictAttackViewModel * model,
{
if(model->keys_found < model->keys_total) {
model->keys_found++;
}
return true;
});
},
true);
}
void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
model->dict_keys_total = dict_keys_total;
return true;
});
dict_attack->view,
DictAttackViewModel * model,
{ model->dict_keys_total = dict_keys_total; },
true);
}
void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
dict_attack->view,
DictAttackViewModel * model,
{
if(model->dict_keys_current + keys_tried < model->dict_keys_total) {
model->dict_keys_current += keys_tried;
}
return true;
});
},
true);
}

View File

@@ -167,6 +167,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
subghz_sleep(subghz);
}
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz_history_set_hopper_state(subghz->txrx->history, false);
subghz->txrx->idx_menu_chosen = 0;
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);

View File

@@ -189,64 +189,64 @@ static void subghz_scene_receiver_config_set_detect_raw(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(subghz->txrx->hopper_state == 0) {
variable_item_set_current_value_text(item, detect_raw_text[index]);
//if(subghz->txrx->hopper_state == 0) {
variable_item_set_current_value_text(item, detect_raw_text[index]);
#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING
subghz->last_settings->detect_raw = index;
subghz->last_settings->detect_raw = index;
subghz_last_settings_set_detect_raw_values(subghz);
subghz_last_settings_set_detect_raw_values(subghz);
#else
subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]);
subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]);
subghz_protocol_decoder_raw_set_auto_mode(
subghz_receiver_search_decoder_base_by_name(
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
(index == 1));
subghz_protocol_decoder_raw_set_auto_mode(
subghz_receiver_search_decoder_base_by_name(
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
(index == 1));
#endif
} else {
/*} else {
variable_item_set_current_value_index(item, 0);
}
}*/
}
static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(subghz_receiver_get_filter(subghz->txrx->receiver) == SubGhzProtocolFlag_Decodable) {
variable_item_set_current_value_text(item, hopping_text[index]);
if(hopping_value[index] == SubGhzHopperStateOFF) {
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_default_frequency(subghz->setting) / 1000000,
(subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000);
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
text_buf);
subghz->txrx->preset->frequency =
subghz_setting_get_default_frequency(subghz->setting);
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_setting_get_frequency_default_index(subghz->setting));
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
" -----");
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_setting_get_frequency_default_index(subghz->setting));
}
subghz->txrx->hopper_state = hopping_value[index];
//if(subghz_receiver_get_filter(subghz->txrx->receiver) == SubGhzProtocolFlag_Decodable) {
variable_item_set_current_value_text(item, hopping_text[index]);
if(hopping_value[index] == SubGhzHopperStateOFF) {
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_default_frequency(subghz->setting) / 1000000,
(subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000);
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
text_buf);
subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting);
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_setting_get_frequency_default_index(subghz->setting));
} else {
variable_item_set_current_value_index(item, 0);
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
" -----");
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_setting_get_frequency_default_index(subghz->setting));
}
subghz->txrx->hopper_state = hopping_value[index];
subghz_history_set_hopper_state(subghz->txrx->history, (index == 1));
/*} else {
variable_item_set_current_value_index(item, 0);
}*/
}
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {

View File

@@ -3,7 +3,7 @@
#include <lib/subghz/receiver.h>
#include <flipper_format/flipper_format_i.h>
#define SUBGHZ_HISTORY_MAX 65
#define SUBGHZ_HISTORY_MAX 60
/**
* @brief Settings for temporary files
@@ -41,6 +41,7 @@ struct SubGhzHistory {
uint8_t code_last_hash_data;
FuriString* tmp_string;
bool write_tmp_files;
bool is_hopper_running;
Storage* storage;
SubGhzHistoryStruct* history;
};
@@ -134,6 +135,8 @@ SubGhzHistory* subghz_history_alloc(void) {
instance->storage = furi_record_open(RECORD_STORAGE);
instance->write_tmp_files = subghz_history_check_sdcard(instance);
instance->is_hopper_running = false;
if(!instance->write_tmp_files) {
FURI_LOG_E(TAG, "Unstable work! Cannot use SD Card!");
}
@@ -209,6 +212,12 @@ void subghz_history_reset(SubGhzHistory* instance) {
instance->code_last_hash_data = 0;
}
void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state) {
furi_assert(instance);
instance->is_hopper_running = hopper_state;
}
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
furi_assert(instance);
return instance->last_index_write;
@@ -354,16 +363,23 @@ bool subghz_history_add_to_history(
item->protocol_name, "%s", furi_string_get_cstr(instance->tmp_string));
}
if(!strcmp(furi_string_get_cstr(instance->tmp_string), "RAW")) {
// Check if hopper enabled we need to add little delay
if(instance->is_hopper_running) {
furi_delay_ms(40);
}
// Enable writing temp files to micro sd
tmp_file_for_raw = true;
// Write display name
furi_string_printf(
item->item_str,
"RAW %03ld.%02ld",
preset->frequency / 1000000 % 1000,
preset->frequency / 10000 % 100);
// Rewind
if(!flipper_format_rewind(item->flipper_string)) {
FURI_LOG_E(TAG, "Rewind error");
}
tmp_file_for_raw = true;
break;
} else if(!strcmp(furi_string_get_cstr(instance->tmp_string), "KeeLoq")) {
furi_string_set(instance->tmp_string, "KL ");

View File

@@ -103,3 +103,10 @@ bool subghz_history_add_to_history(
* @return SubGhzProtocolCommonLoad*
*/
FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
/** Set hopper state for internal usage in history
*
* @param instance - SubGhzHistory instance
* @param hopper_state - bool is hopper running?
*/
void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state);

View File

@@ -68,10 +68,7 @@ void subghz_view_receiver_set_mode(
SubGhzViewReceiver* subghz_receiver,
SubGhzViewReceiverMode mode) {
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
model->mode = mode;
return true;
});
subghz_receiver->view, SubGhzViewReceiverModel * model, { model->mode = mode; }, true);
}
void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) {
@@ -80,17 +77,17 @@ void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLo
if(lock == SubGhzLockOn) {
subghz_receiver->lock = lock;
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
model->bar_show = SubGhzViewReceiverBarShowLock;
return true;
});
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{ model->bar_show = SubGhzViewReceiverBarShowLock; },
true);
furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(1000));
} else {
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
model->bar_show = SubGhzViewReceiverBarShowDefault;
return true;
});
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{ model->bar_show = SubGhzViewReceiverBarShowDefault; },
true);
}
}
@@ -108,7 +105,9 @@ static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiv
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
size_t history_item = model->history_item;
uint16_t bounds = history_item > 3 ? 2 : history_item;
@@ -120,8 +119,8 @@ static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiv
} else if(model->list_offset > model->idx - bounds) {
model->list_offset = CLAMP(model->idx - 1, (int16_t)(history_item - bounds), 0);
}
return true;
});
},
true);
}
void subghz_view_receiver_add_item_to_menu(
@@ -130,7 +129,9 @@ void subghz_view_receiver_add_item_to_menu(
uint8_t type) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
SubGhzReceiverMenuItem* item_menu =
SubGhzReceiverMenuItemArray_push_raw(model->history->data);
item_menu->item_str = furi_string_alloc_set(name);
@@ -141,9 +142,8 @@ void subghz_view_receiver_add_item_to_menu(
} else {
model->history_item++;
}
return true;
});
},
true);
subghz_view_receiver_update_offset(subghz_receiver);
}
@@ -154,12 +154,14 @@ void subghz_view_receiver_add_data_statusbar(
const char* history_stat_str) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
furi_string_set(model->frequency_str, frequency_str);
furi_string_set(model->preset_str, preset_str);
furi_string_set(model->history_stat_str, history_stat_str);
return true;
});
},
true);
}
void subghz_view_receiver_add_data_progress(
@@ -167,10 +169,10 @@ void subghz_view_receiver_add_data_progress(
const char* progress_str) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
furi_string_set(model->progress_str, progress_str);
return true;
});
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{ furi_string_set(model->progress_str, progress_str); },
true);
}
static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
@@ -275,10 +277,10 @@ static void subghz_view_receiver_timer_callback(void* context) {
furi_assert(context);
SubGhzViewReceiver* subghz_receiver = context;
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
model->bar_show = SubGhzViewReceiverBarShowDefault;
return true;
});
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{ model->bar_show = SubGhzViewReceiverBarShowDefault; },
true);
if(subghz_receiver->lock_count < UNLOCK_CNT) {
subghz_receiver->callback(
SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context);
@@ -295,10 +297,10 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
if(subghz_receiver->lock == SubGhzLockOn) {
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
model->bar_show = SubGhzViewReceiverBarShowToUnlockPress;
return true;
});
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{ model->bar_show = SubGhzViewReceiverBarShowToUnlockPress; },
true);
if(subghz_receiver->lock_count == 0) {
furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(1000));
}
@@ -309,10 +311,10 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
// subghz_receiver->callback(
// SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
model->bar_show = SubGhzViewReceiverBarShowUnlock;
return true;
});
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{ model->bar_show = SubGhzViewReceiverBarShowUnlock; },
true);
//subghz_receiver->lock = SubGhzLockOff;
furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650));
}
@@ -326,29 +328,35 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
event->key == InputKeyUp &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
if(model->idx != 0) model->idx--;
return true;
});
},
true);
} else if(
event->key == InputKeyDown &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
if(model->idx != model->history_item - 1) model->idx++;
return true;
});
},
true);
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
if(model->history_item != 0) {
subghz_receiver->callback(
SubGhzCustomEventViewReceiverOK, subghz_receiver->context);
}
return false;
});
},
false);
}
subghz_view_receiver_update_offset(subghz_receiver);
@@ -364,7 +372,9 @@ void subghz_view_receiver_exit(void* context) {
furi_assert(context);
SubGhzViewReceiver* subghz_receiver = context;
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
furi_string_reset(model->frequency_str);
furi_string_reset(model->preset_str);
furi_string_reset(model->history_stat_str);
@@ -378,8 +388,8 @@ void subghz_view_receiver_exit(void* context) {
model->idx = 0;
model->list_offset = 0;
model->history_item = 0;
return false;
});
},
false);
furi_timer_stop(subghz_receiver->timer);
}
@@ -400,7 +410,9 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
view_set_exit_callback(subghz_receiver->view, subghz_view_receiver_exit);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->history_stat_str = furi_string_alloc();
@@ -408,8 +420,8 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
model->bar_show = SubGhzViewReceiverBarShowDefault;
model->history = malloc(sizeof(SubGhzReceiverHistory));
SubGhzReceiverMenuItemArray_init(model->history->data);
return true;
});
},
true);
subghz_receiver->timer =
furi_timer_alloc(subghz_view_receiver_timer_callback, FuriTimerTypeOnce, subghz_receiver);
return subghz_receiver;
@@ -419,7 +431,9 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->history_stat_str);
@@ -431,8 +445,8 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) {
}
SubGhzReceiverMenuItemArray_clear(model->history->data);
free(model->history);
return false;
});
},
false);
furi_timer_free(subghz_receiver->timer);
view_free(subghz_receiver->view);
free(subghz_receiver);
@@ -447,20 +461,19 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver)
furi_assert(subghz_receiver);
uint32_t idx = 0;
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
idx = model->idx;
return false;
});
subghz_receiver->view, SubGhzViewReceiverModel * model, { idx = model->idx; }, false);
return idx;
}
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubGhzViewReceiverModel * model) {
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
model->idx = idx;
if(model->idx > 2) model->list_offset = idx - 2;
return true;
});
},
true);
subghz_view_receiver_update_offset(subghz_receiver);
}

View File

@@ -277,7 +277,9 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
if(event->key == InputKeyOk) {
bool updated = false;
with_view_model(
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{
uint32_t prev_freq_to_save = model->frequency_to_save;
uint32_t frequency_candidate = 0;
if(model->frequency != 0) {
@@ -305,8 +307,8 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
notification_message(instance->notifications, &sequence_hw_blink);
updated = true;
}
return true;
});
},
true);
#ifdef FURI_DEBUG
FURI_LOG_I(
@@ -340,14 +342,16 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
if(need_redraw) {
SubGhzFrequencyAnalyzer* instance = context;
with_view_model(
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{
model->rssi_last = instance->rssi_last;
model->frequency_last = instance->frequency_last;
model->trigger =
subghz_frequency_analyzer_worker_get_trigger_level(instance->worker);
model->feedback_level = instance->feedback_level;
return true;
});
},
true);
}
return true;
@@ -406,15 +410,17 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency,
instance->locked = (rssi != 0.f);
with_view_model(
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{
model->rssi = rssi;
model->rssi_last = instance->rssi_last;
model->frequency = frequency;
model->frequency_last = instance->frequency_last_vis;
model->trigger = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker);
model->feedback_level = instance->feedback_level;
return true;
});
},
true);
}
void subghz_frequency_analyzer_enter(void* context) {
@@ -441,15 +447,17 @@ void subghz_frequency_analyzer_enter(void* context) {
subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, RSSI_MIN);
with_view_model(
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{
model->rssi = 0;
model->rssi_last = 0;
model->frequency = 0;
model->frequency_last = 0;
model->frequency_to_save = 0;
model->trigger = RSSI_MIN;
return true;
});
},
true);
}
void subghz_frequency_analyzer_exit(void* context) {
@@ -503,10 +511,10 @@ uint32_t subghz_frequency_analyzer_get_frequency_to_save(SubGhzFrequencyAnalyzer
furi_assert(instance);
uint32_t frequency;
with_view_model(
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
frequency = model->frequency_to_save;
return false;
});
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{ frequency = model->frequency_to_save; },
false);
return frequency;
}

View File

@@ -46,11 +46,13 @@ void subghz_read_raw_add_data_statusbar(
const char* preset_str) {
furi_assert(instance);
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
furi_string_set(model->frequency_str, frequency_str);
furi_string_set(model->preset_str, preset_str);
return true;
});
},
true);
}
void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi) {
@@ -64,31 +66,35 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi) {
}
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
model->rssi_history[model->ind_write++] = u_rssi;
if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) {
model->rssi_history_end = true;
model->ind_write = 0;
}
return true;
});
},
true);
}
void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample) {
furi_assert(instance);
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
furi_string_printf(model->sample_write, "%d spl.", sample);
return false;
});
instance->view,
SubGhzReadRAWModel * model,
{ furi_string_printf(model->sample_write, "%d spl.", sample); },
false);
}
void subghz_read_raw_stop_send(SubGhzReadRAW* instance) {
furi_assert(instance);
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
switch(model->status) {
case SubGhzReadRAWStatusTXRepeat:
case SubGhzReadRAWStatusLoadKeyTXRepeat:
@@ -106,19 +112,21 @@ void subghz_read_raw_stop_send(SubGhzReadRAW* instance) {
model->status = SubGhzReadRAWStatusIDLE;
break;
}
return true;
});
},
true);
}
void subghz_read_raw_update_sin(SubGhzReadRAW* instance) {
furi_assert(instance);
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
if(model->ind_sin++ > 62) {
model->ind_sin = 0;
}
return true;
});
},
true);
}
static int8_t subghz_read_raw_tab_sin(uint8_t x) {
@@ -289,9 +297,11 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
//further check of events is not needed, we exit
return false;
} else if(event->key == InputKeyOk && event->type == InputTypePress) {
uint8_t ret = false;
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
uint8_t ret = false;
instance->view,
SubGhzReadRAWModel * model,
{
switch(model->status) {
case SubGhzReadRAWStatusIDLE:
// Start TX
@@ -317,11 +327,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
default:
break;
}
return ret;
});
},
ret);
} else if(event->key == InputKeyOk && event->type == InputTypeRelease) {
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
if(model->status == SubGhzReadRAWStatusTXRepeat) {
// Stop repeat TX
model->status = SubGhzReadRAWStatusTX;
@@ -329,11 +341,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
// Stop repeat TX
model->status = SubGhzReadRAWStatusLoadKeyTX;
}
return false;
});
},
false);
} else if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
switch(model->status) {
case SubGhzReadRAWStatusREC:
//Stop REC
@@ -360,11 +374,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context);
break;
}
return true;
});
},
true);
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
if(!model->raw_send_only) {
if(model->status == SubGhzReadRAWStatusStart) {
//Config
@@ -381,11 +397,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
instance->callback(SubGhzCustomEventViewReadRAWErase, instance->context);
}
}
return true;
});
},
true);
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
if(!model->raw_send_only) {
if(model->status == SubGhzReadRAWStatusIDLE) {
//Save
@@ -395,11 +413,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
instance->callback(SubGhzCustomEventViewReadRAWMore, instance->context);
}
}
return true;
});
},
true);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
if(model->status == SubGhzReadRAWStatusStart) {
//Record
instance->callback(SubGhzCustomEventViewReadRAWREC, instance->context);
@@ -411,8 +431,8 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
model->status = SubGhzReadRAWStatusIDLE;
}
return true;
});
},
true);
}
return true;
}
@@ -426,36 +446,42 @@ void subghz_read_raw_set_status(
switch(status) {
case SubGhzReadRAWStatusStart:
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
model->status = SubGhzReadRAWStatusStart;
model->rssi_history_end = false;
model->ind_write = 0;
furi_string_reset(model->file_name);
furi_string_set(model->sample_write, "0 spl.");
return true;
});
},
true);
break;
case SubGhzReadRAWStatusIDLE:
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
model->status = SubGhzReadRAWStatusIDLE;
return true;
});
instance->view,
SubGhzReadRAWModel * model,
{ model->status = SubGhzReadRAWStatusIDLE; },
true);
break;
case SubGhzReadRAWStatusLoadKeyTX:
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
model->status = SubGhzReadRAWStatusLoadKeyIDLE;
model->rssi_history_end = false;
model->ind_write = 0;
furi_string_set(model->file_name, file_name);
furi_string_set(model->sample_write, "RAW");
return true;
});
},
true);
break;
case SubGhzReadRAWStatusSaveKey:
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
model->status = SubGhzReadRAWStatusLoadKeyIDLE;
if(!model->ind_write) {
furi_string_set(model->file_name, file_name);
@@ -463,8 +489,8 @@ void subghz_read_raw_set_status(
} else {
furi_string_reset(model->file_name);
}
return true;
});
},
true);
break;
default:
@@ -483,15 +509,17 @@ void subghz_read_raw_exit(void* context) {
SubGhzReadRAW* instance = context;
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
if(model->status != SubGhzReadRAWStatusIDLE &&
model->status != SubGhzReadRAWStatusStart &&
model->status != SubGhzReadRAWStatusLoadKeyIDLE) {
instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
model->status = SubGhzReadRAWStatusStart;
}
return true;
});
},
true);
}
SubGhzReadRAW* subghz_read_raw_alloc(bool raw_send_only) {
@@ -507,15 +535,17 @@ SubGhzReadRAW* subghz_read_raw_alloc(bool raw_send_only) {
view_set_exit_callback(instance->view, subghz_read_raw_exit);
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->sample_write = furi_string_alloc();
model->file_name = furi_string_alloc();
model->raw_send_only = raw_send_only;
model->rssi_history = malloc(SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE * sizeof(uint8_t));
return true;
});
},
true);
return instance;
}
@@ -524,14 +554,16 @@ void subghz_read_raw_free(SubGhzReadRAW* instance) {
furi_assert(instance);
with_view_model(
instance->view, (SubGhzReadRAWModel * model) {
instance->view,
SubGhzReadRAWModel * model,
{
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->sample_write);
furi_string_free(model->file_name);
free(model->rssi_history);
return true;
});
},
true);
view_free(instance->view);
free(instance);
}

View File

@@ -89,7 +89,9 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
}
with_view_model(
subghz_test_carrier->view, (SubGhzTestCarrierModel * model) {
subghz_test_carrier->view,
SubGhzTestCarrierModel * model,
{
furi_hal_subghz_idle();
if(event->key == InputKeyLeft) {
@@ -125,9 +127,8 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context);
}
}
return true;
});
},
true);
return true;
}
@@ -142,15 +143,17 @@ void subghz_test_carrier_enter(void* context) {
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
with_view_model(
subghz_test_carrier->view, (SubGhzTestCarrierModel * model) {
subghz_test_carrier->view,
SubGhzTestCarrierModel * model,
{
model->frequency = subghz_frequencies_433_92_testing; // 433
model->real_frequency =
furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
model->path = FuriHalSubGhzPathIsolate; // isolate
model->rssi = 0.0f;
model->status = SubGhzTestCarrierModelStatusRx;
return true;
});
},
true);
furi_hal_subghz_rx();
@@ -172,13 +175,14 @@ void subghz_test_carrier_rssi_timer_callback(void* context) {
SubGhzTestCarrier* subghz_test_carrier = context;
with_view_model(
subghz_test_carrier->view, (SubGhzTestCarrierModel * model) {
subghz_test_carrier->view,
SubGhzTestCarrierModel * model,
{
if(model->status == SubGhzTestCarrierModelStatusRx) {
model->rssi = furi_hal_subghz_get_rssi();
return true;
}
return false;
});
},
false);
}
SubGhzTestCarrier* subghz_test_carrier_alloc() {

View File

@@ -68,7 +68,9 @@ static void subghz_test_packet_rssi_timer_callback(void* context) {
SubGhzTestPacket* instance = context;
with_view_model(
instance->view, (SubGhzTestPacketModel * model) {
instance->view,
SubGhzTestPacketModel * model,
{
if(model->status == SubGhzTestPacketModelStatusRx) {
model->rssi = furi_hal_subghz_get_rssi();
model->packets = instance->packet_rx;
@@ -77,8 +79,8 @@ static void subghz_test_packet_rssi_timer_callback(void* context) {
SUBGHZ_TEST_PACKET_COUNT -
subghz_encoder_princeton_for_testing_get_repeat_left(instance->encoder);
}
return true;
});
},
true);
}
static void subghz_test_packet_draw(Canvas* canvas, SubGhzTestPacketModel* model) {
@@ -137,7 +139,9 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) {
}
with_view_model(
instance->view, (SubGhzTestPacketModel * model) {
instance->view,
SubGhzTestPacketModel * model,
{
if(model->status == SubGhzTestPacketModelStatusRx) {
furi_hal_subghz_stop_async_rx();
} else if(model->status == SubGhzTestPacketModelStatusTx) {
@@ -179,9 +183,8 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) {
instance->callback(SubGhzTestPacketEventOnlyRx, instance->context);
}
}
return true;
});
},
true);
return true;
}
@@ -194,15 +197,17 @@ void subghz_test_packet_enter(void* context) {
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
with_view_model(
instance->view, (SubGhzTestPacketModel * model) {
instance->view,
SubGhzTestPacketModel * model,
{
model->frequency = subghz_frequencies_433_92_testing;
model->real_frequency =
furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
model->path = FuriHalSubGhzPathIsolate; // isolate
model->rssi = 0.0f;
model->status = SubGhzTestPacketModelStatusRx;
return true;
});
},
true);
furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance);
@@ -217,15 +222,17 @@ void subghz_test_packet_exit(void* context) {
// Reinitialize IC to default state
with_view_model(
instance->view, (SubGhzTestPacketModel * model) {
instance->view,
SubGhzTestPacketModel * model,
{
if(model->status == SubGhzTestPacketModelStatusRx) {
furi_hal_subghz_stop_async_rx();
} else if(model->status == SubGhzTestPacketModelStatusTx) {
subghz_encoder_princeton_for_testing_stop(instance->encoder, furi_get_tick());
furi_hal_subghz_stop_async_tx();
}
return true;
});
},
true);
furi_hal_subghz_sleep();
}

View File

@@ -77,7 +77,9 @@ bool subghz_test_static_input(InputEvent* event, void* context) {
}
with_view_model(
instance->view, (SubGhzTestStaticModel * model) {
instance->view,
SubGhzTestStaticModel * model,
{
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
@@ -128,9 +130,8 @@ bool subghz_test_static_input(InputEvent* event, void* context) {
}
furi_record_close(RECORD_NOTIFICATION);
}
return true;
});
},
true);
return true;
}
@@ -147,13 +148,14 @@ void subghz_test_static_enter(void* context) {
instance->status_tx = SubGhzTestStaticStatusIDLE;
with_view_model(
instance->view, (SubGhzTestStaticModel * model) {
instance->view,
SubGhzTestStaticModel * model,
{
model->frequency = subghz_frequencies_433_92_testing;
model->real_frequency = subghz_frequencies_testing[model->frequency];
model->button = 0;
return true;
});
},
true);
}
void subghz_test_static_exit(void* context) {

View File

@@ -35,13 +35,15 @@ void subghz_view_transmitter_add_data_to_show(
uint8_t show_button) {
furi_assert(subghz_transmitter);
with_view_model(
subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_set(model->key_str, key_str);
furi_string_set(model->frequency_str, frequency_str);
furi_string_set(model->preset_str, preset_str);
model->show_button = show_button;
return true;
});
},
true);
}
static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) {
@@ -95,23 +97,27 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->frequency_str);
furi_string_reset(model->preset_str);
furi_string_reset(model->key_str);
model->show_button = 0;
return false;
});
},
false);
return false;
}
with_view_model(
subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
if(model->show_button) {
can_be_sent = true;
}
return true;
});
},
true);
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
subghz_transmitter->callback(
@@ -149,12 +155,14 @@ SubGhzViewTransmitter* subghz_view_transmitter_alloc() {
view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit);
with_view_model(
subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->key_str = furi_string_alloc();
return true;
});
},
true);
return subghz_transmitter;
}
@@ -162,12 +170,14 @@ void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter) {
furi_assert(subghz_transmitter);
with_view_model(
subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->key_str);
return true;
});
},
true);
view_free(subghz_transmitter->view);
free(subghz_transmitter);
}

View File

@@ -85,18 +85,17 @@ void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* contex
furi_assert(u2f);
furi_assert(callback);
with_view_model(
u2f->view, (U2fModel * model) {
u2f->view,
U2fModel * model,
{
UNUSED(model);
u2f->callback = callback;
u2f->context = context;
return false;
});
},
false);
}
void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg) {
with_view_model(
u2f->view, (U2fModel * model) {
model->display_msg = msg;
return true;
});
u2f->view, U2fModel * model, { model->display_msg = msg; }, true);
}

View File

@@ -277,7 +277,9 @@ static void bt_hid_keyboard_get_select_key(BtHidKeyboardModel* model, BtHidKeybo
static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* event) {
with_view_model(
bt_hid_keyboard->view, (BtHidKeyboardModel * model) {
bt_hid_keyboard->view,
BtHidKeyboardModel * model,
{
if(event->key == InputKeyOk) {
if(event->type == InputTypePress) {
model->ok_pressed = true;
@@ -338,8 +340,8 @@ static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent*
bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 1, .y = 0});
}
}
return true;
});
},
true);
}
static bool bt_hid_keyboard_input_callback(InputEvent* event, void* context) {
@@ -382,8 +384,5 @@ View* bt_hid_keyboard_get_view(BtHidKeyboard* bt_hid_keyboard) {
void bt_hid_keyboard_set_connected_status(BtHidKeyboard* bt_hid_keyboard, bool connected) {
furi_assert(bt_hid_keyboard);
with_view_model(
bt_hid_keyboard->view, (BtHidKeyboardModel * model) {
model->connected = connected;
return true;
});
bt_hid_keyboard->view, BtHidKeyboardModel * model, { model->connected = connected; }, true);
}

View File

@@ -106,7 +106,9 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) {
static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* event) {
with_view_model(
bt_hid_keynote->view, (BtHidKeynoteModel * model) {
bt_hid_keynote->view,
BtHidKeynoteModel * model,
{
if(event->type == InputTypePress) {
if(event->key == InputKeyUp) {
model->up_pressed = true;
@@ -153,8 +155,8 @@ static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* eve
furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_AC_BACK);
}
}
return true;
});
},
true);
}
static bool bt_hid_keynote_input_callback(InputEvent* event, void* context) {
@@ -197,8 +199,5 @@ View* bt_hid_keynote_get_view(BtHidKeynote* bt_hid_keynote) {
void bt_hid_keynote_set_connected_status(BtHidKeynote* bt_hid_keynote, bool connected) {
furi_assert(bt_hid_keynote);
with_view_model(
bt_hid_keynote->view, (BtHidKeynoteModel * model) {
model->connected = connected;
return true;
});
bt_hid_keynote->view, BtHidKeynoteModel * model, { model->connected = connected; }, true);
}

View File

@@ -107,7 +107,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) {
static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* event) {
with_view_model(
bt_hid_media->view, (BtHidMediaModel * model) {
bt_hid_media->view,
BtHidMediaModel * model,
{
if(event->key == InputKeyUp) {
model->up_pressed = true;
furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT);
@@ -124,13 +126,15 @@ static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* eve
model->ok_pressed = true;
furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE);
}
return true;
});
},
true);
}
static void bt_hid_media_process_release(BtHidMedia* bt_hid_media, InputEvent* event) {
with_view_model(
bt_hid_media->view, (BtHidMediaModel * model) {
bt_hid_media->view,
BtHidMediaModel * model,
{
if(event->key == InputKeyUp) {
model->up_pressed = false;
furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT);
@@ -147,8 +151,8 @@ static void bt_hid_media_process_release(BtHidMedia* bt_hid_media, InputEvent* e
model->ok_pressed = false;
furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE);
}
return true;
});
},
true);
}
static bool bt_hid_media_input_callback(InputEvent* event, void* context) {
@@ -196,8 +200,5 @@ View* bt_hid_media_get_view(BtHidMedia* bt_hid_media) {
void bt_hid_media_set_connected_status(BtHidMedia* bt_hid_media, bool connected) {
furi_assert(bt_hid_media);
with_view_model(
bt_hid_media->view, (BtHidMediaModel * model) {
model->connected = connected;
return true;
});
bt_hid_media->view, BtHidMediaModel * model, { model->connected = connected; }, true);
}

View File

@@ -103,7 +103,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) {
with_view_model(
bt_hid_mouse->view, (BtHidMouseModel * model) {
bt_hid_mouse->view,
BtHidMouseModel * model,
{
if(event->key == InputKeyBack) {
if(event->type == InputTypeShort) {
furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_RIGHT);
@@ -167,8 +169,8 @@ static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) {
model->up_pressed = false;
}
}
return true;
});
},
true);
}
static bool bt_hid_mouse_input_callback(InputEvent* event, void* context) {
@@ -211,8 +213,5 @@ View* bt_hid_mouse_get_view(BtHidMouse* bt_hid_mouse) {
void bt_hid_mouse_set_connected_status(BtHidMouse* bt_hid_mouse, bool connected) {
furi_assert(bt_hid_mouse);
with_view_model(
bt_hid_mouse->view, (BtHidMouseModel * model) {
model->connected = connected;
return true;
});
bt_hid_mouse->view, BtHidMouseModel * model, { model->connected = connected; }, true);
}

View File

@@ -44,12 +44,14 @@ static void pwm_set_config(SignalGenPwm* pwm) {
uint8_t duty;
with_view_model(
pwm->view, (SignalGenPwmViewModel * model) {
pwm->view,
SignalGenPwmViewModel * model,
{
channel = model->channel_id;
freq = model->freq;
duty = model->duty;
return false;
});
},
false);
furi_assert(pwm->callback);
pwm->callback(channel, freq, duty, pwm->context);
@@ -188,7 +190,9 @@ static bool signal_gen_pwm_input_callback(InputEvent* event, void* context) {
bool need_update = false;
with_view_model(
pwm->view, (SignalGenPwmViewModel * model) {
pwm->view,
SignalGenPwmViewModel * model,
{
if(model->edit_mode == false) {
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
if(event->key == InputKeyUp) {
@@ -238,8 +242,8 @@ static bool signal_gen_pwm_input_callback(InputEvent* event, void* context) {
}
}
}
return true;
});
},
true);
if(need_update) {
pwm_set_config(pwm);
@@ -279,22 +283,26 @@ void signal_gen_pwm_set_callback(
furi_assert(callback);
with_view_model(
pwm->view, (SignalGenPwmViewModel * model) {
pwm->view,
SignalGenPwmViewModel * model,
{
UNUSED(model);
pwm->callback = callback;
pwm->context = context;
return false;
});
},
false);
}
void signal_gen_pwm_set_params(SignalGenPwm* pwm, uint8_t channel_id, uint32_t freq, uint8_t duty) {
with_view_model(
pwm->view, (SignalGenPwmViewModel * model) {
pwm->view,
SignalGenPwmViewModel * model,
{
model->channel_id = channel_id;
model->freq = freq;
model->duty = duty;
return true;
});
},
true);
furi_assert(pwm->callback);
pwm->callback(channel_id, freq, duty, pwm->context);

View File

@@ -47,21 +47,23 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) {
if(event->key == InputKeyBack && event->type == InputTypeShort) {
instance->callback(SubBruteCustomEventTypeBackPressed, instance->context);
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
instance->view,
SubBruteAttackViewModel * model,
{
model->is_attacking = false;
model->is_continuous_worker = false;
return true;
});
},
true);
return true;
}
bool is_attacking = false;
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
is_attacking = model->is_attacking;
return false;
});
instance->view,
SubBruteAttackViewModel * model,
{ is_attacking = model->is_attacking; },
false);
// if(!is_attacking) {
// instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context);
@@ -75,13 +77,15 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) {
FURI_LOG_D(TAG, "InputKey: %d OK", event->key);
#endif
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
instance->view,
SubBruteAttackViewModel * model,
{
model->is_attacking = true;
model->is_continuous_worker = false;
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
return true;
});
},
true);
instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);
/*if(event->type == InputTypeRepeat && event->key == InputKeyOk) {
#ifdef FURI_DEBUG
@@ -152,13 +156,15 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) {
if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
(event->key == InputKeyOk || event->key == InputKeyBack)) {
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
instance->view,
SubBruteAttackViewModel * model,
{
model->is_attacking = false;
model->is_continuous_worker = false;
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
return true;
});
},
true);
instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context);
}
}
@@ -174,11 +180,13 @@ SubBruteAttackView* subbrute_attack_view_alloc() {
view_set_context(instance->view, instance);
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
instance->view,
SubBruteAttackViewModel * model,
{
model->icon = icon_animation_alloc(&A_Sub1ghz_14);
view_tie_icon_animation(instance->view, model->icon);
return false;
});
},
false);
view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw);
view_set_input_callback(instance->view, subbrute_attack_view_input);
@@ -204,10 +212,10 @@ void subbrute_attack_view_free(SubBruteAttackView* instance) {
#endif
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
icon_animation_free(model->icon);
return false;
});
instance->view,
SubBruteAttackViewModel * model,
{ icon_animation_free(model->icon); },
false);
view_free(instance->view);
free(instance);
@@ -224,19 +232,19 @@ void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_
//FURI_LOG_D(TAG, "Set step: %d", current_step);
#endif
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
model->current_step = current_step;
return true;
});
instance->view,
SubBruteAttackViewModel * model,
{ model->current_step = current_step; },
true);
}
void subbrute_attack_view_set_worker_type(SubBruteAttackView* instance, bool is_continuous_worker) {
furi_assert(instance);
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
model->is_continuous_worker = is_continuous_worker;
return true;
});
instance->view,
SubBruteAttackViewModel * model,
{ model->is_continuous_worker = is_continuous_worker; },
true);
}
// We need to call init every time, because not every time we calls enter
@@ -256,7 +264,9 @@ void subbrute_attack_view_init_values(
current_step);
#endif
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
instance->view,
SubBruteAttackViewModel * model,
{
model->max_value = max_value;
model->index = index;
model->current_step = current_step;
@@ -266,8 +276,8 @@ void subbrute_attack_view_init_values(
} else {
icon_animation_stop(model->icon);
}
return true;
});
},
true);
}
void subbrute_attack_view_exit(void* context) {
@@ -277,10 +287,10 @@ void subbrute_attack_view_exit(void* context) {
FURI_LOG_D(TAG, "subbrute_attack_view_exit");
#endif
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
icon_animation_stop(model->icon);
return false;
});
instance->view,
SubBruteAttackViewModel * model,
{ icon_animation_stop(model->icon); },
false);
}
void elements_button_top_left(Canvas* canvas, const char* str) {

View File

@@ -173,17 +173,19 @@ bool subbrute_main_view_input(InputEvent* event, void* context) {
uint8_t index = 0;
bool is_select_byte = false;
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
is_select_byte = model->is_select_byte;
return false;
});
instance->view,
SubBruteMainViewModel * model,
{ is_select_byte = model->is_select_byte; },
false);
bool consumed = false;
if(!is_select_byte) {
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
bool ret = false;
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
bool ret = false;
instance->view,
SubBruteMainViewModel * model,
{
uint8_t items_on_screen = 3;
if(event->key == InputKeyUp) {
if(model->index == min_value) {
@@ -219,8 +221,8 @@ bool subbrute_main_view_input(InputEvent* event, void* context) {
}
}
index = model->index;
return ret;
});
},
ret);
}
#ifdef FURI_DEBUG
@@ -243,7 +245,9 @@ bool subbrute_main_view_input(InputEvent* event, void* context) {
} else {
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
instance->view,
SubBruteMainViewModel * model,
{
if(event->key == InputKeyLeft) {
if(model->index > 0) {
model->index--;
@@ -255,8 +259,8 @@ bool subbrute_main_view_input(InputEvent* event, void* context) {
}
index = model->index;
return true;
});
},
true);
}
#ifdef FURI_DEBUG
@@ -304,13 +308,15 @@ SubBruteMainView* subbrute_main_view_alloc() {
view_set_exit_callback(instance->view, subbrute_main_view_exit);
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
instance->view,
SubBruteMainViewModel * model,
{
model->index = 0;
model->window_position = 0;
model->key_field = NULL;
model->is_select_byte = false;
return true;
});
},
true);
return instance;
}
@@ -338,7 +344,9 @@ void subbrute_main_view_set_index(
FURI_LOG_I(TAG, "Set index: %d", idx);
#endif
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
instance->view,
SubBruteMainViewModel * model,
{
model->is_select_byte = is_select_byte;
model->key_field = key_field;
model->index = idx;
@@ -359,8 +367,8 @@ void subbrute_main_view_set_index(
}
}
}
return true;
});
},
true);
}
SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) {
@@ -368,10 +376,7 @@ SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) {
uint8_t idx = 0;
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
idx = model->index;
return false;
});
instance->view, SubBruteMainViewModel * model, { idx = model->index; }, false);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Get index: %d", idx);

View File

@@ -0,0 +1,14 @@
App(
appid="USB_Keyboard",
name="USB Keyboard & Mouse",
apptype=FlipperAppType.EXTERNAL,
entry_point="usb_hid_app",
stack_size=1 * 1024,
cdefines=["APP_USB_KEYBOARD"],
requires=[
"gui",
],
order=60,
fap_icon="usb_keyboard_10px.png",
fap_category="Misc",
)

View File

@@ -0,0 +1,171 @@
#include "usb_hid.h"
#include <furi.h>
#include <furi_hal.h>
#include <notification/notification_messages.h>
#define TAG "UsbHidApp"
enum UsbDebugSubmenuIndex {
UsbHidSubmenuIndexDirpad,
UsbHidSubmenuIndexKeyboard,
UsbHidSubmenuIndexMedia,
UsbHidSubmenuIndexMouse,
};
void usb_hid_submenu_callback(void* context, uint32_t index) {
furi_assert(context);
UsbHid* app = context;
if(index == UsbHidSubmenuIndexDirpad) {
app->view_id = UsbHidViewDirpad;
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewDirpad);
} else if(index == UsbHidSubmenuIndexKeyboard) {
app->view_id = UsbHidViewKeyboard;
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewKeyboard);
} else if(index == UsbHidSubmenuIndexMedia) {
app->view_id = UsbHidViewMedia;
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMedia);
} else if(index == UsbHidSubmenuIndexMouse) {
app->view_id = UsbHidViewMouse;
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouse);
}
}
void usb_hid_dialog_callback(DialogExResult result, void* context) {
furi_assert(context);
UsbHid* app = context;
if(result == DialogExResultLeft) {
view_dispatcher_stop(app->view_dispatcher);
} else if(result == DialogExResultRight) {
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view
} else if(result == DialogExResultCenter) {
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewSubmenu);
}
}
uint32_t usb_hid_exit_confirm_view(void* context) {
UNUSED(context);
return UsbHidViewExitConfirm;
}
uint32_t usb_hid_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
}
UsbHid* usb_hid_app_alloc() {
UsbHid* app = malloc(sizeof(UsbHid));
// Gui
app->gui = furi_record_open(RECORD_GUI);
// Notifications
app->notifications = furi_record_open(RECORD_NOTIFICATION);
// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Submenu view
app->submenu = submenu_alloc();
submenu_add_item(
app->submenu, "Dirpad", UsbHidSubmenuIndexDirpad, usb_hid_submenu_callback, app);
submenu_add_item(
app->submenu, "Keyboard", UsbHidSubmenuIndexKeyboard, usb_hid_submenu_callback, app);
submenu_add_item(app->submenu, "Media", UsbHidSubmenuIndexMedia, usb_hid_submenu_callback, app);
submenu_add_item(app->submenu, "Mouse", UsbHidSubmenuIndexMouse, usb_hid_submenu_callback, app);
view_set_previous_callback(submenu_get_view(app->submenu), usb_hid_exit);
view_dispatcher_add_view(
app->view_dispatcher, UsbHidViewSubmenu, submenu_get_view(app->submenu));
// Dialog view
app->dialog = dialog_ex_alloc();
dialog_ex_set_result_callback(app->dialog, usb_hid_dialog_callback);
dialog_ex_set_context(app->dialog, app);
dialog_ex_set_left_button_text(app->dialog, "Exit");
dialog_ex_set_right_button_text(app->dialog, "Stay");
dialog_ex_set_center_button_text(app->dialog, "Menu");
dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop);
view_dispatcher_add_view(
app->view_dispatcher, UsbHidViewExitConfirm, dialog_ex_get_view(app->dialog));
// Dirpad view
app->usb_hid_dirpad = usb_hid_dirpad_alloc();
view_set_previous_callback(
usb_hid_dirpad_get_view(app->usb_hid_dirpad), usb_hid_exit_confirm_view);
view_dispatcher_add_view(
app->view_dispatcher, UsbHidViewDirpad, usb_hid_dirpad_get_view(app->usb_hid_dirpad));
// Keyboard view
app->usb_hid_keyboard = usb_hid_keyboard_alloc();
view_set_previous_callback(
usb_hid_keyboard_get_view(app->usb_hid_keyboard), usb_hid_exit_confirm_view);
view_dispatcher_add_view(
app->view_dispatcher, UsbHidViewKeyboard, usb_hid_keyboard_get_view(app->usb_hid_keyboard));
// Media view
app->usb_hid_media = usb_hid_media_alloc();
view_set_previous_callback(usb_hid_media_get_view(app->usb_hid_media), usb_hid_exit_confirm_view);
view_dispatcher_add_view(
app->view_dispatcher, UsbHidViewMedia, usb_hid_media_get_view(app->usb_hid_media));
// Mouse view
app->usb_hid_mouse = usb_hid_mouse_alloc();
view_set_previous_callback(usb_hid_mouse_get_view(app->usb_hid_mouse), usb_hid_exit_confirm_view);
view_dispatcher_add_view(
app->view_dispatcher, UsbHidViewMouse, usb_hid_mouse_get_view(app->usb_hid_mouse));
// TODO switch to menu after Media is done
app->view_id = UsbHidViewSubmenu;
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id);
return app;
}
void usb_hid_app_free(UsbHid* app) {
furi_assert(app);
// Reset notification
notification_internal_message(app->notifications, &sequence_reset_blue);
// Free views
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewSubmenu);
submenu_free(app->submenu);
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewExitConfirm);
dialog_ex_free(app->dialog);
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewDirpad);
usb_hid_dirpad_free(app->usb_hid_dirpad);
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewKeyboard);
usb_hid_keyboard_free(app->usb_hid_keyboard);
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMedia);
usb_hid_media_free(app->usb_hid_media);
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouse);
usb_hid_mouse_free(app->usb_hid_mouse);
view_dispatcher_free(app->view_dispatcher);
// Close records
furi_record_close(RECORD_GUI);
app->gui = NULL;
furi_record_close(RECORD_NOTIFICATION);
app->notifications = NULL;
// Free rest
free(app);
}
int32_t usb_hid_app(void* p) {
UNUSED(p);
// Switch profile to Hid
UsbHid* app = usb_hid_app_alloc();
FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
furi_hal_usb_unlock();
furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true);
view_dispatcher_run(app->view_dispatcher);
// Change back profile
furi_hal_usb_set_config(usb_mode_prev, NULL);
usb_hid_app_free(app);
return 0;
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <furi.h>
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <notification/notification.h>
#include <gui/modules/submenu.h>
#include <gui/modules/dialog_ex.h>
#include "views/usb_hid_dirpad.h"
#include "views/usb_hid_keyboard.h"
#include "views/usb_hid_media.h"
#include "views/usb_hid_mouse.h"
typedef struct {
Gui* gui;
NotificationApp* notifications;
ViewDispatcher* view_dispatcher;
Submenu* submenu;
DialogEx* dialog;
UsbHidDirpad* usb_hid_dirpad;
UsbHidKeyboard* usb_hid_keyboard;
UsbHidMedia* usb_hid_media;
UsbHidMouse* usb_hid_mouse;
uint32_t view_id;
} UsbHid;
typedef enum {
UsbHidViewSubmenu,
UsbHidViewDirpad,
UsbHidViewKeyboard,
UsbHidViewMedia,
UsbHidViewMouse,
UsbHidViewExitConfirm,
} UsbHidView;

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

View File

@@ -0,0 +1,196 @@
#include "usb_hid_dirpad.h"
#include <furi.h>
#include <furi_hal_usb_hid.h>
#include <gui/elements.h>
struct UsbHidDirpad {
View* view;
};
typedef struct {
bool left_pressed;
bool up_pressed;
bool right_pressed;
bool down_pressed;
bool ok_pressed;
bool back_pressed;
bool connected;
} UsbHidDirpadModel;
static void usb_hid_dirpad_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) {
canvas_draw_triangle(canvas, x, y, 5, 3, dir);
if(dir == CanvasDirectionBottomToTop) {
canvas_draw_line(canvas, x, y + 6, x, y - 1);
} else if(dir == CanvasDirectionTopToBottom) {
canvas_draw_line(canvas, x, y - 6, x, y + 1);
} else if(dir == CanvasDirectionRightToLeft) {
canvas_draw_line(canvas, x + 6, y, x - 1, y);
} else if(dir == CanvasDirectionLeftToRight) {
canvas_draw_line(canvas, x - 6, y, x + 1, y);
}
}
static void usb_hid_dirpad_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
UsbHidDirpadModel* model = context;
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Dirpad");
canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8);
canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit");
// Up
canvas_draw_icon(canvas, 21, 24, &I_Button_18x18);
if(model->up_pressed) {
elements_slightly_rounded_box(canvas, 24, 26, 13, 13);
canvas_set_color(canvas, ColorWhite);
}
usb_hid_dirpad_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop);
canvas_set_color(canvas, ColorBlack);
// Down
canvas_draw_icon(canvas, 21, 45, &I_Button_18x18);
if(model->down_pressed) {
elements_slightly_rounded_box(canvas, 24, 47, 13, 13);
canvas_set_color(canvas, ColorWhite);
}
usb_hid_dirpad_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom);
canvas_set_color(canvas, ColorBlack);
// Left
canvas_draw_icon(canvas, 0, 45, &I_Button_18x18);
if(model->left_pressed) {
elements_slightly_rounded_box(canvas, 3, 47, 13, 13);
canvas_set_color(canvas, ColorWhite);
}
usb_hid_dirpad_draw_arrow(canvas, 7, 53, CanvasDirectionRightToLeft);
canvas_set_color(canvas, ColorBlack);
// Right
canvas_draw_icon(canvas, 42, 45, &I_Button_18x18);
if(model->right_pressed) {
elements_slightly_rounded_box(canvas, 45, 47, 13, 13);
canvas_set_color(canvas, ColorWhite);
}
usb_hid_dirpad_draw_arrow(canvas, 53, 53, CanvasDirectionLeftToRight);
canvas_set_color(canvas, ColorBlack);
// Ok
canvas_draw_icon(canvas, 63, 25, &I_Space_65x18);
if(model->ok_pressed) {
elements_slightly_rounded_box(canvas, 66, 27, 60, 13);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9);
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Space");
canvas_set_color(canvas, ColorBlack);
// Back
canvas_draw_icon(canvas, 63, 45, &I_Space_65x18);
if(model->back_pressed) {
elements_slightly_rounded_box(canvas, 66, 47, 60, 13);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back");
}
static void usb_hid_dirpad_process(UsbHidDirpad* usb_hid_dirpad, InputEvent* event) {
with_view_model(
usb_hid_dirpad->view,
UsbHidDirpadModel * model,
{
if(event->type == InputTypePress) {
if(event->key == InputKeyUp) {
model->up_pressed = true;
furi_hal_hid_kb_press(HID_KEYBOARD_UP_ARROW);
} else if(event->key == InputKeyDown) {
model->down_pressed = true;
furi_hal_hid_kb_press(HID_KEYBOARD_DOWN_ARROW);
} else if(event->key == InputKeyLeft) {
model->left_pressed = true;
furi_hal_hid_kb_press(HID_KEYBOARD_LEFT_ARROW);
} else if(event->key == InputKeyRight) {
model->right_pressed = true;
furi_hal_hid_kb_press(HID_KEYBOARD_RIGHT_ARROW);
} else if(event->key == InputKeyOk) {
model->ok_pressed = true;
furi_hal_hid_kb_press(HID_KEYBOARD_SPACEBAR);
} else if(event->key == InputKeyBack) {
model->back_pressed = true;
}
} else if(event->type == InputTypeRelease) {
if(event->key == InputKeyUp) {
model->up_pressed = false;
furi_hal_hid_kb_release(HID_KEYBOARD_UP_ARROW);
} else if(event->key == InputKeyDown) {
model->down_pressed = false;
furi_hal_hid_kb_release(HID_KEYBOARD_DOWN_ARROW);
} else if(event->key == InputKeyLeft) {
model->left_pressed = false;
furi_hal_hid_kb_release(HID_KEYBOARD_LEFT_ARROW);
} else if(event->key == InputKeyRight) {
model->right_pressed = false;
furi_hal_hid_kb_release(HID_KEYBOARD_RIGHT_ARROW);
} else if(event->key == InputKeyOk) {
model->ok_pressed = false;
furi_hal_hid_kb_release(HID_KEYBOARD_SPACEBAR);
} else if(event->key == InputKeyBack) {
model->back_pressed = false;
}
} else if(event->type == InputTypeShort) {
if(event->key == InputKeyBack) {
furi_hal_hid_kb_press(HID_KEYBOARD_DELETE);
furi_hal_hid_kb_release(HID_KEYBOARD_DELETE);
furi_hal_hid_consumer_key_press(HID_CONSUMER_AC_BACK);
furi_hal_hid_consumer_key_release(HID_CONSUMER_AC_BACK);
}
}
},
true);
}
static bool usb_hid_dirpad_input_callback(InputEvent* event, void* context) {
furi_assert(context);
UsbHidDirpad* usb_hid_dirpad = context;
bool consumed = false;
if(event->type == InputTypeLong && event->key == InputKeyBack) {
furi_hal_hid_kb_release_all();
} else {
usb_hid_dirpad_process(usb_hid_dirpad, event);
consumed = true;
}
return consumed;
}
UsbHidDirpad* usb_hid_dirpad_alloc() {
UsbHidDirpad* usb_hid_dirpad = malloc(sizeof(UsbHidDirpad));
usb_hid_dirpad->view = view_alloc();
view_set_context(usb_hid_dirpad->view, usb_hid_dirpad);
view_allocate_model(usb_hid_dirpad->view, ViewModelTypeLocking, sizeof(UsbHidDirpadModel));
view_set_draw_callback(usb_hid_dirpad->view, usb_hid_dirpad_draw_callback);
view_set_input_callback(usb_hid_dirpad->view, usb_hid_dirpad_input_callback);
return usb_hid_dirpad;
}
void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad) {
furi_assert(usb_hid_dirpad);
view_free(usb_hid_dirpad->view);
free(usb_hid_dirpad);
}
View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad) {
furi_assert(usb_hid_dirpad);
return usb_hid_dirpad->view;
}
void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected) {
furi_assert(usb_hid_dirpad);
with_view_model(
usb_hid_dirpad->view, UsbHidDirpadModel * model, { model->connected = connected; }, true);
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <gui/view.h>
typedef struct UsbHidDirpad UsbHidDirpad;
UsbHidDirpad* usb_hid_dirpad_alloc();
void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad);
View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad);
void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected);

View File

@@ -0,0 +1,371 @@
#include "usb_hid_keyboard.h"
#include <furi.h>
#include <furi_hal_usb_hid.h>
#include <gui/elements.h>
#include <gui/icon_i.h>
struct UsbHidKeyboard {
View* view;
};
typedef struct {
bool shift;
bool alt;
bool ctrl;
bool gui;
uint8_t x;
uint8_t y;
uint8_t last_key_code;
uint16_t modifier_code;
bool ok_pressed;
bool back_pressed;
bool connected;
char key_string[5];
} UsbHidKeyboardModel;
typedef struct {
uint8_t width;
char* key;
const Icon* icon;
char* shift_key;
uint8_t value;
} UsbHidKeyboardKey;
typedef struct {
int8_t x;
int8_t y;
} UsbHidKeyboardPoint;
// 4 BY 12
#define MARGIN_TOP 0
#define MARGIN_LEFT 4
#define KEY_WIDTH 9
#define KEY_HEIGHT 12
#define KEY_PADDING 1
#define ROW_COUNT 6
#define COLUMN_COUNT 12
// 0 width items are not drawn, but there value is used
const UsbHidKeyboardKey usb_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = {
{
{.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1},
{.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2},
{.width = 1, .icon = NULL, .key = "3", .shift_key = "#", .value = HID_KEYBOARD_3},
{.width = 1, .icon = NULL, .key = "4", .shift_key = "$", .value = HID_KEYBOARD_4},
{.width = 1, .icon = NULL, .key = "5", .shift_key = "%", .value = HID_KEYBOARD_5},
{.width = 1, .icon = NULL, .key = "6", .shift_key = "^", .value = HID_KEYBOARD_6},
{.width = 1, .icon = NULL, .key = "7", .shift_key = "&", .value = HID_KEYBOARD_7},
{.width = 1, .icon = NULL, .key = "8", .shift_key = "*", .value = HID_KEYBOARD_8},
{.width = 1, .icon = NULL, .key = "9", .shift_key = "(", .value = HID_KEYBOARD_9},
{.width = 1, .icon = NULL, .key = "0", .shift_key = ")", .value = HID_KEYBOARD_0},
{.width = 2, .icon = &I_Pin_arrow_left_9x7, .value = HID_KEYBOARD_DELETE},
{.width = 0, .value = HID_KEYBOARD_DELETE},
},
{
{.width = 1, .icon = NULL, .key = "q", .shift_key = "Q", .value = HID_KEYBOARD_Q},
{.width = 1, .icon = NULL, .key = "w", .shift_key = "W", .value = HID_KEYBOARD_W},
{.width = 1, .icon = NULL, .key = "e", .shift_key = "E", .value = HID_KEYBOARD_E},
{.width = 1, .icon = NULL, .key = "r", .shift_key = "R", .value = HID_KEYBOARD_R},
{.width = 1, .icon = NULL, .key = "t", .shift_key = "T", .value = HID_KEYBOARD_T},
{.width = 1, .icon = NULL, .key = "y", .shift_key = "Y", .value = HID_KEYBOARD_Y},
{.width = 1, .icon = NULL, .key = "u", .shift_key = "U", .value = HID_KEYBOARD_U},
{.width = 1, .icon = NULL, .key = "i", .shift_key = "I", .value = HID_KEYBOARD_I},
{.width = 1, .icon = NULL, .key = "o", .shift_key = "O", .value = HID_KEYBOARD_O},
{.width = 1, .icon = NULL, .key = "p", .shift_key = "P", .value = HID_KEYBOARD_P},
{.width = 1, .icon = NULL, .key = "[", .shift_key = "{", .value = HID_KEYBOARD_OPEN_BRACKET},
{.width = 1,
.icon = NULL,
.key = "]",
.shift_key = "}",
.value = HID_KEYBOARD_CLOSE_BRACKET},
},
{
{.width = 1, .icon = NULL, .key = "a", .shift_key = "A", .value = HID_KEYBOARD_A},
{.width = 1, .icon = NULL, .key = "s", .shift_key = "S", .value = HID_KEYBOARD_S},
{.width = 1, .icon = NULL, .key = "d", .shift_key = "D", .value = HID_KEYBOARD_D},
{.width = 1, .icon = NULL, .key = "f", .shift_key = "F", .value = HID_KEYBOARD_F},
{.width = 1, .icon = NULL, .key = "g", .shift_key = "G", .value = HID_KEYBOARD_G},
{.width = 1, .icon = NULL, .key = "h", .shift_key = "H", .value = HID_KEYBOARD_H},
{.width = 1, .icon = NULL, .key = "j", .shift_key = "J", .value = HID_KEYBOARD_J},
{.width = 1, .icon = NULL, .key = "k", .shift_key = "K", .value = HID_KEYBOARD_K},
{.width = 1, .icon = NULL, .key = "l", .shift_key = "L", .value = HID_KEYBOARD_L},
{.width = 1, .icon = NULL, .key = ";", .shift_key = ":", .value = HID_KEYBOARD_SEMICOLON},
{.width = 2, .icon = &I_Pin_arrow_right_9x7, .value = HID_KEYBOARD_RETURN},
{.width = 0, .value = HID_KEYBOARD_RETURN},
},
{
{.width = 1, .icon = NULL, .key = "z", .shift_key = "Z", .value = HID_KEYBOARD_Z},
{.width = 1, .icon = NULL, .key = "x", .shift_key = "X", .value = HID_KEYBOARD_X},
{.width = 1, .icon = NULL, .key = "c", .shift_key = "C", .value = HID_KEYBOARD_C},
{.width = 1, .icon = NULL, .key = "v", .shift_key = "V", .value = HID_KEYBOARD_V},
{.width = 1, .icon = NULL, .key = "b", .shift_key = "B", .value = HID_KEYBOARD_B},
{.width = 1, .icon = NULL, .key = "n", .shift_key = "N", .value = HID_KEYBOARD_N},
{.width = 1, .icon = NULL, .key = "m", .shift_key = "M", .value = HID_KEYBOARD_M},
{.width = 1, .icon = NULL, .key = "/", .shift_key = "?", .value = HID_KEYBOARD_SLASH},
{.width = 1, .icon = NULL, .key = "\\", .shift_key = "|", .value = HID_KEYBOARD_BACKSLASH},
{.width = 1, .icon = NULL, .key = "`", .shift_key = "~", .value = HID_KEYBOARD_GRAVE_ACCENT},
{.width = 1, .icon = &I_ButtonUp_7x4, .value = HID_KEYBOARD_UP_ARROW},
{.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS},
},
{
{.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT},
{.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA},
{.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT},
{.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR},
{.width = 0, .value = HID_KEYBOARD_SPACEBAR},
{.width = 0, .value = HID_KEYBOARD_SPACEBAR},
{.width = 0, .value = HID_KEYBOARD_SPACEBAR},
{.width = 1, .icon = NULL, .key = "'", .shift_key = "\"", .value = HID_KEYBOARD_APOSTROPHE},
{.width = 1, .icon = NULL, .key = "=", .shift_key = "+", .value = HID_KEYBOARD_EQUAL_SIGN},
{.width = 1, .icon = &I_ButtonLeft_4x7, .value = HID_KEYBOARD_LEFT_ARROW},
{.width = 1, .icon = &I_ButtonDown_7x4, .value = HID_KEYBOARD_DOWN_ARROW},
{.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW},
},
{
{.width = 3, .icon = NULL, .key = "Ctrl", .value = HID_KEYBOARD_L_CTRL},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL},
{.width = 3, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT},
{.width = 3, .icon = NULL, .key = "Cmd", .value = HID_KEYBOARD_L_GUI},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI},
{.width = 3, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB},
{.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB},
},
};
static void usb_hid_keyboard_to_upper(char* str) {
while(*str) {
*str = toupper((unsigned char)*str);
str++;
}
}
static void usb_hid_keyboard_draw_key(
Canvas* canvas,
UsbHidKeyboardModel* model,
uint8_t x,
uint8_t y,
UsbHidKeyboardKey key,
bool selected) {
if(!key.width) return;
canvas_set_color(canvas, ColorBlack);
uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1);
if(selected) {
// Draw a filled box
elements_slightly_rounded_box(
canvas,
MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING),
MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING),
keyWidth,
KEY_HEIGHT);
canvas_set_color(canvas, ColorWhite);
} else {
// Draw a framed box
elements_slightly_rounded_frame(
canvas,
MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING),
MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING),
keyWidth,
KEY_HEIGHT);
}
if(key.icon != NULL) {
// Draw the icon centered on the button
canvas_draw_icon(
canvas,
MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2,
MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2 - key.icon->height / 2,
key.icon);
} else {
// If shift is toggled use the shift key when available
strcpy(model->key_string, (model->shift && key.shift_key != 0) ? key.shift_key : key.key);
// Upper case if ctrl or alt was toggled true
if((model->ctrl && key.value == HID_KEYBOARD_L_CTRL) ||
(model->alt && key.value == HID_KEYBOARD_L_ALT) ||
(model->gui && key.value == HID_KEYBOARD_L_GUI)) {
usb_hid_keyboard_to_upper(model->key_string);
}
canvas_draw_str_aligned(
canvas,
MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1,
MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2,
AlignCenter,
AlignCenter,
model->key_string);
}
}
static void usb_hid_keyboard_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
UsbHidKeyboardModel* model = context;
canvas_set_font(canvas, FontKeyboard);
// Start shifting the all keys up if on the next row (Scrolling)
uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0;
for(uint8_t y = initY; y < ROW_COUNT; y++) {
const UsbHidKeyboardKey* keyboardKeyRow = usb_hid_keyboard_keyset[y];
uint8_t x = 0;
for(uint8_t i = 0; i < COLUMN_COUNT; i++) {
UsbHidKeyboardKey key = keyboardKeyRow[i];
// Select when the button is hovered
// Select if the button is hovered within its width
// Select if back is clicked and its the backspace key
// Deselect when the button clicked or not hovered
bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y;
bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE;
usb_hid_keyboard_draw_key(
canvas,
model,
x,
y - initY,
key,
(!model->ok_pressed && keySelected) || backSelected);
x += key.width;
}
}
}
static uint8_t usb_hid_keyboard_get_selected_key(UsbHidKeyboardModel* model) {
UsbHidKeyboardKey key = usb_hid_keyboard_keyset[model->y][model->x];
// Use upper case if shift is toggled
bool useUppercase = model->shift;
// Check if the key has an upper case version
bool hasUppercase = key.shift_key != 0;
if(useUppercase && hasUppercase)
return key.value;
else
return key.value;
}
static void
usb_hid_keyboard_get_select_key(UsbHidKeyboardModel* model, UsbHidKeyboardPoint delta) {
// Keep going until a valid spot is found, this allows for nulls and zero width keys in the map
do {
if(((int8_t)model->y) + delta.y < 0)
model->y = ROW_COUNT - 1;
else
model->y = (model->y + delta.y) % ROW_COUNT;
} while(delta.y != 0 && usb_hid_keyboard_keyset[model->y][model->x].value == 0);
do {
if(((int8_t)model->x) + delta.x < 0)
model->x = COLUMN_COUNT - 1;
else
model->x = (model->x + delta.x) % COLUMN_COUNT;
} while(delta.x != 0 && usb_hid_keyboard_keyset[model->y][model->x].width ==
0); // Skip zero width keys, pretend they are one key
}
static void usb_hid_keyboard_process(UsbHidKeyboard* usb_hid_keyboard, InputEvent* event) {
with_view_model(
usb_hid_keyboard->view,
UsbHidKeyboardModel * model,
{
if(event->key == InputKeyOk) {
if(event->type == InputTypePress) {
model->ok_pressed = true;
} else if(event->type == InputTypeLong || event->type == InputTypeShort) {
model->last_key_code = usb_hid_keyboard_get_selected_key(model);
// Toggle the modifier key when clicked, and click the key
if(model->last_key_code == HID_KEYBOARD_L_SHIFT) {
model->shift = !model->shift;
if(model->shift)
model->modifier_code |= KEY_MOD_LEFT_SHIFT;
else
model->modifier_code &= ~KEY_MOD_LEFT_SHIFT;
} else if(model->last_key_code == HID_KEYBOARD_L_ALT) {
model->alt = !model->alt;
if(model->alt)
model->modifier_code |= KEY_MOD_LEFT_ALT;
else
model->modifier_code &= ~KEY_MOD_LEFT_ALT;
} else if(model->last_key_code == HID_KEYBOARD_L_CTRL) {
model->ctrl = !model->ctrl;
if(model->ctrl)
model->modifier_code |= KEY_MOD_LEFT_CTRL;
else
model->modifier_code &= ~KEY_MOD_LEFT_CTRL;
} else if(model->last_key_code == HID_KEYBOARD_L_GUI) {
model->gui = !model->gui;
if(model->gui)
model->modifier_code |= KEY_MOD_LEFT_GUI;
else
model->modifier_code &= ~KEY_MOD_LEFT_GUI;
}
furi_hal_hid_kb_press(model->modifier_code | model->last_key_code);
} else if(event->type == InputTypeRelease) {
// Release happens after short and long presses
furi_hal_hid_kb_release(model->modifier_code | model->last_key_code);
model->ok_pressed = false;
}
} else if(event->key == InputKeyBack) {
// If back is pressed for a short time, backspace
if(event->type == InputTypePress) {
model->back_pressed = true;
} else if(event->type == InputTypeShort) {
furi_hal_hid_kb_press(HID_KEYBOARD_DELETE);
furi_hal_hid_kb_release(HID_KEYBOARD_DELETE);
} else if(event->type == InputTypeRelease) {
model->back_pressed = false;
}
} else if(event->type == InputTypePress || event->type == InputTypeRepeat) {
// Cycle the selected keys
if(event->key == InputKeyUp) {
usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = -1});
} else if(event->key == InputKeyDown) {
usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = 1});
} else if(event->key == InputKeyLeft) {
usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = -1, .y = 0});
} else if(event->key == InputKeyRight) {
usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 1, .y = 0});
}
}
},
true);
}
static bool usb_hid_keyboard_input_callback(InputEvent* event, void* context) {
furi_assert(context);
UsbHidKeyboard* usb_hid_keyboard = context;
bool consumed = false;
if(event->type == InputTypeLong && event->key == InputKeyBack) {
furi_hal_hid_kb_release_all();
} else {
usb_hid_keyboard_process(usb_hid_keyboard, event);
consumed = true;
}
return consumed;
}
UsbHidKeyboard* usb_hid_keyboard_alloc() {
UsbHidKeyboard* usb_hid_keyboard = malloc(sizeof(UsbHidKeyboard));
usb_hid_keyboard->view = view_alloc();
view_set_context(usb_hid_keyboard->view, usb_hid_keyboard);
view_allocate_model(usb_hid_keyboard->view, ViewModelTypeLocking, sizeof(UsbHidKeyboardModel));
view_set_draw_callback(usb_hid_keyboard->view, usb_hid_keyboard_draw_callback);
view_set_input_callback(usb_hid_keyboard->view, usb_hid_keyboard_input_callback);
with_view_model(
usb_hid_keyboard->view, UsbHidKeyboardModel * model, { model->connected = true; }, true);
return usb_hid_keyboard;
}
void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard) {
furi_assert(usb_hid_keyboard);
view_free(usb_hid_keyboard->view);
free(usb_hid_keyboard);
}
View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard) {
furi_assert(usb_hid_keyboard);
return usb_hid_keyboard->view;
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <gui/view.h>
typedef struct UsbHidKeyboard UsbHidKeyboard;
UsbHidKeyboard* usb_hid_keyboard_alloc();
void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard);
View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard);
void usb_hid_keyboard_set_connected_status(UsbHidKeyboard* usb_hid_keyboard, bool connected);

View File

@@ -0,0 +1,200 @@
#include "usb_hid_media.h"
#include <furi.h>
#include <furi_hal_usb_hid.h>
#include <gui/elements.h>
struct UsbHidMedia {
View* view;
};
typedef struct {
bool left_pressed;
bool up_pressed;
bool right_pressed;
bool down_pressed;
bool ok_pressed;
bool connected;
} UsbHidMediaModel;
static void usb_hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) {
canvas_draw_triangle(canvas, x, y, 5, 3, dir);
if(dir == CanvasDirectionBottomToTop) {
canvas_draw_dot(canvas, x, y - 1);
} else if(dir == CanvasDirectionTopToBottom) {
canvas_draw_dot(canvas, x, y + 1);
} else if(dir == CanvasDirectionRightToLeft) {
canvas_draw_dot(canvas, x - 1, y);
} else if(dir == CanvasDirectionLeftToRight) {
canvas_draw_dot(canvas, x + 1, y);
}
}
static void usb_hid_media_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
UsbHidMediaModel* model = context;
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media");
canvas_set_font(canvas, FontSecondary);
// Keypad circles
canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47);
// Up
if(model->up_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6);
canvas_set_color(canvas, ColorBlack);
// Down
if(model->down_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6);
canvas_set_color(canvas, ColorBlack);
// Left
if(model->left_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
usb_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft);
usb_hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft);
canvas_set_color(canvas, ColorBlack);
// Right
if(model->right_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
usb_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight);
usb_hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight);
canvas_set_color(canvas, ColorBlack);
// Ok
if(model->ok_pressed) {
canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13);
canvas_set_color(canvas, ColorWhite);
}
usb_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight);
canvas_draw_line(canvas, 100, 29, 100, 33);
canvas_draw_line(canvas, 102, 29, 102, 33);
canvas_set_color(canvas, ColorBlack);
// Exit
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
}
static void usb_hid_media_process_press(UsbHidMedia* usb_hid_media, InputEvent* event) {
with_view_model(
usb_hid_media->view,
UsbHidMediaModel * model,
{
if(event->key == InputKeyUp) {
model->up_pressed = true;
furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT);
} else if(event->key == InputKeyDown) {
model->down_pressed = true;
furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT);
} else if(event->key == InputKeyLeft) {
model->left_pressed = true;
furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_PREVIOUS_TRACK);
} else if(event->key == InputKeyRight) {
model->right_pressed = true;
furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_NEXT_TRACK);
} else if(event->key == InputKeyOk) {
model->ok_pressed = true;
furi_hal_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE);
}
},
true);
}
static void hid_media_process_release(UsbHidMedia* usb_hid_media, InputEvent* event) {
with_view_model(
usb_hid_media->view,
UsbHidMediaModel * model,
{
if(event->key == InputKeyUp) {
model->up_pressed = false;
furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT);
} else if(event->key == InputKeyDown) {
model->down_pressed = false;
furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT);
} else if(event->key == InputKeyLeft) {
model->left_pressed = false;
furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_PREVIOUS_TRACK);
} else if(event->key == InputKeyRight) {
model->right_pressed = false;
furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_NEXT_TRACK);
} else if(event->key == InputKeyOk) {
model->ok_pressed = false;
furi_hal_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE);
}
},
true);
}
static bool usb_hid_media_input_callback(InputEvent* event, void* context) {
furi_assert(context);
UsbHidMedia* usb_hid_media = context;
bool consumed = false;
if(event->type == InputTypePress) {
usb_hid_media_process_press(usb_hid_media, event);
consumed = true;
} else if(event->type == InputTypeRelease) {
hid_media_process_release(usb_hid_media, event);
consumed = true;
} else if(event->type == InputTypeShort) {
if(event->key == InputKeyBack) {
furi_hal_hid_kb_release_all();
}
}
return consumed;
}
UsbHidMedia* usb_hid_media_alloc() {
UsbHidMedia* usb_hid_media = malloc(sizeof(UsbHidMedia));
usb_hid_media->view = view_alloc();
view_set_context(usb_hid_media->view, usb_hid_media);
view_allocate_model(usb_hid_media->view, ViewModelTypeLocking, sizeof(UsbHidMediaModel));
view_set_draw_callback(usb_hid_media->view, usb_hid_media_draw_callback);
view_set_input_callback(usb_hid_media->view, usb_hid_media_input_callback);
with_view_model(
usb_hid_media->view, UsbHidMediaModel * model, { model->connected = true; }, true);
return usb_hid_media;
}
void usb_hid_media_free(UsbHidMedia* usb_hid_media) {
furi_assert(usb_hid_media);
view_free(usb_hid_media->view);
free(usb_hid_media);
}
View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media) {
furi_assert(usb_hid_media);
return usb_hid_media->view;
}
void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected) {
furi_assert(usb_hid_media);
with_view_model(
usb_hid_media->view, UsbHidMediaModel * model, { model->connected = connected; }, true);
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <gui/view.h>
typedef struct UsbHidMedia UsbHidMedia;
UsbHidMedia* usb_hid_media_alloc();
void usb_hid_media_free(UsbHidMedia* usb_hid_media);
View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media);
void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected);

View File

@@ -0,0 +1,214 @@
#include "usb_hid_mouse.h"
#include <furi.h>
#include <furi_hal_usb_hid.h>
#include <gui/elements.h>
struct UsbHidMouse {
View* view;
};
#define MOUSE_MOVE_SHORT 5
#define MOUSE_MOVE_LONG 20
typedef struct {
bool left_pressed;
bool up_pressed;
bool right_pressed;
bool down_pressed;
bool left_mouse_pressed;
bool left_mouse_held;
bool right_mouse_pressed;
bool connected;
} UsbHidMouseModel;
static void usb_hid_mouse_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
UsbHidMouseModel* model = context;
// Header
/*if(model->connected) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
} else {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
}*/
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse");
canvas_set_font(canvas, FontSecondary);
if(model->left_mouse_held == true) {
elements_multiline_text_aligned(canvas, 0, 62, AlignLeft, AlignBottom, "Selecting...");
} else {
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
}
// Keypad circles
canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47);
// Up
if(model->up_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9);
canvas_set_color(canvas, ColorBlack);
// Down
if(model->down_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9);
canvas_set_color(canvas, ColorBlack);
// Left
if(model->left_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7);
canvas_set_color(canvas, ColorBlack);
// Right
if(model->right_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7);
canvas_set_color(canvas, ColorBlack);
// Ok
if(model->left_mouse_pressed) {
canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13);
} else {
canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9);
}
// Back
if(model->right_mouse_pressed) {
canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13);
} else {
canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9);
}
}
static void usb_hid_mouse_process(UsbHidMouse* usb_hid_mouse, InputEvent* event) {
with_view_model(
usb_hid_mouse->view,
UsbHidMouseModel * model,
{
if(event->key == InputKeyBack) {
if(event->type == InputTypeShort) {
furi_hal_hid_mouse_press(HID_MOUSE_BTN_RIGHT);
furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT);
} else if(event->type == InputTypePress) {
model->right_mouse_pressed = true;
} else if(event->type == InputTypeRelease) {
model->right_mouse_pressed = false;
}
} else if(event->key == InputKeyOk) {
if(event->type == InputTypeShort) {
// Just release if it was being held before
if(!model->left_mouse_held) furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT);
furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT);
model->left_mouse_held = false;
} else if(event->type == InputTypeLong) {
furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT);
model->left_mouse_held = true;
model->left_mouse_pressed = true;
} else if(event->type == InputTypePress) {
model->left_mouse_pressed = true;
} else if(event->type == InputTypeRelease) {
// Only release if it wasn't a long press
if(!model->left_mouse_held) model->left_mouse_pressed = false;
}
} else if(event->key == InputKeyRight) {
if(event->type == InputTypePress) {
model->right_pressed = true;
furi_hal_hid_mouse_move(MOUSE_MOVE_SHORT, 0);
} else if(event->type == InputTypeRepeat) {
furi_hal_hid_mouse_move(MOUSE_MOVE_LONG, 0);
} else if(event->type == InputTypeRelease) {
model->right_pressed = false;
}
} else if(event->key == InputKeyLeft) {
if(event->type == InputTypePress) {
model->left_pressed = true;
furi_hal_hid_mouse_move(-MOUSE_MOVE_SHORT, 0);
} else if(event->type == InputTypeRepeat) {
furi_hal_hid_mouse_move(-MOUSE_MOVE_LONG, 0);
} else if(event->type == InputTypeRelease) {
model->left_pressed = false;
}
} else if(event->key == InputKeyDown) {
if(event->type == InputTypePress) {
model->down_pressed = true;
furi_hal_hid_mouse_move(0, MOUSE_MOVE_SHORT);
} else if(event->type == InputTypeRepeat) {
furi_hal_hid_mouse_move(0, MOUSE_MOVE_LONG);
} else if(event->type == InputTypeRelease) {
model->down_pressed = false;
}
} else if(event->key == InputKeyUp) {
if(event->type == InputTypePress) {
model->up_pressed = true;
furi_hal_hid_mouse_move(0, -MOUSE_MOVE_SHORT);
} else if(event->type == InputTypeRepeat) {
furi_hal_hid_mouse_move(0, -MOUSE_MOVE_LONG);
} else if(event->type == InputTypeRelease) {
model->up_pressed = false;
}
}
},
true);
}
static bool usb_hid_mouse_input_callback(InputEvent* event, void* context) {
furi_assert(context);
UsbHidMouse* usb_hid_mouse = context;
bool consumed = false;
if(event->type == InputTypeLong && event->key == InputKeyBack) {
furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT);
furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT);
} else {
usb_hid_mouse_process(usb_hid_mouse, event);
consumed = true;
}
return consumed;
}
UsbHidMouse* usb_hid_mouse_alloc() {
UsbHidMouse* usb_hid_mouse = malloc(sizeof(UsbHidMouse));
usb_hid_mouse->view = view_alloc();
view_set_context(usb_hid_mouse->view, usb_hid_mouse);
view_allocate_model(usb_hid_mouse->view, ViewModelTypeLocking, sizeof(UsbHidMouseModel));
view_set_draw_callback(usb_hid_mouse->view, usb_hid_mouse_draw_callback);
view_set_input_callback(usb_hid_mouse->view, usb_hid_mouse_input_callback);
with_view_model(
usb_hid_mouse->view, UsbHidMouseModel * model, { model->connected = true; }, true);
return usb_hid_mouse;
}
void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse) {
furi_assert(usb_hid_mouse);
view_free(usb_hid_mouse->view);
free(usb_hid_mouse);
}
View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse) {
furi_assert(usb_hid_mouse);
return usb_hid_mouse->view;
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <gui/view.h>
typedef struct UsbHidMouse UsbHidMouse;
UsbHidMouse* usb_hid_mouse_alloc();
void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse);
View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse);
void usb_hid_mouse_set_connected_status(UsbHidMouse* usb_hid_mouse, bool connected);

View File

@@ -146,52 +146,39 @@ View* wav_player_view_get_view(WavPlayerView* wav_view) {
void wav_player_view_set_volume(WavPlayerView* wav_view, float volume) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->volume = volume;
return true;
});
wav_view->view, WavPlayerViewModel * model, { model->volume = volume; }, true);
}
void wav_player_view_set_start(WavPlayerView* wav_view, size_t start) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->start = start;
return true;
});
wav_view->view, WavPlayerViewModel * model, { model->start = start; }, true);
}
void wav_player_view_set_end(WavPlayerView* wav_view, size_t end) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->end = end;
return true;
});
wav_view->view, WavPlayerViewModel * model, { model->end = end; }, true);
}
void wav_player_view_set_current(WavPlayerView* wav_view, size_t current) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->current = current;
return true;
});
wav_view->view, WavPlayerViewModel * model, { model->current = current; }, true);
}
void wav_player_view_set_play(WavPlayerView* wav_view, bool play) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->play = play;
return true;
});
wav_view->view, WavPlayerViewModel * model, { model->play = play; }, true);
}
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
wav_view->view,
WavPlayerViewModel * model,
{
size_t inc = (data_count / DATA_COUNT) - 1;
for(size_t i = 0; i < DATA_COUNT; i++) {
@@ -199,8 +186,8 @@ void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t da
if(model->data[i] > 42) model->data[i] = 42;
data += inc;
}
return true;
});
},
true);
}
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback) {

View File

@@ -8,7 +8,7 @@
#include <toolbox/saved_struct.h>
#include <storage/storage.h>
#define DESKTOP_SETTINGS_VER (5)
#define DESKTOP_SETTINGS_VER (6)
#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME)
#define DESKTOP_SETTINGS_MAGIC (0x17)
@@ -34,6 +34,9 @@
#define MAX_PIN_SIZE 10
#define MIN_PIN_SIZE 4
#define MAX_APP_LENGTH 128
#define FAP_LOADER_APP_NAME "Applications"
typedef struct {
InputKey data[MAX_PIN_SIZE];
@@ -41,8 +44,13 @@ typedef struct {
} PinCode;
typedef struct {
uint16_t favorite_primary;
uint16_t favorite_secondary;
bool is_external;
char name_or_path[MAX_APP_LENGTH];
} FavoriteApp;
typedef struct {
FavoriteApp favorite_primary;
FavoriteApp favorite_secondary;
PinCode pin_code;
uint8_t is_locked;
uint32_t auto_lock_delay_ms;

View File

@@ -114,29 +114,39 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
case DesktopMainEventOpenFavoritePrimary:
DESKTOP_SETTINGS_LOAD(&desktop->settings);
if(desktop->settings.favorite_primary < FLIPPER_APPS_COUNT) {
if(desktop->settings.favorite_primary.is_external) {
LoaderStatus status = loader_start(
desktop->loader, FLIPPER_APPS[desktop->settings.favorite_primary].name, NULL);
desktop->loader,
FAP_LOADER_APP_NAME,
desktop->settings.favorite_primary.name_or_path);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
} else {
FURI_LOG_E(TAG, "Can't find primary favorite application");
LoaderStatus status = loader_start(
desktop->loader, desktop->settings.favorite_primary.name_or_path, NULL);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
}
consumed = true;
break;
case DesktopMainEventOpenFavoriteSecondary:
DESKTOP_SETTINGS_LOAD(&desktop->settings);
if(desktop->settings.favorite_secondary < FLIPPER_APPS_COUNT) {
if(desktop->settings.favorite_secondary.is_external) {
LoaderStatus status = loader_start(
desktop->loader,
FLIPPER_APPS[desktop->settings.favorite_secondary].name,
NULL);
FAP_LOADER_APP_NAME,
desktop->settings.favorite_secondary.name_or_path);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
} else {
FURI_LOG_E(TAG, "Can't find secondary favorite application");
LoaderStatus status = loader_start(
desktop->loader, desktop->settings.favorite_secondary.name_or_path, NULL);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
}
consumed = true;
break;
@@ -165,8 +175,8 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
break;
}
case DesktopMainEventOpenGameMenu: {
LoaderStatus status =
loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/Snake.fap"));
LoaderStatus status = loader_start(
desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/Snake.fap"));
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}

View File

@@ -124,16 +124,17 @@ bool desktop_debug_input(InputEvent* event, void* context) {
DesktopViewStatsScreens current = 0;
with_view_model(
debug_view->view, (DesktopDebugViewModel * model) {
debug_view->view,
DesktopDebugViewModel * model,
{
#ifdef SRV_DOLPHIN_STATE_DEBUG
if((event->key == InputKeyDown) || (event->key == InputKeyUp)) {
model->screen = !model->screen;
}
#endif
current = model->screen;
return true;
});
},
true);
size_t count = (event->type == InputTypeRepeat) ? 10 : 1;
if(current == DesktopViewStatsMeta) {
@@ -181,20 +182,19 @@ void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) {
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
DolphinStats stats = dolphin_stats(dolphin);
with_view_model(
debug_view->view, (DesktopDebugViewModel * model) {
debug_view->view,
DesktopDebugViewModel * model,
{
model->icounter = stats.icounter;
model->butthurt = stats.butthurt;
model->timestamp = stats.timestamp;
return true;
});
},
true);
furi_record_close(RECORD_DOLPHIN);
}
void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view) {
with_view_model(
debug_view->view, (DesktopDebugViewModel * model) {
model->screen = 0;
return true;
});
debug_view->view, DesktopDebugViewModel * model, { model->screen = 0; }, true);
}

View File

@@ -24,27 +24,24 @@ void desktop_lock_menu_set_callback(
void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set) {
with_view_model(
lock_menu->view, (DesktopLockMenuViewModel * model) {
model->pin_is_set = pin_is_set;
return true;
});
lock_menu->view,
DesktopLockMenuViewModel * model,
{ model->pin_is_set = pin_is_set; },
true);
}
void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode) {
with_view_model(
lock_menu->view, (DesktopLockMenuViewModel * model) {
model->dummy_mode = dummy_mode;
return true;
});
lock_menu->view,
DesktopLockMenuViewModel * model,
{ model->dummy_mode = dummy_mode; },
true);
}
void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) {
furi_assert(idx < DesktopLockMenuIndexTotalCount);
with_view_model(
lock_menu->view, (DesktopLockMenuViewModel * model) {
model->idx = idx;
return true;
});
lock_menu->view, DesktopLockMenuViewModel * model, { model->idx = idx; }, true);
}
void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) {
@@ -95,10 +92,12 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
uint8_t idx = 0;
bool consumed = false;
bool dummy_mode = false;
bool update = false;
with_view_model(
lock_menu->view, (DesktopLockMenuViewModel * model) {
bool ret = false;
lock_menu->view,
DesktopLockMenuViewModel * model,
{
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
if(event->key == InputKeyUp) {
if(model->idx == 0) {
@@ -106,7 +105,7 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
} else {
model->idx = CLAMP(model->idx - 1, DesktopLockMenuIndexTotalCount - 1, 0);
}
ret = true;
update = true;
consumed = true;
} else if(event->key == InputKeyDown) {
if(model->idx == DesktopLockMenuIndexTotalCount - 1) {
@@ -114,14 +113,14 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
} else {
model->idx = CLAMP(model->idx + 1, DesktopLockMenuIndexTotalCount - 1, 0);
}
ret = true;
update = true;
consumed = true;
}
}
idx = model->idx;
dummy_mode = model->dummy_mode;
return ret;
});
},
update);
if(event->key == InputKeyOk) {
if((idx == DesktopLockMenuIndexLock) && (event->type == InputTypeShort)) {

View File

@@ -148,28 +148,32 @@ static void button_menu_process_up(ButtonMenu* button_menu) {
furi_assert(button_menu);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
button_menu->view,
ButtonMenuModel * model,
{
if(model->position > 0) {
model->position--;
} else {
model->position = ButtonMenuItemArray_size(model->items) - 1;
}
return true;
});
},
true);
}
static void button_menu_process_down(ButtonMenu* button_menu) {
furi_assert(button_menu);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
button_menu->view,
ButtonMenuModel * model,
{
if(model->position < (ButtonMenuItemArray_size(model->items) - 1)) {
model->position++;
} else {
model->position = 0;
}
return true;
});
},
true);
}
static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) {
@@ -178,12 +182,14 @@ static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) {
ButtonMenuItem* item = NULL;
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
button_menu->view,
ButtonMenuModel * model,
{
if(model->position < (ButtonMenuItemArray_size(model->items))) {
item = ButtonMenuItemArray_get(model->items, model->position);
}
return false;
});
},
false);
if(item) {
if(item->type == ButtonMenuItemTypeControl) {
@@ -248,22 +254,21 @@ void button_menu_reset(ButtonMenu* button_menu) {
furi_assert(button_menu);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
button_menu->view,
ButtonMenuModel * model,
{
ButtonMenuItemArray_reset(model->items);
model->position = 0;
model->header = NULL;
return true;
});
},
true);
}
void button_menu_set_header(ButtonMenu* button_menu, const char* header) {
furi_assert(button_menu);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
model->header = header;
return true;
});
button_menu->view, ButtonMenuModel * model, { model->header = header; }, true);
}
ButtonMenuItem* button_menu_add_item(
@@ -278,15 +283,17 @@ ButtonMenuItem* button_menu_add_item(
furi_assert(button_menu);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
button_menu->view,
ButtonMenuModel * model,
{
item = ButtonMenuItemArray_push_new(model->items);
item->label = label;
item->index = index;
item->type = type;
item->callback = callback;
item->callback_context = callback_context;
return true;
});
},
true);
return item;
}
@@ -301,12 +308,14 @@ ButtonMenu* button_menu_alloc(void) {
view_set_input_callback(button_menu->view, button_menu_view_input_callback);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
button_menu->view,
ButtonMenuModel * model,
{
ButtonMenuItemArray_init(model->items);
model->position = 0;
model->header = NULL;
return true;
});
},
true);
button_menu->freeze_input = false;
return button_menu;
@@ -316,10 +325,10 @@ void button_menu_free(ButtonMenu* button_menu) {
furi_assert(button_menu);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
ButtonMenuItemArray_clear(model->items);
return true;
});
button_menu->view,
ButtonMenuModel * model,
{ ButtonMenuItemArray_clear(model->items); },
true);
view_free(button_menu->view);
free(button_menu);
}
@@ -328,7 +337,9 @@ void button_menu_set_selected_item(ButtonMenu* button_menu, uint32_t index) {
furi_assert(button_menu);
with_view_model(
button_menu->view, (ButtonMenuModel * model) {
button_menu->view,
ButtonMenuModel * model,
{
uint8_t item_position = 0;
ButtonMenuItemArray_it_t it;
for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it);
@@ -338,6 +349,6 @@ void button_menu_set_selected_item(ButtonMenu* button_menu, uint32_t index) {
break;
}
}
return true;
});
},
true);
}

View File

@@ -70,26 +70,30 @@ ButtonPanel* button_panel_alloc() {
view_set_input_callback(button_panel->view, button_panel_view_input_callback);
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
model->reserve_x = 0;
model->reserve_y = 0;
model->selected_item_x = 0;
model->selected_item_y = 0;
ButtonMatrix_init(model->button_matrix);
LabelList_init(model->labels);
return true;
});
},
true);
return button_panel;
}
void button_panel_reset_selection(ButtonPanel* button_panel) {
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
model->selected_item_x = 0;
model->selected_item_y = 0;
return true;
});
},
true);
}
void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y) {
@@ -97,7 +101,9 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re
furi_check(reserve_y > 0);
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
model->reserve_x = reserve_x;
model->reserve_y = reserve_y;
ButtonMatrix_reserve(model->button_matrix, model->reserve_y);
@@ -108,8 +114,8 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re
// TODO: do we need to clear allocated memory of ptr-s to ButtonItem ??
}
LabelList_init(model->labels);
return true;
});
},
true);
}
void button_panel_free(ButtonPanel* button_panel) {
@@ -118,11 +124,13 @@ void button_panel_free(ButtonPanel* button_panel) {
button_panel_reset(button_panel);
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
LabelList_clear(model->labels);
ButtonMatrix_clear(model->button_matrix);
return true;
});
},
true);
view_free(button_panel->view);
free(button_panel);
@@ -132,7 +140,9 @@ void button_panel_reset(ButtonPanel* button_panel) {
furi_assert(button_panel);
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
for(size_t x = 0; x < model->reserve_x; ++x) {
for(size_t y = 0; y < model->reserve_y; ++y) {
ButtonItem** button_item = button_panel_get_item(model, x, y);
@@ -146,8 +156,8 @@ void button_panel_reset(ButtonPanel* button_panel) {
model->selected_item_y = 0;
LabelList_reset(model->labels);
ButtonMatrix_reset(model->button_matrix);
return true;
});
},
true);
}
static ButtonItem** button_panel_get_item(ButtonPanelModel* model, size_t x, size_t y) {
@@ -174,7 +184,9 @@ void button_panel_add_item(
furi_assert(button_panel);
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
ButtonItem** button_item_ptr =
button_panel_get_item(model, matrix_place_x, matrix_place_y);
furi_check(*button_item_ptr == NULL);
@@ -187,8 +199,8 @@ void button_panel_add_item(
button_item->icon.name = icon_name;
button_item->icon.name_selected = icon_name_selected;
button_item->index = index;
return true;
});
},
true);
}
View* button_panel_get_view(ButtonPanel* button_panel) {
@@ -225,114 +237,123 @@ static void button_panel_view_draw_callback(Canvas* canvas, void* _model) {
static void button_panel_process_down(ButtonPanel* button_panel) {
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
uint16_t new_selected_item_x = model->selected_item_x;
uint16_t new_selected_item_y = model->selected_item_y;
size_t i;
if(new_selected_item_y >= (model->reserve_y - 1)) return false;
if(new_selected_item_y < (model->reserve_y - 1)) {
++new_selected_item_y;
++new_selected_item_y;
for(i = 0; i < model->reserve_x; ++i) {
new_selected_item_x = (model->selected_item_x + i) % model->reserve_x;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
for(i = 0; i < model->reserve_x; ++i) {
new_selected_item_x = (model->selected_item_x + i) % model->reserve_x;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
}
}
if(i != model->reserve_x) {
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
}
}
if(i == model->reserve_x) return false;
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
return true;
});
},
true);
}
static void button_panel_process_up(ButtonPanel* button_panel) {
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
size_t new_selected_item_x = model->selected_item_x;
size_t new_selected_item_y = model->selected_item_y;
size_t i;
if(new_selected_item_y <= 0) return false;
if(new_selected_item_y > 0) {
--new_selected_item_y;
--new_selected_item_y;
for(i = 0; i < model->reserve_x; ++i) {
new_selected_item_x = (model->selected_item_x + i) % model->reserve_x;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
for(i = 0; i < model->reserve_x; ++i) {
new_selected_item_x = (model->selected_item_x + i) % model->reserve_x;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
}
}
if(i != model->reserve_x) {
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
}
}
if(i == model->reserve_x) return false;
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
return true;
});
},
true);
}
static void button_panel_process_left(ButtonPanel* button_panel) {
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
size_t new_selected_item_x = model->selected_item_x;
size_t new_selected_item_y = model->selected_item_y;
size_t i;
if(new_selected_item_x <= 0) return false;
if(new_selected_item_x > 0) {
--new_selected_item_x;
--new_selected_item_x;
for(i = 0; i < model->reserve_y; ++i) {
new_selected_item_y = (model->selected_item_y + i) % model->reserve_y;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
for(i = 0; i < model->reserve_y; ++i) {
new_selected_item_y = (model->selected_item_y + i) % model->reserve_y;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
}
}
if(i != model->reserve_y) {
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
}
}
if(i == model->reserve_y) return false;
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
return true;
});
},
true);
}
static void button_panel_process_right(ButtonPanel* button_panel) {
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
uint16_t new_selected_item_x = model->selected_item_x;
uint16_t new_selected_item_y = model->selected_item_y;
size_t i;
if(new_selected_item_x >= (model->reserve_x - 1)) return false;
if(new_selected_item_x < (model->reserve_x - 1)) {
++new_selected_item_x;
++new_selected_item_x;
for(i = 0; i < model->reserve_y; ++i) {
new_selected_item_y = (model->selected_item_y + i) % model->reserve_y;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
for(i = 0; i < model->reserve_y; ++i) {
new_selected_item_y = (model->selected_item_y + i) % model->reserve_y;
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
break;
}
}
if(i != model->reserve_y) {
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
}
}
if(i == model->reserve_y) return false;
model->selected_item_x = new_selected_item_x;
model->selected_item_y = new_selected_item_y;
return true;
});
},
true);
}
void button_panel_process_ok(ButtonPanel* button_panel) {
ButtonItem* button_item = NULL;
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
button_item =
*button_panel_get_item(model, model->selected_item_x, model->selected_item_y);
return true;
});
},
true);
if(button_item && button_item->callback) {
button_item->callback(button_item->callback_context, button_item->index);
@@ -383,12 +404,14 @@ void button_panel_add_label(
furi_assert(button_panel);
with_view_model(
button_panel->view, (ButtonPanelModel * model) {
button_panel->view,
ButtonPanelModel * model,
{
LabelElement* label = LabelList_push_raw(model->labels);
label->x = x;
label->y = y;
label->font = font;
label->str = label_str;
return true;
});
},
true);
}

View File

@@ -618,42 +618,30 @@ static bool byte_input_view_input_callback(InputEvent* event, void* context) {
switch(event->key) {
case InputKeyLeft:
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input_handle_left(model);
return true;
});
byte_input->view, ByteInputModel * model, { byte_input_handle_left(model); }, true);
consumed = true;
break;
case InputKeyRight:
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input_handle_right(model);
return true;
});
byte_input->view,
ByteInputModel * model,
{ byte_input_handle_right(model); },
true);
consumed = true;
break;
case InputKeyUp:
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input_handle_up(model);
return true;
});
byte_input->view, ByteInputModel * model, { byte_input_handle_up(model); }, true);
consumed = true;
break;
case InputKeyDown:
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input_handle_down(model);
return true;
});
byte_input->view, ByteInputModel * model, { byte_input_handle_down(model); }, true);
consumed = true;
break;
case InputKeyOk:
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input_handle_ok(model);
return true;
});
byte_input->view, ByteInputModel * model, { byte_input_handle_ok(model); }, true);
consumed = true;
break;
default:
@@ -664,10 +652,10 @@ static bool byte_input_view_input_callback(InputEvent* event, void* context) {
if((event->type == InputTypeLong || event->type == InputTypeRepeat) &&
event->key == InputKeyBack) {
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input_clear_selected_byte(model);
return true;
});
byte_input->view,
ByteInputModel * model,
{ byte_input_clear_selected_byte(model); },
true);
consumed = true;
}
@@ -703,14 +691,16 @@ ByteInput* byte_input_alloc() {
view_set_input_callback(byte_input->view, byte_input_view_input_callback);
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input->view,
ByteInputModel * model,
{
model->header = "";
model->input_callback = NULL;
model->changed_callback = NULL;
model->callback_context = NULL;
byte_input_reset_model_input_data(model);
return true;
});
},
true);
return byte_input;
}
@@ -755,15 +745,17 @@ void byte_input_set_result_callback(
uint8_t* bytes,
uint8_t bytes_count) {
with_view_model(
byte_input->view, (ByteInputModel * model) {
byte_input->view,
ByteInputModel * model,
{
byte_input_reset_model_input_data(model);
model->input_callback = input_callback;
model->changed_callback = changed_callback;
model->callback_context = callback_context;
model->bytes = bytes;
model->bytes_count = bytes_count;
return true;
});
},
true);
}
/**
@@ -774,8 +766,5 @@ void byte_input_set_result_callback(
*/
void byte_input_set_header_text(ByteInput* byte_input, const char* text) {
with_view_model(
byte_input->view, (ByteInputModel * model) {
model->header = text;
return true;
});
byte_input->view, ByteInputModel * model, { model->header = text; }, true);
}

View File

@@ -90,12 +90,14 @@ static bool dialog_ex_view_input_callback(InputEvent* event, void* context) {
const char* right_text = NULL;
with_view_model(
dialog_ex->view, (DialogExModel * model) {
dialog_ex->view,
DialogExModel * model,
{
left_text = model->left_text;
center_text = model->center_text;
right_text = model->right_text;
return true;
});
},
true);
if(dialog_ex->callback) {
if(event->type == InputTypeShort) {
@@ -149,7 +151,9 @@ DialogEx* dialog_ex_alloc() {
view_set_draw_callback(dialog_ex->view, dialog_ex_view_draw_callback);
view_set_input_callback(dialog_ex->view, dialog_ex_view_input_callback);
with_view_model(
dialog_ex->view, (DialogExModel * model) {
dialog_ex->view,
DialogExModel * model,
{
model->header.text = NULL;
model->header.x = 0;
model->header.y = 0;
@@ -169,9 +173,8 @@ DialogEx* dialog_ex_alloc() {
model->left_text = NULL;
model->center_text = NULL;
model->right_text = NULL;
return true;
});
},
true);
dialog_ex->enable_extended_events = false;
return dialog_ex;
}
@@ -206,14 +209,16 @@ void dialog_ex_set_header(
Align vertical) {
furi_assert(dialog_ex);
with_view_model(
dialog_ex->view, (DialogExModel * model) {
dialog_ex->view,
DialogExModel * model,
{
model->header.text = text;
model->header.x = x;
model->header.y = y;
model->header.horizontal = horizontal;
model->header.vertical = vertical;
return true;
});
},
true);
}
void dialog_ex_set_text(
@@ -225,52 +230,47 @@ void dialog_ex_set_text(
Align vertical) {
furi_assert(dialog_ex);
with_view_model(
dialog_ex->view, (DialogExModel * model) {
dialog_ex->view,
DialogExModel * model,
{
model->text.text = text;
model->text.x = x;
model->text.y = y;
model->text.horizontal = horizontal;
model->text.vertical = vertical;
return true;
});
},
true);
}
void dialog_ex_set_icon(DialogEx* dialog_ex, uint8_t x, uint8_t y, const Icon* icon) {
furi_assert(dialog_ex);
with_view_model(
dialog_ex->view, (DialogExModel * model) {
dialog_ex->view,
DialogExModel * model,
{
model->icon.x = x;
model->icon.y = y;
model->icon.icon = icon;
return true;
});
},
true);
}
void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text) {
furi_assert(dialog_ex);
with_view_model(
dialog_ex->view, (DialogExModel * model) {
model->left_text = text;
return true;
});
dialog_ex->view, DialogExModel * model, { model->left_text = text; }, true);
}
void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text) {
furi_assert(dialog_ex);
with_view_model(
dialog_ex->view, (DialogExModel * model) {
model->center_text = text;
return true;
});
dialog_ex->view, DialogExModel * model, { model->center_text = text; }, true);
}
void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) {
furi_assert(dialog_ex);
with_view_model(
dialog_ex->view, (DialogExModel * model) {
model->right_text = text;
return true;
});
dialog_ex->view, DialogExModel * model, { model->right_text = text; }, true);
}
void dialog_ex_reset(DialogEx* dialog_ex) {
@@ -279,15 +279,17 @@ void dialog_ex_reset(DialogEx* dialog_ex) {
.text = NULL, .x = 0, .y = 0, .horizontal = AlignLeft, .vertical = AlignLeft};
IconElement clean_icon_el = {.icon = NULL, .x = 0, .y = 0};
with_view_model(
dialog_ex->view, (DialogExModel * model) {
dialog_ex->view,
DialogExModel * model,
{
model->header = clean_text_el;
model->text = clean_text_el;
model->icon = clean_icon_el;
model->left_text = NULL;
model->center_text = NULL;
model->right_text = NULL;
return true;
});
},
true);
dialog_ex->context = NULL;
dialog_ex->callback = NULL;
}

View File

@@ -139,10 +139,7 @@ FileBrowser* file_browser_alloc(FuriString* result_path) {
browser->result_path = result_path;
with_view_model(
browser->view, (FileBrowserModel * model) {
items_array_init(model->items);
return false;
});
browser->view, FileBrowserModel * model, { items_array_init(model->items); }, false);
return browser;
}
@@ -151,10 +148,7 @@ void file_browser_free(FileBrowser* browser) {
furi_assert(browser);
with_view_model(
browser->view, (FileBrowserModel * model) {
items_array_clear(model->items);
return false;
});
browser->view, FileBrowserModel * model, { items_array_clear(model->items); }, false);
view_free(browser->view);
free(browser);
@@ -178,11 +172,13 @@ void file_browser_configure(
browser->hide_ext = hide_ext;
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
model->file_icon = file_icon;
model->hide_ext = hide_ext;
return false;
});
},
false);
}
void file_browser_start(FileBrowser* browser, FuriString* path) {
@@ -199,14 +195,16 @@ void file_browser_stop(FileBrowser* browser) {
furi_assert(browser);
file_browser_worker_free(browser->worker);
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
items_array_reset(model->items);
model->item_cnt = 0;
model->item_idx = 0;
model->array_offset = 0;
model->list_offset = 0;
return false;
});
},
false);
}
void file_browser_set_callback(FileBrowser* browser, FileBrowserCallback callback, void* context) {
@@ -257,7 +255,9 @@ static void browser_update_offset(FileBrowser* browser) {
furi_assert(browser);
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
uint16_t bounds = model->item_cnt > (LIST_ITEMS - 1) ? 2 : model->item_cnt;
if((model->item_cnt > (LIST_ITEMS - 1)) &&
@@ -272,9 +272,8 @@ static void browser_update_offset(FileBrowser* browser) {
model->list_offset =
CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0);
}
return false;
});
},
false);
}
static void
@@ -285,7 +284,9 @@ static void
int32_t load_offset = 0;
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
items_array_reset(model->items);
if(is_root) {
model->item_cnt = item_cnt;
@@ -303,8 +304,8 @@ static void
model->is_root = is_root;
model->list_loading = true;
model->folder_loading = false;
return true;
});
},
true);
browser_update_offset(browser);
file_browser_worker_load(browser->worker, load_offset, ITEM_LIST_LEN_MAX);
@@ -319,7 +320,9 @@ static void browser_list_load_cb(void* context, uint32_t list_load_offset) {
back_item.type = BrowserItemTypeBack;
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
items_array_reset(model->items);
model->array_offset = list_load_offset;
if(!model->is_root) {
@@ -329,8 +332,8 @@ static void browser_list_load_cb(void* context, uint32_t list_load_offset) {
model->array_offset += 1;
}
}
return false;
});
},
true);
BrowserItem_t_clear(&back_item);
}
@@ -371,11 +374,13 @@ static void
}
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
items_array_push_back(model->items, item);
// TODO: calculate if element is visible
return true;
});
},
true);
furi_string_free(item.display_name);
furi_string_free(item.path);
if(item.custom_icon_data) {
@@ -383,10 +388,7 @@ static void
}
} else {
with_view_model(
browser->view, (FileBrowserModel * model) {
model->list_loading = false;
return true;
});
browser->view, FileBrowserModel * model, { model->list_loading = false; }, true);
}
}
@@ -395,10 +397,7 @@ static void browser_long_load_cb(void* context) {
FileBrowser* browser = (FileBrowser*)context;
with_view_model(
browser->view, (FileBrowserModel * model) {
model->folder_loading = true;
return true;
});
browser->view, FileBrowserModel * model, { model->folder_loading = true; }, true);
}
static void browser_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
@@ -508,17 +507,16 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
bool is_loading = false;
with_view_model(
browser->view, (FileBrowserModel * model) {
is_loading = model->folder_loading;
return false;
});
browser->view, FileBrowserModel * model, { is_loading = model->folder_loading; }, false);
if(is_loading) {
return false;
} else if(event->key == InputKeyUp || event->key == InputKeyDown) {
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
if(event->key == InputKeyUp) {
model->item_idx =
((model->item_idx - 1) + model->item_cnt) % model->item_cnt;
@@ -543,8 +541,8 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
browser->worker, load_offset, ITEM_LIST_LEN_MAX);
}
}
return true;
});
},
true);
browser_update_offset(browser);
consumed = true;
}
@@ -553,7 +551,9 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
BrowserItem_t* selected_item = NULL;
int32_t select_index = 0;
with_view_model(
browser->view, (FileBrowserModel * model) {
browser->view,
FileBrowserModel * model,
{
if(browser_is_item_in_array(model, model->item_idx)) {
selected_item =
items_array_get(model->items, model->item_idx - model->array_offset);
@@ -562,8 +562,8 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
select_index -= 1;
}
}
return false;
});
},
false);
if(selected_item) {
if(selected_item->type == BrowserItemTypeBack) {
@@ -584,10 +584,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
if(event->type == InputTypeShort) {
bool is_root = false;
with_view_model(
browser->view, (FileBrowserModel * model) {
is_root = model->is_root;
return false;
});
browser->view, FileBrowserModel * model, { is_root = model->is_root; }, false);
if(!is_root) {
file_browser_worker_folder_exit(browser->worker);
}

View File

@@ -103,25 +103,29 @@ static bool menu_input_callback(InputEvent* event, void* context) {
static void menu_enter(void* context) {
Menu* menu = context;
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_start(item->icon);
}
return false;
});
},
false);
}
static void menu_exit(void* context) {
Menu* menu = context;
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_stop(item->icon);
}
return false;
});
},
false);
}
Menu* menu_alloc() {
@@ -135,11 +139,13 @@ Menu* menu_alloc() {
view_set_exit_callback(menu->view, menu_exit);
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
MenuItemArray_init(model->items);
model->position = 0;
return true;
});
},
true);
return menu;
}
@@ -168,7 +174,9 @@ void menu_add_item(
MenuItem* item = NULL;
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
item = MenuItemArray_push_new(model->items);
item->label = label;
item->icon = icon ? icon_animation_alloc(icon) : icon_animation_alloc(&A_Plugins_14);
@@ -176,14 +184,16 @@ void menu_add_item(
item->index = index;
item->callback = callback;
item->callback_context = context;
return true;
});
},
true);
}
void menu_reset(Menu* menu) {
furi_assert(menu);
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
for
M_EACH(item, model->items, MenuItemArray_t) {
icon_animation_stop(item->icon);
@@ -192,25 +202,27 @@ void menu_reset(Menu* menu) {
MenuItemArray_reset(model->items);
model->position = 0;
return true;
});
},
true);
}
void menu_set_selected_item(Menu* menu, uint32_t index) {
with_view_model(
menu->view, (MenuModel * model) {
if(index >= MenuItemArray_size(model->items)) {
return false;
menu->view,
MenuModel * model,
{
if(index < MenuItemArray_size(model->items)) {
model->position = index;
}
model->position = index;
return true;
});
},
true);
}
static void menu_process_up(Menu* menu) {
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_stop(item->icon);
@@ -226,13 +238,15 @@ static void menu_process_up(Menu* menu) {
if(item && item->icon) {
icon_animation_start(item->icon);
}
return true;
});
},
true);
}
static void menu_process_down(Menu* menu) {
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_stop(item->icon);
@@ -248,19 +262,21 @@ static void menu_process_down(Menu* menu) {
if(item && item->icon) {
icon_animation_start(item->icon);
}
return true;
});
},
true);
}
static void menu_process_ok(Menu* menu) {
MenuItem* item = NULL;
with_view_model(
menu->view, (MenuModel * model) {
menu->view,
MenuModel * model,
{
if(model->position < MenuItemArray_size(model->items)) {
item = MenuItemArray_get(model->items, model->position);
}
return true;
});
},
true);
if(item && item->callback) {
item->callback(item->callback_context, item->index);
}

View File

@@ -124,7 +124,9 @@ Popup* popup_alloc() {
view_set_exit_callback(popup->view, popup_stop_timer);
with_view_model(
popup->view, (PopupModel * model) {
popup->view,
PopupModel * model,
{
model->header.text = NULL;
model->header.x = 0;
model->header.y = 0;
@@ -140,8 +142,8 @@ Popup* popup_alloc() {
model->icon.x = 0;
model->icon.y = 0;
model->icon.icon = NULL;
return true;
});
},
true);
return popup;
}
@@ -176,14 +178,16 @@ void popup_set_header(
Align vertical) {
furi_assert(popup);
with_view_model(
popup->view, (PopupModel * model) {
popup->view,
PopupModel * model,
{
model->header.text = text;
model->header.x = x;
model->header.y = y;
model->header.horizontal = horizontal;
model->header.vertical = vertical;
return true;
});
},
true);
}
void popup_set_text(
@@ -195,25 +199,29 @@ void popup_set_text(
Align vertical) {
furi_assert(popup);
with_view_model(
popup->view, (PopupModel * model) {
popup->view,
PopupModel * model,
{
model->text.text = text;
model->text.x = x;
model->text.y = y;
model->text.horizontal = horizontal;
model->text.vertical = vertical;
return true;
});
},
true);
}
void popup_set_icon(Popup* popup, uint8_t x, uint8_t y, const Icon* icon) {
furi_assert(popup);
with_view_model(
popup->view, (PopupModel * model) {
popup->view,
PopupModel * model,
{
model->icon.x = x;
model->icon.y = y;
model->icon.icon = icon;
return true;
});
},
true);
}
void popup_set_timeout(Popup* popup, uint32_t timeout_in_ms) {
@@ -233,12 +241,14 @@ void popup_reset(Popup* popup) {
furi_assert(popup);
with_view_model(
popup->view, (PopupModel * model) {
popup->view,
PopupModel * model,
{
memset(&model->header, 0, sizeof(model->header));
memset(&model->text, 0, sizeof(model->text));
memset(&model->icon, 0, sizeof(model->icon));
return false;
});
},
false);
popup->callback = NULL;
popup->context = NULL;
popup->timer_enabled = false;

View File

@@ -128,13 +128,15 @@ Submenu* submenu_alloc() {
view_set_input_callback(submenu->view, submenu_view_input_callback);
with_view_model(
submenu->view, (SubmenuModel * model) {
submenu->view,
SubmenuModel * model,
{
SubmenuItemArray_init(model->items);
model->position = 0;
model->window_position = 0;
model->header = NULL;
return true;
});
},
true);
return submenu;
}
@@ -143,10 +145,7 @@ void submenu_free(Submenu* submenu) {
furi_assert(submenu);
with_view_model(
submenu->view, (SubmenuModel * model) {
SubmenuItemArray_clear(model->items);
return true;
});
submenu->view, SubmenuModel * model, { SubmenuItemArray_clear(model->items); }, true);
view_free(submenu->view);
free(submenu);
}
@@ -167,32 +166,38 @@ void submenu_add_item(
furi_assert(submenu);
with_view_model(
submenu->view, (SubmenuModel * model) {
submenu->view,
SubmenuModel * model,
{
item = SubmenuItemArray_push_new(model->items);
item->label = label;
item->index = index;
item->callback = callback;
item->callback_context = callback_context;
return true;
});
},
true);
}
void submenu_reset(Submenu* submenu) {
furi_assert(submenu);
with_view_model(
submenu->view, (SubmenuModel * model) {
submenu->view,
SubmenuModel * model,
{
SubmenuItemArray_reset(model->items);
model->position = 0;
model->window_position = 0;
model->header = NULL;
return true;
});
},
true);
}
void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
with_view_model(
submenu->view, (SubmenuModel * model) {
submenu->view,
SubmenuModel * model,
{
uint32_t position = 0;
SubmenuItemArray_it_t it;
for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it);
@@ -225,14 +230,15 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
(SubmenuItemArray_size(model->items) - items_on_screen);
}
}
return true;
});
},
true);
}
void submenu_process_up(Submenu* submenu) {
with_view_model(
submenu->view, (SubmenuModel * model) {
submenu->view,
SubmenuModel * model,
{
uint8_t items_on_screen = model->header ? 3 : 4;
if(model->position > 0) {
model->position--;
@@ -246,13 +252,15 @@ void submenu_process_up(Submenu* submenu) {
model->window_position = model->position - (items_on_screen - 1);
}
}
return true;
});
},
true);
}
void submenu_process_down(Submenu* submenu) {
with_view_model(
submenu->view, (SubmenuModel * model) {
submenu->view,
SubmenuModel * model,
{
uint8_t items_on_screen = model->header ? 3 : 4;
if(model->position < (SubmenuItemArray_size(model->items) - 1)) {
model->position++;
@@ -265,20 +273,22 @@ void submenu_process_down(Submenu* submenu) {
model->position = 0;
model->window_position = 0;
}
return true;
});
},
true);
}
void submenu_process_ok(Submenu* submenu) {
SubmenuItem* item = NULL;
with_view_model(
submenu->view, (SubmenuModel * model) {
submenu->view,
SubmenuModel * model,
{
if(model->position < (SubmenuItemArray_size(model->items))) {
item = SubmenuItemArray_get(model->items, model->position);
}
return true;
});
},
true);
if(item && item->callback) {
item->callback(item->callback_context, item->index);
@@ -289,8 +299,5 @@ void submenu_set_header(Submenu* submenu, const char* header) {
furi_assert(submenu);
with_view_model(
submenu->view, (SubmenuModel * model) {
model->header = header;
return true;
});
submenu->view, SubmenuModel * model, { model->header = header; }, true);
}

View File

@@ -21,20 +21,24 @@ typedef struct {
static void text_box_process_down(TextBox* text_box) {
with_view_model(
text_box->view, (TextBoxModel * model) {
text_box->view,
TextBoxModel * model,
{
if(model->scroll_pos < model->scroll_num - 1) {
model->scroll_pos++;
// Search next line start
while(*model->text_pos++ != '\n')
;
}
return true;
});
},
true);
}
static void text_box_process_up(TextBox* text_box) {
with_view_model(
text_box->view, (TextBoxModel * model) {
text_box->view,
TextBoxModel * model,
{
if(model->scroll_pos > 0) {
model->scroll_pos--;
// Reach last symbol of previous line
@@ -46,8 +50,8 @@ static void text_box_process_up(TextBox* text_box) {
model->text_pos++;
}
}
return true;
});
},
true);
}
static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) {
@@ -137,13 +141,15 @@ TextBox* text_box_alloc() {
view_set_input_callback(text_box->view, text_box_view_input_callback);
with_view_model(
text_box->view, (TextBoxModel * model) {
text_box->view,
TextBoxModel * model,
{
model->text = NULL;
model->text_formatted = furi_string_alloc_set("");
model->formatted = false;
model->font = TextBoxFontText;
return true;
});
},
true);
return text_box;
}
@@ -152,10 +158,7 @@ void text_box_free(TextBox* text_box) {
furi_assert(text_box);
with_view_model(
text_box->view, (TextBoxModel * model) {
furi_string_free(model->text_formatted);
return true;
});
text_box->view, TextBoxModel * model, { furi_string_free(model->text_formatted); }, true);
view_free(text_box->view);
free(text_box);
}
@@ -169,13 +172,15 @@ void text_box_reset(TextBox* text_box) {
furi_assert(text_box);
with_view_model(
text_box->view, (TextBoxModel * model) {
text_box->view,
TextBoxModel * model,
{
model->text = NULL;
furi_string_set(model->text_formatted, "");
model->font = TextBoxFontText;
model->focus = TextBoxFocusStart;
return true;
});
},
true);
}
void text_box_set_text(TextBox* text_box, const char* text) {
@@ -183,31 +188,27 @@ void text_box_set_text(TextBox* text_box, const char* text) {
furi_assert(text);
with_view_model(
text_box->view, (TextBoxModel * model) {
text_box->view,
TextBoxModel * model,
{
model->text = text;
furi_string_reset(model->text_formatted);
furi_string_reserve(model->text_formatted, strlen(text));
model->formatted = false;
return true;
});
},
true);
}
void text_box_set_font(TextBox* text_box, TextBoxFont font) {
furi_assert(text_box);
with_view_model(
text_box->view, (TextBoxModel * model) {
model->font = font;
return true;
});
text_box->view, TextBoxModel * model, { model->font = font; }, true);
}
void text_box_set_focus(TextBox* text_box, TextBoxFocus focus) {
furi_assert(text_box);
with_view_model(
text_box->view, (TextBoxModel * model) {
model->focus = focus;
return true;
});
text_box->view, TextBoxModel * model, { model->focus = focus; }, true);
}

View File

@@ -429,10 +429,10 @@ void text_input_timer_callback(void* context) {
TextInput* text_input = context;
with_view_model(
text_input->view, (TextInputModel * model) {
model->valadator_message_visible = false;
return true;
});
text_input->view,
TextInputModel * model,
{ model->valadator_message_visible = false; },
true);
}
TextInput* text_input_alloc() {
@@ -446,10 +446,10 @@ TextInput* text_input_alloc() {
text_input->timer = furi_timer_alloc(text_input_timer_callback, FuriTimerTypeOnce, text_input);
with_view_model(
text_input->view, (TextInputModel * model) {
model->validator_text = furi_string_alloc();
return false;
});
text_input->view,
TextInputModel * model,
{ model->validator_text = furi_string_alloc(); },
false);
text_input_reset(text_input);
@@ -459,10 +459,10 @@ TextInput* text_input_alloc() {
void text_input_free(TextInput* text_input) {
furi_assert(text_input);
with_view_model(
text_input->view, (TextInputModel * model) {
furi_string_free(model->validator_text);
return false;
});
text_input->view,
TextInputModel * model,
{ furi_string_free(model->validator_text); },
false);
// Send stop command
furi_timer_stop(text_input->timer);
@@ -477,7 +477,9 @@ void text_input_free(TextInput* text_input) {
void text_input_reset(TextInput* text_input) {
furi_assert(text_input);
with_view_model(
text_input->view, (TextInputModel * model) {
text_input->view,
TextInputModel * model,
{
model->text_buffer_size = 0;
model->header = "";
model->selected_row = 0;
@@ -491,8 +493,8 @@ void text_input_reset(TextInput* text_input) {
model->validator_callback_context = NULL;
furi_string_reset(model->validator_text);
model->valadator_message_visible = false;
return true;
});
},
true);
}
View* text_input_get_view(TextInput* text_input) {
@@ -508,7 +510,9 @@ void text_input_set_result_callback(
size_t text_buffer_size,
bool clear_default_text) {
with_view_model(
text_input->view, (TextInputModel * model) {
text_input->view,
TextInputModel * model,
{
model->callback = callback;
model->callback_context = callback_context;
model->text_buffer = text_buffer;
@@ -519,8 +523,8 @@ void text_input_set_result_callback(
model->selected_row = 2;
model->selected_column = 8;
}
return true;
});
},
true);
}
void text_input_set_validator(
@@ -528,37 +532,36 @@ void text_input_set_validator(
TextInputValidatorCallback callback,
void* callback_context) {
with_view_model(
text_input->view, (TextInputModel * model) {
text_input->view,
TextInputModel * model,
{
model->validator_callback = callback;
model->validator_callback_context = callback_context;
return true;
});
},
true);
}
TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input) {
TextInputValidatorCallback validator_callback = NULL;
with_view_model(
text_input->view, (TextInputModel * model) {
validator_callback = model->validator_callback;
return false;
});
text_input->view,
TextInputModel * model,
{ validator_callback = model->validator_callback; },
false);
return validator_callback;
}
void* text_input_get_validator_callback_context(TextInput* text_input) {
void* validator_callback_context = NULL;
with_view_model(
text_input->view, (TextInputModel * model) {
validator_callback_context = model->validator_callback_context;
return false;
});
text_input->view,
TextInputModel * model,
{ validator_callback_context = model->validator_callback_context; },
false);
return validator_callback_context;
}
void text_input_set_header_text(TextInput* text_input, const char* text) {
with_view_model(
text_input->view, (TextInputModel * model) {
model->header = text;
return true;
});
text_input->view, TextInputModel * model, { model->header = text; }, true);
}

View File

@@ -92,7 +92,9 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) {
void variable_item_list_set_selected_item(VariableItemList* variable_item_list, uint8_t index) {
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
uint8_t position = index;
if(position >= VariableItemArray_size(model->items)) {
position = 0;
@@ -112,9 +114,8 @@ void variable_item_list_set_selected_item(VariableItemList* variable_item_list,
model->window_position = (VariableItemArray_size(model->items) - 4);
}
}
return true;
});
},
true);
}
uint8_t variable_item_list_get_selected_item_index(VariableItemList* variable_item_list) {
@@ -181,7 +182,9 @@ static bool variable_item_list_input_callback(InputEvent* event, void* context)
void variable_item_list_process_up(VariableItemList* variable_item_list) {
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
uint8_t items_on_screen = 4;
if(model->position > 0) {
model->position--;
@@ -195,13 +198,15 @@ void variable_item_list_process_up(VariableItemList* variable_item_list) {
model->window_position = model->position - (items_on_screen - 1);
}
}
return true;
});
},
true);
}
void variable_item_list_process_down(VariableItemList* variable_item_list) {
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
uint8_t items_on_screen = 4;
if(model->position < (VariableItemArray_size(model->items) - 1)) {
model->position++;
@@ -214,8 +219,8 @@ void variable_item_list_process_down(VariableItemList* variable_item_list) {
model->position = 0;
model->window_position = 0;
}
return true;
});
},
true);
}
VariableItem* variable_item_list_get_selected_item(VariableItemListModel* model) {
@@ -239,7 +244,9 @@ VariableItem* variable_item_list_get_selected_item(VariableItemListModel* model)
void variable_item_list_process_left(VariableItemList* variable_item_list) {
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
VariableItem* item = variable_item_list_get_selected_item(model);
if(item->current_value_index > 0) {
item->current_value_index--;
@@ -247,13 +254,15 @@ void variable_item_list_process_left(VariableItemList* variable_item_list) {
item->change_callback(item);
}
}
return true;
});
},
true);
}
void variable_item_list_process_right(VariableItemList* variable_item_list) {
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
VariableItem* item = variable_item_list_get_selected_item(model);
if(item->current_value_index < (item->values_count - 1)) {
item->current_value_index++;
@@ -261,18 +270,20 @@ void variable_item_list_process_right(VariableItemList* variable_item_list) {
item->change_callback(item);
}
}
return true;
});
},
true);
}
void variable_item_list_process_ok(VariableItemList* variable_item_list) {
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
if(variable_item_list->callback) {
variable_item_list->callback(variable_item_list->context, model->position);
}
return false;
});
},
false);
}
VariableItemList* variable_item_list_alloc() {
@@ -285,12 +296,14 @@ VariableItemList* variable_item_list_alloc() {
view_set_input_callback(variable_item_list->view, variable_item_list_input_callback);
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
VariableItemArray_init(model->items);
model->position = 0;
model->window_position = 0;
return true;
});
},
true);
return variable_item_list;
}
@@ -299,15 +312,17 @@ void variable_item_list_free(VariableItemList* variable_item_list) {
furi_assert(variable_item_list);
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
VariableItemArray_it_t it;
for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
VariableItemArray_next(it)) {
furi_string_free(VariableItemArray_ref(it)->current_value_text);
}
VariableItemArray_clear(model->items);
return false;
});
},
false);
view_free(variable_item_list->view);
free(variable_item_list);
}
@@ -316,15 +331,17 @@ void variable_item_list_reset(VariableItemList* variable_item_list) {
furi_assert(variable_item_list);
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
VariableItemArray_it_t it;
for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
VariableItemArray_next(it)) {
furi_string_free(VariableItemArray_ref(it)->current_value_text);
}
VariableItemArray_reset(model->items);
return false;
});
},
false);
}
View* variable_item_list_get_view(VariableItemList* variable_item_list) {
@@ -343,7 +360,9 @@ VariableItem* variable_item_list_add(
furi_assert(variable_item_list);
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
item = VariableItemArray_push_new(model->items);
item->label = label;
item->values_count = values_count;
@@ -351,8 +370,8 @@ VariableItem* variable_item_list_add(
item->context = context;
item->current_value_index = 0;
item->current_value_text = furi_string_alloc();
return true;
});
},
true);
return item;
}
@@ -363,12 +382,14 @@ void variable_item_list_set_enter_callback(
void* context) {
furi_assert(callback);
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
variable_item_list->view,
VariableItemListModel * model,
{
UNUSED(model);
variable_item_list->callback = callback;
variable_item_list->context = context;
return false;
});
},
false);
}
void variable_item_set_current_value_index(VariableItem* item, uint8_t current_value_index) {

View File

@@ -36,7 +36,9 @@ static bool gui_widget_view_input_callback(InputEvent* event, void* context) {
// Call all Widget Elements input handlers
with_view_model(
widget->view, (GuiWidgetModel * model) {
widget->view,
GuiWidgetModel * model,
{
ElementArray_it_t it;
ElementArray_it(it, model->element);
while(!ElementArray_end_p(it)) {
@@ -46,8 +48,8 @@ static bool gui_widget_view_input_callback(InputEvent* event, void* context) {
}
ElementArray_next(it);
}
return true;
});
},
true);
return consumed;
}
@@ -61,10 +63,7 @@ Widget* widget_alloc() {
view_set_input_callback(widget->view, gui_widget_view_input_callback);
with_view_model(
widget->view, (GuiWidgetModel * model) {
ElementArray_init(model->element);
return true;
});
widget->view, GuiWidgetModel * model, { ElementArray_init(model->element); }, true);
return widget;
}
@@ -73,7 +72,9 @@ void widget_reset(Widget* widget) {
furi_assert(widget);
with_view_model(
widget->view, (GuiWidgetModel * model) {
widget->view,
GuiWidgetModel * model,
{
ElementArray_it_t it;
ElementArray_it(it, model->element);
while(!ElementArray_end_p(it)) {
@@ -83,8 +84,8 @@ void widget_reset(Widget* widget) {
ElementArray_next(it);
}
ElementArray_reset(model->element);
return true;
});
},
true);
}
void widget_free(Widget* widget) {
@@ -93,10 +94,7 @@ void widget_free(Widget* widget) {
widget_reset(widget);
// Free elements container
with_view_model(
widget->view, (GuiWidgetModel * model) {
ElementArray_clear(model->element);
return true;
});
widget->view, GuiWidgetModel * model, { ElementArray_clear(model->element); }, true);
view_free(widget->view);
free(widget);
@@ -112,11 +110,13 @@ static void widget_add_element(Widget* widget, WidgetElement* element) {
furi_assert(element);
with_view_model(
widget->view, (GuiWidgetModel * model) {
widget->view,
GuiWidgetModel * model,
{
element->parent = widget;
ElementArray_push_back(model->element, element);
return true;
});
},
true);
}
void widget_add_string_multiline_element(

View File

@@ -211,25 +211,25 @@ void view_commit_model(View* view, bool update);
#endif
#ifdef __cplusplus
#define with_view_model_cpp(view, type, var, function_body) \
#define with_view_model_cpp(view, type, var, code, update) \
{ \
type* p = static_cast<type*>(view_get_model(view)); \
bool update = [&](type * var) function_body(p); \
type var = static_cast<type>(view_get_model(view)); \
{code}; \
view_commit_model(view, update); \
}
#else
/** With clause for view model
*
* @param view View instance pointer
* @param function_body a (){} lambda declaration, executed within you
* parent function context
* @param type View model type
* @param code Code block that will be executed between model lock and unlock
* @param update Bool flag, if true, view will be updated after code block. Can be variable, so code block can decide if update is needed.
*
* @return true if you want to emit view update, false otherwise
*/
#define with_view_model(view, function_body) \
{ \
void* p = view_get_model(view); \
bool update = ({ bool __fn__ function_body __fn__; })(p); \
view_commit_model(view, update); \
#define with_view_model(view, type, code, update) \
{ \
type = view_get_model(view); \
{code}; \
view_commit_model(view, update); \
}
#endif

View File

@@ -87,19 +87,13 @@ View* power_off_get_view(PowerOff* power_off) {
void power_off_set_time_left(PowerOff* power_off, uint8_t time_left) {
furi_assert(power_off);
with_view_model(
power_off->view, (PowerOffModel * model) {
model->time_left_sec = time_left;
return true;
});
power_off->view, PowerOffModel * model, { model->time_left_sec = time_left; }, true);
}
PowerOffResponse power_off_get_response(PowerOff* power_off) {
furi_assert(power_off);
PowerOffResponse response;
with_view_model(
power_off->view, (PowerOffModel * model) {
response = model->response;
return false;
});
power_off->view, PowerOffModel * model, { response = model->response; }, false);
return response;
}

View File

@@ -77,7 +77,7 @@ static DialogMessageButton unleashed_info_screen2(DialogsApp* dialogs, DialogMes
const char* screen_text = "Custom plugins included\n"
"For updates & info visit\n"
"github.com/Eng1n33r";
"github.com/DarkFlippers";
dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
result = dialog_message_show(dialogs, message);

View File

@@ -22,6 +22,7 @@ DesktopSettingsApp* desktop_settings_app_alloc() {
DesktopSettingsApp* app = malloc(sizeof(DesktopSettingsApp));
app->gui = furi_record_open(RECORD_GUI);
app->dialogs = furi_record_open(RECORD_DIALOGS);
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&desktop_settings_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
@@ -83,6 +84,7 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
// Records
furi_record_close(RECORD_DIALOGS);
furi_record_close(RECORD_GUI);
free(app);
}

View File

@@ -6,6 +6,7 @@
#include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <gui/modules/variable_item_list.h>
#include <dialogs/dialogs.h>
#include <desktop/desktop_settings.h>
#include <desktop/views/desktop_view_pin_input.h>
@@ -25,6 +26,7 @@ typedef struct {
DesktopSettings settings;
Gui* gui;
DialogsApp* dialogs;
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;
VariableItemList* variable_item_list;

View File

@@ -1,6 +1,28 @@
#include "../desktop_settings_app.h"
#include "applications.h"
#include "desktop_settings_scene.h"
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <fap_loader/fap_loader_app.h>
static bool favorite_fap_selector_item_callback(
FuriString* file_path,
void* context,
uint8_t** icon_ptr,
FuriString* item_name) {
UNUSED(context);
Storage* storage = furi_record_open(RECORD_STORAGE);
bool success = fap_loader_load_name_and_icon(file_path, storage, icon_ptr, item_name);
furi_record_close(RECORD_STORAGE);
return success;
}
static bool favorite_fap_selector_file_exists(char* file_path) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool exists = storage_file_exists(storage, file_path);
furi_record_close(RECORD_STORAGE);
return exists;
}
static void desktop_settings_scene_favorite_submenu_callback(void* context, uint32_t index) {
DesktopSettingsApp* app = context;
@@ -12,6 +34,10 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
Submenu* submenu = app->submenu;
submenu_reset(submenu);
uint32_t primary_favorite =
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite);
uint32_t pre_select_item = 0;
for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) {
submenu_add_item(
submenu,
@@ -19,38 +45,95 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
i,
desktop_settings_scene_favorite_submenu_callback,
app);
}
uint32_t primary_favorite =
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite);
if(primary_favorite) { // Select favorite item in submenu
if((app->settings.favorite_primary.is_external &&
!strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) ||
(!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_primary.name_or_path))) {
pre_select_item = i;
}
} else {
if((app->settings.favorite_secondary.is_external &&
!strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) ||
(!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_secondary.name_or_path))) {
pre_select_item = i;
}
}
}
submenu_set_header(
app->submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:");
submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:");
submenu_set_selected_item(submenu, pre_select_item); // If set during loop, visual glitch.
if(primary_favorite) {
submenu_set_selected_item(app->submenu, app->settings.favorite_primary);
} else {
submenu_set_selected_item(app->submenu, app->settings.favorite_secondary);
}
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
}
bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent event) {
DesktopSettingsApp* app = context;
bool consumed = false;
FuriString* temp_path = furi_string_alloc_set_str(EXT_PATH("apps"));
uint32_t primary_favorite =
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite);
if(event.type == SceneManagerEventTypeCustom) {
if(primary_favorite) {
app->settings.favorite_primary = event.event;
if(strcmp(FLIPPER_APPS[event.event].name, FAP_LOADER_APP_NAME)) {
if(primary_favorite) {
app->settings.favorite_primary.is_external = false;
strncpy(
app->settings.favorite_primary.name_or_path,
FLIPPER_APPS[event.event].name,
MAX_APP_LENGTH);
} else {
app->settings.favorite_secondary.is_external = false;
strncpy(
app->settings.favorite_secondary.name_or_path,
FLIPPER_APPS[event.event].name,
MAX_APP_LENGTH);
}
} else {
app->settings.favorite_secondary = event.event;
const DialogsFileBrowserOptions browser_options = {
.extension = ".fap",
.icon = &I_unknown_10px,
.skip_assets = true,
.hide_ext = true,
.item_loader_callback = favorite_fap_selector_item_callback,
.item_loader_context = app,
};
if(primary_favorite) { // Select favorite fap in file browser
if(favorite_fap_selector_file_exists(
app->settings.favorite_primary.name_or_path)) {
furi_string_set_str(temp_path, app->settings.favorite_primary.name_or_path);
}
} else {
if(favorite_fap_selector_file_exists(
app->settings.favorite_secondary.name_or_path)) {
furi_string_set_str(temp_path, app->settings.favorite_secondary.name_or_path);
}
}
if(dialog_file_browser_show(app->dialogs, temp_path, temp_path, &browser_options)) {
if(primary_favorite) {
app->settings.favorite_primary.is_external = true;
strncpy(
app->settings.favorite_primary.name_or_path,
furi_string_get_cstr(temp_path),
MAX_APP_LENGTH);
} else {
app->settings.favorite_secondary.is_external = true;
strncpy(
app->settings.favorite_secondary.name_or_path,
furi_string_get_cstr(temp_path),
MAX_APP_LENGTH);
}
}
}
scene_manager_previous_scene(app->scene_manager);
consumed = true;
}
furi_string_free(temp_path);
return consumed;
}

View File

@@ -119,8 +119,8 @@ void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data) {
furi_assert(battery_info);
furi_assert(data);
with_view_model(
battery_info->view, (BatteryInfoModel * model) {
memcpy(model, data, sizeof(BatteryInfoModel));
return true;
});
battery_info->view,
BatteryInfoModel * model,
{ memcpy(model, data, sizeof(BatteryInfoModel)); },
true);
}

View File

@@ -28,22 +28,25 @@ void updater_main_model_set_state(
const char* message,
uint8_t progress,
bool failed) {
bool update = false;
with_view_model(
main_view->view, (UpdaterProgressModel * model) {
main_view->view,
UpdaterProgressModel * model,
{
model->failed = failed;
model->progress = progress;
if(furi_string_cmp_str(model->status, message)) {
furi_string_set(model->status, message);
model->rendered_progress = progress;
return true;
}
if((model->rendered_progress > progress) ||
((progress - model->rendered_progress) > PROGRESS_RENDER_STEP)) {
update = true;
} else if(
(model->rendered_progress > progress) ||
((progress - model->rendered_progress) > PROGRESS_RENDER_STEP)) {
model->rendered_progress = progress;
return true;
update = true;
}
return false;
});
},
update);
}
View* updater_main_get_view(UpdaterMainView* main_view) {
@@ -104,10 +107,10 @@ UpdaterMainView* updater_main_alloc() {
view_allocate_model(main_view->view, ViewModelTypeLocking, sizeof(UpdaterProgressModel));
with_view_model(
main_view->view, (UpdaterProgressModel * model) {
model->status = furi_string_alloc_set("Waiting for SD card");
return true;
});
main_view->view,
UpdaterProgressModel * model,
{ model->status = furi_string_alloc_set("Waiting for SD card"); },
true);
view_set_context(main_view->view, main_view);
view_set_input_callback(main_view->view, updater_main_input);
@@ -119,10 +122,7 @@ UpdaterMainView* updater_main_alloc() {
void updater_main_free(UpdaterMainView* main_view) {
furi_assert(main_view);
with_view_model(
main_view->view, (UpdaterProgressModel * model) {
furi_string_free(model->status);
return false;
});
main_view->view, UpdaterProgressModel * model, { furi_string_free(model->status); }, false);
view_free(main_view->view);
free(main_view);
}

View File

@@ -1,7 +1,13 @@
Filetype: IR library file
Version: 1
# Last Updated 28th Sept, 2022
# Last Updated 9th Oct, 2022
#
# ON
name: POWER
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 3305 1598 432 411 413 404 410 1198 440 403 411 1197 441 402 412 405 409 408 406 1202 436 1198 440 403 411 406 408 409 405 1229 409 1199 439 404 410 407 407 410 414 403 411 406 408 409 405 412 412 405 409 408 406 411 413 404 410 407 407 410 414 1219 409 409 405 412 412 405 409 408 406 411 413 404 410 407 407 1226 412 405 409 409 405 412 412 405 409 1224 414 1194 434 1201 437 1196 432 1203 435 1198 440 1194 434 1200 438 378 436 408 406 1228 410 381 433 410 414 403 411 406 408 409 405 412 412 405 409 408 406 1228 410 1198 440 403 411 406 408 1199 439 405 409 408 406 411 413 1221 407 410 414 1219 409 409 405 1202 436 1199 439 403 411 406 408 410 414 402 412 405 409 408 406 411 413 404 410 407 407 410 414 403 411 406 408 409 405 412 412 405 409 408 406 411 413 404 410 407 407 410 414 403 411 406 408 409 405 412 412 404 410 408 406 411 413 403 411 407 407 410 414 402 412 405 409 408 406 411 413 404 410 407 407 410 414 403 411 406 408 409 405 412 412 405 409 408 406 1202 436 407 407 410 414 403 411 406 408 1200 438 1195 433 1202 436 406 408 1201 437 405 409
# SWING ON
name: SWING
type: raw
@@ -260,7 +266,7 @@ type: raw
frequency: 38000
duty_cycle: 0.330000
data: 5626 5579 569 549 562 582 539 581 540 578 543 577 544 575 536 1702 541 1703 540 549 562 557 564 1700 543 1670 563 1677 566 1698 545 547 564 586 535 1674 569 550 571 1668 565 1674 569 578 543 550 571 1670 563 587 545 1665 568 1671 562 1677 566 1700 543 577 544 548 563 1704 539 557 564 1698 545 574 537 1677 566 552 569 577 544 1668 565 554 567 583 538 1670 563 1702 541 1671 572 547 564 583 538 553 568 552 569 1700 543 545 566 582 539 1698 535 558 563 557 564 554 567 1671 562 585 536
#
# ON
name: POWER
type: raw
frequency: 38000
@@ -783,12 +789,6 @@ protocol: NECext
address: 08 F5 00 00
command: 00 FF 00 00
#
name: POWER
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 3302 1618 435 393 436 391 438 1207 431 396 433 1213 435 392 437 391 438 388 441 1206 432 1214 434 392 437 389 440 388 431 1215 433 1213 435 392 437 390 439 388 431 396 433 395 434 392 437 390 439 388 431 396 433 394 435 392 437 390 439 388 441 1205 433 395 434 392 437 389 440 388 431 396 433 394 435 392 437 1209 439 388 431 397 432 394 435 393 436 1210 438 387 432 396 433 394 435 392 437 390 439 388 431 1215 433 394 435 1211 437 1208 440 1205 433 1213 435 1211 437 1209 439
#
name: TIMER
type: raw
frequency: 38000
@@ -1274,4 +1274,16 @@ type: raw
frequency: 38000
duty_cycle: 0.330000
data: 3157 1552 601 1065 575 1093 598 330 554 330 530 340 545 1094 573 338 545 341 545 1094 572 1095 572 340 544 1097 570 342 543 341 543 1101 567 1123 543 342 542 1124 543 1124 543 344 542 342 542 1125 542 344 542 345 541 1125 541 344 542 344 542 344 542 344 542 344 542 343 541 344 541 345 541 344 542 344 542 344 541 345 541 343 541 344 542 344 541 344 542 344 541 1126 542 344 542 344 541 1126 542 344 542 345 541 1126 541 1126 541 345 541 343 541 345 541 345 541 344 542 344 541 1127 541 1126 541 1125 541 1127 541 345 541 344 541 344 541 344 541 1126 541 344 541 1126 542 344 541 344 541 344 541 344 542 344 542 343 541 345 541 345 541 344 542 344 542 345 540 343 541 344 541 344 541 344 542 344 541 344 541 344 542 343 541 344 542 344 541 345 541 345 541 344 542 344 541 343 541 344 542 344 542 344 542 344 542 344 542 344 542 343 541 344 542 344 542 345 541 344 542 345 541 345 541 343 542 345 542 1127 541 344 541 1126 542 344 542
# OFF
name: POWER
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 3306 1624 406 411 413 404 410 1224 414 403 411 1223 405 412 412 405 409 408 406 1228 410 1224 414 402 412 406 408 409 405 1229 409 1224 414 403 411 407 407 410 414 402 412 406 408 409 405 412 412 404 410 408 406 411 413 403 411 406 408 409 405 1230 408 408 406 411 413 404 410 407 407 410 414 403 411 406 408 1226 412 405 409 408 406 411 413 404 410 1224 414 403 411 406 408 409 405 412 412 405 409 408 406 1228 410 407 407 1227 411 1222 406 1229 409 1198 440 1220 408 1227 411
# OFF
name: POWER
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 3302 1618 435 393 436 391 438 1207 431 396 433 1213 435 392 437 391 438 388 441 1206 432 1214 434 392 437 389 440 388 431 1215 433 1213 435 392 437 390 439 388 431 396 433 395 434 392 437 390 439 388 431 396 433 394 435 392 437 390 439 388 441 1205 433 395 434 392 437 389 440 388 431 396 433 394 435 392 437 1209 439 388 431 397 432 394 435 393 436 1210 438 387 432 396 433 394 435 392 437 390 439 388 431 1215 433 394 435 1211 437 1208 440 1205 433 1213 435 1211 437 1209 439
#

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -13,7 +13,7 @@ FAPs are created and developed the same way as internal applications that are pa
To build your application as a FAP, just create a folder with your app's source code in `applications_user`, then write its code the way you'd do when creating a regular built-in application. Then configure its `application.fam` manifest — and set its *apptype* to FlipperAppType.EXTERNAL. See [Application Manifests](./AppManifests.md#application-definition) for more details.
* To build your application, run `./fbt firmware_{APPID}`, where APPID is your application's ID in its manifest.
* To build your application, run `./fbt fap_{APPID}`, where APPID is your application's ID in its manifest.
* To build your app, then upload it over USB & run it on Flipper, use `./fbt launch_app APPSRC=applications/path/to/app`. This command is configured in default [VSCode profile](../.vscode/ReadMe.md) as "Launch App on Flipper" build action (Ctrl+Shift+B menu).
* To build all FAPs, run `./fbt plugin_dist`.

View File

@@ -1,7 +1,7 @@
# How to change Flipper name:
## Instruction
1. Read [How to build](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToBuild.md) and [How to install](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md) to know how to build and install firmware
1. Read [How to build](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md) and [How to install](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) to know how to build and install firmware
2. Follow how to build instructions to prepare all things before continuing
3. Run release build to verify all is ok - `./fbt COMPACT=1 DEBUG=0 updater_package`
4. Clear build files - `./fbt COMPACT=1 DEBUG=0 updater_package -c`

View File

@@ -14,7 +14,7 @@ For development:
You should clone with
```shell
$ git clone --recursive https://github.com/Eng1n33r/flipperzero-firmware.git
$ git clone --recursive https://github.com/DarkFlippers/unleashed-firmware.git
```
# Build on Linux/macOS

View File

@@ -1,7 +1,7 @@
# Update firmware
## [Get Latest Firmware from GitHub Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases)
## [Get Latest Firmware from GitHub Releases](https://github.com/DarkFlippers/unleashed-firmware/releases)
<br>
<br>
@@ -14,7 +14,7 @@
## With Web Updater
- Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed
- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest)
- Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest)
- Connect your device and select `Install via Web Updater`
after that on web updater page - press `Connect` button
- Press `Install` button
@@ -31,7 +31,7 @@ after that on web updater page - press `Connect` button
## With iOS mobile app
- Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed
- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest)
- Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest)
- Download `flipper-z-f7-update-(version).tgz`
- Open downloads in ios Files app, select downloaded `.tgz` file, click Share, select Flipper App
- In flipper app click green `Update` button, be sure it shows `Custom flipper-z-f7-update...` in Update Channel
@@ -45,11 +45,11 @@ after that on web updater page - press `Connect` button
<br>
<br>
## With qFlipper (1.2.0)
## With qFlipper (1.2.0+)
- Download qFlipper that allows `.tgz` installation [Download qFlipper 1.2.0 (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0/)
- Download qFlipper that allows `.tgz` installation [Download qFlipper 1.2.1 (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.1/)
- Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed
- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest)
- Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest)
- Download `flipper-z-f7-update-(version).tgz`
- Launch qFlipper
- Connect your device and select `Install from file`
@@ -84,6 +84,6 @@ after that on web updater page - press `Connect` button
# After install:
- ## [Read instructions how to use plugins and more](https://github.com/Eng1n33r/flipperzero-firmware#instructions)
- ## [Read instructions how to use plugins and more](https://github.com/DarkFlippers/unleashed-firmware#instructions)
- ## [How To: Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
- ## [How To: Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)

View File

@@ -521,7 +521,7 @@ static SectionType elf_preload_section(
// TODO: how to do it not by name?
// .ARM: type 0x70000001, flags SHF_ALLOC | SHF_LINK_ORDER
// .rel.ARM: type 0x9, flags SHT_REL
if(str_prefix(name, ".ARM") || str_prefix(name, ".rel.ARM")) {
if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.")) {
FURI_LOG_D(TAG, "Ignoring ARM section");
return SectionTypeUnused;
}

View File

@@ -79,7 +79,7 @@ void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) {
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 10;
instance->encoder.size_upload = 1024; //actual size about 760
instance->encoder.size_upload = 900; //actual size 766+
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;

View File

@@ -96,7 +96,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment)
TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name);
}
instance->encoder.repeat = 10;
instance->encoder.size_upload = 1800; //wrong!! upload 186*16 = 2976 - actual size about 1716
instance->encoder.size_upload = 1728; //wrong!! upload 186*16 = 2976 - actual size about 1728
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;