mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Merge branch 'Eng1n33r:dev' into dev
This commit is contained in:
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,12 +1,18 @@
|
||||
### New changes
|
||||
* PR: SubGHz bruteforcer plugin - deep refactoring (huge thanks to @derskythe ! | PR #75)
|
||||
* OFW: Preliminary Rust support
|
||||
* Hide layouts folder in badusb app
|
||||
* SubGHz: Added 868.8 mhz into user config for sommer systems
|
||||
* Renamed apps to make it look a bit better in Apps tab in archive app
|
||||
* Infrared: Update assets (by @Amec0e)
|
||||
* OFW: Keyboard: show Uppercase keys when replacing content
|
||||
* OFW: (Temporarily excluded due to crashes) Furi Thread: don't use thread pointer after FuriThreadStateStopped callback
|
||||
* OFW: Resources cleanup in updater
|
||||
* OFW: Signal Generator app
|
||||
|
||||
#### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use .tgz file with qFlipper, or install automatically via web updater or use microSD update package**
|
||||
#### [🎲 Download extra apps pack](https://download-directory.github.io/?url=https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed)
|
||||
|
||||
[- How to install](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
[-> How to install firmware](https://github.com/Eng1n33r/flipperzero-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.0 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0/)
|
||||
|
||||
**Note: To avoid issues with .dfu, prefer installing using .tgz with qFlipper, web updater or by self update package, all needed assets will be installed**
|
||||
|
||||
|
||||
17
ReadMe.md
17
ReadMe.md
@@ -36,9 +36,11 @@ Our Discord Community:
|
||||
* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.)
|
||||
* BadUSB keyboard layouts
|
||||
* Customizable Flipper name
|
||||
* SubGHz -> Press OK in frequency analyzer to use detected frequency in Read modes
|
||||
* Other small fixes and changes throughout
|
||||
* See other changes in changelog and in readme below
|
||||
|
||||
See changelog in releases for latest updates!
|
||||
Also check changelog in releases for latest updates!
|
||||
|
||||
### Current modified and new SubGHz protocols list:
|
||||
- HCS101
|
||||
@@ -59,8 +61,8 @@ See changelog in releases for latest updates!
|
||||
|
||||
### Community apps included:
|
||||
|
||||
- RFID Fuzzer plugin [(by Ganapati)](https://github.com/Eng1n33r/flipperzero-firmware/pull/54) with some changes by xMasterX
|
||||
- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/Eng1n33r/flipperzero-firmware/pull/57)
|
||||
- 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)
|
||||
- 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)
|
||||
@@ -85,8 +87,10 @@ 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/ClusterM)
|
||||
- SubGHz -> New frequency analyzer - [(by ClusterM)](https://github.com/Eng1n33r/flipperzero-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)
|
||||
|
||||
# Instructions
|
||||
## [- How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
@@ -99,7 +103,7 @@ Games:
|
||||
|
||||
### **Plugins**
|
||||
|
||||
## [- 💎 Extra plugins precompiled for Unleashed](https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed)
|
||||
## [- 🎲 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)
|
||||
|
||||
@@ -139,9 +143,10 @@ Games:
|
||||
<br>
|
||||
|
||||
# Where I can find IR, SubGhz, ... files, DBs, and other stuff?
|
||||
## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero)
|
||||
## [UberGuidoZ Playground - Large collection of files - Github](https://github.com/UberGuidoZ/Flipper)
|
||||
## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero)
|
||||
## [CAME-12bit, NICE-12bit, Linear-10bit, PT-2240 - SubGHz fixed code bruteforce](https://github.com/tobiabocchi/flipperzero-bruteforce)
|
||||
## [SMC5326, UNILARM - SubGHz fixed code bruteforce](https://github.com/Hong5489/flipperzero-gate-bruteforce)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
@@ -7,8 +7,8 @@ App(
|
||||
"vibro_test",
|
||||
"keypad_test",
|
||||
"usb_test",
|
||||
"usb_mouse",
|
||||
"uart_echo",
|
||||
"USB_Mouse",
|
||||
"UART_Echo",
|
||||
"display_test",
|
||||
"text_box_test",
|
||||
"file_browser_test",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="uart_echo",
|
||||
appid="UART_Echo",
|
||||
name="UART Echo",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="uart_echo_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="usb_mouse",
|
||||
appid="USB_Mouse",
|
||||
name="USB Mouse",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="usb_mouse_app",
|
||||
|
||||
@@ -8,6 +8,7 @@ static bool bad_usb_file_select(BadUsbApp* bad_usb) {
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, BAD_USB_APP_SCRIPT_EXTENSION, &I_badusb_10px);
|
||||
browser_options.skip_assets = true;
|
||||
|
||||
// Input events and views are managed by file_browser
|
||||
bool res = dialog_file_browser_show(
|
||||
|
||||
@@ -15,6 +15,9 @@ typedef struct {
|
||||
DialogsApp* dialogs;
|
||||
Gui* gui;
|
||||
string_t fap_path;
|
||||
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Loading* loading;
|
||||
} FapLoader;
|
||||
|
||||
static bool
|
||||
@@ -144,12 +147,12 @@ int32_t fap_loader_app(void* p) {
|
||||
loader->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
loader->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
|
||||
Loading* loading = loading_alloc();
|
||||
loader->view_dispatcher = view_dispatcher_alloc();
|
||||
loader->loading = loading_alloc();
|
||||
|
||||
view_dispatcher_enable_queue(view_dispatcher);
|
||||
view_dispatcher_attach_to_gui(view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_add_view(view_dispatcher, 0, loading_get_view(loading));
|
||||
view_dispatcher_attach_to_gui(
|
||||
loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading));
|
||||
|
||||
if(p) {
|
||||
string_init_set(loader->fap_path, (const char*)p);
|
||||
@@ -158,14 +161,14 @@ int32_t fap_loader_app(void* p) {
|
||||
string_init_set(loader->fap_path, EXT_PATH("apps"));
|
||||
|
||||
while(fap_loader_select_app(loader)) {
|
||||
view_dispatcher_switch_to_view(view_dispatcher, 0);
|
||||
view_dispatcher_switch_to_view(loader->view_dispatcher, 0);
|
||||
fap_loader_run_selected_app(loader);
|
||||
};
|
||||
}
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, 0);
|
||||
loading_free(loading);
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
view_dispatcher_remove_view(loader->view_dispatcher, 0);
|
||||
loading_free(loader->loading);
|
||||
view_dispatcher_free(loader->view_dispatcher);
|
||||
|
||||
string_clear(loader->fap_path);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
@@ -23,34 +23,41 @@ struct InfraredBruteForce {
|
||||
FlipperFormat* ff;
|
||||
const char* db_filename;
|
||||
string_t current_record_name;
|
||||
InfraredSignal* current_signal;
|
||||
InfraredBruteForceRecordDict_t records;
|
||||
bool is_started;
|
||||
};
|
||||
|
||||
InfraredBruteForce* infrared_brute_force_alloc() {
|
||||
InfraredBruteForce* brute_force = malloc(sizeof(InfraredBruteForce));
|
||||
brute_force->ff = NULL;
|
||||
brute_force->db_filename = NULL;
|
||||
brute_force->current_signal = NULL;
|
||||
brute_force->is_started = false;
|
||||
string_init(brute_force->current_record_name);
|
||||
InfraredBruteForceRecordDict_init(brute_force->records);
|
||||
return brute_force;
|
||||
}
|
||||
|
||||
void infrared_brute_force_clear_records(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
InfraredBruteForceRecordDict_reset(brute_force->records);
|
||||
}
|
||||
|
||||
void infrared_brute_force_free(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->ff);
|
||||
furi_assert(!brute_force->is_started);
|
||||
InfraredBruteForceRecordDict_clear(brute_force->records);
|
||||
string_clear(brute_force->current_record_name);
|
||||
free(brute_force);
|
||||
}
|
||||
|
||||
void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
brute_force->db_filename = db_filename;
|
||||
}
|
||||
|
||||
bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
furi_assert(brute_force->db_filename);
|
||||
bool success = false;
|
||||
|
||||
@@ -80,6 +87,7 @@ bool infrared_brute_force_start(
|
||||
InfraredBruteForce* brute_force,
|
||||
uint32_t index,
|
||||
uint32_t* record_count) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
bool success = false;
|
||||
*record_count = 0;
|
||||
|
||||
@@ -100,50 +108,37 @@ bool infrared_brute_force_start(
|
||||
if(*record_count) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
brute_force->ff = flipper_format_buffered_file_alloc(storage);
|
||||
brute_force->current_signal = infrared_signal_alloc();
|
||||
brute_force->is_started = true;
|
||||
success =
|
||||
flipper_format_buffered_file_open_existing(brute_force->ff, brute_force->db_filename);
|
||||
if(!success) {
|
||||
flipper_format_free(brute_force->ff);
|
||||
brute_force->ff = NULL;
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
if(!success) infrared_brute_force_stop(brute_force);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) {
|
||||
return brute_force->ff;
|
||||
return brute_force->is_started;
|
||||
}
|
||||
|
||||
void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
|
||||
furi_assert(string_size(brute_force->current_record_name));
|
||||
furi_assert(brute_force->ff);
|
||||
|
||||
furi_assert(brute_force->is_started);
|
||||
string_reset(brute_force->current_record_name);
|
||||
infrared_signal_free(brute_force->current_signal);
|
||||
flipper_format_free(brute_force->ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
brute_force->current_signal = NULL;
|
||||
brute_force->ff = NULL;
|
||||
brute_force->is_started = false;
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) {
|
||||
furi_assert(string_size(brute_force->current_record_name));
|
||||
furi_assert(brute_force->ff);
|
||||
bool success = false;
|
||||
|
||||
string_t signal_name;
|
||||
string_init(signal_name);
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
|
||||
do {
|
||||
success = infrared_signal_read(signal, brute_force->ff, signal_name);
|
||||
} while(success && !string_equal_p(brute_force->current_record_name, signal_name));
|
||||
|
||||
furi_assert(brute_force->is_started);
|
||||
const bool success = infrared_signal_search_and_read(
|
||||
brute_force->current_signal, brute_force->ff, brute_force->current_record_name);
|
||||
if(success) {
|
||||
infrared_signal_transmit(signal);
|
||||
infrared_signal_transmit(brute_force->current_signal);
|
||||
}
|
||||
|
||||
infrared_signal_free(signal);
|
||||
string_clear(signal_name);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,26 @@ static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperForma
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
string_t tmp;
|
||||
string_init(tmp);
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, "type", tmp)) break;
|
||||
if(string_equal_p(tmp, "raw")) {
|
||||
success = infrared_signal_read_raw(signal, ff);
|
||||
} else if(string_equal_p(tmp, "parsed")) {
|
||||
success = infrared_signal_read_message(signal, ff);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown signal type");
|
||||
}
|
||||
} while(false);
|
||||
|
||||
string_clear(tmp);
|
||||
return success;
|
||||
}
|
||||
|
||||
InfraredSignal* infrared_signal_alloc() {
|
||||
InfraredSignal* signal = malloc(sizeof(InfraredSignal));
|
||||
|
||||
@@ -227,24 +247,41 @@ bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char*
|
||||
}
|
||||
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name) {
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
string_t tmp;
|
||||
string_init(tmp);
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, "name", buf)) break;
|
||||
string_set(name, buf);
|
||||
if(!flipper_format_read_string(ff, "type", buf)) break;
|
||||
if(!string_cmp_str(buf, "raw")) {
|
||||
success = infrared_signal_read_raw(signal, ff);
|
||||
} else if(!string_cmp_str(buf, "parsed")) {
|
||||
success = infrared_signal_read_message(signal, ff);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) ");
|
||||
}
|
||||
if(!flipper_format_read_string(ff, "name", tmp)) break;
|
||||
string_set(name, tmp);
|
||||
if(!infrared_signal_read_body(signal, ff)) break;
|
||||
success = true;
|
||||
} while(0);
|
||||
|
||||
string_clear(buf);
|
||||
string_clear(tmp);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool infrared_signal_search_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
const string_t name) {
|
||||
bool success = false;
|
||||
string_t tmp;
|
||||
string_init(tmp);
|
||||
|
||||
do {
|
||||
bool is_name_found = false;
|
||||
while(flipper_format_read_string(ff, "name", tmp)) {
|
||||
is_name_found = string_equal_p(name, tmp);
|
||||
if(is_name_found) break;
|
||||
}
|
||||
if(!is_name_found) break;
|
||||
if(!infrared_signal_read_body(signal, ff)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
string_clear(tmp);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,5 +37,9 @@ InfraredMessage* infrared_signal_get_message(InfraredSignal* signal);
|
||||
|
||||
bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name);
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name);
|
||||
bool infrared_signal_search_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
const string_t name);
|
||||
|
||||
void infrared_signal_transmit(InfraredSignal* signal);
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef enum {
|
||||
SubmenuIndexNiceFlo24bit,
|
||||
SubmenuIndexCAME12bit,
|
||||
SubmenuIndexCAME24bit,
|
||||
SubmenuIndexBETT_433,
|
||||
SubmenuIndexCAMETwee,
|
||||
SubmenuIndexNeroSketch,
|
||||
SubmenuIndexNeroRadio,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "../views/subghz_frequency_analyzer.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) {
|
||||
@@ -17,8 +16,18 @@ void subghz_scene_frequency_analyzer_on_enter(void* context) {
|
||||
}
|
||||
|
||||
bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom &&
|
||||
event.event == SubGhzCustomEventViewReceiverOK) {
|
||||
uint32_t frequency =
|
||||
subghz_frequency_analyzer_get_frequency_to_save(subghz->subghz_frequency_analyzer);
|
||||
if(frequency > 0) {
|
||||
subghz->last_settings->frequency = frequency;
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
"AM650",
|
||||
subghz_setting_get_default_frequency(subghz->setting),
|
||||
subghz_setting_get_preset_name(subghz->setting, subghz->last_settings->preset),
|
||||
subghz->last_settings->frequency,
|
||||
NULL,
|
||||
0);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
|
||||
@@ -136,8 +136,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
//Restore default setting
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
"AM650",
|
||||
subghz_setting_get_default_frequency(subghz->setting),
|
||||
subghz_setting_get_preset_name(subghz->setting, subghz->last_settings->preset),
|
||||
subghz->last_settings->frequency,
|
||||
NULL,
|
||||
0);
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "../views/receiver.h"
|
||||
|
||||
#define TAG "SubGhzSceneReceiver"
|
||||
|
||||
const NotificationSequence subghz_sequence_rx = {
|
||||
&message_green_255,
|
||||
|
||||
@@ -103,7 +105,11 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
|
||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
|
||||
subghz_preset_init(
|
||||
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||
subghz,
|
||||
subghz_setting_get_preset_name(subghz->setting, subghz->last_settings->preset),
|
||||
subghz->last_settings->frequency,
|
||||
NULL,
|
||||
0);
|
||||
subghz_history_reset(subghz->txrx->history);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
|
||||
}
|
||||
@@ -169,8 +175,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
"AM650",
|
||||
subghz_setting_get_default_frequency(subghz->setting),
|
||||
subghz_setting_get_preset_name(subghz->setting, subghz->last_settings->preset),
|
||||
subghz->last_settings->frequency,
|
||||
NULL,
|
||||
0);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
@@ -188,6 +194,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
subghz->txrx->idx_menu_chosen =
|
||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzViewIdReceiver, SubGhzCustomEventManagerSet);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
#define TAG "SubGhzSceneReceiverConfig"
|
||||
|
||||
enum SubGhzSettingIndex {
|
||||
SubGhzSettingIndexFrequency,
|
||||
SubGhzSettingIndexHopping,
|
||||
@@ -145,6 +147,8 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
||||
(subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
|
||||
variable_item_set_current_value_text(item, text_buf);
|
||||
subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index);
|
||||
subghz->last_settings->frequency = subghz->txrx->preset->frequency;
|
||||
subghz_setting_set_default_frequency(subghz->setting, subghz->txrx->preset->frequency);
|
||||
} else {
|
||||
variable_item_set_current_value_index(
|
||||
item, subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
@@ -154,11 +158,13 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
||||
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(
|
||||
item, subghz_setting_get_preset_name(subghz->setting, index));
|
||||
const char* preset_name = subghz_setting_get_preset_name(subghz->setting, index);
|
||||
variable_item_set_current_value_text(item, preset_name);
|
||||
subghz->last_settings->preset = index;
|
||||
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
subghz_setting_get_preset_name(subghz->setting, index),
|
||||
preset_name,
|
||||
subghz->txrx->preset->frequency,
|
||||
subghz_setting_get_preset_data(subghz->setting, index),
|
||||
subghz_setting_get_preset_data_size(subghz->setting, index));
|
||||
@@ -238,6 +244,13 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"last frequency: %d, preset: %d",
|
||||
subghz->last_settings->frequency,
|
||||
subghz->last_settings->preset);
|
||||
#endif
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Frequency:",
|
||||
@@ -258,20 +271,6 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
(subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000);
|
||||
variable_item_set_current_value_text(item, text_buf);
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubGhzCustomEventManagerSet) {
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Hopping:",
|
||||
HOPPING_COUNT,
|
||||
subghz_scene_receiver_config_set_hopping_running,
|
||||
subghz);
|
||||
value_index = subghz_scene_receiver_config_hopper_value_index(
|
||||
subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, hopping_text[value_index]);
|
||||
}
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Modulation:",
|
||||
@@ -286,6 +285,19 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubGhzCustomEventManagerSet) {
|
||||
// Hopping
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Hopping:",
|
||||
HOPPING_COUNT,
|
||||
subghz_scene_receiver_config_set_hopping_running,
|
||||
subghz);
|
||||
value_index = subghz_scene_receiver_config_hopper_value_index(
|
||||
subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, hopping_text[value_index]);
|
||||
|
||||
// Detect Raw
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Detect Raw:",
|
||||
@@ -298,10 +310,8 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
DETECT_RAW_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, detect_raw_text[value_index]);
|
||||
}
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubGhzCustomEventManagerSet) {
|
||||
// RSSI
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"RSSI for Raw:",
|
||||
@@ -315,10 +325,8 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
RSSI_THRESHOLD_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, rssi_threshold_text[value_index]);
|
||||
}
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubGhzCustomEventManagerSet) {
|
||||
// Lock keyboard
|
||||
variable_item_list_add(subghz->variable_item_list, "Lock Keyboard", 1, NULL, NULL);
|
||||
variable_item_list_set_enter_callback(
|
||||
subghz->variable_item_list,
|
||||
@@ -347,6 +355,7 @@ void subghz_scene_receiver_config_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
variable_item_list_set_selected_item(subghz->variable_item_list, 0);
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||
}
|
||||
|
||||
@@ -69,61 +69,67 @@ void subghz_scene_set_type_on_enter(void* context) {
|
||||
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Faac SLH_868",
|
||||
"Faac SLH 868MHz",
|
||||
SubmenuIndexFaacSLH_868,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Faac SLH_433",
|
||||
"Faac SLH 433MHz",
|
||||
SubmenuIndexFaacSLH_433,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"BFT Mitto",
|
||||
"BFT Mitto 433MHz",
|
||||
SubmenuIndexBFT,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Princeton_433",
|
||||
"Princeton 433MHz",
|
||||
SubmenuIndexPricenton,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Nice Flo 12bit_433",
|
||||
"Nice Flo 12bit 433MHz",
|
||||
SubmenuIndexNiceFlo12bit,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Nice Flo 24bit_433",
|
||||
"Nice Flo 24bit 433MHz",
|
||||
SubmenuIndexNiceFlo24bit,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"CAME 12bit_433",
|
||||
"CAME 12bit 433MHz",
|
||||
SubmenuIndexCAME12bit,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"CAME 24bit_433",
|
||||
"CAME 24bit 433MHz",
|
||||
SubmenuIndexCAME24bit,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Linear_300",
|
||||
"BETT 433MHz",
|
||||
SubmenuIndexBETT_433,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Linear 300MHz",
|
||||
SubmenuIndexLinear_300_00,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"CAME TWEE",
|
||||
"CAME TWEE 433MHz",
|
||||
SubmenuIndexCAMETwee,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
@@ -133,49 +139,49 @@ void subghz_scene_set_type_on_enter(void* context) {
|
||||
// subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Gate TX_433",
|
||||
"Gate TX 433MHz",
|
||||
SubmenuIndexGateTX,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"DoorHan_315",
|
||||
"DoorHan 315MHz",
|
||||
SubmenuIndexDoorHan_315_00,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"DoorHan_433",
|
||||
"DoorHan 433MHz",
|
||||
SubmenuIndexDoorHan_433_92,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"LiftMaster_315",
|
||||
"Security+1.0 315MHz",
|
||||
SubmenuIndexLiftMaster_315_00,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"LiftMaster_390",
|
||||
"Security+1.0 390MHz",
|
||||
SubmenuIndexLiftMaster_390_00,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Security+2.0_310",
|
||||
"Security+2.0 310MHz",
|
||||
SubmenuIndexSecPlus_v2_310_00,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Security+2.0_315",
|
||||
"Security+2.0 315MHz",
|
||||
SubmenuIndexSecPlus_v2_315_00,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Security+2.0_390",
|
||||
"Security+2.0 390MHz",
|
||||
SubmenuIndexSecPlus_v2_390_00,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
@@ -247,6 +253,13 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
generated_protocol = true;
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexBETT_433:
|
||||
key = (key & 0x0000FFF0);
|
||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||
subghz, SUBGHZ_PROTOCOL_BETT_NAME, key, 18, 433920000, "AM650")) {
|
||||
generated_protocol = true;
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexCAMETwee:
|
||||
key = (key & 0x0FFFFFF0);
|
||||
key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <lib/toolbox/path.h>
|
||||
#include "subghz_i.h"
|
||||
|
||||
#define TAG "SubGhzApp"
|
||||
|
||||
bool subghz_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
@@ -174,13 +176,30 @@ SubGhz* subghz_alloc() {
|
||||
subghz->setting = subghz_setting_alloc();
|
||||
subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user"));
|
||||
|
||||
// Load last used values for Read, Read RAW, etc. or default
|
||||
subghz->last_settings = subghz_last_settings_alloc();
|
||||
subghz_last_settings_load(
|
||||
subghz->last_settings, subghz_setting_get_preset_count(subghz->setting));
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"last frequency: %d, preset: %d",
|
||||
subghz->last_settings->frequency,
|
||||
subghz->last_settings->preset);
|
||||
#endif
|
||||
subghz_setting_set_default_frequency(subghz->setting, subghz->last_settings->frequency);
|
||||
|
||||
//init Worker & Protocol & History & KeyBoard
|
||||
subghz->lock = SubGhzLockOff;
|
||||
subghz->txrx = malloc(sizeof(SubGhzTxRx));
|
||||
subghz->txrx->preset = malloc(sizeof(SubGhzPresetDefinition));
|
||||
string_init(subghz->txrx->preset->name);
|
||||
subghz_preset_init(
|
||||
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||
subghz,
|
||||
subghz_setting_get_preset_name(subghz->setting, subghz->last_settings->preset),
|
||||
subghz->last_settings->frequency,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
|
||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
||||
@@ -287,6 +306,7 @@ void subghz_free(SubGhz* subghz) {
|
||||
|
||||
//setting
|
||||
subghz_setting_free(subghz->setting);
|
||||
subghz_last_settings_free(subghz->last_settings);
|
||||
|
||||
//Worker & Protocol & History
|
||||
subghz_receiver_free(subghz->txrx->receiver);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "subghz_history.h"
|
||||
#include "subghz_setting.h"
|
||||
#include "subghz_last_settings.h"
|
||||
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
@@ -100,10 +101,10 @@ struct SubGhz {
|
||||
SubGhzTestPacket* subghz_test_packet;
|
||||
string_t error_str;
|
||||
SubGhzSetting* setting;
|
||||
SubGhzLastSettings* last_settings;
|
||||
SubGhzLock lock;
|
||||
|
||||
bool in_decoder_scene;
|
||||
|
||||
void* rpc_ctx;
|
||||
};
|
||||
|
||||
|
||||
105
applications/main/subghz/subghz_last_settings.c
Normal file
105
applications/main/subghz/subghz_last_settings.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "subghz_last_settings.h"
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
|
||||
#define TAG "SubGhzLastSettings"
|
||||
|
||||
#define SUBGHZ_LAST_SETTING_FILE_TYPE "Flipper SubGhz Last Setting File"
|
||||
#define SUBGHZ_LAST_SETTING_FILE_VERSION 1
|
||||
#define SUBGHZ_LAST_SETTINGS_PATH EXT_PATH("subghz/assets/last_subghz.settings")
|
||||
// 1 = "AM650"
|
||||
// "AM270", "AM650", "FM238", "FM476",
|
||||
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET 1
|
||||
#define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void) {
|
||||
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_last_settings_free(SubGhzLastSettings* instance) {
|
||||
furi_assert(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count) {
|
||||
furi_assert(instance);
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "subghz_last_settings_load");
|
||||
#endif
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
|
||||
uint32_t temp_frequency = 0;
|
||||
int32_t temp_preset = 0;
|
||||
|
||||
if(FSE_OK == storage_sd_status(storage) && SUBGHZ_LAST_SETTINGS_PATH &&
|
||||
flipper_format_file_open_existing(fff_data_file, SUBGHZ_LAST_SETTINGS_PATH)) {
|
||||
flipper_format_read_int32(fff_data_file, "Preset", (int32_t*)&temp_preset, 1);
|
||||
flipper_format_read_uint32(fff_data_file, "Frequency", (uint32_t*)&temp_frequency, 1);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH);
|
||||
}
|
||||
|
||||
if(temp_frequency == 0 || !furi_hal_subghz_is_tx_allowed(temp_frequency)) {
|
||||
FURI_LOG_W(TAG, "Last used frequency not found or can't be used!");
|
||||
instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY;
|
||||
instance->preset = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
|
||||
} else {
|
||||
instance->frequency = temp_frequency;
|
||||
|
||||
if(temp_preset > (int32_t)preset_count - 1 || temp_preset < 0) {
|
||||
FURI_LOG_W(TAG, "Last used preset no found");
|
||||
instance->preset = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
|
||||
} else {
|
||||
instance->preset = temp_preset;
|
||||
}
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_data_file);
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
bool subghz_last_settings_save(SubGhzLastSettings* instance) {
|
||||
furi_assert(instance);
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "subghz_last_settings_save");
|
||||
#endif
|
||||
|
||||
bool saved = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
do {
|
||||
if(FSE_OK != storage_sd_status(storage)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Open file
|
||||
if(!flipper_format_file_open_always(file, SUBGHZ_LAST_SETTINGS_PATH)) break;
|
||||
|
||||
// Write header
|
||||
if(!flipper_format_write_header_cstr(
|
||||
file, SUBGHZ_LAST_SETTING_FILE_TYPE, SUBGHZ_LAST_SETTING_FILE_VERSION))
|
||||
break;
|
||||
|
||||
if(!flipper_format_insert_or_update_int32(file, "Preset", &instance->preset, 1)) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_insert_or_update_uint32(file, "Frequency", &instance->frequency, 1)) {
|
||||
break;
|
||||
}
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
||||
if(!saved) {
|
||||
FURI_LOG_E(TAG, "Error save file %s", SUBGHZ_LAST_SETTINGS_PATH);
|
||||
}
|
||||
|
||||
flipper_format_file_close(file);
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return saved;
|
||||
}
|
||||
19
applications/main/subghz/subghz_last_settings.h
Normal file
19
applications/main/subghz/subghz_last_settings.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t frequency;
|
||||
int32_t preset;
|
||||
} SubGhzLastSettings;
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void);
|
||||
|
||||
void subghz_last_settings_free(SubGhzLastSettings* instance);
|
||||
|
||||
void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count);
|
||||
|
||||
bool subghz_last_settings_save(SubGhzLastSettings* instance);
|
||||
@@ -260,13 +260,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
||||
break;
|
||||
}
|
||||
if(flipper_format_read_uint32(fff_data_file, "Default_frequency", &temp_data32, 1)) {
|
||||
for
|
||||
M_EACH(frequency, instance->frequencies, FrequencyList_t) {
|
||||
*frequency &= FREQUENCY_MASK;
|
||||
if(*frequency == temp_data32) {
|
||||
*frequency |= FREQUENCY_FLAG_DEFAULT;
|
||||
}
|
||||
}
|
||||
subghz_setting_set_default_frequency(instance, temp_data32);
|
||||
}
|
||||
|
||||
// custom preset (optional)
|
||||
@@ -294,6 +288,16 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_setting_set_default_frequency(SubGhzSetting* instance, uint32_t frequency_to_setup) {
|
||||
for
|
||||
M_EACH(frequency, instance->frequencies, FrequencyList_t) {
|
||||
*frequency &= FREQUENCY_MASK;
|
||||
if(*frequency == frequency_to_setup) {
|
||||
*frequency |= FREQUENCY_FLAG_DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t subghz_setting_get_frequency_count(SubGhzSetting* instance) {
|
||||
furi_assert(instance);
|
||||
return FrequencyList_size(instance->frequencies);
|
||||
@@ -311,6 +315,9 @@ size_t subghz_setting_get_preset_count(SubGhzSetting* instance) {
|
||||
|
||||
const char* subghz_setting_get_preset_name(SubGhzSetting* instance, size_t idx) {
|
||||
furi_assert(instance);
|
||||
if(idx >= SubGhzSettingCustomPresetItemArray_size(instance->preset->data)) {
|
||||
idx = 0;
|
||||
}
|
||||
SubGhzSettingCustomPresetItem* item =
|
||||
SubGhzSettingCustomPresetItemArray_get(instance->preset->data, idx);
|
||||
return string_get_cstr(item->custom_preset_name);
|
||||
|
||||
@@ -46,3 +46,5 @@ uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx
|
||||
uint32_t subghz_setting_get_frequency_default_index(SubGhzSetting* instance);
|
||||
|
||||
uint32_t subghz_setting_get_default_frequency(SubGhzSetting* instance);
|
||||
|
||||
void subghz_setting_set_default_frequency(SubGhzSetting* instance, uint32_t frequency_to_setup);
|
||||
|
||||
@@ -30,6 +30,32 @@ static const NotificationSequence sequence_hw_blink_stop = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_saved = {
|
||||
&message_blink_stop,
|
||||
&message_blue_0,
|
||||
&message_green_255,
|
||||
&message_red_0,
|
||||
&message_vibro_on,
|
||||
&message_delay_100,
|
||||
&message_vibro_off,
|
||||
NULL,
|
||||
};
|
||||
static const NotificationSequence sequence_not_saved = {
|
||||
&message_blink_stop,
|
||||
&message_green_255,
|
||||
&message_blue_255,
|
||||
&message_red_255,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const uint32_t subghz_frequency_list[] = {
|
||||
300000000, 302757000, 303875000, 304250000, 307000000, 307500000, 307800000,
|
||||
309000000, 310000000, 312000000, 312100000, 313000000, 313850000, 314000000,
|
||||
314350000, 315000000, 318000000, 345000000, 348000000, 387000000, 390000000,
|
||||
418000000, 433075000, 433220000, 433420000, 433657070, 433889000, 433920000,
|
||||
434176948, 434420000, 434775000, 438900000, 464000000, 779000000, 868350000,
|
||||
868400000, 868950000, 906400000, 915000000, 925000000, 928000000};
|
||||
|
||||
typedef enum {
|
||||
SubGhzFrequencyAnalyzerStatusIDLE,
|
||||
} SubGhzFrequencyAnalyzerStatus;
|
||||
@@ -50,6 +76,7 @@ struct SubGhzFrequencyAnalyzer {
|
||||
typedef struct {
|
||||
uint32_t frequency;
|
||||
uint32_t frequency_last;
|
||||
uint32_t frequency_to_save;
|
||||
float rssi;
|
||||
float rssi_last;
|
||||
float trigger;
|
||||
@@ -163,6 +190,33 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel
|
||||
elements_button_right(canvas, "T+");
|
||||
}
|
||||
|
||||
uint32_t subghz_frequency_find_correct(uint32_t input) {
|
||||
uint32_t prev_freq = 0;
|
||||
uint32_t current = 0;
|
||||
uint32_t result = 0;
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "input: %d", input);
|
||||
#endif
|
||||
for(size_t i = 0; i < sizeof(subghz_frequency_list); i++) {
|
||||
current = subghz_frequency_list[i];
|
||||
if(current == input) {
|
||||
result = current;
|
||||
break;
|
||||
}
|
||||
if(current > input && prev_freq < input) {
|
||||
if(current - input < input - prev_freq) {
|
||||
result = current;
|
||||
} else {
|
||||
result = prev_freq;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev_freq = current;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzFrequencyAnalyzer* instance = context;
|
||||
@@ -201,6 +255,43 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
|
||||
need_redraw = true;
|
||||
}
|
||||
|
||||
if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||
with_view_model(
|
||||
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
|
||||
uint32_t prev_freq_to_save = model->frequency_to_save;
|
||||
uint32_t frequency_candidate = 0;
|
||||
if(model->frequency != 0) {
|
||||
frequency_candidate = model->frequency;
|
||||
} else if(model->frequency_last != 0) {
|
||||
frequency_candidate = model->frequency_last;
|
||||
}
|
||||
if(frequency_candidate == 0 ||
|
||||
!furi_hal_subghz_is_frequency_valid(frequency_candidate) ||
|
||||
prev_freq_to_save == frequency_candidate) {
|
||||
frequency_candidate = 0;
|
||||
} else {
|
||||
frequency_candidate = subghz_frequency_find_correct(frequency_candidate);
|
||||
}
|
||||
if(frequency_candidate > 0 && frequency_candidate != model->frequency_to_save) {
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"frequency_to_save: %d, candidate: %d",
|
||||
model->frequency_to_save,
|
||||
frequency_candidate);
|
||||
#endif
|
||||
model->frequency_to_save = frequency_candidate;
|
||||
notification_message(instance->notifications, &sequence_saved);
|
||||
instance->callback(SubGhzCustomEventViewReceiverOK, instance->context);
|
||||
notification_message(instance->notifications, &sequence_hw_blink);
|
||||
} else {
|
||||
notification_message(instance->notifications, &sequence_not_saved);
|
||||
notification_message(instance->notifications, &sequence_hw_blink);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if(need_redraw) {
|
||||
SubGhzFrequencyAnalyzer* instance = context;
|
||||
with_view_model(
|
||||
@@ -309,6 +400,7 @@ void subghz_frequency_analyzer_enter(void* context) {
|
||||
model->rssi_last = 0;
|
||||
model->frequency = 0;
|
||||
model->frequency_last = 0;
|
||||
model->frequency_to_save = 0;
|
||||
model->trigger = RSSI_MIN;
|
||||
return true;
|
||||
});
|
||||
@@ -359,4 +451,16 @@ void subghz_frequency_analyzer_free(SubGhzFrequencyAnalyzer* instance) {
|
||||
View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->view;
|
||||
}
|
||||
|
||||
uint32_t subghz_frequency_analyzer_get_frequency_to_save(SubGhzFrequencyAnalyzer* instance) {
|
||||
furi_assert(instance);
|
||||
uint32_t frequency;
|
||||
with_view_model(
|
||||
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
|
||||
frequency = model->frequency_to_save;
|
||||
return false;
|
||||
});
|
||||
|
||||
return frequency;
|
||||
}
|
||||
@@ -17,3 +17,5 @@ SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc();
|
||||
void subghz_frequency_analyzer_free(SubGhzFrequencyAnalyzer* subghz_static);
|
||||
|
||||
View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* subghz_static);
|
||||
|
||||
uint32_t subghz_frequency_analyzer_get_frequency_to_save(SubGhzFrequencyAnalyzer* instance);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="arkanoid_game",
|
||||
appid="Arkanoid",
|
||||
name="Arkanoid",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="arkanoid_game_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="barcode_generator",
|
||||
appid="Barcode_Generator",
|
||||
name="UPC-A Generator",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="barcode_UPCA_generator_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="bt_hid",
|
||||
appid="Bluetooth_Remote",
|
||||
name="Bluetooth Remote",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="bt_hid_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="game_doom",
|
||||
appid="DOOM",
|
||||
name="DOOM",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="doom_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="esp8266_deauth",
|
||||
appid="ESP8266_Deauther",
|
||||
name="[ESP8266] Deauther",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="esp8266_deauth_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="game_flappybird",
|
||||
appid="FlappyBird",
|
||||
name="Flappy Bird",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flappy_game_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="flipfrid",
|
||||
appid="RFID_Fuzzer",
|
||||
name="RFID Fuzzer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flipfrid_start",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="mouse_jacker",
|
||||
appid="NRF24_Mouse_Jacker",
|
||||
name="[NRF24] Mouse Jacker",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="mousejacker_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="multi_converter",
|
||||
appid="Multi_Converter",
|
||||
name="Multi Converter",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="multi_converter_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="music_player",
|
||||
appid="Music_Player",
|
||||
name="Music Player",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="music_player_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="nrf_sniff",
|
||||
appid="NRF24_Sniffer",
|
||||
name="[NRF24] Sniffer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="nrfsniff_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="picopass",
|
||||
appid="Picopass",
|
||||
name="PicoPass Reader",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="picopass_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="sub_playlist",
|
||||
appid="SubGHz_Playlist",
|
||||
name="Sub-GHz Playlist",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="playlist_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="sentry_safe",
|
||||
appid="GPIO_Sentry_Safe",
|
||||
name="[GPIO] Sentry Safe",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="sentry_safe_app",
|
||||
|
||||
12
applications/plugins/signal_generator/application.fam
Normal file
12
applications/plugins/signal_generator/application.fam
Normal file
@@ -0,0 +1,12 @@
|
||||
App(
|
||||
appid="Signal_Generator",
|
||||
name="Signal Generator",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="signal_gen_app",
|
||||
cdefines=["APP_SIGNAL_GEN"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=50,
|
||||
fap_icon="signal_gen_10px.png",
|
||||
fap_category="Tools",
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const signal_gen_scene_on_enter_handlers[])(void*) = {
|
||||
#include "signal_gen_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const signal_gen_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "signal_gen_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const signal_gen_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "signal_gen_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers signal_gen_scene_handlers = {
|
||||
.on_enter_handlers = signal_gen_scene_on_enter_handlers,
|
||||
.on_event_handlers = signal_gen_scene_on_event_handlers,
|
||||
.on_exit_handlers = signal_gen_scene_on_exit_handlers,
|
||||
.scene_num = SignalGenSceneNum,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) SignalGenScene##id,
|
||||
typedef enum {
|
||||
#include "signal_gen_scene_config.h"
|
||||
SignalGenSceneNum,
|
||||
} SignalGenScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers signal_gen_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "signal_gen_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "signal_gen_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "signal_gen_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,3 @@
|
||||
ADD_SCENE(signal_gen, start, Start)
|
||||
ADD_SCENE(signal_gen, pwm, Pwm)
|
||||
ADD_SCENE(signal_gen, mco, Mco)
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
LineIndexSource,
|
||||
LineIndexDivision,
|
||||
} LineIndex;
|
||||
|
||||
static const char* const mco_source_names[] = {
|
||||
"32768",
|
||||
"64MHz",
|
||||
"~100K",
|
||||
"~200K",
|
||||
"~400K",
|
||||
"~800K",
|
||||
"~1MHz",
|
||||
"~2MHz",
|
||||
"~4MHz",
|
||||
"~8MHz",
|
||||
"~16MHz",
|
||||
"~24MHz",
|
||||
"~32MHz",
|
||||
"~48MHz",
|
||||
};
|
||||
|
||||
static const FuriHalClockMcoSourceId mco_sources[] = {
|
||||
FuriHalClockMcoLse,
|
||||
FuriHalClockMcoSysclk,
|
||||
FuriHalClockMcoMsi100k,
|
||||
FuriHalClockMcoMsi200k,
|
||||
FuriHalClockMcoMsi400k,
|
||||
FuriHalClockMcoMsi800k,
|
||||
FuriHalClockMcoMsi1m,
|
||||
FuriHalClockMcoMsi2m,
|
||||
FuriHalClockMcoMsi4m,
|
||||
FuriHalClockMcoMsi8m,
|
||||
FuriHalClockMcoMsi16m,
|
||||
FuriHalClockMcoMsi24m,
|
||||
FuriHalClockMcoMsi32m,
|
||||
FuriHalClockMcoMsi48m,
|
||||
};
|
||||
|
||||
static const char* const mco_divisor_names[] = {
|
||||
"1",
|
||||
"2",
|
||||
"4",
|
||||
"8",
|
||||
"16",
|
||||
};
|
||||
|
||||
static const FuriHalClockMcoDivisorId mco_divisors[] = {
|
||||
FuriHalClockMcoDiv1,
|
||||
FuriHalClockMcoDiv2,
|
||||
FuriHalClockMcoDiv4,
|
||||
FuriHalClockMcoDiv8,
|
||||
FuriHalClockMcoDiv16,
|
||||
};
|
||||
|
||||
static void mco_source_list_change_callback(VariableItem* item) {
|
||||
SignalGenApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, mco_source_names[index]);
|
||||
|
||||
app->mco_src = mco_sources[index];
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenMcoEventUpdate);
|
||||
}
|
||||
|
||||
static void mco_divisor_list_change_callback(VariableItem* item) {
|
||||
SignalGenApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, mco_divisor_names[index]);
|
||||
|
||||
app->mco_div = mco_divisors[index];
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenMcoEventUpdate);
|
||||
}
|
||||
|
||||
void signal_gen_scene_mco_on_enter(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
VariableItemList* var_item_list = app->var_item_list;
|
||||
|
||||
VariableItem* item;
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "Source", COUNT_OF(mco_source_names), mco_source_list_change_callback, app);
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
variable_item_set_current_value_text(item, mco_source_names[0]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
"Division",
|
||||
COUNT_OF(mco_divisor_names),
|
||||
mco_divisor_list_change_callback,
|
||||
app);
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
variable_item_set_current_value_text(item, mco_divisor_names[0]);
|
||||
|
||||
variable_item_list_set_selected_item(var_item_list, LineIndexSource);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SignalGenViewVarItemList);
|
||||
|
||||
app->mco_src = FuriHalClockMcoLse;
|
||||
app->mco_div = FuriHalClockMcoDiv1;
|
||||
furi_hal_clock_mco_enable(app->mco_src, app->mco_div);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn0MCO);
|
||||
}
|
||||
|
||||
bool signal_gen_scene_mco_on_event(void* context, SceneManagerEvent event) {
|
||||
SignalGenApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SignalGenMcoEventUpdate) {
|
||||
consumed = true;
|
||||
furi_hal_clock_mco_enable(app->mco_src, app->mco_div);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void signal_gen_scene_mco_on_exit(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
variable_item_list_reset(app->var_item_list);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_tx,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn7USART1);
|
||||
furi_hal_clock_mco_disable();
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
static const FuriHalPwmOutputId pwm_ch_id[] = {
|
||||
FuriHalPwmOutputIdTim1PA7,
|
||||
FuriHalPwmOutputIdLptim2PA4,
|
||||
};
|
||||
|
||||
#define DEFAULT_FREQ 1000
|
||||
#define DEFAULT_DUTY 50
|
||||
|
||||
static void
|
||||
signal_gen_pwm_callback(uint8_t channel_id, uint32_t freq, uint8_t duty, void* context) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
app->pwm_freq = freq;
|
||||
app->pwm_duty = duty;
|
||||
|
||||
if(app->pwm_ch != pwm_ch_id[channel_id]) {
|
||||
app->pwm_ch_prev = app->pwm_ch;
|
||||
app->pwm_ch = pwm_ch_id[channel_id];
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventChannelChange);
|
||||
} else {
|
||||
app->pwm_ch = pwm_ch_id[channel_id];
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
void signal_gen_scene_pwm_on_enter(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SignalGenViewPwm);
|
||||
|
||||
signal_gen_pwm_set_callback(app->pwm_view, signal_gen_pwm_callback, app);
|
||||
|
||||
signal_gen_pwm_set_params(app->pwm_view, 0, DEFAULT_FREQ, DEFAULT_DUTY);
|
||||
furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY);
|
||||
}
|
||||
|
||||
bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) {
|
||||
SignalGenApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SignalGenPwmEventUpdate) {
|
||||
consumed = true;
|
||||
furi_hal_pwm_set_params(app->pwm_ch, app->pwm_freq, app->pwm_duty);
|
||||
} else if(event.event == SignalGenPwmEventChannelChange) {
|
||||
consumed = true;
|
||||
furi_hal_pwm_stop(app->pwm_ch_prev);
|
||||
furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void signal_gen_scene_pwm_on_exit(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
variable_item_list_reset(app->var_item_list);
|
||||
furi_hal_pwm_stop(app->pwm_ch);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexPwm,
|
||||
SubmenuIndexClockOutput,
|
||||
} SubmenuIndex;
|
||||
|
||||
void signal_gen_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void signal_gen_scene_start_on_enter(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "PWM", SubmenuIndexPwm, signal_gen_scene_start_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Clock Output",
|
||||
SubmenuIndexClockOutput,
|
||||
signal_gen_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, SignalGenSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SignalGenViewSubmenu);
|
||||
}
|
||||
|
||||
bool signal_gen_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
SignalGenApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexPwm) {
|
||||
scene_manager_next_scene(app->scene_manager, SignalGenScenePwm);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexClockOutput) {
|
||||
scene_manager_next_scene(app->scene_manager, SignalGenSceneMco);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, SignalGenSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void signal_gen_scene_start_on_exit(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
BIN
applications/plugins/signal_generator/signal_gen_10px.png
Normal file
BIN
applications/plugins/signal_generator/signal_gen_10px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
93
applications/plugins/signal_generator/signal_gen_app.c
Normal file
93
applications/plugins/signal_generator/signal_gen_app.c
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "signal_gen_app_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
static bool signal_gen_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
SignalGenApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool signal_gen_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SignalGenApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void signal_gen_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SignalGenApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
SignalGenApp* signal_gen_app_alloc() {
|
||||
SignalGenApp* app = malloc(sizeof(SignalGenApp));
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&signal_gen_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, signal_gen_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, signal_gen_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, signal_gen_app_tick_event_callback, 100);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
app->var_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
SignalGenViewVarItemList,
|
||||
variable_item_list_get_view(app->var_item_list));
|
||||
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, SignalGenViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->pwm_view = signal_gen_pwm_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, SignalGenViewPwm, signal_gen_pwm_get_view(app->pwm_view));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, SignalGenSceneStart);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void signal_gen_app_free(SignalGenApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SignalGenViewVarItemList);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SignalGenViewSubmenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SignalGenViewPwm);
|
||||
|
||||
submenu_free(app->submenu);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
signal_gen_pwm_free(app->pwm_view);
|
||||
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t signal_gen_app(void* p) {
|
||||
UNUSED(p);
|
||||
SignalGenApp* signal_gen_app = signal_gen_app_alloc();
|
||||
|
||||
view_dispatcher_run(signal_gen_app->view_dispatcher);
|
||||
|
||||
signal_gen_app_free(signal_gen_app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
applications/plugins/signal_generator/signal_gen_app_i.h
Normal file
46
applications/plugins/signal_generator/signal_gen_app_i.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "scenes/signal_gen_scene.h"
|
||||
|
||||
#include "furi_hal_clock.h"
|
||||
#include "furi_hal_pwm.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include "views/signal_gen_pwm.h"
|
||||
|
||||
typedef struct SignalGenApp SignalGenApp;
|
||||
|
||||
struct SignalGenApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
|
||||
VariableItemList* var_item_list;
|
||||
Submenu* submenu;
|
||||
SignalGenPwm* pwm_view;
|
||||
|
||||
FuriHalClockMcoSourceId mco_src;
|
||||
FuriHalClockMcoDivisorId mco_div;
|
||||
|
||||
FuriHalPwmOutputId pwm_ch_prev;
|
||||
FuriHalPwmOutputId pwm_ch;
|
||||
uint32_t pwm_freq;
|
||||
uint8_t pwm_duty;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SignalGenViewVarItemList,
|
||||
SignalGenViewSubmenu,
|
||||
SignalGenViewPwm,
|
||||
} SignalGenAppView;
|
||||
|
||||
typedef enum {
|
||||
SignalGenMcoEventUpdate,
|
||||
SignalGenPwmEventUpdate,
|
||||
SignalGenPwmEventChannelChange,
|
||||
} SignalGenCustomEvent;
|
||||
301
applications/plugins/signal_generator/views/signal_gen_pwm.c
Normal file
301
applications/plugins/signal_generator/views/signal_gen_pwm.c
Normal file
@@ -0,0 +1,301 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
#include "furi_hal.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
typedef enum {
|
||||
LineIndexChannel,
|
||||
LineIndexFrequency,
|
||||
LineIndexDuty,
|
||||
LineIndexTotalCount
|
||||
} LineIndex;
|
||||
|
||||
static const char* const pwm_ch_names[] = {"TIM1(2)", "LPTIM2(4)"};
|
||||
|
||||
struct SignalGenPwm {
|
||||
View* view;
|
||||
SignalGenPwmViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
LineIndex line_sel;
|
||||
bool edit_mode;
|
||||
uint8_t edit_digit;
|
||||
|
||||
uint8_t channel_id;
|
||||
uint32_t freq;
|
||||
uint8_t duty;
|
||||
|
||||
} SignalGenPwmViewModel;
|
||||
|
||||
#define ITEM_H 64 / 3
|
||||
#define ITEM_W 128
|
||||
|
||||
#define VALUE_X 95
|
||||
#define VALUE_W 55
|
||||
|
||||
#define FREQ_VALUE_X 62
|
||||
#define FREQ_MAX 1000000UL
|
||||
#define FREQ_DIGITS_NB 7
|
||||
|
||||
static void pwm_set_config(SignalGenPwm* pwm) {
|
||||
FuriHalPwmOutputId channel;
|
||||
uint32_t freq;
|
||||
uint8_t duty;
|
||||
|
||||
with_view_model(
|
||||
pwm->view, (SignalGenPwmViewModel * model) {
|
||||
channel = model->channel_id;
|
||||
freq = model->freq;
|
||||
duty = model->duty;
|
||||
return false;
|
||||
});
|
||||
|
||||
furi_assert(pwm->callback);
|
||||
pwm->callback(channel, freq, duty, pwm->context);
|
||||
}
|
||||
|
||||
static void pwm_channel_change(SignalGenPwmViewModel* model, InputEvent* event) {
|
||||
if(event->key == InputKeyLeft) {
|
||||
if(model->channel_id > 0) {
|
||||
model->channel_id--;
|
||||
}
|
||||
} else if(event->key == InputKeyRight) {
|
||||
if(model->channel_id < (COUNT_OF(pwm_ch_names) - 1)) {
|
||||
model->channel_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pwm_duty_change(SignalGenPwmViewModel* model, InputEvent* event) {
|
||||
if(event->key == InputKeyLeft) {
|
||||
if(model->duty > 0) {
|
||||
model->duty--;
|
||||
}
|
||||
} else if(event->key == InputKeyRight) {
|
||||
if(model->duty < 100) {
|
||||
model->duty++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool pwm_freq_edit(SignalGenPwmViewModel* model, InputEvent* event) {
|
||||
bool consumed = false;
|
||||
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
|
||||
if(event->key == InputKeyRight) {
|
||||
if(model->edit_digit > 0) {
|
||||
model->edit_digit--;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
if(model->edit_digit < (FREQ_DIGITS_NB - 1)) {
|
||||
model->edit_digit++;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
uint32_t step = 1;
|
||||
for(uint8_t i = 0; i < model->edit_digit; i++) {
|
||||
step *= 10;
|
||||
}
|
||||
if((model->freq + step) < FREQ_MAX) {
|
||||
model->freq += step;
|
||||
} else {
|
||||
model->freq = FREQ_MAX;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
uint32_t step = 1;
|
||||
for(uint8_t i = 0; i < model->edit_digit; i++) {
|
||||
step *= 10;
|
||||
}
|
||||
if(model->freq > (step + 1)) {
|
||||
model->freq -= step;
|
||||
} else {
|
||||
model->freq = 1;
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static void signal_gen_pwm_draw_callback(Canvas* canvas, void* _model) {
|
||||
SignalGenPwmViewModel* model = _model;
|
||||
char* line_label = NULL;
|
||||
char val_text[16];
|
||||
|
||||
for(uint8_t line = 0; line < LineIndexTotalCount; line++) {
|
||||
if(line == LineIndexChannel) {
|
||||
line_label = "PWM Channel";
|
||||
} else if(line == LineIndexFrequency) {
|
||||
line_label = "Frequency";
|
||||
} else if(line == LineIndexDuty) {
|
||||
line_label = "Duty Cycle";
|
||||
}
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
if(line == model->line_sel) {
|
||||
elements_slightly_rounded_box(canvas, 0, ITEM_H * line + 1, ITEM_W, ITEM_H - 1);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
|
||||
uint8_t text_y = ITEM_H * line + ITEM_H / 2 + 2;
|
||||
|
||||
canvas_draw_str_aligned(canvas, 6, text_y, AlignLeft, AlignCenter, line_label);
|
||||
|
||||
if(line == LineIndexChannel) {
|
||||
snprintf(val_text, sizeof(val_text), "%s", pwm_ch_names[model->channel_id]);
|
||||
canvas_draw_str_aligned(canvas, VALUE_X, text_y, AlignCenter, AlignCenter, val_text);
|
||||
if(model->channel_id != 0) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas, VALUE_X - VALUE_W / 2, text_y, AlignCenter, AlignCenter, "<");
|
||||
}
|
||||
if(model->channel_id != (COUNT_OF(pwm_ch_names) - 1)) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas, VALUE_X + VALUE_W / 2, text_y, AlignCenter, AlignCenter, ">");
|
||||
}
|
||||
} else if(line == LineIndexFrequency) {
|
||||
snprintf(val_text, sizeof(val_text), "%7lu Hz", model->freq);
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, FREQ_VALUE_X, text_y, AlignLeft, AlignCenter, val_text);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
if(model->edit_mode) {
|
||||
uint8_t icon_x = (FREQ_VALUE_X - 1) + (FREQ_DIGITS_NB - model->edit_digit - 1) * 6;
|
||||
canvas_draw_icon(canvas, icon_x, text_y - 9, &I_SmallArrowUp_4x7);
|
||||
canvas_draw_icon(canvas, icon_x, text_y + 4, &I_SmallArrowDown_4x7);
|
||||
}
|
||||
} else if(line == LineIndexDuty) {
|
||||
snprintf(val_text, sizeof(val_text), "%d%%", model->duty);
|
||||
canvas_draw_str_aligned(canvas, VALUE_X, text_y, AlignCenter, AlignCenter, val_text);
|
||||
if(model->duty != 0) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas, VALUE_X - VALUE_W / 2, text_y, AlignCenter, AlignCenter, "<");
|
||||
}
|
||||
if(model->duty != 100) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas, VALUE_X + VALUE_W / 2, text_y, AlignCenter, AlignCenter, ">");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool signal_gen_pwm_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SignalGenPwm* pwm = context;
|
||||
bool consumed = false;
|
||||
bool need_update = false;
|
||||
|
||||
with_view_model(
|
||||
pwm->view, (SignalGenPwmViewModel * model) {
|
||||
if(model->edit_mode == false) {
|
||||
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
|
||||
if(event->key == InputKeyUp) {
|
||||
if(model->line_sel == 0) {
|
||||
model->line_sel = LineIndexTotalCount - 1;
|
||||
} else {
|
||||
model->line_sel =
|
||||
CLAMP(model->line_sel - 1, LineIndexTotalCount - 1, 0);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
if(model->line_sel == LineIndexTotalCount - 1) {
|
||||
model->line_sel = 0;
|
||||
} else {
|
||||
model->line_sel =
|
||||
CLAMP(model->line_sel + 1, LineIndexTotalCount - 1, 0);
|
||||
}
|
||||
consumed = true;
|
||||
} else if((event->key == InputKeyLeft) || (event->key == InputKeyRight)) {
|
||||
if(model->line_sel == LineIndexChannel) {
|
||||
pwm_channel_change(model, event);
|
||||
need_update = true;
|
||||
} else if(model->line_sel == LineIndexDuty) {
|
||||
pwm_duty_change(model, event);
|
||||
need_update = true;
|
||||
} else if(model->line_sel == LineIndexFrequency) {
|
||||
model->edit_mode = true;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyOk) {
|
||||
if(model->line_sel == LineIndexFrequency) {
|
||||
model->edit_mode = true;
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if((event->key == InputKeyOk) || (event->key == InputKeyBack)) {
|
||||
if(event->type == InputTypeShort) {
|
||||
model->edit_mode = false;
|
||||
consumed = true;
|
||||
}
|
||||
} else {
|
||||
if(model->line_sel == LineIndexFrequency) {
|
||||
consumed = pwm_freq_edit(model, event);
|
||||
need_update = consumed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if(need_update) {
|
||||
pwm_set_config(pwm);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
SignalGenPwm* signal_gen_pwm_alloc() {
|
||||
SignalGenPwm* pwm = malloc(sizeof(SignalGenPwm));
|
||||
|
||||
pwm->view = view_alloc();
|
||||
view_allocate_model(pwm->view, ViewModelTypeLocking, sizeof(SignalGenPwmViewModel));
|
||||
view_set_context(pwm->view, pwm);
|
||||
view_set_draw_callback(pwm->view, signal_gen_pwm_draw_callback);
|
||||
view_set_input_callback(pwm->view, signal_gen_pwm_input_callback);
|
||||
|
||||
return pwm;
|
||||
}
|
||||
|
||||
void signal_gen_pwm_free(SignalGenPwm* pwm) {
|
||||
furi_assert(pwm);
|
||||
view_free(pwm->view);
|
||||
free(pwm);
|
||||
}
|
||||
|
||||
View* signal_gen_pwm_get_view(SignalGenPwm* pwm) {
|
||||
furi_assert(pwm);
|
||||
return pwm->view;
|
||||
}
|
||||
|
||||
void signal_gen_pwm_set_callback(
|
||||
SignalGenPwm* pwm,
|
||||
SignalGenPwmViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(pwm);
|
||||
furi_assert(callback);
|
||||
|
||||
with_view_model(
|
||||
pwm->view, (SignalGenPwmViewModel * model) {
|
||||
UNUSED(model);
|
||||
pwm->callback = callback;
|
||||
pwm->context = context;
|
||||
return 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) {
|
||||
model->channel_id = channel_id;
|
||||
model->freq = freq;
|
||||
model->duty = duty;
|
||||
return true;
|
||||
});
|
||||
|
||||
furi_assert(pwm->callback);
|
||||
pwm->callback(channel_id, freq, duty, pwm->context);
|
||||
}
|
||||
21
applications/plugins/signal_generator/views/signal_gen_pwm.h
Normal file
21
applications/plugins/signal_generator/views/signal_gen_pwm.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
typedef struct SignalGenPwm SignalGenPwm;
|
||||
typedef void (
|
||||
*SignalGenPwmViewCallback)(uint8_t channel_id, uint32_t freq, uint8_t duty, void* context);
|
||||
|
||||
SignalGenPwm* signal_gen_pwm_alloc();
|
||||
|
||||
void signal_gen_pwm_free(SignalGenPwm* pwm);
|
||||
|
||||
View* signal_gen_pwm_get_view(SignalGenPwm* pwm);
|
||||
|
||||
void signal_gen_pwm_set_callback(
|
||||
SignalGenPwm* pwm,
|
||||
SignalGenPwmViewCallback callback,
|
||||
void* context);
|
||||
|
||||
void signal_gen_pwm_set_params(SignalGenPwm* pwm, uint8_t channel_id, uint32_t freq, uint8_t duty);
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="snake_game",
|
||||
appid="Snake",
|
||||
name="Snake Game",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="snake_game_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="spectrum_analyzer",
|
||||
appid="Spectrum_Analyzer",
|
||||
name="Spectrum Analyzer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="spectrum_analyzer_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="subbrute",
|
||||
appid="SubGHz_Bruteforcer",
|
||||
name="Sub-GHz Bruteforcer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="subbrute_app",
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
#include <subghz/environment.h>
|
||||
#include <subghz/transmitter.h>
|
||||
#include <flipper_format_i.h>
|
||||
#include <lib/subghz/subghz_tx_rx_worker.h>
|
||||
|
||||
#define TAG "SubBruteWorker"
|
||||
|
||||
struct SubBruteWorker {
|
||||
FuriThread* thread;
|
||||
SubGhzTxRxWorker* subghz_txrx;
|
||||
volatile bool worker_running;
|
||||
volatile bool worker_manual_mode;
|
||||
bool is_manual_init;
|
||||
bool is_continuous_worker;
|
||||
|
||||
SubGhzEnvironment* environment;
|
||||
SubGhzTransmitter* transmitter;
|
||||
@@ -31,80 +33,25 @@ struct SubBruteWorker {
|
||||
#define SUBBRUTE_TXRX_WORKER_BUF_SIZE 2048
|
||||
#define SUBBRUTE_TXRX_WORKER_MAX_TXRX_SIZE 60
|
||||
#define SUBBRUTE_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF 40
|
||||
#define SUBBRUTE_TX_TIMEOUT 1
|
||||
#define SUBBRUTE_SEND_DELAY 260
|
||||
|
||||
/**
|
||||
* Entrypoint for worker
|
||||
*
|
||||
* @param context SubBruteWorker*
|
||||
* @return 0 if ok
|
||||
*/
|
||||
int32_t subbrute_worker_thread(void* context) {
|
||||
furi_assert(context);
|
||||
SubBruteWorker* instance = (SubBruteWorker*)context;
|
||||
|
||||
if(!instance->worker_running) {
|
||||
FURI_LOG_W(TAG, "Worker is not set to running state!");
|
||||
return -1;
|
||||
}
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Worker start");
|
||||
#endif
|
||||
|
||||
//instance->environment = subghz_environment_alloc();
|
||||
instance->transmitter = subghz_transmitter_alloc_init(
|
||||
instance->environment, string_get_cstr(instance->protocol_name));
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(instance->preset);
|
||||
instance->frequency = furi_hal_subghz_set_frequency_and_path(instance->frequency);
|
||||
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_cc1101_g0, true);
|
||||
|
||||
// Set ready to transmit value
|
||||
//instance->last_time_tx_data = furi_get_tick() - SUBBRUTE_SEND_DELAY;
|
||||
|
||||
while(instance->worker_running) {
|
||||
// Transmit
|
||||
if(!furi_hal_subghz_tx()) {
|
||||
FURI_LOG_E(TAG, "Cannot transmit!");
|
||||
break;
|
||||
}
|
||||
furi_delay_ms(SUBBRUTE_TX_TIMEOUT);
|
||||
}
|
||||
|
||||
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
|
||||
furi_hal_subghz_sleep();
|
||||
|
||||
subghz_transmitter_free(instance->transmitter);
|
||||
instance->transmitter = NULL;
|
||||
/*subghz_environment_free(instance->environment);
|
||||
instance->environment = NULL;*/
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Worker stop");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#define SUBBRUTE_TX_TIMEOUT 5
|
||||
#define SUBBRUTE_SEND_DELAY 20
|
||||
|
||||
SubBruteWorker* subbrute_worker_alloc() {
|
||||
SubBruteWorker* instance = malloc(sizeof(SubBruteWorker));
|
||||
|
||||
instance->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(instance->thread, "SubBruteAttackWorker");
|
||||
furi_thread_set_stack_size(instance->thread, 2048);
|
||||
furi_thread_set_context(instance->thread, instance);
|
||||
furi_thread_set_callback(instance->thread, subbrute_worker_thread);
|
||||
|
||||
//instance->status = SubBruteWorkerStatusIDLE;
|
||||
instance->worker_running = false;
|
||||
instance->worker_manual_mode = false;
|
||||
|
||||
//instance->environment = subghz_environment_alloc();
|
||||
instance->transmitter = NULL;
|
||||
|
||||
instance->flipper_format = flipper_format_string_alloc();
|
||||
string_init(instance->protocol_name);
|
||||
|
||||
// SubGhzTxRxWorker
|
||||
instance->subghz_txrx = subghz_tx_rx_worker_alloc();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -122,11 +69,13 @@ void subbrute_worker_free(SubBruteWorker* instance) {
|
||||
instance->environment = NULL;
|
||||
}*/
|
||||
|
||||
furi_thread_free(instance->thread);
|
||||
flipper_format_free(instance->flipper_format);
|
||||
|
||||
string_clear(instance->protocol_name);
|
||||
|
||||
// SubGhzTxRxWorker
|
||||
subghz_tx_rx_worker_free(instance->subghz_txrx);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
@@ -138,6 +87,7 @@ bool subbrute_worker_start(
|
||||
furi_assert(instance);
|
||||
|
||||
if(instance->worker_manual_mode) {
|
||||
FURI_LOG_W(TAG, "Invalid mode for starting worker!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -156,19 +106,20 @@ bool subbrute_worker_start(
|
||||
furi_hal_subghz_set_frequency_and_path(instance->frequency);
|
||||
furi_hal_subghz_flush_rx();
|
||||
|
||||
if(furi_hal_subghz_is_tx_allowed(frequency)) {
|
||||
instance->frequency = frequency;
|
||||
res = true;
|
||||
}
|
||||
//if(furi_hal_subghz_is_tx_allowed(frequency)) {
|
||||
instance->frequency = frequency;
|
||||
res = true;
|
||||
//}
|
||||
instance->worker_running = res;
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Frequency: %d", frequency);
|
||||
#endif
|
||||
instance->preset = preset;
|
||||
|
||||
furi_thread_start(instance->thread);
|
||||
|
||||
if(res) {
|
||||
instance->worker_running = res =
|
||||
subghz_tx_rx_worker_start(instance->subghz_txrx, frequency);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -177,10 +128,21 @@ void subbrute_worker_stop(SubBruteWorker* instance) {
|
||||
|
||||
instance->worker_running = false;
|
||||
|
||||
furi_thread_join(instance->thread);
|
||||
if(subghz_tx_rx_worker_is_running(instance->subghz_txrx)) {
|
||||
subghz_tx_rx_worker_stop(instance->subghz_txrx);
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
|
||||
furi_hal_subghz_sleep();
|
||||
void subbrute_worker_set_continuous_worker(SubBruteWorker* instance, bool is_continuous_worker) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->is_continuous_worker = is_continuous_worker;
|
||||
}
|
||||
|
||||
bool subbrute_worker_get_continuous_worker(SubBruteWorker* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->is_continuous_worker;
|
||||
}
|
||||
|
||||
bool subbrute_worker_is_running(SubBruteWorker* instance) {
|
||||
@@ -190,10 +152,21 @@ bool subbrute_worker_is_running(SubBruteWorker* instance) {
|
||||
}
|
||||
|
||||
bool subbrute_worker_can_transmit(SubBruteWorker* instance) {
|
||||
UNUSED(instance);
|
||||
return true;
|
||||
//furi_assert(instance);
|
||||
//return (furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_SEND_DELAY;
|
||||
furi_assert(instance);
|
||||
|
||||
return (furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_SEND_DELAY;
|
||||
}
|
||||
|
||||
bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance, bool is_button_pressed) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(is_button_pressed) {
|
||||
// It's human pressed, trying to reset twice pressing
|
||||
return !instance->worker_manual_mode &&
|
||||
(furi_get_tick() - instance->last_time_tx_data) > 500;
|
||||
} else {
|
||||
return !instance->worker_manual_mode;
|
||||
}
|
||||
}
|
||||
|
||||
bool subbrute_worker_transmit(SubBruteWorker* instance, const char* payload) {
|
||||
@@ -211,14 +184,20 @@ bool subbrute_worker_transmit(SubBruteWorker* instance, const char* payload) {
|
||||
//FURI_LOG_D(TAG, "payload: %s", payload);
|
||||
#endif
|
||||
|
||||
Stream* stream = flipper_format_get_raw_stream(instance->flipper_format);
|
||||
stream_clean(stream);
|
||||
stream_write_cstring(stream, payload);
|
||||
subghz_transmitter_deserialize(instance->transmitter, instance->flipper_format);
|
||||
while(!subghz_tx_rx_worker_write(instance->subghz_txrx, (uint8_t*)payload, strlen(payload))) {
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
|
||||
furi_hal_subghz_flush_tx();
|
||||
// Stream* stream = flipper_format_get_raw_stream(instance->flipper_format);
|
||||
// stream_clean(stream);
|
||||
// stream_write_cstring(stream, payload);
|
||||
// subghz_transmitter_deserialize(instance->transmitter, instance->flipper_format);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Init MANUAL
|
||||
bool subbrute_worker_init_manual_transmit(
|
||||
SubBruteWorker* instance,
|
||||
uint32_t frequency,
|
||||
@@ -231,7 +210,8 @@ bool subbrute_worker_init_manual_transmit(
|
||||
frequency,
|
||||
protocol_name);
|
||||
#endif
|
||||
if(instance->worker_manual_mode || !subbrute_worker_can_transmit(instance)) {
|
||||
if(instance->worker_manual_mode || !subbrute_worker_can_manual_transmit(instance, false) ||
|
||||
instance->worker_running) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "cannot transmit");
|
||||
#endif
|
||||
@@ -265,19 +245,18 @@ bool subbrute_worker_init_manual_transmit(
|
||||
furi_hal_subghz_set_frequency_and_path(instance->frequency);
|
||||
furi_hal_subghz_flush_rx();
|
||||
|
||||
if(!furi_hal_subghz_is_tx_allowed(frequency)) {
|
||||
/*if(!furi_hal_subghz_is_tx_allowed(frequency)) {
|
||||
FURI_LOG_E(TAG, "Frequency: %d invalid!", frequency);
|
||||
|
||||
instance->frequency = frequency;
|
||||
instance->worker_manual_mode = false;
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Frequency: %d", frequency);
|
||||
#endif
|
||||
|
||||
//instance->environment = subghz_environment_alloc();
|
||||
instance->transmitter = subghz_transmitter_alloc_init(
|
||||
instance->environment, string_get_cstr(instance->protocol_name));
|
||||
|
||||
@@ -311,8 +290,6 @@ void subbrute_worker_manual_transmit_stop(SubBruteWorker* instance) {
|
||||
subghz_transmitter_free(instance->transmitter);
|
||||
instance->transmitter = NULL;
|
||||
}
|
||||
/*subghz_environment_free(instance->environment);
|
||||
instance->environment = NULL;*/
|
||||
|
||||
instance->is_manual_init = false;
|
||||
}
|
||||
@@ -327,9 +304,7 @@ bool subbrute_worker_manual_transmit(SubBruteWorker* instance, const char* paylo
|
||||
return false;
|
||||
}
|
||||
if(instance->worker_running) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "subbrute_worker_stop");
|
||||
#endif
|
||||
FURI_LOG_W(TAG, "Worker was working for manual mode. Shutdown thread");
|
||||
subbrute_worker_stop(instance);
|
||||
}
|
||||
if(!instance->is_manual_init) {
|
||||
|
||||
@@ -23,13 +23,17 @@ bool subbrute_worker_start(
|
||||
FuriHalSubGhzPreset preset,
|
||||
const char* protocol_name);
|
||||
void subbrute_worker_stop(SubBruteWorker* instance);
|
||||
bool subbrute_worker_get_continuous_worker(SubBruteWorker* instance);
|
||||
void subbrute_worker_set_continuous_worker(SubBruteWorker* instance, bool is_continuous_worker);
|
||||
//bool subbrute_worker_write(SubBruteWorker* instance, uint8_t* data, size_t size);
|
||||
bool subbrute_worker_is_running(SubBruteWorker* instance);
|
||||
bool subbrute_worker_can_transmit(SubBruteWorker* instance);
|
||||
bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance, bool is_button_pressed);
|
||||
bool subbrute_worker_transmit(SubBruteWorker* instance, const char* payload);
|
||||
bool subbrute_worker_init_manual_transmit(SubBruteWorker* instance,
|
||||
uint32_t frequency,
|
||||
FuriHalSubGhzPreset preset,
|
||||
const char* protocol_name);
|
||||
bool subbrute_worker_init_manual_transmit(
|
||||
SubBruteWorker* instance,
|
||||
uint32_t frequency,
|
||||
FuriHalSubGhzPreset preset,
|
||||
const char* protocol_name);
|
||||
bool subbrute_worker_manual_transmit(SubBruteWorker* instance, const char* payload);
|
||||
void subbrute_worker_manual_transmit_stop(SubBruteWorker* instance);
|
||||
@@ -45,19 +45,22 @@ void subbrute_scene_load_file_on_enter(void* context) {
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(load_result == SubBruteFileResultOk) {
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadSelect);
|
||||
if(load_result == SubBruteFileResultOk) {
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadSelect);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Returned error: %d", load_result);
|
||||
|
||||
string_t dialog_msg;
|
||||
string_init(dialog_msg);
|
||||
string_cat_printf(
|
||||
dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result));
|
||||
dialog_message_show_storage_error(instance->dialogs, string_get_cstr(dialog_msg));
|
||||
string_clear(dialog_msg);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
instance->scene_manager, SubBruteSceneStart);
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Returned error: %d", load_result);
|
||||
|
||||
string_t dialog_msg;
|
||||
string_init(dialog_msg);
|
||||
string_cat_printf(
|
||||
dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result));
|
||||
dialog_message_show_storage_error(instance->dialogs, string_get_cstr(dialog_msg));
|
||||
string_clear(dialog_msg);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
instance->scene_manager, SubBruteSceneStart);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "../views/subbrute_attack_view.h"
|
||||
#include "../helpers/subbrute_worker.h"
|
||||
|
||||
#define TAG "SubBruteSceneRunAttack"
|
||||
|
||||
static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
@@ -10,10 +12,57 @@ static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void*
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, event);
|
||||
}
|
||||
|
||||
//static void subbrute_scene_run_attack_worker_callback(void* context) {
|
||||
// SubBruteState* instance = (SubBruteState*)context;
|
||||
//
|
||||
// if(instance->locked || instance->device->key_index + 1 > instance->device->max_value) {
|
||||
// return;
|
||||
// }
|
||||
// instance->locked = true;
|
||||
//
|
||||
// if(subbrute_worker_can_manual_transmit(instance->worker)) {
|
||||
// // Blink
|
||||
// notification_message(instance->notifications, &sequence_blink_yellow_100);
|
||||
// subbrute_device_create_packet_parsed(instance->device, instance->device->key_index, true);
|
||||
//
|
||||
//#ifdef FURI_DEBUG
|
||||
// FURI_LOG_I(TAG, "subbrute_worker_manual_transmit");
|
||||
//#endif
|
||||
// if(subbrute_worker_manual_transmit(instance->worker, instance->device->payload)) {
|
||||
//#ifdef FURI_DEBUG
|
||||
// FURI_LOG_I(TAG, "transmit ok");
|
||||
//#endif
|
||||
// // Make payload for new iteration or exit
|
||||
// if(instance->device->key_index + 1 <= instance->device->max_value) {
|
||||
// instance->device->key_index++;
|
||||
// } else {
|
||||
// view_dispatcher_send_custom_event(
|
||||
// instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Stop
|
||||
// notification_message(instance->notifications, &sequence_blink_stop);
|
||||
// }
|
||||
//
|
||||
// instance->locked = false;
|
||||
// subbrute_attack_view_set_current_step(instance->view_attack, instance->device->key_index);
|
||||
//}
|
||||
|
||||
void subbrute_scene_run_attack_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubBruteState* instance = (SubBruteState*)context;
|
||||
// SubBruteAttackState* state = (SubBruteAttackState*)scene_manager_get_scene_state(
|
||||
// instance->scene_manager, SubBruteSceneRunAttack);
|
||||
// furi_assert(state);
|
||||
//
|
||||
// furi_timer_free(state->timer);
|
||||
// free(state);
|
||||
|
||||
if(subbrute_worker_get_continuous_worker(instance->worker)) {
|
||||
subbrute_worker_stop(instance->worker);
|
||||
}
|
||||
|
||||
notification_message(instance->notifications, &sequence_blink_stop);
|
||||
}
|
||||
|
||||
@@ -21,6 +70,10 @@ void subbrute_scene_run_attack_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
SubBruteState* instance = (SubBruteState*)context;
|
||||
SubBruteAttackView* view = instance->view_attack;
|
||||
//
|
||||
// SubBruteAttackState* state = malloc(sizeof(SubBruteAttackState));
|
||||
// scene_manager_set_scene_state(
|
||||
// instance->scene_manager, SubBruteSceneRunAttack, (uint32_t)state);
|
||||
|
||||
instance->current_view = SubBruteViewAttack;
|
||||
subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance);
|
||||
@@ -33,49 +86,107 @@ void subbrute_scene_run_attack_on_enter(void* context) {
|
||||
instance->device->key_index,
|
||||
true);
|
||||
|
||||
// Start worker if not started
|
||||
subbrute_worker_init_manual_transmit(
|
||||
instance->worker,
|
||||
instance->device->frequency,
|
||||
instance->device->preset,
|
||||
string_get_cstr(instance->device->protocol_name));
|
||||
if(subbrute_worker_get_continuous_worker(instance->worker)) {
|
||||
// Init Continuous worker with values!
|
||||
if(!subbrute_worker_start(
|
||||
instance->worker,
|
||||
instance->device->frequency,
|
||||
instance->device->preset,
|
||||
string_get_cstr(instance->device->protocol_name))) {
|
||||
FURI_LOG_W(TAG, "Worker Continuous init failed!");
|
||||
}
|
||||
} else {
|
||||
// Init worker with values
|
||||
if(!subbrute_worker_init_manual_transmit(
|
||||
instance->worker,
|
||||
instance->device->frequency,
|
||||
instance->device->preset,
|
||||
string_get_cstr(instance->device->protocol_name))) {
|
||||
FURI_LOG_W(TAG, "Worker init failed!");
|
||||
}
|
||||
|
||||
notification_message(instance->notifications, &sequence_blink_start_magenta);
|
||||
// state->timer = furi_timer_alloc(
|
||||
// subbrute_scene_run_attack_worker_callback, FuriTimerTypePeriodic, instance);
|
||||
// furi_timer_start(state->timer, pdMS_TO_TICKS(100)); // 20 ms
|
||||
}
|
||||
}
|
||||
|
||||
bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) {
|
||||
SubBruteState* instance = (SubBruteState*)context;
|
||||
SubBruteAttackView* view = instance->view_attack;
|
||||
// SubBruteAttackState* state = (SubBruteAttackState*)scene_manager_get_scene_state(
|
||||
// instance->scene_manager, SubBruteSceneRunAttack);
|
||||
// furi_assert(state);
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
SubBruteAttackView* view = instance->view_attack;
|
||||
|
||||
if(event.event == SubBruteCustomEventTypeTransmitNotStarted ||
|
||||
event.event == SubBruteCustomEventTypeTransmitFinished ||
|
||||
event.event == SubBruteCustomEventTypeBackPressed) {
|
||||
// furi_timer_stop(state->timer);
|
||||
// Stop transmit
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
|
||||
notification_message(instance->notifications, &sequence_display_backlight_on);
|
||||
notification_message(instance->notifications, &sequence_single_vibro);
|
||||
subbrute_attack_view_set_current_step(view, instance->device->key_index);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
instance->scene_manager, SubBruteSceneSetupAttack);
|
||||
consumed = true;
|
||||
} else if(event.event == SubBruteCustomEventTypeUpdateView) {
|
||||
subbrute_attack_view_set_current_step(view, instance->device->key_index);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
if(subbrute_worker_can_transmit(instance->worker)) {
|
||||
// Blink
|
||||
if(subbrute_worker_get_continuous_worker(instance->worker)) {
|
||||
if(subbrute_worker_can_transmit(instance->worker)) {
|
||||
// Blink
|
||||
notification_message(instance->notifications, &sequence_blink_yellow_100);
|
||||
|
||||
if(subbrute_worker_manual_transmit(instance->worker, instance->device->payload)) {
|
||||
// Make payload for new iteration or exit
|
||||
if(instance->device->key_index + 1 > instance->device->max_value) {
|
||||
// End of list
|
||||
notification_message(instance->notifications, &sequence_single_vibro);
|
||||
notification_message(instance->notifications, &sequence_blink_stop);
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
|
||||
} else {
|
||||
instance->device->key_index++;
|
||||
subbrute_attack_view_set_current_step(view, instance->device->key_index);
|
||||
subbrute_device_create_packet_parsed(
|
||||
instance->device, instance->device->key_index);
|
||||
subbrute_device_create_packet_parsed(
|
||||
instance->device, instance->device->key_index, true);
|
||||
|
||||
if(subbrute_worker_transmit(instance->worker, instance->device->payload)) {
|
||||
// Make payload for new iteration or exit
|
||||
if(instance->device->key_index + 1 > instance->device->max_value) {
|
||||
// End of list
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished);
|
||||
} else {
|
||||
instance->device->key_index++;
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, SubBruteCustomEventTypeUpdateView);
|
||||
//subbrute_attack_view_set_current_step(view, instance->device->key_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop
|
||||
// Stop
|
||||
notification_message(instance->notifications, &sequence_blink_stop);
|
||||
}
|
||||
} else {
|
||||
if(subbrute_worker_can_manual_transmit(instance->worker, false)) {
|
||||
// Blink
|
||||
notification_message(instance->notifications, &sequence_blink_yellow_100);
|
||||
|
||||
subbrute_device_create_packet_parsed(
|
||||
instance->device, instance->device->key_index, true);
|
||||
|
||||
if(subbrute_worker_manual_transmit(instance->worker, instance->device->payload)) {
|
||||
// Make payload for new iteration or exit
|
||||
if(instance->device->key_index + 1 > instance->device->max_value) {
|
||||
// End of list
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished);
|
||||
} else {
|
||||
instance->device->key_index++;
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, SubBruteCustomEventTypeUpdateView);
|
||||
//subbrute_attack_view_set_current_step(view, instance->device->key_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop
|
||||
notification_message(instance->notifications, &sequence_blink_stop);
|
||||
}
|
||||
}
|
||||
|
||||
consumed = true;
|
||||
|
||||
@@ -21,7 +21,7 @@ bool subbrute_scene_save_success_on_event(void* context, SceneManagerEvent event
|
||||
|
||||
SubBruteState* instance = (SubBruteState*)context;
|
||||
//SubBruteMainView* view = instance->view_main;
|
||||
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubBruteCustomEventTypePopupClosed) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
|
||||
@@ -27,11 +27,13 @@ void subbrute_scene_setup_attack_on_enter(void* context) {
|
||||
instance->device->key_index,
|
||||
false);
|
||||
|
||||
subbrute_worker_init_manual_transmit(
|
||||
instance->worker,
|
||||
instance->device->frequency,
|
||||
instance->device->preset,
|
||||
string_get_cstr(instance->device->protocol_name));
|
||||
if(!subbrute_worker_init_manual_transmit(
|
||||
instance->worker,
|
||||
instance->device->frequency,
|
||||
instance->device->preset,
|
||||
string_get_cstr(instance->device->protocol_name))) {
|
||||
FURI_LOG_W(TAG, "Worker init failed!");
|
||||
}
|
||||
|
||||
instance->current_view = SubBruteViewAttack;
|
||||
subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance);
|
||||
@@ -55,7 +57,13 @@ bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubBruteCustomEventTypeTransmitStarted) {
|
||||
subbrute_device_create_packet_parsed(instance->device, instance->device->key_index);
|
||||
subbrute_worker_set_continuous_worker(instance->worker, false);
|
||||
subbrute_attack_view_set_worker_type(view, false);
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack);
|
||||
} else if(event.event == SubBruteCustomEventTypeTransmitContinuousStarted) {
|
||||
// Setting different type of worker
|
||||
subbrute_worker_set_continuous_worker(instance->worker, true);
|
||||
subbrute_attack_view_set_worker_type(view, true);
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack);
|
||||
} else if(event.event == SubBruteCustomEventTypeSaveFile) {
|
||||
subbrute_worker_manual_transmit_stop(instance->worker);
|
||||
@@ -127,9 +135,9 @@ bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event
|
||||
}
|
||||
subbrute_attack_view_set_current_step(view, instance->device->key_index);
|
||||
} else if(event.event == SubBruteCustomEventTypeTransmitCustom) {
|
||||
if(subbrute_worker_can_transmit(instance->worker)) {
|
||||
if(subbrute_worker_can_manual_transmit(instance->worker, true)) {
|
||||
// Blink
|
||||
notification_message(instance->notifications, &sequence_blink_magenta_10);
|
||||
notification_message(instance->notifications, &sequence_blink_green_100);
|
||||
|
||||
// if(!subbrute_attack_view_is_worker_running(view)) {
|
||||
// subbrute_attack_view_start_worker(
|
||||
@@ -139,7 +147,7 @@ bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event
|
||||
// string_get_cstr(instance->device->protocol_name));
|
||||
// }
|
||||
subbrute_device_create_packet_parsed(
|
||||
instance->device, instance->device->key_index);
|
||||
instance->device, instance->device->key_index, false);
|
||||
subbrute_worker_manual_transmit(instance->worker, instance->device->payload);
|
||||
|
||||
// Stop
|
||||
|
||||
@@ -21,29 +21,31 @@
|
||||
#define TAG "SubBruteApp"
|
||||
|
||||
static const char* subbrute_menu_names[] = {
|
||||
[SubBruteAttackCAME12bit307] = "CAME 12bit 307mhz",
|
||||
[SubBruteAttackCAME12bit433] = "CAME 12bit 433mhz",
|
||||
[SubBruteAttackCAME12bit868] = "CAME 12bit 868mhz",
|
||||
[SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315mhz",
|
||||
[SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390mhz",
|
||||
[SubBruteAttackLinear10bit300] = "Linear 10bit 300mhz",
|
||||
[SubBruteAttackLinear10bit310] = "Linear 10bit 310mhz",
|
||||
[SubBruteAttackNICE12bit433] = "NICE 12bit 433mhz",
|
||||
[SubBruteAttackNICE12bit868] = "NICE 12bit 868mhz",
|
||||
[SubBruteAttackCAME12bit307] = "CAME 12bit 307MHz",
|
||||
[SubBruteAttackCAME12bit433] = "CAME 12bit 433MHz",
|
||||
[SubBruteAttackCAME12bit868] = "CAME 12bit 868MHz",
|
||||
[SubBruteAttackNICE12bit433] = "NICE 12bit 433MHz",
|
||||
[SubBruteAttackNICE12bit868] = "NICE 12bit 868MHz",
|
||||
[SubBruteAttackChamberlain9bit300] = "Chamberlain 9bit 300MHz",
|
||||
[SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315MHz",
|
||||
[SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390MHz",
|
||||
[SubBruteAttackLinear10bit300] = "Linear 10bit 300MHz",
|
||||
[SubBruteAttackLinear10bit310] = "Linear 10bit 310MHz",
|
||||
[SubBruteAttackLoadFile] = "BF existing dump",
|
||||
[SubBruteAttackTotalCount] = "Total Count",
|
||||
};
|
||||
|
||||
static const char* subbrute_menu_names_small[] = {
|
||||
[SubBruteAttackCAME12bit307] = "CAME 307mhz",
|
||||
[SubBruteAttackCAME12bit433] = "CAME 433mhz",
|
||||
[SubBruteAttackCAME12bit868] = "CAME 868mhz",
|
||||
[SubBruteAttackChamberlain9bit315] = "Cham 315mhz",
|
||||
[SubBruteAttackChamberlain9bit390] = "Cham 390mhz",
|
||||
[SubBruteAttackLinear10bit300] = "Linear 300mhz",
|
||||
[SubBruteAttackLinear10bit310] = "Linear 310mhz",
|
||||
[SubBruteAttackNICE12bit433] = "NICE 433mhz",
|
||||
[SubBruteAttackNICE12bit868] = "NICE 868mhz",
|
||||
[SubBruteAttackCAME12bit307] = "CAME 307MHz",
|
||||
[SubBruteAttackCAME12bit433] = "CAME 433MHz",
|
||||
[SubBruteAttackCAME12bit868] = "CAME 868MHz",
|
||||
[SubBruteAttackNICE12bit433] = "NICE 433MHz",
|
||||
[SubBruteAttackNICE12bit868] = "NICE 868MHz",
|
||||
[SubBruteAttackChamberlain9bit300] = "Cham 300MHz",
|
||||
[SubBruteAttackChamberlain9bit315] = "Cham 315MHz",
|
||||
[SubBruteAttackChamberlain9bit390] = "Cham 390MHz",
|
||||
[SubBruteAttackLinear10bit300] = "Linear 300MHz",
|
||||
[SubBruteAttackLinear10bit310] = "Linear 310MHz",
|
||||
[SubBruteAttackLoadFile] = "Existing",
|
||||
[SubBruteAttackTotalCount] = "Total Count",
|
||||
};
|
||||
@@ -81,7 +83,7 @@ SubBruteState* subbrute_alloc() {
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
instance->view_dispatcher, subbrute_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
instance->view_dispatcher, subbrute_tick_event_callback, 100);
|
||||
instance->view_dispatcher, subbrute_tick_event_callback, 10);
|
||||
|
||||
//Dialog
|
||||
instance->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
@@ -297,6 +299,7 @@ int32_t subbrute_app(void* p) {
|
||||
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
notification_message(instance->notifications, &sequence_display_backlight_on);
|
||||
view_dispatcher_run(instance->view_dispatcher);
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
subbrute_free(instance);
|
||||
|
||||
@@ -10,11 +10,12 @@ typedef enum {
|
||||
SubBruteCustomEventTypeBackPressed,
|
||||
SubBruteCustomEventTypeIndexSelected,
|
||||
SubBruteCustomEventTypeTransmitStarted,
|
||||
SubBruteCustomEventTypeTransmitContinuousStarted,
|
||||
SubBruteCustomEventTypeTransmitFinished,
|
||||
SubBruteCustomEventTypeTransmitNotStarted,
|
||||
SubBruteCustomEventTypeTransmitCustom,
|
||||
SubBruteCustomEventTypeSaveFile,
|
||||
SubBruteCustomEventTypeSaveSuccess,
|
||||
SubBruteCustomEventTypeUpdateView,
|
||||
SubBruteCustomEventTypeChangeStepUp,
|
||||
SubBruteCustomEventTypeChangeStepDown,
|
||||
SubBruteCustomEventTypeChangeStepUpMore,
|
||||
|
||||
@@ -37,6 +37,8 @@ static const char* subbrute_key_file_start =
|
||||
"Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d";
|
||||
static const char* subbrute_key_file_key = "%s\nKey: %s\n";
|
||||
static const char* subbrute_key_file_princeton_end = "%s\nKey: %s\nTE: %d\n";
|
||||
static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\n";
|
||||
static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\n";
|
||||
|
||||
// Why nobody set in as const in all codebase?
|
||||
static const char* preset_ook270_async = "FuriHalSubGhzPresetOok270Async";
|
||||
@@ -58,8 +60,6 @@ SubBruteDevice* subbrute_device_alloc() {
|
||||
|
||||
instance->decoder_result = NULL;
|
||||
instance->receiver = NULL;
|
||||
instance->environment = NULL;
|
||||
|
||||
instance->environment = subghz_environment_alloc();
|
||||
|
||||
subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit307);
|
||||
@@ -84,13 +84,8 @@ void subbrute_device_free(SubBruteDevice* instance) {
|
||||
instance->receiver = NULL;
|
||||
}
|
||||
|
||||
if(instance->environment != NULL) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "subghz_environment_free");
|
||||
#endif
|
||||
subghz_environment_free(instance->environment);
|
||||
instance->environment = NULL;
|
||||
}
|
||||
subghz_environment_free(instance->environment);
|
||||
instance->environment = NULL;
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "before free");
|
||||
@@ -109,7 +104,7 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name);
|
||||
#endif
|
||||
bool result = subbrute_device_create_packet_parsed(instance, instance->key_index);
|
||||
bool result = subbrute_device_create_packet_parsed(instance, instance->key_index, false);
|
||||
|
||||
if(!result) {
|
||||
FURI_LOG_E(TAG, "subbrute_device_create_packet_parsed failed!");
|
||||
@@ -193,7 +188,7 @@ const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool subbrute_device_create_packet_parsed(SubBruteDevice* instance, uint64_t step) {
|
||||
bool subbrute_device_create_packet_parsed(SubBruteDevice* instance, uint64_t step, bool small) {
|
||||
furi_assert(instance);
|
||||
|
||||
//char step_payload[32];
|
||||
@@ -236,21 +231,40 @@ bool subbrute_device_create_packet_parsed(SubBruteDevice* instance, uint64_t ste
|
||||
FURI_LOG_D(TAG, "candidate: %s, step: %d", string_get_cstr(candidate), step);
|
||||
#endif
|
||||
|
||||
if(instance->has_tail) {
|
||||
snprintf(
|
||||
instance->payload,
|
||||
sizeof(instance->payload),
|
||||
subbrute_key_file_princeton_end,
|
||||
instance->file_template,
|
||||
string_get_cstr(candidate),
|
||||
instance->te);
|
||||
if(small) {
|
||||
if(instance->has_tail) {
|
||||
snprintf(
|
||||
instance->payload,
|
||||
sizeof(instance->payload),
|
||||
subbrute_key_small_with_tail,
|
||||
instance->bit,
|
||||
string_get_cstr(candidate),
|
||||
instance->te);
|
||||
} else {
|
||||
snprintf(
|
||||
instance->payload,
|
||||
sizeof(instance->payload),
|
||||
subbrute_key_small_no_tail,
|
||||
instance->bit,
|
||||
string_get_cstr(candidate));
|
||||
}
|
||||
} else {
|
||||
snprintf(
|
||||
instance->payload,
|
||||
sizeof(instance->payload),
|
||||
subbrute_key_file_key,
|
||||
instance->file_template,
|
||||
string_get_cstr(candidate));
|
||||
if(instance->has_tail) {
|
||||
snprintf(
|
||||
instance->payload,
|
||||
sizeof(instance->payload),
|
||||
subbrute_key_file_princeton_end,
|
||||
instance->file_template,
|
||||
string_get_cstr(candidate),
|
||||
instance->te);
|
||||
} else {
|
||||
snprintf(
|
||||
instance->payload,
|
||||
sizeof(instance->payload),
|
||||
subbrute_key_file_key,
|
||||
instance->file_template,
|
||||
string_get_cstr(candidate));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FURI_DEBUG
|
||||
@@ -292,14 +306,16 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute
|
||||
string_set_str(instance->protocol_name, protocol_came);
|
||||
string_set_str(instance->preset_name, preset_ook650_async);
|
||||
break;
|
||||
case SubBruteAttackChamberlain9bit300:
|
||||
case SubBruteAttackChamberlain9bit315:
|
||||
instance->frequency = 315000000;
|
||||
instance->bit = 9;
|
||||
string_set_str(instance->protocol_name, protocol_cham_code);
|
||||
string_set_str(instance->preset_name, preset_ook650_async);
|
||||
break;
|
||||
case SubBruteAttackChamberlain9bit390:
|
||||
instance->frequency = 390000000;
|
||||
if(type == SubBruteAttackChamberlain9bit300) {
|
||||
instance->frequency = 300000000;
|
||||
} else if(type == SubBruteAttackChamberlain9bit315) {
|
||||
instance->frequency = 315000000;
|
||||
} else /* ALWAYS TRUE if(type == SubBruteAttackChamberlain9bit390) */ {
|
||||
instance->frequency = 390000000;
|
||||
}
|
||||
instance->bit = 9;
|
||||
string_set_str(instance->protocol_name, protocol_cham_code);
|
||||
string_set_str(instance->preset_name, preset_ook650_async);
|
||||
@@ -333,13 +349,12 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute
|
||||
return SubBruteFileResultProtocolNotFound; // RETURN
|
||||
}
|
||||
|
||||
if(!furi_hal_subghz_is_tx_allowed(instance->frequency)) {
|
||||
/*if(!furi_hal_subghz_is_tx_allowed(instance->frequency)) {
|
||||
FURI_LOG_E(TAG, "Frequency invalid: %d", instance->frequency);
|
||||
return SubBruteFileResultMissingOrIncorrectFrequency; // RETURN
|
||||
}
|
||||
}*/
|
||||
|
||||
// For non-file types we didn't set SubGhzProtocolDecoderBase
|
||||
//instance->environment = subghz_environment_alloc();
|
||||
instance->receiver = subghz_receiver_alloc_init(instance->environment);
|
||||
subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable);
|
||||
furi_hal_subghz_reset();
|
||||
@@ -361,10 +376,8 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute
|
||||
protocol_check_result = SubBruteFileResultOk;
|
||||
}
|
||||
|
||||
//subghz_environment_free(instance->environment);
|
||||
subghz_receiver_free(instance->receiver);
|
||||
instance->receiver = NULL;
|
||||
//instance->environment = NULL;
|
||||
|
||||
if(protocol_check_result != SubBruteFileResultOk) {
|
||||
return SubBruteFileResultProtocolNotFound;
|
||||
@@ -409,7 +422,7 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute
|
||||
#endif
|
||||
|
||||
// Init payload
|
||||
subbrute_device_create_packet_parsed(instance, instance->key_index);
|
||||
subbrute_device_create_packet_parsed(instance, instance->key_index, false);
|
||||
|
||||
return SubBruteFileResultOk;
|
||||
}
|
||||
@@ -428,7 +441,6 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, string_t file_p
|
||||
string_init(temp_str);
|
||||
uint32_t temp_data32;
|
||||
|
||||
//instance->environment = subghz_environment_alloc();
|
||||
instance->receiver = subghz_receiver_alloc_init(instance->environment);
|
||||
subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable);
|
||||
furi_hal_subghz_reset();
|
||||
@@ -563,12 +575,10 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, string_t file_p
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
//subghz_environment_free(instance->environment);
|
||||
subghz_receiver_free(instance->receiver);
|
||||
|
||||
instance->decoder_result = NULL;
|
||||
instance->receiver = NULL;
|
||||
//instance->environment = NULL;
|
||||
|
||||
if(result == SubBruteFileResultOk) {
|
||||
#ifdef FURI_DEBUG
|
||||
|
||||
@@ -20,12 +20,13 @@ typedef enum {
|
||||
SubBruteAttackCAME12bit307,
|
||||
SubBruteAttackCAME12bit433,
|
||||
SubBruteAttackCAME12bit868,
|
||||
SubBruteAttackNICE12bit433,
|
||||
SubBruteAttackNICE12bit868,
|
||||
SubBruteAttackChamberlain9bit300,
|
||||
SubBruteAttackChamberlain9bit315,
|
||||
SubBruteAttackChamberlain9bit390,
|
||||
SubBruteAttackLinear10bit300,
|
||||
SubBruteAttackLinear10bit310,
|
||||
SubBruteAttackNICE12bit433,
|
||||
SubBruteAttackNICE12bit868,
|
||||
SubBruteAttackLoadFile,
|
||||
SubBruteAttackTotalCount,
|
||||
} SubBruteAttacks;
|
||||
@@ -92,8 +93,10 @@ SubBruteDevice* subbrute_device_alloc();
|
||||
void subbrute_device_free(SubBruteDevice* instance);
|
||||
bool subbrute_device_save_file(SubBruteDevice* instance, const char* key_name);
|
||||
const char* subbrute_device_error_get_desc(SubBruteFileResult error_id);
|
||||
bool subbrute_device_create_packet_parsed(SubBruteDevice* context, uint64_t step);
|
||||
bool subbrute_device_create_packet_parsed(SubBruteDevice* context, uint64_t step, bool small);
|
||||
SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* context, SubBruteAttacks type);
|
||||
uint8_t subbrute_device_load_from_file(SubBruteDevice* context, string_t file_path);
|
||||
FuriHalSubGhzPreset subbrute_device_convert_preset(const char* preset);
|
||||
void subbrute_device_attack_set_default_values(SubBruteDevice* context, SubBruteAttacks default_attack);
|
||||
void subbrute_device_attack_set_default_values(
|
||||
SubBruteDevice* context,
|
||||
SubBruteAttacks default_attack);
|
||||
@@ -20,6 +20,7 @@ typedef struct {
|
||||
uint64_t max_value;
|
||||
uint64_t current_step;
|
||||
bool is_attacking;
|
||||
bool is_continuous_worker;
|
||||
IconAnimation* icon;
|
||||
} SubBruteAttackViewModel;
|
||||
|
||||
@@ -47,6 +48,7 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) {
|
||||
with_view_model(
|
||||
instance->view, (SubBruteAttackViewModel * model) {
|
||||
model->is_attacking = false;
|
||||
model->is_continuous_worker = false;
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
@@ -67,25 +69,45 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) {
|
||||
// }
|
||||
|
||||
if(!is_attacking) {
|
||||
if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
|
||||
event->key == InputKeyOk) {
|
||||
if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "InputKey: %d OK", event->key);
|
||||
#endif
|
||||
with_view_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;
|
||||
});
|
||||
instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);
|
||||
// } else if(event->key == InputKeyBack) {
|
||||
// if(previous_scene == SubBruteSceneLoadFile) {
|
||||
// instance->callback(SubBruteCustomEventTypeLoadFile, instance->context);
|
||||
// } else {
|
||||
// instance->callback(SubBruteCustomEventTypeBackPressed, instance->context);
|
||||
// }
|
||||
/*if(event->type == InputTypeRepeat && event->key == InputKeyOk) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "InputKey: %d OK. SubBruteCustomEventTypeTransmitContinuousStarted", event->key);
|
||||
#endif
|
||||
with_view_model(
|
||||
instance->view, (SubBruteAttackViewModel * model) {
|
||||
model->is_attacking = true;
|
||||
model->is_continuous_worker = true;
|
||||
icon_animation_stop(model->icon);
|
||||
icon_animation_start(model->icon);
|
||||
return true;
|
||||
});
|
||||
instance->callback(SubBruteCustomEventTypeTransmitContinuousStarted, instance->context);
|
||||
} else if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "InputKey: %d OK", event->key);
|
||||
#endif
|
||||
with_view_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;
|
||||
});
|
||||
instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);*/
|
||||
} else if(event->key == InputKeyUp) {
|
||||
instance->callback(SubBruteCustomEventTypeSaveFile, instance->context);
|
||||
} else if(event->key == InputKeyDown) {
|
||||
@@ -131,6 +153,7 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) {
|
||||
with_view_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;
|
||||
@@ -161,7 +184,6 @@ SubBruteAttackView* subbrute_attack_view_alloc() {
|
||||
view_set_enter_callback(instance->view, subbrute_attack_view_enter);
|
||||
view_set_exit_callback(instance->view, subbrute_attack_view_exit);
|
||||
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -198,7 +220,7 @@ View* subbrute_attack_view_get_view(SubBruteAttackView* instance) {
|
||||
void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step) {
|
||||
furi_assert(instance);
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "Set step: %d", current_step);
|
||||
//FURI_LOG_D(TAG, "Set step: %d", current_step);
|
||||
#endif
|
||||
with_view_model(
|
||||
instance->view, (SubBruteAttackViewModel * model) {
|
||||
@@ -207,17 +229,13 @@ void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_
|
||||
});
|
||||
}
|
||||
|
||||
uint64_t subbrute_attack_view_get_current_step(SubBruteAttackView* instance) {
|
||||
uint64_t current_step;
|
||||
void subbrute_attack_view_set_worker_type(SubBruteAttackView* instance, bool is_continuous_worker) {
|
||||
furi_assert(instance);
|
||||
with_view_model(
|
||||
instance->view, (SubBruteAttackViewModel * model) {
|
||||
current_step = model->current_step;
|
||||
return false;
|
||||
model->is_continuous_worker = is_continuous_worker;
|
||||
return true;
|
||||
});
|
||||
#ifdef FURI_DEBUG
|
||||
FURI_LOG_D(TAG, "Get step: %d", current_step);
|
||||
#endif
|
||||
return current_step;
|
||||
}
|
||||
|
||||
// We need to call init every time, because not every time we calls enter
|
||||
@@ -356,6 +374,9 @@ void subbrute_attack_view_draw(Canvas* canvas, void* context) {
|
||||
elements_button_top_left(canvas, "Save");
|
||||
elements_button_top_right(canvas, "Resend");
|
||||
} else {
|
||||
if(model->is_continuous_worker) {
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
// canvas_draw_icon_animation
|
||||
const uint8_t icon_h_offset = 0;
|
||||
const uint8_t icon_width_with_offset = model->icon->icon->width + icon_h_offset;
|
||||
@@ -370,5 +391,8 @@ void subbrute_attack_view_draw(Canvas* canvas, void* context) {
|
||||
elements_progress_bar(canvas, 8, 37, 110, progress_value > 1 ? 1 : progress_value);
|
||||
|
||||
elements_button_center(canvas, "Stop");
|
||||
if(model->is_continuous_worker) {
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ SubBruteAttackView* subbrute_attack_view_alloc();
|
||||
void subbrute_attack_view_free(SubBruteAttackView* instance);
|
||||
View* subbrute_attack_view_get_view(SubBruteAttackView* instance);
|
||||
void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step);
|
||||
uint64_t subbrute_attack_view_get_current_step(SubBruteAttackView* instance);
|
||||
void subbrute_attack_view_set_worker_type(SubBruteAttackView* instance, bool is_continuous_worker);
|
||||
void subbrute_attack_view_init_values(
|
||||
SubBruteAttackView* instance,
|
||||
uint8_t index,
|
||||
|
||||
@@ -85,7 +85,7 @@ void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_box(canvas, 0, 0, canvas_width(canvas), STATUS_BAR_Y_SHIFT);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Sub-GHz Bruteforcer");
|
||||
canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, "Sub-GHz Bruteforcer");
|
||||
canvas_invert_color(canvas);
|
||||
|
||||
if(m->is_select_byte) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="tetris_game",
|
||||
appid="Tetris",
|
||||
name="Tetris",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="tetris_game_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="tictactoe_game",
|
||||
appid="TicTacToe",
|
||||
name="Tic Tac Toe",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="tictactoe_game_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="wav_player",
|
||||
appid="WAV_Player",
|
||||
name="WAV Player",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="wav_player_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="wifi_marauder",
|
||||
appid="ESP32_WiFi_Marauder",
|
||||
name="[ESP32] WiFi Marauder",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="wifi_marauder_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="wifi_scanner",
|
||||
appid="WiFi_Scanner",
|
||||
name="[WiFi] Scanner",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="wifi_scanner_app",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="game_zombiez",
|
||||
appid="Zombiez",
|
||||
name="Zombiez",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="zombiez_game_app",
|
||||
|
||||
@@ -165,8 +165,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_game.fap"));
|
||||
LoaderStatus status =
|
||||
loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/Snake.fap"));
|
||||
if(status != LoaderStatusOk) {
|
||||
FURI_LOG_E(TAG, "loader_start failed: %d", status);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ typedef struct {
|
||||
uint8_t descender;
|
||||
} CanvasFontParameters;
|
||||
|
||||
/** Canvas anonymouse structure */
|
||||
/** Canvas anonymous structure */
|
||||
typedef struct Canvas Canvas;
|
||||
|
||||
/** Get Canvas width
|
||||
@@ -298,7 +298,7 @@ void canvas_draw_disc(Canvas* canvas, uint8_t x, uint8_t y, uint8_t r);
|
||||
* @param y y coordinate of base and height intersection
|
||||
* @param base length of triangle side
|
||||
* @param height length of triangle height
|
||||
* @param dir CanvasDirection triangle orientaion
|
||||
* @param dir CanvasDirection triangle orientation
|
||||
*/
|
||||
void canvas_draw_triangle(
|
||||
Canvas* canvas,
|
||||
@@ -324,7 +324,7 @@ void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch);
|
||||
*/
|
||||
void canvas_set_bitmap_mode(Canvas* canvas, bool alpha);
|
||||
|
||||
/** Draw rounded-corner frame of width, height at x,y, with round value raduis
|
||||
/** Draw rounded-corner frame of width, height at x,y, with round value radius
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
|
||||
@@ -59,7 +59,7 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param index value to pass to callback
|
||||
* @param matrix_place_x coordinates by x-axis on virtual grid, it
|
||||
* is only used for naviagation
|
||||
* is only used for navigation
|
||||
* @param matrix_place_y coordinates by y-axis on virtual grid, it
|
||||
* is only used for naviagation
|
||||
* @param x x-coordinate to draw icon on
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define TAG "BrowserWorker"
|
||||
|
||||
#define ASSETS_DIR "assets"
|
||||
#define BADUSB_LAYOUTS_DIR "layouts"
|
||||
#define BROWSER_ROOT STORAGE_ANY_PATH_PREFIX
|
||||
#define FILE_NAME_LEN_MAX 256
|
||||
#define LONG_LOAD_THRESHOLD 100
|
||||
@@ -78,7 +79,8 @@ static bool browser_filter_by_name(BrowserWorker* browser, string_t name, bool i
|
||||
if(is_folder) {
|
||||
// Skip assets folders (if enabled)
|
||||
if(browser->skip_assets) {
|
||||
return ((string_cmp_str(name, ASSETS_DIR) == 0) ? (false) : (true));
|
||||
return ((string_cmp_str(name, ASSETS_DIR) == 0) ? (false) : (true)) &&
|
||||
((string_cmp_str(name, BADUSB_LAYOUTS_DIR) == 0) ? (false) : (true));
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -232,7 +232,8 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
if(text_length == 0 && char_is_lowercase(keys[column].text)) {
|
||||
if(model->clear_default_text ||
|
||||
(text_length == 0 && char_is_lowercase(keys[column].text))) {
|
||||
canvas_draw_glyph(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
|
||||
@@ -149,7 +149,7 @@ void power_free(Power* power) {
|
||||
|
||||
static void power_check_charging_state(Power* power) {
|
||||
if(furi_hal_power_is_charging()) {
|
||||
if(power->info.charge == 100) {
|
||||
if((power->info.charge == 100) || (furi_hal_power_is_charging_done())) {
|
||||
if(power->state != PowerStateCharged) {
|
||||
notification_internal_message(power->notification, &sequence_charged);
|
||||
power->state = PowerStateCharged;
|
||||
|
||||
@@ -10,7 +10,7 @@ extern "C" {
|
||||
#include <stdbool.h>
|
||||
#include <m-string.h>
|
||||
|
||||
#define UPDATE_DELAY_OPERATION_OK 300
|
||||
#define UPDATE_DELAY_OPERATION_OK 10
|
||||
#define UPDATE_DELAY_OPERATION_ERROR INT_MAX
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <update_util/dfu_file.h>
|
||||
#include <update_util/lfs_backup.h>
|
||||
#include <update_util/update_operation.h>
|
||||
#include <update_util/resources/manifest.h>
|
||||
#include <toolbox/tar/tar_archive.h>
|
||||
#include <toolbox/crc32_calc.h>
|
||||
|
||||
@@ -50,10 +51,46 @@ static bool update_task_resource_unpack_cb(const char* name, bool is_directory,
|
||||
update_task_set_progress(
|
||||
unpack_progress->update_task,
|
||||
UpdateTaskStageProgress,
|
||||
unpack_progress->processed_files * 100 / (unpack_progress->total_files + 1));
|
||||
/* For this stage, last 70% of progress = extraction */
|
||||
30 + (unpack_progress->processed_files * 70) / (unpack_progress->total_files + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
update_task_cleanup_resources(UpdateTask* update_task, uint32_t n_approx_file_entries) {
|
||||
ResourceManifestReader* manifest_reader = resource_manifest_reader_alloc(update_task->storage);
|
||||
do {
|
||||
FURI_LOG_I(TAG, "Cleaning up old manifest");
|
||||
if(!resource_manifest_reader_open(manifest_reader, EXT_PATH("Manifest"))) {
|
||||
FURI_LOG_W(TAG, "No existing manifest");
|
||||
break;
|
||||
}
|
||||
|
||||
/* We got # of entries in TAR file. Approx 1/4th is dir entries, we skip them */
|
||||
n_approx_file_entries = n_approx_file_entries * 3 / 4 + 1;
|
||||
uint32_t n_processed_files = 0;
|
||||
|
||||
ResourceManifestEntry* entry_ptr = NULL;
|
||||
while((entry_ptr = resource_manifest_reader_next(manifest_reader))) {
|
||||
if(entry_ptr->type == ResourceManifestEntryTypeFile) {
|
||||
update_task_set_progress(
|
||||
update_task,
|
||||
UpdateTaskStageProgress,
|
||||
/* For this stage, first 30% of progress = cleanup */
|
||||
(n_processed_files++ * 30) / (n_approx_file_entries + 1));
|
||||
|
||||
string_t file_path;
|
||||
string_init(file_path);
|
||||
path_concat(STORAGE_EXT_PATH_PREFIX, string_get_cstr(entry_ptr->name), file_path);
|
||||
FURI_LOG_D(TAG, "Removing %s", string_get_cstr(file_path));
|
||||
storage_simply_remove(update_task->storage, string_get_cstr(file_path));
|
||||
string_clear(file_path);
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
resource_manifest_reader_free(manifest_reader);
|
||||
}
|
||||
|
||||
static bool update_task_post_update(UpdateTask* update_task) {
|
||||
bool success = false;
|
||||
|
||||
@@ -88,6 +125,8 @@ static bool update_task_post_update(UpdateTask* update_task) {
|
||||
|
||||
progress.total_files = tar_archive_get_entries_count(archive);
|
||||
if(progress.total_files > 0) {
|
||||
update_task_cleanup_resources(update_task, progress.total_files);
|
||||
|
||||
CHECK_RESULT(tar_archive_unpack_to(archive, STORAGE_EXT_PATH_PREFIX, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ bool update_task_validate_optionbytes(UpdateTask* update_task) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_I(
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"OB MATCH: #%d: real %08X == %08X (exp.)",
|
||||
idx,
|
||||
|
||||
BIN
assets/icons/Interface/SmallArrowDown_4x7.png
Normal file
BIN
assets/icons/Interface/SmallArrowDown_4x7.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
BIN
assets/icons/Interface/SmallArrowUp_4x7.png
Normal file
BIN
assets/icons/Interface/SmallArrowUp_4x7.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
@@ -1,7 +1,25 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 20th Sept, 2022
|
||||
# Last Updated 28th Sept, 2022
|
||||
#
|
||||
# SWING ON
|
||||
name: SWING
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3158 1552 601 1065 575 1093 596 328 560 330 555 329 556 1068 573 338 545 341 544 1095 571 1096 571 341 543 1101 566 342 543 342 542 1125 543 1125 542 343 542 1124 542 1125 542 344 542 343 542 1126 542 344 541 345 541 1124 542 344 542 345 541 344 541 345 540 345 541 343 541 345 540 345 541 345 541 345 541 345 541 345 541 343 541 345 541 345 541 344 542 344 541 1127 541 345 541 344 542 1126 541 345 541 345 541 1126 541 1127 541 345 541 343 541 345 541 345 541 345 541 344 541 1127 541 346 541 1127 540 1127 541 345 541 344 541 345 541 346 540 1127 541 1127 540 344 541 1128 541 1126 541 1127 541 345 541 345 541 344 540 345 541 345 541 345 541 345 541 345 541 344 541 345 541 345 541 345 541 345 541 345 541 345 541 344 541 345 541 345 541 345 541 345 541 345 541 345 541 344 541 345 541 345 541 345 541 345 541 345 541 345 541 344 541 345 541 345 541 345 541 345 541 345 541 345 540 1127 541 345 541 345 541 344 541 346 541 1127 542
|
||||
# ON
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3126 1586 542 1123 544 1124 543 346 540 344 542 344 541 1124 543 345 541 343 541 1124 543 1125 542 346 540 1124 542 346 540 346 516 1149 518 1150 517 369 516 1151 517 1148 518 369 517 370 516 1148 518 369 516 369 541 1125 543 342 542 344 542 345 541 346 540 371 515 371 515 371 514 370 514 371 515 371 515 371 515 371 515 371 515 370 515 371 514 371 515 372 515 1151 515 371 515 372 515 1151 515 372 514 372 515 1153 514 1153 515 371 515 372 514 370 514 372 514 372 514 372 514 1153 514 1153 514 1131 538 1127 539 347 539 346 540 346 540 345 540 1128 540 347 540 1126 540 346 540 345 541 345 541 345 541 345 541 345 541 343 541 345 541 345 541 345 541 345 541 345 541 344 541 343 541 344 542 344 542 345 541 345 541 344 542 343 541 344 542 345 541 344 542 345 541 345 541 345 541 344 540 345 541 345 541 345 541 345 541 345 541 345 541 343 541 345 541 345 541 345 541 345 541 345 541 345 541 344 541 1127 541 344 541 1127 541 345 541
|
||||
# ON
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3034 3976 1907 1980 1914 2004 1880 1006 941 1032 915 999 937 1008 939 1982 933 1008 1907 2008 939 978 1916 998 970 980 936 976 971 1034 913 1000 936 1984 942 997 1939 975 941 1003 944 1004 943 999 937 1037 941 971 965 984 942 999 969 1919 975 1025 3890 3957 1936 1982 1912 1940 1944 1038 909 1033 914 996 940 1009 938 1948 967 1009 1917 1970 945 994 1942 979 937 1034 913 1003 944 1000 936 1012 935 1981 934 1008 1907 1036 932 982 944 1036 911 1027 910 1004 964 984 942 1033 914 999 937 1976 939 1008 3917 3982 1932 1922 1941 1945 1970 981 945 997 940 1008 939 1004 943 1979 936 998 1917 1943 972 1002 1913 1032 904 1013 944 1000 936 1041 906 1001 967 1923 972 1003 1912 1030 906 1009 969 975 941 1004 943 1002 945 996 940 975 972 1005 942 1944 971 968 4915
|
||||
# ON
|
||||
name: POWER
|
||||
type: raw
|
||||
@@ -1232,4 +1250,28 @@ type: parsed
|
||||
protocol: NEC
|
||||
address: 80 00 00 00
|
||||
command: 92 00 00 00
|
||||
# OFF
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3031 3980 1912 1945 1969 1950 1912 973 994 981 965 951 975 1027 909 1950 975 965 971 974 1941 1006 940 977 969 1003 964 951 975 1000 936 1006 940 973 973 1974 941 973 1942 1006 941 974 993 950 975 999 937 1036 910 975 992 952 974 998 938 1950 975 967 3947 3987 1916 2002 1881 1975 1939 947 999 943 972 971 996 948 967 1949 997 949 976 997 1907 980 966 1006 941 975 971 1001 945 999 968 945 970 976 970 1974 972 942 1942 975 992 952 994 949 977 970 997 948 967 979 967 1005 942 999 968 1923 971 1000 3914 3958 1965 1919 1995 1893 1969 984 962 954 972 996 971 973 942 1949 976 992 965 947 1947 1002 965 950 976 1001 945 997 939 1007 939 1006 940 998 969 1915 1000 944 2002 946 969 944 992 956 1001 943 972 1000 967 949 966 977 969 1001 966 1926 968 1003 4889
|
||||
# OFF
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3160 1550 576 1092 576 1091 577 329 555 338 573 329 558 1065 601 329 557 329 556 1065 601 1066 575 338 547 1093 574 339 546 339 546 1095 573 1095 572 339 546 1096 572 1097 571 341 544 341 544 1124 544 342 543 342 543 1125 542 344 542 344 541 344 542 344 542 343 541 344 542 344 542 344 542 344 542 344 542 344 542 343 541 344 542 344 542 344 542 344 542 344 542 344 542 343 541 345 542 1126 542 343 541 345 541 1126 542 1126 542 344 542 344 542 344 542 343 541 344 542 345 541 1126 541 1126 541 1127 542 1127 541 343 542 345 541 344 542 345 542 1125 541 345 542 1127 541 343 542 345 541 345 541 345 541 345 541 345 541 345 541 343 541 345 541 345 541 345 541 345 541 345 541 345 541 344 541 345 541 345 541 345 541 345 541 345 541 345 541 344 540 345 541 345 541 345 541 345 541 345 541 344 541 345 541 345 541 345 541 346 540 345 541 344 540 345 541 346 540 345 541 345 541 345 540 1128 541 1126 541 345 541 346 541 1126 541 345 541
|
||||
# SWING OFF
|
||||
name: SWING
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3186 1522 603 1065 602 1063 603 330 554 330 556 330 551 1068 600 330 529 340 546 1093 573 1094 573 340 545 1095 573 340 545 340 545 1097 570 1098 569 343 543 1123 544 1125 542 343 542 343 542 1126 542 344 542 343 542 1126 541 344 542 345 541 345 541 343 541 344 541 345 541 344 541 345 541 345 541 345 541 343 541 345 541 345 541 345 541 344 541 345 541 344 541 1126 541 345 541 344 541 1126 541 345 541 344 541 1127 541 1125 541 345 541 345 541 345 541 345 541 345 541 344 541 1128 540 345 540 1128 541 1126 541 345 541 346 540 346 540 345 540 1129 540 1128 540 344 541 346 540 346 540 346 540 346 540 345 541 346 540 344 540 346 540 346 539 346 540 346 540 346 540 346 539 344 540 346 540 346 540 346 540 346 540 346 540 345 539 346 540 346 540 346 540 346 540 346 539 346 540 345 540 346 540 346 540 347 539 346 540 346 540 346 540 345 539 346 540 346 540 346 540 346 540 346 539 1129 540 1127 539 347 539 347 540 1127 539 346 540
|
||||
#
|
||||
name: MODE
|
||||
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
|
||||
#
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 17th Sept, 2022
|
||||
# Last Updated 27th Sept, 2022
|
||||
#
|
||||
# ON
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3522 1701 472 426 444 1269 472 426 444 426 443 427 443 427 443 426 444 427 443 426 444 427 442 428 441 429 440 431 438 1304 437 433 437 433 438 433 437 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1305 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 459 411 459 411 459 411 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 459 411 459 411 1330 411 1330 411 460 410 1330 411 1330 411 1331 410 1330 411 74392 3516 1736 436 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 435 435 1305 436 435 435 435 435 1306 435 435 435 435 435 435 435 436 434 436 434 436 434 435 435 436 434 436 434 436 434 1330 411 1331 410 1330 411 1330 411 1330 411 459 411 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 435 436 434 436 1306 435 435 435 435 435 1306 435 435 435 435 435 435 435 435 435 435 435 436 434 436 434 435 435 436 434 435 435 1306 435 1330 411 1307 434 1331 410 1308 433 436 434 436 434 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 435 435 434 436 434 436 434 436 434 436 434 436 1306 435 435 435 435 435 435 435 1306 435 435 435 436 434 1306 435 435 435 436 434 436 434 435 435 436 434 436 434 460 410 460 410 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 434 436 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 435 435 435 435 434 436 1306 435 434 436 435 435 435 435 1306 435 436 434 435 435 1306 435 435 435 436 434 436 434 436 434 436 434 460 410 437 433 459 411 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3514 1736 437 434 436 1304 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 435 435 434 436 434 436 435 435 434 436 1305 436 435 435 435 435 435 435 1306 435 435 435 435 435 1306 435 435 435 436 434 435 435 459 411 436 434 435 435 459 411 459 411 459 411 459 411 1330 411 1306 435 1330 411 1330 411 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410
|
||||
# ON
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 529 7218 126 6585 219 703 180 5362 427 18618 177
|
||||
#
|
||||
name: VOL+
|
||||
@@ -410,4 +416,9 @@ type: parsed
|
||||
protocol: Samsung32
|
||||
address: 07 00 00 00
|
||||
command: 0F 00 00 00
|
||||
#
|
||||
# OFF
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3523 1701 472 426 444 1269 472 426 444 426 442 429 443 427 443 426 444 426 444 426 443 427 442 429 440 430 439 432 438 1304 437 433 437 432 438 432 438 433 437 433 437 433 437 433 437 433 437 433 437 1304 437 433 437 433 437 433 437 1304 437 433 437 433 437 1304 437 433 437 434 436 433 437 434 436 434 436 434 436 433 437 433 437 434 436 1304 437 1305 436 1305 436 1305 436 1305 436 1305 436 434 436 434 436 1305 436 1305 436 1305 436 434 436 1305 436 1305 436 1306 435 1306 435 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 1304 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 436 434 435 435 1307 434 1331 410 1307 434 1307 434 1330 411 1307 434 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 434 436 433 437 433 437 1304 437 434 436 434 436 434 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 435 435 434 436 1305 436 434 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1306 435 1307 434 1307 434 1307 434 1331 410 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 1304 437 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 437 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410
|
||||
|
||||
@@ -1,6 +1,30 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 25th Sept, 2022
|
||||
# Last Updated 28th Sept, 2022
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3557 1672 516 388 488 1237 515 389 487 389 487 389 487 389 486 389 487 388 487 365 512 386 490 386 489 386 489 387 488 1263 488 389 485 391 483 392 483 394 481 397 479 398 478 421 455 398 478 421 455 1297 455 421 455 421 455 421 455 421 455 421 455 421 455 421 455 421 455 1298 454 421 455 1298 454 1298 454 1298 454 1298 454 421 455 422 454 1298 454 422 454 1298 454 1299 453 1299 453 1298 454 422 454 1298 454 74664 3522 1735 454 422 454 1299 453 422 454 422 454 422 454 422 454 422 454 422 454 422 454 422 454 422 454 422 454 422 454 1299 453 422 454 422 454 422 454 422 454 422 454 422 454 422 454 422 454 422 454 1299 453 422 454 422 454 423 453 423 453 423 453 422 454 423 453 423 453 1299 453 423 453 1299 453 1299 453 1300 452 1299 453 423 453 423 453 1300 452 423 453 1300 452 1300 452 1300 452 1300 452 423 453 1300 452 74665 3522 1735 453 422 454 1299 453 422 454 422 454 422 454 422 454 422 454 422 453 422 454 422 454 422 454 422 454 422 454 1299 453 422 454 422 454 422 454 422 454 422 454 422 454 422 454 422 454 423 453 1299 453 423 453 422 454 422 454 422 454 422 454 423 453 423 453 423 453 1299 453 423 453 1299 453 1299 453 1299 453 1299 453 423 453 423 453 1299 453 423 453 1299 453 1299 453 1299 453 1300 452 423 453 1299 453 74662 3527 1705 482 394 482 1270 482 394 482 393 483 394 482 393 483 393 483 393 483 393 483 393 483 394 482 393 483 394 482 1294 458 418 458 417 459 417 459 418 458 418 458 418 458 418 458 418 458 418 458 1295 457 419 456 419 457 419 457 419 457 419 457 419 457 419 457 419 457 1296 456 419 457 1296 456 1297 455 1297 455 1299 453 446 430 446 430 1323 429 446 430 1323 429 1323 429 1323 429 1323 429 446 430 1323 429
|
||||
#
|
||||
name: VOL+
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3542 1717 467 411 465 1285 467 411 493 383 493 382 494 381 466 409 467 408 493 383 493 383 492 384 491 387 488 413 462 1290 461 416 459 416 460 416 460 417 459 417 459 416 460 417 459 417 459 417 459 1293 459 417 459 417 459 417 459 417 458 417 459 417 459 417 459 417 458 417 459 417 459 417 459 417 459 417 459 1293 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 1294 458 417 459 1294 458 74496 3534 1725 460 416 460 1293 459 416 460 417 459 417 459 416 460 416 460 416 460 416 460 416 460 416 460 416 459 417 459 1293 459 416 460 417 459 417 459 417 459 416 460 417 459 417 459 416 460 417 459 1293 459 416 460 417 459 416 460 417 459 417 459 416 460 416 460 417 459 417 459 417 459 417 459 417 459 416 460 1293 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 1293 459 417 459 1293 459 74497 3534 1725 459 416 460 1293 459 416 460 417 459 417 459 416 460 417 459 417 459 416 460 417 459 417 459 417 459 417 459 1293 459 417 459 417 459 417 459 417 459 417 459 417 458 417 459 417 459 417 459 1294 458 417 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 418 458 418 458 417 459 418 458 1294 458 417 459 418 458 418 458 418 458 418 458 418 458 418 458 1294 458 418 458 1294 458
|
||||
#
|
||||
name: VOL-
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3540 1691 494 383 465 1284 468 409 492 383 493 383 492 384 491 386 488 388 486 414 461 415 460 416 460 416 460 416 460 1293 459 416 460 416 460 416 460 416 460 416 460 416 460 417 459 417 459 417 459 1293 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 1293 459 416 460 417 459 417 459 416 459 1294 458 417 459 417 458 1294 458 417 459 417 459 417 459 417 459 1294 458 417 459 1294 458 74801 3534 1725 459 416 460 1293 459 416 460 416 460 416 460 417 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 1293 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 1294 458 417 459 417 459 417 459 417 459 417 459 417 459 417 459 417 459 1294 458 417 459 417 459 418 458 418 458 1294 458 418 458 418 458 1294 458 418 458 418 458 418 458 418 458 1294 458 418 458 1294 458
|
||||
#
|
||||
name: MUTE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3512 1685 500 409 467 1256 496 409 467 409 466 410 466 410 466 409 467 410 466 410 466 410 495 381 495 380 522 353 493 1256 469 407 494 381 495 382 493 383 492 384 491 386 489 413 462 414 461 415 460 1291 461 415 461 415 461 415 461 415 461 415 461 415 461 415 461 415 461 415 461 1292 460 415 461 415 461 1292 460 1292 460 415 461 415 461 415 461 1292 460 416 460 415 461 1292 460 1292 460 415 461 1292 460 74573 3531 1726 460 416 460 1292 460 416 460 416 460 416 460 392 484 415 460 416 460 416 460 393 483 393 483 392 484 393 483 1268 484 392 484 392 484 392 484 392 484 392 484 392 484 392 484 392 484 392 484 1268 484 392 484 392 484 392 484 392 484 392 484 392 484 392 484 392 484 392 484 1268 484 392 484 391 485 1268 484 1268 484 392 484 392 484 392 484 1292 460 392 484 392 484 1269 483 1269 483 392 484 1292 460
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
|
||||
@@ -44,6 +44,7 @@ Frequency: 464000000
|
||||
Frequency: 779000000
|
||||
Frequency: 868350000
|
||||
Frequency: 868400000
|
||||
Frequency: 868800000
|
||||
Frequency: 868950000
|
||||
Frequency: 906400000
|
||||
Frequency: 915000000
|
||||
|
||||
@@ -48,7 +48,7 @@ The following parameters are used only for [FAPs](./AppsOnSDCard.md):
|
||||
* **fap_icon**: name of a .png file, 1-bit color depth, 10x10px, to be embedded within .fap file.
|
||||
* **fap_libs**: list of extra libraries to link application against. Provides access to extra functions that are not exported as a part of main firmware at expense of increased .fap file size and RAM consumption.
|
||||
* **fap_category**: string, may be empty. App subcategory, also works as path of FAP within apps folder in the file system.
|
||||
* **fap_description**: string, may be empty. Short application descriotion.
|
||||
* **fap_description**: string, may be empty. Short application description.
|
||||
* **fap_author**: string, may be empty. Application's author.
|
||||
* **fap_weburl**: string, may be empty. Application's homepage.
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_types.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_config.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,,
|
||||
@@ -974,6 +975,8 @@ Function,+,furi_hal_cdc_set_callbacks,void,"uint8_t, CdcCallbacks*, void*"
|
||||
Function,+,furi_hal_clock_deinit_early,void,
|
||||
Function,-,furi_hal_clock_init,void,
|
||||
Function,-,furi_hal_clock_init_early,void,
|
||||
Function,+,furi_hal_clock_mco_disable,void,
|
||||
Function,+,furi_hal_clock_mco_enable,void,"FuriHalClockMcoSourceId, FuriHalClockMcoDivisorId"
|
||||
Function,-,furi_hal_clock_resume_tick,void,
|
||||
Function,-,furi_hal_clock_suspend_tick,void,
|
||||
Function,-,furi_hal_clock_switch_to_hsi,void,
|
||||
@@ -1161,6 +1164,7 @@ Function,+,furi_hal_power_insomnia_enter,void,
|
||||
Function,+,furi_hal_power_insomnia_exit,void,
|
||||
Function,-,furi_hal_power_insomnia_level,uint16_t,
|
||||
Function,+,furi_hal_power_is_charging,_Bool,
|
||||
Function,+,furi_hal_power_is_charging_done,_Bool,
|
||||
Function,+,furi_hal_power_is_otg_enabled,_Bool,
|
||||
Function,+,furi_hal_power_off,void,
|
||||
Function,+,furi_hal_power_reset,void,
|
||||
@@ -1169,6 +1173,9 @@ Function,+,furi_hal_power_sleep,void,
|
||||
Function,+,furi_hal_power_sleep_available,_Bool,
|
||||
Function,+,furi_hal_power_suppress_charge_enter,void,
|
||||
Function,+,furi_hal_power_suppress_charge_exit,void,
|
||||
Function,+,furi_hal_pwm_set_params,void,"FuriHalPwmOutputId, uint32_t, uint8_t"
|
||||
Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t"
|
||||
Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId
|
||||
Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t"
|
||||
Function,+,furi_hal_random_get,uint32_t,
|
||||
Function,+,furi_hal_region_get_name,const char*,
|
||||
@@ -2734,6 +2741,7 @@ Function,+,tar_archive_get_entries_count,int32_t,TarArchive*
|
||||
Function,+,tar_archive_open,_Bool,"TarArchive*, const char*, TarOpenMode"
|
||||
Function,+,tar_archive_set_file_callback,void,"TarArchive*, tar_unpack_file_cb, void*"
|
||||
Function,+,tar_archive_store_data,_Bool,"TarArchive*, const char*, const uint8_t*, const int32_t"
|
||||
Function,+,tar_archive_unpack_file,_Bool,"TarArchive*, const char*, const char*"
|
||||
Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, Storage_name_converter"
|
||||
Function,-,tempnam,char*,"const char*, const char*"
|
||||
Function,+,text_box_alloc,TextBox*,
|
||||
@@ -4207,6 +4215,8 @@ Variable,+,I_SDQuestion_35x43,const Icon,
|
||||
Variable,+,I_SDcardFail_11x8,const Icon,
|
||||
Variable,+,I_SDcardMounted_11x8,const Icon,
|
||||
Variable,+,I_Scanning_123x52,const Icon,
|
||||
Variable,+,I_SmallArrowDown_4x7,const Icon,
|
||||
Variable,+,I_SmallArrowUp_4x7,const Icon,
|
||||
Variable,+,I_Smile_18x18,const Icon,
|
||||
Variable,+,I_Space_65x18,const Icon,
|
||||
Variable,+,I_Swing_25x27,const Icon,
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include <furi_hal_clock.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi.h>
|
||||
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
@@ -236,3 +237,63 @@ void furi_hal_clock_suspend_tick() {
|
||||
void furi_hal_clock_resume_tick() {
|
||||
SET_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);
|
||||
}
|
||||
|
||||
void furi_hal_clock_mco_enable(FuriHalClockMcoSourceId source, FuriHalClockMcoDivisorId div) {
|
||||
if(source == FuriHalClockMcoLse) {
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_LSE, div);
|
||||
} else if(source == FuriHalClockMcoSysclk) {
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_SYSCLK, div);
|
||||
} else {
|
||||
LL_RCC_MSI_Enable();
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
;
|
||||
switch(source) {
|
||||
case FuriHalClockMcoMsi100k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_0);
|
||||
break;
|
||||
case FuriHalClockMcoMsi200k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_1);
|
||||
break;
|
||||
case FuriHalClockMcoMsi400k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_2);
|
||||
break;
|
||||
case FuriHalClockMcoMsi800k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_3);
|
||||
break;
|
||||
case FuriHalClockMcoMsi1m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_4);
|
||||
break;
|
||||
case FuriHalClockMcoMsi2m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_5);
|
||||
break;
|
||||
case FuriHalClockMcoMsi4m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);
|
||||
break;
|
||||
case FuriHalClockMcoMsi8m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_7);
|
||||
break;
|
||||
case FuriHalClockMcoMsi16m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_8);
|
||||
break;
|
||||
case FuriHalClockMcoMsi24m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_9);
|
||||
break;
|
||||
case FuriHalClockMcoMsi32m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_10);
|
||||
break;
|
||||
case FuriHalClockMcoMsi48m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_11);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_MSI, div);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_clock_mco_disable() {
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_NOCLOCK, FuriHalClockMcoDiv1);
|
||||
LL_RCC_MSI_Disable();
|
||||
while(LL_RCC_MSI_IsReady() != 0)
|
||||
;
|
||||
}
|
||||
@@ -4,6 +4,33 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
|
||||
typedef enum {
|
||||
FuriHalClockMcoLse,
|
||||
FuriHalClockMcoSysclk,
|
||||
FuriHalClockMcoMsi100k,
|
||||
FuriHalClockMcoMsi200k,
|
||||
FuriHalClockMcoMsi400k,
|
||||
FuriHalClockMcoMsi800k,
|
||||
FuriHalClockMcoMsi1m,
|
||||
FuriHalClockMcoMsi2m,
|
||||
FuriHalClockMcoMsi4m,
|
||||
FuriHalClockMcoMsi8m,
|
||||
FuriHalClockMcoMsi16m,
|
||||
FuriHalClockMcoMsi24m,
|
||||
FuriHalClockMcoMsi32m,
|
||||
FuriHalClockMcoMsi48m,
|
||||
} FuriHalClockMcoSourceId;
|
||||
|
||||
typedef enum {
|
||||
FuriHalClockMcoDiv1 = LL_RCC_MCO1_DIV_1,
|
||||
FuriHalClockMcoDiv2 = LL_RCC_MCO1_DIV_2,
|
||||
FuriHalClockMcoDiv4 = LL_RCC_MCO1_DIV_4,
|
||||
FuriHalClockMcoDiv8 = LL_RCC_MCO1_DIV_8,
|
||||
FuriHalClockMcoDiv16 = LL_RCC_MCO1_DIV_16,
|
||||
} FuriHalClockMcoDivisorId;
|
||||
|
||||
/** Early initialization */
|
||||
void furi_hal_clock_init_early();
|
||||
|
||||
@@ -25,6 +52,16 @@ void furi_hal_clock_suspend_tick();
|
||||
/** Continue SysTick counter operation */
|
||||
void furi_hal_clock_resume_tick();
|
||||
|
||||
/** Enable clock output on MCO pin
|
||||
*
|
||||
* @param source MCO clock source
|
||||
* @param div MCO clock division
|
||||
*/
|
||||
void furi_hal_clock_mco_enable(FuriHalClockMcoSourceId source, FuriHalClockMcoDivisorId div);
|
||||
|
||||
/** Disable clock output on MCO pin */
|
||||
void furi_hal_clock_mco_disable();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,9 @@ void furi_hal_cortex_init_early() {
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
DWT->CYCCNT = 0U;
|
||||
|
||||
/* Enable instruction prefetch */
|
||||
SET_BIT(FLASH->ACR, FLASH_ACR_PRFTEN);
|
||||
}
|
||||
|
||||
void furi_hal_cortex_delay_us(uint32_t microseconds) {
|
||||
|
||||
@@ -266,6 +266,13 @@ bool furi_hal_power_is_charging() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_power_is_charging_done() {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bool ret = bq25896_is_charging_done(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_power_shutdown() {
|
||||
furi_hal_power_insomnia_enter();
|
||||
|
||||
|
||||
138
firmware/targets/f7/furi_hal/furi_hal_pwm.c
Normal file
138
firmware/targets/f7/furi_hal/furi_hal_pwm.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "furi_hal_pwm.h"
|
||||
#include <core/check.h>
|
||||
#include <furi_hal_resources.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <stm32wbxx_ll_lptim.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
const uint32_t lptim_psc_table[] = {
|
||||
LL_LPTIM_PRESCALER_DIV1,
|
||||
LL_LPTIM_PRESCALER_DIV2,
|
||||
LL_LPTIM_PRESCALER_DIV4,
|
||||
LL_LPTIM_PRESCALER_DIV8,
|
||||
LL_LPTIM_PRESCALER_DIV16,
|
||||
LL_LPTIM_PRESCALER_DIV32,
|
||||
LL_LPTIM_PRESCALER_DIV64,
|
||||
LL_LPTIM_PRESCALER_DIV128,
|
||||
};
|
||||
|
||||
void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) {
|
||||
if(channel == FuriHalPwmOutputIdTim1PA7) {
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pa7,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn1TIM1);
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_TIM_DeInit(TIM1);
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetRepetitionCounter(TIM1, 0);
|
||||
LL_TIM_SetClockDivision(TIM1, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_EnableARRPreload(TIM1);
|
||||
|
||||
LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
|
||||
LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
|
||||
LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N);
|
||||
|
||||
LL_TIM_EnableAllOutputs(TIM1);
|
||||
|
||||
furi_hal_pwm_set_params(channel, freq, duty);
|
||||
|
||||
LL_TIM_EnableCounter(TIM1);
|
||||
} else if(channel == FuriHalPwmOutputIdLptim2PA4) {
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pa4,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn14LPTIM2);
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_LPTIM_DeInit(LPTIM2);
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
LL_LPTIM_SetUpdateMode(LPTIM2, LL_LPTIM_UPDATE_MODE_ENDOFPERIOD);
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1);
|
||||
LL_LPTIM_SetClockSource(LPTIM2, LL_LPTIM_CLK_SOURCE_INTERNAL);
|
||||
LL_LPTIM_ConfigOutput(
|
||||
LPTIM2, LL_LPTIM_OUTPUT_WAVEFORM_PWM, LL_LPTIM_OUTPUT_POLARITY_INVERSE);
|
||||
LL_LPTIM_SetCounterMode(LPTIM2, LL_LPTIM_COUNTER_MODE_INTERNAL);
|
||||
|
||||
LL_LPTIM_Enable(LPTIM2);
|
||||
|
||||
furi_hal_pwm_set_params(channel, freq, duty);
|
||||
|
||||
LL_LPTIM_StartCounter(LPTIM2, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_pwm_stop(FuriHalPwmOutputId channel) {
|
||||
if(channel == FuriHalPwmOutputIdTim1PA7) {
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog);
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_TIM_DeInit(TIM1);
|
||||
FURI_CRITICAL_EXIT();
|
||||
} else if(channel == FuriHalPwmOutputIdLptim2PA4) {
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog);
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_LPTIM_DeInit(LPTIM2);
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) {
|
||||
furi_assert(freq > 0);
|
||||
uint32_t freq_div = 64000000LU / freq;
|
||||
|
||||
if(channel == FuriHalPwmOutputIdTim1PA7) {
|
||||
uint32_t prescaler = freq_div / 0x10000LU;
|
||||
uint32_t period = freq_div / (prescaler + 1);
|
||||
uint32_t compare = period * duty / 100;
|
||||
|
||||
LL_TIM_SetPrescaler(TIM1, prescaler);
|
||||
LL_TIM_SetAutoReload(TIM1, period - 1);
|
||||
LL_TIM_OC_SetCompareCH1(TIM1, compare);
|
||||
} else if(channel == FuriHalPwmOutputIdLptim2PA4) {
|
||||
uint32_t prescaler = 0;
|
||||
uint32_t period = 0;
|
||||
|
||||
bool clock_lse = false;
|
||||
|
||||
do {
|
||||
period = freq_div / (1 << prescaler);
|
||||
if(period <= 0xFFFF) {
|
||||
break;
|
||||
}
|
||||
prescaler++;
|
||||
if(prescaler > 7) {
|
||||
prescaler = 0;
|
||||
clock_lse = true;
|
||||
period = 32768LU / freq;
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
|
||||
uint32_t compare = period * duty / 100;
|
||||
|
||||
LL_LPTIM_SetPrescaler(LPTIM2, lptim_psc_table[prescaler]);
|
||||
LL_LPTIM_SetAutoReload(LPTIM2, period);
|
||||
LL_LPTIM_SetCompare(LPTIM2, compare);
|
||||
|
||||
if(clock_lse) {
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE);
|
||||
} else {
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
firmware/targets/f7/furi_hal/furi_hal_pwm.h
Normal file
42
firmware/targets/f7/furi_hal/furi_hal_pwm.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file furi_hal_pwm.h
|
||||
* PWM contol HAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
FuriHalPwmOutputIdTim1PA7,
|
||||
FuriHalPwmOutputIdLptim2PA4,
|
||||
} FuriHalPwmOutputId;
|
||||
|
||||
/** Enable PWM channel and set parameters
|
||||
*
|
||||
* @param[in] channel PWM channel (FuriHalPwmOutputId)
|
||||
* @param[in] freq Frequency in Hz
|
||||
* @param[in] duty Duty cycle value in %
|
||||
*/
|
||||
void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty);
|
||||
|
||||
/** Disable PWM channel
|
||||
*
|
||||
* @param[in] channel PWM channel (FuriHalPwmOutputId)
|
||||
*/
|
||||
void furi_hal_pwm_stop(FuriHalPwmOutputId channel);
|
||||
|
||||
/** Set PWM channel parameters
|
||||
*
|
||||
* @param[in] channel PWM channel (FuriHalPwmOutputId)
|
||||
* @param[in] freq Frequency in Hz
|
||||
* @param[in] duty Duty cycle value in %
|
||||
*/
|
||||
void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -85,6 +85,12 @@ uint8_t furi_hal_power_get_bat_health_pct();
|
||||
*/
|
||||
bool furi_hal_power_is_charging();
|
||||
|
||||
/** Get charge complete status
|
||||
*
|
||||
* @return true if done charging and connected to charger
|
||||
*/
|
||||
bool furi_hal_power_is_charging_done();
|
||||
|
||||
/** Switch MCU to SHUTDOWN */
|
||||
void furi_hal_power_shutdown();
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "bq25896.h"
|
||||
#include "bq25896_reg.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -81,7 +80,7 @@ void bq25896_poweroff(FuriHalI2cBusHandle* handle) {
|
||||
handle, BQ25896_ADDRESS, 0x09, *(uint8_t*)&bq25896_regs.r09, BQ25896_I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
bool bq25896_is_charging(FuriHalI2cBusHandle* handle) {
|
||||
ChrgStat bq25896_get_charge_status(FuriHalI2cBusHandle* handle) {
|
||||
furi_hal_i2c_read_mem(
|
||||
handle,
|
||||
BQ25896_ADDRESS,
|
||||
@@ -91,7 +90,16 @@ bool bq25896_is_charging(FuriHalI2cBusHandle* handle) {
|
||||
BQ25896_I2C_TIMEOUT);
|
||||
furi_hal_i2c_read_reg_8(
|
||||
handle, BQ25896_ADDRESS, 0x0B, (uint8_t*)&bq25896_regs.r0B, BQ25896_I2C_TIMEOUT);
|
||||
return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo;
|
||||
return bq25896_regs.r0B.CHRG_STAT;
|
||||
}
|
||||
|
||||
bool bq25896_is_charging(FuriHalI2cBusHandle* handle) {
|
||||
// Include precharge, fast charging, and charging termination done as "charging"
|
||||
return bq25896_get_charge_status(handle) != ChrgStatNo;
|
||||
}
|
||||
|
||||
bool bq25896_is_charging_done(FuriHalI2cBusHandle* handle) {
|
||||
return bq25896_get_charge_status(handle) == ChrgStatDone;
|
||||
}
|
||||
|
||||
void bq25896_enable_charging(FuriHalI2cBusHandle* handle) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "bq25896_reg.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <furi_hal_i2c.h>
|
||||
@@ -10,9 +12,15 @@ void bq25896_init(FuriHalI2cBusHandle* handle);
|
||||
/** Send device into shipping mode */
|
||||
void bq25896_poweroff(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get charging status */
|
||||
ChrgStat bq25896_get_charge_status(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Is currently charging */
|
||||
bool bq25896_is_charging(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Is charging completed while connected to charger */
|
||||
bool bq25896_is_charging_done(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Enable charging */
|
||||
void bq25896_enable_charging(FuriHalI2cBusHandle* handle);
|
||||
|
||||
|
||||
@@ -925,7 +925,7 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) {
|
||||
flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_a, 6);
|
||||
}
|
||||
if(!key_save_success) break;
|
||||
if(FURI_BIT(data->key_a_mask, i)) {
|
||||
if(FURI_BIT(data->key_b_mask, i)) {
|
||||
string_printf(temp_str, "Key B sector %d", i);
|
||||
key_save_success =
|
||||
flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_b, 6);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user