Compare commits

...

5 Commits

Author SHA1 Message Date
Andrea
ce085b6895 Revise automotive RKE security references and add new entries, fixed a DOI 2026-03-12 21:26:45 +01:00
D4rk$1d3
f4c753b673 Update README.md 2026-03-12 15:10:57 -03:00
Andrea
41191df7fd Remove Implemented Protocols section from README (redundant)
Removed the Implemented Protocols section from the README.
2026-03-12 15:33:00 +01:00
Andrea Santaniello
d5eb983caa Modulation hopping settings for time and rssi 2026-03-12 15:18:54 +01:00
Andrea Santaniello
853c609977 Marelli BSI buttons 2026-03-12 15:00:34 +01:00
9 changed files with 247 additions and 82 deletions

View File

@@ -16,7 +16,6 @@ This project may incorporate, adapt, or build upon **other open-source projects*
- [Supported Systems](#supported-systems) - [Supported Systems](#supported-systems)
- [How to Build](#how-to-build) - [How to Build](#how-to-build)
- [Project Scope](#project-scope) - [Project Scope](#project-scope)
- [Implemented Protocols](#implemented-protocols)
- [To Do / Planned Features](#to-do--planned-features) - [To Do / Planned Features](#to-do--planned-features)
- [Design Philosophy](#design-philosophy) - [Design Philosophy](#design-philosophy)
- [Research Direction](#research-direction) - [Research Direction](#research-direction)
@@ -132,22 +131,10 @@ Flipper-ARF aims to achieve:
--- ---
## Implemented Protocols
- [x] Mazda Siemens Protocol (5WK49365D) — ported from open-source references (testing required)
- [x] Full VAG, Fiat, Ford, Subaru, Kia, PSA support
- [x] D-Pad mapping (Lock / Unlock / Boot / Trunk) during emulation
- [x] VAG MFKey support and updated Keeloq codes
- [x] PSA XTEA brute force for saved → emulation workflow
- [x] Brute force of counter in saved → can be accellerated trough the companion app via bluetooth
- [X] Keeloq Key Manager inside firmware
- [x] RollJam app (Internal CC1101 for RX & TX captured signal; External CC1101 for jamming) — requires more real-world testing (no available yet)
---
## To Do / Planned Features ## To Do / Planned Features
- [ ] Add Scher Khan & Starline protocols - [ ] Add Scher Khan & Starline protocols
- [ ] Marelli BSI encodere and encryption
- [ ] Fix and reintegrate RollJam app (future updates) - [ ] Fix and reintegrate RollJam app (future updates)
- [ ] Expand and refine Subaru, Kia, PSA, and other manufacturer protocols - [ ] Expand and refine Subaru, Kia, PSA, and other manufacturer protocols
- [ ] Improve collaboration workflow to avoid overlapping work - [ ] Improve collaboration workflow to avoid overlapping work
@@ -202,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** - **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 Flavio D. Garcia, David Oswald, Timo Kasper, Pierre Pavlidès
*USENIX Security 2016* *USENIX Security 2016, pp. 929944*
DOI: [10.5555/3241094.3241166](https://doi.org/10.5555/3241094.3241166)
https://www.usenix.org/system/files/conference/usenixsecurity16/sec16_paper_garcia.pdf https://www.usenix.org/system/files/conference/usenixsecurity16/sec16_paper_garcia.pdf
- **Clonable Key Fobs: Analyzing and Breaking RKE Protocols** - **Clonable Key Fobs: Analyzing and Breaking RKE Protocols**
@@ -225,33 +213,65 @@ The following academic publications have been invaluable to the development and
*Wiley, February 2025* *Wiley, February 2025*
DOI: [10.1002/9781394351930.ch11](https://doi.org/10.1002/9781394351930.ch11) 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. 99127*
DOI: [10.13154/tches.v2020.i2.99-127](https://doi.org/10.13154/tches.v2020.i2.99-127)
### KeeLoq Cryptanalysis ### KeeLoq Cryptanalysis
- **Cryptanalysis of the KeeLoq Block Cipher** - **Cryptanalysis of the KeeLoq Block Cipher**
Andrey Bogdanov 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 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** - **A Practical Attack on KeeLoq**
Sebastiaan Indesteege, Nathan Keller, Orr Dunkelman, Eli Biham, Bart Preneel Sebastiaan Indesteege, Nathan Keller, Orr Dunkelman, Eli Biham, Bart Preneel
*EUROCRYPT 2008* *EUROCRYPT 2008 (LNCS vol. 4965, pp. 118)*
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 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. 97115)*
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. 203220)*
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** - **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. 403420)*
DOI: [10.1007/978-3-642-02384-2_25](https://doi.org/10.1007/978-3-642-02384-2_25) 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** - **Gone in 360 Seconds: Hijacking with Hitag2**
Lennert Wouters, Jan Van den Herrewegen, Flavio D. Garcia, David Oswald, Benedikt Gierlichs, Bart Preneel Roel Verdult, Flavio D. Garcia, Josep Balasch
*IACR Transactions on Cryptographic Hardware and Embedded Systems (TCHES), 2020, Vol. 2* *21st USENIX Security Symposium (USENIX Security '12), pp. 237252*
DOI: [10.13154/tches.v2020.i2.99-127](https://doi.org/10.13154/tches.v2020.i2.99-127) 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. 703718*
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. 4669*
DOI: [10.13154/tches.v2018.i2.46-69](https://doi.org/10.13154/tches.v2018.i2.46-69)
### RFID & Protocol Analysis Tooling ### RFID & Protocol Analysis Tooling
@@ -262,6 +282,11 @@ The following academic publications have been invaluable to the development and
### Relay & Replay Attacks ### 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** - **Implementing and Testing RollJam on Software-Defined Radios**
*Università di Bologna (UNIBO), CRIS* *Università di Bologna (UNIBO), CRIS*
https://cris.unibo.it/handle/11585/999874 https://cris.unibo.it/handle/11585/999874
@@ -272,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** - **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 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) 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** - **Rolling-PWN Attack (Honda RKE Vulnerability)**
Aurelien Francillon, Boris Danev, Srdjan Capkun Kevin2600 (Haoqi Shan), Wesley Li — Star-V Lab
*NDSS 2011* *Independent disclosure, 2022 (CVE-2021-46145)*
https://www.ndss-symposium.org/ndss2011/relay-attacks-on-passive-keyless-entry-and-start-systems-in-modern-cars/ https://rollingpwn.github.io/rolling-pwn/
--- ---

View File

@@ -1,5 +1,6 @@
#include "subghz_txrx_i.h" // IWYU pragma: keep #include "subghz_txrx_i.h" // IWYU pragma: keep
#include <math.h>
#include <lib/subghz/protocols/protocol_items.h> #include <lib/subghz/protocols/protocol_items.h>
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h> #include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h> #include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
@@ -494,28 +495,39 @@ void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
} }
} }
#define SUBGHZ_MOD_HOPPER_DWELL_TICKS 3
bool subghz_txrx_mod_hopper_get_running(SubGhzTxRx* instance) { bool subghz_txrx_mod_hopper_get_running(SubGhzTxRx* instance) {
furi_assert(instance); furi_assert(instance);
return instance->mod_hopper_running; return instance->mod_hopper_running;
} }
void subghz_txrx_mod_hopper_set_running(SubGhzTxRx* instance, bool running) { void subghz_txrx_mod_hopper_set_running(
SubGhzTxRx* instance,
bool running,
uint8_t dwell_ticks,
float rssi_threshold) {
furi_assert(instance); furi_assert(instance);
instance->mod_hopper_running = running; instance->mod_hopper_running = running;
if(running) instance->mod_hopper_timer = SUBGHZ_MOD_HOPPER_DWELL_TICKS; 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) { void subghz_txrx_mod_hopper_update(SubGhzTxRx* instance, float current_rssi) {
furi_assert(instance); furi_assert(instance);
if(!instance->mod_hopper_running) return; 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;
return;
}
if(instance->mod_hopper_timer > 0) { if(instance->mod_hopper_timer > 0) {
instance->mod_hopper_timer--; instance->mod_hopper_timer--;
return; return;
} }
instance->mod_hopper_timer = SUBGHZ_MOD_HOPPER_DWELL_TICKS; instance->mod_hopper_timer = instance->mod_hopper_dwell;
size_t count = subghz_setting_get_preset_count(instance->setting); size_t count = subghz_setting_get_preset_count(instance->setting);
if(count == 0) return; if(count == 0) return;

View File

@@ -166,19 +166,27 @@ void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
/** /**
* Update modulation (preset) CC1101 in automatic mode (mod hopper) * Update modulation (preset) CC1101 in automatic mode (mod hopper)
* Cycles through available presets at a fixed dwell time. * 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 instance Pointer to a SubGhzTxRx
* @param current_rssi Current RSSI reading from the radio
*/ */
void subghz_txrx_mod_hopper_update(SubGhzTxRx* instance); void subghz_txrx_mod_hopper_update(SubGhzTxRx* instance, float current_rssi);
/** /**
* Set mod hopper running state * Set mod hopper running state with configuration
* *
* @param instance Pointer to a SubGhzTxRx * @param instance Pointer to a SubGhzTxRx
* @param running true to enable, false to disable * @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); void subghz_txrx_mod_hopper_set_running(
SubGhzTxRx* instance,
bool running,
uint8_t dwell_ticks,
float rssi_threshold);
/** /**
* Get mod hopper running state * Get mod hopper running state

View File

@@ -19,9 +19,11 @@ struct SubGhzTxRx {
bool is_database_loaded; bool is_database_loaded;
SubGhzHopperState hopper_state; SubGhzHopperState hopper_state;
uint8_t mod_hopper_idx; // index into setting presets (wraps around) 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_timer; // countdown ticks before advancing modulation
bool mod_hopper_running; // is mod hopping active 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
SubGhzTxRxState txrx_state; SubGhzTxRxState txrx_state;
SubGhzSpeakerState speaker_state; SubGhzSpeakerState speaker_state;

View File

@@ -1,4 +1,5 @@
#include "../subghz_i.h" #include "../subghz_i.h"
#include <math.h>
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#include <lib/subghz/protocols/bin_raw.h> #include <lib/subghz/protocols/bin_raw.h>
@@ -213,7 +214,11 @@ void subghz_scene_receiver_on_enter(void* context) {
} else { } else {
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
} }
subghz_txrx_mod_hopper_set_running(subghz->txrx, subghz->last_settings->enable_mod_hopping); 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);
subghz_txrx_rx_start(subghz->txrx); subghz_txrx_rx_start(subghz->txrx);
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen);
@@ -303,7 +308,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
subghz_scene_receiver_update_statusbar(subghz); subghz_scene_receiver_update_statusbar(subghz);
} }
if(subghz_txrx_mod_hopper_get_running(subghz->txrx)) { if(subghz_txrx_mod_hopper_get_running(subghz->txrx)) {
subghz_txrx_mod_hopper_update(subghz->txrx); float rssi = subghz_txrx_radio_device_get_rssi(subghz->txrx);
subghz_txrx_mod_hopper_update(subghz->txrx, rssi);
subghz_scene_receiver_update_statusbar(subghz); subghz_scene_receiver_update_statusbar(subghz);
} }

View File

@@ -1,5 +1,6 @@
#include "../subghz_i.h" #include "../subghz_i.h"
#include <lib/toolbox/value_index.h> #include <lib/toolbox/value_index.h>
#include <math.h>
#define TAG "SubGhzSceneReceiverConfig" #define TAG "SubGhzSceneReceiverConfig"
@@ -81,6 +82,44 @@ const float hopping_mode_value[HOPPING_MODE_COUNT] = {
-40.0f, -40.0f,
}; };
#define MOD_HOP_DBM_COUNT 8
const char* const mod_hop_dbm_text[MOD_HOP_DBM_COUNT] = {
"OFF",
"-90",
"-85",
"-80",
"-75",
"-70",
"-65",
"-60",
};
const float mod_hop_dbm_value[MOD_HOP_DBM_COUNT] = {
NAN,
-90.0f,
-85.0f,
-80.0f,
-75.0f,
-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,
};
#define COMBO_BOX_COUNT 2 #define COMBO_BOX_COUNT 2
const uint32_t hopping_value[COMBO_BOX_COUNT] = { const uint32_t hopping_value[COMBO_BOX_COUNT] = {
@@ -276,13 +315,31 @@ static void subghz_scene_receiver_config_set_hopping(VariableItem* item) {
subghz->txrx, index != 0 ? SubGhzHopperStateRunning : SubGhzHopperStateOFF); subghz->txrx, index != 0 ? SubGhzHopperStateRunning : SubGhzHopperStateOFF);
} }
static void subghz_scene_receiver_config_set_mod_hopping(VariableItem* item) { static void subghz_scene_receiver_config_set_mod_hop_dbm(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item); SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item); uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, combobox_text[index]); variable_item_set_current_value_text(item, mod_hop_dbm_text[index]);
bool enabled = index == 1; subghz->last_settings->mod_hopping_threshold = mod_hop_dbm_value[index];
subghz->last_settings->enable_mod_hopping = enabled; bool enabled = index != 0;
subghz_txrx_mod_hopper_set_running(subghz->txrx, enabled); subghz_txrx_mod_hopper_set_running(
subghz->txrx,
enabled,
(uint8_t)subghz->last_settings->mod_hopping_dwell,
mod_hop_dbm_value[index]);
}
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);
}
} }
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
@@ -385,8 +442,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_txrx_hopper_set_state(subghz->txrx, hopping_value[default_index]);
subghz->last_settings->enable_hopping = hopping_value[default_index]; subghz->last_settings->enable_hopping = hopping_value[default_index];
subghz->last_settings->enable_mod_hopping = false; subghz->last_settings->mod_hopping_threshold = NAN;
subghz_txrx_mod_hopper_set_running(subghz->txrx, false); subghz->last_settings->mod_hopping_dwell = 20;
subghz_txrx_mod_hopper_set_running(subghz->txrx, false, 20, NAN);
variable_item_list_set_selected_item(subghz->variable_item_list, default_index); variable_item_list_set_selected_item(subghz->variable_item_list, default_index);
variable_item_list_reset(subghz->variable_item_list); variable_item_list_reset(subghz->variable_item_list);
@@ -451,16 +509,47 @@ void subghz_scene_receiver_config_on_enter(void* context) {
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, hopping_mode_text[value_index]); variable_item_set_current_value_text(item, hopping_mode_text[value_index]);
// Mod Hopping // Mod Hop dBm
item = variable_item_list_add( {
subghz->variable_item_list, uint8_t mod_dbm_idx = 0; // OFF
"Mod Hopping", float thresh = subghz->last_settings->mod_hopping_threshold;
COMBO_BOX_COUNT, if(!isnan(thresh)) {
subghz_scene_receiver_config_set_mod_hopping, for(uint8_t k = 1; k < MOD_HOP_DBM_COUNT; k++) {
subghz); if(mod_hop_dbm_value[k] == thresh) {
value_index = subghz->last_settings->enable_mod_hopping ? 1 : 0; mod_dbm_idx = k;
variable_item_set_current_value_index(item, value_index); break;
variable_item_set_current_value_text(item, combobox_text[value_index]); }
}
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]);
}
// 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]);
}
} }
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=

View File

@@ -1,5 +1,6 @@
#include "subghz_last_settings.h" #include "subghz_last_settings.h"
#include "subghz_i.h" #include "subghz_i.h"
#include <math.h>
#define TAG "SubGhzLastSettings" #define TAG "SubGhzLastSettings"
@@ -13,7 +14,8 @@
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER "FATrigger" #define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER "FATrigger"
#define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES "ProtocolNames" #define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES "ProtocolNames"
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE "Hopping" #define SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE "Hopping"
#define SUBGHZ_LAST_SETTING_FIELD_MOD_HOPPING "ModHopping" #define SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_THRESHOLD "ModHopThreshold"
#define SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_DWELL "ModHopDwell"
#define SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER "IgnoreFilter" #define SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER "IgnoreFilter"
#define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter" #define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter"
#define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI" #define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI"
@@ -46,6 +48,8 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
instance->filter = SubGhzProtocolFlag_Decodable; instance->filter = SubGhzProtocolFlag_Decodable;
instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN; instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN;
instance->hopping_threshold = -90.0f; instance->hopping_threshold = -90.0f;
instance->mod_hopping_threshold = NAN; // disabled by default
instance->mod_hopping_dwell = 20; // 2 seconds (20 × 100ms ticks)
instance->leds_and_amp = true; instance->leds_and_amp = true;
Storage* storage = furi_record_open(RECORD_STORAGE); Storage* storage = furi_record_open(RECORD_STORAGE);
@@ -99,10 +103,17 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
1)) { 1)) {
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
} }
if(!flipper_format_read_bool( if(!flipper_format_read_float(
fff_data_file, fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_MOD_HOPPING, SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_THRESHOLD,
&instance->enable_mod_hopping, &instance->mod_hopping_threshold,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_DWELL,
&instance->mod_hopping_dwell,
1)) { 1)) {
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
} }
@@ -221,10 +232,17 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE, &instance->enable_hopping, 1)) { file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE, &instance->enable_hopping, 1)) {
break; break;
} }
if(!flipper_format_write_bool( if(!flipper_format_write_float(
file, file,
SUBGHZ_LAST_SETTING_FIELD_MOD_HOPPING, SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_THRESHOLD,
&instance->enable_mod_hopping, &instance->mod_hopping_threshold,
1)) {
break;
}
if(!flipper_format_write_uint32(
file,
SUBGHZ_LAST_SETTING_FIELD_MOD_HOP_DWELL,
&instance->mod_hopping_dwell,
1)) { 1)) {
break; break;
} }

View File

@@ -20,7 +20,8 @@ typedef struct {
float frequency_analyzer_trigger; float frequency_analyzer_trigger;
bool protocol_file_names; bool protocol_file_names;
bool enable_hopping; bool enable_hopping;
bool enable_mod_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 ignore_filter;
uint32_t filter; uint32_t filter;
float rssi; float rssi;

View File

@@ -17,8 +17,9 @@
// //
// Frame layout (after stripping 16-bit 0xFFFF preamble): // Frame layout (after stripping 16-bit 0xFFFF preamble):
// Bytes 0-3: Fixed ID / Serial (32 bits) // Bytes 0-3: Fixed ID / Serial (32 bits)
// Byte 4: Button (upper nibble) | Type (lower nibble, always 0x2) // Byte 4: Button (upper nibble) | Type (lower nibble)
// Bytes 5-10: Rolling/encrypted code (48 bits) // Buttons: 0x7=Lock, 0xB=Unlock, 0xD=Trunk
// Bytes 5-10: Rolling/encrypted code (48 bits)
#define FIAT_MARELLI_PREAMBLE_MIN 200 // Min preamble pulses (100 pairs) #define FIAT_MARELLI_PREAMBLE_MIN 200 // Min preamble pulses (100 pairs)
#define FIAT_MARELLI_GAP_MIN 2500 // Gap detection threshold (us) #define FIAT_MARELLI_GAP_MIN 2500 // Gap detection threshold (us)
#define FIAT_MARELLI_SYNC_MIN 1500 // Sync pulse minimum (us) #define FIAT_MARELLI_SYNC_MIN 1500 // Sync pulse minimum (us)
@@ -402,10 +403,12 @@ SubGhzProtocolStatus subghz_protocol_decoder_fiat_marelli_deserialize(
static const char* fiat_marelli_button_name(uint8_t btn) { static const char* fiat_marelli_button_name(uint8_t btn) {
switch(btn) { switch(btn) {
case 0x2: case 0x7:
return "Btn A"; return "Lock";
case 0x4: case 0xB:
return "Btn B"; return "Unlock";
case 0xD:
return "Trunk";
default: default:
return "Unknown"; return "Unknown";
} }