[FL-2230] SubGhz: protocol API refactoring (#969)

* SubGhz: protocols library refactoring
* SubGhz: new architecture and refactoring
* SubGhz: simplify protocol structure, remove unused types
* SubGhz: rename Subghz to SubGhz
* SubGhz: add environment concept

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
This commit is contained in:
Skorpionm
2022-03-03 13:48:56 +04:00
committed by GitHub
parent 052237f8c9
commit 3164184bbc
173 changed files with 9836 additions and 8486 deletions

View File

@@ -0,0 +1 @@
#include "const.h"

12
lib/subghz/blocks/const.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
typedef struct {
const uint16_t te_long;
const uint16_t te_short;
const uint16_t te_delta;
const uint8_t min_count_bit_for_found;
} SubGhzBlockConst;

View File

@@ -0,0 +1,17 @@
#include "decoder.h"
#define TAG "SubGhzBlockDecoder"
void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit) {
decoder->decode_data = decoder->decode_data << 1 | bit;
decoder->decode_count_bit++;
}
uint8_t subghz_protocol_blocks_get_hash_data(SubGhzBlockDecoder* decoder, size_t len) {
uint8_t hash = 0;
uint8_t* p = (uint8_t*)&decoder->decode_data;
for(size_t i = 0; i < len; i++) {
hash ^= p[i];
}
return hash;
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
typedef struct SubGhzBlockDecoder SubGhzBlockDecoder;
struct SubGhzBlockDecoder {
uint32_t parser_step;
uint32_t te_last;
uint64_t decode_data;
uint8_t decode_count_bit;
};
void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit);
uint8_t subghz_protocol_blocks_get_hash_data(SubGhzBlockDecoder* decoder, size_t len);

View File

@@ -0,0 +1,3 @@
#include "encoder.h"
#define TAG "SubGhzBlockEncoder"

View File

@@ -0,0 +1,16 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <lib/toolbox/level_duration.h>
typedef struct {
bool is_runing;
size_t repeat;
size_t front;
size_t size_upload;
LevelDuration* upload;
} SubGhzProtocolBlockEncoder;

118
lib/subghz/blocks/generic.c Normal file
View File

@@ -0,0 +1,118 @@
#include "generic.h"
#include "../types.h"
#include <lib/toolbox/stream/stream.h>
#include <lib/flipper_format/flipper_format_i.h>
#define TAG "SubGhzBlockGeneric"
bool subghz_block_generic_get_preset_name(FuriHalSubGhzPreset preset, string_t preset_str) {
const char* preset_name;
switch(preset) {
case FuriHalSubGhzPresetOok270Async:
preset_name = "FuriHalSubGhzPresetOok270Async";
break;
case FuriHalSubGhzPresetOok650Async:
preset_name = "FuriHalSubGhzPresetOok650Async";
break;
case FuriHalSubGhzPreset2FSKDev238Async:
preset_name = "FuriHalSubGhzPreset2FSKDev238Async";
break;
case FuriHalSubGhzPreset2FSKDev476Async:
preset_name = "FuriHalSubGhzPreset2FSKDev476Async";
break;
default:
FURI_LOG_E(TAG, "Unknown preset");
return false;
break;
}
string_set(preset_str, preset_name);
return true;
}
bool subghz_block_generic_serialize(
SubGhzBlockGeneric* instance,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(instance);
bool res = false;
string_t temp_str;
string_init(temp_str);
do {
stream_clean(flipper_format_get_raw_stream(flipper_format));
if(!flipper_format_write_header_cstr(
flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) {
FURI_LOG_E(TAG, "Unable to add header");
break;
}
if(!flipper_format_write_uint32(flipper_format, "Frequency", &frequency, 1)) {
FURI_LOG_E(TAG, "Unable to add Frequency");
break;
}
if(!subghz_block_generic_get_preset_name(preset, temp_str)) {
break;
}
if(!flipper_format_write_string_cstr(flipper_format, "Preset", string_get_cstr(temp_str))) {
FURI_LOG_E(TAG, "Unable to add Preset");
break;
}
if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->protocol_name)) {
FURI_LOG_E(TAG, "Unable to add Protocol");
break;
}
uint32_t temp = instance->data_count_bit;
if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) {
FURI_LOG_E(TAG, "Unable to add Bit");
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->data >> i * 8) & 0xFF;
}
if(!flipper_format_write_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to add Key");
break;
}
res = true;
} while(false);
string_clear(temp_str);
return res;
}
bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format) {
furi_assert(instance);
bool res = false;
string_t temp_str;
string_init(temp_str);
uint32_t temp_data = 0;
do {
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Bit");
break;
}
instance->data_count_bit = (uint8_t)temp_data;
uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Missing Key");
break;
}
for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
instance->data = instance->data << 8 | key_data[i];
}
res = true;
} while(0);
string_clear(temp_str);
return res;
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <lib/flipper_format/flipper_format.h>
#include "furi.h"
#include "furi_hal.h"
typedef struct SubGhzBlockGeneric SubGhzBlockGeneric;
struct SubGhzBlockGeneric {
const char* protocol_name;
uint64_t data;
uint32_t serial;
uint8_t data_count_bit;
uint8_t btn;
uint16_t cnt;
};
bool subghz_block_generic_get_preset_name(FuriHalSubGhzPreset preset, string_t preset_str);
bool subghz_block_generic_serialize(
SubGhzBlockGeneric* instance,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format);

9
lib/subghz/blocks/math.c Normal file
View File

@@ -0,0 +1,9 @@
#include "math.h"
uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit) {
uint64_t key_reverse = 0;
for(uint8_t i = 0; i < count_bit; i++) {
key_reverse = key_reverse << 1 | bit_read(key, i);
}
return key_reverse;
}

13
lib/subghz/blocks/math.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
#define bit_set(value, bit) ((value) |= (1UL << (bit)))
#define bit_clear(value, bit) ((value) &= ~(1UL << (bit)))
#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
#define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y))
uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit);

67
lib/subghz/environment.c Normal file
View File

@@ -0,0 +1,67 @@
#include "environment.h"
struct SubGhzEnvironment {
SubGhzKeystore* keystore;
const char* came_atomo_rainbow_table_file_name;
const char* nice_flor_s_rainbow_table_file_name;
};
SubGhzEnvironment* subghz_environment_alloc() {
SubGhzEnvironment* instance = malloc(sizeof(SubGhzEnvironment));
instance->keystore = subghz_keystore_alloc();
instance->came_atomo_rainbow_table_file_name = NULL;
instance->nice_flor_s_rainbow_table_file_name = NULL;
return instance;
}
void subghz_environment_free(SubGhzEnvironment* instance) {
furi_assert(instance);
subghz_keystore_free(instance->keystore);
free(instance);
}
bool subghz_environment_load_keystore(SubGhzEnvironment* instance, const char* filename) {
furi_assert(instance);
return subghz_keystore_load(instance->keystore, filename);
}
SubGhzKeystore* subghz_environment_get_keystore(SubGhzEnvironment* instance) {
furi_assert(instance);
return instance->keystore;
}
void subghz_environment_set_came_atomo_rainbow_table_file_name(
SubGhzEnvironment* instance,
const char* filename) {
furi_assert(instance);
instance->came_atomo_rainbow_table_file_name = filename;
}
const char*
subghz_environment_get_came_atomo_rainbow_table_file_name(SubGhzEnvironment* instance) {
furi_assert(instance);
return instance->came_atomo_rainbow_table_file_name;
}
void subghz_environment_set_nice_flor_s_rainbow_table_file_name(
SubGhzEnvironment* instance,
const char* filename) {
furi_assert(instance);
instance->nice_flor_s_rainbow_table_file_name = filename;
}
const char*
subghz_environment_get_nice_flor_s_rainbow_table_file_name(SubGhzEnvironment* instance) {
furi_assert(instance);
return instance->nice_flor_s_rainbow_table_file_name;
}

28
lib/subghz/environment.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <furi.h>
#include "subghz_keystore.h"
typedef struct SubGhzEnvironment SubGhzEnvironment;
SubGhzEnvironment* subghz_environment_alloc();
void subghz_environment_free(SubGhzEnvironment* instance);
bool subghz_environment_load_keystore(SubGhzEnvironment* instance, const char* filename);
SubGhzKeystore* subghz_environment_get_keystore(SubGhzEnvironment* instance);
void subghz_environment_set_came_atomo_rainbow_table_file_name(
SubGhzEnvironment* instance,
const char* filename);
const char* subghz_environment_get_came_atomo_rainbow_table_file_name(SubGhzEnvironment* instance);
void subghz_environment_set_nice_flor_s_rainbow_table_file_name(
SubGhzEnvironment* instance,
const char* filename);
const char*
subghz_environment_get_nice_flor_s_rainbow_table_file_name(SubGhzEnvironment* instance);

View File

@@ -0,0 +1,64 @@
#include "base.h"
#include "registry.h"
void subghz_protocol_decoder_base_set_decoder_callback(
SubGhzProtocolDecoderBase* decoder_base,
SubGhzProtocolDecoderBaseRxCallback callback,
void* context) {
decoder_base->callback = callback;
decoder_base->context = context;
}
bool subghz_protocol_decoder_base_get_string(
SubGhzProtocolDecoderBase* decoder_base,
string_t output) {
bool status = false;
if(decoder_base->protocol && decoder_base->protocol->decoder &&
decoder_base->protocol->decoder->get_string) {
decoder_base->protocol->decoder->get_string(decoder_base, output);
status = true;
}
return status;
}
bool subghz_protocol_decoder_base_serialize(
SubGhzProtocolDecoderBase* decoder_base,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
bool status = false;
if(decoder_base->protocol && decoder_base->protocol->decoder &&
decoder_base->protocol->decoder->serialize) {
status = decoder_base->protocol->decoder->serialize(
decoder_base, flipper_format, frequency, preset);
}
return status;
}
bool subghz_protocol_decoder_base_deserialize(
SubGhzProtocolDecoderBase* decoder_base,
FlipperFormat* flipper_format) {
bool status = false;
if(decoder_base->protocol && decoder_base->protocol->decoder &&
decoder_base->protocol->decoder->deserialize) {
status = decoder_base->protocol->decoder->deserialize(decoder_base, flipper_format);
}
return status;
}
uint8_t subghz_protocol_decoder_base_get_hash_data(SubGhzProtocolDecoderBase* decoder_base) {
uint8_t hash = 0;
if(decoder_base->protocol && decoder_base->protocol->decoder &&
decoder_base->protocol->decoder->get_hash_data) {
hash = decoder_base->protocol->decoder->get_hash_data(decoder_base);
}
return hash;
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include "../types.h"
typedef struct SubGhzProtocolDecoderBase SubGhzProtocolDecoderBase;
typedef void (
*SubGhzProtocolDecoderBaseRxCallback)(SubGhzProtocolDecoderBase* instance, void* context);
typedef void (
*SubGhzProtocolDecoderBaseSerialize)(SubGhzProtocolDecoderBase* decoder_base, string_t output);
struct SubGhzProtocolDecoderBase {
// Decoder general section
const SubGhzProtocol* protocol;
// Callback section
SubGhzProtocolDecoderBaseRxCallback callback;
void* context;
};
void subghz_protocol_decoder_base_set_decoder_callback(
SubGhzProtocolDecoderBase* decoder_base,
SubGhzProtocolDecoderBaseRxCallback callback,
void* context);
bool subghz_protocol_decoder_base_get_string(
SubGhzProtocolDecoderBase* decoder_base,
string_t output);
bool subghz_protocol_decoder_base_serialize(
SubGhzProtocolDecoderBase* decoder_base,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_base_deserialize(
SubGhzProtocolDecoderBase* decoder_base,
FlipperFormat* flipper_format);
uint8_t subghz_protocol_decoder_base_get_hash_data(SubGhzProtocolDecoderBase* decoder_base);
// Encoder Base
typedef struct SubGhzProtocolEncoderBase SubGhzProtocolEncoderBase;
struct SubGhzProtocolEncoderBase {
// Decoder general section
const SubGhzProtocol* protocol;
// Callback section
};

313
lib/subghz/protocols/came.c Normal file
View File

@@ -0,0 +1,313 @@
#include "came.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
#define TAG "SubGhzProtocolCAME"
static const SubGhzBlockConst subghz_protocol_came_const = {
.te_short = 320,
.te_long = 640,
.te_delta = 150,
.min_count_bit_for_found = 12,
};
struct SubGhzProtocolDecoderCame {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderCame {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
CameDecoderStepReset = 0,
CameDecoderStepFoundStartBit,
CameDecoderStepSaveDuration,
CameDecoderStepCheckDuration,
} CameDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_came_decoder = {
.alloc = subghz_protocol_decoder_came_alloc,
.free = subghz_protocol_decoder_came_free,
.feed = subghz_protocol_decoder_came_feed,
.reset = subghz_protocol_decoder_came_reset,
.get_hash_data = subghz_protocol_decoder_came_get_hash_data,
.serialize = subghz_protocol_decoder_came_serialize,
.deserialize = subghz_protocol_decoder_came_deserialize,
.get_string = subghz_protocol_decoder_came_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_came_encoder = {
.alloc = subghz_protocol_encoder_came_alloc,
.free = subghz_protocol_encoder_came_free,
.deserialize = subghz_protocol_encoder_came_deserialize,
.stop = subghz_protocol_encoder_came_stop,
.yield = subghz_protocol_encoder_came_yield,
};
const SubGhzProtocol subghz_protocol_came = {
.name = SUBGHZ_PROTOCOL_CAME_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save |
SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_came_decoder,
.encoder = &subghz_protocol_came_encoder,
};
void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderCame* instance = malloc(sizeof(SubGhzProtocolEncoderCame));
instance->base.protocol = &subghz_protocol_came;
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_came_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderCame* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* 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_came_const.te_short * 36);
//Send start bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short);
//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_came_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_long);
}
}
return true;
}
bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderCame* 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_came_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_came_stop(void* context) {
SubGhzProtocolEncoderCame* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_came_yield(void* context) {
SubGhzProtocolEncoderCame* 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_came_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderCame* instance = malloc(sizeof(SubGhzProtocolDecoderCame));
instance->base.protocol = &subghz_protocol_came;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_came_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCame* instance = context;
free(instance);
}
void subghz_protocol_decoder_came_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCame* instance = context;
instance->decoder.parser_step = CameDecoderStepReset;
}
void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderCame* instance = context;
switch(instance->decoder.parser_step) {
case CameDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_const.te_short * 51) <
subghz_protocol_came_const.te_delta * 51)) { //Need protocol 36 te_short
//Found header CAME
instance->decoder.parser_step = CameDecoderStepFoundStartBit;
}
break;
case CameDecoderStepFoundStartBit:
if(!level) {
break;
} else if(
DURATION_DIFF(duration, subghz_protocol_came_const.te_short) <
subghz_protocol_came_const.te_delta) {
//Found start bit CAME
instance->decoder.parser_step = CameDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = CameDecoderStepReset;
}
break;
case CameDecoderStepSaveDuration:
if(!level) { //save interval
if(duration >= (subghz_protocol_came_const.te_short * 4)) {
instance->decoder.parser_step = CameDecoderStepFoundStartBit;
if(instance->decoder.decode_count_bit >=
subghz_protocol_came_const.min_count_bit_for_found) {
instance->generic.serial = 0x0;
instance->generic.btn = 0x0;
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);
}
break;
}
instance->decoder.te_last = duration;
instance->decoder.parser_step = CameDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = CameDecoderStepReset;
}
break;
case CameDecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_came_const.te_short) <
subghz_protocol_came_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_came_const.te_long) <
subghz_protocol_came_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = CameDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_came_const.te_long) <
subghz_protocol_came_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_came_const.te_short) <
subghz_protocol_came_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = CameDecoderStepSaveDuration;
} else
instance->decoder.parser_step = CameDecoderStepReset;
} else {
instance->decoder.parser_step = CameDecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_decoder_came_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCame* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_came_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderCame* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderCame* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_came_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderCame* instance = context;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
uint64_t code_found_reverse = 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",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_lo,
code_found_reverse_lo);
}

View File

@@ -0,0 +1,63 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_CAME_NAME "CAME"
typedef struct SubGhzProtocolDecoderCame SubGhzProtocolDecoderCame;
typedef struct SubGhzProtocolEncoderCame SubGhzProtocolEncoderCame;
extern const SubGhzProtocolDecoder subghz_protocol_came_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_came_encoder;
extern const SubGhzProtocol subghz_protocol_came;
void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_came_free(void* context);
bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_came_stop(void* context);
LevelDuration subghz_protocol_encoder_came_yield(void* context);
/** Allocate SubGhzProtocolCame
*
* @return SubGhzProtocolCame*
*/
void* subghz_protocol_decoder_came_alloc(SubGhzEnvironment* environment);
/** Free SubGhzProtocolCame
*
* @param instance
*/
void subghz_protocol_decoder_came_free(void* context);
/** Reset internal state
* @param instance - SubGhzProtocolCame instance
*/
void subghz_protocol_decoder_came_reset(void* context);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolCame instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_came_get_hash_data(void* context);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolCame* instance
* @param output - output string
*/
bool subghz_protocol_decoder_came_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_came_get_string(void* context, string_t output);

View File

@@ -0,0 +1,338 @@
#include "came_atomo.h"
#include <lib/toolbox/manchester_decoder.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocoCameAtomo"
#define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF
static const SubGhzBlockConst subghz_protocol_came_atomo_const = {
.te_short = 600,
.te_long = 1200,
.te_delta = 250,
.min_count_bit_for_found = 62,
};
struct SubGhzProtocolDecoderCameAtomo {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
ManchesterState manchester_saved_state;
const char* came_atomo_rainbow_table_file_name;
};
struct SubGhzProtocolEncoderCameAtomo {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
CameAtomoDecoderStepReset = 0,
CameAtomoDecoderStepDecoderData,
} CameAtomoDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_came_atomo_decoder = {
.alloc = subghz_protocol_decoder_came_atomo_alloc,
.free = subghz_protocol_decoder_came_atomo_free,
.feed = subghz_protocol_decoder_came_atomo_feed,
.reset = subghz_protocol_decoder_came_atomo_reset,
.get_hash_data = subghz_protocol_decoder_came_atomo_get_hash_data,
.serialize = subghz_protocol_decoder_came_atomo_serialize,
.deserialize = subghz_protocol_decoder_came_atomo_deserialize,
.get_string = subghz_protocol_decoder_came_atomo_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_came_atomo_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_came_atomo = {
.name = SUBGHZ_PROTOCOL_CAME_ATOMO_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_came_atomo_decoder,
.encoder = &subghz_protocol_came_atomo_encoder,
};
void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderCameAtomo* instance = malloc(sizeof(SubGhzProtocolDecoderCameAtomo));
instance->base.protocol = &subghz_protocol_came_atomo;
instance->generic.protocol_name = instance->base.protocol->name;
instance->came_atomo_rainbow_table_file_name =
subghz_environment_get_came_atomo_rainbow_table_file_name(environment);
if(instance->came_atomo_rainbow_table_file_name) {
FURI_LOG_I(
TAG, "Loading rainbow table from %s", instance->came_atomo_rainbow_table_file_name);
}
return instance;
}
void subghz_protocol_decoder_came_atomo_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCameAtomo* instance = context;
instance->came_atomo_rainbow_table_file_name = NULL;
free(instance);
}
void subghz_protocol_decoder_came_atomo_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCameAtomo* instance = context;
instance->decoder.parser_step = CameAtomoDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderCameAtomo* instance = context;
ManchesterEvent event = ManchesterEventReset;
switch(instance->decoder.parser_step) {
case CameAtomoDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long * 65) <
subghz_protocol_came_atomo_const.te_delta * 20)) {
//Found header CAME
instance->decoder.parser_step = CameAtomoDecoderStepDecoderData;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 1;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
}
break;
case CameAtomoDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) <
subghz_protocol_came_atomo_const.te_delta) {
event = ManchesterEventShortLow;
} else if(
DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) <
subghz_protocol_came_atomo_const.te_delta) {
event = ManchesterEventLongLow;
} else if(
duration >= (subghz_protocol_came_atomo_const.te_long * 2 +
subghz_protocol_came_atomo_const.te_delta)) {
if(instance->decoder.decode_count_bit ==
subghz_protocol_came_atomo_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 = 1;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
} else {
instance->decoder.parser_step = CameAtomoDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) <
subghz_protocol_came_atomo_const.te_delta) {
event = ManchesterEventShortHigh;
} else if(
DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) <
subghz_protocol_came_atomo_const.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->decoder.parser_step = CameAtomoDecoderStepReset;
}
}
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;
}
}
/** Read bytes from rainbow table
*
* @param file_name - file name rainbow table
* @param number_atomo_magic_xor
* @return atomo_magic_xor
*/
static uint64_t subghz_protocol_came_atomo_get_magic_xor_in_file(
const char* file_name,
uint8_t number_atomo_magic_xor) {
if(!strcmp(file_name, "")) return SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
uint8_t buffer[sizeof(uint64_t)] = {0};
uint32_t address = number_atomo_magic_xor * sizeof(uint64_t);
uint64_t atomo_magic_xor = 0;
if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint64_t))) {
for(size_t i = 0; i < sizeof(uint64_t); i++) {
atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i];
}
} else {
atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
}
return atomo_magic_xor;
}
/** Analysis of received data
*
* @param instance SubGhzBlockGeneric instance
*/
static void subghz_protocol_came_atomo_remote_controller(
SubGhzBlockGeneric* instance,
const char* file_name) {
/*
* 0x1fafef3ed0f7d9ef
* 0x185fcc1531ee86e7
* 0x184fa96912c567ff
* 0x187f8a42f3dc38f7
* 0x186f63915492a5cd
* 0x181f40bab58bfac5
* 0x180f25c696a01bdd
* 0x183f06ed77b944d5
* 0x182ef661d83d21a9
* 0x18ded54a39247ea1
* 0x18ceb0361a0f9fb9
* 0x18fe931dfb16c0b1
* 0x18ee7ace5c585d8b
* ........
* transmission consists of 99 parcels with increasing counter while holding down the button
* with each new press, the counter in the encrypted part increases
*
* 0x1FAFF13ED0F7D9EF
* 0x1FAFF11ED0F7D9EF
* 0x1FAFF10ED0F7D9EF
* 0x1FAFF0FED0F7D9EF
* 0x1FAFF0EED0F7D9EF
* 0x1FAFF0DED0F7D9EF
* 0x1FAFF0CED0F7D9EF
* 0x1FAFF0BED0F7D9EF
* 0x1FAFF0AED0F7D9EF
*
* where 0x1FAF - parcel counter, 0хF0A - button press counter,
* 0xED0F7D9E - serial number, 0хF - key
* 0x1FAF parcel counter - 1 in the parcel queue ^ 0x185F = 0x07F0
* 0x185f ^ 0x185F = 0x0000
* 0x184f ^ 0x185F = 0x0010
* 0x187f ^ 0x185F = 0x0020
* .....
* 0x182e ^ 0x185F = 0x0071
* 0x18de ^ 0x185F = 0x0081
* .....
* 0x1e43 ^ 0x185F = 0x061C
* where the last nibble is incremented every 8 samples
*
* Decode
*
* 0x1cf6931dfb16c0b1 => 0x1cf6
* 0x1cf6 ^ 0x185F = 0x04A9
* 0x04A9 => 0x04A = 74 (dec)
* 74+1 % 32(atomo_magic_xor) = 11
* GET atomo_magic_xor[11] = 0xXXXXXXXXXXXXXXXX
* 0x931dfb16c0b1 ^ 0xXXXXXXXXXXXXXXXX = 0xEF3ED0F7D9EF
* 0xEF3 ED0F7D9E F => 0xEF3 - CNT, 0xED0F7D9E - SN, 0xF - key
*
* */
uint16_t parcel_counter = instance->data >> 48;
parcel_counter = parcel_counter ^ 0x185F;
parcel_counter >>= 4;
uint8_t ind = (parcel_counter + 1) % 32;
uint64_t temp_data = instance->data & 0x0000FFFFFFFFFFFF;
uint64_t atomo_magic_xor = subghz_protocol_came_atomo_get_magic_xor_in_file(file_name, ind);
if(atomo_magic_xor != SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE) {
temp_data = temp_data ^ atomo_magic_xor;
instance->cnt = temp_data >> 36;
instance->serial = (temp_data >> 4) & 0x000FFFFFFFF;
instance->btn = temp_data & 0xF;
} else {
instance->cnt = 0;
instance->serial = 0;
instance->btn = 0;
}
}
uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCameAtomo* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_came_atomo_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderCameAtomo* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderCameAtomo* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_came_atomo_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderCameAtomo* instance = context;
subghz_protocol_came_atomo_remote_controller(
&instance->generic, instance->came_atomo_rainbow_table_file_name);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %db\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%08lX Btn:0x%01X\r\n"
"Cnt:0x%03X\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
instance->generic.serial,
instance->generic.btn,
instance->generic.cnt);
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_CAME_ATOMO_NAME "CAME Atomo"
typedef struct SubGhzProtocolDecoderCameAtomo SubGhzProtocolDecoderCameAtomo;
typedef struct SubGhzProtocolEncoderCameAtomo SubGhzProtocolEncoderCameAtomo;
extern const SubGhzProtocolDecoder subghz_protocol_came_atomo_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_came_atomo_encoder;
extern const SubGhzProtocol subghz_protocol_came_atomo;
void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_came_atomo_free(void* context);
void subghz_protocol_decoder_came_atomo_reset(void* context);
void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context);
bool subghz_protocol_decoder_came_atomo_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_came_atomo_get_string(void* context, string_t output);

View File

@@ -0,0 +1,445 @@
#include "came_twee.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"
/*
* Help
* https://phreakerclub.com/forum/showthread.php?t=635&highlight=came+twin
*
*/
#define TAG "SubGhzProtocolCAME_Twee"
#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c"
#define CNT_TO_DIP(dip) \
(dip & 0x0200 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), \
(dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), \
(dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), \
(dip & 0x0001 ? '1' : '0')
static const uint32_t came_twee_magic_numbers_xor[15] = {
0x0E0E0E00,
0x1D1D1D11,
0x2C2C2C22,
0x3B3B3B33,
0x4A4A4A44,
0x59595955,
0x68686866,
0x77777777,
0x86868688,
0x95959599,
0xA4A4A4AA,
0xB3B3B3BB,
0xC2C2C2CC,
0xD1D1D1DD,
0xE0E0E0EE,
};
static const SubGhzBlockConst subghz_protocol_came_twee_const = {
.te_short = 500,
.te_long = 1000,
.te_delta = 250,
.min_count_bit_for_found = 54,
};
struct SubGhzProtocolDecoderCameTwee {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
ManchesterState manchester_saved_state;
};
struct SubGhzProtocolEncoderCameTwee {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
CameTweeDecoderStepReset = 0,
CameTweeDecoderStepDecoderData,
} CameTweeDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_came_twee_decoder = {
.alloc = subghz_protocol_decoder_came_twee_alloc,
.free = subghz_protocol_decoder_came_twee_free,
.feed = subghz_protocol_decoder_came_twee_feed,
.reset = subghz_protocol_decoder_came_twee_reset,
.get_hash_data = subghz_protocol_decoder_came_twee_get_hash_data,
.serialize = subghz_protocol_decoder_came_twee_serialize,
.deserialize = subghz_protocol_decoder_came_twee_deserialize,
.get_string = subghz_protocol_decoder_came_twee_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_came_twee_encoder = {
.alloc = subghz_protocol_encoder_came_twee_alloc,
.free = subghz_protocol_encoder_came_twee_free,
.deserialize = subghz_protocol_encoder_came_twee_deserialize,
.stop = subghz_protocol_encoder_came_twee_stop,
.yield = subghz_protocol_encoder_came_twee_yield,
};
const SubGhzProtocol subghz_protocol_came_twee = {
.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_came_twee_decoder,
.encoder = &subghz_protocol_came_twee_encoder,
};
void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderCameTwee* instance = malloc(sizeof(SubGhzProtocolEncoderCameTwee));
instance->base.protocol = &subghz_protocol_came_twee;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 10;
instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!!
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_runing = false;
return instance;
}
void subghz_protocol_encoder_came_twee_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderCameTwee* instance = context;
free(instance->encoder.upload);
free(instance);
}
static LevelDuration
subghz_protocol_encoder_came_twee_add_duration_to_upload(ManchesterEncoderResult result) {
LevelDuration data = {.duration = 0, .level = 0};
switch(result) {
case ManchesterEncoderResultShortLow:
data.duration = subghz_protocol_came_twee_const.te_short;
data.level = false;
break;
case ManchesterEncoderResultLongLow:
data.duration = subghz_protocol_came_twee_const.te_long;
data.level = false;
break;
case ManchesterEncoderResultLongHigh:
data.duration = subghz_protocol_came_twee_const.te_long;
data.level = true;
break;
case ManchesterEncoderResultShortHigh:
data.duration = subghz_protocol_came_twee_const.te_short;
data.level = true;
break;
default:
FURI_LOG_E(TAG, "DO CRASH HERE.");
furi_crash(NULL);
break;
}
return level_duration_make(data.level, data.duration);
}
static void subghz_protocol_encoder_came_twee_get_upload(SubGhzProtocolEncoderCameTwee* instance) {
furi_assert(instance);
size_t index = 0;
ManchesterEncoderState enc_state;
manchester_encoder_reset(&enc_state);
ManchesterEncoderResult result;
uint64_t temp_parcel = 0x003FFF7200000000; //parcel mask
for(int i = 14; i >= 0; i--) {
temp_parcel = (temp_parcel & 0xFFFFFFFF00000000) |
(instance->generic.serial ^ came_twee_magic_numbers_xor[i]);
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(!manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result)) {
instance->encoder.upload[index++] =
subghz_protocol_encoder_came_twee_add_duration_to_upload(result);
manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result);
}
instance->encoder.upload[index++] =
subghz_protocol_encoder_came_twee_add_duration_to_upload(result);
}
instance->encoder.upload[index] = subghz_protocol_encoder_came_twee_add_duration_to_upload(
manchester_encoder_finish(&enc_state));
if(level_duration_get_level(instance->encoder.upload[index])) {
index++;
}
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_came_twee_const.te_long * 51);
}
instance->encoder.size_upload = index;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolCameTwee instance
*/
static void subghz_protocol_came_twee_remote_controller(SubGhzBlockGeneric* instance) {
/* Came Twee 54 bit, rolling code 15 parcels with
* a decreasing counter from 0xE to 0x0
* with originally coded dip switches on the console 10 bit code
*
* 0x003FFF72E04A6FEE
* 0x003FFF72D17B5EDD
* 0x003FFF72C2684DCC
* 0x003FFF72B3193CBB
* 0x003FFF72A40E2BAA
* 0x003FFF72953F1A99
* 0x003FFF72862C0988
* 0x003FFF7277DDF877
* 0x003FFF7268C2E766
* 0x003FFF7259F3D655
* 0x003FFF724AE0C544
* 0x003FFF723B91B433
* 0x003FFF722C86A322
* 0x003FFF721DB79211
* 0x003FFF720EA48100
*
* decryption
* the last 32 bits, do XOR by the desired number, divide the result by 4,
* convert the first 16 bits of the resulting 32-bit number to bin and do
* bit-by-bit mirroring, adding up to 10 bits
*
* Example
* Step 1. 0x003FFF721DB79211 => 0x1DB79211
* Step 4. 0x1DB79211 xor 0x1D1D1D11 => 0x00AA8F00
* Step 4. 0x00AA8F00 / 4 => 0x002AA3C0
* Step 5. 0x002AA3C0 => 0x002A
* Step 6. 0x002A bin => b101010
* Step 7. b101010 => b0101010000
* Step 8. b0101010000 => (Dip) Off ON Off ON Off ON Off Off Off Off
*/
uint8_t cnt_parcel = (uint8_t)(instance->data & 0xF);
uint32_t data = (uint32_t)(instance->data & 0x0FFFFFFFF);
data = (data ^ came_twee_magic_numbers_xor[cnt_parcel]);
instance->serial = data;
data /= 4;
instance->btn = (data >> 4) & 0x0F;
data >>= 16;
data = (uint16_t)subghz_protocol_blocks_reverse_key(data, 16);
instance->cnt = data >> 6;
}
bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderCameTwee* 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_came_twee_remote_controller(&instance->generic);
subghz_protocol_encoder_came_twee_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_came_twee_stop(void* context) {
SubGhzProtocolEncoderCameTwee* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_came_twee_yield(void* context) {
SubGhzProtocolEncoderCameTwee* 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_came_twee_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderCameTwee* instance = malloc(sizeof(SubGhzProtocolDecoderCameTwee));
instance->base.protocol = &subghz_protocol_came_twee;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_came_twee_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCameTwee* instance = context;
free(instance);
}
void subghz_protocol_decoder_came_twee_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCameTwee* instance = context;
instance->decoder.parser_step = CameTweeDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
void subghz_protocol_decoder_came_twee_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderCameTwee* instance = context;
ManchesterEvent event = ManchesterEventReset;
switch(instance->decoder.parser_step) {
case CameTweeDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long * 51) <
subghz_protocol_came_twee_const.te_delta * 20)) {
//Found header CAME
instance->decoder.parser_step = CameTweeDecoderStepDecoderData;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongLow,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
}
break;
case CameTweeDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_short) <
subghz_protocol_came_twee_const.te_delta) {
event = ManchesterEventShortLow;
} else if(
DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long) <
subghz_protocol_came_twee_const.te_delta) {
event = ManchesterEventLongLow;
} else if(
duration >= (subghz_protocol_came_twee_const.te_long * 2 +
subghz_protocol_came_twee_const.te_delta)) {
if(instance->decoder.decode_count_bit >=
subghz_protocol_came_twee_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;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongLow,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
} else {
instance->decoder.parser_step = CameTweeDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_short) <
subghz_protocol_came_twee_const.te_delta) {
event = ManchesterEventShortHigh;
} else if(
DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long) <
subghz_protocol_came_twee_const.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->decoder.parser_step = CameTweeDecoderStepReset;
}
}
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_came_twee_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderCameTwee* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_came_twee_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderCameTwee* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderCameTwee* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_came_twee_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderCameTwee* instance = context;
subghz_protocol_came_twee_remote_controller(&instance->generic);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Btn:%lX\r\n"
"DIP:" DIP_PATTERN "\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
instance->generic.btn,
CNT_TO_DIP(instance->generic.cnt));
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_CAME_TWEE_NAME "CAME TWEE"
typedef struct SubGhzProtocolDecoderCameTwee SubGhzProtocolDecoderCameTwee;
typedef struct SubGhzProtocolEncoderCameTwee SubGhzProtocolEncoderCameTwee;
extern const SubGhzProtocolDecoder subghz_protocol_came_twee_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_came_twee_encoder;
extern const SubGhzProtocol subghz_protocol_came_twee;
void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_came_twee_free(void* context);
bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_came_twee_stop(void* context);
LevelDuration subghz_protocol_encoder_came_twee_yield(void* context);
void* subghz_protocol_decoder_came_twee_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_came_twee_free(void* context);
void subghz_protocol_decoder_came_twee_reset(void* context);
void subghz_protocol_decoder_came_twee_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_came_twee_get_hash_data(void* context);
bool subghz_protocol_decoder_came_twee_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_came_twee_get_string(void* context, string_t output);

View File

