mirror of
https://github.com/flipperdevices/flipperzero-firmware.git
synced 2025-12-12 04:41:26 +04:00
* Fix Typos * Tune decoders * Better parsing, show more data in existing protocols * Add new protocols * Update keeloqs * Add unit tests & raws * Add honeywell unittest * Comment until better solution is found Adding GAPs to be sent first to make signal better suitable for decoder (decoding from only one signal sample) does nothing, needs something else TODO: Fix encoders? * suppressed missing issue warning * subghz: re-enabled failing encoder tests * Fix two? 3 left * properly do gangqi and marantec for unit test and real use * fix unit tests now * fix possible memory leak * reset decoder step too * subghz: extra encoder safety; report random signal test results on failure * unit_tests: subghz: renamed test file for consistency * subghz: more explicit buffer position resets * Fix gangqi samples --------- Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: hedger <hedger@nanode.su>
319 lines
12 KiB
C
319 lines
12 KiB
C
#include "scher_khan.h"
|
|
|
|
#include "../blocks/const.h"
|
|
#include "../blocks/decoder.h"
|
|
#include "../blocks/encoder.h"
|
|
#include "../blocks/generic.h"
|
|
#include "../blocks/math.h"
|
|
|
|
//https://phreakerclub.com/72
|
|
//https://phreakerclub.com/forum/showthread.php?t=7&page=2
|
|
//https://phreakerclub.com/forum/showthread.php?t=274&highlight=magicar
|
|
//!!! https://phreakerclub.com/forum/showthread.php?t=489&highlight=magicar&page=5
|
|
|
|
#define TAG "SubGhzProtocolScherKhan"
|
|
|
|
static const SubGhzBlockConst subghz_protocol_scher_khan_const = {
|
|
.te_short = 750,
|
|
.te_long = 1100,
|
|
.te_delta = 150,
|
|
.min_count_bit_for_found = 35,
|
|
};
|
|
|
|
struct SubGhzProtocolDecoderScherKhan {
|
|
SubGhzProtocolDecoderBase base;
|
|
|
|
SubGhzBlockDecoder decoder;
|
|
SubGhzBlockGeneric generic;
|
|
|
|
uint16_t header_count;
|
|
const char* protocol_name;
|
|
};
|
|
|
|
struct SubGhzProtocolEncoderScherKhan {
|
|
SubGhzProtocolEncoderBase base;
|
|
|
|
SubGhzProtocolBlockEncoder encoder;
|
|
SubGhzBlockGeneric generic;
|
|
};
|
|
|
|
typedef enum {
|
|
ScherKhanDecoderStepReset = 0,
|
|
ScherKhanDecoderStepCheckPreambula,
|
|
ScherKhanDecoderStepSaveDuration,
|
|
ScherKhanDecoderStepCheckDuration,
|
|
} ScherKhanDecoderStep;
|
|
|
|
const SubGhzProtocolDecoder subghz_protocol_scher_khan_decoder = {
|
|
.alloc = subghz_protocol_decoder_scher_khan_alloc,
|
|
.free = subghz_protocol_decoder_scher_khan_free,
|
|
|
|
.feed = subghz_protocol_decoder_scher_khan_feed,
|
|
.reset = subghz_protocol_decoder_scher_khan_reset,
|
|
|
|
.get_hash_data = subghz_protocol_decoder_scher_khan_get_hash_data,
|
|
.serialize = subghz_protocol_decoder_scher_khan_serialize,
|
|
.deserialize = subghz_protocol_decoder_scher_khan_deserialize,
|
|
.get_string = subghz_protocol_decoder_scher_khan_get_string,
|
|
};
|
|
|
|
const SubGhzProtocolEncoder subghz_protocol_scher_khan_encoder = {
|
|
.alloc = NULL,
|
|
.free = NULL,
|
|
|
|
.deserialize = NULL,
|
|
.stop = NULL,
|
|
.yield = NULL,
|
|
};
|
|
|
|
const SubGhzProtocol subghz_protocol_scher_khan = {
|
|
.name = SUBGHZ_PROTOCOL_SCHER_KHAN_NAME,
|
|
.type = SubGhzProtocolTypeDynamic,
|
|
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable,
|
|
|
|
.decoder = &subghz_protocol_scher_khan_decoder,
|
|
.encoder = &subghz_protocol_scher_khan_encoder,
|
|
};
|
|
|
|
void* subghz_protocol_decoder_scher_khan_alloc(SubGhzEnvironment* environment) {
|
|
UNUSED(environment);
|
|
SubGhzProtocolDecoderScherKhan* instance = malloc(sizeof(SubGhzProtocolDecoderScherKhan));
|
|
instance->base.protocol = &subghz_protocol_scher_khan;
|
|
instance->generic.protocol_name = instance->base.protocol->name;
|
|
|
|
return instance;
|
|
}
|
|
|
|
void subghz_protocol_decoder_scher_khan_free(void* context) {
|
|
furi_assert(context);
|
|
SubGhzProtocolDecoderScherKhan* instance = context;
|
|
free(instance);
|
|
}
|
|
|
|
void subghz_protocol_decoder_scher_khan_reset(void* context) {
|
|
furi_assert(context);
|
|
SubGhzProtocolDecoderScherKhan* instance = context;
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
|
|
void subghz_protocol_decoder_scher_khan_feed(void* context, bool level, uint32_t duration) {
|
|
furi_assert(context);
|
|
SubGhzProtocolDecoderScherKhan* instance = context;
|
|
|
|
switch(instance->decoder.parser_step) {
|
|
case ScherKhanDecoderStepReset:
|
|
if((level) && (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) <
|
|
subghz_protocol_scher_khan_const.te_delta)) {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepCheckPreambula;
|
|
instance->decoder.te_last = duration;
|
|
instance->header_count = 0;
|
|
}
|
|
break;
|
|
case ScherKhanDecoderStepCheckPreambula:
|
|
if(level) {
|
|
if((DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) <
|
|
subghz_protocol_scher_khan_const.te_delta) ||
|
|
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) <
|
|
subghz_protocol_scher_khan_const.te_delta)) {
|
|
instance->decoder.te_last = duration;
|
|
} else {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
} else if(
|
|
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) <
|
|
subghz_protocol_scher_khan_const.te_delta) ||
|
|
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) <
|
|
subghz_protocol_scher_khan_const.te_delta)) {
|
|
if(DURATION_DIFF(
|
|
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short * 2) <
|
|
subghz_protocol_scher_khan_const.te_delta) {
|
|
// Found header
|
|
instance->header_count++;
|
|
break;
|
|
} else if(
|
|
DURATION_DIFF(
|
|
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short) <
|
|
subghz_protocol_scher_khan_const.te_delta) {
|
|
// Found start bit
|
|
if(instance->header_count >= 2) {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration;
|
|
instance->decoder.decode_data = 0;
|
|
instance->decoder.decode_count_bit = 1;
|
|
} else {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
} else {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
} else {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
break;
|
|
case ScherKhanDecoderStepSaveDuration:
|
|
if(level) {
|
|
if(duration >= (subghz_protocol_scher_khan_const.te_delta * 2UL +
|
|
subghz_protocol_scher_khan_const.te_long)) {
|
|
//Found stop bit
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
if(instance->decoder.decode_count_bit >=
|
|
subghz_protocol_scher_khan_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 = ScherKhanDecoderStepCheckDuration;
|
|
}
|
|
|
|
} else {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
break;
|
|
case ScherKhanDecoderStepCheckDuration:
|
|
if(!level) {
|
|
if((DURATION_DIFF(
|
|
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short) <
|
|
subghz_protocol_scher_khan_const.te_delta) &&
|
|
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) <
|
|
subghz_protocol_scher_khan_const.te_delta)) {
|
|
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
|
instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration;
|
|
} else if(
|
|
(DURATION_DIFF(
|
|
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_long) <
|
|
subghz_protocol_scher_khan_const.te_delta) &&
|
|
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_long) <
|
|
subghz_protocol_scher_khan_const.te_delta)) {
|
|
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
|
instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration;
|
|
} else {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
} else {
|
|
instance->decoder.parser_step = ScherKhanDecoderStepReset;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Analysis of received data
|
|
* @param instance Pointer to a SubGhzBlockGeneric* instance
|
|
* @param protocol_name
|
|
*/
|
|
static void subghz_protocol_scher_khan_check_remote_controller(
|
|
SubGhzBlockGeneric* instance,
|
|
const char** protocol_name) {
|
|
/*
|
|
* MAGICAR 51 bit 00000001A99121DE83C3 MAGIC CODE, Dynamic
|
|
* 0E8C1619E830C -> 000011101000110000010110 0001 1001 1110 1000001100001100
|
|
* 0E8C1629D830D -> 000011101000110000010110 0010 1001 1101 1000001100001101
|
|
* 0E8C1649B830E -> 000011101000110000010110 0100 1001 1011 1000001100001110
|
|
* 0E8C16897830F -> 000011101000110000010110 1000 1001 0111 1000001100001111
|
|
* Serial Key Ser ~Key CNT
|
|
*/
|
|
|
|
switch(instance->data_count_bit) {
|
|
case 35: //MAGIC CODE, Static
|
|
*protocol_name = "MAGIC CODE, Static";
|
|
instance->serial = 0;
|
|
instance->btn = 0;
|
|
instance->cnt = 0;
|
|
break;
|
|
case 51: //MAGIC CODE, Dynamic
|
|
*protocol_name = "MAGIC CODE, Dynamic";
|
|
instance->serial = ((instance->data >> 24) & 0xFFFFFF0) | ((instance->data >> 20) & 0x0F);
|
|
instance->btn = (instance->data >> 24) & 0x0F;
|
|
instance->cnt = instance->data & 0xFFFF;
|
|
break;
|
|
case 57: //MAGIC CODE PRO / PRO2
|
|
*protocol_name = "MAGIC CODE PRO/PRO2";
|
|
instance->serial = 0;
|
|
instance->btn = 0;
|
|
instance->cnt = 0;
|
|
break;
|
|
case 63: //MAGIC CODE, Dynamic Response
|
|
*protocol_name = "MAGIC CODE, Response";
|
|
instance->serial = 0;
|
|
instance->btn = 0;
|
|
instance->cnt = 0;
|
|
break;
|
|
case 64: //MAGICAR, Response ???
|
|
*protocol_name = "MAGICAR, Response";
|
|
instance->serial = 0;
|
|
instance->btn = 0;
|
|
instance->cnt = 0;
|
|
break;
|
|
case 81: //MAGIC CODE PRO / PRO2 Response ???
|
|
*protocol_name = "MAGIC CODE PRO,\n Response";
|
|
instance->serial = 0;
|
|
instance->btn = 0;
|
|
instance->cnt = 0;
|
|
break;
|
|
case 82: //MAGIC CODE PRO / PRO2 Response ???
|
|
*protocol_name = "MAGIC CODE PRO,\n Response";
|
|
instance->serial = 0;
|
|
instance->btn = 0;
|
|
instance->cnt = 0;
|
|
break;
|
|
|
|
default:
|
|
*protocol_name = "Unknown";
|
|
instance->serial = 0;
|
|
instance->btn = 0;
|
|
instance->cnt = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint8_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context) {
|
|
furi_assert(context);
|
|
SubGhzProtocolDecoderScherKhan* instance = context;
|
|
return subghz_protocol_blocks_get_hash_data(
|
|
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
|
|
}
|
|
|
|
SubGhzProtocolStatus subghz_protocol_decoder_scher_khan_serialize(
|
|
void* context,
|
|
FlipperFormat* flipper_format,
|
|
SubGhzRadioPreset* preset) {
|
|
furi_assert(context);
|
|
SubGhzProtocolDecoderScherKhan* instance = context;
|
|
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
|
|
}
|
|
|
|
SubGhzProtocolStatus
|
|
subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format) {
|
|
furi_assert(context);
|
|
SubGhzProtocolDecoderScherKhan* instance = context;
|
|
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
|
|
}
|
|
|
|
void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* output) {
|
|
furi_assert(context);
|
|
SubGhzProtocolDecoderScherKhan* instance = context;
|
|
|
|
subghz_protocol_scher_khan_check_remote_controller(
|
|
&instance->generic, &instance->protocol_name);
|
|
|
|
furi_string_cat_printf(
|
|
output,
|
|
"%s %dbit\r\n"
|
|
"Key:0x%lX%08lX\r\n"
|
|
"Sn:%07lX Btn:%X Cnt:%04lX\r\n"
|
|
"Pt: %s\r\n",
|
|
instance->generic.protocol_name,
|
|
instance->generic.data_count_bit,
|
|
(uint32_t)(instance->generic.data >> 32),
|
|
(uint32_t)instance->generic.data,
|
|
instance->generic.serial,
|
|
instance->generic.btn,
|
|
instance->generic.cnt,
|
|
instance->protocol_name);
|
|
}
|