mirror of
https://github.com/D4C1-Labs/Flipper-ARF.git
synced 2026-03-30 13:15:38 +00:00
Compare commits
3 Commits
dev-41191d
...
dev-730bb3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
730bb318fb | ||
|
|
ce085b6895 | ||
|
|
f4c753b673 |
78
README.md
78
README.md
@@ -16,7 +16,6 @@ This project may incorporate, adapt, or build upon **other open-source projects*
|
||||
- [Supported Systems](#supported-systems)
|
||||
- [How to Build](#how-to-build)
|
||||
- [Project Scope](#project-scope)
|
||||
- [Implemented Protocols](#implemented-protocols)
|
||||
- [To Do / Planned Features](#to-do--planned-features)
|
||||
- [Design Philosophy](#design-philosophy)
|
||||
- [Research Direction](#research-direction)
|
||||
@@ -190,7 +189,8 @@ The following academic publications have been invaluable to the development and
|
||||
|
||||
- **Lock It and Still Lose It — On the (In)Security of Automotive Remote Keyless Entry Systems**
|
||||
Flavio D. Garcia, David Oswald, Timo Kasper, Pierre Pavlidès
|
||||
*USENIX Security 2016*
|
||||
*USENIX Security 2016, pp. 929–944*
|
||||
DOI: [10.5555/3241094.3241166](https://doi.org/10.5555/3241094.3241166)
|
||||
https://www.usenix.org/system/files/conference/usenixsecurity16/sec16_paper_garcia.pdf
|
||||
|
||||
- **Clonable Key Fobs: Analyzing and Breaking RKE Protocols**
|
||||
@@ -213,33 +213,65 @@ The following academic publications have been invaluable to the development and
|
||||
*Wiley, February 2025*
|
||||
DOI: [10.1002/9781394351930.ch11](https://doi.org/10.1002/9781394351930.ch11)
|
||||
|
||||
### DST Cipher Family (DST40 / DST80)
|
||||
|
||||
- **Security Analysis of a Cryptographically-Enabled RFID Device**
|
||||
Steve Bono, Matthew Green, Adam Stubblefield, Ari Juels, Avi Rubin, Michael Szydlo
|
||||
*14th USENIX Security Symposium (USENIX Security '05)*
|
||||
https://www.usenix.org/conference/14th-usenix-security-symposium/security-analysis-cryptographically-enabled-rfid-device
|
||||
https://www.usenix.org/legacy/event/sec05/tech/bono/bono.pdf
|
||||
|
||||
- **Dismantling DST80-based Immobiliser Systems**
|
||||
Lennert Wouters, Jan Van den Herrewegen, Flavio D. Garcia, David Oswald, Benedikt Gierlichs, Bart Preneel
|
||||
*IACR Transactions on Cryptographic Hardware and Embedded Systems (TCHES), 2020, Vol. 2020(2), pp. 99–127*
|
||||
DOI: [10.13154/tches.v2020.i2.99-127](https://doi.org/10.13154/tches.v2020.i2.99-127)
|
||||
|
||||
### KeeLoq Cryptanalysis
|
||||
|
||||
- **Cryptanalysis of the KeeLoq Block Cipher**
|
||||
Andrey Bogdanov
|
||||
*Cryptology ePrint Archive, Paper 2007/055*
|
||||
*Cryptology ePrint Archive, Paper 2007/055; also presented at RFIDSec 2007*
|
||||
https://eprint.iacr.org/2007/055
|
||||
|
||||
- **On the Power of Power Analysis in the Real World: A Complete Break of the KeeLoq Code Hopping Scheme**
|
||||
Thomas Eisenbarth, Timo Kasper, Amir Moradi, Christof Paar, Mahmoud Salmasizadeh, Mohammad T. Manzuri Shalmani
|
||||
*CRYPTO 2008*
|
||||
https://www.iacr.org/archive/crypto2008/51570204/51570204.pdf
|
||||
|
||||
- **A Practical Attack on KeeLoq**
|
||||
Sebastiaan Indesteege, Nathan Keller, Orr Dunkelman, Eli Biham, Bart Preneel
|
||||
*EUROCRYPT 2008*
|
||||
*EUROCRYPT 2008 (LNCS vol. 4965, pp. 1–18)*
|
||||
DOI: [10.1007/978-3-540-78967-3_1](https://doi.org/10.1007/978-3-540-78967-3_1)
|
||||
https://www.iacr.org/archive/eurocrypt2008/49650001/49650001.pdf
|
||||
|
||||
- **Algebraic and Slide Attacks on KeeLoq**
|
||||
Nicolas T. Courtois, Gregory V. Bard, David Wagner
|
||||
*FSE 2008 (LNCS vol. 5086, pp. 97–115)*
|
||||
DOI: [10.1007/978-3-540-71039-4_6](https://doi.org/10.1007/978-3-540-71039-4_6)
|
||||
|
||||
- **On the Power of Power Analysis in the Real World: A Complete Break of the KeeLoq Code Hopping Scheme**
|
||||
Thomas Eisenbarth, Timo Kasper, Amir Moradi, Christof Paar, Mahmoud Salmasizadeh, Mohammad T. Manzuri Shalmani
|
||||
*CRYPTO 2008 (LNCS vol. 5157, pp. 203–220)*
|
||||
DOI: [10.1007/978-3-540-85174-5_12](https://doi.org/10.1007/978-3-540-85174-5_12)
|
||||
https://www.iacr.org/archive/crypto2008/51570204/51570204.pdf
|
||||
|
||||
- **Breaking KeeLoq in a Flash: On Extracting Keys at Lightning Speed**
|
||||
*Springer*
|
||||
Markus Kasper, Timo Kasper, Amir Moradi, Christof Paar
|
||||
*AFRICACRYPT 2009 (LNCS vol. 5580, pp. 403–420)*
|
||||
DOI: [10.1007/978-3-642-02384-2_25](https://doi.org/10.1007/978-3-642-02384-2_25)
|
||||
|
||||
### Immobiliser & Transponder Systems
|
||||
### Immobiliser & Transponder Cipher Attacks
|
||||
|
||||
- **Dismantling DST80-based Immobiliser Systems**
|
||||
Lennert Wouters, Jan Van den Herrewegen, Flavio D. Garcia, David Oswald, Benedikt Gierlichs, Bart Preneel
|
||||
*IACR Transactions on Cryptographic Hardware and Embedded Systems (TCHES), 2020, Vol. 2*
|
||||
DOI: [10.13154/tches.v2020.i2.99-127](https://doi.org/10.13154/tches.v2020.i2.99-127)
|
||||
- **Gone in 360 Seconds: Hijacking with Hitag2**
|
||||
Roel Verdult, Flavio D. Garcia, Josep Balasch
|
||||
*21st USENIX Security Symposium (USENIX Security '12), pp. 237–252*
|
||||
DOI: [10.5555/2362793.2362830](https://doi.org/10.5555/2362793.2362830)
|
||||
https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final95.pdf
|
||||
|
||||
- **Dismantling Megamos Crypto: Wirelessly Lockpicking a Vehicle Immobilizer**
|
||||
Roel Verdult, Flavio D. Garcia, Baris Ege
|
||||
*Supplement to 22nd USENIX Security Symposium (USENIX Security '13/15), pp. 703–718*
|
||||
https://www.usenix.org/sites/default/files/sec15_supplement.pdf
|
||||
|
||||
- **Dismantling the AUT64 Automotive Cipher**
|
||||
Christopher Hicks, Flavio D. Garcia, David Oswald
|
||||
*IACR Transactions on Cryptographic Hardware and Embedded Systems (TCHES), 2018, Vol. 2018(2), pp. 46–69*
|
||||
DOI: [10.13154/tches.v2018.i2.46-69](https://doi.org/10.13154/tches.v2018.i2.46-69)
|
||||
|
||||
### RFID & Protocol Analysis Tooling
|
||||
|
||||
@@ -250,6 +282,11 @@ The following academic publications have been invaluable to the development and
|
||||
|
||||
### Relay & Replay Attacks
|
||||
|
||||
- **Relay Attacks on Passive Keyless Entry and Start Systems in Modern Cars**
|
||||
Aurélien Francillon, Boris Danev, Srdjan Čapkun
|
||||
*NDSS 2011*
|
||||
https://www.ndss-symposium.org/ndss2011/relay-attacks-on-passive-keyless-entry-and-start-systems-in-modern-cars/
|
||||
|
||||
- **Implementing and Testing RollJam on Software-Defined Radios**
|
||||
*Università di Bologna (UNIBO), CRIS*
|
||||
https://cris.unibo.it/handle/11585/999874
|
||||
@@ -260,13 +297,14 @@ The following academic publications have been invaluable to the development and
|
||||
|
||||
- **RollBack: A New Time-Agnostic Replay Attack Against the Automotive Remote Keyless Entry Systems**
|
||||
Levente Csikor, Hoon Wei Lim, Jun Wen Wong, Soundarya Ramesh, Rohini Poolat Parameswarath, Mun Choon Chan
|
||||
*ACM*
|
||||
*Black Hat USA 2022; ACM Transactions on Cyber-Physical Systems, 2024*
|
||||
DOI: [10.1145/3627827](https://doi.org/10.1145/3627827)
|
||||
https://i.blackhat.com/USA-22/Thursday/US-22-Csikor-Rollback-A-New-Time-Agnostic-Replay-wp.pdf
|
||||
|
||||
- **Relay Attacks on Passive Keyless Entry and Start Systems in Modern Cars**
|
||||
Aurelien Francillon, Boris Danev, Srdjan Capkun
|
||||
*NDSS 2011*
|
||||
https://www.ndss-symposium.org/ndss2011/relay-attacks-on-passive-keyless-entry-and-start-systems-in-modern-cars/
|
||||
- **Rolling-PWN Attack (Honda RKE Vulnerability)**
|
||||
Kevin2600 (Haoqi Shan), Wesley Li — Star-V Lab
|
||||
*Independent disclosure, 2022 (CVE-2021-46145)*
|
||||
https://rollingpwn.github.io/rolling-pwn/
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ SubGhzTxRx* subghz_txrx_alloc(void) {
|
||||
instance->txrx_state = SubGhzTxRxStateSleep;
|
||||
|
||||
subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF);
|
||||
subghz_txrx_preset_hopper_set_state(instance, SubGhzPresetHopperStateOFF);
|
||||
instance->preset_hopper_idx = 0;
|
||||
instance->preset_hopper_timeout = 0;
|
||||
subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable);
|
||||
subghz_txrx_set_debug_pin_state(instance, false);
|
||||
|
||||
@@ -495,63 +498,153 @@ void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_txrx_mod_hopper_get_running(SubGhzTxRx* instance) {
|
||||
void subghz_txrx_preset_hopper_update(SubGhzTxRx* instance, float stay_threshold) {
|
||||
furi_assert(instance);
|
||||
return instance->mod_hopper_running;
|
||||
}
|
||||
|
||||
void subghz_txrx_mod_hopper_set_running(
|
||||
SubGhzTxRx* instance,
|
||||
bool running,
|
||||
uint8_t dwell_ticks,
|
||||
float rssi_threshold) {
|
||||
furi_assert(instance);
|
||||
instance->mod_hopper_running = running;
|
||||
instance->mod_hopper_dwell = dwell_ticks;
|
||||
instance->mod_hopper_rssi_threshold = rssi_threshold;
|
||||
if(running) instance->mod_hopper_timer = dwell_ticks;
|
||||
}
|
||||
|
||||
void subghz_txrx_mod_hopper_update(SubGhzTxRx* instance, float current_rssi) {
|
||||
furi_assert(instance);
|
||||
if(!instance->mod_hopper_running) return;
|
||||
|
||||
// If RSSI gating is enabled and signal is present, pause hopping
|
||||
if(!isnan(instance->mod_hopper_rssi_threshold) &&
|
||||
current_rssi > instance->mod_hopper_rssi_threshold) {
|
||||
instance->mod_hopper_timer = instance->mod_hopper_dwell;
|
||||
switch(instance->preset_hopper_state) {
|
||||
case SubGhzPresetHopperStateOFF:
|
||||
case SubGhzPresetHopperStatePause:
|
||||
return;
|
||||
case SubGhzPresetHopperStateRSSITimeOut:
|
||||
if(instance->preset_hopper_timeout != 0) {
|
||||
instance->preset_hopper_timeout--;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(instance->mod_hopper_timer > 0) {
|
||||
instance->mod_hopper_timer--;
|
||||
return;
|
||||
if(instance->preset_hopper_state != SubGhzPresetHopperStateRSSITimeOut) {
|
||||
float rssi = subghz_devices_get_rssi(instance->radio_device);
|
||||
|
||||
if(rssi > stay_threshold) {
|
||||
instance->preset_hopper_timeout = 20;
|
||||
instance->preset_hopper_state = SubGhzPresetHopperStateRSSITimeOut;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
instance->preset_hopper_state = SubGhzPresetHopperStateRunning;
|
||||
}
|
||||
instance->mod_hopper_timer = instance->mod_hopper_dwell;
|
||||
|
||||
size_t count = subghz_setting_get_preset_count(instance->setting);
|
||||
if(count == 0) return;
|
||||
size_t hopper_preset_count = subghz_setting_get_hopper_preset_count(instance->setting);
|
||||
|
||||
// Advance index, skip CUSTOM presets
|
||||
uint8_t tries = 0;
|
||||
do {
|
||||
instance->mod_hopper_idx = (instance->mod_hopper_idx + 1) % count;
|
||||
tries++;
|
||||
} while(tries < count &&
|
||||
strcmp(
|
||||
subghz_setting_get_preset_name(instance->setting, instance->mod_hopper_idx),
|
||||
"CUSTOM") == 0);
|
||||
if(hopper_preset_count > 0) {
|
||||
if(instance->preset_hopper_idx < hopper_preset_count - 1) {
|
||||
instance->preset_hopper_idx++;
|
||||
} else {
|
||||
instance->preset_hopper_idx = 0;
|
||||
}
|
||||
|
||||
const char* preset_name =
|
||||
subghz_setting_get_preset_name(instance->setting, instance->mod_hopper_idx);
|
||||
uint8_t* preset_data =
|
||||
subghz_setting_get_preset_data(instance->setting, instance->mod_hopper_idx);
|
||||
size_t preset_data_size =
|
||||
subghz_setting_get_preset_data_size(instance->setting, instance->mod_hopper_idx);
|
||||
size_t actual_preset_idx = subghz_setting_get_hopper_preset_index(
|
||||
instance->setting, instance->preset_hopper_idx);
|
||||
|
||||
subghz_txrx_set_preset(
|
||||
instance, preset_name, instance->preset->frequency, preset_data, preset_data_size);
|
||||
subghz_txrx_rx_start(instance);
|
||||
if(instance->txrx_state == SubGhzTxRxStateRx) {
|
||||
subghz_txrx_rx_end(instance);
|
||||
}
|
||||
if(instance->txrx_state == SubGhzTxRxStateIDLE) {
|
||||
const char* old_preset_name = furi_string_get_cstr(instance->preset->name);
|
||||
|
||||
const char* preset_name =
|
||||
subghz_setting_get_preset_name(instance->setting, actual_preset_idx);
|
||||
subghz_txrx_set_preset_internal(
|
||||
instance, instance->preset->frequency, actual_preset_idx, 0);
|
||||
|
||||
bool old_is_am = (strstr(old_preset_name, "AM") != NULL);
|
||||
bool new_is_am = (strstr(preset_name, "AM") != NULL);
|
||||
bool modulation_changed = (old_is_am != new_is_am);
|
||||
|
||||
if(modulation_changed) {
|
||||
subghz_devices_reset(instance->radio_device);
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
} else {
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
}
|
||||
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
} else {
|
||||
size_t preset_count = subghz_setting_get_preset_count(instance->setting);
|
||||
if(instance->preset_hopper_idx < preset_count - 1) {
|
||||
instance->preset_hopper_idx++;
|
||||
} else {
|
||||
instance->preset_hopper_idx = 0;
|
||||
}
|
||||
|
||||
if(instance->txrx_state == SubGhzTxRxStateRx) {
|
||||
subghz_txrx_rx_end(instance);
|
||||
}
|
||||
if(instance->txrx_state == SubGhzTxRxStateIDLE) {
|
||||
const char* old_preset_name = furi_string_get_cstr(instance->preset->name);
|
||||
|
||||
const char* preset_name =
|
||||
subghz_setting_get_preset_name(instance->setting, instance->preset_hopper_idx);
|
||||
subghz_txrx_set_preset_internal(
|
||||
instance, instance->preset->frequency, instance->preset_hopper_idx, 0);
|
||||
|
||||
bool old_is_am = (strstr(old_preset_name, "AM") != NULL);
|
||||
bool new_is_am = (strstr(preset_name, "AM") != NULL);
|
||||
bool modulation_changed = (old_is_am != new_is_am);
|
||||
|
||||
if(modulation_changed) {
|
||||
subghz_devices_reset(instance->radio_device);
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
} else {
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
}
|
||||
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SubGhzPresetHopperState subghz_txrx_preset_hopper_get_state(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->preset_hopper_state;
|
||||
}
|
||||
|
||||
void subghz_txrx_preset_hopper_set_state(SubGhzTxRx* instance, SubGhzPresetHopperState state) {
|
||||
furi_assert(instance);
|
||||
instance->preset_hopper_state = state;
|
||||
|
||||
if(state == SubGhzPresetHopperStateRunning) {
|
||||
subghz_devices_reset(instance->radio_device);
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_preset_hopper_unpause(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->preset_hopper_state == SubGhzPresetHopperStatePause) {
|
||||
instance->preset_hopper_state = SubGhzPresetHopperStateRunning;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_preset_hopper_pause(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->preset_hopper_state == SubGhzPresetHopperStateRunning) {
|
||||
instance->preset_hopper_state = SubGhzPresetHopperStatePause;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_preset_hopper_reset_index(SubGhzTxRx* instance, size_t index) {
|
||||
furi_assert(instance);
|
||||
instance->preset_hopper_idx = index;
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_on(SubGhzTxRx* instance) {
|
||||
|
||||
@@ -164,37 +164,17 @@ void subghz_txrx_hopper_unpause(SubGhzTxRx* instance);
|
||||
*/
|
||||
void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Update modulation (preset) CC1101 in automatic mode (mod hopper)
|
||||
* Cycles through available presets at the configured dwell time.
|
||||
* Pauses hopping when current_rssi exceeds the configured threshold.
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param current_rssi Current RSSI reading from the radio
|
||||
*/
|
||||
void subghz_txrx_mod_hopper_update(SubGhzTxRx* instance, float current_rssi);
|
||||
void subghz_txrx_preset_hopper_update(SubGhzTxRx* instance, float stay_threshold);
|
||||
|
||||
/**
|
||||
* Set mod hopper running state with configuration
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param running true to enable, false to disable
|
||||
* @param dwell_ticks Ticks to dwell on each modulation (100ms per tick)
|
||||
* @param rssi_threshold RSSI threshold to pause hopping (NAN = no gating)
|
||||
*/
|
||||
void subghz_txrx_mod_hopper_set_running(
|
||||
SubGhzTxRx* instance,
|
||||
bool running,
|
||||
uint8_t dwell_ticks,
|
||||
float rssi_threshold);
|
||||
SubGhzPresetHopperState subghz_txrx_preset_hopper_get_state(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Get mod hopper running state
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return true if mod hopping is active
|
||||
*/
|
||||
bool subghz_txrx_mod_hopper_get_running(SubGhzTxRx* instance);
|
||||
void subghz_txrx_preset_hopper_set_state(SubGhzTxRx* instance, SubGhzPresetHopperState state);
|
||||
|
||||
void subghz_txrx_preset_hopper_unpause(SubGhzTxRx* instance);
|
||||
|
||||
void subghz_txrx_preset_hopper_pause(SubGhzTxRx* instance);
|
||||
|
||||
void subghz_txrx_preset_hopper_reset_index(SubGhzTxRx* instance, size_t index);
|
||||
|
||||
/**
|
||||
* Speaker on
|
||||
|
||||
@@ -19,11 +19,9 @@ struct SubGhzTxRx {
|
||||
bool is_database_loaded;
|
||||
SubGhzHopperState hopper_state;
|
||||
|
||||
uint8_t mod_hopper_idx; // index into setting presets (wraps around)
|
||||
uint8_t mod_hopper_timer; // countdown ticks before advancing modulation
|
||||
uint8_t mod_hopper_dwell; // stored dwell ticks (configurable)
|
||||
float mod_hopper_rssi_threshold; // RSSI threshold; NAN = no RSSI gating
|
||||
bool mod_hopper_running; // is mod hopping active
|
||||
uint8_t preset_hopper_timeout;
|
||||
size_t preset_hopper_idx;
|
||||
SubGhzPresetHopperState preset_hopper_state;
|
||||
|
||||
SubGhzTxRxState txrx_state;
|
||||
SubGhzSpeakerState speaker_state;
|
||||
|
||||
@@ -29,6 +29,14 @@ typedef enum {
|
||||
SubGhzHopperStateRSSITimeOut,
|
||||
} SubGhzHopperState;
|
||||
|
||||
/** SubGhzPresetHopperState state */
|
||||
typedef enum {
|
||||
SubGhzPresetHopperStateOFF,
|
||||
SubGhzPresetHopperStateRunning,
|
||||
SubGhzPresetHopperStatePause,
|
||||
SubGhzPresetHopperStateRSSITimeOut,
|
||||
} SubGhzPresetHopperState;
|
||||
|
||||
/** SubGhzSpeakerState state */
|
||||
typedef enum {
|
||||
SubGhzSpeakerStateDisable,
|
||||
|
||||
@@ -40,3 +40,8 @@ Version: 1
|
||||
#Custom_preset_name: AM_2
|
||||
#Custom_preset_module: CC1101
|
||||
#Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00
|
||||
|
||||
# Presets used for preset hopping mode (cycles through these modulations)
|
||||
#Hopping_Preset: AM650
|
||||
#Hopping_Preset: FM238
|
||||
#Hopping_Preset: FM476
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "../subghz_i.h"
|
||||
#include <math.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <lib/subghz/protocols/bin_raw.h>
|
||||
|
||||
@@ -214,11 +213,12 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
} else {
|
||||
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
|
||||
}
|
||||
subghz_txrx_mod_hopper_set_running(
|
||||
subghz->txrx,
|
||||
!isnan(subghz->last_settings->mod_hopping_threshold),
|
||||
(uint8_t)subghz->last_settings->mod_hopping_dwell,
|
||||
subghz->last_settings->mod_hopping_threshold);
|
||||
|
||||
if(subghz->last_settings->enable_preset_hopping) {
|
||||
subghz_txrx_preset_hopper_set_state(subghz->txrx, SubGhzPresetHopperStateRunning);
|
||||
} else {
|
||||
subghz_txrx_preset_hopper_set_state(subghz->txrx, SubGhzPresetHopperStateOFF);
|
||||
}
|
||||
|
||||
subghz_txrx_rx_start(subghz->txrx);
|
||||
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen);
|
||||
@@ -247,6 +247,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
|
||||
subghz_txrx_preset_hopper_set_state(subghz->txrx, SubGhzPresetHopperStateOFF);
|
||||
subghz_txrx_set_rx_callback(subghz->txrx, NULL, subghz);
|
||||
|
||||
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
|
||||
@@ -307,9 +308,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz_txrx_hopper_update(subghz->txrx, subghz->last_settings->hopping_threshold);
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
}
|
||||
if(subghz_txrx_mod_hopper_get_running(subghz->txrx)) {
|
||||
float rssi = subghz_txrx_radio_device_get_rssi(subghz->txrx);
|
||||
subghz_txrx_mod_hopper_update(subghz->txrx, rssi);
|
||||
if(subghz_txrx_preset_hopper_get_state(subghz->txrx) != SubGhzPresetHopperStateOFF) {
|
||||
subghz_txrx_preset_hopper_update(subghz->txrx, subghz->last_settings->preset_hopping_threshold);
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
enum SubGhzSettingIndex {
|
||||
SubGhzSettingIndexFrequency,
|
||||
SubGhzSettingIndexHopping,
|
||||
SubGhzSettingIndexModulation,
|
||||
SubGhzSettingIndexModHopping,
|
||||
SubGhzSettingIndexHopping,
|
||||
SubGhzSettingIndexPresetHopping,
|
||||
SubGhzSettingIndexBinRAW,
|
||||
SubGhzSettingIndexIgnoreReversRB2,
|
||||
SubGhzSettingIndexIgnoreAlarms,
|
||||
@@ -82,18 +82,22 @@ const float hopping_mode_value[HOPPING_MODE_COUNT] = {
|
||||
-40.0f,
|
||||
};
|
||||
|
||||
#define MOD_HOP_DBM_COUNT 8
|
||||
const char* const mod_hop_dbm_text[MOD_HOP_DBM_COUNT] = {
|
||||
#define PRESET_HOPPING_MODE_COUNT 12
|
||||
const char* const preset_hopping_mode_text[PRESET_HOPPING_MODE_COUNT] = {
|
||||
"OFF",
|
||||
"-90",
|
||||
"-85",
|
||||
"-80",
|
||||
"-75",
|
||||
"-70",
|
||||
"-65",
|
||||
"-60",
|
||||
"-90dBm",
|
||||
"-85dBm",
|
||||
"-80dBm",
|
||||
"-75dBm",
|
||||
"-70dBm",
|
||||
"-65dBm",
|
||||
"-60dBm",
|
||||
"-55dBm",
|
||||
"-50dBm",
|
||||
"-45dBm",
|
||||
"-40dBm",
|
||||
};
|
||||
const float mod_hop_dbm_value[MOD_HOP_DBM_COUNT] = {
|
||||
const float preset_hopping_mode_value[PRESET_HOPPING_MODE_COUNT] = {
|
||||
NAN,
|
||||
-90.0f,
|
||||
-85.0f,
|
||||
@@ -102,22 +106,10 @@ const float mod_hop_dbm_value[MOD_HOP_DBM_COUNT] = {
|
||||
-70.0f,
|
||||
-65.0f,
|
||||
-60.0f,
|
||||
};
|
||||
|
||||
#define MOD_HOP_TIME_COUNT 5
|
||||
const char* const mod_hop_time_text[MOD_HOP_TIME_COUNT] = {
|
||||
"0.5s",
|
||||
"1s",
|
||||
"2s",
|
||||
"5s",
|
||||
"10s",
|
||||
};
|
||||
const uint32_t mod_hop_time_ticks[MOD_HOP_TIME_COUNT] = {
|
||||
5,
|
||||
10,
|
||||
20,
|
||||
50,
|
||||
100,
|
||||
-55.0f,
|
||||
-50.0f,
|
||||
-45.0f,
|
||||
-40.0f,
|
||||
};
|
||||
|
||||
#define COMBO_BOX_COUNT 2
|
||||
@@ -192,6 +184,23 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void*
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t subghz_scene_receiver_config_preset_hopper_value_index(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
|
||||
if(subghz_txrx_preset_hopper_get_state(subghz->txrx) == SubGhzPresetHopperStateOFF) {
|
||||
return 0;
|
||||
} else {
|
||||
variable_item_set_current_value_text(
|
||||
variable_item_list_get(subghz->variable_item_list, SubGhzSettingIndexModulation),
|
||||
" -----");
|
||||
return value_index_float(
|
||||
subghz->last_settings->preset_hopping_threshold,
|
||||
preset_hopping_mode_value,
|
||||
PRESET_HOPPING_MODE_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t subghz_scene_receiver_config_hopper_value_index(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
@@ -252,19 +261,21 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||
|
||||
const char* preset_name = subghz_setting_get_preset_name(setting, index);
|
||||
variable_item_set_current_value_text(item, preset_name);
|
||||
//subghz->last_settings->preset = index;
|
||||
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||
uint8_t* preset_data = subghz_setting_get_preset_data(setting, index);
|
||||
size_t preset_data_size = subghz_setting_get_preset_data_size(setting, index);
|
||||
if(subghz_txrx_preset_hopper_get_state(subghz->txrx) == SubGhzPresetHopperStateOFF) {
|
||||
const char* preset_name = subghz_setting_get_preset_name(setting, index);
|
||||
variable_item_set_current_value_text(item, preset_name);
|
||||
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||
uint8_t* preset_data = subghz_setting_get_preset_data(setting, index);
|
||||
size_t preset_data_size = subghz_setting_get_preset_data_size(setting, index);
|
||||
|
||||
//Edit TX power, if necessary.
|
||||
subghz_txrx_set_tx_power(preset_data, preset_data_size, subghz->tx_power);
|
||||
subghz_txrx_set_tx_power(preset_data, preset_data_size, subghz->tx_power);
|
||||
|
||||
subghz_txrx_set_preset(
|
||||
subghz->txrx, preset_name, preset.frequency, preset_data, preset_data_size);
|
||||
subghz->last_settings->preset_index = index;
|
||||
subghz_txrx_set_preset(
|
||||
subghz->txrx, preset_name, preset.frequency, preset_data, preset_data_size);
|
||||
subghz->last_settings->preset_index = index;
|
||||
} else {
|
||||
variable_item_set_current_value_index(item, subghz->last_settings->preset_index);
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_hopping(VariableItem* item) {
|
||||
@@ -313,33 +324,57 @@ static void subghz_scene_receiver_config_set_hopping(VariableItem* item) {
|
||||
subghz->last_settings->hopping_threshold = hopping_mode_value[index];
|
||||
subghz_txrx_hopper_set_state(
|
||||
subghz->txrx, index != 0 ? SubGhzHopperStateRunning : SubGhzHopperStateOFF);
|
||||
|
||||
VariableItem* preset_hopping_item =
|
||||
variable_item_list_get(subghz->variable_item_list, SubGhzSettingIndexPresetHopping);
|
||||
variable_item_set_locked(
|
||||
preset_hopping_item,
|
||||
index != 0,
|
||||
"Turn off\nHopping\nfirst!");
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_mod_hop_dbm(VariableItem* item) {
|
||||
static void subghz_scene_receiver_config_set_preset_hopping(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, mod_hop_dbm_text[index]);
|
||||
subghz->last_settings->mod_hopping_threshold = mod_hop_dbm_value[index];
|
||||
bool enabled = index != 0;
|
||||
subghz_txrx_mod_hopper_set_running(
|
||||
subghz->txrx,
|
||||
enabled,
|
||||
(uint8_t)subghz->last_settings->mod_hopping_dwell,
|
||||
mod_hop_dbm_value[index]);
|
||||
}
|
||||
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||
VariableItem* preset_item =
|
||||
variable_item_list_get(subghz->variable_item_list, SubGhzSettingIndexModulation);
|
||||
|
||||
static void subghz_scene_receiver_config_set_mod_hop_time(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, mod_hop_time_text[index]);
|
||||
subghz->last_settings->mod_hopping_dwell = mod_hop_time_ticks[index];
|
||||
if(subghz_txrx_mod_hopper_get_running(subghz->txrx)) {
|
||||
subghz_txrx_mod_hopper_set_running(
|
||||
subghz->txrx,
|
||||
true,
|
||||
(uint8_t)mod_hop_time_ticks[index],
|
||||
subghz->last_settings->mod_hopping_threshold);
|
||||
variable_item_set_current_value_text(item, preset_hopping_mode_text[index]);
|
||||
|
||||
if(index == 0) {
|
||||
SubGhzRadioPreset current_preset = subghz_txrx_get_preset(subghz->txrx);
|
||||
const char* current_preset_name = furi_string_get_cstr(current_preset.name);
|
||||
int current_preset_index = subghz_setting_get_inx_preset_by_name(setting, current_preset_name);
|
||||
if(current_preset_index >= 0) {
|
||||
subghz->last_settings->preset_index = current_preset_index;
|
||||
}
|
||||
variable_item_set_current_value_text(preset_item, current_preset_name);
|
||||
variable_item_set_current_value_index(preset_item, subghz->last_settings->preset_index);
|
||||
|
||||
subghz->last_settings->enable_preset_hopping = false;
|
||||
subghz_txrx_preset_hopper_set_state(subghz->txrx, SubGhzPresetHopperStateOFF);
|
||||
} else {
|
||||
bool was_running = (subghz_txrx_preset_hopper_get_state(subghz->txrx) == SubGhzPresetHopperStateRunning);
|
||||
if(was_running) {
|
||||
subghz_txrx_preset_hopper_pause(subghz->txrx);
|
||||
}
|
||||
|
||||
subghz->last_settings->preset_hopping_threshold = preset_hopping_mode_value[index];
|
||||
|
||||
variable_item_set_current_value_text(preset_item, " -----");
|
||||
variable_item_set_current_value_index(preset_item, subghz->last_settings->preset_index);
|
||||
|
||||
subghz->last_settings->enable_preset_hopping = true;
|
||||
subghz_txrx_preset_hopper_set_state(subghz->txrx, SubGhzPresetHopperStateRunning);
|
||||
}
|
||||
|
||||
VariableItem* hopping_item =
|
||||
variable_item_list_get(subghz->variable_item_list, SubGhzSettingIndexHopping);
|
||||
variable_item_set_locked(
|
||||
hopping_item,
|
||||
index != 0,
|
||||
"Turn off\nPreset\nHopping\nfirst!");
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
|
||||
@@ -442,9 +477,9 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context,
|
||||
|
||||
subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[default_index]);
|
||||
subghz->last_settings->enable_hopping = hopping_value[default_index];
|
||||
subghz->last_settings->mod_hopping_threshold = NAN;
|
||||
subghz->last_settings->mod_hopping_dwell = 20;
|
||||
subghz_txrx_mod_hopper_set_running(subghz->txrx, false, 20, NAN);
|
||||
subghz->last_settings->enable_preset_hopping = false;
|
||||
subghz->last_settings->preset_hopping_threshold = SUBGHZ_LAST_SETTING_DEFAULT_PRESET_HOPPING_THRESHOLD;
|
||||
subghz_txrx_preset_hopper_set_state(subghz->txrx, SubGhzPresetHopperStateOFF);
|
||||
|
||||
variable_item_list_set_selected_item(subghz->variable_item_list, default_index);
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
@@ -509,47 +544,26 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, hopping_mode_text[value_index]);
|
||||
|
||||
// Mod Hop dBm
|
||||
{
|
||||
uint8_t mod_dbm_idx = 0; // OFF
|
||||
float thresh = subghz->last_settings->mod_hopping_threshold;
|
||||
if(!isnan(thresh)) {
|
||||
for(uint8_t k = 1; k < MOD_HOP_DBM_COUNT; k++) {
|
||||
if(mod_hop_dbm_value[k] == thresh) {
|
||||
mod_dbm_idx = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(mod_dbm_idx == 0) mod_dbm_idx = 1; // fallback to -90
|
||||
}
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Mod Hop dBm",
|
||||
MOD_HOP_DBM_COUNT,
|
||||
subghz_scene_receiver_config_set_mod_hop_dbm,
|
||||
subghz);
|
||||
variable_item_set_current_value_index(item, mod_dbm_idx);
|
||||
variable_item_set_current_value_text(item, mod_hop_dbm_text[mod_dbm_idx]);
|
||||
}
|
||||
variable_item_set_locked(
|
||||
item,
|
||||
subghz_txrx_preset_hopper_get_state(subghz->txrx) != SubGhzPresetHopperStateOFF,
|
||||
"Turn off\nPreset\nHopping\nfirst!");
|
||||
|
||||
// Mod Hop Time
|
||||
{
|
||||
uint8_t mod_time_idx = 2; // default 2s
|
||||
for(uint8_t k = 0; k < MOD_HOP_TIME_COUNT; k++) {
|
||||
if(mod_hop_time_ticks[k] == subghz->last_settings->mod_hopping_dwell) {
|
||||
mod_time_idx = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Mod Hop Time",
|
||||
MOD_HOP_TIME_COUNT,
|
||||
subghz_scene_receiver_config_set_mod_hop_time,
|
||||
subghz);
|
||||
variable_item_set_current_value_index(item, mod_time_idx);
|
||||
variable_item_set_current_value_text(item, mod_hop_time_text[mod_time_idx]);
|
||||
}
|
||||
value_index = subghz_scene_receiver_config_preset_hopper_value_index(subghz);
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Preset Hopping",
|
||||
PRESET_HOPPING_MODE_COUNT,
|
||||
subghz_scene_receiver_config_set_preset_hopping,
|
||||
subghz);
|
||||
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, preset_hopping_mode_text[value_index]);
|
||||
|
||||
variable_item_set_locked(
|
||||
item,
|
||||
subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF,
|
||||
"Turn off\nHopping\nfirst!");
|
||||
}
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "subghz_last_settings.h"
|
||||
#include "subghz_i.h"
|
||||
#include <math.h>
|
||||
|
||||
#define TAG "SubGhzLastSettings"
|
||||
|
||||
@@ -14,8 +13,8 @@
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER "FATrigger"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES "ProtocolNames"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE "Hopping"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_THRESHOLD "ModHopThreshold"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_DWELL "ModHopDwell"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_PRESET_HOPPING "PresetHopping"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_PRESET_HOPPING_THRESHOLD "PresetHoppingThreshold"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER "IgnoreFilter"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI"
|
||||
@@ -48,8 +47,8 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
instance->filter = SubGhzProtocolFlag_Decodable;
|
||||
instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN;
|
||||
instance->hopping_threshold = -90.0f;
|
||||
instance->mod_hopping_threshold = NAN; // disabled by default
|
||||
instance->mod_hopping_dwell = 20; // 2 seconds (20 × 100ms ticks)
|
||||
instance->enable_preset_hopping = false;
|
||||
instance->preset_hopping_threshold = SUBGHZ_LAST_SETTING_DEFAULT_PRESET_HOPPING_THRESHOLD;
|
||||
instance->leds_and_amp = true;
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
@@ -103,19 +102,24 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
1)) {
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
if(!flipper_format_read_float(
|
||||
if(!flipper_format_read_bool(
|
||||
fff_data_file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_THRESHOLD,
|
||||
&instance->mod_hopping_threshold,
|
||||
SUBGHZ_LAST_SETTING_FIELD_PRESET_HOPPING,
|
||||
&instance->enable_preset_hopping,
|
||||
1)) {
|
||||
instance->enable_preset_hopping = false;
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
if(!flipper_format_read_uint32(
|
||||
float temp_preset_threshold = 0;
|
||||
if(!flipper_format_read_float(
|
||||
fff_data_file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_DWELL,
|
||||
&instance->mod_hopping_dwell,
|
||||
SUBGHZ_LAST_SETTING_FIELD_PRESET_HOPPING_THRESHOLD,
|
||||
&temp_preset_threshold,
|
||||
1)) {
|
||||
instance->preset_hopping_threshold = SUBGHZ_LAST_SETTING_DEFAULT_PRESET_HOPPING_THRESHOLD;
|
||||
flipper_format_rewind(fff_data_file);
|
||||
} else {
|
||||
instance->preset_hopping_threshold = temp_preset_threshold;
|
||||
}
|
||||
if(!flipper_format_read_uint32(
|
||||
fff_data_file,
|
||||
@@ -232,17 +236,17 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
|
||||
file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE, &instance->enable_hopping, 1)) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_write_float(
|
||||
if(!flipper_format_write_bool(
|
||||
file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_THRESHOLD,
|
||||
&instance->mod_hopping_threshold,
|
||||
SUBGHZ_LAST_SETTING_FIELD_PRESET_HOPPING,
|
||||
&instance->enable_preset_hopping,
|
||||
1)) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_write_uint32(
|
||||
if(!flipper_format_write_float(
|
||||
file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_DWELL,
|
||||
&instance->mod_hopping_dwell,
|
||||
SUBGHZ_LAST_SETTING_FIELD_PRESET_HOPPING_THRESHOLD,
|
||||
&instance->preset_hopping_threshold,
|
||||
1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,21 +12,22 @@
|
||||
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET 1
|
||||
#define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000
|
||||
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL 2
|
||||
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET_HOPPING_THRESHOLD (-80.0f)
|
||||
|
||||
typedef struct {
|
||||
uint32_t frequency;
|
||||
uint32_t preset_index; // AKA Modulation
|
||||
uint32_t preset_index;
|
||||
uint32_t frequency_analyzer_feedback_level;
|
||||
float frequency_analyzer_trigger;
|
||||
bool protocol_file_names;
|
||||
bool enable_hopping;
|
||||
float mod_hopping_threshold; // RSSI threshold for mod hopping, NAN = disabled
|
||||
uint32_t mod_hopping_dwell; // Dwell time in ticks (100ms units)
|
||||
uint32_t ignore_filter;
|
||||
uint32_t filter;
|
||||
float rssi;
|
||||
bool delete_old_signals;
|
||||
float hopping_threshold;
|
||||
bool enable_preset_hopping;
|
||||
float preset_hopping_threshold;
|
||||
bool leds_and_amp;
|
||||
uint8_t tx_power;
|
||||
} SubGhzLastSettings;
|
||||
|
||||
@@ -117,6 +117,7 @@ typedef struct {
|
||||
struct SubGhzSetting {
|
||||
FrequencyList_t frequencies;
|
||||
FrequencyList_t hopper_frequencies;
|
||||
PresetIndexList_t hopper_preset_indices;
|
||||
SubGhzSettingCustomPresetStruct* preset;
|
||||
};
|
||||
|
||||
@@ -124,6 +125,7 @@ SubGhzSetting* subghz_setting_alloc(void) {
|
||||
SubGhzSetting* instance = malloc(sizeof(SubGhzSetting));
|
||||
FrequencyList_init(instance->frequencies);
|
||||
FrequencyList_init(instance->hopper_frequencies);
|
||||
PresetIndexList_init(instance->hopper_preset_indices);
|
||||
instance->preset = malloc(sizeof(SubGhzSettingCustomPresetStruct));
|
||||
SubGhzSettingCustomPresetItemArray_init(instance->preset->data);
|
||||
return instance;
|
||||
@@ -142,6 +144,7 @@ void subghz_setting_free(SubGhzSetting* instance) {
|
||||
furi_check(instance);
|
||||
FrequencyList_clear(instance->frequencies);
|
||||
FrequencyList_clear(instance->hopper_frequencies);
|
||||
PresetIndexList_clear(instance->hopper_preset_indices);
|
||||
for
|
||||
M_EACH(item, instance->preset->data, SubGhzSettingCustomPresetItemArray_t) {
|
||||
furi_string_free(item->custom_preset_name);
|
||||
@@ -183,6 +186,7 @@ static void subghz_setting_load_default_region(
|
||||
|
||||
FrequencyList_reset(instance->frequencies);
|
||||
FrequencyList_reset(instance->hopper_frequencies);
|
||||
PresetIndexList_reset(instance->hopper_preset_indices);
|
||||
subghz_setting_preset_reset(instance);
|
||||
|
||||
while(*frequencies) {
|
||||
@@ -308,6 +312,22 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
||||
instance, furi_string_get_cstr(temp_str), fff_data_file);
|
||||
}
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
break;
|
||||
}
|
||||
furi_string_reset(temp_str);
|
||||
while(flipper_format_read_string(fff_data_file, "Hopping_Preset", temp_str)) {
|
||||
const char* preset_name = furi_string_get_cstr(temp_str);
|
||||
int preset_index = subghz_setting_get_inx_preset_by_name(instance, preset_name);
|
||||
if(preset_index >= 0) {
|
||||
PresetIndexList_push_back(instance->hopper_preset_indices, (size_t)preset_index);
|
||||
FURI_LOG_I(TAG, "Hopper preset loaded: %s (index %d)", preset_name, preset_index);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Hopper preset not found: %s", preset_name);
|
||||
}
|
||||
}
|
||||
|
||||
} while(false);
|
||||
}
|
||||
|
||||
@@ -347,6 +367,19 @@ size_t subghz_setting_get_preset_count(SubGhzSetting* instance) {
|
||||
return SubGhzSettingCustomPresetItemArray_size(instance->preset->data);
|
||||
}
|
||||
|
||||
size_t subghz_setting_get_hopper_preset_count(SubGhzSetting* instance) {
|
||||
furi_check(instance);
|
||||
return PresetIndexList_size(instance->hopper_preset_indices);
|
||||
}
|
||||
|
||||
size_t subghz_setting_get_hopper_preset_index(SubGhzSetting* instance, size_t idx) {
|
||||
furi_check(instance);
|
||||
if(idx < PresetIndexList_size(instance->hopper_preset_indices)) {
|
||||
return *PresetIndexList_get(instance->hopper_preset_indices, idx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* subghz_setting_get_preset_name(SubGhzSetting* instance, size_t idx) {
|
||||
furi_check(instance);
|
||||
if(idx >= SubGhzSettingCustomPresetItemArray_size(instance->preset->data)) {
|
||||
@@ -367,7 +400,6 @@ int subghz_setting_get_inx_preset_by_name(SubGhzSetting* instance, const char* p
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
furi_crash("SubGhz: No name preset.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
#include <m-list.h>
|
||||
#include <furi_hal.h>
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
|
||||
@@ -12,6 +13,9 @@ extern "C" {
|
||||
|
||||
#define SUBGHZ_SETTING_DEFAULT_PRESET_COUNT 4
|
||||
|
||||
LIST_DEF(PresetIndexList, size_t)
|
||||
#define M_OPL_PresetIndexList_t() LIST_OPLIST(PresetIndexList)
|
||||
|
||||
typedef struct SubGhzSetting SubGhzSetting;
|
||||
|
||||
SubGhzSetting* subghz_setting_alloc(void);
|
||||
@@ -55,6 +59,9 @@ void subghz_setting_set_default_frequency(SubGhzSetting* instance, uint32_t freq
|
||||
|
||||
uint8_t subghz_setting_customs_presets_to_log(SubGhzSetting* instance);
|
||||
|
||||
size_t subghz_setting_get_hopper_preset_count(SubGhzSetting* instance);
|
||||
size_t subghz_setting_get_hopper_preset_index(SubGhzSetting* instance, size_t idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,87.9,,
|
||||
Version,+,87.10,,
|
||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||
Header,+,applications/services/applications.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
@@ -3692,6 +3692,8 @@ Function,+,subghz_setting_get_frequency_count,size_t,SubGhzSetting*
|
||||
Function,+,subghz_setting_get_frequency_default_index,uint32_t,SubGhzSetting*
|
||||
Function,+,subghz_setting_get_hopper_frequency,uint32_t,"SubGhzSetting*, size_t"
|
||||
Function,+,subghz_setting_get_hopper_frequency_count,size_t,SubGhzSetting*
|
||||
Function,+,subghz_setting_get_hopper_preset_count,size_t,SubGhzSetting*
|
||||
Function,+,subghz_setting_get_hopper_preset_index,size_t,"SubGhzSetting*, size_t"
|
||||
Function,+,subghz_setting_get_inx_preset_by_name,int,"SubGhzSetting*, const char*"
|
||||
Function,+,subghz_setting_get_preset_count,size_t,SubGhzSetting*
|
||||
Function,+,subghz_setting_get_preset_data,uint8_t*,"SubGhzSetting*, size_t"
|
||||
|
||||
|
Reference in New Issue
Block a user