From 2bd80f510a57fb6c8b1bf0756b93b7ab2c4b833a Mon Sep 17 00:00:00 2001 From: assasinfil Date: Thu, 9 Feb 2023 22:45:02 +0300 Subject: [PATCH] Init encoder --- firmware/targets/f7/api_symbols.csv | 8 +- lib/subghz/protocols/alutech_at_4n.c | 184 ++++++++++++++++++++++++++- lib/subghz/protocols/alutech_at_4n.h | 54 ++++++++ 3 files changed, 239 insertions(+), 7 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 6910c8d35..6b514f7f9 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,14.0,, +Version,+,14.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2616,6 +2616,7 @@ Function,-,subghz_keystore_load,_Bool,"SubGhzKeystore*, const char*" Function,-,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, uint8_t*" Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" +Function,-,subghz_protocol_alutech_at_4n_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" Function,+,subghz_protocol_blocks_add_bytes,uint8_t,"const uint8_t[], size_t" Function,+,subghz_protocol_blocks_add_to_128_bit,void,"SubGhzBlockDecoder*, uint8_t, uint64_t*" @@ -2977,6 +2978,11 @@ Function,-,subghz_protocol_decoder_star_line_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_star_line_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_star_line_reset,void,void* Function,-,subghz_protocol_decoder_star_line_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" +Function,-,subghz_protocol_encoder_alutech_at_4n_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_alutech_at_4n_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_alutech_at_4n_free,void,void* +Function,-,subghz_protocol_encoder_alutech_at_4n_stop,void,void* +Function,-,subghz_protocol_encoder_alutech_at_4n_yield,LevelDuration,void* Function,-,subghz_protocol_encoder_ansonic_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_ansonic_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_ansonic_free,void,void* diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 6bcf9f25d..10da9781c 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -34,6 +34,7 @@ struct SubGhzProtocolEncoderAlutech_at_4n { SubGhzProtocolBlockEncoder encoder; SubGhzBlockGeneric generic; + const char* alutech_at_4n_rainbow_table_file_name; }; typedef enum { @@ -57,23 +58,194 @@ const SubGhzProtocolDecoder subghz_protocol_alutech_at_4n_decoder = { }; const SubGhzProtocolEncoder subghz_protocol_alutech_at_4n_encoder = { - .alloc = NULL, - .free = NULL, + .alloc = subghz_protocol_encoder_alutech_at_4n_alloc, + .free = subghz_protocol_encoder_alutech_at_4n_free, - .deserialize = NULL, - .stop = NULL, - .yield = NULL, + .deserialize = subghz_protocol_encoder_alutech_at_4n_deserialize, + .stop = subghz_protocol_encoder_alutech_at_4n_stop, + .yield = subghz_protocol_encoder_alutech_at_4n_yield, }; const SubGhzProtocol subghz_protocol_alutech_at_4n = { .name = SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME, .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, .decoder = &subghz_protocol_alutech_at_4n_decoder, .encoder = &subghz_protocol_alutech_at_4n_encoder, }; +void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderAlutech_at_4n* instance = + malloc(sizeof(SubGhzProtocolEncoderAlutech_at_4n)); + + instance->base.protocol = &subghz_protocol_alutech_at_4n; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 512; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + + instance->alutech_at_4n_rainbow_table_file_name = + subghz_environment_get_alutech_at_4n_rainbow_table_file_name(environment); + if(instance->alutech_at_4n_rainbow_table_file_name) { + FURI_LOG_I( + TAG, "Loading rainbow table from %s", instance->alutech_at_4n_rainbow_table_file_name); + } + + return instance; +} + +void subghz_protocol_encoder_alutech_at_4n_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + free(instance->encoder.upload); + free(instance); +} + +static bool subghz_protocol_alutech_at_4n_gen_data( + SubGhzProtocolEncoderAlutech_at_4n* instance, + uint8_t btn) { + UNUSED(btn); + + uint64_t data = subghz_protocol_blocks_reverse_key(instance->generic.data, 64); + uint8_t crc = subghz_protocol_blocks_reverse_key(crc, 8); + + if(crc == subghz_protocol_alutech_at_4n_crc(data)) { + data = subghz_protocol_alutech_at_4n_decrypt( + data, instance->alutech_at_4n_rainbow_table_file_name); + } + + if(((uint8_t)(data >> 56) == + subghz_protocol_alutech_at_4n_decrypt_data_crc((uint8_t)((data >> 8) & 0xFF)))) { + instance->generic.btn = (uint8_t)data & 0xFF; + instance->generic.cnt = (uint16_t)(data >> 8) & 0xFFFF; + instance->generic.serial = (uint32_t)(data >> 24) & 0xFFFFFFFF; + } + + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } + + return true; +} + +bool subghz_protocol_alutech_at_4n_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->generic.data_count_bit = 72; + bool res = subghz_protocol_alutech_at_4n_gen_data(instance, btn); + if(res) { + res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + } + return res; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance + * @return true On success + */ +static bool subghz_protocol_encoder_alutech_at_4n_get_upload( + SubGhzProtocolEncoderAlutech_at_4n* instance, + uint8_t btn) { + furi_assert(instance); + + //gen new key + if(subghz_protocol_alutech_at_4n_gen_data(instance, btn)) { + //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 = index; + + 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; + } + return true; +} + +bool subghz_protocol_encoder_alutech_at_4n_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_alutech_at_4n_get_upload(instance, instance->generic.btn); + + 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_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_alutech_at_4n_stop(void* context) { + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context) { + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = 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; +} + /** * Read bytes from rainbow table * @param file_name Full path to rainbow table the file diff --git a/lib/subghz/protocols/alutech_at_4n.h b/lib/subghz/protocols/alutech_at_4n.h index 38bac3ea6..ddf983fc2 100644 --- a/lib/subghz/protocols/alutech_at_4n.h +++ b/lib/subghz/protocols/alutech_at_4n.h @@ -10,6 +10,60 @@ extern const SubGhzProtocolDecoder subghz_protocol_alutech_at_4n_decoder; extern const SubGhzProtocolEncoder subghz_protocol_alutech_at_4n_encoder; extern const SubGhzProtocol subghz_protocol_alutech_at_4n; +/** + * Allocate SubGhzProtocolEncoderAlutech_at_4n. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderAlutech_at_4n* pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + */ +void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderAlutech_at_4n. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + */ +void subghz_protocol_encoder_alutech_at_4n_free(void* context); + +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 24 bit + * @param btn Button number, 8 bit + * @param cnt Counter value, 16 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_alutech_at_4n_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_alutech_at_4n_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + */ +void subghz_protocol_encoder_alutech_at_4n_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context); + /** * Allocate SubGhzProtocolDecoderAlutech_at_4n. * @param environment Pointer to a SubGhzEnvironment instance