@@ -0,0 +1,218 @@
#include "faac_slh.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolFaacSHL"
static const SubGhzBlockConst subghz_protocol_faac_slh_const = {
.te_short = 255,
.te_long = 595,
.te_delta = 100,
.min_count_bit_for_found = 64,
};
struct SubGhzProtocolDecoderFaacSLH {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderFaacSLH {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
FaacSLHDecoderStepReset = 0,
FaacSLHDecoderStepFoundPreambula,
FaacSLHDecoderStepSaveDuration,
FaacSLHDecoderStepCheckDuration,
} FaacSLHDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder = {
.alloc = subghz_protocol_decoder_faac_slh_alloc,
.free = subghz_protocol_decoder_faac_slh_free,
.feed = subghz_protocol_decoder_faac_slh_feed,
.reset = subghz_protocol_decoder_faac_slh_reset,
.get_hash_data = subghz_protocol_decoder_faac_slh_get_hash_data,
.serialize = subghz_protocol_decoder_faac_slh_serialize,
.deserialize = subghz_protocol_decoder_faac_slh_deserialize,
.get_string = subghz_protocol_decoder_faac_slh_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_faac_slh = {
.name = SUBGHZ_PROTOCOL_FAAC_SLH_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_faac_slh_decoder,
.encoder = &subghz_protocol_faac_slh_encoder,
};
void* subghz_protocol_decoder_faac_slh_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderFaacSLH* instance = malloc(sizeof(SubGhzProtocolDecoderFaacSLH));
instance->base.protocol = &subghz_protocol_faac_slh;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_faac_slh_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderFaacSLH* instance = context;
free(instance);
}
void subghz_protocol_decoder_faac_slh_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderFaacSLH* instance = context;
instance->decoder.parser_step = FaacSLHDecoderStepReset;
}
void subghz_protocol_decoder_faac_slh_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderFaacSLH* instance = context;
switch(instance->decoder.parser_step) {
case FaacSLHDecoderStepReset:
if((level) && (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long * 2) <
subghz_protocol_faac_slh_const.te_delta * 3)) {
instance->decoder.parser_step = FaacSLHDecoderStepFoundPreambula;
}
break;
case FaacSLHDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long * 2) <
subghz_protocol_faac_slh_const.te_delta * 3)) {
//Found Preambula
instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = FaacSLHDecoderStepReset;
}
break;
case FaacSLHDecoderStepSaveDuration:
if(level) {
if(duration >= (subghz_protocol_faac_slh_const.te_short * 3 +
subghz_protocol_faac_slh_const.te_delta)) {
instance->decoder.parser_step = FaacSLHDecoderStepFoundPreambula;
if(instance->decoder.decode_count_bit >=
subghz_protocol_faac_slh_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 = FaacSLHDecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = FaacSLHDecoderStepReset;
}
break;
case FaacSLHDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_faac_slh_const.te_short) <
subghz_protocol_faac_slh_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long) <
subghz_protocol_faac_slh_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_faac_slh_const.te_long) <
subghz_protocol_faac_slh_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_short) <
subghz_protocol_faac_slh_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = FaacSLHDecoderStepReset;
}
} else {
instance->decoder.parser_step = FaacSLHDecoderStepReset;
}
break;
}
}
static void subghz_protocol_faac_slh_check_remote_controller(SubGhzBlockGeneric* instance) {
uint64_t code_found_reverse =
subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
instance->serial = code_fix & 0xFFFFFFF;
instance->btn = (code_fix >> 28) & 0x0F;
}
uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderFaacSLH* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_faac_slh_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderFaacSLH* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderFaacSLH* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_faac_slh_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderFaacSLH* instance = context;
subghz_protocol_faac_slh_check_remote_controller(&instance->generic);
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
uint32_t code_hop = (code_found_reverse >> 32) & 0xFFFFFFFF;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%lX%08lX\r\n"
"Fix:%08lX \r\n"
"Hop:%08lX \r\n"
"Sn:%07lX Btn:%lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
(uint32_t)instance->generic.data,
code_fix,
code_hop,
instance->generic.serial,
instance->generic.btn);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_FAAC_SLH_NAME "Faac SLH"
typedef struct SubGhzProtocolDecoderFaacSLH SubGhzProtocolDecoderFaacSLH;
typedef struct SubGhzProtocolEncoderFaacSLH SubGhzProtocolEncoderFaacSLH;
extern const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder;
extern const SubGhzProtocol subghz_protocol_faac_slh;
void* subghz_protocol_decoder_faac_slh_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_faac_slh_free(void* context);
void subghz_protocol_decoder_faac_slh_reset(void* context);
void subghz_protocol_decoder_faac_slh_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context);
bool subghz_protocol_decoder_faac_slh_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_faac_slh_get_string(void* context, string_t output);

View File

@@ -0,0 +1,308 @@
#include "gate_tx.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolGateTx"
static const SubGhzBlockConst subghz_protocol_gate_tx_const = {
.te_short = 350,
.te_long = 700,
.te_delta = 100,
.min_count_bit_for_found = 24,
};
struct SubGhzProtocolDecoderGateTx {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderGateTx {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
GateTXDecoderStepReset = 0,
GateTXDecoderStepFoundStartBit,
GateTXDecoderStepSaveDuration,
GateTXDecoderStepCheckDuration,
} GateTXDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_gate_tx_decoder = {
.alloc = subghz_protocol_decoder_gate_tx_alloc,
.free = subghz_protocol_decoder_gate_tx_free,
.feed = subghz_protocol_decoder_gate_tx_feed,
.reset = subghz_protocol_decoder_gate_tx_reset,
.get_hash_data = subghz_protocol_decoder_gate_tx_get_hash_data,
.serialize = subghz_protocol_decoder_gate_tx_serialize,
.deserialize = subghz_protocol_decoder_gate_tx_deserialize,
.get_string = subghz_protocol_decoder_gate_tx_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_gate_tx_encoder = {
.alloc = subghz_protocol_encoder_gate_tx_alloc,
.free = subghz_protocol_encoder_gate_tx_free,
.deserialize = subghz_protocol_encoder_gate_tx_deserialize,
.stop = subghz_protocol_encoder_gate_tx_stop,
.yield = subghz_protocol_encoder_gate_tx_yield,
};
const SubGhzProtocol subghz_protocol_gate_tx = {
.name = SUBGHZ_PROTOCOL_GATE_TX_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_gate_tx_decoder,
.encoder = &subghz_protocol_gate_tx_encoder,
};
void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderGateTx* instance = malloc(sizeof(SubGhzProtocolEncoderGateTx));
instance->base.protocol = &subghz_protocol_gate_tx;
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_gate_tx_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderGateTx* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool subghz_protocol_encoder_gate_tx_get_upload(SubGhzProtocolEncoderGateTx* 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_gate_tx_const.te_short * 49);
//Send start bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_long);
//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_gate_tx_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_short);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_gate_tx_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_long);
}
}
return true;
}
bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderGateTx* 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_gate_tx_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_gate_tx_stop(void* context) {
SubGhzProtocolEncoderGateTx* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context) {
SubGhzProtocolEncoderGateTx* 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_gate_tx_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderGateTx* instance = malloc(sizeof(SubGhzProtocolDecoderGateTx));
instance->base.protocol = &subghz_protocol_gate_tx;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_gate_tx_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderGateTx* instance = context;
free(instance);
}
void subghz_protocol_decoder_gate_tx_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderGateTx* instance = context;
instance->decoder.parser_step = GateTXDecoderStepReset;
}
void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderGateTx* instance = context;
switch(instance->decoder.parser_step) {
case GateTXDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_short * 47) <
subghz_protocol_gate_tx_const.te_delta * 47)) {
//Found Preambula
instance->decoder.parser_step = GateTXDecoderStepFoundStartBit;
}
break;
case GateTXDecoderStepFoundStartBit:
if(level && ((DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_long) <
subghz_protocol_gate_tx_const.te_delta * 3))) {
//Found start bit
instance->decoder.parser_step = GateTXDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = GateTXDecoderStepReset;
}
break;
case GateTXDecoderStepSaveDuration:
if(!level) {
if(duration >= (subghz_protocol_gate_tx_const.te_short * 10 +
subghz_protocol_gate_tx_const.te_delta)) {
instance->decoder.parser_step = GateTXDecoderStepFoundStartBit;
if(instance->decoder.decode_count_bit >=
subghz_protocol_gate_tx_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 = GateTXDecoderStepCheckDuration;
}
}
break;
case GateTXDecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_gate_tx_const.te_short) <
subghz_protocol_gate_tx_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_long) <
subghz_protocol_gate_tx_const.te_delta * 3)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = GateTXDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_gate_tx_const.te_long) <
subghz_protocol_gate_tx_const.te_delta * 3) &&
(DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_short) <
subghz_protocol_gate_tx_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = GateTXDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = GateTXDecoderStepReset;
}
} else {
instance->decoder.parser_step = GateTXDecoderStepReset;
}
break;
}
}
static void subghz_protocol_gate_tx_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_gate_tx_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderGateTx* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_gate_tx_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderGateTx* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderGateTx* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_gate_tx_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderGateTx* instance = context;
subghz_protocol_gate_tx_check_remote_controller(&instance->generic);
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%06lX\r\n"
"Sn:%05lX Btn:%lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data & 0xFFFFFF),
instance->generic.serial,
instance->generic.btn);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_GATE_TX_NAME "GateTX"
typedef struct SubGhzProtocolDecoderGateTx SubGhzProtocolDecoderGateTx;
typedef struct SubGhzProtocolEncoderGateTx SubGhzProtocolEncoderGateTx;
extern const SubGhzProtocolDecoder subghz_protocol_gate_tx_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_gate_tx_encoder;
extern const SubGhzProtocol subghz_protocol_gate_tx;
void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_gate_tx_free(void* context);
bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_gate_tx_stop(void* context);
LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context);
void* subghz_protocol_decoder_gate_tx_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_gate_tx_free(void* context);
void subghz_protocol_decoder_gate_tx_reset(void* context);
void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_gate_tx_get_hash_data(void* context);
bool subghz_protocol_decoder_gate_tx_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_gate_tx_get_string(void* context, string_t output);

View File

@@ -0,0 +1,331 @@
#include "hormann.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolHormannHSM"
static const SubGhzBlockConst subghz_protocol_hormann_const = {
.te_short = 500,
.te_long = 1000,
.te_delta = 200,
.min_count_bit_for_found = 44,
};
struct SubGhzProtocolDecoderHormann {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderHormann {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
HormannDecoderStepReset = 0,
HormannDecoderStepFoundStartHeader,
HormannDecoderStepFoundHeader,
HormannDecoderStepFoundStartBit,
HormannDecoderStepSaveDuration,
HormannDecoderStepCheckDuration,
} HormannDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_hormann_decoder = {
.alloc = subghz_protocol_decoder_hormann_alloc,
.free = subghz_protocol_decoder_hormann_free,
.feed = subghz_protocol_decoder_hormann_feed,
.reset = subghz_protocol_decoder_hormann_reset,
.get_hash_data = subghz_protocol_decoder_hormann_get_hash_data,
.serialize = subghz_protocol_decoder_hormann_serialize,
.deserialize = subghz_protocol_decoder_hormann_deserialize,
.get_string = subghz_protocol_decoder_hormann_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_hormann_encoder = {
.alloc = subghz_protocol_encoder_hormann_alloc,
.free = subghz_protocol_encoder_hormann_free,
.deserialize = subghz_protocol_encoder_hormann_deserialize,
.stop = subghz_protocol_encoder_hormann_stop,
.yield = subghz_protocol_encoder_hormann_yield,
};
const SubGhzProtocol subghz_protocol_hormann = {
.name = SUBGHZ_PROTOCOL_HORMANN_HSM_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save |
SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_hormann_decoder,
.encoder = &subghz_protocol_hormann_encoder,
};
void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderHormann* instance = malloc(sizeof(SubGhzProtocolEncoderHormann));
instance->base.protocol = &subghz_protocol_hormann;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 10;
instance->encoder.size_upload = 2048;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_runing = false;
return instance;
}
void subghz_protocol_encoder_hormann_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderHormann* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHormann* instance) {
furi_assert(instance);
size_t index = 0;
size_t size_upload = 3 + (instance->generic.data_count_bit * 2 + 2) * 20 + 1;
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_hormann_const.te_short * 64);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 64);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short * 64);
instance->encoder.repeat = 10; //original remote does 10 repeats
for(size_t repeat = 0; repeat < 20; repeat++) {
//Send start bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short);
//Send key data
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_long);
}
}
}
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24);
return true;
}
bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderHormann* 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_hormann_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_hormann_stop(void* context) {
SubGhzProtocolEncoderHormann* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_hormann_yield(void* context) {
SubGhzProtocolEncoderHormann* 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_hormann_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderHormann* instance = malloc(sizeof(SubGhzProtocolDecoderHormann));
instance->base.protocol = &subghz_protocol_hormann;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_hormann_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderHormann* instance = context;
free(instance);
}
void subghz_protocol_decoder_hormann_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderHormann* instance = context;
instance->decoder.parser_step = HormannDecoderStepReset;
}
void subghz_protocol_decoder_hormann_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderHormann* instance = context;
switch(instance->decoder.parser_step) {
case HormannDecoderStepReset:
if((level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 64) <
subghz_protocol_hormann_const.te_delta * 64)) {
instance->decoder.parser_step = HormannDecoderStepFoundStartHeader;
}
break;
case HormannDecoderStepFoundStartHeader:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 64) <
subghz_protocol_hormann_const.te_delta * 64)) {
instance->decoder.parser_step = HormannDecoderStepFoundHeader;
} else {
instance->decoder.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepFoundHeader:
if((level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 24) <
subghz_protocol_hormann_const.te_delta * 24)) {
instance->decoder.parser_step = HormannDecoderStepFoundStartBit;
} else {
instance->decoder.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepFoundStartBit:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short) <
subghz_protocol_hormann_const.te_delta)) {
instance->decoder.parser_step = HormannDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepSaveDuration:
if(level) { //save interval
if(duration >= (subghz_protocol_hormann_const.te_short * 5)) {
instance->decoder.parser_step = HormannDecoderStepFoundStartBit;
if(instance->decoder.decode_count_bit >=
subghz_protocol_hormann_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);
}
break;
}
instance->decoder.te_last = duration;
instance->decoder.parser_step = HormannDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_hormann_const.te_short) <
subghz_protocol_hormann_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_hormann_const.te_long) <
subghz_protocol_hormann_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = HormannDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_hormann_const.te_long) <
subghz_protocol_hormann_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short) <
subghz_protocol_hormann_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = HormannDecoderStepSaveDuration;
} else
instance->decoder.parser_step = HormannDecoderStepReset;
} else {
instance->decoder.parser_step = HormannDecoderStepReset;
}
break;
}
}
static void subghz_protocol_hormann_check_remote_controller(SubGhzBlockGeneric* instance) {
instance->btn = (instance->data >> 4) & 0xF;
}
uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderHormann* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_hormann_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderHormann* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderHormann* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_hormann_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderHormann* instance = context;
subghz_protocol_hormann_check_remote_controller(&instance->generic);
string_cat_printf(
output,
"%s\r\n"
"%dbit\r\n"
"Key:0x%03lX%08lX\r\n"
"Btn:0x%01X\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
(uint32_t)instance->generic.data,
instance->generic.btn);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_HORMANN_HSM_NAME "Hormann HSM"
typedef struct SubGhzProtocolDecoderHormann SubGhzProtocolDecoderHormann;
typedef struct SubGhzProtocolEncoderHormann SubGhzProtocolEncoderHormann;
extern const SubGhzProtocolDecoder subghz_protocol_hormann_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_hormann_encoder;
extern const SubGhzProtocol subghz_protocol_hormann;
void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_hormann_free(void* context);
bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_hormann_stop(void* context);
LevelDuration subghz_protocol_encoder_hormann_yield(void* context);
void* subghz_protocol_decoder_hormann_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_hormann_free(void* context);
void subghz_protocol_decoder_hormann_reset(void* context);
void subghz_protocol_decoder_hormann_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context);
bool subghz_protocol_decoder_hormann_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_hormann_get_string(void* context, string_t output);

218
lib/subghz/protocols/ido.c Normal file
View File

@@ -0,0 +1,218 @@
#include "ido.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocol_iDo_117/111"
static const SubGhzBlockConst subghz_protocol_ido_const = {
.te_short = 450,
.te_long = 1450,
.te_delta = 150,
.min_count_bit_for_found = 48,
};
struct SubGhzProtocolDecoderIDo {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderIDo {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
IDoDecoderStepReset = 0,
IDoDecoderStepFoundPreambula,
IDoDecoderStepSaveDuration,
IDoDecoderStepCheckDuration,
} IDoDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_ido_decoder = {
.alloc = subghz_protocol_decoder_ido_alloc,
.free = subghz_protocol_decoder_ido_free,
.feed = subghz_protocol_decoder_ido_feed,
.reset = subghz_protocol_decoder_ido_reset,
.get_hash_data = subghz_protocol_decoder_ido_get_hash_data,
.deserialize = subghz_protocol_decoder_ido_deserialize,
.serialize = subghz_protocol_decoder_ido_serialize,
.get_string = subghz_protocol_decoder_ido_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_ido_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_ido = {
.name = SUBGHZ_PROTOCOL_IDO_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_ido_decoder,
.encoder = &subghz_protocol_ido_encoder,
};
void* subghz_protocol_decoder_ido_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderIDo* instance = malloc(sizeof(SubGhzProtocolDecoderIDo));
instance->base.protocol = &subghz_protocol_ido;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_ido_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderIDo* instance = context;
free(instance);
}
void subghz_protocol_decoder_ido_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderIDo* instance = context;
instance->decoder.parser_step = IDoDecoderStepReset;
}
void subghz_protocol_decoder_ido_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderIDo* instance = context;
switch(instance->decoder.parser_step) {
case IDoDecoderStepReset:
if((level) && (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short * 10) <
subghz_protocol_ido_const.te_delta * 5)) {
instance->decoder.parser_step = IDoDecoderStepFoundPreambula;
}
break;
case IDoDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short * 10) <
subghz_protocol_ido_const.te_delta * 5)) {
//Found Preambula
instance->decoder.parser_step = IDoDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = IDoDecoderStepReset;
}
break;
case IDoDecoderStepSaveDuration:
if(level) {
if(duration >=
(subghz_protocol_ido_const.te_short * 5 + subghz_protocol_ido_const.te_delta)) {
instance->decoder.parser_step = IDoDecoderStepFoundPreambula;
if(instance->decoder.decode_count_bit >=
subghz_protocol_ido_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 = IDoDecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = IDoDecoderStepReset;
}
break;
case IDoDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ido_const.te_short) <
subghz_protocol_ido_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_ido_const.te_long) <
subghz_protocol_ido_const.te_delta * 3)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = IDoDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ido_const.te_short) <
subghz_protocol_ido_const.te_delta * 3) &&
(DURATION_DIFF(duration, subghz_protocol_ido_const.te_short) <
subghz_protocol_ido_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = IDoDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = IDoDecoderStepReset;
}
} else {
instance->decoder.parser_step = IDoDecoderStepReset;
}
break;
}
}
static void subghz_protocol_ido_check_remote_controller(SubGhzBlockGeneric* instance) {
uint64_t code_found_reverse =
subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFF;
instance->serial = code_fix & 0xFFFFF;
instance->btn = (code_fix >> 20) & 0x0F;
}
uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderIDo* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_ido_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderIDo* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderIDo* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_ido_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderIDo* instance = context;
subghz_protocol_ido_check_remote_controller(&instance->generic);
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFF;
uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFFF;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Fix:%06lX \r\n"
"Hop:%06lX \r\n"
"Sn:%05lX Btn:%lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
(uint32_t)instance->generic.data,
code_fix,
code_hop,
instance->generic.serial,
instance->generic.btn);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_IDO_NAME "iDo 117/111"
typedef struct SubGhzProtocolDecoderIDo SubGhzProtocolDecoderIDo;
typedef struct SubGhzProtocolEncoderIDo SubGhzProtocolEncoderIDo;
extern const SubGhzProtocolDecoder subghz_protocol_ido_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_ido_encoder;
extern const SubGhzProtocol subghz_protocol_ido;
void* subghz_protocol_decoder_ido_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_ido_free(void* context);
void subghz_protocol_decoder_ido_reset(void* context);
void subghz_protocol_decoder_ido_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context);
bool subghz_protocol_decoder_ido_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_ido_get_string(void* context, string_t output);

View File

@@ -0,0 +1,681 @@
#include "keeloq.h"
#include "keeloq_common.h"
#include "../subghz_keystore.h"
#include <m-string.h>
#include <m-array.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolkeeloq"
static const SubGhzBlockConst subghz_protocol_keeloq_const = {
.te_short = 400,
.te_long = 800,
.te_delta = 140,
.min_count_bit_for_found = 64,
};
struct SubGhzProtocolDecoderKeeloq {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
SubGhzKeystore* keystore;
const char* manufacture_name;
};
struct SubGhzProtocolEncoderKeeloq {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
SubGhzKeystore* keystore;
const char* manufacture_name;
};
typedef enum {
KeeloqDecoderStepReset = 0,
KeeloqDecoderStepCheckPreambula,
KeeloqDecoderStepSaveDuration,
KeeloqDecoderStepCheckDuration,
} KeeloqDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_keeloq_decoder = {
.alloc = subghz_protocol_decoder_keeloq_alloc,
.free = subghz_protocol_decoder_keeloq_free,
.feed = subghz_protocol_decoder_keeloq_feed,
.reset = subghz_protocol_decoder_keeloq_reset,
.get_hash_data = subghz_protocol_decoder_keeloq_get_hash_data,
.serialize = subghz_protocol_decoder_keeloq_serialize,
.deserialize = subghz_protocol_decoder_keeloq_deserialize,
.get_string = subghz_protocol_decoder_keeloq_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_keeloq_encoder = {
.alloc = subghz_protocol_encoder_keeloq_alloc,
.free = subghz_protocol_encoder_keeloq_free,
.deserialize = subghz_protocol_encoder_keeloq_deserialize,
.stop = subghz_protocol_encoder_keeloq_stop,
.yield = subghz_protocol_encoder_keeloq_yield,
};
const SubGhzProtocol subghz_protocol_keeloq = {
.name = SUBGHZ_PROTOCOL_KEELOQ_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_315 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_keeloq_decoder,
.encoder = &subghz_protocol_keeloq_encoder,
};
static void subghz_protocol_keeloq_check_remote_controller(
SubGhzBlockGeneric* instance,
SubGhzKeystore* keystore,
const char** manufacture_name);
void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderKeeloq* instance = malloc(sizeof(SubGhzProtocolEncoderKeeloq));
instance->base.protocol = &subghz_protocol_keeloq;
instance->generic.protocol_name = instance->base.protocol->name;
instance->keystore = subghz_environment_get_keystore(environment);
instance->encoder.repeat = 10;
instance->encoder.size_upload = 256;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_runing = false;
return instance;
}
void subghz_protocol_encoder_keeloq_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderKeeloq* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool subghz_protocol_keeloq_gen_data(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) {
instance->generic.cnt++;
uint32_t fix = btn << 28 | instance->generic.serial;
uint32_t decrypt = btn << 28 |
(instance->generic.serial & 0x3FF)
<< 16 | //ToDo in some protocols the discriminator is 0
instance->generic.cnt;
uint32_t hop = 0;
uint64_t man = 0;
int res = 0;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Simple Learning
man =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
hop = 0; //todo
break;
}
break;
}
}
if(hop) {
uint64_t yek = (uint64_t)fix << 32 | hop;
instance->generic.data =
subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit);
return true;
} else {
instance->manufacture_name = "Unknown";
return false;
}
}
bool subghz_protocol_keeloq_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint16_t cnt,
const char* manufacture_name,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolEncoderKeeloq* instance = context;
instance->generic.serial = serial;
instance->generic.cnt = cnt;
instance->manufacture_name = manufacture_name;
instance->generic.data_count_bit = 64;
bool res = subghz_protocol_keeloq_gen_data(instance, btn);
if(res) {
res =
subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
return res;
}
static bool
subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) {
furi_assert(instance);
//gen new key
if(subghz_protocol_keeloq_gen_data(instance, btn)) {
//ToDo Update display data
// if(instance->common.callback)
// instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
} else {
return false;
}
size_t index = 0;
size_t size_upload = 11 * 2 + 2 + (instance->generic.data_count_bit * 2) + 4;
if(size_upload > instance->encoder.size_upload) {
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
return false;
} else {
instance->encoder.size_upload = size_upload;
}
//Send header
for(uint8_t i = 11; i > 0; i--) {
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short);
}
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 10);
//Send key data
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_long);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short);
}
}
// +send 2 status bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_long);
// send end
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 40);
return true;
}
bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderKeeloq* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
subghz_protocol_keeloq_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
if(strcmp(instance->manufacture_name, "DoorHan")) {
break;
}
//optional parameter parameter
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
subghz_protocol_encoder_keeloq_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_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_keeloq_stop(void* context) {
SubGhzProtocolEncoderKeeloq* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_keeloq_yield(void* context) {
SubGhzProtocolEncoderKeeloq* 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_keeloq_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderKeeloq* instance = malloc(sizeof(SubGhzProtocolDecoderKeeloq));
instance->base.protocol = &subghz_protocol_keeloq;
instance->generic.protocol_name = instance->base.protocol->name;
instance->keystore = subghz_environment_get_keystore(environment);
return instance;
}
void subghz_protocol_decoder_keeloq_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;
free(instance);
}
void subghz_protocol_decoder_keeloq_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;
instance->decoder.parser_step = KeeloqDecoderStepReset;
}
void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;
switch(instance->decoder.parser_step) {
case KeeloqDecoderStepReset:
if((level) && DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) <
subghz_protocol_keeloq_const.te_delta) {
instance->decoder.parser_step = KeeloqDecoderStepCheckPreambula;
instance->header_count++;
}
break;
case KeeloqDecoderStepCheckPreambula:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) <
subghz_protocol_keeloq_const.te_delta)) {
instance->decoder.parser_step = KeeloqDecoderStepReset;
break;
}
if((instance->header_count > 2) &&
(DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short * 10) <
subghz_protocol_keeloq_const.te_delta * 10)) {
// Found header
instance->decoder.parser_step = KeeloqDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = KeeloqDecoderStepReset;
instance->header_count = 0;
}
break;
case KeeloqDecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = KeeloqDecoderStepCheckDuration;
}
break;
case KeeloqDecoderStepCheckDuration:
if(!level) {
if(duration >= (subghz_protocol_keeloq_const.te_short * 2 +
subghz_protocol_keeloq_const.te_delta)) {
// Found end TX
instance->decoder.parser_step = KeeloqDecoderStepReset;
if(instance->decoder.decode_count_bit >=
subghz_protocol_keeloq_const.min_count_bit_for_found) {
if(instance->generic.data != instance->decoder.decode_data) {
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;
instance->header_count = 0;
}
break;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_short) <
subghz_protocol_keeloq_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_long) <
subghz_protocol_keeloq_const.te_delta)) {
if(instance->decoder.decode_count_bit <
subghz_protocol_keeloq_const.min_count_bit_for_found) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
}
instance->decoder.parser_step = KeeloqDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_long) <
subghz_protocol_keeloq_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) <
subghz_protocol_keeloq_const.te_delta)) {
if(instance->decoder.decode_count_bit <
subghz_protocol_keeloq_const.min_count_bit_for_found) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
}
instance->decoder.parser_step = KeeloqDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = KeeloqDecoderStepReset;
instance->header_count = 0;
}
} else {
instance->decoder.parser_step = KeeloqDecoderStepReset;
instance->header_count = 0;
}
break;
}
}
static inline bool subghz_protocol_keeloq_check_decrypt(
SubGhzBlockGeneric* instance,
uint32_t decrypt,
uint8_t btn,
uint32_t end_serial) {
furi_assert(instance);
if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) ||
((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) {
instance->cnt = decrypt & 0x0000FFFF;
return true;
}
return false;
}
/** Checking the accepted code against the database manafacture key
*
* @param instance SubGhzProtocolKeeloq instance
* @param fix fix part of the parcel
* @param hop hop encrypted part of the parcel
* @return true on successful search
*/
static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
SubGhzBlockGeneric* instance,
uint32_t fix,
uint32_t hop,
SubGhzKeystore* keystore,
const char** manufacture_name) {
// protocol HCS300 uses 10 bits in discriminator, HCS200 uses 8 bits, for backward compatibility, we are looking for the 8-bit pattern
// HCS300 -> uint16_t end_serial = (uint16_t)(fix & 0x3FF);
// HCS200 -> uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint8_t btn = (uint8_t)(fix >> 28);
uint32_t decrypt = 0;
uint64_t man;
uint32_t seed = 0;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_SECURE:
man = subghz_protocol_keeloq_common_secure_learning(
fix, seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Secure Learning
man = subghz_protocol_keeloq_common_secure_learning(
fix, seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Magic xor type1 learning
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
}
}
*manufacture_name = "Unknown";
instance->cnt = 0;
return 0;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolKeeloq instance
*/
static void subghz_protocol_keeloq_check_remote_controller(
SubGhzBlockGeneric* instance,
SubGhzKeystore* keystore,
const char** manufacture_name) {
uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff;
// Check key AN-Motors
if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) &&
(key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) {
*manufacture_name = "AN-Motors";
instance->cnt = key_hop >> 16;
} else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) {
*manufacture_name = "HCS101";
instance->cnt = key_hop >> 16;
} else {
subghz_protocol_keeloq_check_remote_controller_selector(
instance, key_fix, key_hop, keystore, manufacture_name);
}
instance->serial = key_fix & 0x0FFFFFFF;
instance->btn = key_fix >> 28;
}
uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_keeloq_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;
subghz_protocol_keeloq_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
bool res =
subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
if(res && !flipper_format_write_string_cstr(
flipper_format, "Manufacture", instance->manufacture_name)) {
FURI_LOG_E(TAG, "Unable to add manufacture name");
res = false;
}
return res;
}
bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
res = true;
} while(false);
return res;
}
void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;
subghz_protocol_keeloq_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%01lX\r\n"
"MF:%s\r\n"
"Sn:0x%07lX \r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
instance->generic.cnt,
code_found_reverse_lo,
instance->generic.btn,
instance->manufacture_name,
instance->generic.serial);
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_KEELOQ_NAME "KeeLoq"
typedef struct SubGhzProtocolDecoderKeeloq SubGhzProtocolDecoderKeeloq;
typedef struct SubGhzProtocolEncoderKeeloq SubGhzProtocolEncoderKeeloq;
extern const SubGhzProtocolDecoder subghz_protocol_keeloq_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_keeloq_encoder;
extern const SubGhzProtocol subghz_protocol_keeloq;
void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_keeloq_free(void* context);
bool subghz_protocol_keeloq_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint16_t cnt,
const char* manufacture_name,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_keeloq_stop(void* context);
LevelDuration subghz_protocol_encoder_keeloq_yield(void* context);
void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_keeloq_free(void* context);
void subghz_protocol_decoder_keeloq_reset(void* context);
void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context);
bool subghz_protocol_decoder_keeloq_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output);

View File

@@ -1,4 +1,4 @@
#include "subghz_protocol_keeloq_common.h"
#include "keeloq_common.h"
#include <furi.h>
@@ -8,7 +8,7 @@
/** Simple Learning Encrypt
* @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
* @param key - manufacture (64bit)
* @return keelog encrypt data
* @return keeloq encrypt data
*/
inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key) {
uint32_t x = data, r;

View File

@@ -1,6 +1,6 @@
#pragma once
#include "subghz_protocol_common.h"
#include "file_worker.h"
#include "base.h"
#include <furi.h>
@@ -29,12 +29,12 @@
/** Simple Learning Encrypt
* @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
* @param key - manufacture (64bit)
* @return keelog encrypt data
* @return keeloq encrypt data
*/
uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key);
/** Simple Learning Decrypt
* @param data - keelog encrypt data
* @param data - keeloq encrypt data
* @param key - manufacture (64bit)
* @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
*/

268
lib/subghz/protocols/kia.c Normal file
View File

@@ -0,0 +1,268 @@
#include "kia.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocoKIA"
static const SubGhzBlockConst subghz_protocol_kia_const = {
.te_short = 250,
.te_long = 500,
.te_delta = 100,
.min_count_bit_for_found = 60,
};
struct SubGhzProtocolDecoderKIA {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
};
struct SubGhzProtocolEncoderKIA {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
KIADecoderStepReset = 0,
KIADecoderStepCheckPreambula,
KIADecoderStepSaveDuration,
KIADecoderStepCheckDuration,
} KIADecoderStep;
const SubGhzProtocolDecoder subghz_protocol_kia_decoder = {
.alloc = subghz_protocol_decoder_kia_alloc,
.free = subghz_protocol_decoder_kia_free,
.feed = subghz_protocol_decoder_kia_feed,
.reset = subghz_protocol_decoder_kia_reset,
.get_hash_data = subghz_protocol_decoder_kia_get_hash_data,
.serialize = subghz_protocol_decoder_kia_serialize,
.deserialize = subghz_protocol_decoder_kia_deserialize,
.get_string = subghz_protocol_decoder_kia_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_kia_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_kia = {
.name = SUBGHZ_PROTOCOL_KIA_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_kia_decoder,
.encoder = &subghz_protocol_kia_encoder,
};
void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderKIA* instance = malloc(sizeof(SubGhzProtocolDecoderKIA));
instance->base.protocol = &subghz_protocol_kia;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_kia_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
free(instance);
}
void subghz_protocol_decoder_kia_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
instance->decoder.parser_step = KIADecoderStepReset;
}
void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
switch(instance->decoder.parser_step) {
case KIADecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta)) {
instance->decoder.parser_step = KIADecoderStepCheckPreambula;
instance->decoder.te_last = duration;
instance->header_count = 0;
}
break;
case KIADecoderStepCheckPreambula:
if(!level) {
if((DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta) ||
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta)) {
instance->decoder.te_last = duration;
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
} else if(
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta)) {
// Found header
instance->header_count++;
break;
} else if(
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta)) {
// Found start bit
if(instance->header_count > 15) {
instance->decoder.parser_step = KIADecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 1;
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
break;
case KIADecoderStepSaveDuration:
if(!level) {
if(duration >=
(subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2)) {
//Found stop bit
instance->decoder.parser_step = KIADecoderStepReset;
if(instance->decoder.decode_count_bit >=
subghz_protocol_kia_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 = KIADecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
break;
case KIADecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = KIADecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = KIADecoderStepSaveDuration;
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_kia_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) ^ 0x7F);
else
crc <<= 1;
}
}
return crc;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolKIA instance
*/
static void subghz_protocol_kia_check_remote_controller(SubGhzBlockGeneric* instance) {
/*
* 0x0F 0112 43B04EC 1 7D
* 0x0F 0113 43B04EC 1 DF
* 0x0F 0114 43B04EC 1 30
* 0x0F 0115 43B04EC 2 13
* 0x0F 0116 43B04EC 3 F5
* CNT Serial K CRC8 Kia (CRC8, poly 0x7f, start_crc 0x08)
*/
instance->serial = (uint32_t)((instance->data >> 12) & 0x0FFFFFFF);
instance->btn = (instance->data >> 8) & 0x0F;
instance->cnt = (instance->data >> 40) & 0xFFFF;
}
uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_kia_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_kia_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
subghz_protocol_kia_check_remote_controller(&instance->generic);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Sn:%07lX Btn:%lX Cnt:%04X\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
instance->generic.serial,
instance->generic.btn,
instance->generic.cnt);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_KIA_NAME "KIA Seed"
typedef struct SubGhzProtocolDecoderKIA SubGhzProtocolDecoderKIA;
typedef struct SubGhzProtocolEncoderKIA SubGhzProtocolEncoderKIA;
extern const SubGhzProtocolDecoder subghz_protocol_kia_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_kia_encoder;
extern const SubGhzProtocol subghz_protocol_kia;
void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_kia_free(void* context);
void subghz_protocol_decoder_kia_reset(void* context);
void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context);
bool subghz_protocol_decoder_kia_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_kia_get_string(void* context, string_t output);

View File

