diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 3a005de74f..97b0a7284d 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -120,5 +120,8 @@ typedef enum { SubGhzCustomEventViewFreqAnalOkShort, SubGhzCustomEventViewFreqAnalOkLong, + SubGhzCustomEventViewRepeaterStart, + SubGhzCustomEventViewRepeaterStop, + SubGhzCustomEventByteInputDone, } SubGhzCustomEvent; diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 0d748a80be..0ee1bb5492 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -53,6 +53,7 @@ typedef enum { SubGhzRxKeyStateExit, SubGhzRxKeyStateRAWLoad, SubGhzRxKeyStateRAWSave, + SubGhzRxKeyStateRepeating, } SubGhzRxKeyState; /** SubGhzLoadKeyState state */ @@ -101,4 +102,12 @@ typedef enum { SubGhzDecodeRawStateStart, SubGhzDecodeRawStateLoading, SubGhzDecodeRawStateLoaded, -} SubGhzDecodeRawState; \ No newline at end of file +} SubGhzDecodeRawState; + +/** SubGhz Repeater */ +typedef enum { + SubGhzRepeaterStateOff, + SubGhzRepeaterStateOn, + SubGhzRepeaterStateOnLong, + SubGhzRepeaterStateOnShort, +} SubGhzRepeaterState; diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 7bd3933c27..b2be9b8e28 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -20,7 +20,8 @@ static void subghz_scene_receiver_update_statusbar(void* context) { furi_string_get_cstr(modulation_str), furi_string_get_cstr(history_stat_str), subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF, - READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0); + READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0, + subghz->repeater); furi_string_free(frequency_str); furi_string_free(modulation_str); @@ -31,7 +32,8 @@ static void subghz_scene_receiver_update_statusbar(void* context) { "", "", subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF, - READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0); + READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0, + subghz->repeater); } furi_string_free(history_stat_str); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 95a5fb06dc..d311559f36 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -36,6 +36,16 @@ const NotificationSequence subghz_sequence_rx_locked = { NULL, }; +const NotificationSequence subghz_sequence_tx_beep = { + &message_vibro_on, + &message_note_c6, + &message_delay_50, + &message_sound_off, + &message_vibro_off, + &message_delay_50, + NULL, +}; + static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; FuriString* history_stat_str = furi_string_alloc(); @@ -72,7 +82,8 @@ static void subghz_scene_receiver_update_statusbar(void* context) { furi_string_get_cstr(modulation_str), furi_string_get_cstr(history_stat_str), subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF, - READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0); + READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0, + subghz->repeater); furi_string_free(frequency_str); furi_string_free(modulation_str); @@ -83,7 +94,8 @@ static void subghz_scene_receiver_update_statusbar(void* context) { "", "", subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF, - READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0); + READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0, + subghz->repeater); subghz->state_notifications = SubGhzNotificationStateIDLE; } furi_string_free(history_stat_str); @@ -98,6 +110,12 @@ void subghz_scene_receiver_callback(SubGhzCustomEvent event, void* context) { view_dispatcher_send_custom_event(subghz->view_dispatcher, event); } +void repeater_stop_callback(void* context) { + SubGhz* subghz = context; + furi_timer_stop(subghz->fav_timer); + scene_manager_handle_custom_event(subghz->scene_manager, SubGhzCustomEventViewRepeaterStop); +} + static void subghz_scene_add_to_history_callback( SubGhzReceiver* receiver, SubGhzProtocolDecoderBase* decoder_base, @@ -120,49 +138,56 @@ static void subghz_scene_add_to_history_callback( furi_string_reset(item_name); furi_string_reset(item_time); - subghz->state_notifications = SubGhzNotificationStateRxDone; - - if(subghz->remove_duplicates) { - // Look in history for signal hash - uint8_t hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); - uint16_t menu_idx = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); - subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver); - for(uint16_t i = idx; i > 0; i--) { - i--; // Iterating in reverse with off by one - if(subghz_history_get_hash_data(subghz->history, i) == hash_data) { - // Remove previous instance and update menu index - subghz_history_delete_item(subghz->history, i); - subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, i); - subghz_view_receiver_delete_element_callback(subghz->subghz_receiver); - if(menu_idx > i) { - menu_idx--; - idx--; + //If the repeater is on, dont add to the menu, just TX the signal. + if(subghz->repeater != SubGhzRepeaterStateOff) { + //subghz_scene_receiver_update_statusbar(subghz); + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubGhzCustomEventViewRepeaterStart); + } else { + subghz->state_notifications = SubGhzNotificationStateRxDone; + + if(subghz->remove_duplicates) { + // Look in history for signal hash + uint8_t hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); + uint16_t menu_idx = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver); + for(uint16_t i = idx; i > 0; i--) { + i--; // Iterating in reverse with off by one + if(subghz_history_get_hash_data(subghz->history, i) == hash_data) { + // Remove previous instance and update menu index + subghz_history_delete_item(subghz->history, i); + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, i); + subghz_view_receiver_delete_element_callback(subghz->subghz_receiver); + if(menu_idx > i) { + menu_idx--; + idx--; + } } + i++; + } + // Restore ui state + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, menu_idx); + subghz->idx_menu_chosen = + subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver); + if(subghz_history_get_last_index(subghz->history) == 0) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } - i++; - } - // Restore ui state - subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, menu_idx); - subghz->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); - subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver); - if(subghz_history_get_last_index(subghz->history) == 0) { - subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } - } - - subghz_history_get_text_item_menu(history, item_name, idx); - subghz_history_get_time_item_menu(history, item_time, idx); - subghz_view_receiver_add_item_to_menu( - subghz->subghz_receiver, - furi_string_get_cstr(item_name), - furi_string_get_cstr(item_time), - subghz_history_get_type_protocol(history, idx), - subghz_history_get_repeats(history, idx)); - subghz_scene_receiver_update_statusbar(subghz); - if(subghz_history_get_text_space_left(subghz->history, NULL, 0)) { - notification_message(subghz->notifications, &sequence_error); + subghz_history_get_text_item_menu(history, item_name, idx); + subghz_history_get_time_item_menu(history, item_time, idx); + subghz_view_receiver_add_item_to_menu( + subghz->subghz_receiver, + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), + subghz_history_get_type_protocol(history, idx), + subghz_history_get_repeats(history, idx)); + + subghz_scene_receiver_update_statusbar(subghz); + if(subghz_history_get_text_space_left(subghz->history, NULL, 0)) { + notification_message(subghz->notifications, &sequence_error); + } } } subghz_receiver_reset(receiver); @@ -233,6 +258,34 @@ void subghz_scene_receiver_on_enter(void* context) { subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); } + // Check if Sound was enabled, and restart the Speaker. + subghz_txrx_speaker_set_state( + subghz->txrx, + subghz->last_settings->enable_sound ? SubGhzSpeakerStateEnable : + SubGhzSpeakerStateShutdown); + + //Set up a timer for the repeater (recycled favorites timeout TX timer!). + subghz->fav_timer = furi_timer_alloc(repeater_stop_callback, FuriTimerTypePeriodic, subghz); + + //Remember if the repeater was loaded, and do cleanups we need. + subghz->repeater = subghz->last_settings->repeater_state; + + //Did the user set BinRAW or me? + if(subghz->last_settings->repeater_state != SubGhzRepeaterStateOff) { + //Save the state, we are on. + subghz->repeater = subghz->last_settings->repeater_state; + + //User had BinRAW on if the last settings had BinRAW on, if not, repeater is on, and BinRAW goes on, but State CHanged is false! + subghz->bin_raw_menu_changed = + (subghz->last_settings->filter != + (SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW)); + subghz->filter = SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW; + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); + } else { + subghz->repeater = SubGhzRepeaterStateOff; + subghz->bin_raw_menu_changed = false; + } + subghz_txrx_rx_start(subghz->txrx); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); @@ -309,35 +362,78 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_unlock(subghz); consumed = true; break; + case SubGhzCustomEventViewRepeaterStart: + subghz_txrx_stop(subghz->txrx); + subghz_txrx_hopper_pause(subghz->txrx); + + FlipperFormat* key_repeat_data = subghz_history_get_raw_data( + subghz->history, subghz_history_get_last_index(subghz->history) - 1); + + uint32_t tmpTe = 300; + if(!flipper_format_rewind(key_repeat_data)) { + FURI_LOG_E(TAG, "Rewind error"); + } else if(!flipper_format_read_uint32(key_repeat_data, "TE", (uint32_t*)&tmpTe, 1)) { + FURI_LOG_E(TAG, "Missing TE"); + } + + if(!subghz_tx_start(subghz, key_repeat_data)) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubGhzCustomEventViewRepeaterStop); + } else { + subghz->state_notifications = SubGhzNotificationStateTx; + notification_message(subghz->notifications, &subghz_sequence_tx_beep); + + uint32_t repeatnormal = (tmpTe > 1000) ? 1 : 3; + uint32_t repeat_time = ((subghz->repeater & SubGhzRepeaterStateOnLong) != 0) ? + 2 * repeatnormal * tmpTe : + ((subghz->repeater & SubGhzRepeaterStateOnShort) != 0) ? + 1 * tmpTe : + repeatnormal * tmpTe; + furi_timer_start(subghz->fav_timer, repeat_time); + } + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRepeating); + break; + case SubGhzCustomEventViewRepeaterStop: + subghz_txrx_stop(subghz->txrx); + subghz_history_delete_item( + subghz->history, subghz_history_get_last_index(subghz->history) - 1); + subghz_txrx_rx_start(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); + subghz->state_notifications = SubGhzNotificationStateRx; + break; default: break; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { - subghz_txrx_hopper_update(subghz->txrx); - subghz_scene_receiver_update_statusbar(subghz); - } + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateRepeating) { + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); + subghz_scene_receiver_update_statusbar(subghz); + } + + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data( + subghz->threshold_rssi, subghz_txrx_radio_device_get_rssi(subghz->txrx)); - SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data( - subghz->threshold_rssi, subghz_txrx_radio_device_get_rssi(subghz->txrx)); - - if(subghz->last_settings->gps_baudrate != 0) { - FuriHalRtcDateTime datetime; - furi_hal_rtc_get_datetime(&datetime); - if((datetime.second - subghz->gps->fix_second) > 15) { - subghz->gps->latitude = NAN; - subghz->gps->longitude = NAN; - subghz->gps->satellites = 0; - subghz->gps->fix_hour = 0; - subghz->gps->fix_minute = 0; - subghz->gps->fix_second = 0; + if(subghz->last_settings->gps_baudrate != 0) { + FuriHalRtcDateTime datetime; + furi_hal_rtc_get_datetime(&datetime); + if((datetime.second - subghz->gps->fix_second) > 15) { + subghz->gps->latitude = NAN; + subghz->gps->longitude = NAN; + subghz->gps->satellites = 0; + subghz->gps->fix_hour = 0; + subghz->gps->fix_minute = 0; + subghz->gps->fix_second = 0; + } + subghz_scene_receiver_update_statusbar(subghz); } - subghz_scene_receiver_update_statusbar(subghz); - } - subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); - subghz_protocol_decoder_bin_raw_data_input_rssi( - (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi); + subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); + subghz_protocol_decoder_bin_raw_data_input_rssi( + (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), + ret_rssi.rssi); + } switch(subghz->state_notifications) { case SubGhzNotificationStateRx: @@ -359,6 +455,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { } subghz->state_notifications = SubGhzNotificationStateRx; break; + case SubGhzNotificationStateTx: + notification_message(subghz->notifications, &sequence_blink_magenta_10); + break; default: break; } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index e2f1061e65..4105b7f8fc 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -3,6 +3,9 @@ #define TAG "SubGhzSceneReceiverConfig" +#define BIN_RAW_MENU_POS 3 +#define TURN_OFF_REPEATER_INFO "Turn off\n Repeater!\n to do\n that!" + enum SubGhzSettingIndex { SubGhzSettingIndexFrequency, SubGhzSettingIndexModulation, @@ -21,6 +24,7 @@ enum SubGhzSettingIndex { SubGhzSettingIndexSound, SubGhzSettingIndexResetToDefault, SubGhzSettingIndexLock, + SubGhzSettingIndexRepeater, }; #define RAW_THRESHOLD_RSSI_COUNT 11 @@ -53,6 +57,7 @@ const float raw_threshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { }; #define COMBO_BOX_COUNT 2 +#define REPEATER_BOX_COUNT 4 const uint32_t hopping_value[COMBO_BOX_COUNT] = { SubGhzHopperStateOFF, @@ -69,11 +74,25 @@ const uint32_t bin_raw_value[COMBO_BOX_COUNT] = { SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW, }; +const uint32_t repeater_value[REPEATER_BOX_COUNT] = { + SubGhzRepeaterStateOff, + SubGhzRepeaterStateOn, + SubGhzRepeaterStateOnLong, + SubGhzRepeaterStateOnShort, +}; + const char* const combobox_text[COMBO_BOX_COUNT] = { "OFF", "ON", }; +const char* const repeater_box_text[REPEATER_BOX_COUNT] = { + "OFF", + "Normal", + "Long", + "Short", +}; + static void subghz_scene_receiver_config_set_ignore_filter( VariableItem* item, SubGhzProtocolFilter filter) { @@ -244,6 +263,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { variable_item_set_current_value_text(item, combobox_text[index]); subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]); + subghz->last_settings->enable_sound = (speaker_value[index] == SubGhzSpeakerStateEnable); } static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { @@ -256,6 +276,53 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { // We can set here, but during subghz_last_settings_save filter was changed to ignore BinRAW subghz->last_settings->filter = subghz->filter; + + //If the user changed BinRAW menu, dont reset it with the repeater. + subghz->bin_raw_menu_changed = false; +} + +static void subghz_scene_receiver_config_set_repeater(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + //Set menu Text. + variable_item_set_current_value_text(item, repeater_box_text[index]); + + //Save state and in last settings. + subghz->repeater = repeater_value[index]; + subghz->last_settings->repeater_state = repeater_value[index]; + + //Get the BinRAW menu for state change. + VariableItem* bin_raw_menu = + variable_item_list_get(subghz->variable_item_list, BIN_RAW_MENU_POS); + + //Change BinRAW to ON or OFF as required, and remember whether I changed it! (Put back for the user.) + if(repeater_value[index] != SubGhzRepeaterStateOff) { + if((bin_raw_value[variable_item_get_current_value_index(bin_raw_menu)] & + SubGhzProtocolFlag_BinRAW) == SubGhzProtocolFlag_BinRAW) { + //BinRAW is on, repeater is on. + } else { + //Repeater is on, Binraw is Off. + variable_item_set_current_value_index( + bin_raw_menu, 1 /*Index of ON in BIN_Raw menu!*/); + subghz_scene_receiver_config_set_bin_raw(bin_raw_menu); + subghz->bin_raw_menu_changed = true; + } + + //Lock the BinRAW menu, Flipper doesnt understand everything so BinRAW makes very key send. + variable_item_set_locked(bin_raw_menu, true, TURN_OFF_REPEATER_INFO); + } else { + //Put BinRAW back how it was, if we changed it. + if(subghz->bin_raw_menu_changed) { + variable_item_set_current_value_index( + bin_raw_menu, 0 /*Index of OFF in BIN_Raw menu!*/); + subghz_scene_receiver_config_set_bin_raw(bin_raw_menu); + subghz->bin_raw_menu_changed = false; + } + + //Lock the BinRAW menu, Flipper doesnt understand everything so BinRAW makes very key send. + variable_item_set_locked(bin_raw_menu, false, TURN_OFF_REPEATER_INFO); + } } static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { @@ -347,7 +414,8 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context, subghz->last_settings->remove_duplicates = subghz->remove_duplicates; subghz->last_settings->ignore_filter = subghz->ignore_filter; subghz->last_settings->filter = subghz->filter; - + subghz->last_settings->repeater_state = SubGhzRepeaterStateOff; + subghz->repeater = SubGhzRepeaterStateOff; subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[default_index]); subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[default_index]); @@ -431,10 +499,20 @@ void subghz_scene_receiver_config_on_enter(void* context) { value_index = value_index_uint32(subghz->filter, bin_raw_value, COMBO_BOX_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, combobox_text[value_index]); - } + variable_item_set_locked( + item, (subghz->repeater != SubGhzRepeaterStateOff), TURN_OFF_REPEATER_INFO); + + item = variable_item_list_add( + subghz->variable_item_list, + "Repeater", + REPEATER_BOX_COUNT, + subghz_scene_receiver_config_set_repeater, + subghz); + + value_index = value_index_uint32(subghz->repeater, repeater_value, REPEATER_BOX_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, repeater_box_text[value_index]); - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != - SubGhzCustomEventManagerSet) { item = variable_item_list_add( subghz->variable_item_list, "Remove Duplicates", @@ -604,6 +682,11 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even void subghz_scene_receiver_config_on_exit(void* context) { SubGhz* subghz = context; + + if(subghz->bin_raw_menu_changed) { + subghz->last_settings->filter = bin_raw_value[0 /*BinRAW Off*/]; + } + variable_item_list_set_selected_item(subghz->variable_item_list, 0); variable_item_list_reset(subghz->variable_item_list); #ifdef FURI_DEBUG diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 5357808d42..cdd77e8251 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -96,6 +96,8 @@ struct SubGhz { SubGhzRxKeyState rx_key_state; SubGhzHistory* history; SubGhzGPS* gps; + SubGhzRepeaterState repeater; + bool bin_raw_menu_changed; uint16_t idx_menu_chosen; SubGhzLoadTypeFile load_type_file; diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 08929af7b4..73b4ddbd7f 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -21,6 +21,8 @@ #define SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER "IgnoreFilter" #define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter" #define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI" +#define SUBGHZ_LAST_SETTING_FIELD_REPEATER "Repeater" +#define SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND "Sound" SubGhzLastSettings* subghz_last_settings_alloc(void) { SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings)); @@ -46,6 +48,8 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count bool temp_external_module_power_amp = false; bool temp_timestamp_file_names = false; bool temp_enable_hopping = false; + bool temp_enable_sound = false; + uint32_t temp_repeater_state; bool temp_remove_duplicates = false; uint32_t temp_ignore_filter = 0; uint32_t temp_filter = 0; @@ -59,6 +63,9 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count bool remove_duplicates_was_read = false; bool frequency_analyzer_feedback_level_was_read = false; bool frequency_analyzer_trigger_was_read = false; + bool repeater_was_read = false; + bool enable_sound_was_read = false; + uint32_t temp_gps_baudrate = 0; if(FSE_OK == storage_sd_status(storage) && SUBGHZ_LAST_SETTINGS_PATH && @@ -118,6 +125,11 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count 1); filter_was_read = flipper_format_read_uint32( fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FILTER, (uint32_t*)&temp_filter, 1); + repeater_was_read = flipper_format_read_uint32( + fff_data_file, SUBGHZ_LAST_SETTING_FIELD_REPEATER, (uint32_t*)&temp_repeater_state, 1); + enable_sound_was_read = flipper_format_read_bool( + fff_data_file, SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND, (bool*)&temp_enable_sound, 1); + } else { FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH); } @@ -136,6 +148,8 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->gps_baudrate = 0; instance->enable_hopping = false; instance->remove_duplicates = false; + instance->repeater_state = 0; + instance->enable_sound = 0; instance->ignore_filter = 0x00; // See bin_raw_value in applications/main/subghz/scenes/subghz_scene_receiver_config.c instance->filter = SubGhzProtocolFlag_Decodable; @@ -175,6 +189,8 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->rssi = rssi_was_read ? temp_rssi : SUBGHZ_RAW_THRESHOLD_MIN; instance->enable_hopping = temp_enable_hopping; + instance->repeater_state = repeater_was_read ? temp_repeater_state : 0; + instance->enable_sound = enable_sound_was_read ? temp_enable_sound : false; instance->remove_duplicates = remove_duplicates_was_read ? temp_remove_duplicates : false; instance->ignore_filter = ignore_filter_was_read ? temp_ignore_filter : 0x00; #if SUBGHZ_LAST_SETTING_SAVE_BIN_RAW @@ -298,7 +314,14 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) { file, SUBGHZ_LAST_SETTING_FIELD_FILTER, &instance->filter, 1)) { break; } - saved = true; + if(!flipper_format_insert_or_update_uint32( + file, SUBGHZ_LAST_SETTING_FIELD_REPEATER, &instance->repeater_state, 1)) { + break; + } + if(!flipper_format_insert_or_update_bool( + file, SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND, &instance->enable_sound, 1)) { + break; + } } while(0); if(!saved) { @@ -331,7 +354,7 @@ void subghz_last_settings_log(SubGhzLastSettings* instance) { TAG, "Frequency: %03ld.%02ld, FeedbackLevel: %ld, FATrigger: %.2f, External: %s, ExtPower: %s, TimestampNames: %s, ExtPowerAmp: %s,\n" "GPSBaudrate: %ld, Hopping: %s,\nPreset: %ld, RSSI: %.2f, " - "BinRAW: %s, Duplicates: %s, Starline: %s, Cars: %s, Magellan: %s, NiceFloR-S: %s, Weather: %s, TPMS: %s", + "BinRAW: %s, Repeater: %lu, Duplicates: %s, Starline: %s, Cars: %s, Magellan: %s, NiceFloR-S: %s, Weather: %s, TPMS: %s, Sound: %s", instance->frequency / 1000000 % 1000, instance->frequency / 10000 % 100, instance->frequency_analyzer_feedback_level, @@ -345,6 +368,7 @@ void subghz_last_settings_log(SubGhzLastSettings* instance) { instance->preset_index, (double)instance->rssi, subghz_last_settings_log_filter_get_index(instance->filter, SubGhzProtocolFlag_BinRAW), + instance->repeater_state, instance->remove_duplicates ? LOG_ON : LOG_OFF, subghz_last_settings_log_filter_get_index( instance->ignore_filter, SubGhzProtocolFilter_StarLine), @@ -357,5 +381,6 @@ void subghz_last_settings_log(SubGhzLastSettings* instance) { subghz_last_settings_log_filter_get_index( instance->ignore_filter, SubGhzProtocolFilter_Weather), subghz_last_settings_log_filter_get_index( - instance->ignore_filter, SubGhzProtocolFilter_TPMS)); + instance->ignore_filter, SubGhzProtocolFilter_TPMS), + bool_to_char(instance->enable_sound)); } diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index 7ec2411584..44c163dd20 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -28,6 +28,9 @@ typedef struct { bool timestamp_file_names; uint32_t gps_baudrate; bool enable_hopping; + uint32_t repeater_state; + bool enable_sound; + bool remove_duplicates; uint32_t ignore_filter; uint32_t filter; diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 0fea59af55..11dbae2d03 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -65,6 +65,7 @@ typedef struct { FuriString* progress_str; bool hopping_enabled; bool bin_raw_enabled; + SubGhzRepeaterState repeater_state; SubGhzReceiverHistory* history; uint16_t idx; uint16_t list_offset; @@ -207,7 +208,8 @@ void subghz_view_receiver_add_data_statusbar( const char* preset_str, const char* history_stat_str, bool hopping_enabled, - bool bin_raw_enabled) { + bool bin_raw_enabled, + SubGhzRepeaterState repeater_state) { furi_assert(subghz_receiver); with_view_model( subghz_receiver->view, @@ -218,6 +220,7 @@ void subghz_view_receiver_add_data_statusbar( furi_string_set(model->history_stat_str, history_stat_str); model->hopping_enabled = hopping_enabled; model->bin_raw_enabled = bin_raw_enabled; + model->repeater_state = repeater_state; }, true); } @@ -336,7 +339,9 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { (model->device_type == SubGhzRadioDeviceTypeInternal) ? &I_Scanning_123x52 : &I_Fishing_123x52); canvas_set_font(canvas, FontPrimary); - if(model->hopping_enabled) { + if(model->repeater_state != SubGhzRepeaterStateOff) { + canvas_draw_str(canvas, 59, 46, "Repeater..."); + } else if(model->hopping_enabled) { canvas_draw_str(canvas, 59, 46, "Hopper scan..."); } else { canvas_draw_str(canvas, 59, 46, "Fixed scan..."); @@ -595,6 +600,7 @@ void subghz_view_receiver_exit(void* context) { model->nodraw = false; model->hopping_enabled = false; model->bin_raw_enabled = false; + model->repeater_state = SubGhzRepeaterStateOff; }, false); furi_timer_stop(subghz_receiver->timer); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 6f8a5863f8..f376aca517 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -33,7 +33,8 @@ void subghz_view_receiver_add_data_statusbar( const char* preset_str, const char* history_stat_str, bool hopping_enabled, - bool bin_raw_enabled); + bool bin_raw_enabled, + SubGhzRepeaterState repeater_enabled); void subghz_view_receiver_set_radio_device_type( SubGhzViewReceiver* subghz_receiver,