#include "raw.h" #include #include "../subghz_file_encoder_worker.h" #include "../blocks/const.h" #include "../blocks/decoder.h" #include "../blocks/encoder.h" #include "../blocks/generic.h" #include "../blocks/math.h" #include #include #define TAG "SubGhzProtocolRAW" #define SUBGHZ_DOWNLOAD_MAX_SIZE 512 static const SubGhzBlockConst subghz_protocol_raw_const = { .te_short = 80, .te_long = 32700, .te_delta = 0, .min_count_bit_for_found = 0, }; struct SubGhzProtocolDecoderRAW { SubGhzProtocolDecoderBase base; int32_t* upload_raw; uint16_t ind_write; Storage* storage; FlipperFormat* flipper_file; uint32_t file_is_open; string_t file_name; size_t sample_write; bool last_level; }; struct SubGhzProtocolEncoderRAW { SubGhzProtocolEncoderBase base; bool is_runing; string_t file_name; SubGhzFileEncoderWorker* file_worker_encoder; }; typedef enum { RAWFileIsOpenClose = 0, RAWFileIsOpenWrite, RAWFileIsOpenRead, } RAWFilIsOpen; const SubGhzProtocolDecoder subghz_protocol_raw_decoder = { .alloc = subghz_protocol_decoder_raw_alloc, .free = subghz_protocol_decoder_raw_free, .feed = subghz_protocol_decoder_raw_feed, .reset = subghz_protocol_decoder_raw_reset, .get_hash_data = NULL, .serialize = NULL, .get_string = subghz_protocol_decoder_raw_get_string, }; const SubGhzProtocolEncoder subghz_protocol_raw_encoder = { .alloc = subghz_protocol_encoder_raw_alloc, .free = subghz_protocol_encoder_raw_free, .deserialize = subghz_protocol_encoder_raw_deserialize, .stop = subghz_protocol_encoder_raw_stop, .yield = subghz_protocol_encoder_raw_yield, }; const SubGhzProtocol subghz_protocol_raw = { .name = SUBGHZ_PROTOCOL_RAW_NAME, .type = SubGhzProtocolTypeRAW, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_RAW | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, .decoder = &subghz_protocol_raw_decoder, .encoder = &subghz_protocol_raw_encoder, }; bool subghz_protocol_raw_save_to_file_init( SubGhzProtocolDecoderRAW* instance, const char* dev_name, uint32_t frequency, FuriHalSubGhzPreset preset) { furi_assert(instance); instance->storage = furi_record_open("storage"); instance->flipper_file = flipper_format_file_alloc(instance->storage); string_t temp_str; string_init(temp_str); bool init = false; do { // Create subghz folder directory if necessary if(!storage_simply_mkdir(instance->storage, SUBGHZ_RAW_FOLDER)) { break; } // Create saved directory if necessary if(!storage_simply_mkdir(instance->storage, SUBGHZ_RAW_FOLDER)) { break; } string_set(instance->file_name, dev_name); // First remove subghz device file if it was saved string_printf(temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); if(!storage_simply_remove(instance->storage, string_get_cstr(temp_str))) { break; } // Open file if(!flipper_format_file_open_always(instance->flipper_file, string_get_cstr(temp_str))) { FURI_LOG_E(TAG, "Unable to open file for write: %s", temp_str); break; } if(!flipper_format_write_header_cstr( instance->flipper_file, SUBGHZ_RAW_FILE_TYPE, SUBGHZ_RAW_FILE_VERSION)) { FURI_LOG_E(TAG, "Unable to add header"); break; } if(!flipper_format_write_uint32(instance->flipper_file, "Frequency", &frequency, 1)) { FURI_LOG_E(TAG, "Unable to add Frequency"); break; } if(!subghz_block_generic_get_preset_name(preset, temp_str)) { break; } if(!flipper_format_write_string_cstr( instance->flipper_file, "Preset", string_get_cstr(temp_str))) { FURI_LOG_E(TAG, "Unable to add Preset"); break; } if(!flipper_format_write_string_cstr( instance->flipper_file, "Protocol", instance->base.protocol->name)) { FURI_LOG_E(TAG, "Unable to add Protocol"); break; } instance->upload_raw = malloc(SUBGHZ_DOWNLOAD_MAX_SIZE * sizeof(int32_t)); instance->file_is_open = RAWFileIsOpenWrite; instance->sample_write = 0; init = true; } while(0); string_clear(temp_str); return init; } static bool subghz_protocol_raw_save_to_file_write(SubGhzProtocolDecoderRAW* instance) { furi_assert(instance); bool is_write = false; if(instance->file_is_open == RAWFileIsOpenWrite) { if(!flipper_format_write_int32( instance->flipper_file, "RAW_Data", instance->upload_raw, instance->ind_write)) { FURI_LOG_E(TAG, "Unable to add RAW_Data"); } else { instance->sample_write += instance->ind_write; instance->ind_write = 0; is_write = true; } } return is_write; } void subghz_protocol_raw_save_to_file_stop(SubGhzProtocolDecoderRAW* instance) { furi_assert(instance); if(instance->file_is_open == RAWFileIsOpenWrite && instance->ind_write) subghz_protocol_raw_save_to_file_write(instance); if(instance->file_is_open != RAWFileIsOpenClose) { free(instance->upload_raw); instance->upload_raw = NULL; flipper_format_file_close(instance->flipper_file); flipper_format_free(instance->flipper_file); furi_record_close("storage"); } instance->file_is_open = RAWFileIsOpenClose; } size_t subghz_protocol_raw_get_sample_write(SubGhzProtocolDecoderRAW* instance) { return instance->sample_write + instance->ind_write; } void* subghz_protocol_decoder_raw_alloc(SubGhzEnvironment* environment) { SubGhzProtocolDecoderRAW* instance = malloc(sizeof(SubGhzProtocolDecoderRAW)); instance->base.protocol = &subghz_protocol_raw; instance->upload_raw = NULL; instance->ind_write = 0; instance->last_level = false; instance->file_is_open = RAWFileIsOpenClose; string_init(instance->file_name); return instance; } void subghz_protocol_decoder_raw_free(void* context) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; string_clear(instance->file_name); free(instance); } void subghz_protocol_decoder_raw_reset(void* context) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; instance->ind_write = 0; instance->last_level = false; } 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(duration > subghz_protocol_raw_const.te_long) duration = subghz_protocol_raw_const.te_long; if(instance->last_level != level) { instance->last_level = (level ? true : false); instance->upload_raw[instance->ind_write++] = (level ? duration : -duration); } } if(instance->ind_write == SUBGHZ_DOWNLOAD_MAX_SIZE) { subghz_protocol_raw_save_to_file_write(instance); } } } 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"); } void* subghz_protocol_encoder_raw_alloc(SubGhzEnvironment* environment) { SubGhzProtocolEncoderRAW* instance = malloc(sizeof(SubGhzProtocolEncoderRAW)); instance->base.protocol = &subghz_protocol_raw; string_init(instance->file_name); instance->is_runing = false; return instance; } void subghz_protocol_encoder_raw_stop(void* context) { SubGhzProtocolEncoderRAW* instance = context; instance->is_runing = false; if(subghz_file_encoder_worker_is_running(instance->file_worker_encoder)) { subghz_file_encoder_worker_stop(instance->file_worker_encoder); subghz_file_encoder_worker_free(instance->file_worker_encoder); } } void subghz_protocol_encoder_raw_free(void* context) { furi_assert(context); SubGhzProtocolEncoderRAW* instance = context; subghz_protocol_encoder_raw_stop(instance); string_clear(instance->file_name); free(instance); } void subghz_protocol_raw_file_encoder_worker_set_callback_end( SubGhzProtocolEncoderRAW* instance, SubGhzProtocolEncoderRAWCallbackEnd callback_end, void* context_end) { furi_assert(instance); furi_assert(callback_end); subghz_file_encoder_worker_callback_end( instance->file_worker_encoder, callback_end, context_end); } static bool subghz_protocol_encoder_raw_worker_init(SubGhzProtocolEncoderRAW* instance) { furi_assert(instance); instance->file_worker_encoder = subghz_file_encoder_worker_alloc(); if(subghz_file_encoder_worker_start( instance->file_worker_encoder, string_get_cstr(instance->file_name))) { //the worker needs a file in order to open and read part of the file osDelay(100); instance->is_runing = true; } else { subghz_protocol_encoder_raw_stop(instance); } return instance->is_runing; } void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_name) { string_t temp_str; string_init(temp_str); do { stream_clean(flipper_format_get_raw_stream(flipper_format)); if(!flipper_format_write_string_cstr(flipper_format, "Protocol", "RAW")) { FURI_LOG_E(TAG, "Unable to add Protocol"); break; } string_printf(temp_str, "%s/%s%s", SUBGHZ_APP_FOLDER, file_name, SUBGHZ_APP_EXTENSION); if(!flipper_format_write_string_cstr( flipper_format, "File_name", string_get_cstr(temp_str))) { FURI_LOG_E(TAG, "Unable to add File_name"); break; } } while(false); string_clear(temp_str); } bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderRAW* instance = context; bool res = false; string_t temp_str; string_init(temp_str); do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); break; } if(!flipper_format_read_string(flipper_format, "File_name", temp_str)) { FURI_LOG_E(TAG, "Missing File_name"); break; } string_set(instance->file_name, temp_str); res = subghz_protocol_encoder_raw_worker_init(instance); } while(false); string_clear(temp_str); return res; } LevelDuration subghz_protocol_encoder_raw_yield(void* context) { SubGhzProtocolEncoderRAW* instance = context; if(!instance->is_runing) return level_duration_reset(); return subghz_file_encoder_worker_get_level_duration(instance->file_worker_encoder); }