[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:
co-authored by
Aleksandr Kutuzov
DrZlo13
parent
052237f8c9
commit
3164184bbc
+1
-1
@@ -20,6 +20,6 @@
|
||||
- `qrcode` - Qr code generator library
|
||||
- `ST25RFAL002` - ST253916 driver and NFC hal
|
||||
- `STM32CubeWB` - STM32WB series cube package
|
||||
- `subghz` - Subghz library
|
||||
- `subghz` - SubGhz library
|
||||
- `toolbox` - Toolbox of things that we are using but don't place in core
|
||||
- `u8g2` - Graphics library that we use to draw GUI
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "const.h"
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "encoder.h"
|
||||
|
||||
#define TAG "SubGhzBlockEncoder"
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
+2
-2
@@ -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;
|
||||
+4
-4
@@ -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
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
/*
|
||||
* https://phreakerclub.com/616
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user