diff options
author | Skorpionm <85568270+Skorpionm@users.noreply.github.com> | 2022-08-07 18:56:45 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-07 18:56:45 +0300 |
commit | 416cce9ffc9819422940978cbc66476150aec900 (patch) | |
tree | 96ae67f85b9dc0789ac8e5d31ae552ce860e4ed9 /lib | |
parent | 81b404aafa3ead93c1496de696bef5c99b21d6fa (diff) |
[FL-2718, FL-2719] SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER / Doitrand / Marantec / Phoenix V2 (static mode) / Phox (static mode), fix Princeton (#1516)
* SubGhz: add protocol marantec
* SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER
* SubGhz: add protocol Doitrand
* SubGhz: delete debug
* SubGhz: add protocol Phoenix V2 (static mode)
* SubGhz: fix serial decode Phoenix V2
* SubGhz: fix Princeton, display serial number and button on boot
* SubGhz: fix Bett decoder and fix unit_test
* SubGhz: update test_random_raw for unit_test
Co-authored-by: あく <alleteam@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/subghz/protocols/bett.c | 357 | ||||
-rw-r--r-- | lib/subghz/protocols/bett.h | 107 | ||||
-rw-r--r-- | lib/subghz/protocols/doitrand.c | 356 | ||||
-rw-r--r-- | lib/subghz/protocols/doitrand.h | 107 | ||||
-rw-r--r-- | lib/subghz/protocols/holtek.c | 2 | ||||
-rw-r--r-- | lib/subghz/protocols/marantec.c | 393 | ||||
-rw-r--r-- | lib/subghz/protocols/marantec.h | 107 | ||||
-rw-r--r-- | lib/subghz/protocols/phoenix_v2.c | 339 | ||||
-rw-r--r-- | lib/subghz/protocols/phoenix_v2.h | 107 | ||||
-rw-r--r-- | lib/subghz/protocols/princeton.c | 25 | ||||
-rw-r--r-- | lib/subghz/protocols/registry.c | 3 | ||||
-rw-r--r-- | lib/subghz/protocols/registry.h | 4 |
12 files changed, 1894 insertions, 13 deletions
diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c new file mode 100644 index 00000000..e32679d2 --- /dev/null +++ b/lib/subghz/protocols/bett.c @@ -0,0 +1,357 @@ +#include "bett.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +// protocol BERNER / ELKA / TEDSEN / TELETASTER +#define TAG "SubGhzProtocolBETT" + +#define DIP_P 0b11 //(+) +#define DIP_O 0b10 //(0) +#define DIP_N 0b00 //(-) + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c" +#define SHOW_DIP_P(dip, check_dip) \ + ((((dip >> 0x8) >> 0x8) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_') + +static const SubGhzBlockConst subghz_protocol_bett_const = { + .te_short = 340, + .te_long = 2000, + .te_delta = 150, + .min_count_bit_for_found = 18, +}; + +struct SubGhzProtocolDecoderBETT { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderBETT { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + BETTDecoderStepReset = 0, + BETTDecoderStepSaveDuration, + BETTDecoderStepCheckDuration, +} BETTDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_bett_decoder = { + .alloc = subghz_protocol_decoder_bett_alloc, + .free = subghz_protocol_decoder_bett_free, + + .feed = subghz_protocol_decoder_bett_feed, + .reset = subghz_protocol_decoder_bett_reset, + + .get_hash_data = subghz_protocol_decoder_bett_get_hash_data, + .serialize = subghz_protocol_decoder_bett_serialize, + .deserialize = subghz_protocol_decoder_bett_deserialize, + .get_string = subghz_protocol_decoder_bett_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_bett_encoder = { + .alloc = subghz_protocol_encoder_bett_alloc, + .free = subghz_protocol_encoder_bett_free, + + .deserialize = subghz_protocol_encoder_bett_deserialize, + .stop = subghz_protocol_encoder_bett_stop, + .yield = subghz_protocol_encoder_bett_yield, +}; + +const SubGhzProtocol subghz_protocol_bett = { + .name = SUBGHZ_PROTOCOL_BETT_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_bett_decoder, + .encoder = &subghz_protocol_bett_encoder, +}; + +void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderBETT* instance = malloc(sizeof(SubGhzProtocolEncoderBETT)); + + instance->base.protocol = &subghz_protocol_bett; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_bett_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderBETT* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderBETT instance + * @return true On success + */ +static bool subghz_protocol_encoder_bett_get_upload(SubGhzProtocolEncoderBETT* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (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; + } + + for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_bett_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_bett_const.te_long); + } + } + if(bit_read(instance->generic.data, 0)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_bett_const.te_short + + subghz_protocol_bett_const.te_long * 7); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_bett_const.te_long + subghz_protocol_bett_const.te_long * 7); + } + return true; +} + +bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderBETT* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_bett_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_bett_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_bett_stop(void* context) { + SubGhzProtocolEncoderBETT* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_bett_yield(void* context) { + SubGhzProtocolEncoderBETT* 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_bett_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderBETT* instance = malloc(sizeof(SubGhzProtocolDecoderBETT)); + instance->base.protocol = &subghz_protocol_bett; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_bett_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + free(instance); +} + +void subghz_protocol_decoder_bett_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + instance->decoder.parser_step = BETTDecoderStepReset; +} + +void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + + switch(instance->decoder.parser_step) { + case BETTDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 42) < + subghz_protocol_bett_const.te_delta * 21)) { + //Found Preambula + instance->decoder.parser_step = BETTDecoderStepCheckDuration; + } + break; + case BETTDecoderStepSaveDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_bett_const.te_short * 10 + + subghz_protocol_bett_const.te_delta)) { + instance->decoder.parser_step = BETTDecoderStepSaveDuration; + if(instance->decoder.decode_count_bit == + subghz_protocol_bett_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + break; + } else { + if((DURATION_DIFF(duration, subghz_protocol_bett_const.te_short) < + subghz_protocol_bett_const.te_delta) || + (DURATION_DIFF(duration, subghz_protocol_bett_const.te_long) < + subghz_protocol_bett_const.te_delta * 3)) { + instance->decoder.parser_step = BETTDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + } + } + break; + case BETTDecoderStepCheckDuration: + if(level) { + if(DURATION_DIFF(duration, subghz_protocol_bett_const.te_long) < + subghz_protocol_bett_const.te_delta * 3) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = BETTDecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, subghz_protocol_bett_const.te_short) < + subghz_protocol_bett_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = BETTDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_bett_check_remote_controller(SubGhzBlockGeneric* instance) { + uint32_t code_found_reverse = + subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); + + instance->serial = (code_found_reverse & 0xFF) << 12 | + ((code_found_reverse >> 8) & 0xFF) << 4 | + ((code_found_reverse >> 20) & 0x0F); + instance->btn = ((code_found_reverse >> 16) & 0x0F); +} + +uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_bett_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_bett_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_bett_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + subghz_protocol_bett_check_remote_controller(&instance->generic); + uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%05lX\r\n" + " +: " DIP_PATTERN "\r\n" + " o: " DIP_PATTERN "\r\n" + " -: " DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0xFFFFFF), + SHOW_DIP_P(data, DIP_P), + SHOW_DIP_P(data, DIP_O), + SHOW_DIP_P(data, DIP_N)); +} diff --git a/lib/subghz/protocols/bett.h b/lib/subghz/protocols/bett.h new file mode 100644 index 00000000..48f32b3e --- /dev/null +++ b/lib/subghz/protocols/bett.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_BETT_NAME "BETT" + +typedef struct SubGhzProtocolDecoderBETT SubGhzProtocolDecoderBETT; +typedef struct SubGhzProtocolEncoderBETT SubGhzProtocolEncoderBETT; + +extern const SubGhzProtocolDecoder subghz_protocol_bett_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_bett_encoder; +extern const SubGhzProtocol subghz_protocol_bett; + +/** + * Allocate SubGhzProtocolEncoderBETT. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderBETT* pointer to a SubGhzProtocolEncoderBETT instance + */ +void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderBETT. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + */ +void subghz_protocol_encoder_bett_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + */ +void subghz_protocol_encoder_bett_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_bett_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderBETT. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderBETT* pointer to a SubGhzProtocolDecoderBETT instance + */ +void* subghz_protocol_decoder_bett_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + */ +void subghz_protocol_decoder_bett_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + */ +void subghz_protocol_decoder_bett_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_bett_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param output Resulting text + */ +void subghz_protocol_decoder_bett_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c new file mode 100644 index 00000000..c26cbc5b --- /dev/null +++ b/lib/subghz/protocols/doitrand.c @@ -0,0 +1,356 @@ +#include "doitrand.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolDoitrand" + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c" +#define CNT_TO_DIP(dip) \ + (dip & 0x0001 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), \ + (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x1000 ? '1' : '0'), \ + (dip & 0x0800 ? '1' : '0'), (dip & 0x0400 ? '1' : '0'), (dip & 0x0200 ? '1' : '0'), \ + (dip & 0x0002 ? '1' : '0') + +static const SubGhzBlockConst subghz_protocol_doitrand_const = { + .te_short = 400, + .te_long = 1100, + .te_delta = 150, + .min_count_bit_for_found = 37, +}; + +struct SubGhzProtocolDecoderDoitrand { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderDoitrand { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + DoitrandDecoderStepReset = 0, + DoitrandDecoderStepFoundStartBit, + DoitrandDecoderStepSaveDuration, + DoitrandDecoderStepCheckDuration, +} DoitrandDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_doitrand_decoder = { + .alloc = subghz_protocol_decoder_doitrand_alloc, + .free = subghz_protocol_decoder_doitrand_free, + + .feed = subghz_protocol_decoder_doitrand_feed, + .reset = subghz_protocol_decoder_doitrand_reset, + + .get_hash_data = subghz_protocol_decoder_doitrand_get_hash_data, + .serialize = subghz_protocol_decoder_doitrand_serialize, + .deserialize = subghz_protocol_decoder_doitrand_deserialize, + .get_string = subghz_protocol_decoder_doitrand_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_doitrand_encoder = { + .alloc = subghz_protocol_encoder_doitrand_alloc, + .free = subghz_protocol_encoder_doitrand_free, + + .deserialize = subghz_protocol_encoder_doitrand_deserialize, + .stop = subghz_protocol_encoder_doitrand_stop, + .yield = subghz_protocol_encoder_doitrand_yield, +}; + +const SubGhzProtocol subghz_protocol_doitrand = { + .name = SUBGHZ_PROTOCOL_DOITRAND_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_doitrand_decoder, + .encoder = &subghz_protocol_doitrand_encoder, +}; + +void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderDoitrand* instance = malloc(sizeof(SubGhzProtocolEncoderDoitrand)); + + instance->base.protocol = &subghz_protocol_doitrand; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 128; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_doitrand_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderDoitrand* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderDoitrand instance + * @return true On success + */ +static bool subghz_protocol_encoder_doitrand_get_upload(SubGhzProtocolEncoderDoitrand* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 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 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_short * 62); + //Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_short * 2 - 100); + //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(false, (uint32_t)subghz_protocol_doitrand_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_long); + } + } + return true; +} + +bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderDoitrand* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_doitrand_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_doitrand_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_doitrand_stop(void* context) { + SubGhzProtocolEncoderDoitrand* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_doitrand_yield(void* context) { + SubGhzProtocolEncoderDoitrand* 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_doitrand_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderDoitrand* instance = malloc(sizeof(SubGhzProtocolDecoderDoitrand)); + instance->base.protocol = &subghz_protocol_doitrand; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_doitrand_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + free(instance); +} + +void subghz_protocol_decoder_doitrand_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + instance->decoder.parser_step = DoitrandDecoderStepReset; +} + +void subghz_protocol_decoder_doitrand_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + + switch(instance->decoder.parser_step) { + case DoitrandDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_short * 62) < + subghz_protocol_doitrand_const.te_delta * 30)) { + //Found Preambula + instance->decoder.parser_step = DoitrandDecoderStepFoundStartBit; + } + break; + case DoitrandDecoderStepFoundStartBit: + if(level && ((DURATION_DIFF(duration, (subghz_protocol_doitrand_const.te_short * 2)) < + subghz_protocol_doitrand_const.te_delta * 3))) { + //Found start bit + instance->decoder.parser_step = DoitrandDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = DoitrandDecoderStepReset; + } + break; + case DoitrandDecoderStepSaveDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_doitrand_const.te_short * 10 + + subghz_protocol_doitrand_const.te_delta)) { + instance->decoder.parser_step = DoitrandDecoderStepFoundStartBit; + if(instance->decoder.decode_count_bit == + subghz_protocol_doitrand_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + break; + } else { + instance->decoder.te_last = duration; + instance->decoder.parser_step = DoitrandDecoderStepCheckDuration; + } + } + break; + case DoitrandDecoderStepCheckDuration: + if(level) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_doitrand_const.te_short) < + subghz_protocol_doitrand_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_long) < + subghz_protocol_doitrand_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = DoitrandDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_doitrand_const.te_long) < + subghz_protocol_doitrand_const.te_delta * 3) && + (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_short) < + subghz_protocol_doitrand_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = DoitrandDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = DoitrandDecoderStepReset; + } + } else { + instance->decoder.parser_step = DoitrandDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_doitrand_check_remote_controller(SubGhzBlockGeneric* instance) { + /* +* 67892345 0 k 1 +* 0000082F5F => 00000000000000000 10 000010111101011111 +* 0002082F5F => 00000000000100000 10 000010111101011111 +* 0200082F5F => 00010000000000000 10 000010111101011111 +* 0400082F5F => 00100000000000000 10 000010111101011111 +* 0800082F5F => 01000000000000000 10 000010111101011111 +* 1000082F5F => 10000000000000000 10 000010111101011111 +* 0020082F5F => 00000001000000000 10 000010111101011111 +* 0040082F5F => 00000010000000000 10 000010111101011111 +* 0080082F5F => 00000100000000000 10 000010111101011111 +* 0100082F5F => 00001000000000000 10 000010111101011111 +* 000008AF5F => 00000000000000000 10 001010111101011111 +* 1FE208AF5F => 11111111000100000 10 001010111101011111 +* +* 0...9 - DIP +* k- KEY +*/ + instance->cnt = (instance->data >> 24) | ((instance->data >> 15) & 0x1); + instance->btn = ((instance->data >> 18) & 0x3); +} + +uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_doitrand_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_doitrand_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_doitrand_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + subghz_protocol_doitrand_check_remote_controller(&instance->generic); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%02lX%08lX\r\n" + "Btn:%lX\r\n" + "DIP:" DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32) & 0xFFFFFFFF, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.btn, + CNT_TO_DIP(instance->generic.cnt)); +} diff --git a/lib/subghz/protocols/doitrand.h b/lib/subghz/protocols/doitrand.h new file mode 100644 index 00000000..f94d7389 --- /dev/null +++ b/lib/subghz/protocols/doitrand.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_DOITRAND_NAME "Doitrand" + +typedef struct SubGhzProtocolDecoderDoitrand SubGhzProtocolDecoderDoitrand; +typedef struct SubGhzProtocolEncoderDoitrand SubGhzProtocolEncoderDoitrand; + +extern const SubGhzProtocolDecoder subghz_protocol_doitrand_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_doitrand_encoder; +extern const SubGhzProtocol subghz_protocol_doitrand; + +/** + * Allocate SubGhzProtocolEncoderDoitrand. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderDoitrand* pointer to a SubGhzProtocolEncoderDoitrand instance + */ +void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderDoitrand. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + */ +void subghz_protocol_encoder_doitrand_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + */ +void subghz_protocol_encoder_doitrand_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_doitrand_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderDoitrand. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderDoitrand* pointer to a SubGhzProtocolDecoderDoitrand instance + */ +void* subghz_protocol_decoder_doitrand_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + */ +void subghz_protocol_decoder_doitrand_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + */ +void subghz_protocol_decoder_doitrand_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_doitrand_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_doitrand_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param output Resulting text + */ +void subghz_protocol_decoder_doitrand_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index eeb24026..ed5e4fb5 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -359,7 +359,7 @@ void subghz_protocol_decoder_holtek_get_string(void* context, string_t output) { output, "%s %dbit\r\n" "Key:0x%lX%08lX\r\n" - "Sn:0x%05lX BTN:%X ", + "Sn:0x%05lX Btn:%X ", instance->generic.protocol_name, instance->generic.data_count_bit, (uint32_t)((instance->generic.data >> 32) & 0xFFFFFFFF), diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c new file mode 100644 index 00000000..d4692724 --- /dev/null +++ b/lib/subghz/protocols/marantec.c @@ -0,0 +1,393 @@ +#include "marantec.h" +#include <lib/toolbox/manchester_decoder.h> +#include <lib/toolbox/manchester_encoder.h> +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolMarantec" + +static const SubGhzBlockConst subghz_protocol_marantec_const = { + .te_short = 1000, + .te_long = 2000, + .te_delta = 200, + .min_count_bit_for_found = 49, +}; + +struct SubGhzProtocolDecoderMarantec { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + ManchesterState manchester_saved_state; + uint16_t header_count; +}; + +struct SubGhzProtocolEncoderMarantec { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + MarantecDecoderStepReset = 0, + MarantecDecoderFoundHeader, + MarantecDecoderStepDecoderData, +} MarantecDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_marantec_decoder = { + .alloc = subghz_protocol_decoder_marantec_alloc, + .free = subghz_protocol_decoder_marantec_free, + + .feed = subghz_protocol_decoder_marantec_feed, + .reset = subghz_protocol_decoder_marantec_reset, + + .get_hash_data = subghz_protocol_decoder_marantec_get_hash_data, + .serialize = subghz_protocol_decoder_marantec_serialize, + .deserialize = subghz_protocol_decoder_marantec_deserialize, + .get_string = subghz_protocol_decoder_marantec_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_marantec_encoder = { + .alloc = subghz_protocol_encoder_marantec_alloc, + .free = subghz_protocol_encoder_marantec_free, + + .deserialize = subghz_protocol_encoder_marantec_deserialize, + .stop = subghz_protocol_encoder_marantec_stop, + .yield = subghz_protocol_encoder_marantec_yield, +}; + +const SubGhzProtocol subghz_protocol_marantec = { + .name = SUBGHZ_PROTOCOL_MARANTEC_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_marantec_decoder, + .encoder = &subghz_protocol_marantec_encoder, +}; + +void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderMarantec* instance = malloc(sizeof(SubGhzProtocolEncoderMarantec)); + + instance->base.protocol = &subghz_protocol_marantec; + instance->generic.protocol_name = instance->base.protocol->name; + + 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_marantec_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderMarantec* instance = context; + free(instance->encoder.upload); + free(instance); +} + +static LevelDuration + subghz_protocol_encoder_marantec_add_duration_to_upload(ManchesterEncoderResult result) { + LevelDuration data = {.duration = 0, .level = 0}; + switch(result) { + case ManchesterEncoderResultShortLow: + data.duration = subghz_protocol_marantec_const.te_short; + data.level = false; + break; + case ManchesterEncoderResultLongLow: + data.duration = subghz_protocol_marantec_const.te_long; + data.level = false; + break; + case ManchesterEncoderResultLongHigh: + data.duration = subghz_protocol_marantec_const.te_long; + data.level = true; + break; + case ManchesterEncoderResultShortHigh: + data.duration = subghz_protocol_marantec_const.te_short; + data.level = true; + break; + + default: + furi_crash("SubGhz: ManchesterEncoderResult is incorrect."); + break; + } + return level_duration_make(data.level, data.duration); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderMarantec instance + */ +static void subghz_protocol_encoder_marantec_get_upload(SubGhzProtocolEncoderMarantec* instance) { + furi_assert(instance); + size_t index = 0; + + ManchesterEncoderState enc_state; + manchester_encoder_reset(&enc_state); + ManchesterEncoderResult result; + + if(!manchester_encoder_advance( + &enc_state, + bit_read(instance->generic.data, instance->generic.data_count_bit - 1), + &result)) { + instance->encoder.upload[index++] = + subghz_protocol_encoder_marantec_add_duration_to_upload(result); + manchester_encoder_advance( + &enc_state, + bit_read(instance->generic.data, instance->generic.data_count_bit - 1), + &result); + } + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_marantec_const.te_long * 5); + + for(uint8_t i = instance->generic.data_count_bit - 1; i > 0; i--) { + if(!manchester_encoder_advance( + &enc_state, bit_read(instance->generic.data, i - 1), &result)) { + instance->encoder.upload[index++] = + subghz_protocol_encoder_marantec_add_duration_to_upload(result); + manchester_encoder_advance( + &enc_state, bit_read(instance->generic.data, i - 1), &result); + } + instance->encoder.upload[index++] = + subghz_protocol_encoder_marantec_add_duration_to_upload(result); + } + instance->encoder.upload[index] = subghz_protocol_encoder_marantec_add_duration_to_upload( + manchester_encoder_finish(&enc_state)); + if(level_duration_get_level(instance->encoder.upload[index])) { + index++; + } + instance->encoder.size_upload = index; +} + +uint8_t subghz_protocol_marantec_crc8(uint8_t* data, size_t len) { + uint8_t crc = 0x08; + size_t i, j; + for(i = 0; i < len; i++) { + crc ^= data[i]; + for(j = 0; j < 8; j++) { + if((crc & 0x80) != 0) + crc = (uint8_t)((crc << 1) ^ 0x1D); + else + crc <<= 1; + } + } + return crc; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_marantec_remote_controller(SubGhzBlockGeneric* instance) { + instance->btn = (instance->data >> 16) & 0xF; + instance->serial = ((instance->data >> 12) & 0xFFFFFF00) | ((instance->data >> 8) & 0xFF); +} + +bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderMarantec* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_marantec_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_marantec_remote_controller(&instance->generic); + subghz_protocol_encoder_marantec_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_marantec_stop(void* context) { + SubGhzProtocolEncoderMarantec* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_marantec_yield(void* context) { + SubGhzProtocolEncoderMarantec* 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_marantec_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderMarantec* instance = malloc(sizeof(SubGhzProtocolDecoderMarantec)); + instance->base.protocol = &subghz_protocol_marantec; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_marantec_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + free(instance); +} + +void subghz_protocol_decoder_marantec_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); +} + +void subghz_protocol_decoder_marantec_feed(void* context, bool level, volatile uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + ManchesterEvent event = ManchesterEventReset; + + switch(instance->decoder.parser_step) { + case MarantecDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long * 5) < + subghz_protocol_marantec_const.te_delta * 8)) { + //Found header marantec + instance->decoder.parser_step = MarantecDecoderStepDecoderData; + instance->decoder.decode_data = 1; + instance->decoder.decode_count_bit = 1; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + } + break; + case MarantecDecoderStepDecoderData: + if(!level) { + if(DURATION_DIFF(duration, subghz_protocol_marantec_const.te_short) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventShortLow; + } else if( + DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventLongLow; + } else if( + duration >= ((uint32_t)subghz_protocol_marantec_const.te_long * 2 + + subghz_protocol_marantec_const.te_delta)) { + if(instance->decoder.decode_count_bit == + subghz_protocol_marantec_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 1; + instance->decoder.decode_count_bit = 1; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + } else { + instance->decoder.parser_step = MarantecDecoderStepReset; + } + } else { + if(DURATION_DIFF(duration, subghz_protocol_marantec_const.te_short) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventShortHigh; + } else if( + DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventLongHigh; + } else { + instance->decoder.parser_step = MarantecDecoderStepReset; + } + } + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); + + if(data_ok) { + instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data; + instance->decoder.decode_count_bit++; + } + } + break; + } +} + +uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_marantec_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_marantec_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_marantec_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + subghz_protocol_marantec_remote_controller(&instance->generic); + + string_cat_printf( + output, + "%s %db\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%07lX \r\n" + "Btn:%lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + instance->generic.btn); +} diff --git a/lib/subghz/protocols/marantec.h b/lib/subghz/protocols/marantec.h new file mode 100644 index 00000000..2da3c88a --- /dev/null +++ b/lib/subghz/protocols/marantec.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_MARANTEC_NAME "Marantec" + +typedef struct SubGhzProtocolDecoderMarantec SubGhzProtocolDecoderMarantec; +typedef struct SubGhzProtocolEncoderMarantec SubGhzProtocolEncoderMarantec; + +extern const SubGhzProtocolDecoder subghz_protocol_marantec_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_marantec_encoder; +extern const SubGhzProtocol subghz_protocol_marantec; + +/** + * Allocate SubGhzProtocolEncoderMarantec. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderMarantec* pointer to a SubGhzProtocolEncoderMarantec instance + */ +void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderMarantec. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + */ +void subghz_protocol_encoder_marantec_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + */ +void subghz_protocol_encoder_marantec_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_marantec_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderMarantec. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderMarantec* pointer to a SubGhzProtocolDecoderMarantec instance + */ +void* subghz_protocol_decoder_marantec_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + */ +void subghz_protocol_decoder_marantec_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + */ +void subghz_protocol_decoder_marantec_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_marantec_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_marantec_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param output Resulting text + */ +void subghz_protocol_decoder_marantec_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c new file mode 100644 index 00000000..e71e2834 --- /dev/null +++ b/lib/subghz/protocols/phoenix_v2.c @@ -0,0 +1,339 @@ +#include "phoenix_v2.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolPhoenix_V2" + +//transmission only static mode + +static const SubGhzBlockConst subghz_protocol_phoenix_v2_const = { + .te_short = 427, + .te_long = 853, + .te_delta = 100, + .min_count_bit_for_found = 52, +}; + +struct SubGhzProtocolDecoderPhoenix_V2 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderPhoenix_V2 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + Phoenix_V2DecoderStepReset = 0, + Phoenix_V2DecoderStepFoundStartBit, + Phoenix_V2DecoderStepSaveDuration, + Phoenix_V2DecoderStepCheckDuration, +} Phoenix_V2DecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_phoenix_v2_decoder = { + .alloc = subghz_protocol_decoder_phoenix_v2_alloc, + .free = subghz_protocol_decoder_phoenix_v2_free, + + .feed = subghz_protocol_decoder_phoenix_v2_feed, + .reset = subghz_protocol_decoder_phoenix_v2_reset, + + .get_hash_data = subghz_protocol_decoder_phoenix_v2_get_hash_data, + .serialize = subghz_protocol_decoder_phoenix_v2_serialize, + .deserialize = subghz_protocol_decoder_phoenix_v2_deserialize, + .get_string = subghz_protocol_decoder_phoenix_v2_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_phoenix_v2_encoder = { + .alloc = subghz_protocol_encoder_phoenix_v2_alloc, + .free = subghz_protocol_encoder_phoenix_v2_free, + + .deserialize = subghz_protocol_encoder_phoenix_v2_deserialize, + .stop = subghz_protocol_encoder_phoenix_v2_stop, + .yield = subghz_protocol_encoder_phoenix_v2_yield, +}; + +const SubGhzProtocol subghz_protocol_phoenix_v2 = { + .name = SUBGHZ_PROTOCOL_PHOENIX_V2_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_phoenix_v2_decoder, + .encoder = &subghz_protocol_phoenix_v2_encoder, +}; + +void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderPhoenix_V2* instance = malloc(sizeof(SubGhzProtocolEncoderPhoenix_V2)); + + instance->base.protocol = &subghz_protocol_phoenix_v2; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 128; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_phoenix_v2_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderPhoenix_V2* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + * @return true On success + */ +static bool + subghz_protocol_encoder_phoenix_v2_get_upload(SubGhzProtocolEncoderPhoenix_V2* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 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 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_short * 60); + //Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_short * 6); + //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(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_long); + } + } + return true; +} + +bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderPhoenix_V2* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_phoenix_v2_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_phoenix_v2_stop(void* context) { + SubGhzProtocolEncoderPhoenix_V2* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context) { + SubGhzProtocolEncoderPhoenix_V2* 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_phoenix_v2_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderPhoenix_V2* instance = malloc(sizeof(SubGhzProtocolDecoderPhoenix_V2)); + instance->base.protocol = &subghz_protocol_phoenix_v2; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_phoenix_v2_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + free(instance); +} + +void subghz_protocol_decoder_phoenix_v2_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; +} + +void subghz_protocol_decoder_phoenix_v2_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + + switch(instance->decoder.parser_step) { + case Phoenix_V2DecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_short * 60) < + subghz_protocol_phoenix_v2_const.te_delta * 30)) { + //Found Preambula + instance->decoder.parser_step = Phoenix_V2DecoderStepFoundStartBit; + } + break; + case Phoenix_V2DecoderStepFoundStartBit: + if(level && ((DURATION_DIFF(duration, (subghz_protocol_phoenix_v2_const.te_short * 6)) < + subghz_protocol_phoenix_v2_const.te_delta * 4))) { + //Found start bit + instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; + } + break; + case Phoenix_V2DecoderStepSaveDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_phoenix_v2_const.te_short * 10 + + subghz_protocol_phoenix_v2_const.te_delta)) { + instance->decoder.parser_step = Phoenix_V2DecoderStepFoundStartBit; + if(instance->decoder.decode_count_bit == + subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + break; + } else { + instance->decoder.te_last = duration; + instance->decoder.parser_step = Phoenix_V2DecoderStepCheckDuration; + } + } + break; + case Phoenix_V2DecoderStepCheckDuration: + if(level) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_phoenix_v2_const.te_short) < + subghz_protocol_phoenix_v2_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_long) < + subghz_protocol_phoenix_v2_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_phoenix_v2_const.te_long) < + subghz_protocol_phoenix_v2_const.te_delta * 3) && + (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_short) < + subghz_protocol_phoenix_v2_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; + } + } else { + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_phoenix_v2_check_remote_controller(SubGhzBlockGeneric* instance) { + uint64_t data_rev = + subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit + 4); + instance->serial = data_rev & 0xFFFFFFFF; + instance->cnt = (data_rev >> 40) & 0xFFFF; + instance->btn = (data_rev >> 32) & 0xF; +} + +uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_phoenix_v2_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_phoenix_v2_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%02lX%08lX\r\n" + "Sn:0x%07lX \r\n" + "Btn:%lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32) & 0xFFFFFFFF, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + instance->generic.btn); +} diff --git a/lib/subghz/protocols/phoenix_v2.h b/lib/subghz/protocols/phoenix_v2.h new file mode 100644 index 00000000..38cadc1a --- /dev/null +++ b/lib/subghz/protocols/phoenix_v2.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_PHOENIX_V2_NAME "Phoenix_V2" + +typedef struct SubGhzProtocolDecoderPhoenix_V2 SubGhzProtocolDecoderPhoenix_V2; +typedef struct SubGhzProtocolEncoderPhoenix_V2 SubGhzProtocolEncoderPhoenix_V2; + +extern const SubGhzProtocolDecoder subghz_protocol_phoenix_v2_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_phoenix_v2_encoder; +extern const SubGhzProtocol subghz_protocol_phoenix_v2; + +/** + * Allocate SubGhzProtocolEncoderPhoenix_V2. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderPhoenix_V2* pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + */ +void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + */ +void subghz_protocol_encoder_phoenix_v2_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + */ +void subghz_protocol_encoder_phoenix_v2_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderPhoenix_V2. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderPhoenix_V2* pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + */ +void* subghz_protocol_decoder_phoenix_v2_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + */ +void subghz_protocol_decoder_phoenix_v2_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + */ +void subghz_protocol_decoder_phoenix_v2_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_phoenix_v2_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_phoenix_v2_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param output Resulting text + */ +void subghz_protocol_decoder_phoenix_v2_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index 0f100137..3fdeaae9 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -256,8 +256,6 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; - instance->generic.serial = instance->decoder.decode_data >> 4; - instance->generic.btn = (uint8_t)instance->decoder.decode_data & 0x00000F; if(instance->base.callback) instance->base.callback(&instance->base, instance->base.context); @@ -295,6 +293,15 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t } } +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_princeton_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = instance->data >> 4; + instance->btn = instance->data & 0xF; +} + uint8_t subghz_protocol_decoder_princeton_get_hash_data(void* context) { furi_assert(context); SubGhzProtocolDecoderPrinceton* instance = context; @@ -347,25 +354,21 @@ bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* void subghz_protocol_decoder_princeton_get_string(void* context, string_t output) { furi_assert(context); SubGhzProtocolDecoderPrinceton* instance = context; - - uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; - - uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( + subghz_protocol_princeton_check_remote_controller(&instance->generic); + uint32_t data_rev = subghz_protocol_blocks_reverse_key( instance->generic.data, instance->generic.data_count_bit); - uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; - string_cat_printf( output, "%s %dbit\r\n" "Key:0x%08lX\r\n" "Yek:0x%08lX\r\n" - "Sn:0x%05lX BTN:%02X\r\n" + "Sn:0x%05lX Btn:%01X\r\n" "Te:%dus\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, - code_found_lo, - code_found_reverse_lo, + (uint32_t)(instance->generic.data & 0xFFFFFF), + data_rev, instance->generic.serial, instance->generic.btn, instance->te); diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index 5a09ee8c..89394730 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -9,7 +9,8 @@ const SubGhzProtocol* subghz_protocol_registry[] = { &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, - &subghz_protocol_chamb_code, &subghz_protocol_power_smart, + &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, + &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index d64b0cdd..97a1376d 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -28,6 +28,10 @@ #include "holtek.h" #include "chamberlain_code.h" #include "power_smart.h" +#include "marantec.h" +#include "bett.h" +#include "doitrand.h" +#include "phoenix_v2.h" /** * Registration by name SubGhzProtocol. |