@@ -0,0 +1,375 @@
#include "nero_radio.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolNeroRadio"
static const SubGhzBlockConst subghz_protocol_nero_radio_const = {
.te_short = 200,
.te_long = 400,
.te_delta = 80,
.min_count_bit_for_found = 56,
};
struct SubGhzProtocolDecoderNeroRadio {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
};
struct SubGhzProtocolEncoderNeroRadio {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
NeroRadioDecoderStepReset = 0,
NeroRadioDecoderStepCheckPreambula,
NeroRadioDecoderStepSaveDuration,
NeroRadioDecoderStepCheckDuration,
} NeroRadioDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_nero_radio_decoder = {
.alloc = subghz_protocol_decoder_nero_radio_alloc,
.free = subghz_protocol_decoder_nero_radio_free,
.feed = subghz_protocol_decoder_nero_radio_feed,
.reset = subghz_protocol_decoder_nero_radio_reset,
.get_hash_data = subghz_protocol_decoder_nero_radio_get_hash_data,
.serialize = subghz_protocol_decoder_nero_radio_serialize,
.deserialize = subghz_protocol_decoder_nero_radio_deserialize,
.get_string = subghz_protocol_decoder_nero_radio_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_nero_radio_encoder = {
.alloc = subghz_protocol_encoder_nero_radio_alloc,
.free = subghz_protocol_encoder_nero_radio_free,
.deserialize = subghz_protocol_encoder_nero_radio_deserialize,
.stop = subghz_protocol_encoder_nero_radio_stop,
.yield = subghz_protocol_encoder_nero_radio_yield,
};
const SubGhzProtocol subghz_protocol_nero_radio = {
.name = SUBGHZ_PROTOCOL_NERO_RADIO_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_nero_radio_decoder,
.encoder = &subghz_protocol_nero_radio_encoder,
};
void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderNeroRadio* instance = malloc(sizeof(SubGhzProtocolEncoderNeroRadio));
instance->base.protocol = &subghz_protocol_nero_radio;
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_nero_radio_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderNeroRadio* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool
subghz_protocol_encoder_nero_radio_get_upload(SubGhzProtocolEncoderNeroRadio* instance) {
furi_assert(instance);
size_t index = 0;
size_t size_upload = 49 * 2 + 2 + (instance->generic.data_count_bit * 2);
if(size_upload > instance->encoder.size_upload) {
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
return false;
} else {
instance->encoder.size_upload = size_upload;
}
//Send header
for(uint8_t i = 0; i < 49; i++) {
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short);
}
//Send start bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short * 4);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short);
//Send key data
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_nero_radio_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_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_nero_radio_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37);
}
return true;
}
bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderNeroRadio* 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_nero_radio_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_nero_radio_stop(void* context) {
SubGhzProtocolEncoderNeroRadio* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context) {
SubGhzProtocolEncoderNeroRadio* 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_nero_radio_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderNeroRadio* instance = malloc(sizeof(SubGhzProtocolDecoderNeroRadio));
instance->base.protocol = &subghz_protocol_nero_radio;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_nero_radio_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNeroRadio* instance = context;
free(instance);
}
void subghz_protocol_decoder_nero_radio_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNeroRadio* instance = context;
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderNeroRadio* instance = context;
switch(instance->decoder.parser_step) {
case NeroRadioDecoderStepReset:
if((level) && (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
subghz_protocol_nero_radio_const.te_delta)) {
instance->decoder.parser_step = NeroRadioDecoderStepCheckPreambula;
instance->decoder.te_last = duration;
instance->header_count = 0;
}
break;
case NeroRadioDecoderStepCheckPreambula:
if(level) {
if((DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
subghz_protocol_nero_radio_const.te_delta) ||
(DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short * 4) <
subghz_protocol_nero_radio_const.te_delta)) {
instance->decoder.te_last = duration;
} else {
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
} else if(
DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
subghz_protocol_nero_radio_const.te_delta) {
if(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) <
subghz_protocol_nero_radio_const.te_delta) {
// Found header
instance->header_count++;
break;
} else if(
DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short * 4) <
subghz_protocol_nero_radio_const.te_delta) {
// Found start bit
if(instance->header_count > 40) {
instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
} else {
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
} else {
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
break;
case NeroRadioDecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = NeroRadioDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
break;
case NeroRadioDecoderStepCheckDuration:
if(!level) {
if(duration >= (subghz_protocol_nero_radio_const.te_short * 10 +
subghz_protocol_nero_radio_const.te_delta * 2)) {
//Found stop bit
if(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) <
subghz_protocol_nero_radio_const.te_delta) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
} else if(
DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_radio_const.te_long) <
subghz_protocol_nero_radio_const.te_delta) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
}
instance->decoder.parser_step = NeroRadioDecoderStepReset;
if(instance->decoder.decode_count_bit >=
subghz_protocol_nero_radio_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;
instance->decoder.parser_step = NeroRadioDecoderStepReset;
break;
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) <
subghz_protocol_nero_radio_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_long) <
subghz_protocol_nero_radio_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_radio_const.te_long) <
subghz_protocol_nero_radio_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
subghz_protocol_nero_radio_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
} else {
instance->decoder.parser_step = NeroRadioDecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNeroRadio* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_nero_radio_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderNeroRadio* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderNeroRadio* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_nero_radio_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderNeroRadio* instance = context;
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Yek:0x%lX%08lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
code_found_reverse_lo);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_NERO_RADIO_NAME "Nero Radio"
typedef struct SubGhzProtocolDecoderNeroRadio SubGhzProtocolDecoderNeroRadio;
typedef struct SubGhzProtocolEncoderNeroRadio SubGhzProtocolEncoderNeroRadio;
extern const SubGhzProtocolDecoder subghz_protocol_nero_radio_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_nero_radio_encoder;
extern const SubGhzProtocol subghz_protocol_nero_radio;
void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_nero_radio_free(void* context);
bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_nero_radio_stop(void* context);
LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context);
void* subghz_protocol_decoder_nero_radio_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_nero_radio_free(void* context);
void subghz_protocol_decoder_nero_radio_reset(void* context);
void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context);
bool subghz_protocol_decoder_nero_radio_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_nero_radio_get_string(void* context, string_t output);

View File

@@ -0,0 +1,366 @@
#include "nero_sketch.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
#define TAG "SubGhzProtocolNeroSketch"
static const SubGhzBlockConst subghz_protocol_nero_sketch_const = {
.te_short = 330,
.te_long = 660,
.te_delta = 150,
.min_count_bit_for_found = 40,
};
struct SubGhzProtocolDecoderNeroSketch {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
};
struct SubGhzProtocolEncoderNeroSketch {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
NeroSketchDecoderStepReset = 0,
NeroSketchDecoderStepCheckPreambula,
NeroSketchDecoderStepSaveDuration,
NeroSketchDecoderStepCheckDuration,
} NeroSketchDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_nero_sketch_decoder = {
.alloc = subghz_protocol_decoder_nero_sketch_alloc,
.free = subghz_protocol_decoder_nero_sketch_free,
.feed = subghz_protocol_decoder_nero_sketch_feed,
.reset = subghz_protocol_decoder_nero_sketch_reset,
.get_hash_data = subghz_protocol_decoder_nero_sketch_get_hash_data,
.serialize = subghz_protocol_decoder_nero_sketch_serialize,
.deserialize = subghz_protocol_decoder_nero_sketch_deserialize,
.get_string = subghz_protocol_decoder_nero_sketch_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_nero_sketch_encoder = {
.alloc = subghz_protocol_encoder_nero_sketch_alloc,
.free = subghz_protocol_encoder_nero_sketch_free,
.deserialize = subghz_protocol_encoder_nero_sketch_deserialize,
.stop = subghz_protocol_encoder_nero_sketch_stop,
.yield = subghz_protocol_encoder_nero_sketch_yield,
};
const SubGhzProtocol subghz_protocol_nero_sketch = {
.name = SUBGHZ_PROTOCOL_NERO_SKETCH_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_nero_sketch_decoder,
.encoder = &subghz_protocol_nero_sketch_encoder,
};
void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderNeroSketch* instance = malloc(sizeof(SubGhzProtocolEncoderNeroSketch));
instance->base.protocol = &subghz_protocol_nero_sketch;
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_nero_sketch_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderNeroSketch* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool
subghz_protocol_encoder_nero_sketch_get_upload(SubGhzProtocolEncoderNeroSketch* instance) {
furi_assert(instance);
size_t index = 0;
size_t size_upload = 47 * 2 + 2 + (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
for(uint8_t i = 0; i < 47; i++) {
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
}
//Send start bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short * 4);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
//Send key data
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_long);
}
}
//Send stop bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
return true;
}
bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderNeroSketch* 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_nero_sketch_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_nero_sketch_stop(void* context) {
SubGhzProtocolEncoderNeroSketch* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context) {
SubGhzProtocolEncoderNeroSketch* 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_nero_sketch_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderNeroSketch* instance = malloc(sizeof(SubGhzProtocolDecoderNeroSketch));
instance->base.protocol = &subghz_protocol_nero_sketch;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_nero_sketch_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNeroSketch* instance = context;
free(instance);
}
void subghz_protocol_decoder_nero_sketch_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNeroSketch* instance = context;
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
void subghz_protocol_decoder_nero_sketch_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderNeroSketch* instance = context;
switch(instance->decoder.parser_step) {
case NeroSketchDecoderStepReset:
if((level) && (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
subghz_protocol_nero_sketch_const.te_delta)) {
instance->decoder.parser_step = NeroSketchDecoderStepCheckPreambula;
instance->decoder.te_last = duration;
instance->header_count = 0;
}
break;
case NeroSketchDecoderStepCheckPreambula:
if(level) {
if((DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
subghz_protocol_nero_sketch_const.te_delta) ||
(DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short * 4) <
subghz_protocol_nero_sketch_const.te_delta)) {
instance->decoder.te_last = duration;
} else {
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
} else if(
DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
subghz_protocol_nero_sketch_const.te_delta) {
if(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short) <
subghz_protocol_nero_sketch_const.te_delta) {
// Found header
instance->header_count++;
break;
} else if(
DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short * 4) <
subghz_protocol_nero_sketch_const.te_delta) {
// Found start bit
if(instance->header_count > 40) {
instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
} else {
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
} else {
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
break;
case NeroSketchDecoderStepSaveDuration:
if(level) {
if(duration >= (subghz_protocol_nero_sketch_const.te_short * 2 +
subghz_protocol_nero_sketch_const.te_delta * 2)) {
//Found stop bit
instance->decoder.parser_step = NeroSketchDecoderStepReset;
if(instance->decoder.decode_count_bit >=
subghz_protocol_nero_sketch_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 = NeroSketchDecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
break;
case NeroSketchDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short) <
subghz_protocol_nero_sketch_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_long) <
subghz_protocol_nero_sketch_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_long) <
subghz_protocol_nero_sketch_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
subghz_protocol_nero_sketch_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
} else {
instance->decoder.parser_step = NeroSketchDecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNeroSketch* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_nero_sketch_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderNeroSketch* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderNeroSketch* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_nero_sketch_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderNeroSketch* instance = context;
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Yek:0x%lX%08lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
code_found_reverse_lo);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_NERO_SKETCH_NAME "Nero Sketch"
typedef struct SubGhzProtocolDecoderNeroSketch SubGhzProtocolDecoderNeroSketch;
typedef struct SubGhzProtocolEncoderNeroSketch SubGhzProtocolEncoderNeroSketch;
extern const SubGhzProtocolDecoder subghz_protocol_nero_sketch_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_nero_sketch_encoder;
extern const SubGhzProtocol subghz_protocol_nero_sketch;
void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_nero_sketch_free(void* context);
bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_nero_sketch_stop(void* context);
LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context);
void* subghz_protocol_decoder_nero_sketch_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_nero_sketch_free(void* context);
void subghz_protocol_decoder_nero_sketch_reset(void* context);
void subghz_protocol_decoder_nero_sketch_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context);
bool subghz_protocol_decoder_nero_sketch_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_nero_sketch_get_string(void* context, string_t output);

View File

@@ -0,0 +1,310 @@
#include "nice_flo.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
#define TAG "SubGhzProtocolNiceFLO"
static const SubGhzBlockConst subghz_protocol_nice_flo_const = {
.te_short = 700,
.te_long = 1400,
.te_delta = 200,
.min_count_bit_for_found = 12,
};
struct SubGhzProtocolDecoderNiceFlo {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderNiceFlo {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
NiceFloDecoderStepReset = 0,
NiceFloDecoderStepFoundStartBit,
NiceFloDecoderStepSaveDuration,
NiceFloDecoderStepCheckDuration,
} NiceFloDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_nice_flo_decoder = {
.alloc = subghz_protocol_decoder_nice_flo_alloc,
.free = subghz_protocol_decoder_nice_flo_free,
.feed = subghz_protocol_decoder_nice_flo_feed,
.reset = subghz_protocol_decoder_nice_flo_reset,
.get_hash_data = subghz_protocol_decoder_nice_flo_get_hash_data,
.serialize = subghz_protocol_decoder_nice_flo_serialize,
.deserialize = subghz_protocol_decoder_nice_flo_deserialize,
.get_string = subghz_protocol_decoder_nice_flo_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_nice_flo_encoder = {
.alloc = subghz_protocol_encoder_nice_flo_alloc,
.free = subghz_protocol_encoder_nice_flo_free,
.deserialize = subghz_protocol_encoder_nice_flo_deserialize,
.stop = subghz_protocol_encoder_nice_flo_stop,
.yield = subghz_protocol_encoder_nice_flo_yield,
};
const SubGhzProtocol subghz_protocol_nice_flo = {
.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save |
SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_nice_flo_decoder,
.encoder = &subghz_protocol_nice_flo_encoder,
};
void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderNiceFlo* instance = malloc(sizeof(SubGhzProtocolEncoderNiceFlo));
instance->base.protocol = &subghz_protocol_nice_flo;
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_nice_flo_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderNiceFlo* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool subghz_protocol_encoder_nice_flo_get_upload(SubGhzProtocolEncoderNiceFlo* 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_nice_flo_const.te_short * 36);
//Send start bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_short);
//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_nice_flo_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_short);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_nice_flo_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_long);
}
}
return true;
}
bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderNiceFlo* 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_nice_flo_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_nice_flo_stop(void* context) {
SubGhzProtocolEncoderNiceFlo* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context) {
SubGhzProtocolEncoderNiceFlo* 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_nice_flo_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderNiceFlo* instance = malloc(sizeof(SubGhzProtocolDecoderNiceFlo));
instance->base.protocol = &subghz_protocol_nice_flo;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_nice_flo_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlo* instance = context;
free(instance);
}
void subghz_protocol_decoder_nice_flo_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlo* instance = context;
instance->decoder.parser_step = NiceFloDecoderStepReset;
}
void subghz_protocol_decoder_nice_flo_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlo* instance = context;
switch(instance->decoder.parser_step) {
case NiceFloDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short * 36) <
subghz_protocol_nice_flo_const.te_delta * 36)) {
//Found header Nice Flo
instance->decoder.parser_step = NiceFloDecoderStepFoundStartBit;
}
break;
case NiceFloDecoderStepFoundStartBit:
if(!level) {
break;
} else if(
DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short) <
subghz_protocol_nice_flo_const.te_delta) {
//Found start bit Nice Flo
instance->decoder.parser_step = NiceFloDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = NiceFloDecoderStepReset;
}
break;
case NiceFloDecoderStepSaveDuration:
if(!level) { //save interval
if(duration >= (subghz_protocol_nice_flo_const.te_short * 4)) {
instance->decoder.parser_step = NiceFloDecoderStepFoundStartBit;
if(instance->decoder.decode_count_bit >=
subghz_protocol_nice_flo_const.min_count_bit_for_found) {
instance->generic.serial = 0x0;
instance->generic.btn = 0x0;
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);
}
break;
}
instance->decoder.te_last = duration;
instance->decoder.parser_step = NiceFloDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = NiceFloDecoderStepReset;
}
break;
case NiceFloDecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nice_flo_const.te_short) <
subghz_protocol_nice_flo_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_long) <
subghz_protocol_nice_flo_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = NiceFloDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nice_flo_const.te_long) <
subghz_protocol_nice_flo_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short) <
subghz_protocol_nice_flo_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = NiceFloDecoderStepSaveDuration;
} else
instance->decoder.parser_step = NiceFloDecoderStepReset;
} else {
instance->decoder.parser_step = NiceFloDecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlo* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_nice_flo_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlo* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlo* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_nice_flo_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlo* instance = context;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
uint64_t code_found_reverse = 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",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_lo,
code_found_reverse_lo);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_NICE_FLO_NAME "Nice FLO"
typedef struct SubGhzProtocolDecoderNiceFlo SubGhzProtocolDecoderNiceFlo;
typedef struct SubGhzProtocolEncoderNiceFlo SubGhzProtocolEncoderNiceFlo;
extern const SubGhzProtocolDecoder subghz_protocol_nice_flo_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_nice_flo_encoder;
extern const SubGhzProtocol subghz_protocol_nice_flo;
void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_nice_flo_free(void* context);
bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_nice_flo_stop(void* context);
LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context);
void* subghz_protocol_decoder_nice_flo_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_nice_flo_free(void* context);
void subghz_protocol_decoder_nice_flo_reset(void* context);
void subghz_protocol_decoder_nice_flo_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context);
void subghz_protocol_decoder_nice_flo_get_string(void* context, string_t output);
bool subghz_protocol_decoder_nice_flo_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format);

View File

@@ -0,0 +1,366 @@
#include "nice_flor_s.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
/*
* https://phreakerclub.com/1615
* https://phreakerclub.com/forum/showthread.php?t=2360
* https://vrtp.ru/index.php?showtopic=27867
*/
#define TAG "SubGhzProtocoNiceFlorS"
static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = {
.te_short = 500,
.te_long = 1000,
.te_delta = 300,
.min_count_bit_for_found = 52,
};
struct SubGhzProtocolDecoderNiceFlorS {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
const char* nice_flor_s_rainbow_table_file_name;
};
struct SubGhzProtocolEncoderNiceFlorS {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
NiceFlorSDecoderStepReset = 0,
NiceFlorSDecoderStepCheckHeader,
NiceFlorSDecoderStepFoundHeader,
NiceFlorSDecoderStepSaveDuration,
NiceFlorSDecoderStepCheckDuration,
} NiceFlorSDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_nice_flor_s_decoder = {
.alloc = subghz_protocol_decoder_nice_flor_s_alloc,
.free = subghz_protocol_decoder_nice_flor_s_free,
.feed = subghz_protocol_decoder_nice_flor_s_feed,
.reset = subghz_protocol_decoder_nice_flor_s_reset,
.get_hash_data = subghz_protocol_decoder_nice_flor_s_get_hash_data,
.serialize = subghz_protocol_decoder_nice_flor_s_serialize,
.deserialize = subghz_protocol_decoder_nice_flor_s_deserialize,
.get_string = subghz_protocol_decoder_nice_flor_s_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_nice_flor_s_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_nice_flor_s = {
.name = SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_nice_flor_s_decoder,
.encoder = &subghz_protocol_nice_flor_s_encoder,
};
/** Read bytes from rainbow table
*
* @param instance - SubGhzProtocolNiceFlorS* instance
* @param address - address byte
* @return byte data
*/
static uint8_t
subghz_protocol_nice_flor_s_get_byte_in_file(const char* file_name, uint32_t address) {
if(!file_name) return 0;
uint8_t buffer[1] = {0};
if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint8_t))) {
return buffer[0];
} else {
return 0;
}
}
static inline void subghz_protocol_decoder_nice_flor_s_magic_xor(uint8_t* p, uint8_t k) {
for(uint8_t i = 1; i < 6; i++) {
p[i] ^= k;
}
}
uint64_t subghz_protocol_nice_flor_s_encrypt(uint64_t data, const char* file_name) {
uint8_t* p = (uint8_t*)&data;
uint8_t k = 0;
for(uint8_t y = 0; y < 2; y++) {
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f);
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
p[0] ^= k & 0xe0;
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25;
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
p[0] ^= k & 0x7;
if(y == 0) {
k = p[0];
p[0] = p[1];
p[1] = k;
}
}
p[5] = ~p[5] & 0x0f;
k = ~p[4];
p[4] = ~p[0];
p[0] = ~p[2];
p[2] = k;
k = ~p[3];
p[3] = ~p[1];
p[1] = k;
return data;
}
static uint64_t
subghz_protocol_nice_flor_s_decrypt(SubGhzBlockGeneric* instance, const char* file_name) {
furi_assert(instance);
uint64_t data = instance->data;
uint8_t* p = (uint8_t*)&data;
uint8_t k = 0;
k = ~p[4];
p[5] = ~p[5];
p[4] = ~p[2];
p[2] = ~p[0];
p[0] = k;
k = ~p[3];
p[3] = ~p[1];
p[1] = k;
for(uint8_t y = 0; y < 2; y++) {
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25;
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
p[0] ^= k & 0x7;
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f);
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
p[0] ^= k & 0xe0;
if(y == 0) {
k = p[0];
p[0] = p[1];
p[1] = k;
}
}
return data;
}
void* subghz_protocol_decoder_nice_flor_s_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderNiceFlorS* instance = malloc(sizeof(SubGhzProtocolDecoderNiceFlorS));
instance->base.protocol = &subghz_protocol_nice_flor_s;
instance->generic.protocol_name = instance->base.protocol->name;
instance->nice_flor_s_rainbow_table_file_name =
subghz_environment_get_nice_flor_s_rainbow_table_file_name(environment);
if(instance->nice_flor_s_rainbow_table_file_name) {
FURI_LOG_I(
TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name);
}
return instance;
}
void subghz_protocol_decoder_nice_flor_s_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;
instance->nice_flor_s_rainbow_table_file_name = NULL;
free(instance);
}
void subghz_protocol_decoder_nice_flor_s_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;
instance->decoder.parser_step = NiceFlorSDecoderStepReset;
}
void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;
switch(instance->decoder.parser_step) {
case NiceFlorSDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 38) <
subghz_protocol_nice_flor_s_const.te_delta * 38)) {
//Found start header Nice Flor-S
instance->decoder.parser_step = NiceFlorSDecoderStepCheckHeader;
}
break;
case NiceFlorSDecoderStepCheckHeader:
if((level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) <
subghz_protocol_nice_flor_s_const.te_delta * 3)) {
//Found next header Nice Flor-S
instance->decoder.parser_step = NiceFlorSDecoderStepFoundHeader;
} else {
instance->decoder.parser_step = NiceFlorSDecoderStepReset;
}
break;
case NiceFlorSDecoderStepFoundHeader:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) <
subghz_protocol_nice_flor_s_const.te_delta * 3)) {
//Found header Nice Flor-S
instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = NiceFlorSDecoderStepReset;
}
break;
case NiceFlorSDecoderStepSaveDuration:
if(level) {
if(DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) <
subghz_protocol_nice_flor_s_const.te_delta) {
//Found STOP bit
instance->decoder.parser_step = NiceFlorSDecoderStepReset;
if(instance->decoder.decode_count_bit >=
subghz_protocol_nice_flor_s_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);
}
break;
} else {
//save interval
instance->decoder.te_last = duration;
instance->decoder.parser_step = NiceFlorSDecoderStepCheckDuration;
}
}
break;
case NiceFlorSDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nice_flor_s_const.te_short) <
subghz_protocol_nice_flor_s_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_long) <
subghz_protocol_nice_flor_s_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_nice_flor_s_const.te_long) <
subghz_protocol_nice_flor_s_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short) <
subghz_protocol_nice_flor_s_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration;
} else
instance->decoder.parser_step = NiceFlorSDecoderStepReset;
} else {
instance->decoder.parser_step = NiceFlorSDecoderStepReset;
}
break;
}
}
/** Decrypt protocol Nice Flor S
*
* @param instance - SubGhzProtocolNiceFlorS* instance
*/
static void subghz_protocol_nice_flor_s_remote_controller(
SubGhzBlockGeneric* instance,
const char* file_name) {
/*
* Packet format Nice Flor-s: START-P0-P1-P2-P3-P4-P5-P6-P7-STOP
* P0 (4-bit) - button positional code - 1:0x1, 2:0x2, 3:0x4, 4:0x8;
* P1 (4-bit) - batch repetition number, calculated by the formula:
* P1 = 0xF ^ P0 ^ n; where n changes from 1 to 15, then 0, and then in a circle
* key 1: {0xE,0xF,0xC,0xD,0xA,0xB,0x8,0x9,0x6,0x7,0x4,0x5,0x2,0x3,0x0,0x1};
* key 2: {0xD,0xC,0xF,0xE,0x9,0x8,0xB,0xA,0x5,0x4,0x7,0x6,0x1,0x0,0x3,0x2};
* key 3: {0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC,0x3,0x2,0x1,0x0,0x7,0x6,0x5,0x4};
* key 4: {0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0,0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8};
* P2 (4-bit) - part of the serial number, P2 = (K ^ S3) & 0xF;
* P3 (byte) - the major part of the encrypted index
* P4 (byte) - the low-order part of the encrypted index
* P5 (byte) - part of the serial number, P5 = K ^ S2;
* P6 (byte) - part of the serial number, P6 = K ^ S1;
* P7 (byte) - part of the serial number, P7 = K ^ S0;
* K (byte) - depends on P3 and P4, K = Fk(P3, P4);
* S3,S2,S1,S0 - serial number of the console 28 bit.
*
* data => 0x1c5783607f7b3 key serial cnt
* decrypt => 0x10436c6820444 => 0x1 0436c682 0444
*
*/
if(!file_name) {
instance->cnt = 0;
instance->serial = 0;
instance->btn = 0;
} else {
uint64_t decrypt = subghz_protocol_nice_flor_s_decrypt(instance, file_name);
instance->cnt = decrypt & 0xFFFF;
instance->serial = (decrypt >> 16) & 0xFFFFFFF;
instance->btn = (decrypt >> 48) & 0xF;
}
}
uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_nice_flor_s_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_nice_flor_s_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;
subghz_protocol_nice_flor_s_remote_controller(
&instance->generic, instance->nice_flor_s_rainbow_table_file_name);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:%05lX\r\n"
"Cnt:%04X Btn:%02lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
instance->generic.serial,
instance->generic.cnt,
instance->generic.btn);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME "Nice FloR-S"
typedef struct SubGhzProtocolDecoderNiceFlorS SubGhzProtocolDecoderNiceFlorS;
typedef struct SubGhzProtocolEncoderNiceFlorS SubGhzProtocolEncoderNiceFlorS;
extern const SubGhzProtocolDecoder subghz_protocol_nice_flor_s_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_nice_flor_s_encoder;
extern const SubGhzProtocol subghz_protocol_nice_flor_s;
void* subghz_protocol_decoder_nice_flor_s_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_nice_flor_s_free(void* context);
void subghz_protocol_decoder_nice_flor_s_reset(void* context);
void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context);
bool subghz_protocol_decoder_nice_flor_s_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_nice_flor_s_get_string(void* context, string_t output);

View File

@@ -0,0 +1,351 @@
#include "princeton.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
#define TAG "SubGhzProtocolCAME"
static const SubGhzBlockConst subghz_protocol_princeton_const = {
.te_short = 400,
.te_long = 1200,
.te_delta = 250,
.min_count_bit_for_found = 24,
};
struct SubGhzProtocolDecoderPrinceton {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint32_t te;
};
struct SubGhzProtocolEncoderPrinceton {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
uint32_t te;
};
typedef enum {
PrincetonDecoderStepReset = 0,
PrincetonDecoderStepSaveDuration,
PrincetonDecoderStepCheckDuration,
} PrincetonDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_princeton_decoder = {
.alloc = subghz_protocol_decoder_princeton_alloc,
.free = subghz_protocol_decoder_princeton_free,
.feed = subghz_protocol_decoder_princeton_feed,
.reset = subghz_protocol_decoder_princeton_reset,
.get_hash_data = subghz_protocol_decoder_princeton_get_hash_data,
.serialize = subghz_protocol_decoder_princeton_serialize,
.deserialize = subghz_protocol_decoder_princeton_deserialize,
.get_string = subghz_protocol_decoder_princeton_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_princeton_encoder = {
.alloc = subghz_protocol_encoder_princeton_alloc,
.free = subghz_protocol_encoder_princeton_free,
.deserialize = subghz_protocol_encoder_princeton_deserialize,
.stop = subghz_protocol_encoder_princeton_stop,
.yield = subghz_protocol_encoder_princeton_yield,
};
const SubGhzProtocol subghz_protocol_princeton = {
.name = SUBGHZ_PROTOCOL_PRINCETON_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_315 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_princeton_decoder,
.encoder = &subghz_protocol_princeton_encoder,
};
void* subghz_protocol_encoder_princeton_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderPrinceton* instance = malloc(sizeof(SubGhzProtocolEncoderPrinceton));
instance->base.protocol = &subghz_protocol_princeton;
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_princeton_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderPrinceton* instance = context;
free(instance->encoder.upload);
free(instance);
}
static bool
subghz_protocol_encoder_princeton_get_upload(SubGhzProtocolEncoderPrinceton* 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 key data
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)instance->te * 3);
instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)instance->te);
} else {
//send bit 0
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)instance->te);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)instance->te * 3);
}
}
//Send Stop bit
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)instance->te);
//Send PT_GUARD
instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)instance->te * 30);
return true;
}
bool subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderPrinceton* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) {
FURI_LOG_E(TAG, "Missing TE");
break;
}
//optional parameter parameter
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
subghz_protocol_encoder_princeton_get_upload(instance);
instance->encoder.is_runing = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_princeton_stop(void* context) {
SubGhzProtocolEncoderPrinceton* instance = context;
instance->encoder.is_runing = false;
}
LevelDuration subghz_protocol_encoder_princeton_yield(void* context) {
SubGhzProtocolEncoderPrinceton* 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_princeton_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderPrinceton* instance = malloc(sizeof(SubGhzProtocolDecoderPrinceton));
instance->base.protocol = &subghz_protocol_princeton;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_princeton_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
free(instance);
}
void subghz_protocol_decoder_princeton_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
instance->decoder.parser_step = PrincetonDecoderStepReset;
}
void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
switch(instance->decoder.parser_step) {
case PrincetonDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_princeton_const.te_short * 36) <
subghz_protocol_princeton_const.te_delta * 36)) {
//Found Preambula
instance->decoder.parser_step = PrincetonDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->te = 0;
}
break;
case PrincetonDecoderStepSaveDuration:
//save duration
if(level) {
instance->decoder.te_last = duration;
instance->te += duration;
instance->decoder.parser_step = PrincetonDecoderStepCheckDuration;
}
break;
case PrincetonDecoderStepCheckDuration:
if(!level) {
if(duration >= (subghz_protocol_princeton_const.te_short * 10 +
subghz_protocol_princeton_const.te_delta)) {
instance->decoder.parser_step = PrincetonDecoderStepSaveDuration;
if(instance->decoder.decode_count_bit ==
subghz_protocol_princeton_const.min_count_bit_for_found) {
instance->te /= (instance->decoder.decode_count_bit * 4 + 1);
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);
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->te = 0;
break;
}
instance->te += duration;
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_princeton_const.te_short) <
subghz_protocol_princeton_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_princeton_const.te_long) <
subghz_protocol_princeton_const.te_delta * 3)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = PrincetonDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_princeton_const.te_long) <
subghz_protocol_princeton_const.te_delta * 3) &&
(DURATION_DIFF(duration, subghz_protocol_princeton_const.te_short) <
subghz_protocol_princeton_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = PrincetonDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = PrincetonDecoderStepReset;
}
} else {
instance->decoder.parser_step = PrincetonDecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_decoder_princeton_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_princeton_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
bool res =
subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
if(res && !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) {
FURI_LOG_E(TAG, "Unable to add TE");
res = false;
}
return res;
}
bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) {
FURI_LOG_E(TAG, "Missing TE");
break;
}
res = true;
} while(false);
return res;
}
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(
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"
"Te:%dus\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_lo,
code_found_reverse_lo,
instance->generic.serial,
instance->generic.btn,
instance->te);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_PRINCETON_NAME "Princeton"
typedef struct SubGhzProtocolDecoderPrinceton SubGhzProtocolDecoderPrinceton;
typedef struct SubGhzProtocolEncoderPrinceton SubGhzProtocolEncoderPrinceton;
extern const SubGhzProtocolDecoder subghz_protocol_princeton_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_princeton_encoder;
extern const SubGhzProtocol subghz_protocol_princeton;
void* subghz_protocol_encoder_princeton_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_princeton_free(void* context);
bool subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_encoder_princeton_stop(void* context);
LevelDuration subghz_protocol_encoder_princeton_yield(void* context);
void* subghz_protocol_decoder_princeton_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_princeton_free(void* context);
void subghz_protocol_decoder_princeton_reset(void* context);
void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_princeton_get_hash_data(void* context);
bool subghz_protocol_decoder_princeton_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_princeton_get_string(void* context, string_t output);

View File

@@ -0,0 +1,287 @@
#include "princeton_for_testing.h"
#include "furi_hal.h"
#include "../blocks/math.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
#define SUBGHZ_PT_SHORT 300
#define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3)
#define SUBGHZ_PT_GUARD (SUBGHZ_PT_SHORT * 30)
#define SUBGHZ_PT_COUNT_KEY_433 9
#define SUBGHZ_PT_TIMEOUT_433 900
#define SUBGHZ_PT_COUNT_KEY_868 9
#define SUBGHZ_PT_TIMEOUT_868 14000
#define TAG "SubGhzProtocolPrinceton"
struct SubGhzEncoderPrinceton {
uint32_t key;
uint16_t te;
size_t repeat;
size_t front;
size_t count_key;
size_t count_key_package;
uint32_t time_high;
uint32_t time_low;
uint32_t timeout;
uint32_t time_stop;
};
typedef enum {
PrincetonDecoderStepReset = 0,
PrincetonDecoderStepSaveDuration,
PrincetonDecoderStepCheckDuration,
} PrincetonDecoderStep;
SubGhzEncoderPrinceton* subghz_encoder_princeton_for_testing_alloc() {
SubGhzEncoderPrinceton* instance = malloc(sizeof(SubGhzEncoderPrinceton));
return instance;
}
void subghz_encoder_princeton_for_testing_free(SubGhzEncoderPrinceton* instance) {
furi_assert(instance);
free(instance);
}
void subghz_encoder_princeton_for_testing_stop(
SubGhzEncoderPrinceton* instance,
uint32_t time_stop) {
instance->time_stop = time_stop;
}
void subghz_encoder_princeton_for_testing_set(
SubGhzEncoderPrinceton* instance,
uint32_t key,
size_t repeat,
uint32_t frequency) {
furi_assert(instance);
instance->te = SUBGHZ_PT_SHORT;
instance->key = key;
instance->repeat = repeat + 1;
instance->front = 48;
instance->time_high = 0;
instance->time_low = 0;
if(frequency < 700000000) {
instance->count_key_package = SUBGHZ_PT_COUNT_KEY_433;
instance->timeout = SUBGHZ_PT_TIMEOUT_433;
} else {
instance->count_key_package = SUBGHZ_PT_COUNT_KEY_868;
instance->timeout = SUBGHZ_PT_TIMEOUT_868;
}
instance->count_key = instance->count_key_package + 3;
if((millis() - instance->time_stop) < instance->timeout) {
instance->time_stop = (instance->timeout - (millis() - instance->time_stop)) * 1000;
} else {
instance->time_stop = 0;
}
}
size_t subghz_encoder_princeton_for_testing_get_repeat_left(SubGhzEncoderPrinceton* instance) {
furi_assert(instance);
return instance->repeat;
}
void subghz_encoder_princeton_for_testing_print_log(void* context) {
SubGhzEncoderPrinceton* instance = context;
float duty_cycle =
((float)instance->time_high / (instance->time_high + instance->time_low)) * 100;
FURI_LOG_I(
TAG "Encoder",
"Radio tx_time=%dus ON=%dus, OFF=%dus, DutyCycle=%d,%d%%",
instance->time_high + instance->time_low,
instance->time_high,
instance->time_low,
(uint32_t)duty_cycle,
(uint32_t)((duty_cycle - (uint32_t)duty_cycle) * 100));
}
LevelDuration subghz_encoder_princeton_for_testing_yield(void* context) {
SubGhzEncoderPrinceton* instance = context;
if(instance->repeat == 0) {
subghz_encoder_princeton_for_testing_print_log(instance);
return level_duration_reset();
}
size_t bit = instance->front / 2;
bool level = !(instance->front % 2);
LevelDuration ret;
if(bit < 24) {
uint8_t byte = bit / 8;
uint8_t bit_in_byte = bit % 8;
bool value = (((uint8_t*)&instance->key)[2 - byte] >> (7 - bit_in_byte)) & 1;
if(value) {
ret = level_duration_make(level, level ? instance->te * 3 : instance->te);
if(level)
instance->time_high += instance->te * 3;
else
instance->time_low += instance->te;
} else {
ret = level_duration_make(level, level ? instance->te : instance->te * 3);
if(level)
instance->time_high += instance->te;
else
instance->time_low += instance->te * 3;
}
} else {
if(instance->time_stop) {
ret = level_duration_make(level, level ? instance->te : instance->time_stop);
if(level)
instance->time_high += instance->te;
else {
instance->time_low += instance->time_stop;
instance->time_stop = 0;
instance->front = 47;
}
} else {
if(--instance->count_key != 0) {
ret = level_duration_make(level, level ? instance->te : instance->te * 30);
if(level)
instance->time_high += instance->te;
else
instance->time_low += instance->te * 30;
} else {
instance->count_key = instance->count_key_package + 2;
instance->front = 48;
ret = level_duration_make(level, level ? instance->te : instance->timeout * 1000);
if(level)
instance->time_high += instance->te;
else
instance->time_low += instance->timeout * 1000;
}
}
}
instance->front++;
if(instance->front == 50) {
instance->repeat--;
instance->front = 0;
}
return ret;
}
struct SubGhzDecoderPrinceton {
const char* name;
uint16_t te_long;
uint16_t te_short;
uint16_t te_delta;
uint8_t code_count_bit;
uint8_t code_last_count_bit;
uint64_t code_found;
uint64_t code_last_found;
uint8_t code_min_count_bit_for_found;
uint8_t btn;
uint32_t te_last;
uint32_t serial;
uint32_t parser_step;
uint16_t cnt;
uint32_t te;
SubGhzDecoderPrincetonCallback callback;
void* context;
};
SubGhzDecoderPrinceton* subghz_decoder_princeton_for_testing_alloc(void) {
SubGhzDecoderPrinceton* instance = malloc(sizeof(SubGhzDecoderPrinceton));
instance->te = SUBGHZ_PT_SHORT;
instance->name = "Princeton";
instance->code_min_count_bit_for_found = 24;
instance->te_short = 400;
instance->te_long = 1200;
instance->te_delta = 250;
return instance;
}
void subghz_decoder_princeton_for_testing_free(SubGhzDecoderPrinceton* instance) {
furi_assert(instance);
free(instance);
}
void subghz_decoder_princeton_for_testing_set_callback(
SubGhzDecoderPrinceton* instance,
SubGhzDecoderPrincetonCallback callback,
void* context) {
instance->callback = callback;
instance->context = context;
}
void subghz_decoder_princeton_for_testing_reset(SubGhzDecoderPrinceton* instance) {
instance->parser_step = PrincetonDecoderStepReset;
}
static void
subghz_decoder_princeton_for_testing_add_bit(SubGhzDecoderPrinceton* instance, uint8_t bit) {
instance->code_found = instance->code_found << 1 | bit;
instance->code_count_bit++;
}
void subghz_decoder_princeton_for_testing_parse(
SubGhzDecoderPrinceton* instance,
bool level,
uint32_t duration) {
switch(instance->parser_step) {
case PrincetonDecoderStepReset:
if((!level) &&
(DURATION_DIFF(duration, instance->te_short * 36) < instance->te_delta * 36)) {
//Found Preambula
instance->parser_step = PrincetonDecoderStepSaveDuration;
instance->code_found = 0;
instance->code_count_bit = 0;
instance->te = 0;
}
break;
case PrincetonDecoderStepSaveDuration:
//save duration
if(level) {
instance->te_last = duration;
instance->te += duration;
instance->parser_step = PrincetonDecoderStepCheckDuration;
}
break;
case PrincetonDecoderStepCheckDuration:
if(!level) {
if(duration >= (instance->te_short * 10 + instance->te_delta)) {
instance->parser_step = PrincetonDecoderStepSaveDuration;
if(instance->code_count_bit == instance->code_min_count_bit_for_found) {
instance->te /= (instance->code_count_bit * 4 + 1);
instance->code_last_found = instance->code_found;
instance->code_last_count_bit = instance->code_count_bit;
instance->serial = instance->code_found >> 4;
instance->btn = (uint8_t)instance->code_found & 0x00000F;
if(instance->callback) instance->callback(instance, instance->context);
}
instance->code_found = 0;
instance->code_count_bit = 0;
instance->te = 0;
break;
}
instance->te += duration;
if((DURATION_DIFF(instance->te_last, instance->te_short) < instance->te_delta) &&
(DURATION_DIFF(duration, instance->te_long) < instance->te_delta * 3)) {
subghz_decoder_princeton_for_testing_add_bit(instance, 0);
instance->parser_step = PrincetonDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->te_last, instance->te_long) < instance->te_delta * 3) &&
(DURATION_DIFF(duration, instance->te_short) < instance->te_delta)) {
subghz_decoder_princeton_for_testing_add_bit(instance, 1);
instance->parser_step = PrincetonDecoderStepSaveDuration;
} else {
instance->parser_step = PrincetonDecoderStepReset;
}
} else {
instance->parser_step = PrincetonDecoderStepReset;
}
break;
}
}

