[FL-3242] SubGhz: refactoring app (#2554)
* SubGhz: add SubGhzThresholdRssi * SubGhz: remove direct reading of subghz-txrx-txrx_state * SubGhz: remove direct reading subghz->txrx->hopper_state * SubGhz: remove direct reading subghz->lock * SubGhz: check load type file * SubGhz: remove direct reading subghz->txrx->rx_key_state * SubGhz: remove direct reading subghz->txrx->speaker_state * SubGhz: refactoring subghz_scene_set_type.c * SubGhz: moving "txrx" entity to a separate file * SubGhz: show error tx start * SubGhz: refactoring RPC * SubGhz: value get optimizations * SubGhz: fix name file * SubGhz: add function description * SubGhz: fix double back with a blocked transmission in this region and speacker, when a transmission is blocked in this region * SubGhz: correct spelling * SubGhz: better naming * SubGhz: simplify includes Co-authored-by: SG <who.just.the.doctor@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									71e85ac367
								
							
						
					
					
						commit
						d2ca67d261
					
				@ -12,7 +12,7 @@
 | 
				
			|||||||
#define MENU_ITEMS 4u
 | 
					#define MENU_ITEMS 4u
 | 
				
			||||||
#define UNLOCK_CNT 3
 | 
					#define UNLOCK_CNT 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
 | 
					#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    FuriString* item_str;
 | 
					    FuriString* item_str;
 | 
				
			||||||
    uint8_t type;
 | 
					    uint8_t type;
 | 
				
			||||||
@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) {
 | 
				
			|||||||
        instance->view,
 | 
					        instance->view,
 | 
				
			||||||
        WSReceiverModel * model,
 | 
					        WSReceiverModel * model,
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
 | 
					            if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
 | 
				
			||||||
                model->u_rssi = 0;
 | 
					                model->u_rssi = 0;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
 | 
					                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        true);
 | 
					        true);
 | 
				
			||||||
 | 
				
			|||||||
