diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 1a41904bb..c6e698833 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -59,12 +59,12 @@ const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder = { }; const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder = { - .alloc = NULL, - .free = NULL, + .alloc = subghz_protocol_encoder_faac_slh_alloc, + .free = subghz_protocol_encoder_faac_slh_free, - .deserialize = NULL, - .stop = NULL, - .yield = NULL, + .deserialize = subghz_protocol_encoder_faac_slh_deserialize, + .stop = subghz_protocol_encoder_faac_slh_stop, + .yield = subghz_protocol_encoder_faac_slh_yield, }; const SubGhzProtocol subghz_protocol_faac_slh = { @@ -77,6 +77,218 @@ const SubGhzProtocol subghz_protocol_faac_slh = { .encoder = &subghz_protocol_faac_slh_encoder, }; +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + * @param keystore Pointer to a SubGhzKeystore* instance + * @param manufacture_name + */ +static void subghz_protocol_faac_slh_check_remote_controller + (SubGhzBlockGeneric* instance, + SubGhzKeystore* keystore, + const char** manufacture_name); + +void* subghz_protocol_encoder_faac_slh_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolEncoderFaacSLH* instance = malloc(sizeof(SubGhzProtocolEncoderFaacSLH)); + + instance->base.protocol = &subghz_protocol_faac_slh; + instance->generic.protocol_name = instance->base.protocol->name; + instance->keystore = subghz_environment_get_keystore(environment); + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 256; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_faac_slh_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderFaacSLH* instance = context; + free(instance->encoder.upload); + free(instance); +} + +static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* instance) { + instance->generic.cnt++; + uint32_t fix = instance->generic.data >> 32; + uint32_t hop = 0; + uint32_t decrypt = 0; + uint64_t man = 0; + uint32_t seed = 0; + int res = 0; + char fixx[8] = {}; + int shiftby = 32; + for (int i = 0; i < 8; i++) { + fixx[i] = (fix >> (shiftby -= 4)) & 0xF; + } + if ((instance->generic.cnt % 2) == 0) { + decrypt = fixx[6] << 28 | fixx[7] << 24 | fixx[5] << 20 | + fixx[1] << 16 | instance->generic.cnt; + } + else { + decrypt = fixx[2] << 28 | fixx[3] << 24 | fixx[4] << 20 | + fixx[1] << 16 | instance->generic.cnt; + } + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name); + if(res == 0) { + switch(manufacture_code->type) { + case KEELOQ_LEARNING_FAAC: + //FAAC Learning + man = + subghz_protocol_keeloq_common_faac_learning(fix, seed, manufacture_code->key); + hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); + break; + } + break; + } + } + if(hop) { + instance->generic.data = (uint64_t)fix << 32 | hop; + } + return true; +} + +bool subghz_protocol_faac_slh_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name, + uint32_t frequency, + FuriHalSubGhzPreset preset) { + furi_assert(context); + SubGhzProtocolEncoderFaacSLH* instance = context; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->manufacture_name = manufacture_name; + instance->generic.data_count_bit = 64; + bool res = subghz_protocol_faac_slh_gen_data(instance); + if(res) { + res = + subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); + } + return res; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderFaacSLH instance + * @return true On success + */ +static bool + subghz_protocol_encoder_faac_slh_get_upload(SubGhzProtocolEncoderFaacSLH* instance) { + furi_assert(instance); + + //gen new key + if(subghz_protocol_faac_slh_gen_data(instance)) { + //ToDo if you need to add a callback to automatically update the data on the display + } else { + return false; + } + + size_t index = 0; + size_t size_upload = 2 + (instance->generic.data_count_bit * 2); + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + //Send header + for(uint8_t i = 11; i > 0; i--) { + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_faac_slh_const.te_long * 2); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_faac_slh_const.te_short * 2); + } + + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_faac_slh_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_faac_slh_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_faac_slh_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_faac_slh_const.te_long); + } + } + return true; +} + +bool subghz_protocol_encoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderFaacSLH* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + subghz_protocol_faac_slh_check_remote_controller( + &instance->generic, instance->keystore, &instance->manufacture_name); + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_faac_slh_get_upload(instance); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + 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] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Key"); + break; + } + + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_faac_slh_stop(void* context) { + SubGhzProtocolEncoderFaacSLH* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_faac_slh_yield(void* context) { + SubGhzProtocolEncoderFaacSLH* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + void* subghz_protocol_decoder_faac_slh_alloc(SubGhzEnvironment* environment) { SubGhzProtocolDecoderFaacSLH* instance = malloc(sizeof(SubGhzProtocolDecoderFaacSLH)); instance->base.protocol = &subghz_protocol_faac_slh; diff --git a/lib/subghz/protocols/faac_slh.h b/lib/subghz/protocols/faac_slh.h index 2575a5ff5..b20a1e639 100644 --- a/lib/subghz/protocols/faac_slh.h +++ b/lib/subghz/protocols/faac_slh.h @@ -11,6 +11,62 @@ extern const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder; extern const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder; extern const SubGhzProtocol subghz_protocol_faac_slh; +/** + * Allocate SubGhzProtocolEncoderFaacSLH. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderFaacSLH* pointer to a SubGhzProtocolEncoderFaacSLH instance + */ +void* subghz_protocol_encoder_faac_slh_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderFaacSLH. + * @param context Pointer to a SubGhzProtocolEncoderFaacSLH instance + */ +void subghz_protocol_encoder_faac_slh_free(void* context); + +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderFaacSLH instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 28 bit + * @param btn Button number, 4 bit + * @param cnt Counter value, 16 bit + * @param manufacture_name Name of manufacturer's key + * @param frequency Transmission frequency, Hz + * @param preset Modulation, FuriHalSubGhzPreset + * @return true On success + */ +bool subghz_protocol_faac_slh_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name, + uint32_t frequency, + FuriHalSubGhzPreset preset); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderFaacSLH instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderFaacSLH instance + */ +void subghz_protocol_encoder_faac_slh_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderFaacSLH instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_faac_slh_yield(void* context); + /** * Allocate SubGhzProtocolDecoderFaacSLH. * @param environment Pointer to a SubGhzEnvironment instance