View File

@@ -0,0 +1,85 @@
#pragma once
#include "base.h"
/** SubGhzDecoderPrinceton anonymous type */
typedef struct SubGhzDecoderPrinceton SubGhzDecoderPrinceton;
/** SubGhzEncoderPrinceton anonymous type */
typedef struct SubGhzEncoderPrinceton SubGhzEncoderPrinceton;
typedef void (*SubGhzDecoderPrincetonCallback)(SubGhzDecoderPrinceton* parser, void* context);
/** Allocate SubGhzEncoderPrinceton
* @return pointer to SubGhzEncoderPrinceton instance
*/
SubGhzEncoderPrinceton* subghz_encoder_princeton_for_testing_alloc();
/** Free SubGhzEncoderPrinceton instance
* @param instance - SubGhzEncoderPrinceton instance
*/
void subghz_encoder_princeton_for_testing_free(SubGhzEncoderPrinceton* instance);
void subghz_encoder_princeton_for_testing_stop(
SubGhzEncoderPrinceton* instance,
uint32_t time_stop);
/** Set new encoder params
* @param instance - SubGhzEncoderPrinceton instance
* @param key - 24bit key
* @param repeat - how many times to repeat
* @param frequency - frequency
*/
void subghz_encoder_princeton_for_testing_set(
SubGhzEncoderPrinceton* instance,
uint32_t key,
size_t repeat,
uint32_t frequency);
/** Get repeat count left
* @param instance - SubGhzEncoderPrinceton instance
* @return repeat count left
*/
size_t subghz_encoder_princeton_for_testing_get_repeat_left(SubGhzEncoderPrinceton* instance);
/** Print encoder log
* @param instance - SubGhzEncoderPrinceton instance
*/
void subghz_encoder_princeton_for_testing_print_log(void* context);
/** Get level duration
* @param instance - SubGhzEncoderPrinceton instance
* @return level duration
*/
LevelDuration subghz_encoder_princeton_for_testing_yield(void* context);
/** Allocate SubGhzDecoderPrinceton
*
* @return SubGhzDecoderPrinceton*
*/
SubGhzDecoderPrinceton* subghz_decoder_princeton_for_testing_alloc();
/** Free SubGhzDecoderPrinceton
*
* @param instance
*/
void subghz_decoder_princeton_for_testing_free(SubGhzDecoderPrinceton* instance);
void subghz_decoder_princeton_for_testing_set_callback(
SubGhzDecoderPrinceton* instance,
SubGhzDecoderPrincetonCallback callback,
void* context);
/** Reset internal state
* @param instance - SubGhzDecoderPrinceton instance
*/
void subghz_decoder_princeton_for_testing_reset(SubGhzDecoderPrinceton* instance);
/** Parse accepted duration
*
* @param instance - SubGhzDecoderPrinceton instance
* @param data - LevelDuration level_duration
*/
void subghz_decoder_princeton_for_testing_parse(
SubGhzDecoderPrinceton* instance,
bool level,
uint32_t duration);

347
lib/subghz/protocols/raw.c Normal file
View File

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

View File

@@ -0,0 +1,40 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_RAW_NAME "RAW"
typedef void (*SubGhzProtocolEncoderRAWCallbackEnd)(void* context);
typedef struct SubGhzProtocolDecoderRAW SubGhzProtocolDecoderRAW;
typedef struct SubGhzProtocolEncoderRAW SubGhzProtocolEncoderRAW;
extern const SubGhzProtocolDecoder subghz_protocol_raw_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_raw_encoder;
extern const SubGhzProtocol subghz_protocol_raw;
bool subghz_protocol_raw_save_to_file_init(
SubGhzProtocolDecoderRAW* instance,
const char* dev_name,
uint32_t frequency,
FuriHalSubGhzPreset preset);
void subghz_protocol_raw_save_to_file_stop(SubGhzProtocolDecoderRAW* instance);
size_t subghz_protocol_raw_get_sample_write(SubGhzProtocolDecoderRAW* instance);
void* subghz_protocol_decoder_raw_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_raw_free(void* context);
void subghz_protocol_decoder_raw_reset(void* context);
void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t duration);
void subghz_protocol_decoder_raw_get_string(void* context, string_t output);
void* subghz_protocol_encoder_raw_alloc(SubGhzEnvironment* environment);
void subghz_protocol_encoder_raw_free(void* context);
void subghz_protocol_encoder_raw_stop(void* context);
void subghz_protocol_raw_file_encoder_worker_callback_end(void* context);
void subghz_protocol_raw_file_encoder_worker_set_callback_end(
SubGhzProtocolEncoderRAW* instance,
SubGhzProtocolEncoderRAWCallbackEnd callback_end,
void* context_end);
void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_name);
bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format);
LevelDuration subghz_protocol_encoder_raw_yield(void* context);

View File

@@ -0,0 +1,53 @@
#include "registry.h"
#include "princeton.h"
#include "keeloq.h"
#include "star_line.h"
#include "nice_flo.h"
#include "came.h"
#include "faac_slh.h"
#include "nice_flor_s.h"
#include "came_twee.h"
#include "came_atomo.h"
#include "nero_sketch.h"
#include "ido.h"
#include "kia.h"
#include "hormann.h"
#include "nero_radio.h"
#include "somfy_telis.h"
#include "somfy_keytis.h"
#include "scher_khan.h"
#include "gate_tx.h"
#include "raw.h"
const SubGhzProtocol* subghz_protocol_registry[] = {
&subghz_protocol_princeton, &subghz_protocol_keeloq, &subghz_protocol_star_line,
&subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh,
&subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo,
&subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia,
&subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis,
&subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_gate_tx,
&subghz_protocol_raw,
};
const SubGhzProtocol* subghz_protocol_registry_get_by_name(const char* name) {
for(size_t i = 0; i < subghz_protocol_registry_count(); i++) {
if(strcmp(name, subghz_protocol_registry[i]->name) == 0) {
return subghz_protocol_registry[i];
}
}
return NULL;
}
const SubGhzProtocol* subghz_protocol_registry_get_by_index(size_t index) {
if(index < subghz_protocol_registry_count()) {
return subghz_protocol_registry[index];
} else {
return NULL;
}
}
size_t subghz_protocol_registry_count() {
return COUNT_OF(subghz_protocol_registry);
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include "../types.h"
const SubGhzProtocol* subghz_protocol_registry_get_by_name(const char* name);
const SubGhzProtocol* subghz_protocol_registry_get_by_index(size_t index);
size_t subghz_protocol_registry_count();

View File

@@ -0,0 +1,286 @@
#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) {
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_long +
subghz_protocol_scher_khan_const.te_delta * 2)) {
//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 SubGhzProtocolScherKhan instance
*/
static void subghz_protocol_scher_khan_check_remote_controller(
SubGhzBlockGeneric* instance,
const char* protocol_name) {
/*
* MAGICAR 51 bit 00000001A99121DE83C3 MAGIC CODE, Dinamic
* 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
// instance->protocol_name = "MAGIC CODE, Static";
// break;
case 51: //MAGIC CODE, Dinamic
protocol_name = "MAGIC CODE, Dinamic";
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
// instance->protocol_name = "MAGIC CODE PRO / PRO2";
// break;
default:
instance->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);
}
bool subghz_protocol_decoder_scher_khan_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool 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, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
subghz_protocol_scher_khan_check_remote_controller(
&instance->generic, instance->protocol_name);
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:%07lX Btn:%lX Cnt:%04X\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);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_SCHER_KHAN_NAME "Scher-Khan"
typedef struct SubGhzProtocolDecoderScherKhan SubGhzProtocolDecoderScherKhan;
typedef struct SubGhzProtocolEncoderScherKhan SubGhzProtocolEncoderScherKhan;
extern const SubGhzProtocolDecoder subghz_protocol_scher_khan_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_scher_khan_encoder;
extern const SubGhzProtocol subghz_protocol_scher_khan;
void* subghz_protocol_decoder_scher_khan_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_scher_khan_free(void* context);
void subghz_protocol_decoder_scher_khan_reset(void* context);
void subghz_protocol_decoder_scher_khan_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context);
bool subghz_protocol_decoder_scher_khan_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_scher_khan_get_string(void* context, string_t output);

View File

@@ -0,0 +1,438 @@
#include "somfy_keytis.h"
#include <lib/toolbox/manchester_decoder.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolSomfyKeytis"
static const SubGhzBlockConst subghz_protocol_somfy_keytis_const = {
.te_short = 640,
.te_long = 1280,
.te_delta = 250,
.min_count_bit_for_found = 80,
};
struct SubGhzProtocolDecoderSomfyKeytis {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
ManchesterState manchester_saved_state;
uint32_t press_duration_counter;
};
struct SubGhzProtocolEncoderSomfyKeytis {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
SomfyKeytisDecoderStepReset = 0,
SomfyKeytisDecoderStepCheckPreambula,
SomfyKeytisDecoderStepFoundPreambula,
SomfyKeytisDecoderStepStartDecode,
SomfyKeytisDecoderStepDecoderData,
} SomfyKeytisDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_somfy_keytis_decoder = {
.alloc = subghz_protocol_decoder_somfy_keytis_alloc,
.free = subghz_protocol_decoder_somfy_keytis_free,
.feed = subghz_protocol_decoder_somfy_keytis_feed,
.reset = subghz_protocol_decoder_somfy_keytis_reset,
.get_hash_data = subghz_protocol_decoder_somfy_keytis_get_hash_data,
.serialize = subghz_protocol_decoder_somfy_keytis_serialize,
.deserialize = subghz_protocol_decoder_somfy_keytis_deserialize,
.get_string = subghz_protocol_decoder_somfy_keytis_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_somfy_keytis = {
.name = SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_somfy_keytis_decoder,
.encoder = &subghz_protocol_somfy_keytis_encoder,
};
void* subghz_protocol_decoder_somfy_keytis_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderSomfyKeytis* instance = malloc(sizeof(SubGhzProtocolDecoderSomfyKeytis));
instance->base.protocol = &subghz_protocol_somfy_keytis;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_somfy_keytis_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSomfyKeytis* instance = context;
free(instance);
}
void subghz_protocol_decoder_somfy_keytis_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSomfyKeytis* instance = context;
instance->decoder.parser_step = SomfyKeytisDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
static uint8_t subghz_protocol_somfy_keytis_crc(uint64_t data) {
uint8_t crc = 0;
data &= 0xFFF0FFFFFFFFFF;
for(uint8_t i = 0; i < 56; i += 8) {
crc = crc ^ data >> i ^ (data >> (i + 4));
}
return crc & 0xf;
}
void subghz_protocol_decoder_somfy_keytis_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderSomfyKeytis* instance = context;
ManchesterEvent event = ManchesterEventReset;
switch(instance->decoder.parser_step) {
case SomfyKeytisDecoderStepReset:
if((level) && DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_short * 4) <
subghz_protocol_somfy_keytis_const.te_delta * 4) {
instance->decoder.parser_step = SomfyKeytisDecoderStepFoundPreambula;
instance->header_count++;
}
break;
case SomfyKeytisDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_short * 4) <
subghz_protocol_somfy_keytis_const.te_delta * 4)) {
instance->decoder.parser_step = SomfyKeytisDecoderStepCheckPreambula;
} else {
instance->header_count = 0;
instance->decoder.parser_step = SomfyKeytisDecoderStepReset;
}
break;
case SomfyKeytisDecoderStepCheckPreambula:
if(level) {
if(DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_short * 4) <
subghz_protocol_somfy_keytis_const.te_delta * 4) {
instance->decoder.parser_step = SomfyKeytisDecoderStepFoundPreambula;
instance->header_count++;
} else if(
(instance->header_count > 1) &&
(DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_short * 7) <
subghz_protocol_somfy_keytis_const.te_delta * 4)) {
instance->decoder.parser_step = SomfyKeytisDecoderStepDecoderData;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->press_duration_counter = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
}
}
break;
case SomfyKeytisDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_short) <
subghz_protocol_somfy_keytis_const.te_delta) {
event = ManchesterEventShortLow;
} else if(
DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_long) <
subghz_protocol_somfy_keytis_const.te_delta) {
event = ManchesterEventLongLow;
} else if(
duration >= (subghz_protocol_somfy_keytis_const.te_long +
subghz_protocol_somfy_keytis_const.te_delta)) {
if(instance->decoder.decode_count_bit ==
subghz_protocol_somfy_keytis_const.min_count_bit_for_found) {
//check crc
uint64_t data_tmp = instance->generic.data ^ (instance->generic.data >> 8);
if(((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_keytis_crc(data_tmp)) {
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;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
instance->decoder.parser_step = SomfyKeytisDecoderStepReset;
} else {
instance->decoder.parser_step = SomfyKeytisDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_short) <
subghz_protocol_somfy_keytis_const.te_delta) {
event = ManchesterEventShortHigh;
} else if(
DURATION_DIFF(duration, subghz_protocol_somfy_keytis_const.te_long) <
subghz_protocol_somfy_keytis_const.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->decoder.parser_step = SomfyKeytisDecoderStepReset;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
if(data_ok) {
if(instance->decoder.decode_count_bit < 56) {
instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data;
} else {
instance->press_duration_counter = (instance->press_duration_counter << 1) |
data;
}
instance->decoder.decode_count_bit++;
}
}
break;
}
}
/** Analysis of received data
*
* @param instance SubGhzProtocolSomfyKeytis instance
*/
static void subghz_protocol_somfy_keytis_check_remote_controller(SubGhzBlockGeneric* instance) {
//https://pushstack.wordpress.com/somfy-rts-protocol/
/*
* 604 us
* /
* | 2416us | 2416us | 2416us | 2416us | 4550 us | |
*
* +--------+ +--------+ +---...---+
* + +--------+ +--------+ +--+XXXX...XXX+
*
* | hw. sync. | soft. | |
* | | sync. | data |
*
*
* encrypt | decrypt
*
* package 80 bit pdc key btn crc cnt serial
*
* 0xA453537C4B9855 C40019 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 C80026 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 CC0033 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 D00049 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 D4005C => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 D80063 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 DC0076 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 E00086 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 E40093 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 E800AC => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 EC00B9 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 F000C3 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 F400D6 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 F800E9 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC00FC => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC0102 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC0113 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC0120 => 0xA 4 F 7 002F 37D3CD
* ..........
* 0xA453537C4B9855 FC048F => 0xA 4 F 7 002F 37D3CD
*
* Pdc: "Press Duration Counter" the total delay of the button is sent 72 parcels,
* pdc cnt4b cnt8b pdc_crc
* C40019 => 11 0001 00 0000 00000001 1001
* C80026 => 11 0010 00 0000 00000010 0110
* CC0033 => 11 0011 00 0000 00000011 0011
* D00049 => 11 0100 00 0000 00000100 1001
* D4005C => 11 0101 00 0000 00000101 1100
* D80063 => 11 0110 00 0000 00000110 0011
* DC0076 => 11 0111 00 0000 00000111 0110
* E00086 => 11 1000 00 0000 00001000 0110
* E40093 => 11 1001 00 0000 00001001 0011
* E800AC => 11 1010 00 0000 00001010 1100
* EC00B9 => 11 1011 00 0000 00001011 1001
* F000C3 => 11 1100 00 0000 00001100 0011
* F400D6 => 11 1101 00 0000 00001101 0110
* F800E9 => 11 1110 00 0000 00001110 1001
* FC00FC => 11 1111 00 0000 00001111 1100
* FC0102 => 11 1111 00 0000 00010000 0010
* FC0113 => 11 1111 00 0000 00010001 0011
* FC0120 => 11 1111 00 0000 00010010 0000
*
* Cnt4b: 4-bit counter changes from 1 to 15 then always equals 15
* Cnt8b: 8-bit counter changes from 1 to 72 (0x48)
* Ppdc_crc:
* uint8_t crc=0;
* for(i=4; i<24; i+=4){
* crc ^=(pdc>>i);
* }
* return crc;
* example: crc = 1^0^0^4^C = 9
* 11, 00, 0000: const
*
* Key: “Encryption Key”, Most significant 4-bit are always 0xA, Least Significant bits is
* a linear counter. In the Smoove Origin this counter is increased together with the
* rolling code. But leaving this on a constant value also works. Gerardwr notes that
* for some other types of remotes the MSB is not constant.
* Btn: 4-bit Control codes, this indicates the button that is pressed
* CRC: 4-bit Checksum.
* Ctn: 16-bit rolling code (big-endian) increased with every button press.
* Serial: 24-bit identifier of sending device (little-endian)
*
*
* Decrypt
*
* uint8_t frame[7];
* for (i=1; i < 7; i++) {
* frame[i] = frame[i] ^ frame[i-1];
* }
* or
* uint64 Decrypt = frame ^ (frame>>8);
*
* CRC
*
* uint8_t frame[7];
* for (i=0; i < 7; i++) {
* crc = crc ^ frame[i] ^ (frame[i] >> 4);
* }
* crc = crc & 0xf;
*
*/
uint64_t data = instance->data ^ (instance->data >> 8);
instance->btn = (data >> 48) & 0xF;
instance->cnt = (data >> 24) & 0xFFFF;
instance->serial = data & 0xFFFFFF;
}
static const char* subghz_protocol_somfy_keytis_get_name_button(uint8_t btn) {
const char* name_btn[0x10] = {
"Unknown",
"0x01",
"0x02",
"Prog",
"Key_1",
"0x05",
"0x06",
"0x07",
"0x08",
"0x09",
"0x0A",
"0x0B",
"0x0C",
"0x0D",
"0x0E",
"0x0F"};
return btn <= 0xf ? name_btn[btn] : name_btn[0];
}
uint8_t subghz_protocol_decoder_somfy_keytis_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSomfyKeytis* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_somfy_keytis_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderSomfyKeytis* instance = context;
bool res =
subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
if(res && !flipper_format_write_uint32(
flipper_format, "Duration_Counter", &instance->press_duration_counter, 1)) {
FURI_LOG_E(TAG, "Unable to add Duration_Counter");
res = false;
}
return res;
}
bool subghz_protocol_decoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderSomfyKeytis* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(
flipper_format,
"Duration_Counter",
(uint32_t*)&instance->press_duration_counter,
1)) {
FURI_LOG_E(TAG, "Missing Duration_Counter");
break;
}
res = true;
} while(false);
return res;
}
void subghz_protocol_decoder_somfy_keytis_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderSomfyKeytis* instance = context;
subghz_protocol_somfy_keytis_check_remote_controller(&instance->generic);
string_cat_printf(
output,
"%s %db\r\n"
"%lX%08lX%06lX\r\n"
"Sn:0x%06lX \r\n"
"Cnt:0x%04X\r\n"
"Btn:%s\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
(uint32_t)instance->generic.data,
instance->press_duration_counter,
instance->generic.serial,
instance->generic.cnt,
subghz_protocol_somfy_keytis_get_name_button(instance->generic.btn));
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME "Somfy Keytis"
typedef struct SubGhzProtocolDecoderSomfyKeytis SubGhzProtocolDecoderSomfyKeytis;
typedef struct SubGhzProtocolEncoderSomfyKeytis SubGhzProtocolEncoderSomfyKeytis;
extern const SubGhzProtocolDecoder subghz_protocol_somfy_keytis_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder;
extern const SubGhzProtocol subghz_protocol_somfy_keytis;
void* subghz_protocol_decoder_somfy_keytis_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_somfy_keytis_free(void* context);
void subghz_protocol_decoder_somfy_keytis_reset(void* context);
void subghz_protocol_decoder_somfy_keytis_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_somfy_keytis_get_hash_data(void* context);
bool subghz_protocol_decoder_somfy_keytis_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_somfy_keytis_get_string(void* context, string_t output);

View File

@@ -0,0 +1,366 @@
#include "somfy_telis.h"
#include <lib/toolbox/manchester_decoder.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolSomfyTelis"
static const SubGhzBlockConst subghz_protocol_somfy_telis_const = {
.te_short = 640,
.te_long = 1280,
.te_delta = 250,
.min_count_bit_for_found = 56,
};
struct SubGhzProtocolDecoderSomfyTelis {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
ManchesterState manchester_saved_state;
};
struct SubGhzProtocolEncoderSomfyTelis {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
SomfyTelisDecoderStepReset = 0,
SomfyTelisDecoderStepCheckPreambula,
SomfyTelisDecoderStepFoundPreambula,
SomfyTelisDecoderStepStartDecode,
SomfyTelisDecoderStepDecoderData,
} SomfyTelisDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_somfy_telis_decoder = {
.alloc = subghz_protocol_decoder_somfy_telis_alloc,
.free = subghz_protocol_decoder_somfy_telis_free,
.feed = subghz_protocol_decoder_somfy_telis_feed,
.reset = subghz_protocol_decoder_somfy_telis_reset,
.get_hash_data = subghz_protocol_decoder_somfy_telis_get_hash_data,
.serialize = subghz_protocol_decoder_somfy_telis_serialize,
.deserialize = subghz_protocol_decoder_somfy_telis_deserialize,
.get_string = subghz_protocol_decoder_somfy_telis_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_somfy_telis_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_somfy_telis = {
.name = SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_somfy_telis_decoder,
.encoder = &subghz_protocol_somfy_telis_encoder,
};
void* subghz_protocol_decoder_somfy_telis_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderSomfyTelis* instance = malloc(sizeof(SubGhzProtocolDecoderSomfyTelis));
instance->base.protocol = &subghz_protocol_somfy_telis;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_somfy_telis_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;
free(instance);
}
void subghz_protocol_decoder_somfy_telis_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;
instance->decoder.parser_step = SomfyTelisDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
static uint8_t subghz_protocol_somfy_telis_crc(uint64_t data) {
uint8_t crc = 0;
data &= 0xFFF0FFFFFFFFFF;
for(uint8_t i = 0; i < 56; i += 8) {
crc = crc ^ data >> i ^ (data >> (i + 4));
}
return crc & 0xf;
}
void subghz_protocol_decoder_somfy_telis_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;
ManchesterEvent event = ManchesterEventReset;
switch(instance->decoder.parser_step) {
case SomfyTelisDecoderStepReset:
if((level) && DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_short * 4) <
subghz_protocol_somfy_telis_const.te_delta * 4) {
instance->decoder.parser_step = SomfyTelisDecoderStepFoundPreambula;
instance->header_count++;
}
break;
case SomfyTelisDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_short * 4) <
subghz_protocol_somfy_telis_const.te_delta * 4)) {
instance->decoder.parser_step = SomfyTelisDecoderStepCheckPreambula;
} else {
instance->header_count = 0;
instance->decoder.parser_step = SomfyTelisDecoderStepReset;
}
break;
case SomfyTelisDecoderStepCheckPreambula:
if(level) {
if(DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_short * 4) <
subghz_protocol_somfy_telis_const.te_delta * 4) {
instance->decoder.parser_step = SomfyTelisDecoderStepFoundPreambula;
instance->header_count++;
} else if(
(instance->header_count > 1) &&
(DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_short * 7) <
subghz_protocol_somfy_telis_const.te_delta * 4)) {
instance->decoder.parser_step = SomfyTelisDecoderStepDecoderData;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->header_count = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
}
}
break;
case SomfyTelisDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_short) <
subghz_protocol_somfy_telis_const.te_delta) {
event = ManchesterEventShortLow;
} else if(
DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_long) <
subghz_protocol_somfy_telis_const.te_delta) {
event = ManchesterEventLongLow;
} else if(
duration >= (subghz_protocol_somfy_telis_const.te_long +
subghz_protocol_somfy_telis_const.te_delta)) {
if(instance->decoder.decode_count_bit ==
subghz_protocol_somfy_telis_const.min_count_bit_for_found) {
//check crc
uint64_t data_tmp = instance->decoder.decode_data ^
(instance->decoder.decode_data >> 8);
if(((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_telis_crc(data_tmp)) {
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;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
instance->decoder.parser_step = SomfyTelisDecoderStepReset;
} else {
instance->decoder.parser_step = SomfyTelisDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_short) <
subghz_protocol_somfy_telis_const.te_delta) {
event = ManchesterEventShortHigh;
} else if(
DURATION_DIFF(duration, subghz_protocol_somfy_telis_const.te_long) <
subghz_protocol_somfy_telis_const.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->decoder.parser_step = SomfyTelisDecoderStepReset;
}
}
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;
}
}
/** Analysis of received data
*
* @param instance SubGhzProtocolSomfyTelis instance
*/
static void subghz_protocol_somfy_telis_check_remote_controller(SubGhzBlockGeneric* instance) {
//https://pushstack.wordpress.com/somfy-rts-protocol/
/*
* 604 us
* /
* | 2416us | 2416us | 2416us | 2416us | 4550 us | | 67648 us | 30415 us |
*
* +--------+ +--------+ +---...---+
* + +--------+ +--------+ +--+XXXX...XXX+-----...-----
*
* | hw. sync. | soft. | | Inter-frame
* | | sync. | data | gap
*
*
* encrypt | decrypt
*
* package 56 bit cnt key btn|crc cnt serial
* 0xA7232323312222 - 0 => A7 8 0 | 00 00 | 12 13 00
* 0xA7222223312222 - 1 => A7 8 5 | 00 01 | 12 13 00
* 0xA7212123312222 - 2 => A7 8 6 | 00 02 | 12 13 00
*
* Key: “Encryption Key”, Most significant 4-bit are always 0xA, Least Significant bits is
* a linear counter. In the Smoove Origin this counter is increased together with the
* rolling code. But leaving this on a constant value also works. Gerardwr notes that
* for some other types of remotes the MSB is not constant.
* Btn: 4-bit Control codes, this indicates the button that is pressed
* CRC: 4-bit Checksum.
* Ctn: 16-bit rolling code (big-endian) increased with every button press.
* Serial: 24-bit identifier of sending device (little-endian)
*
*
* Decrypt
*
* uint8_t frame[7];
* for (i=1; i < 7; i++) {
* frame[i] = frame[i] ^ frame[i-1];
* }
* or
* uint64 Decrypt = frame ^ (frame>>8);
*
* Btn
*
* Value Button(s) Description
* 0x1 My Stop or move to favourite position
* 0x2 Up Move up
* 0x3 My + Up Set upper motor limit in initial programming mode
* 0x4 Down Move down
* 0x5 My + Down Set lower motor limit in initial programming mode
* 0x6 Up + Down Change motor limit and initial programming mode
* 0x8 Prog Used for (de-)registering remotes, see below
* 0x9 Sun + Flag Enable sun and wind detector (SUN and FLAG symbol on the Telis Soliris RC)
* 0xA Flag Disable sun detector (FLAG symbol on the Telis Soliris RC)
*
* CRC
*
* uint8_t frame[7];
* for (i=0; i < 7; i++) {
* cksum = cksum ^ frame[i] ^ (frame[i] >> 4);
* }
* cksum = cksum & 0xf;
*
*/
uint64_t data = instance->data ^ (instance->data >> 8);
instance->btn = (data >> 44) & 0xF;
instance->cnt = (data >> 24) & 0xFFFF;
instance->serial = data & 0xFFFFFF;
}
static const char* subghz_protocol_somfy_telis_get_name_button(uint8_t btn) {
const char* name_btn[0x10] = {
"Unknown",
"My",
"Up",
"My+Up",
"Down",
"My+Down",
"Up+Down",
"0x07",
"Prog",
"Sun+Flag",
"Flag",
"0x0B",
"0x0C",
"0x0D",
"0x0E",
"0x0F"};
return btn <= 0xf ? name_btn[btn] : name_btn[0];
}
uint8_t subghz_protocol_decoder_somfy_telis_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_somfy_telis_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
}
bool subghz_protocol_decoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_somfy_telis_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;
subghz_protocol_somfy_telis_check_remote_controller(&instance->generic);
string_cat_printf(
output,
"%s %db\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%06lX \r\n"
"Cnt:0x%04X\r\n"
"Btn:%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.cnt,
subghz_protocol_somfy_telis_get_name_button(instance->generic.btn));
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME "Somfy Telis"
typedef struct SubGhzProtocolDecoderSomfyTelis SubGhzProtocolDecoderSomfyTelis;
typedef struct SubGhzProtocolEncoderSomfyTelis SubGhzProtocolEncoderSomfyTelis;
extern const SubGhzProtocolDecoder subghz_protocol_somfy_telis_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_somfy_telis_encoder;
extern const SubGhzProtocol subghz_protocol_somfy_telis;
void* subghz_protocol_decoder_somfy_telis_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_somfy_telis_free(void* context);
void subghz_protocol_decoder_somfy_telis_reset(void* context);
void subghz_protocol_decoder_somfy_telis_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_somfy_telis_get_hash_data(void* context);
bool subghz_protocol_decoder_somfy_telis_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_somfy_telis_get_string(void* context, string_t output);

View File

@@ -0,0 +1,376 @@
#include "star_line.h"
#include "keeloq_common.h"
#include "../subghz_keystore.h"
#include <m-string.h>
#include <m-array.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolStarLine"
static const SubGhzBlockConst subghz_protocol_star_line_const = {
.te_short = 250,
.te_long = 500,
.te_delta = 120,
.min_count_bit_for_found = 64,
};
struct SubGhzProtocolDecoderStarLine {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
SubGhzKeystore* keystore;
const char* manufacture_name;
};
struct SubGhzProtocolEncoderStarLine {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
StarLineDecoderStepReset = 0,
StarLineDecoderStepCheckPreambula,
StarLineDecoderStepSaveDuration,
StarLineDecoderStepCheckDuration,
} StarLineDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_star_line_decoder = {
.alloc = subghz_protocol_decoder_star_line_alloc,
.free = subghz_protocol_decoder_star_line_free,
.feed = subghz_protocol_decoder_star_line_feed,
.reset = subghz_protocol_decoder_star_line_reset,
.get_hash_data = subghz_protocol_decoder_star_line_get_hash_data,
.serialize = subghz_protocol_decoder_star_line_serialize,
.deserialize = subghz_protocol_decoder_star_line_deserialize,
.get_string = subghz_protocol_decoder_star_line_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_star_line_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_star_line = {
.name = SUBGHZ_PROTOCOL_STAR_LINE_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_star_line_decoder,
.encoder = &subghz_protocol_star_line_encoder,
};
void* subghz_protocol_decoder_star_line_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderStarLine* instance = malloc(sizeof(SubGhzProtocolDecoderStarLine));
instance->base.protocol = &subghz_protocol_star_line;
instance->generic.protocol_name = instance->base.protocol->name;
instance->keystore = subghz_environment_get_keystore(environment);
return instance;
}
void subghz_protocol_decoder_star_line_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
free(instance);
}
void subghz_protocol_decoder_star_line_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
instance->decoder.parser_step = StarLineDecoderStepReset;
}
void subghz_protocol_decoder_star_line_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
switch(instance->decoder.parser_step) {
case StarLineDecoderStepReset:
if(level) {
if(DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long * 2) <
subghz_protocol_star_line_const.te_delta * 2) {
instance->decoder.parser_step = StarLineDecoderStepCheckPreambula;
instance->header_count++;
} else if(instance->header_count > 4) {
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->decoder.te_last = duration;
instance->decoder.parser_step = StarLineDecoderStepCheckDuration;
}
} else {
instance->header_count = 0;
}
break;
case StarLineDecoderStepCheckPreambula:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long * 2) <
subghz_protocol_star_line_const.te_delta * 2)) {
//Found Preambula
instance->decoder.parser_step = StarLineDecoderStepReset;
} else {
instance->header_count = 0;
instance->decoder.parser_step = StarLineDecoderStepReset;
}
break;
case StarLineDecoderStepSaveDuration:
if(level) {
if(duration >= (subghz_protocol_star_line_const.te_long +
subghz_protocol_star_line_const.te_delta)) {
instance->decoder.parser_step = StarLineDecoderStepReset;
if(instance->decoder.decode_count_bit >=
subghz_protocol_star_line_const.min_count_bit_for_found) {
if(instance->generic.data != instance->decoder.decode_data) {
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;
instance->header_count = 0;
break;
} else {
instance->decoder.te_last = duration;
instance->decoder.parser_step = StarLineDecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = StarLineDecoderStepReset;
}
break;
case StarLineDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_star_line_const.te_short) <
subghz_protocol_star_line_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_star_line_const.te_short) <
subghz_protocol_star_line_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = StarLineDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_star_line_const.te_long) <
subghz_protocol_star_line_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long) <
subghz_protocol_star_line_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = StarLineDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = StarLineDecoderStepReset;
}
} else {
instance->decoder.parser_step = StarLineDecoderStepReset;
}
break;
}
}
static inline bool subghz_protocol_star_line_check_decrypt(
SubGhzBlockGeneric* instance,
uint32_t decrypt,
uint8_t btn,
uint32_t end_serial) {
furi_assert(instance);
if((decrypt >> 24 == btn) && ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->cnt = decrypt & 0x0000FFFF;
return true;
}
return false;
}
/** Checking the accepted code against the database manafacture key
*
* @param instance SubGhzProtocolStarLine instance
* @param fix fix part of the parcel
* @param hop hop encrypted part of the parcel
* @return true on successful search
*/
static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
SubGhzBlockGeneric* instance,
uint32_t fix,
uint32_t hop,
SubGhzKeystore* keystore,
const char** manufacture_name) {
uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint8_t btn = (uint8_t)(fix >> 24);
uint32_t decrypt = 0;
uint64_t man_normal_learning;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal_Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
//###########################
// Normal_Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
}
}
*manufacture_name = "Unknown";
instance->cnt = 0;
return 0;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolStarLine instance
*/
static void subghz_protocol_star_line_check_remote_controller(
SubGhzBlockGeneric* instance,
SubGhzKeystore* keystore,
const char** manufacture_name) {
uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff;
subghz_protocol_star_line_check_remote_controller_selector(
instance, key_fix, key_hop, keystore, manufacture_name);
instance->serial = key_fix & 0x00FFFFFF;
instance->btn = key_fix >> 24;
}
uint8_t subghz_protocol_decoder_star_line_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_star_line_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
subghz_protocol_star_line_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
bool res =
subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
if(res && !flipper_format_write_string_cstr(
flipper_format, "Manufacture", instance->manufacture_name)) {
FURI_LOG_E(TAG, "Unable to add manufacture name");
res = false;
}
return res;
}
bool subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
res = true;
} while(false);
return res;
}
void subghz_protocol_decoder_star_line_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
subghz_protocol_star_line_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%02lX\r\n"
"MF:%s\r\n"
"Sn:0x%07lX \r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
instance->generic.cnt,
code_found_reverse_lo,
instance->generic.btn,
instance->manufacture_name,
instance->generic.serial);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_STAR_LINE_NAME "Star Line"
typedef struct SubGhzProtocolDecoderStarLine SubGhzProtocolDecoderStarLine;
typedef struct SubGhzProtocolEncoderStarLine SubGhzProtocolEncoderStarLine;
extern const SubGhzProtocolDecoder subghz_protocol_star_line_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_star_line_encoder;
extern const SubGhzProtocol subghz_protocol_star_line;
void* subghz_protocol_decoder_star_line_alloc(SubGhzEnvironment* environment);
void subghz_protocol_decoder_star_line_free(void* context);
void subghz_protocol_decoder_star_line_reset(void* context);
void subghz_protocol_decoder_star_line_feed(void* context, bool level, uint32_t duration);
uint8_t subghz_protocol_decoder_star_line_get_hash_data(void* context);
bool subghz_protocol_decoder_star_line_serialize(
void* context,
FlipperFormat* flipper_format,
uint32_t frequency,
FuriHalSubGhzPreset preset);
bool subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format);
void subghz_protocol_decoder_star_line_get_string(void* context, string_t output);

