diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index adb4efa4..17b18360 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -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) { diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 1b4831b4..9e05558c 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -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 diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h index 83ef5ce1..71192509 100644 --- a/applications/main/subghz/helpers/subghz_txrx_i.h +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -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; diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index ad28b35f..58a8ed5f 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -29,6 +29,14 @@ typedef enum { SubGhzHopperStateRSSITimeOut, } SubGhzHopperState; +/** SubGhzPresetHopperState state */ +typedef enum { + SubGhzPresetHopperStateOFF, + SubGhzPresetHopperStateRunning, + SubGhzPresetHopperStatePause, + SubGhzPresetHopperStateRSSITimeOut, +} SubGhzPresetHopperState; + /** SubGhzSpeakerState state */ typedef enum { SubGhzSpeakerStateDisable, diff --git a/applications/main/subghz/resources/subghz/assets/setting_user.example b/applications/main/subghz/resources/subghz/assets/setting_user.example index 9f74ee37..f36be0b0 100644 --- a/applications/main/subghz/resources/subghz/assets/setting_user.example +++ b/applications/main/subghz/resources/subghz/assets/setting_user.example @@ -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 diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index aac8f4ae..d2b86110 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -1,5 +1,4 @@ #include "../subghz_i.h" -#include #include #include @@ -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); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 721bbff6..3c9c9789 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -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) != diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 2a40d440..384446a8 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -1,6 +1,5 @@ #include "subghz_last_settings.h" #include "subghz_i.h" -#include #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; } diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index 8fa98af6..1f65e6bb 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -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; diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 3d062e41..be846791 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -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; } diff --git a/lib/subghz/subghz_setting.h b/lib/subghz/subghz_setting.h index 3e705312..85695b2a 100644 --- a/lib/subghz/subghz_setting.h +++ b/lib/subghz/subghz_setting.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -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 diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index b58b33e5..a7a75cb2 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -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"