From 6daa0f3b3545af15caf829526f79ff3c9ec0870f Mon Sep 17 00:00:00 2001 From: Daniel Isenhower Date: Tue, 2 Aug 2022 00:16:42 -0500 Subject: [PATCH] re-implemented auto-detect raw --- .../subghz/scenes/subghz_scene_read_raw.c | 8 +- .../scenes/subghz_scene_receiver_config.c | 53 ++++++ applications/subghz/subghz_history.c | 15 +- applications/subghz/views/receiver.c | 1 + lib/subghz/protocols/raw.c | 160 +++++++++++++++++- lib/subghz/protocols/raw.h | 40 ++++- lib/subghz/receiver.c | 7 +- lib/subghz/receiver.h | 7 + 8 files changed, 279 insertions(+), 12 deletions(-) diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index 726d40b0aae..2db992ecacc 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -99,6 +99,12 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME); furi_assert(subghz->txrx->decoder_result); + // make sure we're not in auto-detect mode, which is only meant for the Read app + subghz_protocol_decoder_raw_set_auto_mode( + subghz->txrx->decoder_result, + false + ); + //set filter RAW feed subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); @@ -339,4 +345,4 @@ void subghz_scene_read_raw_on_exit(void* context) { //filter restoration subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); -} \ No newline at end of file +} diff --git a/applications/subghz/scenes/subghz_scene_receiver_config.c b/applications/subghz/scenes/subghz_scene_receiver_config.c index 590b51d1598..f2db5f47e68 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/subghz/scenes/subghz_scene_receiver_config.c @@ -1,9 +1,12 @@ #include "../subghz_i.h" +#include + enum SubGhzSettingIndex { SubGhzSettingIndexFrequency, SubGhzSettingIndexHopping, SubGhzSettingIndexModulation, + SubGhzSettingIndexDetectRaw, SubGhzSettingIndexLock, }; @@ -17,6 +20,16 @@ const uint32_t hopping_value[HOPPING_COUNT] = { SubGhzHopperStateRunnig, }; +#define DETECT_RAW_COUNT 2 +const char* const detect_raw_text[DETECT_RAW_COUNT] = { + "OFF", + "ON", +}; +const SubGhzProtocolFlag detect_raw_value[DETECT_RAW_COUNT] = { + SubGhzProtocolFlag_Decodable, + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_RAW, +}; + uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { furi_assert(context); SubGhz* subghz = context; @@ -67,6 +80,20 @@ uint8_t subghz_scene_receiver_config_hopper_value_index( } } +uint8_t subghz_scene_receiver_config_detect_raw_value_index( + const SubGhzProtocolFlag value, + const SubGhzProtocolFlag values[], + uint8_t values_count) { + uint8_t index = 0; + for(uint8_t i = 0; i < values_count; i++) { + if(value == values[i]) { + index = i; + break; + } + } + return index; +} + static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -99,6 +126,18 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { subghz_setting_get_preset_data_size(subghz->setting, index)); } +static void subghz_scene_receiver_config_set_detect_raw(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, detect_raw_text[index]); + subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]); + subghz_protocol_decoder_raw_set_auto_mode( + subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), + (index == 1) + ); +} + static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -193,6 +232,20 @@ void subghz_scene_receiver_config_on_enter(void* context) { variable_item_set_current_value_text( item, subghz_setting_get_preset_name(subghz->setting, value_index)); + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != + SubGhzCustomEventManagerSet) { + item = variable_item_list_add( + subghz->variable_item_list, + "Detect Raw:", + DETECT_RAW_COUNT, + subghz_scene_receiver_config_set_detect_raw, + subghz); + value_index = subghz_scene_receiver_config_detect_raw_value_index( + subghz_receiver_get_filter(subghz->txrx->receiver), detect_raw_value, DETECT_RAW_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, detect_raw_text[value_index]); + } + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { variable_item_list_add(subghz->variable_item_list, "Lock Keyboard", 1, NULL, NULL); diff --git a/applications/subghz/subghz_history.c b/applications/subghz/subghz_history.c index 180a91f2952..c2299183d7a 100644 --- a/applications/subghz/subghz_history.c +++ b/applications/subghz/subghz_history.c @@ -180,7 +180,20 @@ bool subghz_history_add_to_history( FURI_LOG_E(TAG, "Missing Protocol"); break; } - if(!strcmp(string_get_cstr(instance->tmp_string), "KeeLoq")) { + if(!strcmp(string_get_cstr(instance->tmp_string), "RAW")) { + string_printf( + item->item_str, + "RAW %03ld.%02ld", + preset->frequency / 1000000 % 1000, + preset->frequency / 10000 % 100); + + if(!flipper_format_rewind(item->flipper_string)) { + FURI_LOG_E(TAG, "Rewind error"); + } + + break; + } + else if(!strcmp(string_get_cstr(instance->tmp_string), "KeeLoq")) { string_set_str(instance->tmp_string, "KL "); if(!flipper_format_read_string(item->flipper_string, "Manufacture", text)) { FURI_LOG_E(TAG, "Missing Protocol"); diff --git a/applications/subghz/views/receiver.c b/applications/subghz/views/receiver.c index c28c3363613..10cee13c29a 100644 --- a/applications/subghz/views/receiver.c +++ b/applications/subghz/views/receiver.c @@ -33,6 +33,7 @@ static const Icon* ReceiverItemIcons[] = { [SubGhzProtocolTypeUnknown] = &I_Quest_7x8, [SubGhzProtocolTypeStatic] = &I_Unlock_7x8, [SubGhzProtocolTypeDynamic] = &I_Lock_7x8, + [SubGhzProtocolTypeRAW] = &I_Unlock_7x8, }; typedef enum { diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index ec4ed41f4cf..9dac2c77995 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -8,11 +8,16 @@ #include "../blocks/generic.h" #include "../blocks/math.h" +#include #include #include +#include #define TAG "SubGhzProtocolRAW" #define SUBGHZ_DOWNLOAD_MAX_SIZE 512 +#define SUBGHZ_AUTO_DETECT_DOWNLOAD_MAX_SIZE 2048 +#define SUBGHZ_AUTO_DETECT_RAW_THRESHOLD -72.0f +#define SUBGHZ_AUTO_DETECT_RAW_POSTROLL_FRAMES 30 static const SubGhzBlockConst subghz_protocol_raw_const = { .te_short = 50, @@ -24,6 +29,8 @@ static const SubGhzBlockConst subghz_protocol_raw_const = { struct SubGhzProtocolDecoderRAW { SubGhzProtocolDecoderBase base; + SubGhzBlockDecoder decoder; + int32_t* upload_raw; uint16_t ind_write; Storage* storage; @@ -32,6 +39,9 @@ struct SubGhzProtocolDecoderRAW { string_t file_name; size_t sample_write; bool last_level; + bool auto_mode; + bool has_rssi_above_threshold; + uint8_t postroll_frames; }; struct SubGhzProtocolEncoderRAW { @@ -55,8 +65,8 @@ const SubGhzProtocolDecoder subghz_protocol_raw_decoder = { .feed = subghz_protocol_decoder_raw_feed, .reset = subghz_protocol_decoder_raw_reset, - .get_hash_data = NULL, - .serialize = NULL, + .get_hash_data = subghz_protocol_decoder_raw_get_hash_data, + .serialize = subghz_protocol_decoder_raw_serialize, .get_string = subghz_protocol_decoder_raw_get_string, }; @@ -197,6 +207,25 @@ void subghz_protocol_raw_save_to_file_stop(SubGhzProtocolDecoderRAW* instance) { instance->file_is_open = RAWFileIsOpenClose; } +void subghz_protocol_decoder_raw_set_auto_mode(void* context, bool auto_mode) { + furi_assert(context); + SubGhzProtocolDecoderRAW* instance = context; + instance->auto_mode = auto_mode; + + if (auto_mode) { + if (instance->upload_raw == NULL) { + instance->upload_raw = malloc(SUBGHZ_AUTO_DETECT_DOWNLOAD_MAX_SIZE * sizeof(int32_t)); + } + } else { + if (instance->upload_raw != NULL) { + free(instance->upload_raw); + instance->upload_raw = NULL; + } + } + + subghz_protocol_decoder_raw_reset(context); +} + size_t subghz_protocol_raw_get_sample_write(SubGhzProtocolDecoderRAW* instance) { return instance->sample_write + instance->ind_write; } @@ -209,6 +238,7 @@ void* subghz_protocol_decoder_raw_alloc(SubGhzEnvironment* environment) { instance->ind_write = 0; instance->last_level = false; instance->file_is_open = RAWFileIsOpenClose; + instance->postroll_frames = 0; string_init(instance->file_name); return instance; @@ -218,6 +248,10 @@ void subghz_protocol_decoder_raw_free(void* context) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; string_clear(instance->file_name); + if (instance->upload_raw != NULL) { + free(instance->upload_raw); + instance->upload_raw = NULL; + } free(instance); } @@ -225,32 +259,80 @@ void subghz_protocol_decoder_raw_reset(void* context) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; instance->ind_write = 0; + instance->has_rssi_above_threshold = false; instance->last_level = false; + instance->postroll_frames = 0; +} + +bool subghz_protocol_decoder_raw_write_data(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderRAW* instance = context; + + bool wrote_data = false; + + if(instance->last_level != level) { + instance->last_level = (level ? true : false); + instance->upload_raw[instance->ind_write++] = (level ? duration : -duration); + subghz_protocol_blocks_add_bit(&instance->decoder, (level) ? 1 : 0); + wrote_data = true; + } + + if(instance->ind_write == SUBGHZ_AUTO_DETECT_DOWNLOAD_MAX_SIZE) { + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + + return false; + } + + return wrote_data; } void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t duration) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; - if(instance->upload_raw != NULL) { - if(duration > subghz_protocol_raw_const.te_short) { + if(instance->upload_raw != NULL && duration > subghz_protocol_raw_const.te_short) { + if (instance->auto_mode) { + float rssi = furi_hal_subghz_get_rssi(); + if (rssi >= SUBGHZ_AUTO_DETECT_RAW_THRESHOLD) { + subghz_protocol_decoder_raw_write_data(context, level, duration); + instance->has_rssi_above_threshold = true; + instance->postroll_frames = 0; + } else if (instance->has_rssi_above_threshold) { + subghz_protocol_decoder_raw_write_data(instance, level, duration); + instance->postroll_frames++; + + if (instance->postroll_frames >= SUBGHZ_AUTO_DETECT_RAW_POSTROLL_FRAMES) { + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + } + } else { if(instance->last_level != level) { instance->last_level = (level ? true : false); instance->upload_raw[instance->ind_write++] = (level ? duration : -duration); + subghz_protocol_blocks_add_bit(&instance->decoder, (level) ? 1 : 0); } - } - if(instance->ind_write == SUBGHZ_DOWNLOAD_MAX_SIZE) { - subghz_protocol_raw_save_to_file_write(instance); + if(instance->ind_write == SUBGHZ_DOWNLOAD_MAX_SIZE) { + subghz_protocol_raw_save_to_file_write(instance); + } } } } +uint8_t subghz_protocol_decoder_raw_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderRAW* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + void subghz_protocol_decoder_raw_get_string(void* context, string_t output) { furi_assert(context); //SubGhzProtocolDecoderRAW* instance = context; //ToDo no use - string_cat_printf(output, "RAW Date"); + string_cat_printf(output, "RAW Data"); } void* subghz_protocol_encoder_raw_alloc(SubGhzEnvironment* environment) { @@ -320,6 +402,68 @@ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* } while(false); } +bool subghz_protocol_decoder_raw_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderRAW* instance = context; + if (instance->auto_mode) { + furi_assert(instance); + bool res = false; + string_t temp_str; + string_init(temp_str); + + do { + stream_clean(flipper_format_get_raw_stream(flipper_format)); + if(!flipper_format_write_header_cstr( + flipper_format, SUBGHZ_RAW_FILE_TYPE, SUBGHZ_RAW_FILE_VERSION)) { + FURI_LOG_E(TAG, "Unable to add header"); + break; + } + + if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { + FURI_LOG_E(TAG, "Unable to add Frequency"); + break; + } + subghz_block_generic_get_preset_name(string_get_cstr(preset->name), temp_str); + if(!flipper_format_write_string_cstr( + flipper_format, "Preset", string_get_cstr(temp_str))) { + FURI_LOG_E(TAG, "Unable to add Preset"); + break; + } + if(!strcmp(string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { + if(!flipper_format_write_string_cstr( + flipper_format, "Custom_preset_module", "CC1101")) { + FURI_LOG_E(TAG, "Unable to add Custom_preset_module"); + break; + } + if(!flipper_format_write_hex( + flipper_format, "Custom_preset_data", preset->data, preset->data_size)) { + FURI_LOG_E(TAG, "Unable to add Custom_preset_data"); + break; + } + } + if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->base.protocol->name)) { + FURI_LOG_E(TAG, "Unable to add Protocol"); + break; + } + + if (!flipper_format_write_int32(flipper_format, "RAW_Data", instance->upload_raw, instance->ind_write)) { + FURI_LOG_E(TAG, "Unable to add Raw Data"); + break; + } else { + instance->ind_write = 0; + } + res = true; + } while(false); + string_clear(temp_str); + return res; + } else { + return false; + } +} + bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderRAW* instance = context; diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index 5d6bb084e92..5582d7b863b 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -2,6 +2,8 @@ #include "base.h" +#include + #define SUBGHZ_PROTOCOL_RAW_NAME "RAW" typedef void (*SubGhzProtocolEncoderRAWCallbackEnd)(void* context); @@ -25,6 +27,13 @@ bool subghz_protocol_raw_save_to_file_init( const char* dev_name, SubGhzPresetDefinition* preset); +/** + * Set SubGhzProtocolDecoderRAW to auto mode, which allows subghz_scene_receiver to capture RAW. + * @param context Pointer to a SubGhzProtocolDecoderRAW instance + * @param auto_mode Whether or not to enable auto mode + */ +void subghz_protocol_decoder_raw_set_auto_mode(void* context, bool auto_mode); + /** * Stop writing file to flash * @param instance Pointer to a SubGhzProtocolDecoderRAW instance @@ -57,6 +66,15 @@ void subghz_protocol_decoder_raw_free(void* context); */ void subghz_protocol_decoder_raw_reset(void* context); +/** + * Write raw data to the instance's internal buffer. + * @param context Pointer to a SubGhzProtocolDecoderRAW instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + * @return whether or not data was written + */ +bool subghz_protocol_decoder_raw_write_data(void* context, bool level, uint32_t duration); + /** * Parse a raw sequence of levels and durations received from the air. * @param context Pointer to a SubGhzProtocolDecoderRAW instance @@ -65,6 +83,13 @@ void subghz_protocol_decoder_raw_reset(void* context); */ void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t duration); +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderRAW instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_raw_get_hash_data(void* context); + /** * Getting a textual representation of the received data. * @param context Pointer to a SubGhzProtocolDecoderRAW instance @@ -115,6 +140,19 @@ void subghz_protocol_raw_file_encoder_worker_set_callback_end( */ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path); +/** + * Serialize data SubGhzProtocolDecoderRAW. + * @param context Pointer to a SubGhzProtocolDecoderRAW instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param frequency The frequency at which the signal was received, Hz + * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset + * @return true On success + */ +bool subghz_protocol_decoder_raw_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + /** * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderRAW instance @@ -126,6 +164,6 @@ bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipp /** * Getting the level and duration of the upload to be loaded into DMA. * @param context Pointer to a SubGhzProtocolEncoderRAW instance - * @return LevelDuration + * @return LevelDuration */ LevelDuration subghz_protocol_encoder_raw_yield(void* context); diff --git a/lib/subghz/receiver.c b/lib/subghz/receiver.c index cf4085df447..129e0091fb0 100644 --- a/lib/subghz/receiver.c +++ b/lib/subghz/receiver.c @@ -61,7 +61,7 @@ void subghz_receiver_decode(SubGhzReceiver* instance, bool level, uint32_t durat for M_EACH(slot, instance->slots, SubGhzReceiverSlotArray_t) { - if((slot->base->protocol->flag & instance->filter) == instance->filter) { + if((slot->base->protocol->flag & instance->filter) != 0) { slot->base->protocol->decoder->feed(slot->base, level, duration); } } @@ -105,6 +105,11 @@ void subghz_receiver_set_filter(SubGhzReceiver* instance, SubGhzProtocolFlag fil instance->filter = filter; } +SubGhzProtocolFlag subghz_receiver_get_filter(SubGhzReceiver* instance) { + furi_assert(instance); + return instance->filter; +} + SubGhzProtocolDecoderBase* subghz_receiver_search_decoder_base_by_name( SubGhzReceiver* instance, const char* decoder_name) { diff --git a/lib/subghz/receiver.h b/lib/subghz/receiver.h index 1357ecbed91..6ea4a3d7d88 100644 --- a/lib/subghz/receiver.h +++ b/lib/subghz/receiver.h @@ -55,6 +55,13 @@ void subghz_receiver_set_rx_callback( */ void subghz_receiver_set_filter(SubGhzReceiver* instance, SubGhzProtocolFlag filter); +/** + * Get the filter of receivers that will work at the moment. + * @param instance Pointer to a SubGhzReceiver instance + * @return filter Filter, SubGhzProtocolFlag + */ +SubGhzProtocolFlag subghz_receiver_get_filter(SubGhzReceiver* instance); + /** * Search for a cattery by his name. * @param instance Pointer to a SubGhzReceiver instance