View File

@@ -1,188 +0,0 @@
#include "subghz_protocol_came.h"
#include "subghz_protocol_common.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
struct SubGhzProtocolCame {
SubGhzProtocolCommon common;
};
typedef enum {
CameDecoderStepReset = 0,
CameDecoderStepFoundStartBit,
CameDecoderStepSaveDuration,
CameDecoderStepCheckDuration,
} CameDecoderStep;
SubGhzProtocolCame* subghz_protocol_came_alloc() {
SubGhzProtocolCame* instance = malloc(sizeof(SubGhzProtocolCame));
instance->common.name = "CAME";
instance->common.code_min_count_bit_for_found = 12;
instance->common.te_short = 320;
instance->common.te_long = 640;
instance->common.te_delta = 150;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_came_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_came_send_key;
return instance;
}
void subghz_protocol_came_free(SubGhzProtocolCame* instance) {
furi_assert(instance);
free(instance);
}
bool subghz_protocol_came_send_key(
SubGhzProtocolCame* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 36);
//Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
}
}
return true;
}
void subghz_protocol_came_reset(SubGhzProtocolCame* instance) {
instance->common.parser_step = CameDecoderStepReset;
}
void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case CameDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 51) <
instance->common.te_delta * 51)) { //Need protocol 36 te_short
//Found header CAME
instance->common.parser_step = CameDecoderStepFoundStartBit;
}
break;
case CameDecoderStepFoundStartBit:
if(!level) {
break;
} else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
//Found start bit CAME
instance->common.parser_step = CameDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = CameDecoderStepReset;
}
break;
case CameDecoderStepSaveDuration:
if(!level) { //save interval
if(duration >= (instance->common.te_short * 4)) {
instance->common.parser_step = CameDecoderStepFoundStartBit;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.serial = 0x0;
instance->common.btn = 0x0;
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
break;
}
instance->common.te_last = duration;
instance->common.parser_step = CameDecoderStepCheckDuration;
} else {
instance->common.parser_step = CameDecoderStepReset;
}
break;
case CameDecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = CameDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = CameDecoderStepSaveDuration;
} else
instance->common.parser_step = CameDecoderStepReset;
} else {
instance->common.parser_step = CameDecoderStepReset;
}
break;
}
}
void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output) {
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_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",
instance->common.name,
instance->common.code_last_count_bit,
code_found_lo,
code_found_reverse_lo);
}
bool subghz_protocol_came_to_save_file(SubGhzProtocolCame* instance, FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_came_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolCame* instance,
const char* file_path) {
return subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format);
}
void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
}

View File

@@ -1,73 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolCame SubGhzProtocolCame;
/** Allocate SubGhzProtocolCame
*
* @return SubGhzProtocolCame*
*/
SubGhzProtocolCame* subghz_protocol_came_alloc();
/** Free SubGhzProtocolCame
*
* @param instance
*/
void subghz_protocol_came_free(SubGhzProtocolCame* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolCame instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_came_send_key(
SubGhzProtocolCame* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolCame instance
*/
void subghz_protocol_came_reset(SubGhzProtocolCame* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolCame instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolCame* instance
* @param output - output string
*/
void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolCame instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_came_to_save_file(SubGhzProtocolCame* instance, FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolCame instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_came_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolCame* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolCame instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context);

View File

@@ -1,264 +0,0 @@
#include "subghz_protocol_came_atomo.h"
#include "subghz_protocol_common.h"
#include <lib/toolbox/manchester_decoder.h>
#include "../subghz_keystore.h"
#define TAG "SubGhzCameAtomo"
#define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF
struct SubGhzProtocolCameAtomo {
SubGhzProtocolCommon common;
ManchesterState manchester_saved_state;
const char* rainbow_table_file_name;
};
typedef enum {
CameAtomoDecoderStepReset = 0,
CameAtomoDecoderStepDecoderData,
} CameAtomoDecoderStep;
SubGhzProtocolCameAtomo* subghz_protocol_came_atomo_alloc() {
SubGhzProtocolCameAtomo* instance = malloc(sizeof(SubGhzProtocolCameAtomo));
instance->common.name = "CAME Atomo";
instance->common.code_min_count_bit_for_found = 62;
instance->common.te_short = 600;
instance->common.te_long = 1200;
instance->common.te_delta = 250;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_atomo_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_atomo_to_load_protocol;
return instance;
}
void subghz_protocol_came_atomo_free(SubGhzProtocolCameAtomo* instance) {
furi_assert(instance);
free(instance);
}
void subghz_protocol_came_atomo_name_file(SubGhzProtocolCameAtomo* instance, const char* name) {
instance->rainbow_table_file_name = name;
FURI_LOG_I(TAG, "Loading rainbow table from %s", name);
}
/** Read bytes from rainbow table
*
* @param instance - SubGhzProtocolCameAtomo* instance
* @param number_atomo_magic_xor
* @return atomo_magic_xor
*/
uint64_t subghz_came_atomo_get_atomo_magic_xor_in_file(
SubGhzProtocolCameAtomo* instance,
uint8_t number_atomo_magic_xor) {
if(!strcmp(instance->rainbow_table_file_name, "")) return SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
uint8_t buffer[sizeof(uint64_t)] = {0};
uint32_t address = number_atomo_magic_xor * sizeof(uint64_t);
uint64_t atomo_magic_xor = 0;
if(subghz_keystore_raw_get_data(
instance->rainbow_table_file_name, address, buffer, sizeof(uint64_t))) {
for(size_t i = 0; i < sizeof(uint64_t); i++) {
atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i];
}
} else {
atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
}
return atomo_magic_xor;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolCameAtomo instance
*/
void subghz_protocol_came_atomo_remote_controller(SubGhzProtocolCameAtomo* instance) {
/*
* 0x1fafef3ed0f7d9ef
* 0x185fcc1531ee86e7
* 0x184fa96912c567ff
* 0x187f8a42f3dc38f7
* 0x186f63915492a5cd
* 0x181f40bab58bfac5
* 0x180f25c696a01bdd
* 0x183f06ed77b944d5
* 0x182ef661d83d21a9
* 0x18ded54a39247ea1
* 0x18ceb0361a0f9fb9
* 0x18fe931dfb16c0b1
* 0x18ee7ace5c585d8b
* ........
* transmission consists of 99 parcels with increasing counter while holding down the button
* with each new press, the counter in the encrypted part increases
*
* 0x1FAFF13ED0F7D9EF
* 0x1FAFF11ED0F7D9EF
* 0x1FAFF10ED0F7D9EF
* 0x1FAFF0FED0F7D9EF
* 0x1FAFF0EED0F7D9EF
* 0x1FAFF0DED0F7D9EF
* 0x1FAFF0CED0F7D9EF
* 0x1FAFF0BED0F7D9EF
* 0x1FAFF0AED0F7D9EF
*
* where 0x1FAF - parcel counter, 0хF0A - button press counter,
* 0xED0F7D9E - serial number, 0хF - key
* 0x1FAF parcel counter - 1 in the parcel queue ^ 0x185F = 0x07F0
* 0x185f ^ 0x185F = 0x0000
* 0x184f ^ 0x185F = 0x0010
* 0x187f ^ 0x185F = 0x0020
* .....
* 0x182e ^ 0x185F = 0x0071
* 0x18de ^ 0x185F = 0x0081
* .....
* 0x1e43 ^ 0x185F = 0x061C
* where the last nibble is incremented every 8 samples
*
* Decode
*
* 0x1cf6931dfb16c0b1 => 0x1cf6
* 0x1cf6 ^ 0x185F = 0x04A9
* 0x04A9 => 0x04A = 74 (dec)
* 74+1 % 32(atomo_magic_xor) = 11
* GET atomo_magic_xor[11] = 0xXXXXXXXXXXXXXXXX
* 0x931dfb16c0b1 ^ 0xXXXXXXXXXXXXXXXX = 0xEF3ED0F7D9EF
* 0xEF3 ED0F7D9E F => 0xEF3 - CNT, 0xED0F7D9E - SN, 0xF - key
*
* */
uint16_t parcel_counter = instance->common.code_last_found >> 48;
parcel_counter = parcel_counter ^ 0x185F;
parcel_counter >>= 4;
uint8_t ind = (parcel_counter + 1) % 32;
uint64_t temp_data = instance->common.code_last_found & 0x0000FFFFFFFFFFFF;
uint64_t atomo_magic_xor = subghz_came_atomo_get_atomo_magic_xor_in_file(instance, ind);
if(atomo_magic_xor != SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE) {
temp_data = temp_data ^ atomo_magic_xor;
instance->common.cnt = temp_data >> 36;
instance->common.serial = (temp_data >> 4) & 0x000FFFFFFFF;
instance->common.btn = temp_data & 0xF;
} else {
instance->common.cnt = 0;
instance->common.serial = 0;
instance->common.btn = 0;
}
}
void subghz_protocol_came_atomo_reset(SubGhzProtocolCameAtomo* instance) {
instance->common.parser_step = CameAtomoDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
void subghz_protocol_came_atomo_parse(
SubGhzProtocolCameAtomo* instance,
bool level,
uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch(instance->common.parser_step) {
case CameAtomoDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 65) <
instance->common.te_delta * 20)) {
//Found header CAME
instance->common.parser_step = CameAtomoDecoderStepDecoderData;
instance->common.code_found = 0;
instance->common.code_count_bit = 1;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
}
break;
case CameAtomoDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortLow;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongLow;
} else if(duration >= (instance->common.te_long * 2 + instance->common.te_delta)) {
if(instance->common.code_count_bit ==
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 1;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
} else {
instance->common.parser_step = CameAtomoDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortHigh;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->common.parser_step = CameAtomoDecoderStepReset;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
if(data_ok) {
instance->common.code_found = (instance->common.code_found << 1) | !data;
instance->common.code_count_bit++;
}
}
break;
}
}
void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string_t output) {
subghz_protocol_came_atomo_remote_controller(instance);
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %db\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%08lX Btn:0x%01X\r\n"
"Cnt:0x%03X\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
instance->common.serial,
instance->common.btn,
instance->common.cnt);
}
void subghz_decoder_came_atomo_to_load_protocol(SubGhzProtocolCameAtomo* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_came_atomo_remote_controller(instance);
}

View File

@@ -1,53 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolCameAtomo SubGhzProtocolCameAtomo;
/** Allocate SubGhzProtocolCameAtomo
*
* @return SubGhzProtocolCameAtomo*
*/
SubGhzProtocolCameAtomo* subghz_protocol_came_atomo_alloc();
/** Free SubGhzProtocolCameAtomo
*
* @param instance
*/
void subghz_protocol_came_atomo_free(SubGhzProtocolCameAtomo* instance);
/** File name rainbow table CAME Atomo
*
* @param instance - SubGhzProtocolCameAtomo instance
* @param file_name - "path/file_name"
*/
void subghz_protocol_came_atomo_name_file(SubGhzProtocolCameAtomo* instance, const char* name);
/** Reset internal state
* @param instance - SubGhzProtocolCameAtomo instance
*/
void subghz_protocol_came_atomo_reset(SubGhzProtocolCameAtomo* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolCameAtomo instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_came_atomo_parse(
SubGhzProtocolCameAtomo* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolCameAtomo* instance
* @param output - output string
*/
void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolCameAtomo instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_came_atomo_to_load_protocol(SubGhzProtocolCameAtomo* instance, void* context);

View File

@@ -1,353 +0,0 @@
#include "subghz_protocol_came_twee.h"
#include "subghz_protocol_common.h"
#include <lib/toolbox/manchester_decoder.h>
#include <lib/toolbox/manchester_encoder.h>
/*
* Help
* https://phreakerclub.com/forum/showthread.php?t=635&highlight=came+twin
*
*/
#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c"
#define CNT_TO_DIP(dip) \
(dip & 0x0200 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), \
(dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), \
(dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), \
(dip & 0x0001 ? '1' : '0')
struct SubGhzProtocolCameTwee {
SubGhzProtocolCommon common;
ManchesterState manchester_saved_state;
};
typedef enum {
CameTweeDecoderStepReset = 0,
CameTweeDecoderStepDecoderData,
} CameTweeDecoderStep;
SubGhzProtocolCameTwee* subghz_protocol_came_twee_alloc() {
SubGhzProtocolCameTwee* instance = malloc(sizeof(SubGhzProtocolCameTwee));
instance->common.name = "CAME TWEE";
instance->common.code_min_count_bit_for_found = 54;
instance->common.te_short = 500;
instance->common.te_long = 1000;
instance->common.te_delta = 250;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_twee_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_came_twee_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_twee_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_twee_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_came_twee_send_key;
return instance;
}
void subghz_protocol_came_twee_free(SubGhzProtocolCameTwee* instance) {
furi_assert(instance);
free(instance);
}
LevelDuration subghz_protocol_came_twee_add_duration_to_upload(
SubGhzProtocolCameTwee* instance,
ManchesterEncoderResult result) {
LevelDuration data = {.duration = 0, .level = 0};
switch(result) {
case ManchesterEncoderResultShortLow:
data.duration = instance->common.te_short;
data.level = false;
break;
case ManchesterEncoderResultLongLow:
data.duration = instance->common.te_long;
data.level = false;
break;
case ManchesterEncoderResultLongHigh:
data.duration = instance->common.te_long;
data.level = true;
break;
case ManchesterEncoderResultShortHigh:
data.duration = instance->common.te_short;
data.level = true;
break;
default:
printf("DO CRASH HERE\r\n");
// furi_crash
break;
}
return level_duration_make(data.level, data.duration);
}
bool subghz_protocol_came_twee_send_key(
SubGhzProtocolCameTwee* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
const uint32_t magic_numbers_xor[15] = {
0x0E0E0E00,
0x1D1D1D11,
0x2C2C2C22,
0x3B3B3B33,
0x4A4A4A44,
0x59595955,
0x68686866,
0x77777777,
0x86868688,
0x95959599,
0xA4A4A4AA,
0xB3B3B3BB,
0xC2C2C2CC,
0xD1D1D1DD,
0xE0E0E0EE,
};
size_t index = 0;
ManchesterEncoderState enc_state;
manchester_encoder_reset(&enc_state);
ManchesterEncoderResult result;
// encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
// if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
uint64_t temp_parcel = 0x003FFF7200000000; //parcel mask
for(int i = 14; i >= 0; i--) {
temp_parcel = (temp_parcel & 0xFFFFFFFF00000000) |
(instance->common.serial ^ magic_numbers_xor[i]);
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(!manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result)) {
encoder->upload[index++] =
subghz_protocol_came_twee_add_duration_to_upload(instance, result);
manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result);
}
encoder->upload[index++] =
subghz_protocol_came_twee_add_duration_to_upload(instance, result);
}
encoder->upload[index] = subghz_protocol_came_twee_add_duration_to_upload(
instance, manchester_encoder_finish(&enc_state));
if(level_duration_get_level(encoder->upload[index])) {
index++;
}
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long * 51);
}
encoder->size_upload = index;
return true;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolCameTwee instance
*/
void subghz_protocol_came_twee_remote_controller(SubGhzProtocolCameTwee* instance) {
/* Came Twee 54 bit, rolling code 15 parcels with
* a decreasing counter from 0xE to 0x0
* with originally coded dip switches on the console 10 bit code
*
* 0x003FFF72E04A6FEE
* 0x003FFF72D17B5EDD
* 0x003FFF72C2684DCC
* 0x003FFF72B3193CBB
* 0x003FFF72A40E2BAA
* 0x003FFF72953F1A99
* 0x003FFF72862C0988
* 0x003FFF7277DDF877
* 0x003FFF7268C2E766
* 0x003FFF7259F3D655
* 0x003FFF724AE0C544
* 0x003FFF723B91B433
* 0x003FFF722C86A322
* 0x003FFF721DB79211
* 0x003FFF720EA48100
*
* decryption
* the last 32 bits, do XOR by the desired number, divide the result by 4,
* convert the first 16 bits of the resulting 32-bit number to bin and do
* bit-by-bit mirroring, adding up to 10 bits
*
* Example
* Step 1. 0x003FFF721DB79211 => 0x1DB79211
* Step 4. 0x1DB79211 xor 0x1D1D1D11 => 0x00AA8F00
* Step 4. 0x00AA8F00 / 4 => 0x002AA3C0
* Step 5. 0x002AA3C0 => 0x002A
* Step 6. 0x002A bin => b101010
* Step 7. b101010 => b0101010000
* Step 8. b0101010000 => (Dip) Off ON Off ON Off ON Off Off Off Off
*/
const uint32_t magic_numbers_xor[15] = {
0x0E0E0E00,
0x1D1D1D11,
0x2C2C2C22,
0x3B3B3B33,
0x4A4A4A44,
0x59595955,
0x68686866,
0x77777777,
0x86868688,
0x95959599,
0xA4A4A4AA,
0xB3B3B3BB,
0xC2C2C2CC,
0xD1D1D1DD,
0xE0E0E0EE,
};
uint8_t cnt_parcel = (uint8_t)(instance->common.code_last_found & 0xF);
uint32_t data = (uint32_t)(instance->common.code_last_found & 0x0FFFFFFFF);
data = (data ^ magic_numbers_xor[cnt_parcel]);
instance->common.serial = data;
data /= 4;
instance->common.btn = (data >> 4) & 0x0F;
data >>= 16;
data = (uint16_t)subghz_protocol_common_reverse_key(data, 16);
instance->common.cnt = data >> 6;
}
void subghz_protocol_came_twee_reset(SubGhzProtocolCameTwee* instance) {
instance->common.parser_step = CameTweeDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
void subghz_protocol_came_twee_parse(
SubGhzProtocolCameTwee* instance,
bool level,
uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch(instance->common.parser_step) {
case CameTweeDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 51) <
instance->common.te_delta * 20)) {
//Found header CAME
instance->common.parser_step = CameTweeDecoderStepDecoderData;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongLow,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
}
break;
case CameTweeDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortLow;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongLow;
} else if(duration >= (instance->common.te_long * 2 + instance->common.te_delta)) {
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongLow,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventShortLow,
&instance->manchester_saved_state,
NULL);
} else {
instance->common.parser_step = CameTweeDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortHigh;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->common.parser_step = CameTweeDecoderStepReset;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
if(data_ok) {
instance->common.code_found = (instance->common.code_found << 1) | !data;
instance->common.code_count_bit++;
}
}
break;
}
}
void subghz_protocol_came_twee_to_str(SubGhzProtocolCameTwee* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Btn:%lX\r\n"
"DIP:" DIP_PATTERN,
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
instance->common.btn,
CNT_TO_DIP(instance->common.cnt));
}
bool subghz_protocol_came_twee_to_save_file(
SubGhzProtocolCameTwee* instance,
FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_came_twee_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolCameTwee* instance,
const char* file_path) {
if(subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format)) {
subghz_protocol_came_twee_remote_controller(instance);
return true;
}
return false;
}
void subghz_decoder_came_twee_to_load_protocol(SubGhzProtocolCameTwee* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_came_twee_remote_controller(instance);
}

View File

@@ -1,78 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolCameTwee SubGhzProtocolCameTwee;
/** Allocate SubGhzProtocolCameTwee
*
* @return SubGhzProtocolCameTwee*
*/
SubGhzProtocolCameTwee* subghz_protocol_came_twee_alloc();
/** Free SubGhzProtocolCameTwee
*
* @param instance
*/
void subghz_protocol_came_twee_free(SubGhzProtocolCameTwee* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolCameTwee instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_came_twee_send_key(
SubGhzProtocolCameTwee* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolCameTwee instance
*/
void subghz_protocol_came_twee_reset(SubGhzProtocolCameTwee* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolCameTwee instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_came_twee_parse(
SubGhzProtocolCameTwee* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolCameTwee* instance
* @param output - output string
*/
void subghz_protocol_came_twee_to_str(SubGhzProtocolCameTwee* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolCameTwee instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_came_twee_to_save_file(
SubGhzProtocolCameTwee* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolCameTwee instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_came_twee_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolCameTwee* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolCameTwee instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_came_twee_to_load_protocol(SubGhzProtocolCameTwee* instance, void* context);

View File

@@ -1,4 +0,0 @@
/*
* https://phreakerclub.com/616
*/

View File

@@ -1,236 +0,0 @@
#include "subghz_protocol_common.h"
#include <stdio.h>
#include <lib/toolbox/hex.h>
SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc() {
SubGhzProtocolCommonEncoder* instance = malloc(sizeof(SubGhzProtocolCommonEncoder));
instance->upload = malloc(SUBGHZ_ENCODER_UPLOAD_MAX_SIZE * sizeof(LevelDuration));
instance->start = true;
instance->repeat = 10; //default number of repeat
return instance;
}
void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance) {
furi_assert(instance);
if(instance->callback_end) {
instance->callback_end((SubGhzProtocolCommon*)instance->context_end);
}
free(instance->upload);
free(instance);
}
size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instance) {
furi_assert(instance);
return instance->repeat;
}
void subghz_protocol_encoder_common_set_callback(
SubGhzProtocolCommonEncoder* instance,
SubGhzProtocolCommonEncoderCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void subghz_protocol_encoder_common_set_callback_end(
SubGhzProtocolCommonEncoder* instance,
SubGhzProtocolCommonEncoderCallbackEnd callback_end,
void* context_end) {
furi_assert(instance);
furi_assert(callback_end);
instance->callback_end = callback_end;
instance->context_end = context_end;
}
LevelDuration subghz_protocol_encoder_common_yield(void* context) {
SubGhzProtocolCommonEncoder* instance = context;
if(instance->callback) {
return instance->callback((SubGhzProtocolCommon*)instance->context);
}
if(instance->repeat == 0) {
return level_duration_reset();
}
LevelDuration ret = instance->upload[instance->front];
if(++instance->front == instance->size_upload) {
instance->repeat--;
instance->front = 0;
}
return ret;
}
void subghz_protocol_common_add_bit(SubGhzProtocolCommon* common, uint8_t bit) {
common->code_found = common->code_found << 1 | bit;
common->code_count_bit++;
}
bool subghz_protocol_common_check_interval(
SubGhzProtocolCommon* common,
uint32_t duration,
uint16_t duration_check) {
if((duration_check >= (duration - common->te_delta)) &&
(duration_check <= (duration + common->te_delta))) {
return true;
} else {
return false;
}
}
uint64_t subghz_protocol_common_reverse_key(uint64_t key, uint8_t count_bit) {
uint64_t key_reverse = 0;
for(uint8_t i = 0; i < count_bit; i++) {
key_reverse = key_reverse << 1 | bit_read(key, i);
}
return key_reverse;
}
void subghz_protocol_common_set_callback(
SubGhzProtocolCommon* common,
SubGhzProtocolCommonCallback callback,
void* context) {
common->callback = callback;
common->context = context;
}
void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output) {
if(instance->to_string) {
instance->to_string(instance, output);
} else {
uint32_t code_found_hi = instance->code_found >> 32;
uint32_t code_found_lo = instance->code_found & 0x00000000ffffffff;
uint64_t code_found_reverse =
subghz_protocol_common_reverse_key(instance->code_found, instance->code_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
if(code_found_hi > 0) {
string_cat_printf(
output,
"Protocol %s, %d Bit\r\n"
" KEY:0x%lX%08lX\r\n"
" YEK:0x%lX%08lX\r\n"
" SN:0x%05lX BTN:%02X\r\n",
instance->name,
instance->code_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
code_found_reverse_lo,
instance->serial,
instance->btn);
} else {
string_cat_printf(
output,
"Protocol %s, %d Bit\r\n"
" KEY:0x%lX%lX\r\n"
" YEK:0x%lX%lX\r\n"
" SN:0x%05lX BTN:%02X\r\n",
instance->name,
instance->code_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
code_found_reverse_lo,
instance->serial,
instance->btn);
}
}
}
bool subghz_protocol_common_read_hex(string_t str, uint8_t* buff, uint16_t len) {
string_strim(str);
uint8_t nibble_high = 0;
uint8_t nibble_low = 0;
bool parsed = true;
for(uint16_t i = 0; i < len; i++) {
if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) &&
hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) {
buff[i] = (nibble_high << 4) | nibble_low;
if(string_size(str) > 2) {
string_right(str, 2);
} else if(i < len - 1) {
parsed = false;
break;
};
} else {
parsed = false;
break;
}
}
return parsed;
}
bool subghz_protocol_common_to_save_file(
SubGhzProtocolCommon* instance,
FlipperFormat* flipper_format) {
furi_assert(instance);
furi_assert(flipper_format);
bool res = false;
do {
if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->name)) {
FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Protocol");
break;
}
uint32_t temp = instance->code_last_count_bit;
if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) {
FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Bit");
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->code_last_found >> i * 8) & 0xFF;
}
if(!flipper_format_write_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Key");
break;
}
res = true;
} while(false);
return res;
}
bool subghz_protocol_common_to_load_protocol_from_file(
SubGhzProtocolCommon* instance,
FlipperFormat* flipper_format) {
furi_assert(instance);
furi_assert(flipper_format);
bool loaded = false;
string_t temp_str;
string_init(temp_str);
uint32_t temp_data = 0;
do {
if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Bit");
break;
}
instance->code_last_count_bit = (uint8_t)temp_data;
uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Key");
break;
}
for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
instance->code_last_found = instance->code_last_found << 8 | key_data[i];
}
loaded = true;
} while(0);
string_clear(temp_str);
return loaded;
}

View File

@@ -1,226 +0,0 @@
#pragma once
#include <m-string.h>
#include <furi_hal.h>
#include <stdint.h>
#include <flipper_format/flipper_format.h>
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
#define bit_set(value, bit) ((value) |= (1UL << (bit)))
#define bit_clear(value, bit) ((value) &= ~(1UL << (bit)))
#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
#define SUBGHZ_TX_PIN_HIGH()
#define SUBGHZ_TX_PIN_LOW()
#define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y))
#define SUBGHZ_APP_FOLDER "/any/subghz"
#define SUBGHZ_RAW_FOLDER "/ext/subghz"
#define SUBGHZ_APP_EXTENSION ".sub"
#define SUBGHZ_ENCODER_UPLOAD_MAX_SIZE 2048
#define SUBGHZ_PARSER_TAG "SubGhzParser"
#define SUBGHZ_KEY_FILE_VERSION 1
#define SUBGHZ_KEY_FILE_TYPE "Flipper SubGhz Key File"
#define SUBGHZ_RAW_FILE_VERSION 1
#define SUBGHZ_RAW_FILE_TYPE "Flipper SubGhz RAW File"
typedef enum {
SubGhzProtocolCommonTypeUnknown,
SubGhzProtocolCommonTypeStatic,
SubGhzProtocolCommonTypeDynamic,
SubGhzProtocolCommonTypeRAW,
} SubGhzProtocolCommonType;
typedef struct SubGhzProtocolCommon SubGhzProtocolCommon;
typedef struct SubGhzProtocolCommonEncoder SubGhzProtocolCommonEncoder;
typedef struct SubGhzProtocolCommonLoad SubGhzProtocolCommonLoad;
typedef void (*SubGhzProtocolCommonCallback)(SubGhzProtocolCommon* parser, void* context);
typedef void (*SubGhzProtocolCommonToStr)(SubGhzProtocolCommon* instance, string_t output);
//Get string to save
typedef bool (
*SubGhzProtocolCommonSaveFile)(SubGhzProtocolCommon* instance, FlipperFormat* flipper_format);
//Load protocol from file
typedef bool (*SubGhzProtocolCommonLoadFromFile)(
FlipperFormat* flipper_format,
SubGhzProtocolCommon* instance,
const char* file_path);
//Load protocol
typedef void (*SubGhzProtocolCommonLoadFromRAW)(SubGhzProtocolCommon* instance, void* context);
//Get upload encoder protocol
typedef bool (*SubGhzProtocolCommonEncoderGetUpLoad)(
SubGhzProtocolCommon* instance,
SubGhzProtocolCommonEncoder* encoder);
typedef LevelDuration (*SubGhzProtocolCommonEncoderCallback)(void* context);
typedef void (*SubGhzProtocolCommonEncoderCallbackEnd)(void* context);
struct SubGhzProtocolCommon {
const char* name;
uint16_t te_long;
uint16_t te_short;
uint16_t te_delta;
uint8_t code_count_bit;
uint8_t code_last_count_bit;
uint64_t code_found;
uint64_t code_last_found;
uint8_t code_min_count_bit_for_found;
uint8_t btn;
uint8_t header_count;
SubGhzProtocolCommonType type_protocol;
uint32_t te_last;
uint32_t serial;
uint32_t parser_step;
uint16_t cnt;
/* Standard Callback for on rx complete event */
SubGhzProtocolCommonCallback callback;
void* context;
/* Dump To String */
SubGhzProtocolCommonToStr to_string;
/* Get string to save */
SubGhzProtocolCommonSaveFile to_save_file;
/* Load protocol from file */
SubGhzProtocolCommonLoadFromFile to_load_protocol_from_file;
/* Load protocol from RAW data */
SubGhzProtocolCommonLoadFromRAW to_load_protocol;
/* Get upload encoder protocol */
SubGhzProtocolCommonEncoderGetUpLoad get_upload_protocol;
};
struct SubGhzProtocolCommonEncoder {
bool start;
size_t repeat;
size_t front;
size_t size_upload;
LevelDuration* upload;
SubGhzProtocolCommonEncoderCallback callback;
SubGhzProtocolCommonEncoderCallbackEnd callback_end;
void* context;
void* context_end;
};
struct SubGhzProtocolCommonLoad {
uint64_t code_found;
uint8_t code_count_bit;
uint32_t param1;
uint32_t param2;
uint32_t param3;
};
/** Allocate SubGhzProtocolCommonEncoder
*
* @return SubGhzProtocolCommonEncoder*
*/
SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc();
/** Free SubGhzProtocolCommonEncoder
*
* @param instance
*/
void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance);
void subghz_protocol_encoder_common_set_callback(
SubGhzProtocolCommonEncoder* instance,
SubGhzProtocolCommonEncoderCallback callback,
void* context);
void subghz_protocol_encoder_common_set_callback_end(
SubGhzProtocolCommonEncoder* instance,
SubGhzProtocolCommonEncoderCallbackEnd callback_end,
void* context_end);
/** Get count repeat left
*
* @param instance - SubGhzProtocolCommonEncoder instance
* @return count repeat left
*/
size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instance);
/** Get LevelDuration this encoder step
*
* @param context - SubGhzProtocolCommonEncoder context
* @return LevelDuration this step
*/
LevelDuration subghz_protocol_encoder_common_yield(void* context);
/** Add data bit to code_found
*
* @param common - SubGhzProtocolCommon common
* @param bit - add bit
*/
void subghz_protocol_common_add_bit(SubGhzProtocolCommon* common, uint8_t bit);
/** Checking that the duration is included in the interval
*
* @param common - SubGhzProtocolCommon common
* @param duration duration reference
* @param duration_check duration checked
* @return true on success
*/
bool subghz_protocol_common_check_interval(
SubGhzProtocolCommon* common,
uint32_t duration,
uint16_t duration_check);
/** Bit-by-bit data mirroring
*
* @param key - data to mirror
* @param count_bit number of data bits
* @return mirrored data
*/
uint64_t subghz_protocol_common_reverse_key(uint64_t key, uint8_t count_bit);
/** Callback protocol
*
* @param instance - SubGhzProtocolCommon* instance
* @param callback
* @param context
*/
void subghz_protocol_common_set_callback(
SubGhzProtocolCommon* instance,
SubGhzProtocolCommonCallback callback,
void* context);
/** outputting information from the parser
*
* @param instance - SubGhzProtocolCommon* instance
* @param output - output string
*/
void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output);
/** Converting a string to a HEX array
*
* @param str - string data
* @param buff - uint8_t* buff
* @param len - size buff
* @return bool
*/
bool subghz_protocol_common_read_hex(string_t str, uint8_t* buff, uint16_t len);
/** Adding data to a file
*
* @param instance - SubGhzProtocolCommon instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_common_to_save_file(
SubGhzProtocolCommon* instance,
FlipperFormat* flipper_format);
/** Loading data to a file
*
* @param instance - SubGhzProtocolCommon instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_common_to_load_protocol_from_file(
SubGhzProtocolCommon* instance,
FlipperFormat* flipper_format);

View File

@@ -1,189 +0,0 @@
#include "subghz_protocol_faac_slh.h"
struct SubGhzProtocolFaacSLH {
SubGhzProtocolCommon common;
};
typedef enum {
FaacSLHDecoderStepReset = 0,
FaacSLHDecoderStepFoundPreambula,
FaacSLHDecoderStepSaveDuration,
FaacSLHDecoderStepCheckDuration,
} FaacSLHDecoderStep;
SubGhzProtocolFaacSLH* subghz_protocol_faac_slh_alloc(void) {
SubGhzProtocolFaacSLH* instance = malloc(sizeof(SubGhzProtocolFaacSLH));
instance->common.name = "Faac SLH";
instance->common.code_min_count_bit_for_found = 64;
instance->common.te_short = 255;
instance->common.te_long = 595;
instance->common.te_delta = 100;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_faac_slh_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_faac_slh_to_load_protocol;
return instance;
}
void subghz_protocol_faac_slh_free(SubGhzProtocolFaacSLH* instance) {
furi_assert(instance);
free(instance);
}
/** Send bit
*
* @param instance - SubGhzProtocolFaacSLH instance
* @param bit - bit
*/
void subghz_protocol_faac_slh_send_bit(SubGhzProtocolFaacSLH* instance, uint8_t bit) {
if(bit) {
//send bit 1
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_long);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short);
} else {
//send bit 0
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_short);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long);
}
}
void subghz_protocol_faac_slh_send_key(
SubGhzProtocolFaacSLH* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat) {
while(repeat--) {
SUBGHZ_TX_PIN_HIGH();
//Send header
delay_us(instance->common.te_long * 2);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long * 2);
//Send key data
for(uint8_t i = bit; i > 0; i--) {
subghz_protocol_faac_slh_send_bit(instance, bit_read(key, i - 1));
}
}
}
void subghz_protocol_faac_slh_reset(SubGhzProtocolFaacSLH* instance) {
instance->common.parser_step = FaacSLHDecoderStepReset;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolFaacSLH instance
*/
void subghz_protocol_faac_slh_check_remote_controller(SubGhzProtocolFaacSLH* instance) {
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
//uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF;
instance->common.serial = code_fix & 0xFFFFFFF;
instance->common.btn = (code_fix >> 28) & 0x0F;
}
void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case FaacSLHDecoderStepReset:
if((level) && (DURATION_DIFF(duration, instance->common.te_long * 2) <
instance->common.te_delta * 3)) {
instance->common.parser_step = FaacSLHDecoderStepFoundPreambula;
}
break;
case FaacSLHDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 2) <
instance->common.te_delta * 3)) {
//Found Preambula
instance->common.parser_step = FaacSLHDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = FaacSLHDecoderStepReset;
}
break;
case FaacSLHDecoderStepSaveDuration:
if(level) {
if(duration >= (instance->common.te_short * 3 + instance->common.te_delta)) {
instance->common.parser_step = FaacSLHDecoderStepFoundPreambula;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
break;
} else {
instance->common.te_last = duration;
instance->common.parser_step = FaacSLHDecoderStepCheckDuration;
}
} else {
instance->common.parser_step = FaacSLHDecoderStepReset;
}
break;
case FaacSLHDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = FaacSLHDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = FaacSLHDecoderStepSaveDuration;
} else {
instance->common.parser_step = FaacSLHDecoderStepReset;
}
} else {
instance->common.parser_step = FaacSLHDecoderStepReset;
}
break;
}
}
void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output) {
subghz_protocol_faac_slh_check_remote_controller(instance);
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
uint32_t code_hop = (code_found_reverse >> 32) & 0xFFFFFFFF;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%lX%08lX\r\n"
"Fix:%08lX \r\n"
"Hop:%08lX \r\n"
"Sn:%07lX Btn:%lX\r\n",
instance->common.name,
instance->common.code_last_count_bit,
(uint32_t)(instance->common.code_last_found >> 32),
(uint32_t)instance->common.code_last_found,
code_fix,
code_hop,
instance->common.serial,
instance->common.btn);
}
void subghz_decoder_faac_slh_to_load_protocol(SubGhzProtocolFaacSLH* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_faac_slh_check_remote_controller(instance);
}