@ -6,14 +6,13 @@ typedef enum {
 | 
				
			|||||||
    SubGhzCustomEventManagerSetRAW,
 | 
					    SubGhzCustomEventManagerSetRAW,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //SubmenuIndex
 | 
					    //SubmenuIndex
 | 
				
			||||||
    SubmenuIndexPricenton,
 | 
					    SubmenuIndexPricenton_433,
 | 
				
			||||||
 | 
					    SubmenuIndexPricenton_315,
 | 
				
			||||||
    SubmenuIndexNiceFlo12bit,
 | 
					    SubmenuIndexNiceFlo12bit,
 | 
				
			||||||
    SubmenuIndexNiceFlo24bit,
 | 
					    SubmenuIndexNiceFlo24bit,
 | 
				
			||||||
    SubmenuIndexCAME12bit,
 | 
					    SubmenuIndexCAME12bit,
 | 
				
			||||||
    SubmenuIndexCAME24bit,
 | 
					    SubmenuIndexCAME24bit,
 | 
				
			||||||
    SubmenuIndexCAMETwee,
 | 
					    SubmenuIndexCAMETwee,
 | 
				
			||||||
    SubmenuIndexNeroSketch,
 | 
					 | 
				
			||||||
    SubmenuIndexNeroRadio,
 | 
					 | 
				
			||||||
    SubmenuIndexGateTX,
 | 
					    SubmenuIndexGateTX,
 | 
				
			||||||
    SubmenuIndexDoorHan_315_00,
 | 
					    SubmenuIndexDoorHan_315_00,
 | 
				
			||||||
    SubmenuIndexDoorHan_433_92,
 | 
					    SubmenuIndexDoorHan_433_92,
 | 
				
			||||||
 | 
				
			|||||||
@ -261,7 +261,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont
 | 
				
			|||||||
    instance->thread = furi_thread_alloc_ex(
 | 
					    instance->thread = furi_thread_alloc_ex(
 | 
				
			||||||
        "SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance);
 | 
					        "SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance);
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    instance->setting = subghz->setting;
 | 
					    instance->setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
    return instance;
 | 
					    return instance;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										60
									
								
								applications/main/subghz/helpers/subghz_threshold_rssi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								applications/main/subghz/helpers/subghz_threshold_rssi.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					#include "subghz_threshold_rssi.h"
 | 
				
			||||||
 | 
					#include <float_tools.h>
 | 
				
			||||||
 | 
					#include "../subghz_i.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TAG "SubGhzThresholdRssi"
 | 
				
			||||||
 | 
					#define THRESHOLD_RSSI_LOW_COUNT 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SubGhzThresholdRssi {
 | 
				
			||||||
 | 
					    float threshold_rssi;
 | 
				
			||||||
 | 
					    uint8_t threshold_rssi_low_count;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void) {
 | 
				
			||||||
 | 
					    SubGhzThresholdRssi* instance = malloc(sizeof(SubGhzThresholdRssi));
 | 
				
			||||||
 | 
					    instance->threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN;
 | 
				
			||||||
 | 
					    instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT;
 | 
				
			||||||
 | 
					    return instance;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    free(instance);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    instance->threshold_rssi = rssi;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return instance->threshold_rssi;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    float rssi = furi_hal_subghz_get_rssi();
 | 
				
			||||||
 | 
					    SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) {
 | 
				
			||||||
 | 
					        ret.is_above = true;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if(rssi < instance->threshold_rssi) {
 | 
				
			||||||
 | 
					            instance->threshold_rssi_low_count++;
 | 
				
			||||||
 | 
					            if(instance->threshold_rssi_low_count > THRESHOLD_RSSI_LOW_COUNT) {
 | 
				
			||||||
 | 
					                instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ret.is_above = false;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            instance->threshold_rssi_low_count = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(instance->threshold_rssi_low_count == THRESHOLD_RSSI_LOW_COUNT) {
 | 
				
			||||||
 | 
					            ret.is_above = false;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ret.is_above = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								applications/main/subghz/helpers/subghz_threshold_rssi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								applications/main/subghz/helpers/subghz_threshold_rssi.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <furi.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    float rssi; /**< Current RSSI */
 | 
				
			||||||
 | 
					    bool is_above; /**< Exceeded threshold level */
 | 
				
			||||||
 | 
					} SubGhzThresholdRssiData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct SubGhzThresholdRssi SubGhzThresholdRssi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Allocate SubGhzThresholdRssi
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @return SubGhzThresholdRssi* 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Free SubGhzThresholdRssi
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzThresholdRssi
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Set threshold
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzThresholdRssi
 | 
				
			||||||
 | 
					 * @param rssi RSSI threshold
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Get threshold
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzThresholdRssi
 | 
				
			||||||
 | 
					 * @return float RSSI threshold
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Check threshold
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzThresholdRssi
 | 
				
			||||||
 | 
					 * @return SubGhzThresholdRssiData 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance);
 | 
				
			||||||
							
								
								
									
										521
									
								
								applications/main/subghz/helpers/subghz_txrx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										521
									
								
								applications/main/subghz/helpers/subghz_txrx.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,521 @@
 | 
				
			|||||||
 | 
					#include "subghz_txrx_i.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/protocol_items.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TAG "SubGhz"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzTxRx* subghz_txrx_alloc() {
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx));
 | 
				
			||||||
 | 
					    instance->setting = subghz_setting_alloc();
 | 
				
			||||||
 | 
					    subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    instance->preset = malloc(sizeof(SubGhzRadioPreset));
 | 
				
			||||||
 | 
					    instance->preset->name = furi_string_alloc();
 | 
				
			||||||
 | 
					    subghz_txrx_set_preset(
 | 
				
			||||||
 | 
					        instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    instance->txrx_state = SubGhzTxRxStateSleep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF);
 | 
				
			||||||
 | 
					    subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    instance->worker = subghz_worker_alloc();
 | 
				
			||||||
 | 
					    instance->fff_data = flipper_format_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    instance->environment = subghz_environment_alloc();
 | 
				
			||||||
 | 
					    instance->is_database_loaded = subghz_environment_load_keystore(
 | 
				
			||||||
 | 
					        instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
 | 
				
			||||||
 | 
					    subghz_environment_load_keystore(
 | 
				
			||||||
 | 
					        instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
 | 
				
			||||||
 | 
					    subghz_environment_set_came_atomo_rainbow_table_file_name(
 | 
				
			||||||
 | 
					        instance->environment, EXT_PATH("subghz/assets/came_atomo"));
 | 
				
			||||||
 | 
					    subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
 | 
				
			||||||
 | 
					        instance->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
 | 
				
			||||||
 | 
					    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
 | 
				
			||||||
 | 
					        instance->environment, EXT_PATH("subghz/assets/nice_flor_s"));
 | 
				
			||||||
 | 
					    subghz_environment_set_protocol_registry(
 | 
				
			||||||
 | 
					        instance->environment, (void*)&subghz_protocol_registry);
 | 
				
			||||||
 | 
					    instance->receiver = subghz_receiver_alloc_init(instance->environment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subghz_worker_set_overrun_callback(
 | 
				
			||||||
 | 
					        instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
 | 
				
			||||||
 | 
					    subghz_worker_set_pair_callback(
 | 
				
			||||||
 | 
					        instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
 | 
				
			||||||
 | 
					    subghz_worker_set_context(instance->worker, instance->receiver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return instance;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_free(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subghz_worker_free(instance->worker);
 | 
				
			||||||
 | 
					    subghz_receiver_free(instance->receiver);
 | 
				
			||||||
 | 
					    subghz_environment_free(instance->environment);
 | 
				
			||||||
 | 
					    flipper_format_free(instance->fff_data);
 | 
				
			||||||
 | 
					    furi_string_free(instance->preset->name);
 | 
				
			||||||
 | 
					    subghz_setting_free(instance->setting);
 | 
				
			||||||
 | 
					    free(instance->preset);
 | 
				
			||||||
 | 
					    free(instance);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return instance->is_database_loaded;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_set_preset(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* preset_name,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    uint8_t* preset_data,
 | 
				
			||||||
 | 
					    size_t preset_data_size) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_string_set(instance->preset->name, preset_name);
 | 
				
			||||||
 | 
					    SubGhzRadioPreset* preset = instance->preset;
 | 
				
			||||||
 | 
					    preset->frequency = frequency;
 | 
				
			||||||
 | 
					    preset->data = preset_data;
 | 
				
			||||||
 | 
					    preset->data_size = preset_data_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) {
 | 
				
			||||||
 | 
					    UNUSED(instance);
 | 
				
			||||||
 | 
					    const char* preset_name = "";
 | 
				
			||||||
 | 
					    if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
 | 
				
			||||||
 | 
					        preset_name = "AM270";
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
 | 
				
			||||||
 | 
					        preset_name = "AM650";
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
 | 
				
			||||||
 | 
					        preset_name = "FM238";
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
 | 
				
			||||||
 | 
					        preset_name = "FM476";
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
 | 
				
			||||||
 | 
					        preset_name = "CUSTOM";
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        FURI_LOG_E(TAG, "Unknown preset");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return preset_name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return *instance->preset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_get_frequency_and_modulation(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    FuriString* frequency,
 | 
				
			||||||
 | 
					    FuriString* modulation) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    SubGhzRadioPreset* preset = instance->preset;
 | 
				
			||||||
 | 
					    if(frequency != NULL) {
 | 
				
			||||||
 | 
					        furi_string_printf(
 | 
				
			||||||
 | 
					            frequency,
 | 
				
			||||||
 | 
					            "%03ld.%02ld",
 | 
				
			||||||
 | 
					            preset->frequency / 1000000 % 1000,
 | 
				
			||||||
 | 
					            preset->frequency / 10000 % 100);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(modulation != NULL) {
 | 
				
			||||||
 | 
					        furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_hal_subghz_reset();
 | 
				
			||||||
 | 
					    furi_hal_subghz_idle();
 | 
				
			||||||
 | 
					    furi_hal_subghz_load_custom_preset(preset_data);
 | 
				
			||||||
 | 
					    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 | 
				
			||||||
 | 
					    instance->txrx_state = SubGhzTxRxStateIDLE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
 | 
				
			||||||
 | 
					        furi_crash("SubGhz: Incorrect RX frequency.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    furi_assert(
 | 
				
			||||||
 | 
					        instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    furi_hal_subghz_idle();
 | 
				
			||||||
 | 
					    uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
 | 
				
			||||||
 | 
					    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 | 
				
			||||||
 | 
					    furi_hal_subghz_flush_rx();
 | 
				
			||||||
 | 
					    subghz_txrx_speaker_on(instance);
 | 
				
			||||||
 | 
					    furi_hal_subghz_rx();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker);
 | 
				
			||||||
 | 
					    subghz_worker_start(instance->worker);
 | 
				
			||||||
 | 
					    instance->txrx_state = SubGhzTxRxStateRx;
 | 
				
			||||||
 | 
					    return value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void subghz_txrx_idle(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
 | 
				
			||||||
 | 
					    furi_hal_subghz_idle();
 | 
				
			||||||
 | 
					    subghz_txrx_speaker_off(instance);
 | 
				
			||||||
 | 
					    instance->txrx_state = SubGhzTxRxStateIDLE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void subghz_txrx_rx_end(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_assert(instance->txrx_state == SubGhzTxRxStateRx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(subghz_worker_is_running(instance->worker)) {
 | 
				
			||||||
 | 
					        subghz_worker_stop(instance->worker);
 | 
				
			||||||
 | 
					        furi_hal_subghz_stop_async_rx();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    furi_hal_subghz_idle();
 | 
				
			||||||
 | 
					    subghz_txrx_speaker_off(instance);
 | 
				
			||||||
 | 
					    instance->txrx_state = SubGhzTxRxStateIDLE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_sleep(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_hal_subghz_sleep();
 | 
				
			||||||
 | 
					    instance->txrx_state = SubGhzTxRxStateSleep;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
 | 
				
			||||||
 | 
					        furi_crash("SubGhz: Incorrect TX frequency.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
 | 
				
			||||||
 | 
					    furi_hal_subghz_idle();
 | 
				
			||||||
 | 
					    furi_hal_subghz_set_frequency_and_path(frequency);
 | 
				
			||||||
 | 
					    furi_hal_gpio_write(&gpio_cc1101_g0, false);
 | 
				
			||||||
 | 
					    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
 | 
				
			||||||
 | 
					    bool ret = furi_hal_subghz_tx();
 | 
				
			||||||
 | 
					    if(ret) {
 | 
				
			||||||
 | 
					        subghz_txrx_speaker_on(instance);
 | 
				
			||||||
 | 
					        instance->txrx_state = SubGhzTxRxStateTx;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_assert(flipper_format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subghz_txrx_stop(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers;
 | 
				
			||||||
 | 
					    FuriString* temp_str = furi_string_alloc();
 | 
				
			||||||
 | 
					    uint32_t repeat = 200;
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        if(!flipper_format_rewind(flipper_format)) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "Rewind error");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "Missing Protocol");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "Unable Repeat");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = SubGhzTxRxStartTxStateOk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SubGhzRadioPreset* preset = instance->preset;
 | 
				
			||||||
 | 
					        instance->transmitter =
 | 
				
			||||||
 | 
					            subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(instance->transmitter) {
 | 
				
			||||||
 | 
					            if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) ==
 | 
				
			||||||
 | 
					               SubGhzProtocolStatusOk) {
 | 
				
			||||||
 | 
					                if(strcmp(furi_string_get_cstr(preset->name), "") != 0) {
 | 
				
			||||||
 | 
					                    subghz_txrx_begin(
 | 
				
			||||||
 | 
					                        instance,
 | 
				
			||||||
 | 
					                        subghz_setting_get_preset_data_by_name(
 | 
				
			||||||
 | 
					                            instance->setting, furi_string_get_cstr(preset->name)));
 | 
				
			||||||
 | 
					                    if(preset->frequency) {
 | 
				
			||||||
 | 
					                        if(!subghz_txrx_tx(instance, preset->frequency)) {
 | 
				
			||||||
 | 
					                            FURI_LOG_E(TAG, "Only Rx");
 | 
				
			||||||
 | 
					                            ret = SubGhzTxRxStartTxStateErrorOnlyRx;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        ret = SubGhzTxRxStartTxStateErrorParserOthers;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    FURI_LOG_E(
 | 
				
			||||||
 | 
					                        TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name));
 | 
				
			||||||
 | 
					                    ret = SubGhzTxRxStartTxStateErrorParserOthers;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(ret == SubGhzTxRxStartTxStateOk) {
 | 
				
			||||||
 | 
					                    //Start TX
 | 
				
			||||||
 | 
					                    furi_hal_subghz_start_async_tx(
 | 
				
			||||||
 | 
					                        subghz_transmitter_yield, instance->transmitter);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ret = SubGhzTxRxStartTxStateErrorParserOthers;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ret = SubGhzTxRxStartTxStateErrorParserOthers;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(ret != SubGhzTxRxStartTxStateOk) {
 | 
				
			||||||
 | 
					            subghz_transmitter_free(instance->transmitter);
 | 
				
			||||||
 | 
					            if(instance->txrx_state != SubGhzTxRxStateIDLE) {
 | 
				
			||||||
 | 
					                subghz_txrx_idle(instance);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } while(false);
 | 
				
			||||||
 | 
					    furi_string_free(temp_str);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_rx_start(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    subghz_txrx_stop(instance);
 | 
				
			||||||
 | 
					    subghz_txrx_begin(
 | 
				
			||||||
 | 
					        instance,
 | 
				
			||||||
 | 
					        subghz_setting_get_preset_data_by_name(
 | 
				
			||||||
 | 
					            subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name)));
 | 
				
			||||||
 | 
					    subghz_txrx_rx(instance, instance->preset->frequency);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_set_need_save_callback(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    SubGhzTxRxNeedSaveCallback callback,
 | 
				
			||||||
 | 
					    void* context) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    instance->need_save_callback = callback;
 | 
				
			||||||
 | 
					    instance->need_save_context = context;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_assert(instance->txrx_state == SubGhzTxRxStateTx);
 | 
				
			||||||
 | 
					    //Stop TX
 | 
				
			||||||
 | 
					    furi_hal_subghz_stop_async_tx();
 | 
				
			||||||
 | 
					    subghz_transmitter_stop(instance->transmitter);
 | 
				
			||||||
 | 
					    subghz_transmitter_free(instance->transmitter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //if protocol dynamic then we save the last upload
 | 
				
			||||||
 | 
					    if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
 | 
				
			||||||
 | 
					        if(instance->need_save_callback) {
 | 
				
			||||||
 | 
					            instance->need_save_callback(instance->need_save_context);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    subghz_txrx_idle(instance);
 | 
				
			||||||
 | 
					    subghz_txrx_speaker_off(instance);
 | 
				
			||||||
 | 
					    //Todo: Show message
 | 
				
			||||||
 | 
					    // notification_message(notifications, &sequence_reset_red);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return instance->fff_data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return instance->setting;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_stop(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(instance->txrx_state) {
 | 
				
			||||||
 | 
					    case SubGhzTxRxStateTx:
 | 
				
			||||||
 | 
					        subghz_txrx_tx_stop(instance);
 | 
				
			||||||
 | 
					        subghz_txrx_speaker_unmute(instance);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case SubGhzTxRxStateRx:
 | 
				
			||||||
 | 
					        subghz_txrx_rx_end(instance);
 | 
				
			||||||
 | 
					        subghz_txrx_speaker_mute(instance);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(instance->hopper_state) {
 | 
				
			||||||
 | 
					    case SubGhzHopperStateOFF:
 | 
				
			||||||
 | 
					    case SubGhzHopperStatePause:
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    case SubGhzHopperStateRSSITimeOut:
 | 
				
			||||||
 | 
					        if(instance->hopper_timeout != 0) {
 | 
				
			||||||
 | 
					            instance->hopper_timeout--;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    float rssi = -127.0f;
 | 
				
			||||||
 | 
					    if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) {
 | 
				
			||||||
 | 
					        // See RSSI Calculation timings in CC1101 17.3 RSSI
 | 
				
			||||||
 | 
					        rssi = furi_hal_subghz_get_rssi();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Stay if RSSI is high enough
 | 
				
			||||||
 | 
					        if(rssi > -90.0f) {
 | 
				
			||||||
 | 
					            instance->hopper_timeout = 10;
 | 
				
			||||||
 | 
					            instance->hopper_state = SubGhzHopperStateRSSITimeOut;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        instance->hopper_state = SubGhzHopperStateRunnig;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Select next frequency
 | 
				
			||||||
 | 
					    if(instance->hopper_idx_frequency <
 | 
				
			||||||
 | 
					       subghz_setting_get_hopper_frequency_count(instance->setting) - 1) {
 | 
				
			||||||
 | 
					        instance->hopper_idx_frequency++;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        instance->hopper_idx_frequency = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(instance->txrx_state == SubGhzTxRxStateRx) {
 | 
				
			||||||
 | 
					        subghz_txrx_rx_end(instance);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if(instance->txrx_state == SubGhzTxRxStateIDLE) {
 | 
				
			||||||
 | 
					        subghz_receiver_reset(instance->receiver);
 | 
				
			||||||
 | 
					        instance->preset->frequency =
 | 
				
			||||||
 | 
					            subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency);
 | 
				
			||||||
 | 
					        subghz_txrx_rx(instance, instance->preset->frequency);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return instance->hopper_state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    instance->hopper_state = state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(instance->hopper_state == SubGhzHopperStatePause) {
 | 
				
			||||||
 | 
					        instance->hopper_state = SubGhzHopperStateRunnig;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(instance->hopper_state == SubGhzHopperStateRunnig) {
 | 
				
			||||||
 | 
					        instance->hopper_state = SubGhzHopperStatePause;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_on(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(instance->speaker_state == SubGhzSpeakerStateEnable) {
 | 
				
			||||||
 | 
					        if(furi_hal_speaker_acquire(30)) {
 | 
				
			||||||
 | 
					            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            instance->speaker_state = SubGhzSpeakerStateDisable;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_off(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(instance->speaker_state != SubGhzSpeakerStateDisable) {
 | 
				
			||||||
 | 
					        if(furi_hal_speaker_is_mine()) {
 | 
				
			||||||
 | 
					            furi_hal_subghz_set_async_mirror_pin(NULL);
 | 
				
			||||||
 | 
					            furi_hal_speaker_release();
 | 
				
			||||||
 | 
					            if(instance->speaker_state == SubGhzSpeakerStateShutdown)
 | 
				
			||||||
 | 
					                instance->speaker_state = SubGhzSpeakerStateDisable;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_mute(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(instance->speaker_state == SubGhzSpeakerStateEnable) {
 | 
				
			||||||
 | 
					        if(furi_hal_speaker_is_mine()) {
 | 
				
			||||||
 | 
					            furi_hal_subghz_set_async_mirror_pin(NULL);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    if(instance->speaker_state == SubGhzSpeakerStateEnable) {
 | 
				
			||||||
 | 
					        if(furi_hal_speaker_is_mine()) {
 | 
				
			||||||
 | 
					            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    instance->speaker_state = state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return instance->speaker_state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    furi_assert(name_protocol);
 | 
				
			||||||
 | 
					    bool res = false;
 | 
				
			||||||
 | 
					    instance->decoder_result =
 | 
				
			||||||
 | 
					        subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol);
 | 
				
			||||||
 | 
					    if(instance->decoder_result) {
 | 
				
			||||||
 | 
					        res = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return instance->decoder_result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
 | 
				
			||||||
 | 
					        SubGhzProtocolFlag_Save);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    const SubGhzProtocol* protocol = instance->decoder_result->protocol;
 | 
				
			||||||
 | 
					    if(check_type) {
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
 | 
				
			||||||
 | 
					            protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
 | 
				
			||||||
 | 
					        protocol->encoder->deserialize);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    subghz_receiver_set_filter(instance->receiver, filter);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_set_rx_calback(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    SubGhzReceiverCallback callback,
 | 
				
			||||||
 | 
					    void* context) {
 | 
				
			||||||
 | 
					    subghz_receiver_set_rx_callback(instance->receiver, callback, context);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_txrx_set_raw_file_encoder_worker_callback_end(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    SubGhzProtocolEncoderRAWCallbackEnd callback,
 | 
				
			||||||
 | 
					    void* context) {
 | 
				
			||||||
 | 
					    subghz_protocol_raw_file_encoder_worker_set_callback_end(
 | 
				
			||||||
 | 
					        (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter),
 | 
				
			||||||
 | 
					        callback,
 | 
				
			||||||
 | 
					        context);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										290
									
								
								applications/main/subghz/helpers/subghz_txrx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								applications/main/subghz/helpers/subghz_txrx.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,290 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "subghz_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <lib/subghz/subghz_worker.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/subghz_setting.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/receiver.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/transmitter.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/raw.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct SubGhzTxRx SubGhzTxRx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void (*SubGhzTxRxNeedSaveCallback)(void* context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    SubGhzTxRxStartTxStateOk,
 | 
				
			||||||
 | 
					    SubGhzTxRxStartTxStateErrorOnlyRx,
 | 
				
			||||||
 | 
					    SubGhzTxRxStartTxStateErrorParserOthers,
 | 
				
			||||||
 | 
					} SubGhzTxRxStartTxState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Allocate SubGhzTxRx
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @return SubGhzTxRx* pointer to SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzTxRx* subghz_txrx_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Free SubGhzTxRx
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_free(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Check if the database is loaded
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @return bool True if the database is loaded
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set preset 
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param preset_name Name of preset
 | 
				
			||||||
 | 
					 * @param frequency Frequency in Hz
 | 
				
			||||||
 | 
					 * @param preset_data Data of preset
 | 
				
			||||||
 | 
					 * @param preset_data_size Size of preset data
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_set_preset(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* preset_name,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    uint8_t* preset_data,
 | 
				
			||||||
 | 
					    size_t preset_data_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get name of preset
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param preset String of preset 
 | 
				
			||||||
 | 
					 * @return const char*  Name of preset
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get of preset
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @return SubGhzRadioPreset Preset
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get string frequency and modulation
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param frequency Pointer to a string frequency
 | 
				
			||||||
 | 
					 * @param modulation Pointer to a string modulation
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_get_frequency_and_modulation(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    FuriString* frequency,
 | 
				
			||||||
 | 
					    FuriString* modulation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Start TX CC1101
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param flipper_format Pointer to a FlipperFormat
 | 
				
			||||||
 | 
					 * @return SubGhzTxRxStartTxState 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Start RX CC1101
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_rx_start(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Stop TX/RX CC1101
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_stop(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set sleep mode CC1101
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_sleep(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Update frequency CC1101 in automatic mode (hopper)
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_update(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get state hopper
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @return SubGhzHopperState 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set state hopper
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param state State hopper
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Unpause hopper
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_unpause(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set pause hopper
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Speaker on
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_on(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Speaker off
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_off(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Speaker mute
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_mute(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Speaker unmute
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_unmute(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set state speaker
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 * @param state State speaker
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get state speaker
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 * @return SubGhzSpeakerState 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * load decoder by name protocol
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param name_protocol Name protocol
 | 
				
			||||||
 | 
					 * @return bool True if the decoder is loaded 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get decoder
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set callback for save data
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param callback Callback for save data
 | 
				
			||||||
 | 
					 * @param context Context for callback
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_set_need_save_callback(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    SubGhzTxRxNeedSaveCallback callback,
 | 
				
			||||||
 | 
					    void* context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get pointer to a load data key
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @return FlipperFormat* 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get pointer to a SugGhzSetting
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @return SubGhzSetting* 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Is it possible to save this protocol
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 * @return bool True if it is possible to save this protocol
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Is it possible to send this protocol
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx 
 | 
				
			||||||
 | 
					 * @return bool True if it is possible to send this protocol
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set filter, what types of decoder to use 
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param filter Filter
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set callback for receive data
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param callback Callback for receive data
 | 
				
			||||||
 | 
					 * @param context Context for callback
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_set_rx_calback(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    SubGhzReceiverCallback callback,
 | 
				
			||||||
 | 
					    void* context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set callback for Raw decoder, end of data transfer  
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param callback Callback for Raw decoder, end of data transfer 
 | 
				
			||||||
 | 
					 * @param context Context for callback
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void subghz_txrx_set_raw_file_encoder_worker_callback_end(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    SubGhzProtocolEncoderRAWCallbackEnd callback,
 | 
				
			||||||
 | 
					    void* context);
 | 
				
			||||||
@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					#include "subghz_txrx_i.h"
 | 
				
			||||||
 | 
					#include "subghz_txrx_create_potocol_key.h"
 | 
				
			||||||
 | 
					#include <lib/subghz/transmitter.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/protocol_items.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/protocol_items.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/keeloq.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/secplus_v1.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/secplus_v2.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <flipper_format/flipper_format_i.h>
 | 
				
			||||||
 | 
					#include <lib/toolbox/stream/stream.h>
 | 
				
			||||||
 | 
					#include <lib/subghz/protocols/raw.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TAG "SubGhzCreateProtocolKey"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_data_protocol(
 | 
				
			||||||
 | 
					    void* context,
 | 
				
			||||||
 | 
					    const char* preset_name,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    const char* protocol_name,
 | 
				
			||||||
 | 
					    uint64_t key,
 | 
				
			||||||
 | 
					    uint32_t bit) {
 | 
				
			||||||
 | 
					    furi_assert(context);
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool res = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0);
 | 
				
			||||||
 | 
					    instance->decoder_result =
 | 
				
			||||||
 | 
					        subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(instance->decoder_result == NULL) {
 | 
				
			||||||
 | 
					        //TODO: Error
 | 
				
			||||||
 | 
					        // furi_string_set(error_str, "Protocol not\nfound!");
 | 
				
			||||||
 | 
					        // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub);
 | 
				
			||||||
 | 
					        FURI_LOG_E(TAG, "Protocol not found!");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data);
 | 
				
			||||||
 | 
					        stream_clean(fff_data_stream);
 | 
				
			||||||
 | 
					        if(subghz_protocol_decoder_base_serialize(
 | 
				
			||||||
 | 
					               instance->decoder_result, instance->fff_data, instance->preset) !=
 | 
				
			||||||
 | 
					           SubGhzProtocolStatusOk) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "Unable to serialize");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "Unable to update Bit");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t key_data[sizeof(uint64_t)] = {0};
 | 
				
			||||||
 | 
					        for(size_t i = 0; i < sizeof(uint64_t); i++) {
 | 
				
			||||||
 | 
					            key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "Unable to update Key");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        res = true;
 | 
				
			||||||
 | 
					    } while(false);
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_data_protocol_and_te(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* preset_name,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    const char* protocol_name,
 | 
				
			||||||
 | 
					    uint64_t key,
 | 
				
			||||||
 | 
					    uint32_t bit,
 | 
				
			||||||
 | 
					    uint32_t te) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    bool ret = false;
 | 
				
			||||||
 | 
					    if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) {
 | 
				
			||||||
 | 
					        if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "Unable to update Te");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ret = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_keelog_protocol(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* name_preset,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    const char* name_sysmem,
 | 
				
			||||||
 | 
					    uint32_t serial,
 | 
				
			||||||
 | 
					    uint8_t btn,
 | 
				
			||||||
 | 
					    uint16_t cnt) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool ret = false;
 | 
				
			||||||
 | 
					    serial &= 0x0FFFFFFF;
 | 
				
			||||||
 | 
					    instance->transmitter =
 | 
				
			||||||
 | 
					        subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
 | 
				
			||||||
 | 
					    subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0);
 | 
				
			||||||
 | 
					    if(instance->transmitter) {
 | 
				
			||||||
 | 
					        subghz_protocol_keeloq_create_data(
 | 
				
			||||||
 | 
					            subghz_transmitter_get_protocol_instance(instance->transmitter),
 | 
				
			||||||
 | 
					            instance->fff_data,
 | 
				
			||||||
 | 
					            serial,
 | 
				
			||||||
 | 
					            btn,
 | 
				
			||||||
 | 
					            cnt,
 | 
				
			||||||
 | 
					            name_sysmem,
 | 
				
			||||||
 | 
					            instance->preset);
 | 
				
			||||||
 | 
					        ret = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    subghz_transmitter_free(instance->transmitter);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_secplus_v2_protocol(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* name_preset,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    uint32_t serial,
 | 
				
			||||||
 | 
					    uint8_t btn,
 | 
				
			||||||
 | 
					    uint32_t cnt) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool ret = false;
 | 
				
			||||||
 | 
					    instance->transmitter =
 | 
				
			||||||
 | 
					        subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
 | 
				
			||||||
 | 
					    subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0);
 | 
				
			||||||
 | 
					    if(instance->transmitter) {
 | 
				
			||||||
 | 
					        subghz_protocol_secplus_v2_create_data(
 | 
				
			||||||
 | 
					            subghz_transmitter_get_protocol_instance(instance->transmitter),
 | 
				
			||||||
 | 
					            instance->fff_data,
 | 
				
			||||||
 | 
					            serial,
 | 
				
			||||||
 | 
					            btn,
 | 
				
			||||||
 | 
					            cnt,
 | 
				
			||||||
 | 
					            instance->preset);
 | 
				
			||||||
 | 
					        ret = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_secplus_v1_protocol(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* name_preset,
 | 
				
			||||||
 | 
					    uint32_t frequency) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool ret = false;
 | 
				
			||||||
 | 
					    uint32_t serial = (uint32_t)rand();
 | 
				
			||||||
 | 
					    while(!subghz_protocol_secplus_v1_check_fixed(serial)) {
 | 
				
			||||||
 | 
					        serial = (uint32_t)rand();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(subghz_txrx_gen_data_protocol(
 | 
				
			||||||
 | 
					           instance,
 | 
				
			||||||
 | 
					           name_preset,
 | 
				
			||||||
 | 
					           frequency,
 | 
				
			||||||
 | 
					           SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
 | 
				
			||||||
 | 
					           (uint64_t)serial << 32 | 0xE6000000,
 | 
				
			||||||
 | 
					           42)) {
 | 
				
			||||||
 | 
					        ret = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include "subghz_types.h"
 | 
				
			||||||
 | 
					#include "subghz_txrx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generate data for protocol
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param preset_name Name of preset
 | 
				
			||||||
 | 
					 * @param frequency Frequency in Hz
 | 
				
			||||||
 | 
					 * @param protocol_name Name of protocol
 | 
				
			||||||
 | 
					 * @param key Key
 | 
				
			||||||
 | 
					 * @param bit Bit
 | 
				
			||||||
 | 
					 * @return bool True if success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_data_protocol(
 | 
				
			||||||
 | 
					    void* context,
 | 
				
			||||||
 | 
					    const char* preset_name,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    const char* protocol_name,
 | 
				
			||||||
 | 
					    uint64_t key,
 | 
				
			||||||
 | 
					    uint32_t bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generate data for protocol and te
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param preset_name Name of preset
 | 
				
			||||||
 | 
					 * @param frequency Frequency in Hz
 | 
				
			||||||
 | 
					 * @param protocol_name Name of protocol
 | 
				
			||||||
 | 
					 * @param key Key
 | 
				
			||||||
 | 
					 * @param bit Bit
 | 
				
			||||||
 | 
					 * @param te Te
 | 
				
			||||||
 | 
					 * @return bool True if success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_data_protocol_and_te(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* preset_name,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    const char* protocol_name,
 | 
				
			||||||
 | 
					    uint64_t key,
 | 
				
			||||||
 | 
					    uint32_t bit,
 | 
				
			||||||
 | 
					    uint32_t te);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generate data Keeloq protocol
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param name_preset Name of preset
 | 
				
			||||||
 | 
					 * @param frequency Frequency in Hz
 | 
				
			||||||
 | 
					 * @param name_sysmem Name of Keeloq sysmem
 | 
				
			||||||
 | 
					 * @param serial Serial number
 | 
				
			||||||
 | 
					 * @param btn Button
 | 
				
			||||||
 | 
					 * @param cnt Counter
 | 
				
			||||||
 | 
					 * @return bool True if success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_keelog_protocol(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* name_preset,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    const char* name_sysmem,
 | 
				
			||||||
 | 
					    uint32_t serial,
 | 
				
			||||||
 | 
					    uint8_t btn,
 | 
				
			||||||
 | 
					    uint16_t cnt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generate data SecPlus v2 protocol
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param name_preset Name of preset
 | 
				
			||||||
 | 
					 * @param frequency Frequency in Hz
 | 
				
			||||||
 | 
					 * @param serial Serial number
 | 
				
			||||||
 | 
					 * @param btn Button
 | 
				
			||||||
 | 
					 * @param cnt Counter
 | 
				
			||||||
 | 
					 * @return bool True if success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_secplus_v2_protocol(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* name_preset,
 | 
				
			||||||
 | 
					    uint32_t frequency,
 | 
				
			||||||
 | 
					    uint32_t serial,
 | 
				
			||||||
 | 
					    uint8_t btn,
 | 
				
			||||||
 | 
					    uint32_t cnt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generate data SecPlus v1 protocol
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param instance Pointer to a SubGhzTxRx
 | 
				
			||||||
 | 
					 * @param name_preset Name of preset
 | 
				
			||||||
 | 
					 * @param frequency Frequency in Hz
 | 
				
			||||||
 | 
					 * @return bool True if success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool subghz_txrx_gen_secplus_v1_protocol(
 | 
				
			||||||
 | 
					    SubGhzTxRx* instance,
 | 
				
			||||||
 | 
					    const char* name_preset,
 | 
				
			||||||
 | 
					    uint32_t frequency);
 | 
				
			||||||
							
								
								
									
										27
									
								
								applications/main/subghz/helpers/subghz_txrx_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								applications/main/subghz/helpers/subghz_txrx_i.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "subghz_txrx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SubGhzTxRx {
 | 
				
			||||||
 | 
					    SubGhzWorker* worker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SubGhzEnvironment* environment;
 | 
				
			||||||
 | 
					    SubGhzReceiver* receiver;
 | 
				
			||||||
 | 
					    SubGhzTransmitter* transmitter;
 | 
				
			||||||
 | 
					    SubGhzProtocolDecoderBase* decoder_result;
 | 
				
			||||||
 | 
					    FlipperFormat* fff_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SubGhzRadioPreset* preset;
 | 
				
			||||||
 | 
					    SubGhzSetting* setting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t hopper_timeout;
 | 
				
			||||||
 | 
					    uint8_t hopper_idx_frequency;
 | 
				
			||||||
 | 
					    bool is_database_loaded;
 | 
				
			||||||
 | 
					    SubGhzHopperState hopper_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SubGhzTxRxState txrx_state;
 | 
				
			||||||
 | 
					    SubGhzSpeakerState speaker_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SubGhzTxRxNeedSaveCallback need_save_callback;
 | 
				
			||||||
 | 
					    void* need_save_context;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -77,3 +77,10 @@ typedef enum {
 | 
				
			|||||||
    SubGhzViewIdTestCarrier,
 | 
					    SubGhzViewIdTestCarrier,
 | 
				
			||||||
    SubGhzViewIdTestPacket,
 | 
					    SubGhzViewIdTestPacket,
 | 
				
			||||||
} SubGhzViewId;
 | 
					} SubGhzViewId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** SubGhz load type file */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    SubGhzLoadTypeFileNoLoad,
 | 
				
			||||||
 | 
					    SubGhzLoadTypeFileKey,
 | 
				
			||||||
 | 
					    SubGhzLoadTypeFileRaw,
 | 
				
			||||||
 | 
					} SubGhzLoadTypeFile;
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ void subghz_scene_delete_on_enter(void* context) {
 | 
				
			|||||||
    modulation_str = furi_string_alloc();
 | 
					    modulation_str = furi_string_alloc();
 | 
				
			||||||
    text = furi_string_alloc();
 | 
					    text = furi_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
 | 
					    subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
 | 
				
			||||||
    widget_add_string_element(
 | 
					    widget_add_string_element(
 | 
				
			||||||
        subghz->widget,
 | 
					        subghz->widget,
 | 
				
			||||||
        78,
 | 
					        78,
 | 
				
			||||||
@ -37,7 +37,7 @@ void subghz_scene_delete_on_enter(void* context) {
 | 
				
			|||||||
        AlignTop,
 | 
					        AlignTop,
 | 
				
			||||||
        FontSecondary,
 | 
					        FontSecondary,
 | 
				
			||||||
        furi_string_get_cstr(modulation_str));
 | 
					        furi_string_get_cstr(modulation_str));
 | 
				
			||||||
    subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
 | 
					    subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text);
 | 
				
			||||||
    widget_add_string_multiline_element(
 | 
					    widget_add_string_multiline_element(
 | 
				
			||||||
        subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
 | 
					        subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ void subghz_scene_delete_raw_on_enter(void* context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    widget_add_string_element(
 | 
					    widget_add_string_element(
 | 
				
			||||||
        subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
 | 
					        subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
 | 
				
			||||||
    subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
 | 
					    subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
 | 
				
			||||||
    widget_add_string_element(
 | 
					    widget_add_string_element(
 | 
				
			||||||
        subghz->widget,
 | 
					        subghz->widget,
 | 
				
			||||||
        35,
 | 
					        35,
 | 
				
			||||||
 | 
				
			|||||||
@ -37,27 +37,23 @@ void subghz_scene_need_saving_on_enter(void* context) {
 | 
				
			|||||||
bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
 | 
					bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeBack) {
 | 
					    if(event.type == SceneManagerEventTypeBack) {
 | 
				
			||||||
        subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
 | 
					        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
 | 
				
			||||||
        scene_manager_previous_scene(subghz->scene_manager);
 | 
					        scene_manager_previous_scene(subghz->scene_manager);
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    } else if(event.type == SceneManagerEventTypeCustom) {
 | 
					    } else if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        if(event.event == SubGhzCustomEventSceneStay) {
 | 
					        if(event.event == SubGhzCustomEventSceneStay) {
 | 
				
			||||||
            subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
 | 
					            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
 | 
				
			||||||
            scene_manager_previous_scene(subghz->scene_manager);
 | 
					            scene_manager_previous_scene(subghz->scene_manager);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventSceneExit) {
 | 
					        } else if(event.event == SubGhzCustomEventSceneExit) {
 | 
				
			||||||
            if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
 | 
					            SubGhzRxKeyState state = subghz_rx_key_state_get(subghz);
 | 
				
			||||||
                subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
 | 
				
			||||||
                subghz_preset_init(
 | 
					
 | 
				
			||||||
                    subghz,
 | 
					            if(state == SubGhzRxKeyStateExit) {
 | 
				
			||||||
                    "AM650",
 | 
					                subghz_set_default_preset(subghz);
 | 
				
			||||||
                    subghz_setting_get_default_frequency(subghz->setting),
 | 
					 | 
				
			||||||
                    NULL,
 | 
					 | 
				
			||||||
                    0);
 | 
					 | 
				
			||||||
                scene_manager_search_and_switch_to_previous_scene(
 | 
					                scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                    subghz->scene_manager, SubGhzSceneStart);
 | 
					                    subghz->scene_manager, SubGhzSceneStart);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					 | 
				
			||||||
                scene_manager_previous_scene(subghz->scene_manager);
 | 
					                scene_manager_previous_scene(subghz->scene_manager);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,11 +3,9 @@
 | 
				
			|||||||
#include <dolphin/dolphin.h>
 | 
					#include <dolphin/dolphin.h>
 | 
				
			||||||
#include <lib/subghz/protocols/raw.h>
 | 
					#include <lib/subghz/protocols/raw.h>
 | 
				
			||||||
#include <lib/toolbox/path.h>
 | 
					#include <lib/toolbox/path.h>
 | 
				
			||||||
#include <float_tools.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RAW_FILE_NAME "Raw_signal_"
 | 
					#define RAW_FILE_NAME "Raw_signal_"
 | 
				
			||||||
#define TAG "SubGhzSceneReadRAW"
 | 
					#define TAG "SubGhzSceneReadRAW"
 | 
				
			||||||
#define RAW_THRESHOLD_RSSI_LOW_COUNT 10
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
 | 
					bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
 | 
				
			||||||
    bool ret = false;
 | 
					    bool ret = false;
 | 
				
			||||||
@ -15,12 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
 | 
				
			|||||||
    FuriString* temp_str;
 | 
					    FuriString* temp_str;
 | 
				
			||||||
    temp_str = furi_string_alloc();
 | 
					    temp_str = furi_string_alloc();
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
        if(!flipper_format_rewind(subghz->txrx->fff_data)) {
 | 
					        FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx);
 | 
				
			||||||
 | 
					        if(!flipper_format_rewind(fff_data)) {
 | 
				
			||||||
            FURI_LOG_E(TAG, "Rewind error");
 | 
					            FURI_LOG_E(TAG, "Rewind error");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) {
 | 
					        if(!flipper_format_read_string(fff_data, "File_name", temp_str)) {
 | 
				
			||||||
            FURI_LOG_E(TAG, "Missing File_name");
 | 
					            FURI_LOG_E(TAG, "Missing File_name");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -38,13 +37,10 @@ static void subghz_scene_read_raw_update_statusbar(void* context) {
 | 
				
			|||||||
    furi_assert(context);
 | 
					    furi_assert(context);
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FuriString* frequency_str;
 | 
					    FuriString* frequency_str = furi_string_alloc();
 | 
				
			||||||
    FuriString* modulation_str;
 | 
					    FuriString* modulation_str = furi_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    frequency_str = furi_string_alloc();
 | 
					    subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
 | 
				
			||||||
    modulation_str = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
 | 
					 | 
				
			||||||
    subghz_read_raw_add_data_statusbar(
 | 
					    subghz_read_raw_add_data_statusbar(
 | 
				
			||||||
        subghz->subghz_read_raw,
 | 
					        subghz->subghz_read_raw,
 | 
				
			||||||
        furi_string_get_cstr(frequency_str),
 | 
					        furi_string_get_cstr(frequency_str),
 | 
				
			||||||
@ -69,13 +65,13 @@ void subghz_scene_read_raw_callback_end_tx(void* context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void subghz_scene_read_raw_on_enter(void* context) {
 | 
					void subghz_scene_read_raw_on_enter(void* context) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    FuriString* file_name;
 | 
					    FuriString* file_name = furi_string_alloc();
 | 
				
			||||||
    file_name = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch(subghz->txrx->rx_key_state) {
 | 
					    float threshold_rssi = subghz_threshold_rssi_get(subghz->threshold_rssi);
 | 
				
			||||||
 | 
					    switch(subghz_rx_key_state_get(subghz)) {
 | 
				
			||||||
    case SubGhzRxKeyStateBack:
 | 
					    case SubGhzRxKeyStateBack:
 | 
				
			||||||
        subghz_read_raw_set_status(
 | 
					        subghz_read_raw_set_status(
 | 
				
			||||||
            subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi);
 | 
					            subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", threshold_rssi);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case SubGhzRxKeyStateRAWLoad:
 | 
					    case SubGhzRxKeyStateRAWLoad:
 | 
				
			||||||
        path_extract_filename(subghz->file_path, file_name, true);
 | 
					        path_extract_filename(subghz->file_path, file_name, true);
 | 
				
			||||||
@ -83,8 +79,7 @@ void subghz_scene_read_raw_on_enter(void* context) {
 | 
				
			|||||||
            subghz->subghz_read_raw,
 | 
					            subghz->subghz_read_raw,
 | 
				
			||||||
            SubGhzReadRAWStatusLoadKeyTX,
 | 
					            SubGhzReadRAWStatusLoadKeyTX,
 | 
				
			||||||
            furi_string_get_cstr(file_name),
 | 
					            furi_string_get_cstr(file_name),
 | 
				
			||||||
            subghz->txrx->raw_threshold_rssi);
 | 
					            threshold_rssi);
 | 
				
			||||||
        subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case SubGhzRxKeyStateRAWSave:
 | 
					    case SubGhzRxKeyStateRAWSave:
 | 
				
			||||||
        path_extract_filename(subghz->file_path, file_name, true);
 | 
					        path_extract_filename(subghz->file_path, file_name, true);
 | 
				
			||||||
@ -92,66 +87,51 @@ void subghz_scene_read_raw_on_enter(void* context) {
 | 
				
			|||||||
            subghz->subghz_read_raw,
 | 
					            subghz->subghz_read_raw,
 | 
				
			||||||
            SubGhzReadRAWStatusSaveKey,
 | 
					            SubGhzReadRAWStatusSaveKey,
 | 
				
			||||||
            furi_string_get_cstr(file_name),
 | 
					            furi_string_get_cstr(file_name),
 | 
				
			||||||
            subghz->txrx->raw_threshold_rssi);
 | 
					            threshold_rssi);
 | 
				
			||||||
        subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        subghz_read_raw_set_status(
 | 
					        subghz_read_raw_set_status(
 | 
				
			||||||
            subghz->subghz_read_raw,
 | 
					            subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", threshold_rssi);
 | 
				
			||||||
            SubGhzReadRAWStatusStart,
 | 
					 | 
				
			||||||
            "",
 | 
					 | 
				
			||||||
            subghz->txrx->raw_threshold_rssi);
 | 
					 | 
				
			||||||
        subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) {
 | 
				
			||||||
 | 
					        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    furi_string_free(file_name);
 | 
					    furi_string_free(file_name);
 | 
				
			||||||
    subghz_scene_read_raw_update_statusbar(subghz);
 | 
					    subghz_scene_read_raw_update_statusbar(subghz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //set callback view raw
 | 
					    //set callback view raw
 | 
				
			||||||
    subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
 | 
					    subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
 | 
					    furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME));
 | 
				
			||||||
        subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME);
 | 
					 | 
				
			||||||
    furi_assert(subghz->txrx->decoder_result);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //set filter RAW feed
 | 
					    //set filter RAW feed
 | 
				
			||||||
    subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW);
 | 
					    subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW);
 | 
				
			||||||
    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
 | 
					    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
					bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    bool consumed = false;
 | 
					    bool consumed = false;
 | 
				
			||||||
 | 
					    SubGhzProtocolDecoderRAW* decoder_raw =
 | 
				
			||||||
 | 
					        (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx);
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
					    if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        switch(event.event) {
 | 
					        switch(event.event) {
 | 
				
			||||||
        case SubGhzCustomEventViewReadRAWBack:
 | 
					        case SubGhzCustomEventViewReadRAWBack:
 | 
				
			||||||
            //Stop TX
 | 
					
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					            subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
                subghz_tx_stop(subghz);
 | 
					 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            //Stop RX
 | 
					 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					 | 
				
			||||||
                subghz_rx_end(subghz);
 | 
					 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            //Stop save file
 | 
					            //Stop save file
 | 
				
			||||||
            subghz_protocol_raw_save_to_file_stop(
 | 
					            subghz_protocol_raw_save_to_file_stop(decoder_raw);
 | 
				
			||||||
                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
 | 
					 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            //needed save?
 | 
					            //needed save?
 | 
				
			||||||
            if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) ||
 | 
					            if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) ||
 | 
				
			||||||
               (subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) {
 | 
					               (subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateBack)) {
 | 
				
			||||||
                subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
 | 
					                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit);
 | 
				
			||||||
                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
 | 
					                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                //Restore default setting
 | 
					                //Restore default setting
 | 
				
			||||||
                subghz_preset_init(
 | 
					                subghz_set_default_preset(subghz);
 | 
				
			||||||
                    subghz,
 | 
					 | 
				
			||||||
                    "AM650",
 | 
					 | 
				
			||||||
                    subghz_setting_get_default_frequency(subghz->setting),
 | 
					 | 
				
			||||||
                    NULL,
 | 
					 | 
				
			||||||
                    0);
 | 
					 | 
				
			||||||
                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
					                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                       subghz->scene_manager, SubGhzSceneSaved)) {
 | 
					                       subghz->scene_manager, SubGhzSceneSaved)) {
 | 
				
			||||||
                    if(!scene_manager_search_and_switch_to_previous_scene(
 | 
					                    if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
@ -165,16 +145,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case SubGhzCustomEventViewReadRAWTXRXStop:
 | 
					        case SubGhzCustomEventViewReadRAWTXRXStop:
 | 
				
			||||||
            //Stop TX
 | 
					            subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					 | 
				
			||||||
                subghz_tx_stop(subghz);
 | 
					 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            //Stop RX
 | 
					 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					 | 
				
			||||||
                subghz_rx_end(subghz);
 | 
					 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -187,13 +158,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case SubGhzCustomEventViewReadRAWErase:
 | 
					        case SubGhzCustomEventViewReadRAWErase:
 | 
				
			||||||
            if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
 | 
					            if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
 | 
				
			||||||
                if(subghz_scene_read_raw_update_filename(subghz)) {
 | 
					                if(subghz_scene_read_raw_update_filename(subghz)) {
 | 
				
			||||||
                    furi_string_set(subghz->file_path_tmp, subghz->file_path);
 | 
					                    furi_string_set(subghz->file_path_tmp, subghz->file_path);
 | 
				
			||||||
                    subghz_delete_file(subghz);
 | 
					                    subghz_delete_file(subghz);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
 | 
				
			||||||
            notification_message(subghz->notifications, &sequence_reset_rgb);
 | 
					            notification_message(subghz->notifications, &sequence_reset_rgb);
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -203,7 +174,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
                if(subghz_scene_read_raw_update_filename(subghz)) {
 | 
					                if(subghz_scene_read_raw_update_filename(subghz)) {
 | 
				
			||||||
                    scene_manager_set_scene_state(
 | 
					                    scene_manager_set_scene_state(
 | 
				
			||||||
                        subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
 | 
					                        subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
 | 
				
			||||||
                    subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
 | 
					                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
 | 
				
			||||||
                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
 | 
					                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
 | 
				
			||||||
                    consumed = true;
 | 
					                    consumed = true;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
@ -223,34 +194,23 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
 | 
					            if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
 | 
				
			||||||
                //start send
 | 
					                //start send
 | 
				
			||||||
                subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					                subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
                if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					                if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
 | 
				
			||||||
                    subghz_rx_end(subghz);
 | 
					                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
 | 
					 | 
				
			||||||
                   (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
 | 
					 | 
				
			||||||
                    if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
 | 
					 | 
				
			||||||
                        subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
 | 
					 | 
				
			||||||
                    subghz_read_raw_set_status(
 | 
					                    subghz_read_raw_set_status(
 | 
				
			||||||
                        subghz->subghz_read_raw,
 | 
					                        subghz->subghz_read_raw,
 | 
				
			||||||
                        SubGhzReadRAWStatusIDLE,
 | 
					                        SubGhzReadRAWStatusIDLE,
 | 
				
			||||||
                        "",
 | 
					                        "",
 | 
				
			||||||
                            subghz->txrx->raw_threshold_rssi);
 | 
					                        subghz_threshold_rssi_get(subghz->threshold_rssi));
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                        if(scene_manager_has_previous_scene(
 | 
					                    if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) ||
 | 
				
			||||||
                               subghz->scene_manager, SubGhzSceneSaved) ||
 | 
					                       !scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) {
 | 
				
			||||||
                           !scene_manager_has_previous_scene(
 | 
					 | 
				
			||||||
                               subghz->scene_manager, SubGhzSceneStart)) {
 | 
					 | 
				
			||||||
                        DOLPHIN_DEED(DolphinDeedSubGhzSend);
 | 
					                        DOLPHIN_DEED(DolphinDeedSubGhzSend);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // set callback end tx
 | 
					                    // set callback end tx
 | 
				
			||||||
                        subghz_protocol_raw_file_encoder_worker_set_callback_end(
 | 
					                    subghz_txrx_set_raw_file_encoder_worker_callback_end(
 | 
				
			||||||
                            (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(
 | 
					                        subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz);
 | 
				
			||||||
                                subghz->txrx->transmitter),
 | 
					 | 
				
			||||||
                            subghz_scene_read_raw_callback_end_tx,
 | 
					 | 
				
			||||||
                            subghz);
 | 
					 | 
				
			||||||
                    subghz->state_notifications = SubGhzNotificationStateTx;
 | 
					                    subghz->state_notifications = SubGhzNotificationStateTx;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
					                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                       subghz->scene_manager, SubGhzSceneStart)) {
 | 
					                       subghz->scene_manager, SubGhzSceneStart)) {
 | 
				
			||||||
@ -263,33 +223,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        case SubGhzCustomEventViewReadRAWSendStop:
 | 
					        case SubGhzCustomEventViewReadRAWSendStop:
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					            subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
                subghz_speaker_unmute(subghz);
 | 
					 | 
				
			||||||
                subghz_tx_stop(subghz);
 | 
					 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            subghz_read_raw_stop_send(subghz->subghz_read_raw);
 | 
					            subghz_read_raw_stop_send(subghz->subghz_read_raw);
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case SubGhzCustomEventViewReadRAWIDLE:
 | 
					        case SubGhzCustomEventViewReadRAWIDLE:
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					            subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
                subghz_rx_end(subghz);
 | 
					            size_t spl_count = subghz_protocol_raw_get_sample_write(decoder_raw);
 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            size_t spl_count = subghz_protocol_raw_get_sample_write(
 | 
					            subghz_protocol_raw_save_to_file_stop(decoder_raw);
 | 
				
			||||||
                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            subghz_protocol_raw_save_to_file_stop(
 | 
					            FuriString* temp_str = furi_string_alloc();
 | 
				
			||||||
                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            FuriString* temp_str;
 | 
					 | 
				
			||||||
            temp_str = furi_string_alloc();
 | 
					 | 
				
			||||||
            furi_string_printf(
 | 
					            furi_string_printf(
 | 
				
			||||||
                temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
 | 
					                temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
 | 
				
			||||||
            subghz_protocol_raw_gen_fff_data(
 | 
					            subghz_protocol_raw_gen_fff_data(
 | 
				
			||||||
                subghz->txrx->fff_data, furi_string_get_cstr(temp_str));
 | 
					                subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str));
 | 
				
			||||||
            furi_string_free(temp_str);
 | 
					            furi_string_free(temp_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(spl_count > 0) {
 | 
					            if(spl_count > 0) {
 | 
				
			||||||
@ -299,32 +248,21 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
 | 
					            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case SubGhzCustomEventViewReadRAWREC:
 | 
					        case SubGhzCustomEventViewReadRAWREC:
 | 
				
			||||||
            if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) {
 | 
					            if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) {
 | 
				
			||||||
                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
 | 
					                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT;
 | 
					                SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 | 
				
			||||||
                if(subghz_protocol_raw_save_to_file_init(
 | 
					                if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) {
 | 
				
			||||||
                       (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
 | 
					 | 
				
			||||||
                       RAW_FILE_NAME,
 | 
					 | 
				
			||||||
                       subghz->txrx->preset)) {
 | 
					 | 
				
			||||||
                    DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
 | 
					                    DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
 | 
				
			||||||
                    if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
 | 
					                    subghz_txrx_rx_start(subghz->txrx);
 | 
				
			||||||
                       (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
 | 
					 | 
				
			||||||
                        subghz_begin(
 | 
					 | 
				
			||||||
                            subghz,
 | 
					 | 
				
			||||||
                            subghz_setting_get_preset_data_by_name(
 | 
					 | 
				
			||||||
                                subghz->setting,
 | 
					 | 
				
			||||||
                                furi_string_get_cstr(subghz->txrx->preset->name)));
 | 
					 | 
				
			||||||
                        subghz_rx(subghz, subghz->txrx->preset->frequency);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    subghz->state_notifications = SubGhzNotificationStateRx;
 | 
					                    subghz->state_notifications = SubGhzNotificationStateRx;
 | 
				
			||||||
                    subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
 | 
					                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    furi_string_set(subghz->error_str, "Function requires\nan SD card.");
 | 
					                    furi_string_set(subghz->error_str, "Function requires\nan SD card.");
 | 
				
			||||||
                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
 | 
					                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
 | 
				
			||||||
@ -337,7 +275,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
 | 
					            if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
 | 
				
			||||||
                scene_manager_set_scene_state(
 | 
					                scene_manager_set_scene_state(
 | 
				
			||||||
                    subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
 | 
					                    subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
 | 
				
			||||||
                subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
 | 
					                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
 | 
				
			||||||
                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
 | 
					                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
					                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
@ -356,41 +294,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
        switch(subghz->state_notifications) {
 | 
					        switch(subghz->state_notifications) {
 | 
				
			||||||
        case SubGhzNotificationStateRx:
 | 
					        case SubGhzNotificationStateRx:
 | 
				
			||||||
            notification_message(subghz->notifications, &sequence_blink_cyan_10);
 | 
					            notification_message(subghz->notifications, &sequence_blink_cyan_10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            subghz_read_raw_update_sample_write(
 | 
					            subghz_read_raw_update_sample_write(
 | 
				
			||||||
                subghz->subghz_read_raw,
 | 
					                subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw));
 | 
				
			||||||
                subghz_protocol_raw_get_sample_write(
 | 
					 | 
				
			||||||
                    (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            float rssi = furi_hal_subghz_get_rssi();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) {
 | 
					 | 
				
			||||||
                subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
 | 
					 | 
				
			||||||
                subghz_protocol_raw_save_to_file_pause(
 | 
					 | 
				
			||||||
                    (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                if(rssi < subghz->txrx->raw_threshold_rssi) {
 | 
					 | 
				
			||||||
                    subghz->txrx->raw_threshold_rssi_low_count++;
 | 
					 | 
				
			||||||
                    if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) {
 | 
					 | 
				
			||||||
                        subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    subghz->txrx->raw_threshold_rssi_low_count = 0;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) {
 | 
					 | 
				
			||||||
                    subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false);
 | 
					 | 
				
			||||||
                    subghz_protocol_raw_save_to_file_pause(
 | 
					 | 
				
			||||||
                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true);
 | 
					 | 
				
			||||||
                    subghz_speaker_mute(subghz);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
 | 
					 | 
				
			||||||
                    subghz_protocol_raw_save_to_file_pause(
 | 
					 | 
				
			||||||
                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
 | 
					 | 
				
			||||||
                    subghz_speaker_unmute(subghz);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            SubGhzThresholdRssiData ret_rssi =
 | 
				
			||||||
 | 
					                subghz_threshold_get_rssi_data(subghz->threshold_rssi);
 | 
				
			||||||
 | 
					            subghz_read_raw_add_data_rssi(
 | 
				
			||||||
 | 
					                subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above);
 | 
				
			||||||
 | 
					            subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubGhzNotificationStateTx:
 | 
					        case SubGhzNotificationStateTx:
 | 
				
			||||||
            notification_message(subghz->notifications, &sequence_blink_magenta_10);
 | 
					            notification_message(subghz->notifications, &sequence_blink_magenta_10);
 | 
				
			||||||
@ -407,13 +319,10 @@ void subghz_scene_read_raw_on_exit(void* context) {
 | 
				
			|||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Stop CC1101
 | 
					    //Stop CC1101
 | 
				
			||||||
    if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					    subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
        subghz_rx_end(subghz);
 | 
					 | 
				
			||||||
        subghz_sleep(subghz);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					    subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
    notification_message(subghz->notifications, &sequence_reset_rgb);
 | 
					    notification_message(subghz->notifications, &sequence_reset_rgb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //filter restoration
 | 
					    //filter restoration
 | 
				
			||||||
    subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
 | 
					    subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -35,16 +35,12 @@ static const NotificationSequence subghs_sequence_rx_locked = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void subghz_scene_receiver_update_statusbar(void* context) {
 | 
					static void subghz_scene_receiver_update_statusbar(void* context) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    FuriString* history_stat_str;
 | 
					    FuriString* history_stat_str = furi_string_alloc();
 | 
				
			||||||
    history_stat_str = furi_string_alloc();
 | 
					    if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) {
 | 
				
			||||||
    if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) {
 | 
					        FuriString* frequency_str = furi_string_alloc();
 | 
				
			||||||
        FuriString* frequency_str;
 | 
					        FuriString* modulation_str = furi_string_alloc();
 | 
				
			||||||
        FuriString* modulation_str;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        frequency_str = furi_string_alloc();
 | 
					        subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
 | 
				
			||||||
        modulation_str = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subghz_view_receiver_add_data_statusbar(
 | 
					        subghz_view_receiver_add_data_statusbar(
 | 
				
			||||||
            subghz->subghz_receiver,
 | 
					            subghz->subghz_receiver,
 | 
				
			||||||
@ -74,80 +70,68 @@ static void subghz_scene_add_to_history_callback(
 | 
				
			|||||||
    void* context) {
 | 
					    void* context) {
 | 
				
			||||||
    furi_assert(context);
 | 
					    furi_assert(context);
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    FuriString* str_buff;
 | 
					    SubGhzHistory* history = subghz->history;
 | 
				
			||||||
    str_buff = furi_string_alloc();
 | 
					    FuriString* str_buff = furi_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) {
 | 
					    SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(subghz_history_add_to_history(history, decoder_base, &preset)) {
 | 
				
			||||||
        furi_string_reset(str_buff);
 | 
					        furi_string_reset(str_buff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subghz->state_notifications = SubGhzNotificationStateRxDone;
 | 
					        subghz->state_notifications = SubGhzNotificationStateRxDone;
 | 
				
			||||||
 | 
					        uint16_t item_history = subghz_history_get_item(history);
 | 
				
			||||||
        subghz_history_get_text_item_menu(
 | 
					        subghz_history_get_text_item_menu(history, str_buff, item_history - 1);
 | 
				
			||||||
            subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
 | 
					 | 
				
			||||||
        subghz_view_receiver_add_item_to_menu(
 | 
					        subghz_view_receiver_add_item_to_menu(
 | 
				
			||||||
            subghz->subghz_receiver,
 | 
					            subghz->subghz_receiver,
 | 
				
			||||||
            furi_string_get_cstr(str_buff),
 | 
					            furi_string_get_cstr(str_buff),
 | 
				
			||||||
            subghz_history_get_type_protocol(
 | 
					            subghz_history_get_type_protocol(history, item_history - 1));
 | 
				
			||||||
                subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subghz_scene_receiver_update_statusbar(subghz);
 | 
					        subghz_scene_receiver_update_statusbar(subghz);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    subghz_receiver_reset(receiver);
 | 
					    subghz_receiver_reset(receiver);
 | 
				
			||||||
    furi_string_free(str_buff);
 | 
					    furi_string_free(str_buff);
 | 
				
			||||||
    subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
 | 
					    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_scene_receiver_on_enter(void* context) {
 | 
					void subghz_scene_receiver_on_enter(void* context) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					    SubGhzHistory* history = subghz->history;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FuriString* str_buff;
 | 
					    FuriString* str_buff;
 | 
				
			||||||
    str_buff = furi_string_alloc();
 | 
					    str_buff = furi_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
 | 
					    if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) {
 | 
				
			||||||
        subghz_preset_init(
 | 
					        subghz_set_default_preset(subghz);
 | 
				
			||||||
            subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
 | 
					        subghz_history_reset(history);
 | 
				
			||||||
        subghz_history_reset(subghz->txrx->history);
 | 
					        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart);
 | 
				
			||||||
        subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock);
 | 
					    subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Load history to receiver
 | 
					    //Load history to receiver
 | 
				
			||||||
    subghz_view_receiver_exit(subghz->subghz_receiver);
 | 
					    subghz_view_receiver_exit(subghz->subghz_receiver);
 | 
				
			||||||
    for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
 | 
					    for(uint8_t i = 0; i < subghz_history_get_item(history); i++) {
 | 
				
			||||||
        furi_string_reset(str_buff);
 | 
					        furi_string_reset(str_buff);
 | 
				
			||||||
        subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
 | 
					        subghz_history_get_text_item_menu(history, str_buff, i);
 | 
				
			||||||
        subghz_view_receiver_add_item_to_menu(
 | 
					        subghz_view_receiver_add_item_to_menu(
 | 
				
			||||||
            subghz->subghz_receiver,
 | 
					            subghz->subghz_receiver,
 | 
				
			||||||
            furi_string_get_cstr(str_buff),
 | 
					            furi_string_get_cstr(str_buff),
 | 
				
			||||||
            subghz_history_get_type_protocol(subghz->txrx->history, i));
 | 
					            subghz_history_get_type_protocol(history, i));
 | 
				
			||||||
        subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
 | 
					        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    furi_string_free(str_buff);
 | 
					    furi_string_free(str_buff);
 | 
				
			||||||
    subghz_scene_receiver_update_statusbar(subghz);
 | 
					    subghz_scene_receiver_update_statusbar(subghz);
 | 
				
			||||||
    subghz_view_receiver_set_callback(
 | 
					    subghz_view_receiver_set_callback(
 | 
				
			||||||
        subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
 | 
					        subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
 | 
				
			||||||
    subghz_receiver_set_rx_callback(
 | 
					    subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
 | 
				
			||||||
        subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz->state_notifications = SubGhzNotificationStateRx;
 | 
					    subghz->state_notifications = SubGhzNotificationStateRx;
 | 
				
			||||||
    if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					    subghz_txrx_rx_start(subghz->txrx);
 | 
				
			||||||
        subghz_rx_end(subghz);
 | 
					    subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen);
 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
 | 
					 | 
				
			||||||
       (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
 | 
					 | 
				
			||||||
        subghz_begin(
 | 
					 | 
				
			||||||
            subghz,
 | 
					 | 
				
			||||||
            subghz_setting_get_preset_data_by_name(
 | 
					 | 
				
			||||||
                subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
 | 
					 | 
				
			||||||
        subghz_rx(subghz, subghz->txrx->preset->frequency);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //to use a universal decoder, we are looking for a link to it
 | 
					    //to use a universal decoder, we are looking for a link to it
 | 
				
			||||||
    subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
 | 
					    furi_check(
 | 
				
			||||||
        subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME);
 | 
					        subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME));
 | 
				
			||||||
    furi_assert(subghz->txrx->decoder_result);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
 | 
					    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -160,41 +144,31 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
        case SubGhzCustomEventViewReceiverBack:
 | 
					        case SubGhzCustomEventViewReceiverBack:
 | 
				
			||||||
            // Stop CC1101 Rx
 | 
					            // Stop CC1101 Rx
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					            subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
                subghz_rx_end(subghz);
 | 
					            subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					            subghz->idx_menu_chosen = 0;
 | 
				
			||||||
            };
 | 
					            subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
 | 
				
			||||||
            subghz->txrx->hopper_state = SubGhzHopperStateOFF;
 | 
					 | 
				
			||||||
            subghz->txrx->idx_menu_chosen = 0;
 | 
					 | 
				
			||||||
            subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
 | 
					            if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
 | 
				
			||||||
                subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
 | 
					                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit);
 | 
				
			||||||
                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
 | 
					                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
 | 
				
			||||||
                subghz_preset_init(
 | 
					                subghz_set_default_preset(subghz);
 | 
				
			||||||
                    subghz,
 | 
					 | 
				
			||||||
                    "AM650",
 | 
					 | 
				
			||||||
                    subghz_setting_get_default_frequency(subghz->setting),
 | 
					 | 
				
			||||||
                    NULL,
 | 
					 | 
				
			||||||
                    0);
 | 
					 | 
				
			||||||
                scene_manager_search_and_switch_to_previous_scene(
 | 
					                scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                    subghz->scene_manager, SubGhzSceneStart);
 | 
					                    subghz->scene_manager, SubGhzSceneStart);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubGhzCustomEventViewReceiverOK:
 | 
					        case SubGhzCustomEventViewReceiverOK:
 | 
				
			||||||
            subghz->txrx->idx_menu_chosen =
 | 
					            subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
 | 
				
			||||||
                subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
 | 
					 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
 | 
					            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
 | 
				
			||||||
            DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
 | 
					            DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubGhzCustomEventViewReceiverConfig:
 | 
					        case SubGhzCustomEventViewReceiverConfig:
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            subghz->txrx->idx_menu_chosen =
 | 
					            subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
 | 
				
			||||||
                subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
 | 
					 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
 | 
					            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -203,30 +177,30 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubGhzCustomEventViewReceiverUnlock:
 | 
					        case SubGhzCustomEventViewReceiverUnlock:
 | 
				
			||||||
            subghz->lock = SubGhzLockOff;
 | 
					            subghz_unlock(subghz);
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if(event.type == SceneManagerEventTypeTick) {
 | 
					    } else if(event.type == SceneManagerEventTypeTick) {
 | 
				
			||||||
        if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
 | 
					        if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
 | 
				
			||||||
            subghz_hopper_update(subghz);
 | 
					            subghz_txrx_hopper_update(subghz->txrx);
 | 
				
			||||||
            subghz_scene_receiver_update_statusbar(subghz);
 | 
					            subghz_scene_receiver_update_statusbar(subghz);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //get RSSI
 | 
					        SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi);
 | 
				
			||||||
        float rssi = furi_hal_subghz_get_rssi();
 | 
					
 | 
				
			||||||
        subghz_receiver_rssi(subghz->subghz_receiver, rssi);
 | 
					        subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi);
 | 
				
			||||||
        subghz_protocol_decoder_bin_raw_data_input_rssi(
 | 
					        subghz_protocol_decoder_bin_raw_data_input_rssi(
 | 
				
			||||||
            (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi);
 | 
					            (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch(subghz->state_notifications) {
 | 
					        switch(subghz->state_notifications) {
 | 
				
			||||||
        case SubGhzNotificationStateRx:
 | 
					        case SubGhzNotificationStateRx:
 | 
				
			||||||
            notification_message(subghz->notifications, &sequence_blink_cyan_10);
 | 
					            notification_message(subghz->notifications, &sequence_blink_cyan_10);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubGhzNotificationStateRxDone:
 | 
					        case SubGhzNotificationStateRxDone:
 | 
				
			||||||
            if(subghz->lock != SubGhzLockOn) {
 | 
					            if(!subghz_is_locked(subghz)) {
 | 
				
			||||||
                notification_message(subghz->notifications, &subghs_sequence_rx);
 | 
					                notification_message(subghz->notifications, &subghs_sequence_rx);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                notification_message(subghz->notifications, &subghs_sequence_rx_locked);
 | 
					                notification_message(subghz->notifications, &subghs_sequence_rx_locked);
 | 
				
			||||||
 | 
				
			|||||||
@ -72,13 +72,15 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = {
 | 
				
			|||||||
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
 | 
					uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
 | 
				
			||||||
    furi_assert(context);
 | 
					    furi_assert(context);
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t index = 0;
 | 
					    uint8_t index = 0;
 | 
				
			||||||
    for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) {
 | 
					    for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) {
 | 
				
			||||||
        if(value == subghz_setting_get_frequency(subghz->setting, i)) {
 | 
					        if(value == subghz_setting_get_frequency(setting, i)) {
 | 
				
			||||||
            index = i;
 | 
					            index = i;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            index = subghz_setting_get_frequency_default_index(subghz->setting);
 | 
					            index = subghz_setting_get_frequency_default_index(setting);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return index;
 | 
					    return index;
 | 
				
			||||||
@ -87,13 +89,15 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void*
 | 
				
			|||||||
uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) {
 | 
					uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) {
 | 
				
			||||||
    furi_assert(context);
 | 
					    furi_assert(context);
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t index = 0;
 | 
					    uint8_t index = 0;
 | 
				
			||||||
    for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) {
 | 
					    for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) {
 | 
				
			||||||
        if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) {
 | 
					        if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) {
 | 
				
			||||||
            index = i;
 | 
					            index = i;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            //  index = subghz_setting_get_frequency_default_index(subghz->setting);
 | 
					            //  index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return index;
 | 
					    return index;
 | 
				
			||||||
@ -122,70 +126,84 @@ uint8_t subghz_scene_receiver_config_hopper_value_index(
 | 
				
			|||||||
static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
 | 
					static void subghz_scene_receiver_config_set_frequency(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);
 | 
				
			||||||
 | 
					    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) {
 | 
					    if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) {
 | 
				
			||||||
        char text_buf[10] = {0};
 | 
					        char text_buf[10] = {0};
 | 
				
			||||||
 | 
					        uint32_t frequency = subghz_setting_get_frequency(setting, index);
 | 
				
			||||||
 | 
					        SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        snprintf(
 | 
					        snprintf(
 | 
				
			||||||
            text_buf,
 | 
					            text_buf,
 | 
				
			||||||
            sizeof(text_buf),
 | 
					            sizeof(text_buf),
 | 
				
			||||||
            "%lu.%02lu",
 | 
					            "%lu.%02lu",
 | 
				
			||||||
            subghz_setting_get_frequency(subghz->setting, index) / 1000000,
 | 
					            frequency / 1000000,
 | 
				
			||||||
            (subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
 | 
					            (frequency % 1000000) / 10000);
 | 
				
			||||||
        variable_item_set_current_value_text(item, text_buf);
 | 
					        variable_item_set_current_value_text(item, text_buf);
 | 
				
			||||||
        subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index);
 | 
					        subghz_txrx_set_preset(
 | 
				
			||||||
 | 
					            subghz->txrx,
 | 
				
			||||||
 | 
					            furi_string_get_cstr(preset.name),
 | 
				
			||||||
 | 
					            frequency,
 | 
				
			||||||
 | 
					            preset.data,
 | 
				
			||||||
 | 
					            preset.data_size);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        variable_item_set_current_value_index(
 | 
					        variable_item_set_current_value_index(
 | 
				
			||||||
            item, subghz_setting_get_frequency_default_index(subghz->setting));
 | 
					            item, subghz_setting_get_frequency_default_index(setting));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
 | 
					static void subghz_scene_receiver_config_set_preset(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(
 | 
					    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
        item, subghz_setting_get_preset_name(subghz->setting, index));
 | 
					
 | 
				
			||||||
    subghz_preset_init(
 | 
					    variable_item_set_current_value_text(item, subghz_setting_get_preset_name(setting, index));
 | 
				
			||||||
        subghz,
 | 
					
 | 
				
			||||||
        subghz_setting_get_preset_name(subghz->setting, index),
 | 
					    SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 | 
				
			||||||
        subghz->txrx->preset->frequency,
 | 
					    subghz_txrx_set_preset(
 | 
				
			||||||
        subghz_setting_get_preset_data(subghz->setting, index),
 | 
					        subghz->txrx,
 | 
				
			||||||
        subghz_setting_get_preset_data_size(subghz->setting, index));
 | 
					        subghz_setting_get_preset_name(setting, index),
 | 
				
			||||||
 | 
					        preset.frequency,
 | 
				
			||||||
 | 
					        subghz_setting_get_preset_data(setting, index),
 | 
				
			||||||
 | 
					        subghz_setting_get_preset_data_size(setting, index));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
 | 
					static void subghz_scene_receiver_config_set_hopping_running(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);
 | 
				
			||||||
 | 
					    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
 | 
					    VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state(
 | 
				
			||||||
 | 
					        subghz->scene_manager, SubGhzSceneReceiverConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    variable_item_set_current_value_text(item, hopping_text[index]);
 | 
					    variable_item_set_current_value_text(item, hopping_text[index]);
 | 
				
			||||||
    if(hopping_value[index] == SubGhzHopperStateOFF) {
 | 
					    if(hopping_value[index] == SubGhzHopperStateOFF) {
 | 
				
			||||||
        char text_buf[10] = {0};
 | 
					        char text_buf[10] = {0};
 | 
				
			||||||
 | 
					        uint32_t frequency = subghz_setting_get_default_frequency(setting);
 | 
				
			||||||
 | 
					        SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        snprintf(
 | 
					        snprintf(
 | 
				
			||||||
            text_buf,
 | 
					            text_buf,
 | 
				
			||||||
            sizeof(text_buf),
 | 
					            sizeof(text_buf),
 | 
				
			||||||
            "%lu.%02lu",
 | 
					            "%lu.%02lu",
 | 
				
			||||||
            subghz_setting_get_default_frequency(subghz->setting) / 1000000,
 | 
					            frequency / 1000000,
 | 
				
			||||||
            (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000);
 | 
					            (frequency % 1000000) / 10000);
 | 
				
			||||||
        variable_item_set_current_value_text(
 | 
					        variable_item_set_current_value_text(frequency_item, text_buf);
 | 
				
			||||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
					
 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneReceiverConfig),
 | 
					        subghz_txrx_set_preset(
 | 
				
			||||||
            text_buf);
 | 
					            subghz->txrx,
 | 
				
			||||||
        subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting);
 | 
					            furi_string_get_cstr(preset.name),
 | 
				
			||||||
 | 
					            frequency,
 | 
				
			||||||
 | 
					            preset.data,
 | 
				
			||||||
 | 
					            preset.data_size);
 | 
				
			||||||
        variable_item_set_current_value_index(
 | 
					        variable_item_set_current_value_index(
 | 
				
			||||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
					            frequency_item, subghz_setting_get_frequency_default_index(setting));
 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneReceiverConfig),
 | 
					 | 
				
			||||||
            subghz_setting_get_frequency_default_index(subghz->setting));
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        variable_item_set_current_value_text(
 | 
					        variable_item_set_current_value_text(frequency_item, " -----");
 | 
				
			||||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
					 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneReceiverConfig),
 | 
					 | 
				
			||||||
            " -----");
 | 
					 | 
				
			||||||
        variable_item_set_current_value_index(
 | 
					        variable_item_set_current_value_index(
 | 
				
			||||||
            (VariableItem*)scene_manager_get_scene_state(
 | 
					            frequency_item, subghz_setting_get_frequency_default_index(setting));
 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneReceiverConfig),
 | 
					 | 
				
			||||||
            subghz_setting_get_frequency_default_index(subghz->setting));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz->txrx->hopper_state = hopping_value[index];
 | 
					    subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
 | 
					static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
 | 
				
			||||||
@ -193,7 +211,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* 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, speaker_text[index]);
 | 
					    variable_item_set_current_value_text(item, speaker_text[index]);
 | 
				
			||||||
    subghz->txrx->speaker_state = speaker_value[index];
 | 
					    subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
 | 
					static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
 | 
				
			||||||
@ -201,8 +219,8 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* 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, bin_raw_text[index]);
 | 
					    variable_item_set_current_value_text(item, bin_raw_text[index]);
 | 
				
			||||||
    subghz->txrx->filter = bin_raw_value[index];
 | 
					    subghz->filter = bin_raw_value[index];
 | 
				
			||||||
    subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
 | 
					    subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
 | 
					static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
 | 
				
			||||||
@ -210,7 +228,7 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it
 | 
				
			|||||||
    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, raw_theshold_rssi_text[index]);
 | 
					    variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]);
 | 
				
			||||||
    subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index];
 | 
					    subghz_threshold_rssi_set(subghz->threshold_rssi, raw_theshold_rssi_value[index]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
 | 
					static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
 | 
				
			||||||
@ -226,25 +244,27 @@ void subghz_scene_receiver_config_on_enter(void* context) {
 | 
				
			|||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    VariableItem* item;
 | 
					    VariableItem* item;
 | 
				
			||||||
    uint8_t value_index;
 | 
					    uint8_t value_index;
 | 
				
			||||||
 | 
					    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
 | 
					    SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    item = variable_item_list_add(
 | 
					    item = variable_item_list_add(
 | 
				
			||||||
        subghz->variable_item_list,
 | 
					        subghz->variable_item_list,
 | 
				
			||||||
        "Frequency:",
 | 
					        "Frequency:",
 | 
				
			||||||
        subghz_setting_get_frequency_count(subghz->setting),
 | 
					        subghz_setting_get_frequency_count(setting),
 | 
				
			||||||
        subghz_scene_receiver_config_set_frequency,
 | 
					        subghz_scene_receiver_config_set_frequency,
 | 
				
			||||||
        subghz);
 | 
					        subghz);
 | 
				
			||||||
    value_index =
 | 
					    value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz);
 | 
				
			||||||
        subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz);
 | 
					 | 
				
			||||||
    scene_manager_set_scene_state(
 | 
					    scene_manager_set_scene_state(
 | 
				
			||||||
        subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
 | 
					        subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
 | 
				
			||||||
    variable_item_set_current_value_index(item, value_index);
 | 
					    variable_item_set_current_value_index(item, value_index);
 | 
				
			||||||
    char text_buf[10] = {0};
 | 
					    char text_buf[10] = {0};
 | 
				
			||||||
 | 
					    uint32_t frequency = subghz_setting_get_frequency(setting, value_index);
 | 
				
			||||||
    snprintf(
 | 
					    snprintf(
 | 
				
			||||||
        text_buf,
 | 
					        text_buf,
 | 
				
			||||||
        sizeof(text_buf),
 | 
					        sizeof(text_buf),
 | 
				
			||||||
        "%lu.%02lu",
 | 
					        "%lu.%02lu",
 | 
				
			||||||
        subghz_setting_get_frequency(subghz->setting, value_index) / 1000000,
 | 
					        frequency / 1000000,
 | 
				
			||||||
        (subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000);
 | 
					        (frequency % 1000000) / 10000);
 | 
				
			||||||
    variable_item_set_current_value_text(item, text_buf);
 | 
					    variable_item_set_current_value_text(item, text_buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
 | 
					    if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
 | 
				
			||||||
@ -256,7 +276,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
 | 
				
			|||||||
            subghz_scene_receiver_config_set_hopping_running,
 | 
					            subghz_scene_receiver_config_set_hopping_running,
 | 
				
			||||||
            subghz);
 | 
					            subghz);
 | 
				
			||||||
        value_index = subghz_scene_receiver_config_hopper_value_index(
 | 
					        value_index = subghz_scene_receiver_config_hopper_value_index(
 | 
				
			||||||
            subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz);
 | 
					            subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz);
 | 
				
			||||||
        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_text[value_index]);
 | 
					        variable_item_set_current_value_text(item, hopping_text[value_index]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -264,14 +284,14 @@ void subghz_scene_receiver_config_on_enter(void* context) {
 | 
				
			|||||||
    item = variable_item_list_add(
 | 
					    item = variable_item_list_add(
 | 
				
			||||||
        subghz->variable_item_list,
 | 
					        subghz->variable_item_list,
 | 
				
			||||||
        "Modulation:",
 | 
					        "Modulation:",
 | 
				
			||||||
        subghz_setting_get_preset_count(subghz->setting),
 | 
					        subghz_setting_get_preset_count(setting),
 | 
				
			||||||
        subghz_scene_receiver_config_set_preset,
 | 
					        subghz_scene_receiver_config_set_preset,
 | 
				
			||||||
        subghz);
 | 
					        subghz);
 | 
				
			||||||
    value_index = subghz_scene_receiver_config_next_preset(
 | 
					    value_index =
 | 
				
			||||||
        furi_string_get_cstr(subghz->txrx->preset->name), subghz);
 | 
					        subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz);
 | 
				
			||||||
    variable_item_set_current_value_index(item, value_index);
 | 
					    variable_item_set_current_value_index(item, value_index);
 | 
				
			||||||
    variable_item_set_current_value_text(
 | 
					    variable_item_set_current_value_text(
 | 
				
			||||||
        item, subghz_setting_get_preset_name(subghz->setting, value_index));
 | 
					        item, subghz_setting_get_preset_name(setting, value_index));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
 | 
					    if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
 | 
				
			||||||
       SubGhzCustomEventManagerSet) {
 | 
					       SubGhzCustomEventManagerSet) {
 | 
				
			||||||
@ -281,7 +301,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
 | 
				
			|||||||
            BIN_RAW_COUNT,
 | 
					            BIN_RAW_COUNT,
 | 
				
			||||||
            subghz_scene_receiver_config_set_bin_raw,
 | 
					            subghz_scene_receiver_config_set_bin_raw,
 | 
				
			||||||
            subghz);
 | 
					            subghz);
 | 
				
			||||||
        value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT);
 | 
					        value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT);
 | 
				
			||||||
        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, bin_raw_text[value_index]);
 | 
					        variable_item_set_current_value_text(item, bin_raw_text[value_index]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -292,7 +312,8 @@ void subghz_scene_receiver_config_on_enter(void* context) {
 | 
				
			|||||||
        SPEAKER_COUNT,
 | 
					        SPEAKER_COUNT,
 | 
				
			||||||
        subghz_scene_receiver_config_set_speaker,
 | 
					        subghz_scene_receiver_config_set_speaker,
 | 
				
			||||||
        subghz);
 | 
					        subghz);
 | 
				
			||||||
    value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT);
 | 
					    value_index = value_index_uint32(
 | 
				
			||||||
 | 
					        subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT);
 | 
				
			||||||
    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, speaker_text[value_index]);
 | 
					    variable_item_set_current_value_text(item, speaker_text[value_index]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -313,7 +334,9 @@ void subghz_scene_receiver_config_on_enter(void* context) {
 | 
				
			|||||||
            subghz_scene_receiver_config_set_raw_threshold_rssi,
 | 
					            subghz_scene_receiver_config_set_raw_threshold_rssi,
 | 
				
			||||||
            subghz);
 | 
					            subghz);
 | 
				
			||||||
        value_index = value_index_float(
 | 
					        value_index = value_index_float(
 | 
				
			||||||
            subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT);
 | 
					            subghz_threshold_rssi_get(subghz->threshold_rssi),
 | 
				
			||||||
 | 
					            raw_theshold_rssi_value,
 | 
				
			||||||
 | 
					            RAW_THRESHOLD_RSSI_COUNT);
 | 
				
			||||||
        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, raw_theshold_rssi_text[value_index]);
 | 
					        variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -326,7 +349,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
					    if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        if(event.event == SubGhzCustomEventSceneSettingLock) {
 | 
					        if(event.event == SubGhzCustomEventSceneSettingLock) {
 | 
				
			||||||
            subghz->lock = SubGhzLockOn;
 | 
					            subghz_lock(subghz);
 | 
				
			||||||
            scene_manager_previous_scene(subghz->scene_manager);
 | 
					            scene_manager_previous_scene(subghz->scene_manager);
 | 
				
			||||||
            consumed = true;
 | 
					            consumed = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -19,20 +19,19 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static bool subghz_scene_receiver_info_update_parser(void* context) {
 | 
					static bool subghz_scene_receiver_info_update_parser(void* context) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
 | 
					 | 
				
			||||||
        subghz->txrx->receiver,
 | 
					 | 
				
			||||||
        subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(subghz->txrx->decoder_result) {
 | 
					    if(subghz_txrx_load_decoder_by_name_protocol(
 | 
				
			||||||
 | 
					           subghz->txrx,
 | 
				
			||||||
 | 
					           subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) {
 | 
				
			||||||
        //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
 | 
					        //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
 | 
				
			||||||
        subghz_protocol_decoder_base_deserialize(
 | 
					        subghz_protocol_decoder_base_deserialize(
 | 
				
			||||||
            subghz->txrx->decoder_result,
 | 
					            subghz_txrx_get_decoder(subghz->txrx),
 | 
				
			||||||
            subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
 | 
					            subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SubGhzRadioPreset* preset =
 | 
					        SubGhzRadioPreset* preset =
 | 
				
			||||||
            subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
 | 
					            subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen);
 | 
				
			||||||
        subghz_preset_init(
 | 
					        subghz_txrx_set_preset(
 | 
				
			||||||
            subghz,
 | 
					            subghz->txrx,
 | 
				
			||||||
            furi_string_get_cstr(preset->name),
 | 
					            furi_string_get_cstr(preset->name),
 | 
				
			||||||
            preset->frequency,
 | 
					            preset->frequency,
 | 
				
			||||||
            preset->data,
 | 
					            preset->data,
 | 
				
			||||||
@ -47,15 +46,11 @@ void subghz_scene_receiver_info_on_enter(void* context) {
 | 
				
			|||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(subghz_scene_receiver_info_update_parser(subghz)) {
 | 
					    if(subghz_scene_receiver_info_update_parser(subghz)) {
 | 
				
			||||||
        FuriString* frequency_str;
 | 
					        FuriString* frequency_str = furi_string_alloc();
 | 
				
			||||||
        FuriString* modulation_str;
 | 
					        FuriString* modulation_str = furi_string_alloc();
 | 
				
			||||||
        FuriString* text;
 | 
					        FuriString* text = furi_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        frequency_str = furi_string_alloc();
 | 
					        subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
 | 
				
			||||||
        modulation_str = furi_string_alloc();
 | 
					 | 
				
			||||||
        text = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
 | 
					 | 
				
			||||||
        widget_add_string_element(
 | 
					        widget_add_string_element(
 | 
				
			||||||
            subghz->widget,
 | 
					            subghz->widget,
 | 
				
			||||||
            78,
 | 
					            78,
 | 
				
			||||||
@ -73,7 +68,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
 | 
				
			|||||||
            AlignTop,
 | 
					            AlignTop,
 | 
				
			||||||
            FontSecondary,
 | 
					            FontSecondary,
 | 
				
			||||||
            furi_string_get_cstr(modulation_str));
 | 
					            furi_string_get_cstr(modulation_str));
 | 
				
			||||||
        subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
 | 
					        subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text);
 | 
				
			||||||
        widget_add_string_multiline_element(
 | 
					        widget_add_string_multiline_element(
 | 
				
			||||||
            subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
 | 
					            subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -81,8 +76,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
 | 
				
			|||||||
        furi_string_free(modulation_str);
 | 
					        furi_string_free(modulation_str);
 | 
				
			||||||
        furi_string_free(text);
 | 
					        furi_string_free(text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
 | 
					        if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
 | 
				
			||||||
           SubGhzProtocolFlag_Save) {
 | 
					 | 
				
			||||||
            widget_add_button_element(
 | 
					            widget_add_button_element(
 | 
				
			||||||
                subghz->widget,
 | 
					                subghz->widget,
 | 
				
			||||||
                GuiButtonTypeRight,
 | 
					                GuiButtonTypeRight,
 | 
				
			||||||
@ -90,10 +84,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
 | 
				
			|||||||
                subghz_scene_receiver_info_callback,
 | 
					                subghz_scene_receiver_info_callback,
 | 
				
			||||||
                subghz);
 | 
					                subghz);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
 | 
					        if(subghz_txrx_protocol_is_transmittable(subghz->txrx, true)) {
 | 
				
			||||||
            SubGhzProtocolFlag_Send) &&
 | 
					 | 
				
			||||||
           subghz->txrx->decoder_result->protocol->encoder->deserialize &&
 | 
					 | 
				
			||||||
           subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) {
 | 
					 | 
				
			||||||
            widget_add_button_element(
 | 
					            widget_add_button_element(
 | 
				
			||||||
                subghz->widget,
 | 
					                subghz->widget,
 | 
				
			||||||
                GuiButtonTypeCenter,
 | 
					                GuiButtonTypeCenter,
 | 
				
			||||||
@ -114,82 +105,49 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
 | 
				
			|||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
					    if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) {
 | 
					        if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) {
 | 
				
			||||||
            //CC1101 Stop RX -> Start TX
 | 
					 | 
				
			||||||
            if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
 | 
					 | 
				
			||||||
                subghz->txrx->hopper_state = SubGhzHopperStatePause;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					 | 
				
			||||||
                subghz_rx_end(subghz);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(!subghz_scene_receiver_info_update_parser(subghz)) {
 | 
					            if(!subghz_scene_receiver_info_update_parser(subghz)) {
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE ||
 | 
					            //CC1101 Stop RX -> Start TX
 | 
				
			||||||
               subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
 | 
					            subghz_txrx_hopper_pause(subghz->txrx);
 | 
				
			||||||
            if(!subghz_tx_start(
 | 
					            if(!subghz_tx_start(
 | 
				
			||||||
                   subghz,
 | 
					                   subghz,
 | 
				
			||||||
                       subghz_history_get_raw_data(
 | 
					                   subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) {
 | 
				
			||||||
                           subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
 | 
					                subghz_txrx_rx_start(subghz->txrx);
 | 
				
			||||||
                    if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					                subghz_txrx_hopper_unpause(subghz->txrx);
 | 
				
			||||||
                        subghz_tx_stop(subghz);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
 | 
					 | 
				
			||||||
                        subghz_begin(
 | 
					 | 
				
			||||||
                            subghz,
 | 
					 | 
				
			||||||
                            subghz_setting_get_preset_data_by_name(
 | 
					 | 
				
			||||||
                                subghz->setting,
 | 
					 | 
				
			||||||
                                furi_string_get_cstr(subghz->txrx->preset->name)));
 | 
					 | 
				
			||||||
                        subghz_rx(subghz, subghz->txrx->preset->frequency);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
 | 
					 | 
				
			||||||
                        subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                subghz->state_notifications = SubGhzNotificationStateRx;
 | 
					                subghz->state_notifications = SubGhzNotificationStateRx;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                subghz->state_notifications = SubGhzNotificationStateTx;
 | 
					                subghz->state_notifications = SubGhzNotificationStateTx;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
 | 
					        } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
 | 
				
			||||||
            //CC1101 Stop Tx -> Start RX
 | 
					            //CC1101 Stop Tx -> Start RX
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					
 | 
				
			||||||
                subghz_tx_stop(subghz);
 | 
					            subghz_txrx_rx_start(subghz->txrx);
 | 
				
			||||||
            }
 | 
					
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
 | 
					            subghz_txrx_hopper_unpause(subghz->txrx);
 | 
				
			||||||
                subghz_begin(
 | 
					 | 
				
			||||||
                    subghz,
 | 
					 | 
				
			||||||
                    subghz_setting_get_preset_data_by_name(
 | 
					 | 
				
			||||||
                        subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
 | 
					 | 
				
			||||||
                subghz_rx(subghz, subghz->txrx->preset->frequency);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
 | 
					 | 
				
			||||||
                subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateRx;
 | 
					            subghz->state_notifications = SubGhzNotificationStateRx;
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
 | 
					        } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
 | 
				
			||||||
            //CC1101 Stop RX -> Save
 | 
					            //CC1101 Stop RX -> Save
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            subghz->txrx->hopper_state = SubGhzHopperStateOFF;
 | 
					            subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					
 | 
				
			||||||
                subghz_rx_end(subghz);
 | 
					            subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(!subghz_scene_receiver_info_update_parser(subghz)) {
 | 
					            if(!subghz_scene_receiver_info_update_parser(subghz)) {
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
 | 
					            if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
 | 
				
			||||||
               SubGhzProtocolFlag_Save) {
 | 
					 | 
				
			||||||
                subghz_file_name_clear(subghz);
 | 
					                subghz_file_name_clear(subghz);
 | 
				
			||||||
                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
 | 
					                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if(event.type == SceneManagerEventTypeTick) {
 | 
					    } else if(event.type == SceneManagerEventTypeTick) {
 | 
				
			||||||
        if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
 | 
					        if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
 | 
				
			||||||
            subghz_hopper_update(subghz);
 | 
					            subghz_txrx_hopper_update(subghz->txrx);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        switch(subghz->state_notifications) {
 | 
					        switch(subghz->state_notifications) {
 | 
				
			||||||
        case SubGhzNotificationStateTx:
 | 
					        case SubGhzNotificationStateTx:
 | 
				
			||||||
 | 
				
			|||||||
@ -5,8 +5,7 @@
 | 
				
			|||||||
void subghz_scene_region_info_on_enter(void* context) {
 | 
					void subghz_scene_region_info_on_enter(void* context) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    const FuriHalRegion* const region = furi_hal_region_get();
 | 
					    const FuriHalRegion* const region = furi_hal_region_get();
 | 
				
			||||||
    FuriString* buffer;
 | 
					    FuriString* buffer = furi_string_alloc();
 | 
				
			||||||
    buffer = furi_string_alloc();
 | 
					 | 
				
			||||||
    if(region) {
 | 
					    if(region) {
 | 
				
			||||||
        furi_string_cat_printf(buffer, "Region: %s,  bands:\n", region->country_code);
 | 
					        furi_string_cat_printf(buffer, "Region: %s,  bands:\n", region->country_code);
 | 
				
			||||||
        for(uint16_t i = 0; i < region->bands_count; ++i) {
 | 
					        for(uint16_t i = 0; i < region->bands_count; ++i) {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    SubGhzRpcStateIdle,
 | 
					    SubGhzRpcStateIdle,
 | 
				
			||||||
    SubGhzRpcStateLoaded,
 | 
					    SubGhzRpcStateLoaded,
 | 
				
			||||||
 | 
					    SubGhzRpcStateTx,
 | 
				
			||||||
} SubGhzRpcState;
 | 
					} SubGhzRpcState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_scene_rpc_on_enter(void* context) {
 | 
					void subghz_scene_rpc_on_enter(void* context) {
 | 
				
			||||||
@ -38,9 +39,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            view_dispatcher_stop(subghz->view_dispatcher);
 | 
					            view_dispatcher_stop(subghz->view_dispatcher);
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) {
 | 
					        } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) {
 | 
				
			||||||
            bool result = false;
 | 
					            bool result = false;
 | 
				
			||||||
            if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) &&
 | 
					            if((state == SubGhzRpcStateLoaded)) {
 | 
				
			||||||
               (state == SubGhzRpcStateLoaded)) {
 | 
					                result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
 | 
				
			||||||
                result = subghz_tx_start(subghz, subghz->txrx->fff_data);
 | 
					                state = SubGhzRpcStateTx;
 | 
				
			||||||
                if(result) subghz_blink_start(subghz);
 | 
					                if(result) subghz_blink_start(subghz);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if(!result) {
 | 
					            if(!result) {
 | 
				
			||||||
@ -52,10 +53,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
 | 
					            rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
 | 
					        } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
 | 
				
			||||||
            bool result = false;
 | 
					            bool result = false;
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					            if(state == SubGhzRpcStateTx) {
 | 
				
			||||||
 | 
					                subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
                subghz_blink_stop(subghz);
 | 
					                subghz_blink_stop(subghz);
 | 
				
			||||||
                subghz_tx_stop(subghz);
 | 
					                state = SubGhzRpcStateIdle;
 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
                result = true;
 | 
					                result = true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result);
 | 
					            rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result);
 | 
				
			||||||
@ -93,10 +94,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void subghz_scene_rpc_on_exit(void* context) {
 | 
					void subghz_scene_rpc_on_exit(void* context) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					    SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc);
 | 
				
			||||||
    if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					    if(state != SubGhzRpcStateIdle) {
 | 
				
			||||||
        subghz_tx_stop(subghz);
 | 
					        subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
        subghz_sleep(subghz);
 | 
					 | 
				
			||||||
        subghz_blink_stop(subghz);
 | 
					        subghz_blink_stop(subghz);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,10 +35,8 @@ void subghz_scene_save_name_on_enter(void* context) {
 | 
				
			|||||||
    TextInput* text_input = subghz->text_input;
 | 
					    TextInput* text_input = subghz->text_input;
 | 
				
			||||||
    bool dev_name_empty = false;
 | 
					    bool dev_name_empty = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FuriString* file_name;
 | 
					    FuriString* file_name = furi_string_alloc();
 | 
				
			||||||
    FuriString* dir_name;
 | 
					    FuriString* dir_name = furi_string_alloc();
 | 
				
			||||||
    file_name = furi_string_alloc();
 | 
					 | 
				
			||||||
    dir_name = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(!subghz_path_is_file(subghz->file_path)) {
 | 
					    if(!subghz_path_is_file(subghz->file_path)) {
 | 
				
			||||||
        char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0};
 | 
					        char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0};
 | 
				
			||||||
@ -69,7 +67,7 @@ void subghz_scene_save_name_on_enter(void* context) {
 | 
				
			|||||||
        subghz_scene_save_name_text_input_callback,
 | 
					        subghz_scene_save_name_text_input_callback,
 | 
				
			||||||
        subghz,
 | 
					        subghz,
 | 
				
			||||||
        subghz->file_name_tmp,
 | 
					        subghz->file_name_tmp,
 | 
				
			||||||
        MAX_TEXT_INPUT_LEN, // buffer size
 | 
					        MAX_TEXT_INPUT_LEN,
 | 
				
			||||||
        dev_name_empty);
 | 
					        dev_name_empty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
 | 
					    ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
 | 
				
			||||||
@ -106,7 +104,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
                       SubGhzCustomEventManagerNoSet) {
 | 
					                       SubGhzCustomEventManagerNoSet) {
 | 
				
			||||||
                        subghz_save_protocol_to_file(
 | 
					                        subghz_save_protocol_to_file(
 | 
				
			||||||
                            subghz,
 | 
					                            subghz,
 | 
				
			||||||
                            subghz->txrx->fff_data,
 | 
					                            subghz_txrx_get_fff_data(subghz->txrx),
 | 
				
			||||||
                            furi_string_get_cstr(subghz->file_path));
 | 
					                            furi_string_get_cstr(subghz->file_path));
 | 
				
			||||||
                        scene_manager_set_scene_state(
 | 
					                        scene_manager_set_scene_state(
 | 
				
			||||||
                            subghz->scene_manager,
 | 
					                            subghz->scene_manager,
 | 
				
			||||||
@ -115,8 +113,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        subghz_save_protocol_to_file(
 | 
					                        subghz_save_protocol_to_file(
 | 
				
			||||||
                            subghz,
 | 
					                            subghz,
 | 
				
			||||||
                            subghz_history_get_raw_data(
 | 
					                            subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen),
 | 
				
			||||||
                                subghz->txrx->history, subghz->txrx->idx_menu_chosen),
 | 
					 | 
				
			||||||
                            furi_string_get_cstr(subghz->file_path));
 | 
					                            furi_string_get_cstr(subghz->file_path));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -124,7 +121,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
                if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
 | 
					                if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
 | 
				
			||||||
                   SubGhzCustomEventManagerNoSet) {
 | 
					                   SubGhzCustomEventManagerNoSet) {
 | 
				
			||||||
                    subghz_protocol_raw_gen_fff_data(
 | 
					                    subghz_protocol_raw_gen_fff_data(
 | 
				
			||||||
                        subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path));
 | 
					                        subghz_txrx_get_fff_data(subghz->txrx),
 | 
				
			||||||
 | 
					                        furi_string_get_cstr(subghz->file_path));
 | 
				
			||||||
                    scene_manager_set_scene_state(
 | 
					                    scene_manager_set_scene_state(
 | 
				
			||||||
                        subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
 | 
					                        subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -26,10 +26,10 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
 | 
				
			|||||||
        if(event.event == SubGhzCustomEventSceneSaveSuccess) {
 | 
					        if(event.event == SubGhzCustomEventSceneSaveSuccess) {
 | 
				
			||||||
            if(!scene_manager_search_and_switch_to_previous_scene(
 | 
					            if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                   subghz->scene_manager, SubGhzSceneReceiver)) {
 | 
					                   subghz->scene_manager, SubGhzSceneReceiver)) {
 | 
				
			||||||
                subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave;
 | 
					                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave);
 | 
				
			||||||
                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
					                if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                       subghz->scene_manager, SubGhzSceneReadRAW)) {
 | 
					                       subghz->scene_manager, SubGhzSceneReadRAW)) {
 | 
				
			||||||
                    subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
 | 
				
			||||||
                    if(!scene_manager_search_and_switch_to_previous_scene(
 | 
					                    if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                           subghz->scene_manager, SubGhzSceneSaved)) {
 | 
					                           subghz->scene_manager, SubGhzSceneSaved)) {
 | 
				
			||||||
                        scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
 | 
					                        scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
 | 
				
			||||||
 | 
				
			|||||||
@ -4,8 +4,8 @@ void subghz_scene_saved_on_enter(void* context) {
 | 
				
			|||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(subghz_load_protocol_from_file(subghz)) {
 | 
					    if(subghz_load_protocol_from_file(subghz)) {
 | 
				
			||||||
        if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
 | 
					        if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) {
 | 
				
			||||||
            subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
 | 
					            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
 | 
					            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu);
 | 
					            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,63 +1,10 @@
 | 
				
			|||||||
#include "../subghz_i.h"
 | 
					#include "../subghz_i.h"
 | 
				
			||||||
#include <lib/subghz/protocols/keeloq.h>
 | 
					#include "../helpers/subghz_txrx_create_potocol_key.h"
 | 
				
			||||||
#include <lib/subghz/protocols/secplus_v1.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/protocols/secplus_v2.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/blocks/math.h>
 | 
					#include <lib/subghz/blocks/math.h>
 | 
				
			||||||
#include <flipper_format/flipper_format_i.h>
 | 
					 | 
				
			||||||
#include <lib/toolbox/stream/stream.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/protocols/protocol_items.h>
 | 
					#include <lib/subghz/protocols/protocol_items.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TAG "SubGhzSetType"
 | 
					#define TAG "SubGhzSetType"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					 | 
				
			||||||
    void* context,
 | 
					 | 
				
			||||||
    const char* protocol_name,
 | 
					 | 
				
			||||||
    uint64_t key,
 | 
					 | 
				
			||||||
    uint32_t bit,
 | 
					 | 
				
			||||||
    uint32_t frequency,
 | 
					 | 
				
			||||||
    const char* preset_name) {
 | 
					 | 
				
			||||||
    furi_assert(context);
 | 
					 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool res = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_preset_init(subghz, preset_name, frequency, NULL, 0);
 | 
					 | 
				
			||||||
    subghz->txrx->decoder_result =
 | 
					 | 
				
			||||||
        subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(subghz->txrx->decoder_result == NULL) {
 | 
					 | 
				
			||||||
        furi_string_set(subghz->error_str, "Protocol not\nfound!");
 | 
					 | 
				
			||||||
        scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    do {
 | 
					 | 
				
			||||||
        Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
 | 
					 | 
				
			||||||
        stream_clean(fff_data_stream);
 | 
					 | 
				
			||||||
        if(subghz_protocol_decoder_base_serialize(
 | 
					 | 
				
			||||||
               subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) !=
 | 
					 | 
				
			||||||
           SubGhzProtocolStatusOk) {
 | 
					 | 
				
			||||||
            FURI_LOG_E(TAG, "Unable to serialize");
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) {
 | 
					 | 
				
			||||||
            FURI_LOG_E(TAG, "Unable to update Bit");
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint8_t key_data[sizeof(uint64_t)] = {0};
 | 
					 | 
				
			||||||
        for(size_t i = 0; i < sizeof(uint64_t); i++) {
 | 
					 | 
				
			||||||
            key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) {
 | 
					 | 
				
			||||||
            FURI_LOG_E(TAG, "Unable to update Key");
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        res = true;
 | 
					 | 
				
			||||||
    } while(false);
 | 
					 | 
				
			||||||
    return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) {
 | 
					void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
 | 
					    view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
 | 
				
			||||||
@ -69,7 +16,13 @@ void subghz_scene_set_type_on_enter(void* context) {
 | 
				
			|||||||
    submenu_add_item(
 | 
					    submenu_add_item(
 | 
				
			||||||
        subghz->submenu,
 | 
					        subghz->submenu,
 | 
				
			||||||
        "Princeton_433",
 | 
					        "Princeton_433",
 | 
				
			||||||
        SubmenuIndexPricenton,
 | 
					        SubmenuIndexPricenton_433,
 | 
				
			||||||
 | 
					        subghz_scene_set_type_submenu_callback,
 | 
				
			||||||
 | 
					        subghz);
 | 
				
			||||||
 | 
					    submenu_add_item(
 | 
				
			||||||
 | 
					        subghz->submenu,
 | 
				
			||||||
 | 
					        "Princeton_315",
 | 
				
			||||||
 | 
					        SubmenuIndexPricenton_315,
 | 
				
			||||||
        subghz_scene_set_type_submenu_callback,
 | 
					        subghz_scene_set_type_submenu_callback,
 | 
				
			||||||
        subghz);
 | 
					        subghz);
 | 
				
			||||||
    submenu_add_item(
 | 
					    submenu_add_item(
 | 
				
			||||||
@ -108,10 +61,6 @@ void subghz_scene_set_type_on_enter(void* context) {
 | 
				
			|||||||
        SubmenuIndexCAMETwee,
 | 
					        SubmenuIndexCAMETwee,
 | 
				
			||||||
        subghz_scene_set_type_submenu_callback,
 | 
					        subghz_scene_set_type_submenu_callback,
 | 
				
			||||||
        subghz);
 | 
					        subghz);
 | 
				
			||||||
    // submenu_add_item(
 | 
					 | 
				
			||||||
    //     subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
 | 
					 | 
				
			||||||
    // submenu_add_item(
 | 
					 | 
				
			||||||
    //     subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz);
 | 
					 | 
				
			||||||
    submenu_add_item(
 | 
					    submenu_add_item(
 | 
				
			||||||
        subghz->submenu,
 | 
					        subghz->submenu,
 | 
				
			||||||
        "Gate TX_433",
 | 
					        "Gate TX_433",
 | 
				
			||||||
@ -172,94 +121,59 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
    bool generated_protocol = false;
 | 
					    bool generated_protocol = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
					    if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        //ToDo Fix
 | 
					        uint32_t key = (uint32_t)rand();
 | 
				
			||||||
        uint32_t key = subghz_random_serial();
 | 
					 | 
				
			||||||
        switch(event.event) {
 | 
					        switch(event.event) {
 | 
				
			||||||
        case SubmenuIndexPricenton:
 | 
					        case SubmenuIndexPricenton_433:
 | 
				
			||||||
            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | 
					            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol_and_te(
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) {
 | 
					                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400);
 | 
				
			||||||
                uint32_t te = 400;
 | 
					            break;
 | 
				
			||||||
                flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
 | 
					        case SubmenuIndexPricenton_315:
 | 
				
			||||||
                generated_protocol = true;
 | 
					            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | 
				
			||||||
            }
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol_and_te(
 | 
				
			||||||
 | 
					                subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexNiceFlo12bit:
 | 
					        case SubmenuIndexNiceFlo12bit:
 | 
				
			||||||
            key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | 
					            key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol(
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) {
 | 
					                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12);
 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexNiceFlo24bit:
 | 
					        case SubmenuIndexNiceFlo24bit:
 | 
				
			||||||
            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | 
					            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol(
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) {
 | 
					                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24);
 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexCAME12bit:
 | 
					        case SubmenuIndexCAME12bit:
 | 
				
			||||||
            key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | 
					            key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol(
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) {
 | 
					                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12);
 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexCAME24bit:
 | 
					        case SubmenuIndexCAME24bit:
 | 
				
			||||||
            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | 
					            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol(
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) {
 | 
					                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24);
 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexLinear_300_00:
 | 
					        case SubmenuIndexLinear_300_00:
 | 
				
			||||||
            key = (key & 0x3FF);
 | 
					            key = (key & 0x3FF);
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol(
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) {
 | 
					                subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10);
 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexCAMETwee:
 | 
					        case SubmenuIndexCAMETwee:
 | 
				
			||||||
            key = (key & 0x0FFFFFF0);
 | 
					            key = (key & 0x0FFFFFF0);
 | 
				
			||||||
            key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
 | 
					            key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) {
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol(
 | 
				
			||||||
                generated_protocol = true;
 | 
					                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        // case SubmenuIndexNeroSketch:
 | 
					 | 
				
			||||||
        //     /* code */
 | 
					 | 
				
			||||||
        //     break;
 | 
					 | 
				
			||||||
        // case SubmenuIndexNeroRadio:
 | 
					 | 
				
			||||||
        //     /* code */
 | 
					 | 
				
			||||||
        //     break;
 | 
					 | 
				
			||||||
        case SubmenuIndexGateTX:
 | 
					        case SubmenuIndexGateTX:
 | 
				
			||||||
            key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
 | 
					            key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
 | 
				
			||||||
            uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
 | 
					            uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					            generated_protocol = subghz_txrx_gen_data_protocol(
 | 
				
			||||||
                   subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) {
 | 
					                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24);
 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexDoorHan_433_92:
 | 
					        case SubmenuIndexDoorHan_433_92:
 | 
				
			||||||
            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
 | 
					            generated_protocol = subghz_txrx_gen_keelog_protocol(
 | 
				
			||||||
                subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
 | 
					                subghz->txrx, "AM650", 433920000, "DoorHan", key, 0x2, 0x0003);
 | 
				
			||||||
            subghz_preset_init(
 | 
					 | 
				
			||||||
                subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
 | 
					 | 
				
			||||||
            if(subghz->txrx->transmitter) {
 | 
					 | 
				
			||||||
                subghz_protocol_keeloq_create_data(
 | 
					 | 
				
			||||||
                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
 | 
					 | 
				
			||||||
                    subghz->txrx->fff_data,
 | 
					 | 
				
			||||||
                    key & 0x0FFFFFFF,
 | 
					 | 
				
			||||||
                    0x2,
 | 
					 | 
				
			||||||
                    0x0003,
 | 
					 | 
				
			||||||
                    "DoorHan",
 | 
					 | 
				
			||||||
                    subghz->txrx->preset);
 | 
					 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                generated_protocol = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            subghz_transmitter_free(subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
            if(!generated_protocol) {
 | 
					            if(!generated_protocol) {
 | 
				
			||||||
                furi_string_set(
 | 
					                furi_string_set(
 | 
				
			||||||
                    subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
 | 
					                    subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
 | 
				
			||||||
@ -267,23 +181,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexDoorHan_315_00:
 | 
					        case SubmenuIndexDoorHan_315_00:
 | 
				
			||||||
            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
 | 
					            generated_protocol = subghz_txrx_gen_keelog_protocol(
 | 
				
			||||||
                subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
 | 
					                subghz->txrx, "AM650", 315000000, "DoorHan", key, 0x2, 0x0003);
 | 
				
			||||||
            subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
 | 
					 | 
				
			||||||
            if(subghz->txrx->transmitter) {
 | 
					 | 
				
			||||||
                subghz_protocol_keeloq_create_data(
 | 
					 | 
				
			||||||
                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
 | 
					 | 
				
			||||||
                    subghz->txrx->fff_data,
 | 
					 | 
				
			||||||
                    key & 0x0FFFFFFF,
 | 
					 | 
				
			||||||
                    0x2,
 | 
					 | 
				
			||||||
                    0x0003,
 | 
					 | 
				
			||||||
                    "DoorHan",
 | 
					 | 
				
			||||||
                    subghz->txrx->preset);
 | 
					 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                generated_protocol = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            subghz_transmitter_free(subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
            if(!generated_protocol) {
 | 
					            if(!generated_protocol) {
 | 
				
			||||||
                furi_string_set(
 | 
					                furi_string_set(
 | 
				
			||||||
                    subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
 | 
					                    subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
 | 
				
			||||||
@ -291,86 +190,24 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexLiftMaster_315_00:
 | 
					        case SubmenuIndexLiftMaster_315_00:
 | 
				
			||||||
            while(!subghz_protocol_secplus_v1_check_fixed(key)) {
 | 
					            generated_protocol =
 | 
				
			||||||
                key = subghz_random_serial();
 | 
					                subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					 | 
				
			||||||
                   subghz,
 | 
					 | 
				
			||||||
                   SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
 | 
					 | 
				
			||||||
                   (uint64_t)key << 32 | 0xE6000000,
 | 
					 | 
				
			||||||
                   42,
 | 
					 | 
				
			||||||
                   315000000,
 | 
					 | 
				
			||||||
                   "AM650")) {
 | 
					 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexLiftMaster_390_00:
 | 
					        case SubmenuIndexLiftMaster_390_00:
 | 
				
			||||||
            while(!subghz_protocol_secplus_v1_check_fixed(key)) {
 | 
					            generated_protocol =
 | 
				
			||||||
                key = subghz_random_serial();
 | 
					                subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(subghz_scene_set_type_submenu_gen_data_protocol(
 | 
					 | 
				
			||||||
                   subghz,
 | 
					 | 
				
			||||||
                   SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
 | 
					 | 
				
			||||||
                   (uint64_t)key << 32 | 0xE6000000,
 | 
					 | 
				
			||||||
                   42,
 | 
					 | 
				
			||||||
                   390000000,
 | 
					 | 
				
			||||||
                   "AM650")) {
 | 
					 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexSecPlus_v2_310_00:
 | 
					        case SubmenuIndexSecPlus_v2_310_00:
 | 
				
			||||||
            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
 | 
					            generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
 | 
				
			||||||
                subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
 | 
					                subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000);
 | 
				
			||||||
            subghz_preset_init(subghz, "AM650", 310000000, NULL, 0);
 | 
					 | 
				
			||||||
            if(subghz->txrx->transmitter) {
 | 
					 | 
				
			||||||
                subghz_protocol_secplus_v2_create_data(
 | 
					 | 
				
			||||||
                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
 | 
					 | 
				
			||||||
                    subghz->txrx->fff_data,
 | 
					 | 
				
			||||||
                    key,
 | 
					 | 
				
			||||||
                    0x68,
 | 
					 | 
				
			||||||
                    0xE500000,
 | 
					 | 
				
			||||||
                    subghz->txrx->preset);
 | 
					 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                generated_protocol = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            subghz_transmitter_free(subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexSecPlus_v2_315_00:
 | 
					        case SubmenuIndexSecPlus_v2_315_00:
 | 
				
			||||||
            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
 | 
					            generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
 | 
				
			||||||
                subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
 | 
					                subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000);
 | 
				
			||||||
            subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
 | 
					 | 
				
			||||||
            if(subghz->txrx->transmitter) {
 | 
					 | 
				
			||||||
                subghz_protocol_secplus_v2_create_data(
 | 
					 | 
				
			||||||
                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
 | 
					 | 
				
			||||||
                    subghz->txrx->fff_data,
 | 
					 | 
				
			||||||
                    key,
 | 
					 | 
				
			||||||
                    0x68,
 | 
					 | 
				
			||||||
                    0xE500000,
 | 
					 | 
				
			||||||
                    subghz->txrx->preset);
 | 
					 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                generated_protocol = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            subghz_transmitter_free(subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SubmenuIndexSecPlus_v2_390_00:
 | 
					        case SubmenuIndexSecPlus_v2_390_00:
 | 
				
			||||||
            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
 | 
					            generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
 | 
				
			||||||
                subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
 | 
					                subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000);
 | 
				
			||||||
            subghz_preset_init(subghz, "AM650", 390000000, NULL, 0);
 | 
					 | 
				
			||||||
            if(subghz->txrx->transmitter) {
 | 
					 | 
				
			||||||
                subghz_protocol_secplus_v2_create_data(
 | 
					 | 
				
			||||||
                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
 | 
					 | 
				
			||||||
                    subghz->txrx->fff_data,
 | 
					 | 
				
			||||||
                    key,
 | 
					 | 
				
			||||||
                    0x68,
 | 
					 | 
				
			||||||
                    0xE500000,
 | 
					 | 
				
			||||||
                    subghz->txrx->preset);
 | 
					 | 
				
			||||||
                generated_protocol = true;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                generated_protocol = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            subghz_transmitter_free(subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
 | 
				
			|||||||
@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
 | 
					bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					    SubGhzCustomEvent scene_state =
 | 
				
			||||||
 | 
					        scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError);
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeBack) {
 | 
					    if(event.type == SceneManagerEventTypeBack) {
 | 
				
			||||||
        if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
 | 
					        if(scene_state == SubGhzCustomEventManagerSet) {
 | 
				
			||||||
           SubGhzCustomEventManagerSet) {
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            scene_manager_search_and_switch_to_previous_scene(
 | 
					            scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    } else if(event.type == SceneManagerEventTypeCustom) {
 | 
					    } else if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        if(event.event == SubGhzCustomEventSceneShowErrorOk) {
 | 
					        if(event.event == SubGhzCustomEventSceneShowErrorOk) {
 | 
				
			||||||
            if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
 | 
					            if(scene_state == SubGhzCustomEventManagerSet) {
 | 
				
			||||||
               SubGhzCustomEventManagerSet) {
 | 
					 | 
				
			||||||
                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
 | 
					                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventSceneShowErrorBack) {
 | 
					        } else if(event.event == SubGhzCustomEventSceneShowErrorBack) {
 | 
				
			||||||
            if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
 | 
					            if(scene_state == SubGhzCustomEventManagerSet) {
 | 
				
			||||||
               SubGhzCustomEventManagerSet) {
 | 
					 | 
				
			||||||
                //exit app
 | 
					                //exit app
 | 
				
			||||||
                if(!scene_manager_previous_scene(subghz->scene_manager)) {
 | 
					                if(!scene_manager_previous_scene(subghz->scene_manager)) {
 | 
				
			||||||
                    scene_manager_stop(subghz->scene_manager);
 | 
					                    scene_manager_stop(subghz->scene_manager);
 | 
				
			||||||
 | 
				
			|||||||
@ -70,7 +70,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
        if(event.event == SubmenuIndexReadRAW) {
 | 
					        if(event.event == SubmenuIndexReadRAW) {
 | 
				
			||||||
            scene_manager_set_scene_state(
 | 
					            scene_manager_set_scene_state(
 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
 | 
					                subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
 | 
				
			||||||
            subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
 | 
					            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if(event.event == SubmenuIndexRead) {
 | 
					        } else if(event.event == SubmenuIndexRead) {
 | 
				
			||||||
 | 
				
			|||||||
@ -11,32 +11,24 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
 | 
				
			|||||||
bool subghz_scene_transmitter_update_data_show(void* context) {
 | 
					bool subghz_scene_transmitter_update_data_show(void* context) {
 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    bool ret = false;
 | 
					    bool ret = false;
 | 
				
			||||||
    if(subghz->txrx->decoder_result) {
 | 
					    SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
 | 
				
			||||||
        FuriString* key_str;
 | 
					 | 
				
			||||||
        FuriString* frequency_str;
 | 
					 | 
				
			||||||
        FuriString* modulation_str;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        key_str = furi_string_alloc();
 | 
					    if(decoder) {
 | 
				
			||||||
        frequency_str = furi_string_alloc();
 | 
					        FuriString* key_str = furi_string_alloc();
 | 
				
			||||||
        modulation_str = furi_string_alloc();
 | 
					        FuriString* frequency_str = furi_string_alloc();
 | 
				
			||||||
        uint8_t show_button = 0;
 | 
					        FuriString* modulation_str = furi_string_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(subghz_protocol_decoder_base_deserialize(
 | 
					        if(subghz_protocol_decoder_base_deserialize(
 | 
				
			||||||
               subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) {
 | 
					               decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) {
 | 
				
			||||||
            subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str);
 | 
					            subghz_protocol_decoder_base_get_string(decoder, key_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
 | 
					            subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
 | 
				
			||||||
               SubGhzProtocolFlag_Send) {
 | 
					 | 
				
			||||||
                show_button = 1;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
 | 
					 | 
				
			||||||
            subghz_view_transmitter_add_data_to_show(
 | 
					            subghz_view_transmitter_add_data_to_show(
 | 
				
			||||||
                subghz->subghz_transmitter,
 | 
					                subghz->subghz_transmitter,
 | 
				
			||||||
                furi_string_get_cstr(key_str),
 | 
					                furi_string_get_cstr(key_str),
 | 
				
			||||||
                furi_string_get_cstr(frequency_str),
 | 
					                furi_string_get_cstr(frequency_str),
 | 
				
			||||||
                furi_string_get_cstr(modulation_str),
 | 
					                furi_string_get_cstr(modulation_str),
 | 
				
			||||||
                show_button);
 | 
					                subghz_txrx_protocol_is_transmittable(subghz->txrx, false));
 | 
				
			||||||
            ret = true;
 | 
					            ret = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        furi_string_free(frequency_str);
 | 
					        furi_string_free(frequency_str);
 | 
				
			||||||
@ -65,24 +57,16 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
					    if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        if(event.event == SubGhzCustomEventViewTransmitterSendStart) {
 | 
					        if(event.event == SubGhzCustomEventViewTransmitterSendStart) {
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					
 | 
				
			||||||
                subghz_rx_end(subghz);
 | 
					            if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
 | 
					 | 
				
			||||||
               (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
 | 
					 | 
				
			||||||
                if(subghz_tx_start(subghz, subghz->txrx->fff_data)) {
 | 
					 | 
				
			||||||
                subghz->state_notifications = SubGhzNotificationStateTx;
 | 
					                subghz->state_notifications = SubGhzNotificationStateTx;
 | 
				
			||||||
                subghz_scene_transmitter_update_data_show(subghz);
 | 
					                subghz_scene_transmitter_update_data_show(subghz);
 | 
				
			||||||
                DOLPHIN_DEED(DolphinDeedSubGhzSend);
 | 
					                DOLPHIN_DEED(DolphinDeedSubGhzSend);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
 | 
					        } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
 | 
					            subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
                subghz_tx_stop(subghz);
 | 
					 | 
				
			||||||
                subghz_sleep(subghz);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if(event.event == SubGhzCustomEventViewTransmitterBack) {
 | 
					        } else if(event.event == SubGhzCustomEventViewTransmitterBack) {
 | 
				
			||||||
            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
					            subghz->state_notifications = SubGhzNotificationStateIDLE;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,6 @@
 | 
				
			|||||||
/* Abandon hope, all ye who enter here. */
 | 
					/* Abandon hope, all ye who enter here. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "subghz/types.h"
 | 
					 | 
				
			||||||
#include "subghz_i.h"
 | 
					#include "subghz_i.h"
 | 
				
			||||||
#include <lib/toolbox/path.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/protocols/protocol_items.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_custom_event_callback(void* context, uint32_t event) {
 | 
					bool subghz_custom_event_callback(void* context, uint32_t event) {
 | 
				
			||||||
    furi_assert(context);
 | 
					    furi_assert(context);
 | 
				
			||||||
@ -49,16 +46,6 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_blink_start(SubGhz* instance) {
 | 
					 | 
				
			||||||
    furi_assert(instance);
 | 
					 | 
				
			||||||
    notification_message(instance->notifications, &sequence_blink_start_magenta);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_blink_stop(SubGhz* instance) {
 | 
					 | 
				
			||||||
    furi_assert(instance);
 | 
					 | 
				
			||||||
    notification_message(instance->notifications, &sequence_blink_stop);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SubGhz* subghz_alloc() {
 | 
					SubGhz* subghz_alloc() {
 | 
				
			||||||
    SubGhz* subghz = malloc(sizeof(SubGhz));
 | 
					    SubGhz* subghz = malloc(sizeof(SubGhz));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -163,45 +150,18 @@ SubGhz* subghz_alloc() {
 | 
				
			|||||||
        SubGhzViewIdStatic,
 | 
					        SubGhzViewIdStatic,
 | 
				
			||||||
        subghz_test_static_get_view(subghz->subghz_test_static));
 | 
					        subghz_test_static_get_view(subghz->subghz_test_static));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //init setting
 | 
					    //init threshold rssi
 | 
				
			||||||
    subghz->setting = subghz_setting_alloc();
 | 
					    subghz->threshold_rssi = subghz_threshold_rssi_alloc();
 | 
				
			||||||
    subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user"));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //init Worker & Protocol & History & KeyBoard
 | 
					    subghz_unlock(subghz);
 | 
				
			||||||
    subghz->lock = SubGhzLockOff;
 | 
					    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
 | 
				
			||||||
    subghz->txrx = malloc(sizeof(SubGhzTxRx));
 | 
					    subghz->history = subghz_history_alloc();
 | 
				
			||||||
    subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset));
 | 
					    subghz->filter = SubGhzProtocolFlag_Decodable;
 | 
				
			||||||
    subghz->txrx->preset->name = furi_string_alloc();
 | 
					 | 
				
			||||||
    subghz_preset_init(
 | 
					 | 
				
			||||||
        subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
 | 
					    //init TxRx & History & KeyBoard
 | 
				
			||||||
    subghz->txrx->hopper_state = SubGhzHopperStateOFF;
 | 
					    subghz->txrx = subghz_txrx_alloc();
 | 
				
			||||||
    subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
 | 
					    subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
 | 
				
			||||||
    subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
 | 
					    subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz);
 | 
				
			||||||
    subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN;
 | 
					 | 
				
			||||||
    subghz->txrx->history = subghz_history_alloc();
 | 
					 | 
				
			||||||
    subghz->txrx->worker = subghz_worker_alloc();
 | 
					 | 
				
			||||||
    subghz->txrx->fff_data = flipper_format_string_alloc();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz->txrx->environment = subghz_environment_alloc();
 | 
					 | 
				
			||||||
    subghz_environment_set_came_atomo_rainbow_table_file_name(
 | 
					 | 
				
			||||||
        subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo"));
 | 
					 | 
				
			||||||
    subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
 | 
					 | 
				
			||||||
        subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
 | 
					 | 
				
			||||||
    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
 | 
					 | 
				
			||||||
        subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s"));
 | 
					 | 
				
			||||||
    subghz_environment_set_protocol_registry(
 | 
					 | 
				
			||||||
        subghz->txrx->environment, (void*)&subghz_protocol_registry);
 | 
					 | 
				
			||||||
    subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment);
 | 
					 | 
				
			||||||
    subghz->txrx->filter = SubGhzProtocolFlag_Decodable;
 | 
					 | 
				
			||||||
    subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_worker_set_overrun_callback(
 | 
					 | 
				
			||||||
        subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
 | 
					 | 
				
			||||||
    subghz_worker_set_pair_callback(
 | 
					 | 
				
			||||||
        subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
 | 
					 | 
				
			||||||
    subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Init Error_str
 | 
					    //Init Error_str
 | 
				
			||||||
    subghz->error_str = furi_string_alloc();
 | 
					    subghz->error_str = furi_string_alloc();
 | 
				
			||||||
@ -219,7 +179,9 @@ void subghz_free(SubGhz* subghz) {
 | 
				
			|||||||
        subghz->rpc_ctx = NULL;
 | 
					        subghz->rpc_ctx = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz_speaker_off(subghz);
 | 
					    subghz_txrx_speaker_off(subghz->txrx);
 | 
				
			||||||
 | 
					    subghz_txrx_stop(subghz->txrx);
 | 
				
			||||||
 | 
					    subghz_txrx_sleep(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Packet Test
 | 
					    // Packet Test
 | 
				
			||||||
    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
 | 
					    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
 | 
				
			||||||
@ -282,18 +244,14 @@ void subghz_free(SubGhz* subghz) {
 | 
				
			|||||||
    furi_record_close(RECORD_GUI);
 | 
					    furi_record_close(RECORD_GUI);
 | 
				
			||||||
    subghz->gui = NULL;
 | 
					    subghz->gui = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //setting
 | 
					    // threshold rssi
 | 
				
			||||||
    subghz_setting_free(subghz->setting);
 | 
					    subghz_threshold_rssi_free(subghz->threshold_rssi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Worker & Protocol & History
 | 
					    //Worker & Protocol & History
 | 
				
			||||||
    subghz_receiver_free(subghz->txrx->receiver);
 | 
					    subghz_history_free(subghz->history);
 | 
				
			||||||
    subghz_environment_free(subghz->txrx->environment);
 | 
					
 | 
				
			||||||
    subghz_worker_free(subghz->txrx->worker);
 | 
					    //TxRx
 | 
				
			||||||
    flipper_format_free(subghz->txrx->fff_data);
 | 
					    subghz_txrx_free(subghz->txrx);
 | 
				
			||||||
    subghz_history_free(subghz->txrx->history);
 | 
					 | 
				
			||||||
    furi_string_free(subghz->txrx->preset->name);
 | 
					 | 
				
			||||||
    free(subghz->txrx->preset);
 | 
					 | 
				
			||||||
    free(subghz->txrx);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Error string
 | 
					    //Error string
 | 
				
			||||||
    furi_string_free(subghz->error_str);
 | 
					    furi_string_free(subghz->error_str);
 | 
				
			||||||
@ -319,11 +277,6 @@ int32_t subghz_app(void* p) {
 | 
				
			|||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Load database
 | 
					 | 
				
			||||||
    bool load_database = subghz_environment_load_keystore(
 | 
					 | 
				
			||||||
        subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
 | 
					 | 
				
			||||||
    subghz_environment_load_keystore(
 | 
					 | 
				
			||||||
        subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
 | 
					 | 
				
			||||||
    // Check argument and run corresponding scene
 | 
					    // Check argument and run corresponding scene
 | 
				
			||||||
    if(p && strlen(p)) {
 | 
					    if(p && strlen(p)) {
 | 
				
			||||||
        uint32_t rpc_ctx = 0;
 | 
					        uint32_t rpc_ctx = 0;
 | 
				
			||||||
@ -340,9 +293,9 @@ int32_t subghz_app(void* p) {
 | 
				
			|||||||
            if(subghz_key_load(subghz, p, true)) {
 | 
					            if(subghz_key_load(subghz, p, true)) {
 | 
				
			||||||
                furi_string_set(subghz->file_path, (const char*)p);
 | 
					                furi_string_set(subghz->file_path, (const char*)p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
 | 
					                if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) {
 | 
				
			||||||
                    //Load Raw TX
 | 
					                    //Load Raw TX
 | 
				
			||||||
                    subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
 | 
					                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
 | 
				
			||||||
                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
 | 
					                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    //Load transmitter TX
 | 
					                    //Load transmitter TX
 | 
				
			||||||
@ -358,7 +311,7 @@ int32_t subghz_app(void* p) {
 | 
				
			|||||||
        view_dispatcher_attach_to_gui(
 | 
					        view_dispatcher_attach_to_gui(
 | 
				
			||||||
            subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
 | 
					            subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
 | 
				
			||||||
        furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
 | 
					        furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
 | 
				
			||||||
        if(load_database) {
 | 
					        if(subghz_txrx_is_database_loaded(subghz->txrx)) {
 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
 | 
					            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            scene_manager_set_scene_state(
 | 
					            scene_manager_set_scene_state(
 | 
				
			||||||
 | 
				
			|||||||
@ -18,214 +18,42 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define TAG "SubGhz"
 | 
					#define TAG "SubGhz"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_preset_init(
 | 
					void subghz_set_default_preset(SubGhz* subghz) {
 | 
				
			||||||
    void* context,
 | 
					 | 
				
			||||||
    const char* preset_name,
 | 
					 | 
				
			||||||
    uint32_t frequency,
 | 
					 | 
				
			||||||
    uint8_t* preset_data,
 | 
					 | 
				
			||||||
    size_t preset_data_size) {
 | 
					 | 
				
			||||||
    furi_assert(context);
 | 
					 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					 | 
				
			||||||
    furi_string_set(subghz->txrx->preset->name, preset_name);
 | 
					 | 
				
			||||||
    subghz->txrx->preset->frequency = frequency;
 | 
					 | 
				
			||||||
    subghz->txrx->preset->data = preset_data;
 | 
					 | 
				
			||||||
    subghz->txrx->preset->data_size = preset_data_size;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool subghz_set_preset(SubGhz* subghz, const char* preset) {
 | 
					 | 
				
			||||||
    if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
 | 
					 | 
				
			||||||
        furi_string_set(subghz->txrx->preset->name, "AM270");
 | 
					 | 
				
			||||||
    } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
 | 
					 | 
				
			||||||
        furi_string_set(subghz->txrx->preset->name, "AM650");
 | 
					 | 
				
			||||||
    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
 | 
					 | 
				
			||||||
        furi_string_set(subghz->txrx->preset->name, "FM238");
 | 
					 | 
				
			||||||
    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
 | 
					 | 
				
			||||||
        furi_string_set(subghz->txrx->preset->name, "FM476");
 | 
					 | 
				
			||||||
    } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
 | 
					 | 
				
			||||||
        furi_string_set(subghz->txrx->preset->name, "CUSTOM");
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        FURI_LOG_E(TAG, "Unknown preset");
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) {
 | 
					 | 
				
			||||||
    furi_assert(subghz);
 | 
					    furi_assert(subghz);
 | 
				
			||||||
    if(frequency != NULL) {
 | 
					    subghz_txrx_set_preset(
 | 
				
			||||||
        furi_string_printf(
 | 
					        subghz->txrx,
 | 
				
			||||||
            frequency,
 | 
					        "AM650",
 | 
				
			||||||
            "%03ld.%02ld",
 | 
					        subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)),
 | 
				
			||||||
            subghz->txrx->preset->frequency / 1000000 % 1000,
 | 
					        NULL,
 | 
				
			||||||
            subghz->txrx->preset->frequency / 10000 % 100);
 | 
					        0);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if(modulation != NULL) {
 | 
					 | 
				
			||||||
        furi_string_printf(modulation, "%.2s", furi_string_get_cstr(subghz->txrx->preset->name));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_begin(SubGhz* subghz, uint8_t* preset_data) {
 | 
					void subghz_blink_start(SubGhz* subghz) {
 | 
				
			||||||
    furi_assert(subghz);
 | 
					    furi_assert(subghz);
 | 
				
			||||||
    furi_hal_subghz_reset();
 | 
					    notification_message(subghz->notifications, &sequence_blink_stop);
 | 
				
			||||||
    furi_hal_subghz_idle();
 | 
					    notification_message(subghz->notifications, &sequence_blink_start_magenta);
 | 
				
			||||||
    furi_hal_subghz_load_custom_preset(preset_data);
 | 
					 | 
				
			||||||
    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 | 
					 | 
				
			||||||
    subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) {
 | 
					void subghz_blink_stop(SubGhz* subghz) {
 | 
				
			||||||
    furi_assert(subghz);
 | 
					    furi_assert(subghz);
 | 
				
			||||||
    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
 | 
					    notification_message(subghz->notifications, &sequence_blink_stop);
 | 
				
			||||||
        furi_crash("SubGhz: Incorrect RX frequency.");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    furi_assert(
 | 
					 | 
				
			||||||
        subghz->txrx->txrx_state != SubGhzTxRxStateRx &&
 | 
					 | 
				
			||||||
        subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    furi_hal_subghz_idle();
 | 
					 | 
				
			||||||
    uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
 | 
					 | 
				
			||||||
    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 | 
					 | 
				
			||||||
    furi_hal_subghz_flush_rx();
 | 
					 | 
				
			||||||
    subghz_speaker_on(subghz);
 | 
					 | 
				
			||||||
    furi_hal_subghz_rx();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker);
 | 
					 | 
				
			||||||
    subghz_worker_start(subghz->txrx->worker);
 | 
					 | 
				
			||||||
    subghz->txrx->txrx_state = SubGhzTxRxStateRx;
 | 
					 | 
				
			||||||
    return value;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool subghz_tx(SubGhz* subghz, uint32_t frequency) {
 | 
					 | 
				
			||||||
    furi_assert(subghz);
 | 
					 | 
				
			||||||
    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
 | 
					 | 
				
			||||||
        furi_crash("SubGhz: Incorrect TX frequency.");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
 | 
					 | 
				
			||||||
    furi_hal_subghz_idle();
 | 
					 | 
				
			||||||
    furi_hal_subghz_set_frequency_and_path(frequency);
 | 
					 | 
				
			||||||
    furi_hal_gpio_write(&gpio_cc1101_g0, false);
 | 
					 | 
				
			||||||
    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
 | 
					 | 
				
			||||||
    bool ret = furi_hal_subghz_tx();
 | 
					 | 
				
			||||||
    if(ret) {
 | 
					 | 
				
			||||||
        subghz_speaker_on(subghz);
 | 
					 | 
				
			||||||
        subghz->txrx->txrx_state = SubGhzTxRxStateTx;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_idle(SubGhz* subghz) {
 | 
					 | 
				
			||||||
    furi_assert(subghz);
 | 
					 | 
				
			||||||
    furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
 | 
					 | 
				
			||||||
    furi_hal_subghz_idle();
 | 
					 | 
				
			||||||
    subghz_speaker_off(subghz);
 | 
					 | 
				
			||||||
    subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_rx_end(SubGhz* subghz) {
 | 
					 | 
				
			||||||
    furi_assert(subghz);
 | 
					 | 
				
			||||||
    furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(subghz_worker_is_running(subghz->txrx->worker)) {
 | 
					 | 
				
			||||||
        subghz_worker_stop(subghz->txrx->worker);
 | 
					 | 
				
			||||||
        furi_hal_subghz_stop_async_rx();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    furi_hal_subghz_idle();
 | 
					 | 
				
			||||||
    subghz_speaker_off(subghz);
 | 
					 | 
				
			||||||
    subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_sleep(SubGhz* subghz) {
 | 
					 | 
				
			||||||
    furi_assert(subghz);
 | 
					 | 
				
			||||||
    furi_hal_subghz_sleep();
 | 
					 | 
				
			||||||
    subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
 | 
					bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
 | 
				
			||||||
    furi_assert(subghz);
 | 
					    switch(subghz_txrx_tx_start(subghz->txrx, flipper_format)) {
 | 
				
			||||||
 | 
					    case SubGhzTxRxStartTxStateErrorParserOthers:
 | 
				
			||||||
    bool ret = false;
 | 
					 | 
				
			||||||
    FuriString* temp_str;
 | 
					 | 
				
			||||||
    temp_str = furi_string_alloc();
 | 
					 | 
				
			||||||
    uint32_t repeat = 200;
 | 
					 | 
				
			||||||
    do {
 | 
					 | 
				
			||||||
        if(!flipper_format_rewind(flipper_format)) {
 | 
					 | 
				
			||||||
            FURI_LOG_E(TAG, "Rewind error");
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
 | 
					 | 
				
			||||||
            FURI_LOG_E(TAG, "Missing Protocol");
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
 | 
					 | 
				
			||||||
            FURI_LOG_E(TAG, "Unable Repeat");
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        subghz->txrx->transmitter = subghz_transmitter_alloc_init(
 | 
					 | 
				
			||||||
            subghz->txrx->environment, furi_string_get_cstr(temp_str));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(subghz->txrx->transmitter) {
 | 
					 | 
				
			||||||
            if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) ==
 | 
					 | 
				
			||||||
               SubGhzProtocolStatusOk) {
 | 
					 | 
				
			||||||
                if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) {
 | 
					 | 
				
			||||||
                    subghz_begin(
 | 
					 | 
				
			||||||
                        subghz,
 | 
					 | 
				
			||||||
                        subghz_setting_get_preset_data_by_name(
 | 
					 | 
				
			||||||
                            subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    FURI_LOG_E(
 | 
					 | 
				
			||||||
                        TAG,
 | 
					 | 
				
			||||||
                        "Unknown name preset \" %s \"",
 | 
					 | 
				
			||||||
                        furi_string_get_cstr(subghz->txrx->preset->name));
 | 
					 | 
				
			||||||
                    subghz_begin(
 | 
					 | 
				
			||||||
                        subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650"));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if(subghz->txrx->preset->frequency) {
 | 
					 | 
				
			||||||
                    ret = subghz_tx(subghz, subghz->txrx->preset->frequency);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    ret = subghz_tx(subghz, 433920000);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if(ret) {
 | 
					 | 
				
			||||||
                    //Start TX
 | 
					 | 
				
			||||||
                    furi_hal_subghz_start_async_tx(
 | 
					 | 
				
			||||||
                        subghz_transmitter_yield, subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    subghz_dialog_message_show_only_rx(subghz);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
        dialog_message_show_storage_error(
 | 
					        dialog_message_show_storage_error(
 | 
				
			||||||
            subghz->dialogs, "Error in protocol\nparameters\ndescription");
 | 
					            subghz->dialogs, "Error in protocol\nparameters\ndescription");
 | 
				
			||||||
            }
 | 
					        break;
 | 
				
			||||||
        }
 | 
					    case SubGhzTxRxStartTxStateErrorOnlyRx:
 | 
				
			||||||
        if(!ret) {
 | 
					        subghz_dialog_message_show_only_rx(subghz);
 | 
				
			||||||
            subghz_transmitter_free(subghz->txrx->transmitter);
 | 
					        break;
 | 
				
			||||||
            if(subghz->txrx->txrx_state != SubGhzTxRxStateSleep) {
 | 
					 | 
				
			||||||
                subghz_idle(subghz);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } while(false);
 | 
					    default:
 | 
				
			||||||
    furi_string_free(temp_str);
 | 
					        return true;
 | 
				
			||||||
    return ret;
 | 
					        break;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_tx_stop(SubGhz* subghz) {
 | 
					 | 
				
			||||||
    furi_assert(subghz);
 | 
					 | 
				
			||||||
    furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx);
 | 
					 | 
				
			||||||
    //Stop TX
 | 
					 | 
				
			||||||
    furi_hal_subghz_stop_async_tx();
 | 
					 | 
				
			||||||
    subghz_transmitter_stop(subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
    subghz_transmitter_free(subghz->txrx->transmitter);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //if protocol dynamic then we save the last upload
 | 
					 | 
				
			||||||
    if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) &&
 | 
					 | 
				
			||||||
       (subghz_path_is_file(subghz->file_path))) {
 | 
					 | 
				
			||||||
        subghz_save_protocol_to_file(
 | 
					 | 
				
			||||||
            subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    subghz_idle(subghz);
 | 
					    return false;
 | 
				
			||||||
    subghz_speaker_off(subghz);
 | 
					 | 
				
			||||||
    notification_message(subghz->notifications, &sequence_reset_red);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_dialog_message_show_only_rx(SubGhz* subghz) {
 | 
					void subghz_dialog_message_show_only_rx(SubGhz* subghz) {
 | 
				
			||||||
@ -254,11 +82,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    Storage* storage = furi_record_open(RECORD_STORAGE);
 | 
					    Storage* storage = furi_record_open(RECORD_STORAGE);
 | 
				
			||||||
    FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
 | 
					    FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
 | 
				
			||||||
    Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
 | 
					    Stream* fff_data_stream =
 | 
				
			||||||
 | 
					        flipper_format_get_raw_stream(subghz_txrx_get_fff_data(subghz->txrx));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr;
 | 
					    SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr;
 | 
				
			||||||
    FuriString* temp_str;
 | 
					    FuriString* temp_str = furi_string_alloc();
 | 
				
			||||||
    temp_str = furi_string_alloc();
 | 
					 | 
				
			||||||
    uint32_t temp_data32;
 | 
					    uint32_t temp_data32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
@ -281,6 +109,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //Load frequency
 | 
				
			||||||
        if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
 | 
					        if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
 | 
				
			||||||
            FURI_LOG_E(TAG, "Missing Frequency");
 | 
					            FURI_LOG_E(TAG, "Missing Frequency");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -291,58 +120,61 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subghz->txrx->preset->frequency = temp_data32;
 | 
					        //Load preset
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
 | 
					        if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
 | 
				
			||||||
            FURI_LOG_E(TAG, "Missing Preset");
 | 
					            FURI_LOG_E(TAG, "Missing Preset");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!subghz_set_preset(subghz, furi_string_get_cstr(temp_str))) {
 | 
					        furi_string_set_str(
 | 
				
			||||||
 | 
					            temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str)));
 | 
				
			||||||
 | 
					        if(!strcmp(furi_string_get_cstr(temp_str), "")) {
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
 | 
					        if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) {
 | 
				
			||||||
            //Todo add Custom_preset_module
 | 
					            //Todo add Custom_preset_module
 | 
				
			||||||
            //delete preset if it already exists
 | 
					            //delete preset if it already exists
 | 
				
			||||||
            subghz_setting_delete_custom_preset(
 | 
					            subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str));
 | 
				
			||||||
                subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name));
 | 
					 | 
				
			||||||
            //load custom preset from file
 | 
					            //load custom preset from file
 | 
				
			||||||
            if(!subghz_setting_load_custom_preset(
 | 
					            if(!subghz_setting_load_custom_preset(
 | 
				
			||||||
                   subghz->setting,
 | 
					                   setting, furi_string_get_cstr(temp_str), fff_data_file)) {
 | 
				
			||||||
                   furi_string_get_cstr(subghz->txrx->preset->name),
 | 
					 | 
				
			||||||
                   fff_data_file)) {
 | 
					 | 
				
			||||||
                FURI_LOG_E(TAG, "Missing Custom preset");
 | 
					                FURI_LOG_E(TAG, "Missing Custom preset");
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        size_t preset_index = subghz_setting_get_inx_preset_by_name(
 | 
					        size_t preset_index =
 | 
				
			||||||
            subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name));
 | 
					            subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str));
 | 
				
			||||||
        subghz_preset_init(
 | 
					        subghz_txrx_set_preset(
 | 
				
			||||||
            subghz,
 | 
					            subghz->txrx,
 | 
				
			||||||
            furi_string_get_cstr(subghz->txrx->preset->name),
 | 
					            furi_string_get_cstr(temp_str),
 | 
				
			||||||
            subghz->txrx->preset->frequency,
 | 
					            temp_data32,
 | 
				
			||||||
            subghz_setting_get_preset_data(subghz->setting, preset_index),
 | 
					            subghz_setting_get_preset_data(setting, preset_index),
 | 
				
			||||||
            subghz_setting_get_preset_data_size(subghz->setting, preset_index));
 | 
					            subghz_setting_get_preset_data_size(setting, preset_index));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //Load protocol
 | 
				
			||||||
        if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
 | 
					        if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
 | 
				
			||||||
            FURI_LOG_E(TAG, "Missing Protocol");
 | 
					            FURI_LOG_E(TAG, "Missing Protocol");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx);
 | 
				
			||||||
        if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
 | 
					        if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
 | 
				
			||||||
            //if RAW
 | 
					            //if RAW
 | 
				
			||||||
            subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path);
 | 
					            subghz->load_type_file = SubGhzLoadTypeFileRaw;
 | 
				
			||||||
 | 
					            subghz_protocol_raw_gen_fff_data(fff_data, file_path);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            subghz->load_type_file = SubGhzLoadTypeFileKey;
 | 
				
			||||||
            stream_copy_full(
 | 
					            stream_copy_full(
 | 
				
			||||||
                flipper_format_get_raw_stream(fff_data_file),
 | 
					                flipper_format_get_raw_stream(fff_data_file),
 | 
				
			||||||
                flipper_format_get_raw_stream(subghz->txrx->fff_data));
 | 
					                flipper_format_get_raw_stream(fff_data));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
 | 
					        if(subghz_txrx_load_decoder_by_name_protocol(
 | 
				
			||||||
            subghz->txrx->receiver, furi_string_get_cstr(temp_str));
 | 
					               subghz->txrx, furi_string_get_cstr(temp_str))) {
 | 
				
			||||||
        if(subghz->txrx->decoder_result) {
 | 
					 | 
				
			||||||
            SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
 | 
					            SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
 | 
				
			||||||
                subghz->txrx->decoder_result, subghz->txrx->fff_data);
 | 
					                subghz_txrx_get_decoder(subghz->txrx), fff_data);
 | 
				
			||||||
            if(status != SubGhzProtocolStatusOk) {
 | 
					            if(status != SubGhzProtocolStatusOk) {
 | 
				
			||||||
                load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
 | 
					                load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@ -381,17 +213,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) {
 | 
				
			||||||
 | 
					    furi_assert(subghz);
 | 
				
			||||||
 | 
					    return subghz->load_type_file;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) {
 | 
					bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) {
 | 
				
			||||||
    furi_assert(subghz);
 | 
					    furi_assert(subghz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Storage* storage = furi_record_open(RECORD_STORAGE);
 | 
					    Storage* storage = furi_record_open(RECORD_STORAGE);
 | 
				
			||||||
    FuriString* temp_str;
 | 
					    FuriString* temp_str = furi_string_alloc();
 | 
				
			||||||
    FuriString* file_name;
 | 
					    FuriString* file_name = furi_string_alloc();
 | 
				
			||||||
    FuriString* file_path;
 | 
					    FuriString* file_path = furi_string_alloc();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    temp_str = furi_string_alloc();
 | 
					 | 
				
			||||||
    file_name = furi_string_alloc();
 | 
					 | 
				
			||||||
    file_path = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool res = false;
 | 
					    bool res = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -438,8 +271,7 @@ bool subghz_save_protocol_to_file(
 | 
				
			|||||||
    Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
 | 
					    Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool saved = false;
 | 
					    bool saved = false;
 | 
				
			||||||
    FuriString* file_dir;
 | 
					    FuriString* file_dir = furi_string_alloc();
 | 
				
			||||||
    file_dir = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    path_extract_dirname(dev_file_name, file_dir);
 | 
					    path_extract_dirname(dev_file_name, file_dir);
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
@ -467,11 +299,21 @@ bool subghz_save_protocol_to_file(
 | 
				
			|||||||
    return saved;
 | 
					    return saved;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_save_to_file(void* context) {
 | 
				
			||||||
 | 
					    furi_assert(context);
 | 
				
			||||||
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					    if(subghz_path_is_file(subghz->file_path)) {
 | 
				
			||||||
 | 
					        subghz_save_protocol_to_file(
 | 
				
			||||||
 | 
					            subghz,
 | 
				
			||||||
 | 
					            subghz_txrx_get_fff_data(subghz->txrx),
 | 
				
			||||||
 | 
					            furi_string_get_cstr(subghz->file_path));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_load_protocol_from_file(SubGhz* subghz) {
 | 
					bool subghz_load_protocol_from_file(SubGhz* subghz) {
 | 
				
			||||||
    furi_assert(subghz);
 | 
					    furi_assert(subghz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FuriString* file_path;
 | 
					    FuriString* file_path = furi_string_alloc();
 | 
				
			||||||
    file_path = furi_string_alloc();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DialogsFileBrowserOptions browser_options;
 | 
					    DialogsFileBrowserOptions browser_options;
 | 
				
			||||||
    dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
 | 
					    dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
 | 
				
			||||||
@ -551,92 +393,27 @@ bool subghz_path_is_file(FuriString* path) {
 | 
				
			|||||||
    return furi_string_end_with(path, SUBGHZ_APP_EXTENSION);
 | 
					    return furi_string_end_with(path, SUBGHZ_APP_EXTENSION);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t subghz_random_serial(void) {
 | 
					void subghz_lock(SubGhz* subghz) {
 | 
				
			||||||
    return (uint32_t)rand();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_hopper_update(SubGhz* subghz) {
 | 
					 | 
				
			||||||
    furi_assert(subghz);
 | 
					    furi_assert(subghz);
 | 
				
			||||||
 | 
					    subghz->lock = SubGhzLockOn;
 | 
				
			||||||
    switch(subghz->txrx->hopper_state) {
 | 
					 | 
				
			||||||
    case SubGhzHopperStateOFF:
 | 
					 | 
				
			||||||
    case SubGhzHopperStatePause:
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    case SubGhzHopperStateRSSITimeOut:
 | 
					 | 
				
			||||||
        if(subghz->txrx->hopper_timeout != 0) {
 | 
					 | 
				
			||||||
            subghz->txrx->hopper_timeout--;
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    float rssi = -127.0f;
 | 
					 | 
				
			||||||
    if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) {
 | 
					 | 
				
			||||||
        // See RSSI Calculation timings in CC1101 17.3 RSSI
 | 
					 | 
				
			||||||
        rssi = furi_hal_subghz_get_rssi();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Stay if RSSI is high enough
 | 
					 | 
				
			||||||
        if(rssi > -90.0f) {
 | 
					 | 
				
			||||||
            subghz->txrx->hopper_timeout = 10;
 | 
					 | 
				
			||||||
            subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut;
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // Select next frequency
 | 
					 | 
				
			||||||
    if(subghz->txrx->hopper_idx_frequency <
 | 
					 | 
				
			||||||
       subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) {
 | 
					 | 
				
			||||||
        subghz->txrx->hopper_idx_frequency++;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        subghz->txrx->hopper_idx_frequency = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
 | 
					 | 
				
			||||||
        subghz_rx_end(subghz);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
 | 
					 | 
				
			||||||
        subghz_receiver_reset(subghz->txrx->receiver);
 | 
					 | 
				
			||||||
        subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency(
 | 
					 | 
				
			||||||
            subghz->setting, subghz->txrx->hopper_idx_frequency);
 | 
					 | 
				
			||||||
        subghz_rx(subghz, subghz->txrx->preset->frequency);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_speaker_on(SubGhz* subghz) {
 | 
					void subghz_unlock(SubGhz* subghz) {
 | 
				
			||||||
    if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
 | 
					    furi_assert(subghz);
 | 
				
			||||||
        if(furi_hal_speaker_acquire(30)) {
 | 
					    subghz->lock = SubGhzLockOff;
 | 
				
			||||||
            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_speaker_off(SubGhz* subghz) {
 | 
					bool subghz_is_locked(SubGhz* subghz) {
 | 
				
			||||||
    if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) {
 | 
					    furi_assert(subghz);
 | 
				
			||||||
        if(furi_hal_speaker_is_mine()) {
 | 
					    return (subghz->lock == SubGhzLockOn);
 | 
				
			||||||
            furi_hal_subghz_set_async_mirror_pin(NULL);
 | 
					 | 
				
			||||||
            furi_hal_speaker_release();
 | 
					 | 
				
			||||||
            if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown)
 | 
					 | 
				
			||||||
                subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_speaker_mute(SubGhz* subghz) {
 | 
					void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) {
 | 
				
			||||||
    if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
 | 
					    furi_assert(subghz);
 | 
				
			||||||
        if(furi_hal_speaker_is_mine()) {
 | 
					    subghz->rx_key_state = state;
 | 
				
			||||||
            furi_hal_subghz_set_async_mirror_pin(NULL);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_speaker_unmute(SubGhz* subghz) {
 | 
					SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) {
 | 
				
			||||||
    if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
 | 
					    furi_assert(subghz);
 | 
				
			||||||
        if(furi_hal_speaker_is_mine()) {
 | 
					    return subghz->rx_key_state;
 | 
				
			||||||
            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -25,10 +25,6 @@
 | 
				
			|||||||
#include <gui/modules/widget.h>
 | 
					#include <gui/modules/widget.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <subghz/scenes/subghz_scene.h>
 | 
					#include <subghz/scenes/subghz_scene.h>
 | 
				
			||||||
#include <lib/subghz/subghz_worker.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/subghz_setting.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/receiver.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/transmitter.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "subghz_history.h"
 | 
					#include "subghz_history.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -37,34 +33,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "rpc/rpc_app.h"
 | 
					#include "rpc/rpc_app.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "helpers/subghz_threshold_rssi.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "helpers/subghz_txrx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SUBGHZ_MAX_LEN_NAME 64
 | 
					#define SUBGHZ_MAX_LEN_NAME 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct SubGhzTxRx {
 | 
					 | 
				
			||||||
    SubGhzWorker* worker;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SubGhzEnvironment* environment;
 | 
					 | 
				
			||||||
    SubGhzReceiver* receiver;
 | 
					 | 
				
			||||||
    SubGhzTransmitter* transmitter;
 | 
					 | 
				
			||||||
    SubGhzProtocolFlag filter;
 | 
					 | 
				
			||||||
    SubGhzProtocolDecoderBase* decoder_result;
 | 
					 | 
				
			||||||
    FlipperFormat* fff_data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SubGhzRadioPreset* preset;
 | 
					 | 
				
			||||||
    SubGhzHistory* history;
 | 
					 | 
				
			||||||
    uint16_t idx_menu_chosen;
 | 
					 | 
				
			||||||
    SubGhzTxRxState txrx_state;
 | 
					 | 
				
			||||||
    SubGhzHopperState hopper_state;
 | 
					 | 
				
			||||||
    SubGhzSpeakerState speaker_state;
 | 
					 | 
				
			||||||
    uint8_t hopper_timeout;
 | 
					 | 
				
			||||||
    uint8_t hopper_idx_frequency;
 | 
					 | 
				
			||||||
    SubGhzRxKeyState rx_key_state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    float raw_threshold_rssi;
 | 
					 | 
				
			||||||
    uint8_t raw_threshold_rssi_low_count;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SubGhzTxRx SubGhzTxRx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct SubGhz {
 | 
					struct SubGhz {
 | 
				
			||||||
    Gui* gui;
 | 
					    Gui* gui;
 | 
				
			||||||
    NotificationApp* notifications;
 | 
					    NotificationApp* notifications;
 | 
				
			||||||
@ -93,47 +67,43 @@ struct SubGhz {
 | 
				
			|||||||
    SubGhzTestStatic* subghz_test_static;
 | 
					    SubGhzTestStatic* subghz_test_static;
 | 
				
			||||||
    SubGhzTestCarrier* subghz_test_carrier;
 | 
					    SubGhzTestCarrier* subghz_test_carrier;
 | 
				
			||||||
    SubGhzTestPacket* subghz_test_packet;
 | 
					    SubGhzTestPacket* subghz_test_packet;
 | 
				
			||||||
    FuriString* error_str;
 | 
					 | 
				
			||||||
    SubGhzSetting* setting;
 | 
					 | 
				
			||||||
    SubGhzLock lock;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SubGhzProtocolFlag filter;
 | 
				
			||||||
 | 
					    FuriString* error_str;
 | 
				
			||||||
 | 
					    SubGhzLock lock;
 | 
				
			||||||
 | 
					    SubGhzThresholdRssi* threshold_rssi;
 | 
				
			||||||
 | 
					    SubGhzRxKeyState rx_key_state;
 | 
				
			||||||
 | 
					    SubGhzHistory* history;
 | 
				
			||||||
 | 
					    uint16_t idx_menu_chosen;
 | 
				
			||||||
 | 
					    SubGhzLoadTypeFile load_type_file;
 | 
				
			||||||
    void* rpc_ctx;
 | 
					    void* rpc_ctx;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_preset_init(
 | 
					void subghz_set_default_preset(SubGhz* subghz);
 | 
				
			||||||
    void* context,
 | 
					void subghz_blink_start(SubGhz* subghz);
 | 
				
			||||||
    const char* preset_name,
 | 
					void subghz_blink_stop(SubGhz* subghz);
 | 
				
			||||||
    uint32_t frequency,
 | 
					 | 
				
			||||||
    uint8_t* preset_data,
 | 
					 | 
				
			||||||
    size_t preset_data_size);
 | 
					 | 
				
			||||||
bool subghz_set_preset(SubGhz* subghz, const char* preset);
 | 
					 | 
				
			||||||
void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation);
 | 
					 | 
				
			||||||
void subghz_begin(SubGhz* subghz, uint8_t* preset_data);
 | 
					 | 
				
			||||||
uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
 | 
					 | 
				
			||||||
void subghz_rx_end(SubGhz* subghz);
 | 
					 | 
				
			||||||
void subghz_sleep(SubGhz* subghz);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_blink_start(SubGhz* instance);
 | 
					 | 
				
			||||||
void subghz_blink_stop(SubGhz* instance);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format);
 | 
					bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format);
 | 
				
			||||||
void subghz_tx_stop(SubGhz* subghz);
 | 
					 | 
				
			||||||
void subghz_dialog_message_show_only_rx(SubGhz* subghz);
 | 
					void subghz_dialog_message_show_only_rx(SubGhz* subghz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog);
 | 
					bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog);
 | 
				
			||||||
bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len);
 | 
					bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len);
 | 
				
			||||||
bool subghz_save_protocol_to_file(
 | 
					bool subghz_save_protocol_to_file(
 | 
				
			||||||
    SubGhz* subghz,
 | 
					    SubGhz* subghz,
 | 
				
			||||||
    FlipperFormat* flipper_format,
 | 
					    FlipperFormat* flipper_format,
 | 
				
			||||||
    const char* dev_file_name);
 | 
					    const char* dev_file_name);
 | 
				
			||||||
 | 
					void subghz_save_to_file(void* context);
 | 
				
			||||||
bool subghz_load_protocol_from_file(SubGhz* subghz);
 | 
					bool subghz_load_protocol_from_file(SubGhz* subghz);
 | 
				
			||||||
bool subghz_rename_file(SubGhz* subghz);
 | 
					bool subghz_rename_file(SubGhz* subghz);
 | 
				
			||||||
bool subghz_file_available(SubGhz* subghz);
 | 
					bool subghz_file_available(SubGhz* subghz);
 | 
				
			||||||
bool subghz_delete_file(SubGhz* subghz);
 | 
					bool subghz_delete_file(SubGhz* subghz);
 | 
				
			||||||
void subghz_file_name_clear(SubGhz* subghz);
 | 
					void subghz_file_name_clear(SubGhz* subghz);
 | 
				
			||||||
bool subghz_path_is_file(FuriString* path);
 | 
					bool subghz_path_is_file(FuriString* path);
 | 
				
			||||||
uint32_t subghz_random_serial(void);
 | 
					SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz);
 | 
				
			||||||
void subghz_hopper_update(SubGhz* subghz);
 | 
					
 | 
				
			||||||
void subghz_speaker_on(SubGhz* subghz);
 | 
					void subghz_lock(SubGhz* subghz);
 | 
				
			||||||
void subghz_speaker_off(SubGhz* subghz);
 | 
					void subghz_unlock(SubGhz* subghz);
 | 
				
			||||||
void subghz_speaker_mute(SubGhz* subghz);
 | 
					bool subghz_is_locked(SubGhz* subghz);
 | 
				
			||||||
void subghz_speaker_unmute(SubGhz* subghz);
 | 
					
 | 
				
			||||||
 | 
					void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state);
 | 
				
			||||||
 | 
					SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz);
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@
 | 
				
			|||||||
#define MENU_ITEMS 4u
 | 
					#define MENU_ITEMS 4u
 | 
				
			||||||
#define UNLOCK_CNT 3
 | 
					#define UNLOCK_CNT 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
 | 
					#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    FuriString* item_str;
 | 
					    FuriString* item_str;
 | 
				
			||||||
@ -44,7 +44,7 @@ typedef enum {
 | 
				
			|||||||
} SubGhzViewReceiverBarShow;
 | 
					} SubGhzViewReceiverBarShow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct SubGhzViewReceiver {
 | 
					struct SubGhzViewReceiver {
 | 
				
			||||||
    SubGhzLock lock;
 | 
					    bool lock;
 | 
				
			||||||
    uint8_t lock_count;
 | 
					    uint8_t lock_count;
 | 
				
			||||||
    FuriTimer* timer;
 | 
					    FuriTimer* timer;
 | 
				
			||||||
    View* view;
 | 
					    View* view;
 | 
				
			||||||
@ -70,20 +70,21 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) {
 | 
				
			|||||||
        instance->view,
 | 
					        instance->view,
 | 
				
			||||||
        SubGhzViewReceiverModel * model,
 | 
					        SubGhzViewReceiverModel * model,
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
 | 
					            if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
 | 
				
			||||||
                model->u_rssi = 0;
 | 
					                model->u_rssi = 0;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
 | 
					                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        true);
 | 
					        true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) {
 | 
					void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) {
 | 
				
			||||||
    furi_assert(subghz_receiver);
 | 
					    furi_assert(subghz_receiver);
 | 
				
			||||||
    subghz_receiver->lock_count = 0;
 | 
					    subghz_receiver->lock_count = 0;
 | 
				
			||||||
    if(lock == SubGhzLockOn) {
 | 
					
 | 
				
			||||||
        subghz_receiver->lock = lock;
 | 
					    if(lock == true) {
 | 
				
			||||||
 | 
					        subghz_receiver->lock = true;
 | 
				
			||||||
        with_view_model(
 | 
					        with_view_model(
 | 
				
			||||||
            subghz_receiver->view,
 | 
					            subghz_receiver->view,
 | 
				
			||||||
            SubGhzViewReceiverModel * model,
 | 
					            SubGhzViewReceiverModel * model,
 | 
				
			||||||
@ -280,7 +281,7 @@ static void subghz_view_receiver_timer_callback(void* context) {
 | 
				
			|||||||
        subghz_receiver->callback(
 | 
					        subghz_receiver->callback(
 | 
				
			||||||
            SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context);
 | 
					            SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        subghz_receiver->lock = SubGhzLockOff;
 | 
					        subghz_receiver->lock = false;
 | 
				
			||||||
        subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context);
 | 
					        subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    subghz_receiver->lock_count = 0;
 | 
					    subghz_receiver->lock_count = 0;
 | 
				
			||||||
@ -290,7 +291,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
 | 
				
			|||||||
    furi_assert(context);
 | 
					    furi_assert(context);
 | 
				
			||||||
    SubGhzViewReceiver* subghz_receiver = context;
 | 
					    SubGhzViewReceiver* subghz_receiver = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(subghz_receiver->lock == SubGhzLockOn) {
 | 
					    if(subghz_receiver->lock == true) {
 | 
				
			||||||
        with_view_model(
 | 
					        with_view_model(
 | 
				
			||||||
            subghz_receiver->view,
 | 
					            subghz_receiver->view,
 | 
				
			||||||
            SubGhzViewReceiverModel * model,
 | 
					            SubGhzViewReceiverModel * model,
 | 
				
			||||||
@ -310,7 +311,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
 | 
				
			|||||||
                SubGhzViewReceiverModel * model,
 | 
					                SubGhzViewReceiverModel * model,
 | 
				
			||||||
                { model->bar_show = SubGhzViewReceiverBarShowUnlock; },
 | 
					                { model->bar_show = SubGhzViewReceiverBarShowUnlock; },
 | 
				
			||||||
                true);
 | 
					                true);
 | 
				
			||||||
            //subghz_receiver->lock = SubGhzLockOff;
 | 
					            //subghz_receiver->lock = false;
 | 
				
			||||||
            furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650));
 | 
					            furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -394,7 +395,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
 | 
				
			|||||||
    // View allocation and configuration
 | 
					    // View allocation and configuration
 | 
				
			||||||
    subghz_receiver->view = view_alloc();
 | 
					    subghz_receiver->view = view_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz_receiver->lock = SubGhzLockOff;
 | 
					    subghz_receiver->lock = false;
 | 
				
			||||||
    subghz_receiver->lock_count = 0;
 | 
					    subghz_receiver->lock_count = 0;
 | 
				
			||||||
    view_allocate_model(
 | 
					    view_allocate_model(
 | 
				
			||||||
        subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel));
 | 
					        subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel));
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* contex
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi);
 | 
					void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard);
 | 
					void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_view_receiver_set_callback(
 | 
					void subghz_view_receiver_set_callback(
 | 
				
			||||||
    SubGhzViewReceiver* subghz_receiver,
 | 
					    SubGhzViewReceiver* subghz_receiver,
 | 
				
			||||||
 | 
				
			|||||||
@ -60,10 +60,10 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra
 | 
				
			|||||||
    furi_assert(instance);
 | 
					    furi_assert(instance);
 | 
				
			||||||
    uint8_t u_rssi = 0;
 | 
					    uint8_t u_rssi = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
 | 
					    if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
 | 
				
			||||||
        u_rssi = 0;
 | 
					        u_rssi = 0;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
 | 
					        u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with_view_model(
 | 
					    with_view_model(
 | 
				
			||||||
@ -261,9 +261,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod
 | 
				
			|||||||
    uint8_t x = 118;
 | 
					    uint8_t x = 118;
 | 
				
			||||||
    uint8_t y = 48;
 | 
					    uint8_t y = 48;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) {
 | 
					    if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) {
 | 
				
			||||||
        uint8_t x = 118;
 | 
					        uint8_t x = 118;
 | 
				
			||||||
        y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
 | 
					        y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint8_t width = 3;
 | 
					        uint8_t width = 3;
 | 
				
			||||||
        for(uint8_t i = 0; i < x; i += width * 2) {
 | 
					        for(uint8_t i = 0; i < x; i += width * 2) {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
#include <gui/view.h>
 | 
					#include <gui/view.h>
 | 
				
			||||||
#include "../helpers/subghz_custom_event.h"
 | 
					#include "../helpers/subghz_custom_event.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
 | 
					#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct SubGhzReadRAW SubGhzReadRAW;
 | 
					typedef struct SubGhzReadRAW SubGhzReadRAW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ typedef struct {
 | 
				
			|||||||
    FuriString* frequency_str;
 | 
					    FuriString* frequency_str;
 | 
				
			||||||
    FuriString* preset_str;
 | 
					    FuriString* preset_str;
 | 
				
			||||||
    FuriString* key_str;
 | 
					    FuriString* key_str;
 | 
				
			||||||
    uint8_t show_button;
 | 
					    bool show_button;
 | 
				
			||||||
} SubGhzViewTransmitterModel;
 | 
					} SubGhzViewTransmitterModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_view_transmitter_set_callback(
 | 
					void subghz_view_transmitter_set_callback(
 | 
				
			||||||
@ -32,7 +32,7 @@ void subghz_view_transmitter_add_data_to_show(
 | 
				
			|||||||
    const char* key_str,
 | 
					    const char* key_str,
 | 
				
			||||||
    const char* frequency_str,
 | 
					    const char* frequency_str,
 | 
				
			||||||
    const char* preset_str,
 | 
					    const char* preset_str,
 | 
				
			||||||
    uint8_t show_button) {
 | 
					    bool show_button) {
 | 
				
			||||||
    furi_assert(subghz_transmitter);
 | 
					    furi_assert(subghz_transmitter);
 | 
				
			||||||
    with_view_model(
 | 
					    with_view_model(
 | 
				
			||||||
        subghz_transmitter->view,
 | 
					        subghz_transmitter->view,
 | 
				
			||||||
@ -104,7 +104,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
 | 
				
			|||||||
                furi_string_reset(model->frequency_str);
 | 
					                furi_string_reset(model->frequency_str);
 | 
				
			||||||
                furi_string_reset(model->preset_str);
 | 
					                furi_string_reset(model->preset_str);
 | 
				
			||||||
                furi_string_reset(model->key_str);
 | 
					                furi_string_reset(model->key_str);
 | 
				
			||||||
                model->show_button = 0;
 | 
					                model->show_button = false;
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            false);
 | 
					            false);
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
 | 
				
			|||||||
@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show(
 | 
				
			|||||||
    const char* key_str,
 | 
					    const char* key_str,
 | 
				
			||||||
    const char* frequency_str,
 | 
					    const char* frequency_str,
 | 
				
			||||||
    const char* preset_str,
 | 
					    const char* preset_str,
 | 
				
			||||||
    uint8_t show_button);
 | 
					    bool show_button);
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@ SubGhzEnvironment* subghz_environment_alloc() {
 | 
				
			|||||||
    instance->protocol_registry = NULL;
 | 
					    instance->protocol_registry = NULL;
 | 
				
			||||||
    instance->came_atomo_rainbow_table_file_name = NULL;
 | 
					    instance->came_atomo_rainbow_table_file_name = NULL;
 | 
				
			||||||
    instance->nice_flor_s_rainbow_table_file_name = NULL;
 | 
					    instance->nice_flor_s_rainbow_table_file_name = NULL;
 | 
				
			||||||
 | 
					    instance->alutech_at_4n_rainbow_table_file_name = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return instance;
 | 
					    return instance;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -26,6 +27,7 @@ void subghz_environment_free(SubGhzEnvironment* instance) {
 | 
				
			|||||||
    instance->protocol_registry = NULL;
 | 
					    instance->protocol_registry = NULL;
 | 
				
			||||||
    instance->came_atomo_rainbow_table_file_name = NULL;
 | 
					    instance->came_atomo_rainbow_table_file_name = NULL;
 | 
				
			||||||
    instance->nice_flor_s_rainbow_table_file_name = NULL;
 | 
					    instance->nice_flor_s_rainbow_table_file_name = NULL;
 | 
				
			||||||
 | 
					    instance->alutech_at_4n_rainbow_table_file_name = NULL;
 | 
				
			||||||
    subghz_keystore_free(instance->keystore);
 | 
					    subghz_keystore_free(instance->keystore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    free(instance);
 | 
					    free(instance);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user