View File

@@ -1,62 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolFaacSLH SubGhzProtocolFaacSLH;
/** Allocate SubGhzProtocolFaacSLH
*
* @return SubGhzProtocolFaacSLH*
*/
SubGhzProtocolFaacSLH* subghz_protocol_faac_slh_alloc();
/** Free SubGhzProtocolFaacSLH
*
* @param instance
*/
void subghz_protocol_faac_slh_free(SubGhzProtocolFaacSLH* instance);
/** Sends the key on the air
*
* @param instance - SubGhzProtocolFaacSLH instance
* @param key - key send
* @param bit - count bit key
* @param repeat - repeat send key
*/
void subghz_protocol_faac_slh_send_key(
SubGhzProtocolFaacSLH* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat);
/** Reset internal state
* @param instance - SubGhzProtocolFaacSLH instance
*/
void subghz_protocol_faac_slh_reset(SubGhzProtocolFaacSLH* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolFaacSLH instance
*/
void subghz_protocol_faac_slh_check_remote_controller(SubGhzProtocolFaacSLH* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolFaacSLH instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolFaacSLH* instance
* @param output - output string
*/
void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolFaacSLH instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_faac_slh_to_load_protocol(SubGhzProtocolFaacSLH* instance, void* context);

View File

@@ -1,195 +0,0 @@
#include "subghz_protocol_gate_tx.h"
struct SubGhzProtocolGateTX {
SubGhzProtocolCommon common;
};
typedef enum {
GateTXDecoderStepReset = 0,
GateTXDecoderStepFoundStartBit,
GateTXDecoderStepSaveDuration,
GateTXDecoderStepCheckDuration,
} GateTXDecoderStep;
SubGhzProtocolGateTX* subghz_protocol_gate_tx_alloc(void) {
SubGhzProtocolGateTX* instance = malloc(sizeof(SubGhzProtocolGateTX));
instance->common.name = "GateTX";
instance->common.code_min_count_bit_for_found = 24;
instance->common.te_short = 350;
instance->common.te_long = 700;
instance->common.te_delta = 100;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_gate_tx_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_gate_tx_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_gate_tx_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_gate_tx_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_gate_tx_send_key;
return instance;
}
void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance) {
furi_assert(instance);
free(instance);
}
bool subghz_protocol_gate_tx_send_key(
SubGhzProtocolGateTX* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 49);
//Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
}
}
return true;
}
void subghz_protocol_gate_tx_reset(SubGhzProtocolGateTX* instance) {
instance->common.parser_step = GateTXDecoderStepReset;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolFaacSLH instance
*/
void subghz_protocol_gate_tx_check_remote_controller(SubGhzProtocolGateTX* instance) {
uint32_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
instance->common.serial = (code_found_reverse & 0xFF) << 12 |
((code_found_reverse >> 8) & 0xFF) << 4 |
((code_found_reverse >> 20) & 0x0F);
instance->common.btn = ((code_found_reverse >> 16) & 0x0F);
}
void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case GateTXDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 47) <
instance->common.te_delta * 47)) {
//Found Preambula
instance->common.parser_step = GateTXDecoderStepFoundStartBit;
}
break;
case GateTXDecoderStepFoundStartBit:
if(level &&
((DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta * 3))) {
//Found start bit
instance->common.parser_step = GateTXDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = GateTXDecoderStepReset;
}
break;
case GateTXDecoderStepSaveDuration:
if(!level) {
if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) {
instance->common.parser_step = GateTXDecoderStepFoundStartBit;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
break;
} else {
instance->common.te_last = duration;
instance->common.parser_step = GateTXDecoderStepCheckDuration;
}
}
break;
case GateTXDecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) <
instance->common.te_delta * 3)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = GateTXDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta * 3) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = GateTXDecoderStepSaveDuration;
} else {
instance->common.parser_step = GateTXDecoderStepReset;
}
} else {
instance->common.parser_step = GateTXDecoderStepReset;
}
break;
}
}
void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output) {
subghz_protocol_gate_tx_check_remote_controller(instance);
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%06lX\r\n"
"Sn:%05lX Btn:%lX\r\n",
instance->common.name,
instance->common.code_last_count_bit,
(uint32_t)(instance->common.code_last_found & 0xFFFFFF),
instance->common.serial,
instance->common.btn);
}
bool subghz_protocol_gate_tx_to_save_file(
SubGhzProtocolGateTX* instance,
FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_gate_tx_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolGateTX* instance,
const char* file_path) {
if(subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format)) {
subghz_protocol_gate_tx_check_remote_controller(instance);
return true;
}
return false;
}
void subghz_decoder_gate_tx_to_load_protocol(SubGhzProtocolGateTX* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_gate_tx_check_remote_controller(instance);
}

View File

@@ -1,75 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolGateTX SubGhzProtocolGateTX;
/** Allocate SubGhzProtocolGateTX
*
* @return SubGhzProtocolGateTX*
*/
SubGhzProtocolGateTX* subghz_protocol_gate_tx_alloc();
/** Free SubGhzProtocolGateTX
*
* @param instance
*/
void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolGateTX instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_gate_tx_send_key(
SubGhzProtocolGateTX* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolGateTX instance
*/
void subghz_protocol_gate_tx_reset(SubGhzProtocolGateTX* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolGateTX instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolFaacSLH* instance
* @param output - output string
*/
void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolGateTX instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_gate_tx_to_save_file(
SubGhzProtocolGateTX* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolGateTX instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_gate_tx_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolGateTX* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolGateTX instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_gate_tx_to_load_protocol(SubGhzProtocolGateTX* instance, void* context);

View File

@@ -1,209 +0,0 @@
#include "subghz_protocol_hormann.h"
#include "subghz_protocol_common.h"
struct SubGhzProtocolHormann {
SubGhzProtocolCommon common;
};
typedef enum {
HormannDecoderStepReset = 0,
HormannDecoderStepFoundStartHeader,
HormannDecoderStepFoundHeader,
HormannDecoderStepFoundStartBit,
HormannDecoderStepSaveDuration,
HormannDecoderStepCheckDuration,
} HormannDecoderStep;
SubGhzProtocolHormann* subghz_protocol_hormann_alloc() {
SubGhzProtocolHormann* instance = malloc(sizeof(SubGhzProtocolHormann));
instance->common.name = "Hormann HSM";
instance->common.code_min_count_bit_for_found = 44;
instance->common.te_short = 511;
instance->common.te_long = 1022;
instance->common.te_delta = 200;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_hormann_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_hormann_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_hormann_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_hormann_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_hormann_send_key;
return instance;
}
void subghz_protocol_hormann_free(SubGhzProtocolHormann* instance) {
furi_assert(instance);
free(instance);
}
bool subghz_protocol_hormann_send_key(
SubGhzProtocolHormann* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = 3 + (instance->common.code_last_count_bit * 2 + 2) * 20 + 1;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 64);
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 64);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 64);
encoder->repeat = 10;
for(size_t repeat = 0; repeat < 20; repeat++) {
//Send start bit
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short * 24);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
}
}
}
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 24);
return true;
}
void subghz_protocol_hormann_reset(SubGhzProtocolHormann* instance) {
instance->common.parser_step = HormannDecoderStepReset;
}
void subghz_protocol_hormann_parse(SubGhzProtocolHormann* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case HormannDecoderStepReset:
if((level) && (DURATION_DIFF(duration, instance->common.te_short * 64) <
instance->common.te_delta * 64)) {
instance->common.parser_step = HormannDecoderStepFoundStartHeader;
}
break;
case HormannDecoderStepFoundStartHeader:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 64) <
instance->common.te_delta * 64)) {
instance->common.parser_step = HormannDecoderStepFoundHeader;
} else {
instance->common.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepFoundHeader:
if((level) && (DURATION_DIFF(duration, instance->common.te_short * 24) <
instance->common.te_delta * 24)) {
instance->common.parser_step = HormannDecoderStepFoundStartBit;
} else {
instance->common.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepFoundStartBit:
if((!level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = HormannDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepSaveDuration:
if(level) { //save interval
if(duration >= (instance->common.te_short * 5)) {
instance->common.parser_step = HormannDecoderStepFoundStartBit;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.serial = 0x0;
instance->common.btn = 0x0;
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
break;
}
instance->common.te_last = duration;
instance->common.parser_step = HormannDecoderStepCheckDuration;
} else {
instance->common.parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = HormannDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = HormannDecoderStepSaveDuration;
} else
instance->common.parser_step = HormannDecoderStepReset;
} else {
instance->common.parser_step = HormannDecoderStepReset;
}
break;
}
}
void subghz_protocol_hormann_to_str(SubGhzProtocolHormann* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
instance->common.btn = (instance->common.code_last_found >> 4) & 0xF;
string_cat_printf(
output,
"%s\r\n"
"%dbit\r\n"
"Key:0x%03lX%08lX\r\n"
"Btn:0x%01X",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
instance->common.btn);
}
bool subghz_protocol_hormann_to_save_file(
SubGhzProtocolHormann* instance,
FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_hormann_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolHormann* instance,
const char* file_path) {
return subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format);
}
void subghz_decoder_hormann_to_load_protocol(SubGhzProtocolHormann* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
}

View File

@@ -1,75 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolHormann SubGhzProtocolHormann;
/** Allocate SubGhzProtocolHormann
*
* @return SubGhzProtocolHormann*
*/
SubGhzProtocolHormann* subghz_protocol_hormann_alloc();
/** Free SubGhzProtocolHormann
*
* @param instance
*/
void subghz_protocol_hormann_free(SubGhzProtocolHormann* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolHormann instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_hormann_send_key(
SubGhzProtocolHormann* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolHormann instance
*/
void subghz_protocol_hormann_reset(SubGhzProtocolHormann* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolHormann instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_hormann_parse(SubGhzProtocolHormann* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolHormann* instance
* @param output - output string
*/
void subghz_protocol_hormann_to_str(SubGhzProtocolHormann* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolHormann instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_hormann_to_save_file(
SubGhzProtocolHormann* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolHormann instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_hormann_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolHormann* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolHormann instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_hormann_to_load_protocol(SubGhzProtocolHormann* instance, void* context);

View File

@@ -1,189 +0,0 @@
#include "subghz_protocol_ido.h"
struct SubGhzProtocolIDo {
SubGhzProtocolCommon common;
};
typedef enum {
IDoDecoderStepReset = 0,
IDoDecoderStepFoundPreambula,
IDoDecoderStepSaveDuration,
IDoDecoderStepCheckDuration,
} IDoDecoderStep;
SubGhzProtocolIDo* subghz_protocol_ido_alloc(void) {
SubGhzProtocolIDo* instance = malloc(sizeof(SubGhzProtocolIDo));
instance->common.name = "iDo 117/111"; // PT4301-X";
instance->common.code_min_count_bit_for_found = 48;
instance->common.te_short = 450;
instance->common.te_long = 1450;
instance->common.te_delta = 150;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_ido_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_ido_to_load_protocol;
return instance;
}
void subghz_protocol_ido_free(SubGhzProtocolIDo* instance) {
furi_assert(instance);
free(instance);
}
/** Send bit
*
* @param instance - SubGhzProtocolIDo instance
* @param bit - bit
*/
void subghz_protocol_ido_send_bit(SubGhzProtocolIDo* instance, uint8_t bit) {
if(bit) {
//send bit 1
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_short);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short);
} else {
//send bit 0
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_short);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long);
}
}
void subghz_protocol_ido_send_key(
SubGhzProtocolIDo* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat) {
while(repeat--) {
SUBGHZ_TX_PIN_HIGH();
//Send header
delay_us(instance->common.te_short * 10);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short * 10);
//Send key data
for(uint8_t i = bit; i > 0; i--) {
subghz_protocol_ido_send_bit(instance, bit_read(key, i - 1));
}
}
}
void subghz_protocol_ido_reset(SubGhzProtocolIDo* instance) {
instance->common.parser_step = IDoDecoderStepReset;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolIDo instance
*/
void subghz_protocol_ido_check_remote_controller(SubGhzProtocolIDo* instance) {
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFF;
instance->common.serial = code_fix & 0xFFFFF;
instance->common.btn = (code_fix >> 20) & 0x0F;
}
void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case IDoDecoderStepReset:
if((level) && (DURATION_DIFF(duration, instance->common.te_short * 10) <
instance->common.te_delta * 5)) {
instance->common.parser_step = IDoDecoderStepFoundPreambula;
}
break;
case IDoDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 10) <
instance->common.te_delta * 5)) {
//Found Preambula
instance->common.parser_step = IDoDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = IDoDecoderStepReset;
}
break;
case IDoDecoderStepSaveDuration:
if(level) {
if(duration >= (instance->common.te_short * 5 + instance->common.te_delta)) {
instance->common.parser_step = IDoDecoderStepFoundPreambula;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
break;
} else {
instance->common.te_last = duration;
instance->common.parser_step = IDoDecoderStepCheckDuration;
}
} else {
instance->common.parser_step = IDoDecoderStepReset;
}
break;
case IDoDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) <
instance->common.te_delta * 3)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = IDoDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta * 3) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = IDoDecoderStepSaveDuration;
} else {
instance->common.parser_step = IDoDecoderStepReset;
}
} else {
instance->common.parser_step = IDoDecoderStepReset;
}
break;
}
}
void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output) {
subghz_protocol_ido_check_remote_controller(instance);
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFF;
uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFFF;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Fix:%06lX \r\n"
"Hop:%06lX \r\n"
"Sn:%05lX Btn:%lX\r\n",
instance->common.name,
instance->common.code_last_count_bit,
(uint32_t)(instance->common.code_last_found >> 32),
(uint32_t)instance->common.code_last_found,
code_fix,
code_hop,
instance->common.serial,
instance->common.btn);
}
void subghz_decoder_ido_to_load_protocol(SubGhzProtocolIDo* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_ido_check_remote_controller(instance);
}

View File

@@ -1,62 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolIDo SubGhzProtocolIDo;
/** Allocate SubGhzProtocolIDo
*
* @return SubGhzProtocolIDo*
*/
SubGhzProtocolIDo* subghz_protocol_ido_alloc();
/** Free SubGhzProtocolIDo
*
* @param instance
*/
void subghz_protocol_ido_free(SubGhzProtocolIDo* instance);
/** Sends the key on the air
*
* @param instance - SubGhzProtocolIDo instance
* @param key - key send
* @param bit - count bit key
* @param repeat - repeat send key
*/
void subghz_protocol_ido_send_key(
SubGhzProtocolIDo* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat);
/** Reset internal state
* @param instance - SubGhzProtocolIDo instance
*/
void subghz_protocol_ido_reset(SubGhzProtocolIDo* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolIDo instance
*/
void subghz_protocol_ido_check_remote_controller(SubGhzProtocolIDo* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolIDo instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolIDo* instance
* @param output - output string
*/
void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolIDo instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_ido_to_load_protocol(SubGhzProtocolIDo* instance, void* context);

View File

@@ -1,493 +0,0 @@
#include "subghz_protocol_keeloq.h"
#include "subghz_protocol_keeloq_common.h"
#include "../subghz_keystore.h"
#include <furi.h>
#include <m-string.h>
struct SubGhzProtocolKeeloq {
SubGhzProtocolCommon common;
SubGhzKeystore* keystore;
const char* manufacture_name;
};
typedef enum {
KeeloqDecoderStepReset = 0,
KeeloqDecoderStepCheckPreambula,
KeeloqDecoderStepSaveDuration,
KeeloqDecoderStepCheckDuration,
} KeeloqDecoderStep;
SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) {
SubGhzProtocolKeeloq* instance = malloc(sizeof(SubGhzProtocolKeeloq));
instance->keystore = keystore;
instance->common.name = "KeeLoq";
instance->common.code_min_count_bit_for_found = 64;
instance->common.te_short = 400;
instance->common.te_long = 800;
instance->common.te_delta = 140;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_keeloq_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_keeloq_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_keeloq_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_keeloq_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_keeloq_send_key;
return instance;
}
void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance) {
furi_assert(instance);
free(instance);
}
static inline bool subghz_protocol_keeloq_check_decrypt(
SubGhzProtocolKeeloq* instance,
uint32_t decrypt,
uint8_t btn,
uint32_t end_serial) {
furi_assert(instance);
if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) ||
((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) {
instance->common.cnt = decrypt & 0x0000FFFF;
return true;
}
return false;
}
/** Checking the accepted code against the database manafacture key
*
* @param instance SubGhzProtocolKeeloq instance
* @param fix fix part of the parcel
* @param hop hop encrypted part of the parcel
* @return true on successful search
*/
uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
SubGhzProtocolKeeloq* instance,
uint32_t fix,
uint32_t hop) {
// protocol HCS300 uses 10 bits in discriminator, HCS200 uses 8 bits, for backward compatibility, we are looking for the 8-bit pattern
// HCS300 -> uint16_t end_serial = (uint16_t)(fix & 0x3FF);
// HCS200 -> uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint8_t btn = (uint8_t)(fix >> 28);
uint32_t decrypt = 0;
uint64_t man_learning;
uint32_t seed = 0;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_SECURE:
man_learning = subghz_protocol_keeloq_common_secure_learning(
fix, seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
man_learning = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
man_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Secure Learning
man_learning = subghz_protocol_keeloq_common_secure_learning(
fix, seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
man_learning = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Magic xor type1 learning
man_learning = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
// Check for mirrored man
man_learning =
subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1;
}
break;
}
}
instance->manufacture_name = "Unknown";
instance->common.cnt = 0;
return 0;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolKeeloq instance
*/
void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instance) {
uint64_t key = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff;
// Check key AN-Motors
if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) &&
(key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) {
instance->manufacture_name = "AN-Motors";
instance->common.cnt = key_hop >> 16;
} else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) {
instance->manufacture_name = "HCS101";
instance->common.cnt = key_hop >> 16;
} else {
subghz_protocol_keeloq_check_remote_controller_selector(instance, key_fix, key_hop);
}
instance->common.serial = key_fix & 0x0FFFFFFF;
instance->common.btn = key_fix >> 28;
}
const char* subghz_protocol_keeloq_find_and_get_manufacture_name(void* context) {
SubGhzProtocolKeeloq* instance = context;
subghz_protocol_keeloq_check_remote_controller(instance);
return instance->manufacture_name;
}
const char* subghz_protocol_keeloq_get_manufacture_name(void* context) {
SubGhzProtocolKeeloq* instance = context;
return instance->manufacture_name;
}
bool subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name) {
SubGhzProtocolKeeloq* instance = context;
instance->manufacture_name = manufacture_name;
int res = 0;
for
M_EACH(
manufacture_code,
*subghz_keystore_get_data(instance->keystore),
SubGhzKeyArray_t) {
res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) return true;
}
instance->manufacture_name = "Unknown";
return false;
}
uint64_t subghz_protocol_keeloq_gen_key(void* context) {
SubGhzProtocolKeeloq* instance = context;
uint32_t fix = instance->common.btn << 28 | instance->common.serial;
uint32_t decrypt = instance->common.btn << 28 | (instance->common.serial & 0x3FF) << 16 |
instance->common.cnt;
uint32_t hop = 0;
uint64_t man_learning = 0;
int res = 0;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Simple Learning
man_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man_learning);
break;
case KEELOQ_LEARNING_UNKNOWN:
hop = 0; //todo
break;
}
break;
}
}
uint64_t yek = (uint64_t)fix << 32 | hop;
return subghz_protocol_common_reverse_key(yek, instance->common.code_last_count_bit);
}
bool subghz_protocol_keeloq_send_key(
SubGhzProtocolKeeloq* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
//gen new key
instance->common.cnt++;
instance->common.code_last_found = subghz_protocol_keeloq_gen_key(instance);
if(instance->common.callback)
instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
if(!strcmp(instance->manufacture_name, "Unknown")) {
return false;
}
size_t index = 0;
encoder->size_upload = 11 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 4;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
for(uint8_t i = 11; i > 0; i--) {
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
}
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 10);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
}
}
// +send 2 status bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_long);
//encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long);
//encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
// send end
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 40);
return true;
}
void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance) {
instance->common.parser_step = KeeloqDecoderStepReset;
}
void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case KeeloqDecoderStepReset:
if((level) &&
DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
instance->common.parser_step = KeeloqDecoderStepCheckPreambula;
instance->common.header_count++;
}
break;
case KeeloqDecoderStepCheckPreambula:
if((!level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = KeeloqDecoderStepReset;
break;
}
if((instance->common.header_count > 2) &&
(DURATION_DIFF(duration, instance->common.te_short * 10) <
instance->common.te_delta * 10)) {
// Found header
instance->common.parser_step = KeeloqDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = KeeloqDecoderStepReset;
instance->common.header_count = 0;
}
break;
case KeeloqDecoderStepSaveDuration:
if(level) {
instance->common.te_last = duration;
instance->common.parser_step = KeeloqDecoderStepCheckDuration;
}
break;
case KeeloqDecoderStepCheckDuration:
if(!level) {
if(duration >= (instance->common.te_short * 2 + instance->common.te_delta)) {
// Found end TX
instance->common.parser_step = KeeloqDecoderStepReset;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
if(instance->common.code_last_found != instance->common.code_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->common.header_count = 0;
}
break;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
if(instance->common.code_count_bit <
instance->common.code_min_count_bit_for_found) {
subghz_protocol_common_add_bit(&instance->common, 1);
}
instance->common.parser_step = KeeloqDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
if(instance->common.code_count_bit <
instance->common.code_min_count_bit_for_found) {
subghz_protocol_common_add_bit(&instance->common, 0);
}
instance->common.parser_step = KeeloqDecoderStepSaveDuration;
} else {
instance->common.parser_step = KeeloqDecoderStepReset;
instance->common.header_count = 0;
}
} else {
instance->common.parser_step = KeeloqDecoderStepReset;
instance->common.header_count = 0;
}
break;
}
}
void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output) {
subghz_protocol_keeloq_check_remote_controller(instance);
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%02lX\r\n"
"MF:%s\r\n"
"Sn:0x%07lX \r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
instance->common.cnt,
code_found_reverse_lo,
instance->common.btn,
instance->manufacture_name,
instance->common.serial);
}
bool subghz_protocol_keeloq_to_save_file(
SubGhzProtocolKeeloq* instance,
FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_keeloq_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolKeeloq* instance,
const char* file_path) {
return subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format);
}
void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_keeloq_check_remote_controller(instance);
}

View File

@@ -1,106 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzKeystore SubGhzKeystore;
typedef struct SubGhzProtocolKeeloq SubGhzProtocolKeeloq;
/** Allocate SubGhzProtocolKeeloq
*
* @return SubGhzProtocolKeeloq*
*/
SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore);
/** Free SubGhzProtocolKeeloq
*
* @param instance
*/
void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance);
/** Find and get manufacture name
*
* @param context - SubGhzProtocolKeeloq context
* @return name - char* manufacture name
*/
const char* subghz_protocol_keeloq_find_and_get_manufacture_name(void* context);
/** Get manufacture name
*
* @param context - SubGhzProtocolKeeloq context
* @return name - char* manufacture name
*/
const char* subghz_protocol_keeloq_get_manufacture_name(void* context);
/** Set manufacture name
*
* @param manufacture_name - manufacture name
* @param context - SubGhzProtocolKeeloq context
* @return bool
*/
bool subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name);
/** Get key keeloq
*
* @param context - SubGhzProtocolKeeloq context
* @return key
*/
uint64_t subghz_protocol_keeloq_gen_key(void* context);
/** Get upload protocol
*
* @param instance - SubGhzProtocolKeeloq instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_keeloq_send_key(
SubGhzProtocolKeeloq* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolKeeloq instance
*/
void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolKeeloq instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolKeeloq* instance
* @param output - output string
*/
void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolKeeloq instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_keeloq_to_save_file(
SubGhzProtocolKeeloq* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolKeeloq instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_keeloq_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolKeeloq* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolKeeloq instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context);

View File

@@ -1,188 +0,0 @@
#include "subghz_protocol_kia.h"
struct SubGhzProtocolKIA {
SubGhzProtocolCommon common;
};
typedef enum {
KIADecoderStepReset = 0,
KIADecoderStepCheckPreambula,
KIADecoderStepSaveDuration,
KIADecoderStepCheckDuration,
} KIADecoderStep;
SubGhzProtocolKIA* subghz_protocol_kia_alloc(void) {
SubGhzProtocolKIA* instance = malloc(sizeof(SubGhzProtocolKIA));
instance->common.name = "KIA";
instance->common.code_min_count_bit_for_found = 60;
instance->common.te_short = 250;
instance->common.te_long = 500;
instance->common.te_delta = 100;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_kia_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_kia_to_load_protocol;
return instance;
}
void subghz_protocol_kia_free(SubGhzProtocolKIA* instance) {
furi_assert(instance);
free(instance);
}
void subghz_protocol_kia_reset(SubGhzProtocolKIA* instance) {
instance->common.parser_step = KIADecoderStepReset;
}
uint8_t subghz_protocol_kia_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) ^ 0x7F);
else
crc <<= 1;
}
}
return crc;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolKIA instance
*/
void subghz_protocol_kia_check_remote_controller(SubGhzProtocolKIA* instance) {
/*
* 0x0F 0112 43B04EC 1 7D
* 0x0F 0113 43B04EC 1 DF
* 0x0F 0114 43B04EC 1 30
* 0x0F 0115 43B04EC 2 13
* 0x0F 0116 43B04EC 3 F5
* CNT Serial K CRC8 Kia (CRC8, poly 0x7f, start_crc 0x08)
*/
instance->common.serial = (uint32_t)((instance->common.code_last_found >> 12) & 0x0FFFFFFF);
instance->common.btn = (instance->common.code_last_found >> 8) & 0x0F;
instance->common.cnt = (instance->common.code_last_found >> 40) & 0xFFFF;
}
void subghz_protocol_kia_parse(SubGhzProtocolKIA* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case KIADecoderStepReset:
if((!level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = KIADecoderStepCheckPreambula;
instance->common.te_last = duration;
instance->common.header_count = 0;
}
break;
case KIADecoderStepCheckPreambula:
if(!level) {
if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) ||
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
instance->common.te_last = duration;
} else {
instance->common.parser_step = KIADecoderStepReset;
}
} else if(
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) &&
(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta)) {
// Found header
instance->common.header_count++;
break;
} else if(
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) &&
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta)) {
// Found start bit
if(instance->common.header_count > 15) {
instance->common.parser_step = KIADecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 1;
subghz_protocol_common_add_bit(&instance->common, 1);
} else {
instance->common.parser_step = KIADecoderStepReset;
}
} else {
instance->common.parser_step = KIADecoderStepReset;
}
break;
case KIADecoderStepSaveDuration:
if(!level) {
if(duration >= (instance->common.te_long + instance->common.te_delta * 2)) {
//Found stop bit
instance->common.parser_step = KIADecoderStepReset;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
break;
} else {
instance->common.te_last = duration;
instance->common.parser_step = KIADecoderStepCheckDuration;
}
} else {
instance->common.parser_step = KIADecoderStepReset;
}
break;
case KIADecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = KIADecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = KIADecoderStepSaveDuration;
} else {
instance->common.parser_step = KIADecoderStepReset;
}
} else {
instance->common.parser_step = KIADecoderStepReset;
}
break;
}
}
void subghz_protocol_kia_to_str(SubGhzProtocolKIA* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Sn:%07lX Btn:%lX Cnt:%04X\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
instance->common.serial,
instance->common.btn,
instance->common.cnt);
}
void subghz_decoder_kia_to_load_protocol(SubGhzProtocolKIA* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_kia_check_remote_controller(instance);
}

View File

@@ -1,56 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolKIA SubGhzProtocolKIA;
/** Allocate SubGhzProtocolKIA
*
* @return SubGhzProtocolKIA*
*/
SubGhzProtocolKIA* subghz_protocol_kia_alloc();
/** Free SubGhzProtocolKIA
*
* @param instance
*/
void subghz_protocol_kia_free(SubGhzProtocolKIA* instance);
/** Reset internal state
* @param instance - SubGhzProtocolKIA instance
*/
void subghz_protocol_kia_reset(SubGhzProtocolKIA* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolKIA instance
*/
void subghz_protocol_kia_check_remote_controller(SubGhzProtocolKIA* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolKIA instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_kia_parse(SubGhzProtocolKIA* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolKIA* instance
* @param output - output string
*/
void subghz_protocol_kia_to_str(SubGhzProtocolKIA* instance, string_t output);
/** Get a string to save the protocol
*
* @param instance - SubGhzProtocolKIA instance
* @param output - the resulting string
*/
void subghz_protocol_kia_to_save_str(SubGhzProtocolKIA* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolKIA instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_kia_to_load_protocol(SubGhzProtocolKIA* instance, void* context);

View File

@@ -1,232 +0,0 @@
#include "subghz_protocol_nero_radio.h"
struct SubGhzProtocolNeroRadio {
SubGhzProtocolCommon common;
};
typedef enum {
NeroRadioDecoderStepReset = 0,
NeroRadioDecoderStepCheckPreambula,
NeroRadioDecoderStepSaveDuration,
NeroRadioDecoderStepCheckDuration,
} NeroRadioDecoderStep;
SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(void) {
SubGhzProtocolNeroRadio* instance = malloc(sizeof(SubGhzProtocolNeroRadio));
instance->common.name = "Nero Radio";
instance->common.code_min_count_bit_for_found = 55;
instance->common.te_short = 200;
instance->common.te_long = 400;
instance->common.te_delta = 80;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_radio_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_nero_radio_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_radio_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_radio_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nero_radio_send_key;
return instance;
}
void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance) {
furi_assert(instance);
free(instance);
}
bool subghz_protocol_nero_radio_send_key(
SubGhzProtocolNeroRadio* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = 2 + 47 * 2 + 2 + (instance->common.code_last_count_bit * 2);
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 37);
for(uint8_t i = 0; i < 47; i++) {
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
}
//Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 4);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
}
}
return true;
}
void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance) {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
void subghz_protocol_nero_radio_parse(
SubGhzProtocolNeroRadio* instance,
bool level,
uint32_t duration) {
switch(instance->common.parser_step) {
case NeroRadioDecoderStepReset:
if((level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = NeroRadioDecoderStepCheckPreambula;
instance->common.te_last = duration;
instance->common.header_count = 0;
}
break;
case NeroRadioDecoderStepCheckPreambula:
if(level) {
if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) ||
(DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta)) {
instance->common.te_last = duration;
} else {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
} else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) {
// Found header
instance->common.header_count++;
break;
} else if(
DURATION_DIFF(instance->common.te_last, instance->common.te_short * 4) <
instance->common.te_delta) {
// Found start bit
if(instance->common.header_count > 40) {
instance->common.parser_step = NeroRadioDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
} else {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
} else {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
break;
case NeroRadioDecoderStepSaveDuration:
if(level) {
instance->common.te_last = duration;
instance->common.parser_step = NeroRadioDecoderStepCheckDuration;
} else {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
break;
case NeroRadioDecoderStepCheckDuration:
if(!level) {
if(duration >= (instance->common.te_short * 10 + instance->common.te_delta * 2)) {
//Found stop bit
if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) {
subghz_protocol_common_add_bit(&instance->common, 0);
} else if(
DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) {
subghz_protocol_common_add_bit(&instance->common, 1);
}
instance->common.parser_step = NeroRadioDecoderStepReset;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->common.parser_step = NeroRadioDecoderStepReset;
break;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = NeroRadioDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = NeroRadioDecoderStepSaveDuration;
} else {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
} else {
instance->common.parser_step = NeroRadioDecoderStepReset;
}
break;
}
}
void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Yek:0x%lX%08lX\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
code_found_reverse_lo);
}
bool subghz_protocol_nero_radio_to_save_file(
SubGhzProtocolNeroRadio* instance,
FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_nero_radio_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolNeroRadio* instance,
const char* file_path) {
return subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format);
}
void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
}

View File

@@ -1,84 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolNeroRadio SubGhzProtocolNeroRadio;
/** Allocate SubGhzProtocolNeroRadio
*
* @return SubGhzProtocolNeroRadio*
*/
SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc();
/** Free SubGhzProtocolNeroRadio
*
* @param instance
*/
void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_nero_radio_send_key(
SubGhzProtocolNeroRadio* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolNeroRadio instance
*/
void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolNeroRadio instance
*/
void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_nero_radio_parse(
SubGhzProtocolNeroRadio* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolNeroRadio* instance
* @param output - output string
*/
void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_nero_radio_to_save_file(
SubGhzProtocolNeroRadio* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolNeroRadio instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_nero_radio_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolNeroRadio* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context);

View File

@@ -1,225 +0,0 @@
#include "subghz_protocol_nero_sketch.h"
struct SubGhzProtocolNeroSketch {
SubGhzProtocolCommon common;
};
typedef enum {
NeroSketchDecoderStepReset = 0,
NeroSketchDecoderStepCheckPreambula,
NeroSketchDecoderStepSaveDuration,
NeroSketchDecoderStepCheckDuration,
} NeroSketchDecoderStep;
SubGhzProtocolNeroSketch* subghz_protocol_nero_sketch_alloc(void) {
SubGhzProtocolNeroSketch* instance = malloc(sizeof(SubGhzProtocolNeroSketch));
instance->common.name = "Nero Sketch";
instance->common.code_min_count_bit_for_found = 40;
instance->common.te_short = 330;
instance->common.te_long = 660;
instance->common.te_delta = 150;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_sketch_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_nero_sketch_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_sketch_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_sketch_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nero_sketch_send_key;
return instance;
}
void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance) {
furi_assert(instance);
free(instance);
}
bool subghz_protocol_nero_sketch_send_key(
SubGhzProtocolNeroSketch* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = 47 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
for(uint8_t i = 0; i < 47; i++) {
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
}
//Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 4);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
}
}
//Send stop bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 3);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
return true;
}
void subghz_protocol_nero_sketch_reset(SubGhzProtocolNeroSketch* instance) {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
void subghz_protocol_nero_sketch_parse(
SubGhzProtocolNeroSketch* instance,
bool level,
uint32_t duration) {
switch(instance->common.parser_step) {
case NeroSketchDecoderStepReset:
if((level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = NeroSketchDecoderStepCheckPreambula;
instance->common.te_last = duration;
instance->common.header_count = 0;
}
break;
case NeroSketchDecoderStepCheckPreambula:
if(level) {
if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) ||
(DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta)) {
instance->common.te_last = duration;
} else {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
} else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) {
// Found header
instance->common.header_count++;
break;
} else if(
DURATION_DIFF(instance->common.te_last, instance->common.te_short * 4) <
instance->common.te_delta) {
// Found start bit
if(instance->common.header_count > 40) {
instance->common.parser_step = NeroSketchDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
} else {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
} else {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
break;
case NeroSketchDecoderStepSaveDuration:
if(level) {
if(duration >= (instance->common.te_short * 2 + instance->common.te_delta * 2)) {
//Found stop bit
instance->common.parser_step = NeroSketchDecoderStepReset;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
break;
} else {
instance->common.te_last = duration;
instance->common.parser_step = NeroSketchDecoderStepCheckDuration;
}
} else {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
break;
case NeroSketchDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = NeroSketchDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = NeroSketchDecoderStepSaveDuration;
} else {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
} else {
instance->common.parser_step = NeroSketchDecoderStepReset;
}
break;
}
}
void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Yek:0x%lX%08lX\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
code_found_reverse_lo);
}
bool subghz_protocol_nero_sketch_to_save_file(
SubGhzProtocolNeroSketch* instance,
FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_nero_sketch_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolNeroSketch* instance,
const char* file_path) {
return subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format);
}
void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
}

View File

@@ -1,84 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolNeroSketch SubGhzProtocolNeroSketch;
/** Allocate SubGhzProtocolNeroSketch
*
* @return SubGhzProtocolNeroSketch*
*/
SubGhzProtocolNeroSketch* subghz_protocol_nero_sketch_alloc();
/** Free SubGhzProtocolNeroSketch
*
* @param instance
*/
void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolNeroSketch instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_nero_sketch_send_key(
SubGhzProtocolNeroSketch* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolNeroSketch instance
*/
void subghz_protocol_nero_sketch_reset(SubGhzProtocolNeroSketch* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolNeroSketch instance
*/
void subghz_protocol_nero_sketch_check_remote_controller(SubGhzProtocolNeroSketch* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolNeroSketch instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_nero_sketch_parse(
SubGhzProtocolNeroSketch* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolNeroSketch* instance
* @param output - output string
*/
void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolNeroSketch instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_nero_sketch_to_save_file(
SubGhzProtocolNeroSketch* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolNeroSketch instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_nero_sketch_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolNeroSketch* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolNeroSketch instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context);

View File

@@ -1,189 +0,0 @@
#include "subghz_protocol_nice_flo.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
struct SubGhzProtocolNiceFlo {
SubGhzProtocolCommon common;
};
typedef enum {
NiceFloDecoderStepReset = 0,
NiceFloDecoderStepFoundStartBit,
NiceFloDecoderStepSaveDuration,
NiceFloDecoderStepCheckDuration,
} NiceFloDecoderStep;
SubGhzProtocolNiceFlo* subghz_protocol_nice_flo_alloc() {
SubGhzProtocolNiceFlo* instance = malloc(sizeof(SubGhzProtocolNiceFlo));
instance->common.name = "Nice FLO";
instance->common.code_min_count_bit_for_found = 12;
instance->common.te_short = 700;
instance->common.te_long = 1400;
instance->common.te_delta = 200;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flo_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_protocol_nice_flo_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_nice_flo_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flo_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nice_flo_send_key;
return instance;
}
void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance) {
furi_assert(instance);
free(instance);
}
bool subghz_protocol_nice_flo_send_key(
SubGhzProtocolNiceFlo* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 36);
//Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
}
}
return true;
}
void subghz_protocol_nice_flo_reset(SubGhzProtocolNiceFlo* instance) {
instance->common.parser_step = NiceFloDecoderStepReset;
}
void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) {
case NiceFloDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 36) <
instance->common.te_delta * 36)) {
//Found header Nice Flo
instance->common.parser_step = NiceFloDecoderStepFoundStartBit;
}
break;
case NiceFloDecoderStepFoundStartBit:
if(!level) {
break;
} else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
//Found start bit Nice Flo
instance->common.parser_step = NiceFloDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = NiceFloDecoderStepReset;
}
break;
case NiceFloDecoderStepSaveDuration:
if(!level) { //save interval
if(duration >= (instance->common.te_short * 4)) {
instance->common.parser_step = NiceFloDecoderStepFoundStartBit;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.serial = 0x0;
instance->common.btn = 0x0;
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
break;
}
instance->common.te_last = duration;
instance->common.parser_step = NiceFloDecoderStepCheckDuration;
} else {
instance->common.parser_step = NiceFloDecoderStepReset;
}
break;
case NiceFloDecoderStepCheckDuration:
if(level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = NiceFloDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = NiceFloDecoderStepSaveDuration;
} else
instance->common.parser_step = NiceFloDecoderStepReset;
} else {
instance->common.parser_step = NiceFloDecoderStepReset;
}
break;
}
}
void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t output) {
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_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",
instance->common.name,
instance->common.code_last_count_bit,
code_found_lo,
code_found_reverse_lo);
}
bool subghz_protocol_nice_flo_to_save_file(
SubGhzProtocolNiceFlo* instance,
FlipperFormat* flipper_format) {
return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
}
bool subghz_protocol_nice_flo_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolNiceFlo* instance,
const char* file_path) {
return subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format);
}
void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
instance->common.serial = 0x0;
instance->common.btn = 0x0;
}

View File

@@ -1,75 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolNiceFlo SubGhzProtocolNiceFlo;
/** Allocate SubGhzProtocolNiceFlo
*
* @return SubGhzProtocolNiceFlo*
*/
SubGhzProtocolNiceFlo* subghz_protocol_nice_flo_alloc();
/** Free SubGhzProtocolNiceFlo
*
* @param instance
*/
void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolNiceFlo instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_nice_flo_send_key(
SubGhzProtocolNiceFlo* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolNiceFlo instance
*/
void subghz_protocol_nice_flo_reset(SubGhzProtocolNiceFlo* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolNiceFlo instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolNiceFlo* instance
* @param output - output string
*/
void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzProtocolNiceFlo instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_protocol_nice_flo_to_save_file(
SubGhzProtocolNiceFlo* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzProtocolNiceFlo instance
* @param file_path - file path
* @return bool
*/
bool subghz_protocol_nice_flo_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolNiceFlo* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolNiceFlo instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, void* context);

View File

@@ -1,264 +0,0 @@
#include "subghz_protocol_nice_flor_s.h"
#include <furi.h>
#include "file_worker.h"
#include "../subghz_keystore.h"
/*
* https://phreakerclub.com/1615
* https://phreakerclub.com/forum/showthread.php?t=2360
* https://vrtp.ru/index.php?showtopic=27867
*/
#define TAG "SubGhzNiceFlorS"
struct SubGhzProtocolNiceFlorS {
SubGhzProtocolCommon common;
const char* rainbow_table_file_name;
};
typedef enum {
NiceFlorSDecoderStepReset = 0,
NiceFlorSDecoderStepCheckHeader,
NiceFlorSDecoderStepFoundHeader,
NiceFlorSDecoderStepSaveDuration,
NiceFlorSDecoderStepCheckDuration,
} NiceFlorSDecoderStep;
SubGhzProtocolNiceFlorS* subghz_protocol_nice_flor_s_alloc() {
SubGhzProtocolNiceFlorS* instance = malloc(sizeof(SubGhzProtocolNiceFlorS));
instance->common.name = "Nice FloR-S";
instance->common.code_min_count_bit_for_found = 52;
instance->common.te_short = 500;
instance->common.te_long = 1000;
instance->common.te_delta = 300;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flor_s_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flor_s_to_load_protocol;
return instance;
}
void subghz_protocol_nice_flor_s_free(SubGhzProtocolNiceFlorS* instance) {
furi_assert(instance);
free(instance);
}
void subghz_protocol_nice_flor_s_name_file(SubGhzProtocolNiceFlorS* instance, const char* name) {
instance->rainbow_table_file_name = name;
FURI_LOG_I(TAG, "Loading rainbow table from %s", name);
}
/** Send bit
*
* @param instance - SubGhzProtocolNiceFlorS instance
* @param bit - bit
*/
void subghz_protocol_nice_flor_s_send_bit(SubGhzProtocolNiceFlorS* instance, uint8_t bit) {
if(bit) {
//send bit 1
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_long);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short);
} else {
//send bit 0
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_short);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long);
}
}
void subghz_protocol_nice_flor_s_send_key(
SubGhzProtocolNiceFlorS* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat) {
while(repeat--) {
//Send header
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short * 34);
//Send Start Bit
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_short * 3);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short * 3);
//Send key data
for(uint8_t i = bit; i > 0; i--) {
subghz_protocol_nice_flor_s_send_bit(instance, bit_read(key, i - 1));
}
//Send Stop Bit
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_short * 3);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short * 3);
}
}
/** Read bytes from rainbow table
*
* @param instance - SubGhzProtocolNiceFlorS* instance
* @param address - address byte
* @return byte data
*/
uint8_t subghz_nice_flor_s_get_byte_in_file(SubGhzProtocolNiceFlorS* instance, uint32_t address) {
if(!instance->rainbow_table_file_name) return 0;
uint8_t buffer[1] = {0};
if(subghz_keystore_raw_get_data(
instance->rainbow_table_file_name, address, buffer, sizeof(uint8_t))) {
return buffer[0];
} else {
return 0;
}
}
/** Decrypt protocol Nice Flor S
*
* @param instance - SubGhzProtocolNiceFlorS* instance
*/
void subghz_nice_flor_s_decoder_decrypt(SubGhzProtocolNiceFlorS* instance) {
/*
* Packet format Nice Flor-s: START-P0-P1-P2-P3-P4-P5-P6-P7-STOP
* P0 (4-bit) - button positional code - 1:0x1, 2:0x2, 3:0x4, 4:0x8;
* P1 (4-bit) - batch repetition number, calculated by the formula:
* P1 = 0xF ^ P0 ^ n; where n changes from 1 to 15, then 0, and then in a circle
* key 1: {0xF,0xC,0xD,0xA,0xB,0x8,0x9,0x6,0x7,0x4,0x5,0x2,0x3,0x0,0x1,0xE};
* key 2: {0xC,0xF,0xE,0x9,0x8,0xB,0xA,0x5,0x4,0x7,0x6,0x1,0x0,0x3,0x2,0xD};
* key 3: {0xA,0x9,0x8,0xF,0xE,0xD,0xC,0x3,0x2,0x1,0x0,0x7,0x6,0x5,0x4,0xB};
* P2 (4-bit) - part of the serial number, P2 = (K ^ S3) & 0xF;
* P3 (byte) - the major part of the encrypted index
* P4 (byte) - the low-order part of the encrypted index
* P5 (byte) - part of the serial number, P5 = K ^ S2;
* P6 (byte) - part of the serial number, P6 = K ^ S1;
* P7 (byte) - part of the serial number, P7 = K ^ S0;
* K (byte) - depends on P3 and P4, K = Fk(P3, P4);
* S3,S2,S1,S0 - serial number of the console 28 bit.
*/
uint16_t p3p4 = (uint16_t)(instance->common.code_last_found >> 24);
instance->common.cnt = subghz_nice_flor_s_get_byte_in_file(instance, p3p4 * 2) << 8 |
subghz_nice_flor_s_get_byte_in_file(instance, p3p4 * 2 + 1);
uint8_t k =
(uint8_t)(p3p4 & 0x00FF) ^
subghz_nice_flor_s_get_byte_in_file(instance, (0x20000 | (instance->common.cnt & 0x00ff)));
uint8_t s3 = ((uint8_t)(instance->common.code_last_found >> 40) ^ k) & 0x0f;
uint8_t s2 = ((uint8_t)(instance->common.code_last_found >> 16) ^ k);
uint8_t s1 = ((uint8_t)(instance->common.code_last_found >> 8) ^ k);
uint8_t s0 = ((uint8_t)(instance->common.code_last_found) ^ k);
instance->common.serial = s3 << 24 | s2 << 16 | s1 << 8 | s0;
instance->common.btn = (instance->common.code_last_found >> 48) & 0x0f;
}
void subghz_protocol_nice_flor_s_reset(SubGhzProtocolNiceFlorS* instance) {
instance->common.parser_step = NiceFlorSDecoderStepReset;
}
void subghz_protocol_nice_flor_s_parse(
SubGhzProtocolNiceFlorS* instance,
bool level,
uint32_t duration) {
switch(instance->common.parser_step) {
case NiceFlorSDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 38) <
instance->common.te_delta * 38)) {
//Found start header Nice Flor-S
instance->common.parser_step = NiceFlorSDecoderStepCheckHeader;
}
break;
case NiceFlorSDecoderStepCheckHeader:
if((level) && (DURATION_DIFF(duration, instance->common.te_short * 3) <
instance->common.te_delta * 3)) {
//Found next header Nice Flor-S
instance->common.parser_step = NiceFlorSDecoderStepFoundHeader;
} else {
instance->common.parser_step = NiceFlorSDecoderStepReset;
}
break;
case NiceFlorSDecoderStepFoundHeader:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 3) <
instance->common.te_delta * 3)) {
//Found header Nice Flor-S
instance->common.parser_step = NiceFlorSDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = NiceFlorSDecoderStepReset;
}
break;
case NiceFlorSDecoderStepSaveDuration:
if(level) {
if(DURATION_DIFF(duration, instance->common.te_short * 3) <
instance->common.te_delta) {
//Found STOP bit
instance->common.parser_step = NiceFlorSDecoderStepReset;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
break;
} else {
//save interval
instance->common.te_last = duration;
instance->common.parser_step = NiceFlorSDecoderStepCheckDuration;
}
}
break;
case NiceFlorSDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = NiceFlorSDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = NiceFlorSDecoderStepSaveDuration;
} else
instance->common.parser_step = NiceFlorSDecoderStepReset;
} else {
instance->common.parser_step = NiceFlorSDecoderStepReset;
}
break;
}
}
void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, string_t output) {
subghz_nice_flor_s_decoder_decrypt(instance);
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:%05lX\r\n"
"Cnt:%04X Btn:%02lX\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
instance->common.serial,
instance->common.cnt,
instance->common.btn);
}
void subghz_decoder_nice_flor_s_to_load_protocol(SubGhzProtocolNiceFlorS* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_nice_flor_s_decoder_decrypt(instance);
}

View File

@@ -1,66 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolNiceFlorS SubGhzProtocolNiceFlorS;
/** Allocate SubGhzProtocolNiceFlorS
*
* @return SubGhzProtocolNiceFlorS*
*/
SubGhzProtocolNiceFlorS* subghz_protocol_nice_flor_s_alloc();
/** Free SubGhzProtocolNiceFlorS
*
* @param instance
*/
void subghz_protocol_nice_flor_s_free(SubGhzProtocolNiceFlorS* instance);
/** File name rainbow table Nice Flor-S
*
* @param instance - SubGhzProtocolNiceFlorS instance
* @param file_name - "path/file_name"
*/
void subghz_protocol_nice_flor_s_name_file(SubGhzProtocolNiceFlorS* instance, const char* name);
/** Sends the key on the air
*
* @param instance - SubGhzProtocolNiceFlorS instance
* @param key - key send
* @param bit - count bit key
* @param repeat - repeat send key
*/
void subghz_protocol_nice_flor_s_send_key(
SubGhzProtocolNiceFlorS* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat);
/** Reset internal state
* @param instance - SubGhzProtocolNiceFlorS instance
*/
void subghz_protocol_nice_flor_s_reset(SubGhzProtocolNiceFlorS* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolNiceFlorS instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_nice_flor_s_parse(
SubGhzProtocolNiceFlorS* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolNiceFlorS* instance
* @param output - output string
*/
void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolNiceFlorS instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_nice_flor_s_to_load_protocol(SubGhzProtocolNiceFlorS* instance, void* context);

View File

@@ -1,368 +0,0 @@
#include "subghz_protocol_princeton.h"
/*
* Help
* https://phreakerclub.com/447
*
*/
#define SUBGHZ_PT_SHORT 300
#define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3)
#define SUBGHZ_PT_GUARD (SUBGHZ_PT_SHORT * 30)
#define SUBGHZ_PT_COUNT_KEY_433 9
#define SUBGHZ_PT_TIMEOUT_433 900
#define SUBGHZ_PT_COUNT_KEY_868 9
#define SUBGHZ_PT_TIMEOUT_868 14000
#define TAG "SubghzPrinceton"
struct SubGhzEncoderPrinceton {
uint32_t key;
uint16_t te;
size_t repeat;
size_t front;
size_t count_key;
size_t count_key_package;
uint32_t time_high;
uint32_t time_low;
uint32_t timeout;
uint32_t time_stop;
};
typedef enum {
PrincetonDecoderStepReset = 0,
PrincetonDecoderStepSaveDuration,
PrincetonDecoderStepCheckDuration,
} PrincetonDecoderStep;
SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc() {
SubGhzEncoderPrinceton* instance = malloc(sizeof(SubGhzEncoderPrinceton));
return instance;
}
void subghz_encoder_princeton_free(SubGhzEncoderPrinceton* instance) {
furi_assert(instance);
free(instance);
}
void subghz_encoder_princeton_set_te(SubGhzEncoderPrinceton* instance, void* decoder) {
SubGhzDecoderPrinceton* pricenton = decoder;
if((pricenton->te) != 0) {
instance->te = pricenton->te;
} else {
instance->te = SUBGHZ_PT_SHORT;
}
}
void subghz_encoder_princeton_stop(SubGhzEncoderPrinceton* instance, uint32_t time_stop) {
instance->time_stop = time_stop;
}
void subghz_encoder_princeton_set(
SubGhzEncoderPrinceton* instance,
uint32_t key,
size_t repeat,
uint32_t frequency) {
furi_assert(instance);
instance->te = SUBGHZ_PT_SHORT;
instance->key = key;
instance->repeat = repeat + 1;
instance->front = 48;
instance->time_high = 0;
instance->time_low = 0;
if(frequency < 700000000) {
instance->count_key_package = SUBGHZ_PT_COUNT_KEY_433;
instance->timeout = SUBGHZ_PT_TIMEOUT_433;
} else {
instance->count_key_package = SUBGHZ_PT_COUNT_KEY_868;
instance->timeout = SUBGHZ_PT_TIMEOUT_868;
}
instance->count_key = instance->count_key_package + 3;
if((millis() - instance->time_stop) < instance->timeout) {
instance->time_stop = (instance->timeout - (millis() - instance->time_stop)) * 1000;
} else {
instance->time_stop = 0;
}
}
size_t subghz_encoder_princeton_get_repeat_left(SubGhzEncoderPrinceton* instance) {
furi_assert(instance);
return instance->repeat;
}
void subghz_encoder_princeton_print_log(void* context) {
SubGhzEncoderPrinceton* instance = context;
float duty_cycle =
((float)instance->time_high / (instance->time_high + instance->time_low)) * 100;
FURI_LOG_I(
TAG "Encoder",
"Radio tx_time=%dus ON=%dus, OFF=%dus, DutyCycle=%d,%d%%",
instance->time_high + instance->time_low,
instance->time_high,
instance->time_low,
(uint32_t)duty_cycle,
(uint32_t)((duty_cycle - (uint32_t)duty_cycle) * 100));
}
LevelDuration subghz_encoder_princeton_yield(void* context) {
SubGhzEncoderPrinceton* instance = context;
if(instance->repeat == 0) {
subghz_encoder_princeton_print_log(instance);
return level_duration_reset();
}
size_t bit = instance->front / 2;
bool level = !(instance->front % 2);
LevelDuration ret;
if(bit < 24) {
uint8_t byte = bit / 8;
uint8_t bit_in_byte = bit % 8;
bool value = (((uint8_t*)&instance->key)[2 - byte] >> (7 - bit_in_byte)) & 1;
if(value) {
ret = level_duration_make(level, level ? instance->te * 3 : instance->te);
if(level)
instance->time_high += instance->te * 3;
else
instance->time_low += instance->te;
} else {
ret = level_duration_make(level, level ? instance->te : instance->te * 3);
if(level)
instance->time_high += instance->te;
else
instance->time_low += instance->te * 3;
}
} else {
if(instance->time_stop) {
ret = level_duration_make(level, level ? instance->te : instance->time_stop);
if(level)
instance->time_high += instance->te;
else {
instance->time_low += instance->time_stop;
instance->time_stop = 0;
instance->front = 47;
}
} else {
if(--instance->count_key != 0) {
ret = level_duration_make(level, level ? instance->te : instance->te * 30);
if(level)
instance->time_high += instance->te;
else
instance->time_low += instance->te * 30;
} else {
instance->count_key = instance->count_key_package + 2;
instance->front = 48;
ret = level_duration_make(level, level ? instance->te : instance->timeout * 1000);
if(level)
instance->time_high += instance->te;
else
instance->time_low += instance->timeout * 1000;
}
}
}
instance->front++;
if(instance->front == 50) {
instance->repeat--;
instance->front = 0;
}
return ret;
}
SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc(void) {
SubGhzDecoderPrinceton* instance = malloc(sizeof(SubGhzDecoderPrinceton));
instance->te = SUBGHZ_PT_SHORT;
instance->common.name = "Princeton";
instance->common.code_min_count_bit_for_found = 24;
instance->common.te_short = 400; //150;
instance->common.te_long = 1200; //450;
instance->common.te_delta = 250; //50;
instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_decoder_princeton_to_str;
instance->common.to_save_file =
(SubGhzProtocolCommonSaveFile)subghz_decoder_princeton_to_save_file;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_decoder_princeton_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_princeton_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_princeton_send_key;
return instance;
}
void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance) {
furi_assert(instance);
free(instance);
}
uint16_t subghz_protocol_princeton_get_te(void* context) {
SubGhzDecoderPrinceton* instance = context;
return instance->te;
}
bool subghz_protocol_princeton_send_key(
SubGhzDecoderPrinceton* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->te * 3);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te);
} else {
//send bit 0
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->te);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te * 3);
}
}
//Send Stop bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->te);
//Send PT_GUARD
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te * 30);
return true;
}
void subghz_decoder_princeton_reset(SubGhzDecoderPrinceton* instance) {
instance->common.parser_step = PrincetonDecoderStepReset;
}
void subghz_decoder_princeton_parse(
SubGhzDecoderPrinceton* instance,
bool level,
uint32_t duration) {
switch(instance->common.parser_step) {
case PrincetonDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 36) <
instance->common.te_delta * 36)) {
//Found Preambula
instance->common.parser_step = PrincetonDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->te = 0;
}
break;
case PrincetonDecoderStepSaveDuration:
//save duration
if(level) {
instance->common.te_last = duration;
instance->te += duration;
instance->common.parser_step = PrincetonDecoderStepCheckDuration;
}
break;
case PrincetonDecoderStepCheckDuration:
if(!level) {
if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) {
instance->common.parser_step = PrincetonDecoderStepSaveDuration;
if(instance->common.code_count_bit ==
instance->common.code_min_count_bit_for_found) {
instance->te /= (instance->common.code_count_bit * 4 + 1);
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
instance->common.serial = instance->common.code_found >> 4;
instance->common.btn = (uint8_t)instance->common.code_found & 0x00000F;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->te = 0;
break;
}
instance->te += duration;
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) <
instance->common.te_delta * 3)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = PrincetonDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta * 3) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = PrincetonDecoderStepSaveDuration;
} else {
instance->common.parser_step = PrincetonDecoderStepReset;
}
} else {
instance->common.parser_step = PrincetonDecoderStepReset;
}
break;
}
}
void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output) {
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_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"
"Te:%dus\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_lo,
code_found_reverse_lo,
instance->common.serial,
instance->common.btn,
instance->te);
}
bool subghz_decoder_princeton_to_save_file(
SubGhzDecoderPrinceton* instance,
FlipperFormat* flipper_format) {
bool res =
subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_format);
if(res) {
res = flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1);
if(!res) FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Te");
}
return res;
}
bool subghz_decoder_princeton_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzDecoderPrinceton* instance,
const char* file_path) {
bool loaded = subghz_protocol_common_to_load_protocol_from_file(
(SubGhzProtocolCommon*)instance, flipper_format);
if(loaded) {
loaded = flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1);
if(!loaded) FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing TE");
}
return loaded;
}
void subghz_decoder_princeton_to_load_protocol(SubGhzDecoderPrinceton* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
instance->te = data->param1;
instance->common.serial = instance->common.code_last_found >> 4;
instance->common.btn = (uint8_t)instance->common.code_last_found & 0x00000F;
}

View File

@@ -1,137 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
struct SubGhzDecoderPrinceton {
SubGhzProtocolCommon common;
uint32_t te;
};
/** SubGhzEncoderPrinceton anonymous type */
typedef struct SubGhzEncoderPrinceton SubGhzEncoderPrinceton;
/** Allocate SubGhzEncoderPrinceton
* @return pointer to SubGhzEncoderPrinceton instance
*/
SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc();
/** Free SubGhzEncoderPrinceton instance
* @param instance - SubGhzEncoderPrinceton instance
*/
void subghz_encoder_princeton_free(SubGhzEncoderPrinceton* instance);
void subghz_encoder_princeton_stop(SubGhzEncoderPrinceton* instance, uint32_t time_stop);
/** Set new encoder params
* @param instance - SubGhzEncoderPrinceton instance
* @param key - 24bit key
* @param repeat - how many times to repeat
* @param frequency - frequency
*/
void subghz_encoder_princeton_set(
SubGhzEncoderPrinceton* instance,
uint32_t key,
size_t repeat,
uint32_t frequency);
/** Get repeat count left
* @param instance - SubGhzEncoderPrinceton instance
* @return repeat count left
*/
size_t subghz_encoder_princeton_get_repeat_left(SubGhzEncoderPrinceton* instance);
/** Print encoder log
* @param instance - SubGhzEncoderPrinceton instance
*/
void subghz_encoder_princeton_print_log(void* context);
/** Get level duration
* @param instance - SubGhzEncoderPrinceton instance
* @return level duration
*/
LevelDuration subghz_encoder_princeton_yield(void* context);
/** SubGhzDecoderPrinceton anonymous type */
typedef struct SubGhzDecoderPrinceton SubGhzDecoderPrinceton;
void subghz_encoder_princeton_set_te(SubGhzEncoderPrinceton* instance, void* decoder);
/** Allocate SubGhzDecoderPrinceton
*
* @return SubGhzDecoderPrinceton*
*/
SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc();
/** Free SubGhzDecoderPrinceton
*
* @param instance
*/
void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance);
/** Get Te interval protocol
*
* @param context - SubGhzDecoderPrinceton context
* @return Te interval (us)
*/
uint16_t subghz_protocol_princeton_get_te(void* context);
/** Get upload protocol
*
* @param instance - SubGhzDecoderPrinceton instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_princeton_send_key(
SubGhzDecoderPrinceton* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzDecoderPrinceton instance
*/
void subghz_decoder_princeton_reset(SubGhzDecoderPrinceton* instance);
/** Parse accepted duration
*
* @param instance - SubGhzDecoderPrinceton instance
* @param data - LevelDuration level_duration
*/
void subghz_decoder_princeton_parse(
SubGhzDecoderPrinceton* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzDecoderPrinceton* instance
* @param output - output string
*/
void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output);
/** Adding data to a file
*
* @param instance - SubGhzDecoderPrinceton instance
* @param flipper_format - FlipperFormat
* @return bool
*/
bool subghz_decoder_princeton_to_save_file(
SubGhzDecoderPrinceton* instance,
FlipperFormat* flipper_format);
/** Loading protocol from file
*
* @param flipper_format - FlipperFormat
* @param instance - SubGhzDecoderPrinceton instance
* @param file_path - file path
* @return bool
*/
bool subghz_decoder_princeton_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzDecoderPrinceton* instance,
const char* file_path);
/** Loading protocol from bin data
*
* @param instance - SubGhzDecoderPrinceton instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_princeton_to_load_protocol(SubGhzDecoderPrinceton* instance, void* context);

View File

@@ -1,270 +0,0 @@
#include "subghz_protocol_raw.h"
#include "../subghz_file_encoder_worker.h"
#define TAG "SubGhzRaw"
#define SUBGHZ_DOWNLOAD_MAX_SIZE 512
struct SubGhzProtocolRAW {
SubGhzProtocolCommon common;
int32_t* upload_raw;
uint16_t ind_write;
Storage* storage;
FlipperFormat* flipper_format;
SubGhzFileEncoderWorker* file_worker_encoder;
uint32_t file_is_open;
string_t file_name;
size_t sample_write;
bool last_level;
SubGhzProtocolRAWCallbackEnd callback_end;
void* context_end;
};
typedef enum {
RAWFileIsOpenClose = 0,
RAWFileIsOpenWrite,
RAWFileIsOpenRead,
} RAWFilIsOpen;
SubGhzProtocolRAW* subghz_protocol_raw_alloc(void) {
SubGhzProtocolRAW* instance = malloc(sizeof(SubGhzProtocolRAW));
instance->upload_raw = NULL;
instance->ind_write = 0;
instance->last_level = false;
instance->storage = furi_record_open("storage");
instance->flipper_format = flipper_format_file_alloc(instance->storage);
instance->file_is_open = RAWFileIsOpenClose;
string_init(instance->file_name);
instance->common.name = "RAW";
instance->common.code_min_count_bit_for_found = 0;
instance->common.te_short = 80;
instance->common.te_long = 32700;
instance->common.te_delta = 0;
instance->common.type_protocol = SubGhzProtocolCommonTypeRAW;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_raw_to_load_protocol_from_file;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_raw_to_str;
//instance->common.to_load_protocol =
// (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_raw_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_raw_send_key;
return instance;
}
void subghz_protocol_raw_free(SubGhzProtocolRAW* instance) {
furi_assert(instance);
string_clear(instance->file_name);
flipper_format_free(instance->flipper_format);
furi_record_close("storage");
free(instance);
}
void subghz_protocol_raw_file_encoder_worker_callback_end(void* context) {
furi_assert(context);
SubGhzProtocolRAW* instance = context;
if(instance->callback_end) instance->callback_end(instance->context_end);
}
void subghz_protocol_raw_file_encoder_worker_set_callback_end(
SubGhzProtocolRAW* instance,
SubGhzProtocolRAWCallbackEnd callback_end,
void* context_end) {
furi_assert(instance);
furi_assert(callback_end);
instance->callback_end = callback_end;
instance->context_end = context_end;
}
void subghz_protocol_raw_file_encoder_worker_stop(void* context) {
furi_assert(context);
SubGhzProtocolRAW* instance = context;
if(subghz_file_encoder_worker_is_running(instance->file_worker_encoder)) {
subghz_file_encoder_worker_stop(instance->file_worker_encoder);
subghz_file_encoder_worker_free(instance->file_worker_encoder);
instance->file_is_open = RAWFileIsOpenClose;
}
}
bool subghz_protocol_raw_send_key(
SubGhzProtocolRAW* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
bool loaded = false;
instance->file_worker_encoder = subghz_file_encoder_worker_alloc();
if(subghz_file_encoder_worker_start(
instance->file_worker_encoder, string_get_cstr(instance->file_name))) {
//the worker needs a file in order to open and read part of the file
osDelay(100);
instance->file_is_open = RAWFileIsOpenRead;
//Forwarding UPLOAD to common encoder
subghz_protocol_encoder_common_set_callback(
encoder, subghz_file_encoder_worker_get_level_duration, instance->file_worker_encoder);
//forced stop of transmission
subghz_protocol_encoder_common_set_callback_end(
encoder, subghz_protocol_raw_file_encoder_worker_stop, instance);
//file transfer complete callback
subghz_file_encoder_worker_callback_end(
instance->file_worker_encoder,
subghz_protocol_raw_file_encoder_worker_callback_end,
instance);
loaded = true;
} else {
subghz_protocol_raw_file_encoder_worker_stop(instance);
}
return loaded;
}
void subghz_protocol_raw_reset(SubGhzProtocolRAW* instance) {
instance->ind_write = 0;
}
void subghz_protocol_raw_parse(SubGhzProtocolRAW* instance, bool level, uint32_t duration) {
if(instance->upload_raw != NULL) {
if(duration > instance->common.te_short) {
if(duration > instance->common.te_long) duration = instance->common.te_long;
if(instance->last_level != level) {
instance->last_level = (level ? true : false);
instance->upload_raw[instance->ind_write++] = (level ? duration : -duration);
}
}
if(instance->ind_write == SUBGHZ_DOWNLOAD_MAX_SIZE) {
subghz_protocol_raw_save_to_file_write(instance);
}
}
}
void subghz_protocol_raw_to_str(SubGhzProtocolRAW* instance, string_t output) {
string_cat_printf(output, "RAW Date");
}
const char* subghz_protocol_raw_get_last_file_name(SubGhzProtocolRAW* instance) {
return string_get_cstr(instance->file_name);
}
void subghz_protocol_raw_set_last_file_name(SubGhzProtocolRAW* instance, const char* name) {
string_printf(instance->file_name, "%s", name);
}
bool subghz_protocol_raw_save_to_file_init(
SubGhzProtocolRAW* instance,
const char* dev_name,
uint32_t frequency,
const char* preset) {
furi_assert(instance);
//instance->flipper_format = flipper_format_file_alloc(instance->storage);
string_t dev_file_name;
string_init(dev_file_name);
bool init = false;
do {
// Create subghz folder directory if necessary
if(!storage_simply_mkdir(instance->storage, SUBGHZ_RAW_FOLDER)) {
break;
}
string_set(instance->file_name, dev_name);
// First remove subghz device file if it was saved
string_printf(dev_file_name, "%s/%s%s", SUBGHZ_RAW_FOLDER, dev_name, SUBGHZ_APP_EXTENSION);
if(!storage_simply_remove(instance->storage, string_get_cstr(dev_file_name))) {
break;
}
// Open file
if(!flipper_format_file_open_always(
instance->flipper_format, string_get_cstr(dev_file_name))) {
FURI_LOG_E(TAG, "Unable to open file for write: %s", dev_file_name);
break;
}
if(!flipper_format_write_header_cstr(
instance->flipper_format, SUBGHZ_RAW_FILE_TYPE, SUBGHZ_RAW_FILE_VERSION)) {
FURI_LOG_E(TAG, "Unable to add header");
break;
}
if(!flipper_format_write_uint32(instance->flipper_format, "Frequency", &frequency, 1)) {
FURI_LOG_E(TAG, "Unable to add Frequency");
break;
}
if(!flipper_format_write_string_cstr(instance->flipper_format, "Preset", preset)) {
FURI_LOG_E(TAG, "Unable to add Preset");
break;
}
if(!flipper_format_write_string_cstr(
instance->flipper_format, "Protocol", instance->common.name)) {
FURI_LOG_E(TAG, "Unable to add Protocol");
break;
}
instance->upload_raw = malloc(SUBGHZ_DOWNLOAD_MAX_SIZE * sizeof(int32_t));
instance->file_is_open = RAWFileIsOpenWrite;
instance->sample_write = 0;
init = true;
} while(0);
string_clear(dev_file_name);
return init;
}
void subghz_protocol_raw_save_to_file_stop(SubGhzProtocolRAW* instance) {
furi_assert(instance);
if(instance->file_is_open == RAWFileIsOpenWrite && instance->ind_write)
subghz_protocol_raw_save_to_file_write(instance);
if(instance->file_is_open != RAWFileIsOpenClose) {
free(instance->upload_raw);
instance->upload_raw = NULL;
}
flipper_format_file_close(instance->flipper_format);
instance->file_is_open = RAWFileIsOpenClose;
}
bool subghz_protocol_raw_save_to_file_write(SubGhzProtocolRAW* instance) {
furi_assert(instance);
bool is_write = false;
if(instance->file_is_open == RAWFileIsOpenWrite) {
if(!flipper_format_write_int32(
instance->flipper_format, "RAW_Data", instance->upload_raw, instance->ind_write)) {
FURI_LOG_E(TAG, "Unable to add RAW_Data");
} else {
instance->sample_write += instance->ind_write;
instance->ind_write = 0;
is_write = true;
}
}
return is_write;
}
size_t subghz_protocol_raw_get_sample_write(SubGhzProtocolRAW* instance) {
return instance->sample_write + instance->ind_write;
}
bool subghz_protocol_raw_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolRAW* instance,
const char* file_path) {
furi_assert(file_path);
subghz_protocol_raw_set_last_file_name(instance, file_path);
return true;
}

View File

@@ -1,71 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef void (*SubGhzProtocolRAWCallbackEnd)(void* context);
typedef struct SubGhzProtocolRAW SubGhzProtocolRAW;
/** Allocate SubGhzProtocolRAW
*
* @return SubGhzProtocolRAW*
*/
SubGhzProtocolRAW* subghz_protocol_raw_alloc();
/** Free SubGhzProtocolRAW
*
* @param instance
*/
void subghz_protocol_raw_free(SubGhzProtocolRAW* instance);
void subghz_protocol_raw_file_encoder_worker_set_callback_end(
SubGhzProtocolRAW* instance,
SubGhzProtocolRAWCallbackEnd callback_end,
void* context_end);
/** Reset internal state
* @param instance - SubGhzProtocolRAW instance
*/
void subghz_protocol_raw_reset(SubGhzProtocolRAW* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolRAW instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_raw_send_key(
SubGhzProtocolRAW* instance,
SubGhzProtocolCommonEncoder* encoder);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolRAW instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_raw_parse(SubGhzProtocolRAW* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolRAW* instance
* @param output - output string
*/
void subghz_protocol_raw_to_str(SubGhzProtocolRAW* instance, string_t output);
const char* subghz_protocol_raw_get_last_file_name(SubGhzProtocolRAW* instance);
void subghz_protocol_raw_set_last_file_name(SubGhzProtocolRAW* instance, const char* name);
bool subghz_protocol_raw_save_to_file_init(
SubGhzProtocolRAW* instance,
const char* dev_name,
uint32_t frequency,
const char* preset);
void subghz_protocol_raw_save_to_file_stop(SubGhzProtocolRAW* instance);
bool subghz_protocol_raw_save_to_file_write(SubGhzProtocolRAW* instance);
size_t subghz_protocol_raw_get_sample_write(SubGhzProtocolRAW* instance);
bool subghz_protocol_raw_to_load_protocol_from_file(
FlipperFormat* flipper_format,
SubGhzProtocolRAW* instance,
const char* file_path);

View File

@@ -1,244 +0,0 @@
#include "subghz_protocol_scher_khan.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
struct SubGhzProtocolScherKhan {
SubGhzProtocolCommon common;
const char* protocol_name;
};
typedef enum {
ScherKhanDecoderStepReset = 0,
ScherKhanDecoderStepCheckPreambula,
ScherKhanDecoderStepSaveDuration,
ScherKhanDecoderStepCheckDuration,
} ScherKhanDecoderStep;
SubGhzProtocolScherKhan* subghz_protocol_scher_khan_alloc(void) {
SubGhzProtocolScherKhan* instance = malloc(sizeof(SubGhzProtocolScherKhan));
instance->common.name = "Scher-Khan";
instance->common.code_min_count_bit_for_found = 35;
instance->common.te_short = 750;
instance->common.te_long = 1100;
instance->common.te_delta = 150;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_scher_khan_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_scher_khan_to_load_protocol;
return instance;
}
void subghz_protocol_scher_khan_free(SubGhzProtocolScherKhan* instance) {
furi_assert(instance);
free(instance);
}
/** Send bit
*
* @param instance - SubGhzProtocolScherKhan instance
* @param bit - bit
*/
// void subghz_protocol_scher_khan_send_bit(SubGhzProtocolScherKhan* instance, uint8_t bit) {
// if(bit) {
// //send bit 1
// SUBGHZ_TX_PIN_HIGH();
// delay_us(instance->common.te_long);
// SUBGHZ_TX_PIN_LOW();
// delay_us(instance->common.te_short);
// } else {
// //send bit 0
// SUBGHZ_TX_PIN_HIGH();
// delay_us(instance->common.te_short);
// SUBGHZ_TX_PIN_LOW();
// delay_us(instance->common.te_long);
// }
// }
// void subghz_protocol_scher_khan_send_key(
// SubGhzProtocolScherKhan* instance,
// uint64_t key,
// uint8_t bit,
// uint8_t repeat) {
// while(repeat--) {
// SUBGHZ_TX_PIN_HIGH();
// //Send header
// delay_us(instance->common.te_long * 2);
// SUBGHZ_TX_PIN_LOW();
// delay_us(instance->common.te_long * 2);
// //Send key data
// for(uint8_t i = bit; i > 0; i--) {
// subghz_protocol_scher_khan_send_bit(instance, bit_read(key, i - 1));
// }
// }
// }
void subghz_protocol_scher_khan_reset(SubGhzProtocolScherKhan* instance) {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolScherKhan instance
*/
void subghz_protocol_scher_khan_check_remote_controller(SubGhzProtocolScherKhan* instance) {
/*
* MAGICAR 51 bit 00000001A99121DE83C3 MAGIC CODE, Dinamic
* 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->common.code_last_count_bit) {
// case 35: //MAGIC CODE, Static
// instance->protocol_name = "MAGIC CODE, Static";
// break;
case 51: //MAGIC CODE, Dinamic
instance->protocol_name = "MAGIC CODE, Dinamic";
instance->common.serial = ((instance->common.code_last_found >> 24) & 0xFFFFFF0) |
((instance->common.code_last_found >> 20) & 0x0F);
instance->common.btn = (instance->common.code_last_found >> 24) & 0x0F;
instance->common.cnt = instance->common.code_last_found & 0xFFFF;
break;
// case 57: //MAGIC CODE PRO / PRO2
// instance->protocol_name = "MAGIC CODE PRO / PRO2";
// break;
default:
instance->protocol_name = "Unknown";
instance->common.serial = 0;
instance->common.btn = 0;
instance->common.cnt = 0;
break;
}
}
void subghz_protocol_scher_khan_parse(
SubGhzProtocolScherKhan* instance,
bool level,
uint32_t duration) {
switch(instance->common.parser_step) {
case ScherKhanDecoderStepReset:
if((level) &&
(DURATION_DIFF(duration, instance->common.te_short * 2) < instance->common.te_delta)) {
instance->common.parser_step = ScherKhanDecoderStepCheckPreambula;
instance->common.te_last = duration;
instance->common.header_count = 0;
}
break;
case ScherKhanDecoderStepCheckPreambula:
if(level) {
if((DURATION_DIFF(duration, instance->common.te_short * 2) <
instance->common.te_delta) ||
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.te_last = duration;
} else {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
} else if(
(DURATION_DIFF(duration, instance->common.te_short * 2) < instance->common.te_delta) ||
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
if(DURATION_DIFF(instance->common.te_last, instance->common.te_short * 2) <
instance->common.te_delta) {
// Found header
instance->common.header_count++;
break;
} else if(
DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) {
// Found start bit
if(instance->common.header_count >= 2) {
instance->common.parser_step = ScherKhanDecoderStepSaveDuration;
instance->common.code_found = 0;
instance->common.code_count_bit = 1;
} else {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
} else {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
} else {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
break;
case ScherKhanDecoderStepSaveDuration:
if(level) {
if(duration >= (instance->common.te_long + instance->common.te_delta * 2)) {
//Found stop bit
instance->common.parser_step = ScherKhanDecoderStepReset;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
break;
} else {
instance->common.te_last = duration;
instance->common.parser_step = ScherKhanDecoderStepCheckDuration;
}
} else {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
break;
case ScherKhanDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = ScherKhanDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = ScherKhanDecoderStepSaveDuration;
} else {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
} else {
instance->common.parser_step = ScherKhanDecoderStepReset;
}
break;
}
}
void subghz_protocol_scher_khan_to_str(SubGhzProtocolScherKhan* instance, string_t output) {
subghz_protocol_scher_khan_check_remote_controller(instance);
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:%07lX Btn:%lX Cnt:%04X\r\n"
"Pt: %s\r\n",
instance->common.name,
instance->common.code_last_count_bit,
(uint32_t)(instance->common.code_last_found >> 32),
(uint32_t)instance->common.code_last_found,
instance->common.serial,
instance->common.btn,
instance->common.cnt,
instance->protocol_name);
}
void subghz_decoder_scher_khan_to_load_protocol(SubGhzProtocolScherKhan* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_scher_khan_check_remote_controller(instance);
}

View File

@@ -1,65 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolScherKhan SubGhzProtocolScherKhan;
/** Allocate SubGhzProtocolScherKhan
*
* @return SubGhzProtocolScherKhan*
*/
SubGhzProtocolScherKhan* subghz_protocol_scher_khan_alloc();
/** Free SubGhzProtocolScherKhan
*
* @param instance
*/
void subghz_protocol_scher_khan_free(SubGhzProtocolScherKhan* instance);
/** Sends the key on the air
*
* @param instance - SubGhzProtocolScherKhan instance
* @param key - key send
* @param bit - count bit key
* @param repeat - repeat send key
*/
void subghz_protocol_scher_khan_send_key(
SubGhzProtocolScherKhan* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat);
/** Reset internal state
* @param instance - SubGhzProtocolScherKhan instance
*/
void subghz_protocol_scher_khan_reset(SubGhzProtocolScherKhan* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolScherKhan instance
*/
void subghz_protocol_scher_khan_check_remote_controller(SubGhzProtocolScherKhan* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolScherKhan instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_scher_khan_parse(
SubGhzProtocolScherKhan* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolScherKhan* instance
* @param output - output string
*/
void subghz_protocol_scher_khan_to_str(SubGhzProtocolScherKhan* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolScherKhan instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_scher_khan_to_load_protocol(SubGhzProtocolScherKhan* instance, void* context);

View File

@@ -1,345 +0,0 @@
#include "subghz_protocol_somfy_keytis.h"
#include "subghz_protocol_common.h"
#include <lib/toolbox/manchester_decoder.h>
#define TAG "SubGhzSomfyKeytis"
struct SubGhzProtocolSomfyKeytis {
SubGhzProtocolCommon common;
ManchesterState manchester_saved_state;
uint32_t press_duration_counter;
};
typedef enum {
SomfyKeytisDecoderStepReset = 0,
SomfyKeytisDecoderStepCheckPreambula,
SomfyKeytisDecoderStepFoundPreambula,
SomfyKeytisDecoderStepStartDecode,
SomfyKeytisDecoderStepDecoderData,
} SomfyKeytisDecoderStep;
SubGhzProtocolSomfyKeytis* subghz_protocol_somfy_keytis_alloc() {
SubGhzProtocolSomfyKeytis* instance = malloc(sizeof(SubGhzProtocolSomfyKeytis));
instance->common.name = "Somfy Keytis";
instance->common.code_min_count_bit_for_found = 80;
instance->common.te_short = 640;
instance->common.te_long = 1280;
instance->common.te_delta = 250;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_somfy_keytis_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_somfy_keytis_to_load_protocol;
return instance;
}
void subghz_protocol_somfy_keytis_free(SubGhzProtocolSomfyKeytis* instance) {
furi_assert(instance);
free(instance);
}
/** Analysis of received data
*
* @param instance SubGhzProtocolSomfyKeytis instance
*/
void subghz_protocol_somfy_keytis_remote_controller(SubGhzProtocolSomfyKeytis* instance) {
//https://pushstack.wordpress.com/somfy-rts-protocol/
/*
* 604 us
* /
* | 2416us | 2416us | 2416us | 2416us | 4550 us | |
*
* +--------+ +--------+ +---...---+
* + +--------+ +--------+ +--+XXXX...XXX+
*
* | hw. sync. | soft. | |
* | | sync. | data |
*
*
* encrypt | decrypt
*
* package 80 bit pdc key btn crc cnt serial
*
* 0xA453537C4B9855 C40019 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 C80026 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 CC0033 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 D00049 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 D4005C => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 D80063 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 DC0076 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 E00086 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 E40093 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 E800AC => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 EC00B9 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 F000C3 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 F400D6 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 F800E9 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC00FC => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC0102 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC0113 => 0xA 4 F 7 002F 37D3CD
* 0xA453537C4B9855 FC0120 => 0xA 4 F 7 002F 37D3CD
* ..........
* 0xA453537C4B9855 FC048F => 0xA 4 F 7 002F 37D3CD
*
* Pdc: "Press Duration Counter" the total delay of the button is sent 72 parcels,
* pdc cnt4b cnt8b pdc_crc
* C40019 => 11 0001 00 0000 00000001 1001
* C80026 => 11 0010 00 0000 00000010 0110
* CC0033 => 11 0011 00 0000 00000011 0011
* D00049 => 11 0100 00 0000 00000100 1001
* D4005C => 11 0101 00 0000 00000101 1100
* D80063 => 11 0110 00 0000 00000110 0011
* DC0076 => 11 0111 00 0000 00000111 0110
* E00086 => 11 1000 00 0000 00001000 0110
* E40093 => 11 1001 00 0000 00001001 0011
* E800AC => 11 1010 00 0000 00001010 1100
* EC00B9 => 11 1011 00 0000 00001011 1001
* F000C3 => 11 1100 00 0000 00001100 0011
* F400D6 => 11 1101 00 0000 00001101 0110
* F800E9 => 11 1110 00 0000 00001110 1001
* FC00FC => 11 1111 00 0000 00001111 1100
* FC0102 => 11 1111 00 0000 00010000 0010
* FC0113 => 11 1111 00 0000 00010001 0011
* FC0120 => 11 1111 00 0000 00010010 0000
*
* Cnt4b: 4-bit counter changes from 1 to 15 then always equals 15
* Cnt8b: 8-bit counter changes from 1 to 72 (0x48)
* Ppdc_crc:
* uint8_t crc=0;
* for(i=4; i<24; i+=4){
* crc ^=(pdc>>i);
* }
* return crc;
* example: crc = 1^0^0^4^C = 9
* 11, 00, 0000: const
*
* Key: “Encryption Key”, Most significant 4-bit are always 0xA, Least Significant bits is
* a linear counter. In the Smoove Origin this counter is increased together with the
* rolling code. But leaving this on a constant value also works. Gerardwr notes that
* for some other types of remotes the MSB is not constant.
* Btn: 4-bit Control codes, this indicates the button that is pressed
* CRC: 4-bit Checksum.
* Ctn: 16-bit rolling code (big-endian) increased with every button press.
* Serial: 24-bit identifier of sending device (little-endian)
*
*
* Decrypt
*
* uint8_t frame[7];
* for (i=1; i < 7; i++) {
* frame[i] = frame[i] ^ frame[i-1];
* }
* or
* uint64 Decrypt = frame ^ (frame>>8);
*
* CRC
*
* uint8_t frame[7];
* for (i=0; i < 7; i++) {
* crc = crc ^ frame[i] ^ (frame[i] >> 4);
* }
* crc = crc & 0xf;
*
*/
uint64_t data = instance->common.code_last_found ^ (instance->common.code_last_found >> 8);
instance->common.btn = (data >> 48) & 0xF;
instance->common.cnt = (data >> 24) & 0xFFFF;
instance->common.serial = data & 0xFFFFFF;
}
uint8_t subghz_protocol_somfy_keytis_crc(uint64_t data) {
uint8_t crc = 0;
data &= 0xFFF0FFFFFFFFFF;
for(uint8_t i = 0; i < 56; i += 8) {
crc = crc ^ data >> i ^ (data >> (i + 4));
}
return crc & 0xf;
}
const char* subghz_protocol_somfy_keytis_get_name_button(uint8_t btn) {
const char* name_btn[0x10] = {
"Unknown",
"0x01",
"0x02",
"Prog",
"Key_1",
"0x05",
"0x06",
"0x07",
"0x08",
"0x09",
"0x0A",
"0x0B",
"0x0C",
"0x0D",
"0x0E",
"0x0F"};
return btn <= 0xf ? name_btn[btn] : name_btn[0];
}
uint32_t subghz_protocol_somfy_keytis_get_press_duration(void* context) {
SubGhzProtocolSomfyKeytis* instance = context;
return instance->press_duration_counter;
}
void subghz_protocol_somfy_keytis_reset(SubGhzProtocolSomfyKeytis* instance) {
instance->common.parser_step = SomfyKeytisDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
void subghz_protocol_somfy_keytis_parse(
SubGhzProtocolSomfyKeytis* instance,
bool level,
uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch(instance->common.parser_step) {
case SomfyKeytisDecoderStepReset:
if((level) && DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta * 4) {
instance->common.parser_step = SomfyKeytisDecoderStepFoundPreambula;
instance->common.header_count++;
}
break;
case SomfyKeytisDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta * 4)) {
instance->common.parser_step = SomfyKeytisDecoderStepCheckPreambula;
} else {
instance->common.header_count = 0;
instance->common.parser_step = SomfyKeytisDecoderStepReset;
}
break;
case SomfyKeytisDecoderStepCheckPreambula:
if(level) {
if(DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta * 4) {
instance->common.parser_step = SomfyKeytisDecoderStepFoundPreambula;
instance->common.header_count++;
} else if(
(instance->common.header_count > 1) &&
(DURATION_DIFF(duration, instance->common.te_short * 7) <
instance->common.te_delta * 4)) {
instance->common.parser_step = SomfyKeytisDecoderStepDecoderData;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->press_duration_counter = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
}
}
break;
case SomfyKeytisDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortLow;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongLow;
} else if(duration >= (instance->common.te_long + instance->common.te_delta)) {
if(instance->common.code_count_bit ==
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
//check crc
uint64_t data_tmp = instance->common.code_last_found ^
(instance->common.code_last_found >> 8);
if(((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_keytis_crc(data_tmp)) {
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
instance->common.parser_step = SomfyKeytisDecoderStepReset;
} else {
instance->common.parser_step = SomfyKeytisDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortHigh;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->common.parser_step = SomfyKeytisDecoderStepReset;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
if(data_ok) {
if(instance->common.code_count_bit < 56) {
instance->common.code_found = (instance->common.code_found << 1) | data;
} else {
instance->press_duration_counter = (instance->press_duration_counter << 1) |
data;
}
instance->common.code_count_bit++;
}
}
break;
}
}
void subghz_protocol_somfy_keytis_to_str(SubGhzProtocolSomfyKeytis* instance, string_t output) {
subghz_protocol_somfy_keytis_remote_controller(instance);
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %db\r\n"
"%lX%08lX%06lX\r\n"
"Sn:0x%06lX \r\n"
"Cnt:0x%04X\r\n"
"Btn:%s\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
instance->press_duration_counter,
instance->common.serial,
instance->common.cnt,
subghz_protocol_somfy_keytis_get_name_button(instance->common.btn));
}
void subghz_decoder_somfy_keytis_to_load_protocol(
SubGhzProtocolSomfyKeytis* instance,
void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
instance->press_duration_counter = data->param1;
subghz_protocol_somfy_keytis_remote_controller(instance);
}

View File

@@ -1,50 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolSomfyKeytis SubGhzProtocolSomfyKeytis;
/** Allocate SubGhzProtocolSomfyKeytis
*
* @return SubGhzProtocolSomfyKeytis*
*/
SubGhzProtocolSomfyKeytis* subghz_protocol_somfy_keytis_alloc();
/** Free SubGhzProtocolSomfyKeytis
*
* @param instance
*/
void subghz_protocol_somfy_keytis_free(SubGhzProtocolSomfyKeytis* instance);
uint32_t subghz_protocol_somfy_keytis_get_press_duration(void* context);
/** Reset internal state
* @param instance - SubGhzProtocolSomfyKeytis instance
*/
void subghz_protocol_somfy_keytis_reset(SubGhzProtocolSomfyKeytis* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolSomfyKeytis instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_somfy_keytis_parse(
SubGhzProtocolSomfyKeytis* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolSomfyKeytis* instance
* @param output - output string
*/
void subghz_protocol_somfy_keytis_to_str(SubGhzProtocolSomfyKeytis* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolSomfyKeytis instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_somfy_keytis_to_load_protocol(
SubGhzProtocolSomfyKeytis* instance,
void* context);

View File

@@ -1,293 +0,0 @@
#include "subghz_protocol_somfy_telis.h"
#include "subghz_protocol_common.h"
#include <lib/toolbox/manchester_decoder.h>
#define TAG "SubGhzSomfyTelis"
struct SubGhzProtocolSomfyTelis {
SubGhzProtocolCommon common;
ManchesterState manchester_saved_state;
};
typedef enum {
SomfyTelisDecoderStepReset = 0,
SomfyTelisDecoderStepCheckPreambula,
SomfyTelisDecoderStepFoundPreambula,
SomfyTelisDecoderStepStartDecode,
SomfyTelisDecoderStepDecoderData,
} SomfyTelisDecoderStep;
SubGhzProtocolSomfyTelis* subghz_protocol_somfy_telis_alloc() {
SubGhzProtocolSomfyTelis* instance = malloc(sizeof(SubGhzProtocolSomfyTelis));
instance->common.name = "Somfy Telis";
instance->common.code_min_count_bit_for_found = 56;
instance->common.te_short = 640;
instance->common.te_long = 1280;
instance->common.te_delta = 250;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_somfy_telis_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_somfy_telis_to_load_protocol;
return instance;
}
void subghz_protocol_somfy_telis_free(SubGhzProtocolSomfyTelis* instance) {
furi_assert(instance);
free(instance);
}
/** Analysis of received data
*
* @param instance SubGhzProtocolSomfyTelis instance
*/
void subghz_protocol_somfy_telis_remote_controller(SubGhzProtocolSomfyTelis* instance) {
//https://pushstack.wordpress.com/somfy-rts-protocol/
/*
* 604 us
* /
* | 2416us | 2416us | 2416us | 2416us | 4550 us | | 67648 us | 30415 us |
*
* +--------+ +--------+ +---...---+
* + +--------+ +--------+ +--+XXXX...XXX+-----...-----
*
* | hw. sync. | soft. | | Inter-frame
* | | sync. | data | gap
*
*
* encrypt | decrypt
*
* package 56 bit cnt key btn|crc cnt serial
* 0xA7232323312222 - 0 => A7 8 0 | 00 00 | 12 13 00
* 0xA7222223312222 - 1 => A7 8 5 | 00 01 | 12 13 00
* 0xA7212123312222 - 2 => A7 8 6 | 00 02 | 12 13 00
*
* Key: “Encryption Key”, Most significant 4-bit are always 0xA, Least Significant bits is
* a linear counter. In the Smoove Origin this counter is increased together with the
* rolling code. But leaving this on a constant value also works. Gerardwr notes that
* for some other types of remotes the MSB is not constant.
* Btn: 4-bit Control codes, this indicates the button that is pressed
* CRC: 4-bit Checksum.
* Ctn: 16-bit rolling code (big-endian) increased with every button press.
* Serial: 24-bit identifier of sending device (little-endian)
*
*
* Decrypt
*
* uint8_t frame[7];
* for (i=1; i < 7; i++) {
* frame[i] = frame[i] ^ frame[i-1];
* }
* or
* uint64 Decrypt = frame ^ (frame>>8);
*
* Btn
*
* Value Button(s) Description
* 0x1 My Stop or move to favourite position
* 0x2 Up Move up
* 0x3 My + Up Set upper motor limit in initial programming mode
* 0x4 Down Move down
* 0x5 My + Down Set lower motor limit in initial programming mode
* 0x6 Up + Down Change motor limit and initial programming mode
* 0x8 Prog Used for (de-)registering remotes, see below
* 0x9 Sun + Flag Enable sun and wind detector (SUN and FLAG symbol on the Telis Soliris RC)
* 0xA Flag Disable sun detector (FLAG symbol on the Telis Soliris RC)
*
* CRC
*
* uint8_t frame[7];
* for (i=0; i < 7; i++) {
* cksum = cksum ^ frame[i] ^ (frame[i] >> 4);
* }
* cksum = cksum & 0xf;
*
*/
uint64_t data = instance->common.code_last_found ^ (instance->common.code_last_found >> 8);
instance->common.btn = (data >> 44) & 0xF;
instance->common.cnt = (data >> 24) & 0xFFFF;
instance->common.serial = data & 0xFFFFFF;
}
uint8_t subghz_protocol_somfy_telis_crc(uint64_t data) {
uint8_t crc = 0;
data &= 0xFFF0FFFFFFFFFF;
for(uint8_t i = 0; i < 56; i += 8) {
crc = crc ^ data >> i ^ (data >> (i + 4));
}
return crc & 0xf;
}
const char* subghz_protocol_somfy_telis_get_name_button(uint8_t btn) {
const char* name_btn[0x10] = {
"Unknown",
"My",
"Up",
"My+Up",
"Down",
"My+Down",
"Up+Down",
"0x07",
"Prog",
"Sun+Flag",
"Flag",
"0x0B",
"0x0C",
"0x0D",
"0x0E",
"0x0F"};
return btn <= 0xf ? name_btn[btn] : name_btn[0];
}
void subghz_protocol_somfy_telis_reset(SubGhzProtocolSomfyTelis* instance) {
instance->common.parser_step = SomfyTelisDecoderStepReset;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
}
void subghz_protocol_somfy_telis_parse(
SubGhzProtocolSomfyTelis* instance,
bool level,
uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch(instance->common.parser_step) {
case SomfyTelisDecoderStepReset:
if((level) && DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta * 4) {
instance->common.parser_step = SomfyTelisDecoderStepFoundPreambula;
instance->common.header_count++;
}
break;
case SomfyTelisDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta * 4)) {
instance->common.parser_step = SomfyTelisDecoderStepCheckPreambula;
} else {
instance->common.header_count = 0;
instance->common.parser_step = SomfyTelisDecoderStepReset;
}
break;
case SomfyTelisDecoderStepCheckPreambula:
if(level) {
if(DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta * 4) {
instance->common.parser_step = SomfyTelisDecoderStepFoundPreambula;
instance->common.header_count++;
} else if(
(instance->common.header_count > 1) &&
(DURATION_DIFF(duration, instance->common.te_short * 7) <
instance->common.te_delta * 4)) {
instance->common.parser_step = SomfyTelisDecoderStepDecoderData;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->common.header_count = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
}
}
break;
case SomfyTelisDecoderStepDecoderData:
if(!level) {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortLow;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongLow;
} else if(duration >= (instance->common.te_long + instance->common.te_delta)) {
if(instance->common.code_count_bit ==
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
//check crc
uint64_t data_tmp = instance->common.code_last_found ^
(instance->common.code_last_found >> 8);
if(((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_telis_crc(data_tmp)) {
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
manchester_advance(
instance->manchester_saved_state,
ManchesterEventReset,
&instance->manchester_saved_state,
NULL);
manchester_advance(
instance->manchester_saved_state,
ManchesterEventLongHigh,
&instance->manchester_saved_state,
NULL);
instance->common.parser_step = SomfyTelisDecoderStepReset;
} else {
instance->common.parser_step = SomfyTelisDecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
event = ManchesterEventShortHigh;
} else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->common.parser_step = SomfyTelisDecoderStepReset;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
if(data_ok) {
instance->common.code_found = (instance->common.code_found << 1) | data;
instance->common.code_count_bit++;
}
}
break;
}
}
void subghz_protocol_somfy_telis_to_str(SubGhzProtocolSomfyTelis* instance, string_t output) {
subghz_protocol_somfy_telis_remote_controller(instance);
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %db\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%06lX \r\n"
"Cnt:0x%04X\r\n"
"Btn:%s\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
instance->common.serial,
instance->common.cnt,
subghz_protocol_somfy_telis_get_name_button(instance->common.btn));
}
void subghz_decoder_somfy_telis_to_load_protocol(SubGhzProtocolSomfyTelis* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_somfy_telis_remote_controller(instance);
}

View File

@@ -1,46 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolSomfyTelis SubGhzProtocolSomfyTelis;
/** Allocate SubGhzProtocolSomfyTelis
*
* @return SubGhzProtocolSomfyTelis*
*/
SubGhzProtocolSomfyTelis* subghz_protocol_somfy_telis_alloc();
/** Free SubGhzProtocolSomfyTelis
*
* @param instance
*/
void subghz_protocol_somfy_telis_free(SubGhzProtocolSomfyTelis* instance);
/** Reset internal state
* @param instance - SubGhzProtocolSomfyTelis instance
*/
void subghz_protocol_somfy_telis_reset(SubGhzProtocolSomfyTelis* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolSomfyTelis instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_somfy_telis_parse(
SubGhzProtocolSomfyTelis* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolSomfyTelis* instance
* @param output - output string
*/
void subghz_protocol_somfy_telis_to_str(SubGhzProtocolSomfyTelis* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolSomfyTelis instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_somfy_telis_to_load_protocol(SubGhzProtocolSomfyTelis* instance, void* context);

View File

@@ -1,341 +0,0 @@
#include "subghz_protocol_star_line.h"
#include "subghz_protocol_keeloq_common.h"
#include "../subghz_keystore.h"
#include <furi.h>
#include <m-string.h>
#include <m-array.h>
struct SubGhzProtocolStarLine {
SubGhzProtocolCommon common;
SubGhzKeystore* keystore;
const char* manufacture_name;
};
typedef enum {
StarLineDecoderStepReset = 0,
StarLineDecoderStepCheckPreambula,
StarLineDecoderStepSaveDuration,
StarLineDecoderStepCheckDuration,
} StarLineDecoderStep;
SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore) {
SubGhzProtocolStarLine* instance = malloc(sizeof(SubGhzProtocolStarLine));
instance->keystore = keystore;
instance->common.name = "Star Line";
instance->common.code_min_count_bit_for_found = 64;
instance->common.te_short = 250;
instance->common.te_long = 500;
instance->common.te_delta = 120;
instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_star_line_to_str;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_star_line_to_load_protocol;
return instance;
}
void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance) {
furi_assert(instance);
free(instance);
}
const char* subghz_protocol_star_line_find_and_get_manufacture_name(void* context) {
SubGhzProtocolStarLine* instance = context;
subghz_protocol_star_line_check_remote_controller(instance);
return instance->manufacture_name;
}
const char* subghz_protocol_star_line_get_manufacture_name(void* context) {
SubGhzProtocolStarLine* instance = context;
return instance->manufacture_name;
}
/** Send bit
*
* @param instance - SubGhzProtocolStarLine instance
* @param bit - bit
*/
void subghz_protocol_star_line_send_bit(SubGhzProtocolStarLine* instance, uint8_t bit) {
if(bit) {
//send bit 1
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_long);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long);
} else {
//send bit 0
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_short);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_short);
}
}
void subghz_protocol_star_line_send_key(
SubGhzProtocolStarLine* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat) {
while(repeat--) {
//Send header
for(uint8_t i = 0; i < 6; i++) {
SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_long * 2);
SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long * 2);
}
//Send Start bit ??????????
//Send key data
for(uint8_t i = bit; i > 0; i--) {
subghz_protocol_star_line_send_bit(instance, bit_read(key, i - 1));
}
//Send Stop bit ??????????
}
}
void subghz_protocol_star_line_reset(SubGhzProtocolStarLine* instance) {
instance->common.parser_step = StarLineDecoderStepReset;
}
/** Checking the accepted code against the database manafacture key
*
* @param instance SubGhzProtocolStarLine instance
* @param fix fix part of the parcel
* @param hop hop encrypted part of the parcel
* @return true on successful search
*/
uint8_t subghz_protocol_star_line_check_remote_controller_selector(
SubGhzProtocolStarLine* instance,
uint32_t fix,
uint32_t hop) {
uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint8_t btn = (uint8_t)(fix >> 24);
uint32_t decrypt = 0;
uint64_t man_normal_learning;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if((decrypt >> 24 == btn) &&
((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal_Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if((decrypt >> 24 == btn) &&
((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if((decrypt >> 24 == btn) &&
((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if((decrypt >> 24 == btn) &&
((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
//###########################
// Normal_Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if((decrypt >> 24 == btn) &&
((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
// Check for mirrored man
man_rev = 0;
man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if((decrypt >> 24 == btn) &&
((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
break;
}
}
instance->manufacture_name = "Unknown";
instance->common.cnt = 0;
return 0;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolStarLine instance
*/
void subghz_protocol_star_line_check_remote_controller(SubGhzProtocolStarLine* instance) {
uint64_t key = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff;
subghz_protocol_star_line_check_remote_controller_selector(instance, key_fix, key_hop);
instance->common.serial = key_fix & 0x00FFFFFF;
instance->common.btn = key_fix >> 24;
}
void subghz_protocol_star_line_parse(
SubGhzProtocolStarLine* instance,
bool level,
uint32_t duration) {
switch(instance->common.parser_step) {
case StarLineDecoderStepReset:
if(level) {
if(DURATION_DIFF(duration, instance->common.te_long * 2) <
instance->common.te_delta * 2) {
instance->common.parser_step = StarLineDecoderStepCheckPreambula;
instance->common.header_count++;
} else if(instance->common.header_count > 4) {
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->common.te_last = duration;
instance->common.parser_step = StarLineDecoderStepCheckDuration;
}
} else {
instance->common.header_count = 0;
}
break;
case StarLineDecoderStepCheckPreambula:
if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 2) <
instance->common.te_delta * 2)) {
//Found Preambula
instance->common.parser_step = StarLineDecoderStepReset;
} else {
instance->common.header_count = 0;
instance->common.parser_step = StarLineDecoderStepReset;
}
break;
case StarLineDecoderStepSaveDuration:
if(level) {
if(duration >= (instance->common.te_long + instance->common.te_delta)) {
instance->common.parser_step = StarLineDecoderStepReset;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
if(instance->common.code_last_found != instance->common.code_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->common.header_count = 0;
break;
} else {
instance->common.te_last = duration;
instance->common.parser_step = StarLineDecoderStepCheckDuration;
}
} else {
instance->common.parser_step = StarLineDecoderStepReset;
}
break;
case StarLineDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = StarLineDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = StarLineDecoderStepSaveDuration;
} else {
instance->common.parser_step = StarLineDecoderStepReset;
}
} else {
instance->common.parser_step = StarLineDecoderStepReset;
}
break;
}
}
void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output) {
subghz_protocol_star_line_check_remote_controller(instance);
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%02lX\r\n"
"MF:%s\r\n"
"Sn:0x%07lX \r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
instance->common.cnt,
code_found_reverse_lo,
instance->common.btn,
instance->manufacture_name,
instance->common.serial);
}
void subghz_decoder_star_line_to_load_protocol(SubGhzProtocolStarLine* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
subghz_protocol_star_line_check_remote_controller(instance);
}

View File

@@ -1,81 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzKeystore SubGhzKeystore;
typedef struct SubGhzProtocolStarLine SubGhzProtocolStarLine;
/** Allocate SubGhzProtocolStarLine
*
* @return SubGhzProtocolStarLine*
*/
SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore);
/** Free SubGhzProtocolStarLine
*
* @param instance
*/
void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance);
/** Find and get manufacture name
*
* @param context - SubGhzProtocolStarLine context
* @return name - char* manufacture name
*/
const char* subghz_protocol_star_line_find_and_get_manufacture_name(void* context);
/** Get manufacture name
*
* @param context - SubGhzProtocolStarLine context
* @return name - char* manufacture name
*/
const char* subghz_protocol_star_line_get_manufacture_name(void* context);
/** Sends the key on the air
*
* @param instance - SubGhzProtocolStarLine instance
* @param key - key send
* @param bit - count bit key
* @param repeat - repeat send key
*/
void subghz_protocol_star_line_send_key(
SubGhzProtocolStarLine* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat);
/** Reset internal state
* @param instance - SubGhzProtocolStarLine instance
*/
void subghz_protocol_star_line_reset(SubGhzProtocolStarLine* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolStarLine instance
*/
void subghz_protocol_star_line_check_remote_controller(SubGhzProtocolStarLine* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolStarLine instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_star_line_parse(
SubGhzProtocolStarLine* instance,
bool level,
uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolStarLine* instance
* @param output - output string
*/
void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output);
/** Loading protocol from bin data
*
* @param instance - SubGhzDecoderPrinceton instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_star_line_to_load_protocol(SubGhzProtocolStarLine* instance, void* context);

Some files were not shown because too many files have changed in this diff Show More