|
|
@@ -0,0 +1,1120 @@
|
|
|
+#include "bin_raw.h"
|
|
|
+
|
|
|
+#include "../blocks/const.h"
|
|
|
+#include "../blocks/decoder.h"
|
|
|
+#include "../blocks/encoder.h"
|
|
|
+#include "../blocks/generic.h"
|
|
|
+#include "../blocks/math.h"
|
|
|
+#include <lib/toolbox/float_tools.h>
|
|
|
+#include <lib/toolbox/stream/stream.h>
|
|
|
+#include <lib/flipper_format/flipper_format_i.h>
|
|
|
+
|
|
|
+#define TAG "SubGhzProtocolBinRAW"
|
|
|
+
|
|
|
+//change very carefully, RAM ends at the most inopportune moment
|
|
|
+#define BIN_RAW_BUF_RAW_SIZE 2048
|
|
|
+#define BIN_RAW_BUF_DATA_SIZE 512
|
|
|
+
|
|
|
+#define BIN_RAW_THRESHOLD_RSSI -85.0f
|
|
|
+#define BIN_RAW_DELTA_RSSI 7.0f
|
|
|
+#define BIN_RAW_SEARCH_CLASSES 20
|
|
|
+#define BIN_RAW_TE_MIN_COUNT 40
|
|
|
+#define BIN_RAW_BUF_MIN_DATA_COUNT 128
|
|
|
+#define BIN_RAW_MAX_MARKUP_COUNT 20
|
|
|
+
|
|
|
+//#define BIN_RAW_DEBUG
|
|
|
+
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+#define bin_raw_debug(...) FURI_LOG_RAW_D(__VA_ARGS__)
|
|
|
+#define bin_raw_debug_tag(tag, ...) \
|
|
|
+ FURI_LOG_RAW_D("\033[0;32m[" tag "]\033[0m "); \
|
|
|
+ FURI_LOG_RAW_D(__VA_ARGS__)
|
|
|
+#else
|
|
|
+#define bin_raw_debug(...)
|
|
|
+#define bin_raw_debug_tag(...)
|
|
|
+#endif
|
|
|
+
|
|
|
+static const SubGhzBlockConst subghz_protocol_bin_raw_const = {
|
|
|
+ .te_short = 30,
|
|
|
+ .te_long = 65000,
|
|
|
+ .te_delta = 0,
|
|
|
+ .min_count_bit_for_found = 0,
|
|
|
+};
|
|
|
+
|
|
|
+typedef enum {
|
|
|
+ BinRAWDecoderStepReset = 0,
|
|
|
+ BinRAWDecoderStepWrite,
|
|
|
+ BinRAWDecoderStepBufFull,
|
|
|
+ BinRAWDecoderStepNoParse,
|
|
|
+} BinRAWDecoderStep;
|
|
|
+
|
|
|
+typedef enum {
|
|
|
+ BinRAWTypeUnknown = 0,
|
|
|
+ BinRAWTypeNoGap,
|
|
|
+ BinRAWTypeGap,
|
|
|
+ BinRAWTypeGapRecurring,
|
|
|
+ BinRAWTypeGapRolling,
|
|
|
+ BinRAWTypeGapUnknown,
|
|
|
+} BinRAWType;
|
|
|
+
|
|
|
+struct BinRAW_Markup {
|
|
|
+ uint16_t byte_bias;
|
|
|
+ uint16_t bit_count;
|
|
|
+};
|
|
|
+typedef struct BinRAW_Markup BinRAW_Markup;
|
|
|
+
|
|
|
+struct SubGhzProtocolDecoderBinRAW {
|
|
|
+ SubGhzProtocolDecoderBase base;
|
|
|
+
|
|
|
+ SubGhzBlockDecoder decoder;
|
|
|
+ SubGhzBlockGeneric generic;
|
|
|
+ int32_t* data_raw;
|
|
|
+ uint8_t* data;
|
|
|
+ BinRAW_Markup data_markup[BIN_RAW_MAX_MARKUP_COUNT];
|
|
|
+ size_t data_raw_ind;
|
|
|
+ uint32_t te;
|
|
|
+ float adaptive_threshold_rssi;
|
|
|
+};
|
|
|
+
|
|
|
+struct SubGhzProtocolEncoderBinRAW {
|
|
|
+ SubGhzProtocolEncoderBase base;
|
|
|
+
|
|
|
+ SubGhzProtocolBlockEncoder encoder;
|
|
|
+ SubGhzBlockGeneric generic;
|
|
|
+
|
|
|
+ uint8_t* data;
|
|
|
+ BinRAW_Markup data_markup[BIN_RAW_MAX_MARKUP_COUNT];
|
|
|
+ uint32_t te;
|
|
|
+};
|
|
|
+
|
|
|
+const SubGhzProtocolDecoder subghz_protocol_bin_raw_decoder = {
|
|
|
+ .alloc = subghz_protocol_decoder_bin_raw_alloc,
|
|
|
+ .free = subghz_protocol_decoder_bin_raw_free,
|
|
|
+
|
|
|
+ .feed = subghz_protocol_decoder_bin_raw_feed,
|
|
|
+ .reset = subghz_protocol_decoder_bin_raw_reset,
|
|
|
+
|
|
|
+ .get_hash_data = subghz_protocol_decoder_bin_raw_get_hash_data,
|
|
|
+ .serialize = subghz_protocol_decoder_bin_raw_serialize,
|
|
|
+ .deserialize = subghz_protocol_decoder_bin_raw_deserialize,
|
|
|
+ .get_string = subghz_protocol_decoder_bin_raw_get_string,
|
|
|
+};
|
|
|
+
|
|
|
+const SubGhzProtocolEncoder subghz_protocol_bin_raw_encoder = {
|
|
|
+ .alloc = subghz_protocol_encoder_bin_raw_alloc,
|
|
|
+ .free = subghz_protocol_encoder_bin_raw_free,
|
|
|
+
|
|
|
+ .deserialize = subghz_protocol_encoder_bin_raw_deserialize,
|
|
|
+ .stop = subghz_protocol_encoder_bin_raw_stop,
|
|
|
+ .yield = subghz_protocol_encoder_bin_raw_yield,
|
|
|
+};
|
|
|
+
|
|
|
+const SubGhzProtocol subghz_protocol_bin_raw = {
|
|
|
+ .name = SUBGHZ_PROTOCOL_BIN_RAW_NAME,
|
|
|
+ .type = SubGhzProtocolTypeStatic,
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
|
|
|
+ SubGhzProtocolFlag_AM | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable |
|
|
|
+ SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
|
|
|
+#else
|
|
|
+ .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
|
|
|
+ SubGhzProtocolFlag_AM | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_BinRAW |
|
|
|
+ SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
|
|
|
+#endif
|
|
|
+ .decoder = &subghz_protocol_bin_raw_decoder,
|
|
|
+ .encoder = &subghz_protocol_bin_raw_encoder,
|
|
|
+};
|
|
|
+
|
|
|
+static uint16_t subghz_protocol_bin_raw_get_full_byte(uint16_t bit_count) {
|
|
|
+ if(bit_count & 0x7) {
|
|
|
+ return (bit_count >> 3) + 1;
|
|
|
+ } else {
|
|
|
+ return (bit_count >> 3);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment) {
|
|
|
+ UNUSED(environment);
|
|
|
+ SubGhzProtocolEncoderBinRAW* instance = malloc(sizeof(SubGhzProtocolEncoderBinRAW));
|
|
|
+
|
|
|
+ instance->base.protocol = &subghz_protocol_bin_raw;
|
|
|
+ instance->generic.protocol_name = instance->base.protocol->name;
|
|
|
+
|
|
|
+ instance->encoder.repeat = 10;
|
|
|
+ instance->encoder.size_upload = BIN_RAW_BUF_DATA_SIZE * 5;
|
|
|
+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
|
|
|
+ instance->data = malloc(instance->encoder.size_upload * sizeof(uint8_t));
|
|
|
+ memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+ instance->encoder.is_running = false;
|
|
|
+ return instance;
|
|
|
+}
|
|
|
+
|
|
|
+void subghz_protocol_encoder_bin_raw_free(void* context) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolEncoderBinRAW* instance = context;
|
|
|
+ free(instance->encoder.upload);
|
|
|
+ free(instance->data);
|
|
|
+ free(instance);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Generating an upload from data.
|
|
|
+ * @param instance Pointer to a SubGhzProtocolEncoderBinRAW instance
|
|
|
+ * @return true On success
|
|
|
+ */
|
|
|
+static bool subghz_protocol_encoder_bin_raw_get_upload(SubGhzProtocolEncoderBinRAW* instance) {
|
|
|
+ furi_assert(instance);
|
|
|
+
|
|
|
+ //we glue all the pieces of the package into 1 long sequence with left alignment,
|
|
|
+ //in the uploaded data we have right alignment.
|
|
|
+
|
|
|
+ bin_raw_debug_tag(TAG, "Recovery of offset bits in sequences\r\n");
|
|
|
+ uint16_t i = 0;
|
|
|
+ uint16_t ind = 0;
|
|
|
+ bin_raw_debug("\tind byte_bias\tbit_count\tbit_bias\r\n");
|
|
|
+ while((i < BIN_RAW_MAX_MARKUP_COUNT) && (instance->data_markup[i].bit_count != 0)) {
|
|
|
+ uint8_t bit_bias =
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count) * 8 -
|
|
|
+ instance->data_markup[i].bit_count;
|
|
|
+ bin_raw_debug(
|
|
|
+ "\t%d\t%d\t%d :\t\t%d\r\n",
|
|
|
+ i,
|
|
|
+ instance->data_markup[i].byte_bias,
|
|
|
+ instance->data_markup[i].bit_count,
|
|
|
+ bit_bias);
|
|
|
+ for(uint16_t y = instance->data_markup[i].byte_bias * 8;
|
|
|
+ y < instance->data_markup[i].byte_bias * 8 +
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count) * 8 -
|
|
|
+ bit_bias;
|
|
|
+ y++) {
|
|
|
+ subghz_protocol_blocks_set_bit_array(
|
|
|
+ subghz_protocol_blocks_get_bit_array(instance->data, y + bit_bias),
|
|
|
+ instance->data,
|
|
|
+ ind++,
|
|
|
+ BIN_RAW_BUF_DATA_SIZE);
|
|
|
+ }
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n");
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug_tag(TAG, "Restored Sequence left aligned\r\n");
|
|
|
+ for(uint16_t y = 0; y < subghz_protocol_bin_raw_get_full_byte(ind); y++) {
|
|
|
+ bin_raw_debug("%02X ", instance->data[y]);
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n\tbin_count_result= %d\r\n\r\n", ind);
|
|
|
+
|
|
|
+ bin_raw_debug_tag(
|
|
|
+ TAG, "Maximum levels encoded in upload %zu\r\n", instance->encoder.size_upload);
|
|
|
+#endif
|
|
|
+ instance->encoder.size_upload = subghz_protocol_blocks_get_upload_from_bit_array(
|
|
|
+ instance->data,
|
|
|
+ ind,
|
|
|
+ instance->encoder.upload,
|
|
|
+ instance->encoder.size_upload,
|
|
|
+ instance->te,
|
|
|
+ SubGhzProtocolBlockAlignBitLeft);
|
|
|
+
|
|
|
+ bin_raw_debug_tag(TAG, "The result %zu is levels\r\n", instance->encoder.size_upload);
|
|
|
+ bin_raw_debug_tag(TAG, "Remaining free memory %zu\r\n", memmgr_get_free_heap());
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolEncoderBinRAW* instance = context;
|
|
|
+
|
|
|
+ bool res = false;
|
|
|
+ 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->generic.data_count_bit = (uint16_t)temp_data;
|
|
|
+
|
|
|
+ if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) {
|
|
|
+ FURI_LOG_E(TAG, "Missing TE");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ temp_data = 0;
|
|
|
+ uint16_t ind = 0;
|
|
|
+ uint16_t byte_bias = 0;
|
|
|
+ uint16_t byte_count = 0;
|
|
|
+ memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+ while(flipper_format_read_uint32(flipper_format, "Bit_RAW", (uint32_t*)&temp_data, 1)) {
|
|
|
+ if(ind >= BIN_RAW_MAX_MARKUP_COUNT) {
|
|
|
+ FURI_LOG_E(TAG, "Markup overflow");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ byte_count += subghz_protocol_bin_raw_get_full_byte(temp_data);
|
|
|
+ if(byte_count > BIN_RAW_BUF_DATA_SIZE) {
|
|
|
+ FURI_LOG_E(TAG, "Receive buffer overflow");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ instance->data_markup[ind].bit_count = temp_data;
|
|
|
+ instance->data_markup[ind].byte_bias = byte_bias;
|
|
|
+ byte_bias += subghz_protocol_bin_raw_get_full_byte(temp_data);
|
|
|
+
|
|
|
+ if(!flipper_format_read_hex(
|
|
|
+ flipper_format,
|
|
|
+ "Data_RAW",
|
|
|
+ instance->data + instance->data_markup[ind].byte_bias,
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(temp_data))) {
|
|
|
+ instance->data_markup[ind].bit_count = 0;
|
|
|
+ FURI_LOG_E(TAG, "Missing Data_RAW");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ ind++;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ uint16_t i = 0;
|
|
|
+ bin_raw_debug_tag(TAG, "Download data to encoder\r\n");
|
|
|
+ bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data");
|
|
|
+ while((i < BIN_RAW_MAX_MARKUP_COUNT) && (instance->data_markup[i].bit_count != 0)) {
|
|
|
+ bin_raw_debug(
|
|
|
+ "\r\n\t%d\t%d\t%d :\t",
|
|
|
+ i,
|
|
|
+ instance->data_markup[i].byte_bias,
|
|
|
+ instance->data_markup[i].bit_count);
|
|
|
+ for(uint16_t y = instance->data_markup[i].byte_bias;
|
|
|
+ y < instance->data_markup[i].byte_bias +
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count);
|
|
|
+ y++) {
|
|
|
+ bin_raw_debug("%02X ", instance->data[y]);
|
|
|
+ }
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n\r\n");
|
|
|
+#endif
|
|
|
+ if(!flipper_format_rewind(flipper_format)) {
|
|
|
+ FURI_LOG_E(TAG, "Rewind error");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ //optional parameter parameter
|
|
|
+ flipper_format_read_uint32(
|
|
|
+ flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
|
|
|
+
|
|
|
+ if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) break;
|
|
|
+ instance->encoder.is_running = true;
|
|
|
+
|
|
|
+ res = true;
|
|
|
+ } while(0);
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+void subghz_protocol_encoder_bin_raw_stop(void* context) {
|
|
|
+ SubGhzProtocolEncoderBinRAW* instance = context;
|
|
|
+ instance->encoder.is_running = false;
|
|
|
+}
|
|
|
+
|
|
|
+LevelDuration subghz_protocol_encoder_bin_raw_yield(void* context) {
|
|
|
+ SubGhzProtocolEncoderBinRAW* instance = context;
|
|
|
+
|
|
|
+ if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
|
|
|
+ instance->encoder.is_running = false;
|
|
|
+ return level_duration_reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
|
|
+
|
|
|
+ if(++instance->encoder.front == instance->encoder.size_upload) {
|
|
|
+ instance->encoder.repeat--;
|
|
|
+ instance->encoder.front = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+void* subghz_protocol_decoder_bin_raw_alloc(SubGhzEnvironment* environment) {
|
|
|
+ UNUSED(environment);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = malloc(sizeof(SubGhzProtocolDecoderBinRAW));
|
|
|
+ instance->base.protocol = &subghz_protocol_bin_raw;
|
|
|
+ instance->generic.protocol_name = instance->base.protocol->name;
|
|
|
+ instance->data_raw_ind = 0;
|
|
|
+ instance->data_raw = malloc(BIN_RAW_BUF_RAW_SIZE * sizeof(int32_t));
|
|
|
+ instance->data = malloc(BIN_RAW_BUF_RAW_SIZE * sizeof(uint8_t));
|
|
|
+ memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+ instance->adaptive_threshold_rssi = BIN_RAW_THRESHOLD_RSSI;
|
|
|
+ return instance;
|
|
|
+}
|
|
|
+
|
|
|
+void subghz_protocol_decoder_bin_raw_free(void* context) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = context;
|
|
|
+ free(instance->data_raw);
|
|
|
+ free(instance->data);
|
|
|
+ free(instance);
|
|
|
+}
|
|
|
+
|
|
|
+void subghz_protocol_decoder_bin_raw_reset(void* context) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = context;
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ UNUSED(instance);
|
|
|
+#else
|
|
|
+ instance->decoder.parser_step = BinRAWDecoderStepNoParse;
|
|
|
+ instance->data_raw_ind = 0;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void subghz_protocol_decoder_bin_raw_feed(void* context, bool level, uint32_t duration) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = context;
|
|
|
+
|
|
|
+ if(instance->decoder.parser_step == BinRAWDecoderStepWrite) {
|
|
|
+ if(instance->data_raw_ind == BIN_RAW_BUF_RAW_SIZE) {
|
|
|
+ instance->decoder.parser_step = BinRAWDecoderStepBufFull;
|
|
|
+ } else {
|
|
|
+ instance->data_raw[instance->data_raw_ind++] = (level ? duration : -duration);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Analysis of received data
|
|
|
+ * @param instance Pointer to a SubGhzProtocolDecoderBinRAW* instance
|
|
|
+ */
|
|
|
+static bool
|
|
|
+ subghz_protocol_bin_raw_check_remote_controller(SubGhzProtocolDecoderBinRAW* instance) {
|
|
|
+ struct {
|
|
|
+ float data;
|
|
|
+ uint16_t count;
|
|
|
+ } classes[BIN_RAW_SEARCH_CLASSES];
|
|
|
+
|
|
|
+ size_t ind = 0;
|
|
|
+
|
|
|
+ memset(classes, 0x00, sizeof(classes));
|
|
|
+
|
|
|
+ uint16_t data_markup_ind = 0;
|
|
|
+ memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+
|
|
|
+ if(instance->data_raw_ind < 512) {
|
|
|
+ ind =
|
|
|
+ instance->data_raw_ind -
|
|
|
+ 100; //there is usually garbage at the end of the record, we exclude it from the classification
|
|
|
+ } else {
|
|
|
+ ind = 512;
|
|
|
+ }
|
|
|
+
|
|
|
+ //sort the durations to find the shortest correlated interval
|
|
|
+ for(size_t i = 0; i < ind; i++) {
|
|
|
+ for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) {
|
|
|
+ if(classes[k].count == 0) {
|
|
|
+ classes[k].data = (float)(abs(instance->data_raw[i]));
|
|
|
+ classes[k].count++;
|
|
|
+ break;
|
|
|
+ } else if(
|
|
|
+ DURATION_DIFF((float)(abs(instance->data_raw[i])), (classes[k].data)) <
|
|
|
+ (classes[k].data / 4)) { //if the test value does not differ by more than 25%
|
|
|
+ classes[k].data += ((float)(abs(instance->data_raw[i])) - classes[k].data) *
|
|
|
+ 0.05f; //running average k=0.05
|
|
|
+ classes[k].count++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // if(classes[BIN_RAW_SEARCH_CLASSES - 1].count != 0) {
|
|
|
+ // //filling the classifier, it means that they received an unclean signal
|
|
|
+ // return false;
|
|
|
+ // }
|
|
|
+
|
|
|
+ //looking for the minimum te with an occurrence greater than BIN_RAW_TE_MIN_COUNT
|
|
|
+ instance->te = subghz_protocol_bin_raw_const.te_long * 2;
|
|
|
+
|
|
|
+ bool te_ok = false;
|
|
|
+ uint16_t gap_ind = 0;
|
|
|
+ uint16_t gap_delta = 0;
|
|
|
+ uint32_t gap = 0;
|
|
|
+ int data_temp = 0;
|
|
|
+ BinRAWType bin_raw_type = BinRAWTypeUnknown;
|
|
|
+
|
|
|
+ //sort by number of occurrences
|
|
|
+ bool swap = true;
|
|
|
+ while(swap) {
|
|
|
+ swap = false;
|
|
|
+ for(size_t i = 1; i < BIN_RAW_SEARCH_CLASSES; i++) {
|
|
|
+ if(classes[i].count > classes[i - 1].count) {
|
|
|
+ uint32_t data = classes[i - 1].data;
|
|
|
+ uint32_t count = classes[i - 1].count;
|
|
|
+ classes[i - 1].data = classes[i].data;
|
|
|
+ classes[i - 1].count = classes[i].count;
|
|
|
+ classes[i].data = data;
|
|
|
+ classes[i].count = count;
|
|
|
+ swap = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug_tag(TAG, "Sorted durations\r\n");
|
|
|
+ bin_raw_debug("\t\tind\tcount\tus\r\n");
|
|
|
+ for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) {
|
|
|
+ bin_raw_debug("\t\t%zu\t%u\t%lu\r\n", k, classes[k].count, (uint32_t)classes[k].data);
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n");
|
|
|
+#endif
|
|
|
+ if((classes[0].count > BIN_RAW_TE_MIN_COUNT) && (classes[1].count == 0)) {
|
|
|
+ //adopted only the preamble
|
|
|
+ instance->te = (uint32_t)classes[0].data;
|
|
|
+ te_ok = true;
|
|
|
+ gap = 0; //gap no
|
|
|
+ } else {
|
|
|
+ //take the 2 most common durations
|
|
|
+ //check that there are enough
|
|
|
+ if((classes[0].count < BIN_RAW_TE_MIN_COUNT) ||
|
|
|
+ (classes[1].count < (BIN_RAW_TE_MIN_COUNT >> 1)))
|
|
|
+ return false;
|
|
|
+ //arrange the first 2 date values in ascending order
|
|
|
+ if(classes[0].data > classes[1].data) {
|
|
|
+ uint32_t data = classes[1].data;
|
|
|
+ classes[0].data = classes[1].data;
|
|
|
+ classes[1].data = data;
|
|
|
+ }
|
|
|
+
|
|
|
+ //determine the value to be corrected
|
|
|
+ for(uint8_t k = 1; k < 5; k++) {
|
|
|
+ float delta = (classes[1].data / (classes[0].data / k));
|
|
|
+ bin_raw_debug_tag(TAG, "K_div= %f\r\n", (double)(delta));
|
|
|
+ delta -= (uint32_t)delta;
|
|
|
+
|
|
|
+ if((delta < 0.20f) || (delta > 0.80f)) {
|
|
|
+ instance->te = (uint32_t)classes[0].data / k;
|
|
|
+ bin_raw_debug_tag(TAG, "K= %d\r\n", k);
|
|
|
+ te_ok = true; //found a correlated duration
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!te_ok) {
|
|
|
+ //did not find the minimum TE satisfying the condition
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ bin_raw_debug_tag(TAG, "TE= %lu\r\n\r\n", instance->te);
|
|
|
+
|
|
|
+ //looking for a gap
|
|
|
+ for(size_t k = 2; k < BIN_RAW_SEARCH_CLASSES; k++) {
|
|
|
+ if((classes[k].count > 2) && (classes[k].data > gap)) {
|
|
|
+ gap = (uint32_t)classes[k].data;
|
|
|
+ gap_delta = gap / 5; //calculate 20% deviation from ideal value
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if((gap / instance->te) <
|
|
|
+ 10) { //make an assumption, the longest gap should be more than 10 TE
|
|
|
+ gap = 0; //check that our signal has a gap greater than 10*TE
|
|
|
+ bin_raw_type = BinRAWTypeNoGap;
|
|
|
+ } else {
|
|
|
+ bin_raw_type = BinRAWTypeGap;
|
|
|
+ //looking for the last occurrence of gap
|
|
|
+ ind = instance->data_raw_ind - 1;
|
|
|
+ while((ind > 0) && (DURATION_DIFF(abs(instance->data_raw[ind]), gap) > gap_delta)) {
|
|
|
+ ind--;
|
|
|
+ }
|
|
|
+ gap_ind = ind;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //if we consider that there is a gap, then we divide the signal with respect to this gap
|
|
|
+ //processing input data from the end
|
|
|
+ if(bin_raw_type == BinRAWTypeGap) {
|
|
|
+ bin_raw_debug_tag(TAG, "Tinted sequence\r\n");
|
|
|
+ ind = (BIN_RAW_BUF_DATA_SIZE * 8);
|
|
|
+ uint16_t bit_count = 0;
|
|
|
+ do {
|
|
|
+ gap_ind--;
|
|
|
+ data_temp = (int)(round((float)(instance->data_raw[gap_ind]) / instance->te));
|
|
|
+ bin_raw_debug("%d ", data_temp);
|
|
|
+ if(data_temp == 0) bit_count++; //there is noise in the package
|
|
|
+ for(size_t i = 0; i < abs(data_temp); i++) {
|
|
|
+ bit_count++;
|
|
|
+ if(ind) {
|
|
|
+ ind--;
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if(data_temp > 0) {
|
|
|
+ subghz_protocol_blocks_set_bit_array(
|
|
|
+ true, instance->data, ind, BIN_RAW_BUF_DATA_SIZE);
|
|
|
+ } else {
|
|
|
+ subghz_protocol_blocks_set_bit_array(
|
|
|
+ false, instance->data, ind, BIN_RAW_BUF_DATA_SIZE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //split into full bytes if gap is caught
|
|
|
+ if(DURATION_DIFF(abs(instance->data_raw[gap_ind]), gap) < gap_delta) {
|
|
|
+ instance->data_markup[data_markup_ind].byte_bias = ind >> 3;
|
|
|
+ instance->data_markup[data_markup_ind++].bit_count = bit_count;
|
|
|
+ bit_count = 0;
|
|
|
+
|
|
|
+ if(data_markup_ind == BIN_RAW_MAX_MARKUP_COUNT) break;
|
|
|
+ ind &= 0xFFFFFFF8; //jump to the pre whole byte
|
|
|
+ }
|
|
|
+ } while(gap_ind != 0);
|
|
|
+ if((data_markup_ind != BIN_RAW_MAX_MARKUP_COUNT) && (ind != 0)) {
|
|
|
+ instance->data_markup[data_markup_ind].byte_bias = ind >> 3;
|
|
|
+ instance->data_markup[data_markup_ind++].bit_count = bit_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ bin_raw_debug("\r\n\t count bit= %zu\r\n\r\n", (BIN_RAW_BUF_DATA_SIZE * 8) - ind);
|
|
|
+
|
|
|
+ //reset the classifier and classify the received data
|
|
|
+ memset(classes, 0x00, sizeof(classes));
|
|
|
+
|
|
|
+ bin_raw_debug_tag(TAG, "Sort the found pieces by the number of bits in them\r\n");
|
|
|
+ for(size_t i = 0; i < data_markup_ind; i++) {
|
|
|
+ for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) {
|
|
|
+ if(classes[k].count == 0) {
|
|
|
+ classes[k].data = instance->data_markup[i].bit_count;
|
|
|
+ classes[k].count++;
|
|
|
+ break;
|
|
|
+ } else if(instance->data_markup[i].bit_count == (uint16_t)classes[k].data) {
|
|
|
+ classes[k].count++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug("\t\tind\tcount\tus\r\n");
|
|
|
+ for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) {
|
|
|
+ bin_raw_debug("\t\t%zu\t%u\t%lu\r\n", k, classes[k].count, (uint32_t)classes[k].data);
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+ //choose the value with the maximum repetition
|
|
|
+ data_temp = 0;
|
|
|
+ for(size_t i = 0; i < BIN_RAW_SEARCH_CLASSES; i++) {
|
|
|
+ if((classes[i].count > 1) && (data_temp < classes[i].count))
|
|
|
+ data_temp = (int)classes[i].data;
|
|
|
+ }
|
|
|
+
|
|
|
+ //if(data_markup_ind == 0) return false;
|
|
|
+
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ //output in reverse order
|
|
|
+ bin_raw_debug_tag(TAG, "Found sequences\r\n");
|
|
|
+ bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data\r\n");
|
|
|
+ uint16_t data_markup_ind_temp = data_markup_ind;
|
|
|
+ if(data_markup_ind) {
|
|
|
+ data_markup_ind_temp--;
|
|
|
+ for(size_t i = (ind / 8); i < BIN_RAW_BUF_DATA_SIZE; i++) {
|
|
|
+ if(instance->data_markup[data_markup_ind_temp].byte_bias == i) {
|
|
|
+ bin_raw_debug(
|
|
|
+ "\r\n\t%d\t%d\t%d :\t",
|
|
|
+ data_markup_ind_temp,
|
|
|
+ instance->data_markup[data_markup_ind_temp].byte_bias,
|
|
|
+ instance->data_markup[data_markup_ind_temp].bit_count);
|
|
|
+ if(data_markup_ind_temp != 0) data_markup_ind_temp--;
|
|
|
+ }
|
|
|
+ bin_raw_debug("%02X ", instance->data[i]);
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n\r\n");
|
|
|
+ }
|
|
|
+ //compare data in chunks with the same number of bits
|
|
|
+ bin_raw_debug_tag(TAG, "Analyze sequences of long %d bit\r\n\r\n", data_temp);
|
|
|
+#endif
|
|
|
+
|
|
|
+ //if(data_temp == 0) data_temp = (int)classes[0].data;
|
|
|
+
|
|
|
+ if(data_temp != 0) {
|
|
|
+ //check that data in transmission is repeated every packet
|
|
|
+ for(uint16_t i = 0; i < data_markup_ind - 1; i++) {
|
|
|
+ if((instance->data_markup[i].bit_count == data_temp) &&
|
|
|
+ (instance->data_markup[i + 1].bit_count == data_temp)) {
|
|
|
+ //if the number of bits in adjacent parcels is the same, compare the data
|
|
|
+ bin_raw_debug_tag(
|
|
|
+ TAG,
|
|
|
+ "Comparison of neighboring sequences ind_1=%d ind_2=%d %02X=%02X .... %02X=%02X\r\n",
|
|
|
+ i,
|
|
|
+ i + 1,
|
|
|
+ instance->data[instance->data_markup[i].byte_bias],
|
|
|
+ instance->data[instance->data_markup[i + 1].byte_bias],
|
|
|
+ instance->data
|
|
|
+ [instance->data_markup[i].byte_bias +
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(
|
|
|
+ instance->data_markup[i].bit_count) -
|
|
|
+ 1],
|
|
|
+ instance->data
|
|
|
+ [instance->data_markup[i + 1].byte_bias +
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(
|
|
|
+ instance->data_markup[i + 1].bit_count) -
|
|
|
+ 1]);
|
|
|
+
|
|
|
+ uint16_t byte_count =
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count);
|
|
|
+ if(memcmp(
|
|
|
+ instance->data + instance->data_markup[i].byte_bias,
|
|
|
+ instance->data + instance->data_markup[i + 1].byte_bias,
|
|
|
+ byte_count - 1) == 0) {
|
|
|
+ bin_raw_debug_tag(
|
|
|
+ TAG, "Match found bin_raw_type=BinRAWTypeGapRecurring\r\n\r\n");
|
|
|
+
|
|
|
+ //place in 1 element the offset to valid data
|
|
|
+ instance->data_markup[0].bit_count = instance->data_markup[i].bit_count;
|
|
|
+ instance->data_markup[0].byte_bias = instance->data_markup[i].byte_bias;
|
|
|
+ //markup end sign
|
|
|
+ instance->data_markup[1].bit_count = 0;
|
|
|
+ instance->data_markup[1].byte_bias = 0;
|
|
|
+
|
|
|
+ bin_raw_type = BinRAWTypeGapRecurring;
|
|
|
+ i = data_markup_ind;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(bin_raw_type == BinRAWTypeGap) {
|
|
|
+ // check that retry occurs every n packets
|
|
|
+ for(uint16_t i = 0; i < data_markup_ind - 2; i++) {
|
|
|
+ uint16_t byte_count =
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count);
|
|
|
+ for(uint16_t y = i + 1; y < data_markup_ind - 1; y++) {
|
|
|
+ bin_raw_debug_tag(
|
|
|
+ TAG,
|
|
|
+ "Comparison every N sequences ind_1=%d ind_2=%d %02X=%02X .... %02X=%02X\r\n",
|
|
|
+ i,
|
|
|
+ y,
|
|
|
+ instance->data[instance->data_markup[i].byte_bias],
|
|
|
+ instance->data[instance->data_markup[y].byte_bias],
|
|
|
+ instance->data
|
|
|
+ [instance->data_markup[i].byte_bias +
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(
|
|
|
+ instance->data_markup[i].bit_count) -
|
|
|
+ 1],
|
|
|
+ instance->data
|
|
|
+ [instance->data_markup[y].byte_bias +
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(
|
|
|
+ instance->data_markup[y].bit_count) -
|
|
|
+ 1]);
|
|
|
+
|
|
|
+ if(byte_count ==
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(
|
|
|
+ instance->data_markup[y].bit_count)) { //if the length in bytes matches
|
|
|
+
|
|
|
+ if((memcmp(
|
|
|
+ instance->data + instance->data_markup[i].byte_bias,
|
|
|
+ instance->data + instance->data_markup[y].byte_bias,
|
|
|
+ byte_count - 1) == 0) &&
|
|
|
+ (memcmp(
|
|
|
+ instance->data + instance->data_markup[i + 1].byte_bias,
|
|
|
+ instance->data + instance->data_markup[y + 1].byte_bias,
|
|
|
+ byte_count - 1) == 0)) {
|
|
|
+ uint8_t index = 0;
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug_tag(
|
|
|
+ TAG, "Match found bin_raw_type=BinRAWTypeGapRolling\r\n\r\n");
|
|
|
+ //output in reverse order
|
|
|
+ bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data\r\n");
|
|
|
+ index = y - 1;
|
|
|
+ for(size_t z = instance->data_markup[y].byte_bias + byte_count;
|
|
|
+ z < instance->data_markup[i].byte_bias + byte_count;
|
|
|
+ z++) {
|
|
|
+ if(instance->data_markup[index].byte_bias == z) {
|
|
|
+ bin_raw_debug(
|
|
|
+ "\r\n\t%d\t%d\t%d :\t",
|
|
|
+ index,
|
|
|
+ instance->data_markup[index].byte_bias,
|
|
|
+ instance->data_markup[index].bit_count);
|
|
|
+ if(index != 0) index--;
|
|
|
+ }
|
|
|
+ bin_raw_debug("%02X ", instance->data[z]);
|
|
|
+ }
|
|
|
+
|
|
|
+ bin_raw_debug("\r\n\r\n");
|
|
|
+#endif
|
|
|
+ //todo can be optimized
|
|
|
+ BinRAW_Markup markup_temp[BIN_RAW_MAX_MARKUP_COUNT];
|
|
|
+ memcpy(
|
|
|
+ markup_temp,
|
|
|
+ instance->data_markup,
|
|
|
+ BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+ memset(
|
|
|
+ instance->data_markup,
|
|
|
+ 0x00,
|
|
|
+ BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+
|
|
|
+ for(index = i; index < y; index++) {
|
|
|
+ instance->data_markup[index - i].bit_count =
|
|
|
+ markup_temp[y - index - 1].bit_count;
|
|
|
+ instance->data_markup[index - i].byte_bias =
|
|
|
+ markup_temp[y - index - 1].byte_bias;
|
|
|
+ }
|
|
|
+
|
|
|
+ bin_raw_type = BinRAWTypeGapRolling;
|
|
|
+ i = data_markup_ind;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //todo can be optimized
|
|
|
+ if(bin_raw_type == BinRAWTypeGap) {
|
|
|
+ if(data_temp != 0) { //there are sequences with the same number of bits
|
|
|
+
|
|
|
+ BinRAW_Markup markup_temp[BIN_RAW_MAX_MARKUP_COUNT];
|
|
|
+ memcpy(
|
|
|
+ markup_temp,
|
|
|
+ instance->data_markup,
|
|
|
+ BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+ memset(
|
|
|
+ instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+ uint16_t byte_count = subghz_protocol_bin_raw_get_full_byte(data_temp);
|
|
|
+ uint16_t index = 0;
|
|
|
+ uint16_t it = BIN_RAW_MAX_MARKUP_COUNT;
|
|
|
+ do {
|
|
|
+ it--;
|
|
|
+ if(subghz_protocol_bin_raw_get_full_byte(markup_temp[it].bit_count) ==
|
|
|
+ byte_count) {
|
|
|
+ instance->data_markup[index].bit_count = markup_temp[it].bit_count;
|
|
|
+ instance->data_markup[index].byte_bias = markup_temp[it].byte_bias;
|
|
|
+ index++;
|
|
|
+ bin_raw_type = BinRAWTypeGapUnknown;
|
|
|
+ }
|
|
|
+ } while(it != 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(bin_raw_type != BinRAWTypeGap)
|
|
|
+ return true;
|
|
|
+ else
|
|
|
+ return false;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // if bin_raw_type == BinRAWTypeGap
|
|
|
+ bin_raw_debug_tag(TAG, "Sequence analysis without gap\r\n");
|
|
|
+ ind = 0;
|
|
|
+ for(size_t i = 0; i < instance->data_raw_ind; i++) {
|
|
|
+ int data_temp = (int)(round((float)(instance->data_raw[i]) / instance->te));
|
|
|
+ if(data_temp == 0) break; //found an interval 2 times shorter than TE, this is noise
|
|
|
+ bin_raw_debug("%d ", data_temp);
|
|
|
+
|
|
|
+ for(size_t k = 0; k < abs(data_temp); k++) {
|
|
|
+ if(data_temp > 0) {
|
|
|
+ subghz_protocol_blocks_set_bit_array(
|
|
|
+ true, instance->data, ind++, BIN_RAW_BUF_DATA_SIZE);
|
|
|
+ } else {
|
|
|
+ subghz_protocol_blocks_set_bit_array(
|
|
|
+ false, instance->data, ind++, BIN_RAW_BUF_DATA_SIZE);
|
|
|
+ }
|
|
|
+ if(ind == BIN_RAW_BUF_DATA_SIZE * 8) {
|
|
|
+ i = instance->data_raw_ind;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(ind != 0) {
|
|
|
+ bin_raw_type = BinRAWTypeNoGap;
|
|
|
+ //right alignment
|
|
|
+ uint8_t bit_bias = (subghz_protocol_bin_raw_get_full_byte(ind) << 3) - ind;
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug(
|
|
|
+ "\r\n\t count bit= %zu\tcount full byte= %d\tbias bit= %d\r\n\r\n",
|
|
|
+ ind,
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(ind),
|
|
|
+ bit_bias);
|
|
|
+
|
|
|
+ for(size_t i = 0; i < subghz_protocol_bin_raw_get_full_byte(ind); i++) {
|
|
|
+ bin_raw_debug("%02X ", instance->data[i]);
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n\r\n");
|
|
|
+#endif
|
|
|
+ //checking that the received sequence contains useful data
|
|
|
+ bool data_check = false;
|
|
|
+ for(size_t i = 0; i < subghz_protocol_bin_raw_get_full_byte(ind); i++) {
|
|
|
+ if(instance->data[i] != 0) {
|
|
|
+ data_check = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(data_check) {
|
|
|
+ for(size_t i = subghz_protocol_bin_raw_get_full_byte(ind) - 1; i > 0; i--) {
|
|
|
+ instance->data[i] = (instance->data[i - 1] << (8 - bit_bias)) |
|
|
|
+ (instance->data[i] >> bit_bias);
|
|
|
+ }
|
|
|
+ instance->data[0] = (instance->data[0] >> bit_bias);
|
|
|
+
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug_tag(TAG, "Data right alignment\r\n");
|
|
|
+ for(size_t i = 0; i < subghz_protocol_bin_raw_get_full_byte(ind); i++) {
|
|
|
+ bin_raw_debug("%02X ", instance->data[i]);
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n\r\n");
|
|
|
+#endif
|
|
|
+ instance->data_markup[0].bit_count = ind;
|
|
|
+ instance->data_markup[0].byte_bias = 0;
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void subghz_protocol_decoder_bin_raw_data_input_rssi(
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance,
|
|
|
+ float rssi) {
|
|
|
+ furi_assert(instance);
|
|
|
+ switch(instance->decoder.parser_step) {
|
|
|
+ case BinRAWDecoderStepReset:
|
|
|
+
|
|
|
+ bin_raw_debug("%ld %ld :", (int32_t)rssi, (int32_t)instance->adaptive_threshold_rssi);
|
|
|
+ if(rssi > (instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI)) {
|
|
|
+ instance->data_raw_ind = 0;
|
|
|
+ memset(instance->data_raw, 0x00, BIN_RAW_BUF_RAW_SIZE * sizeof(int32_t));
|
|
|
+ memset(instance->data, 0x00, BIN_RAW_BUF_RAW_SIZE * sizeof(uint8_t));
|
|
|
+ instance->decoder.parser_step = BinRAWDecoderStepWrite;
|
|
|
+ bin_raw_debug_tag(TAG, "RSSI\r\n");
|
|
|
+ } else {
|
|
|
+ //adaptive noise level adjustment
|
|
|
+ instance->adaptive_threshold_rssi += (rssi - instance->adaptive_threshold_rssi) * 0.2f;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BinRAWDecoderStepBufFull:
|
|
|
+ case BinRAWDecoderStepWrite:
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ if(rssi > (instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI)) {
|
|
|
+ bin_raw_debug("\033[0;32m%ld \033[0m ", (int32_t)rssi);
|
|
|
+ } else {
|
|
|
+ bin_raw_debug("%ld ", (int32_t)rssi);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ if(rssi < instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI) {
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug("\r\n\r\n");
|
|
|
+ bin_raw_debug_tag(TAG, "Data for analysis, positive high, negative low, us\r\n");
|
|
|
+ for(size_t i = 0; i < instance->data_raw_ind; i++) {
|
|
|
+ bin_raw_debug("%ld ", instance->data_raw[i]);
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n\t count data= %zu\r\n\r\n", instance->data_raw_ind);
|
|
|
+#endif
|
|
|
+ instance->decoder.parser_step = BinRAWDecoderStepReset;
|
|
|
+ instance->generic.data_count_bit = 0;
|
|
|
+ if(instance->data_raw_ind >= BIN_RAW_BUF_MIN_DATA_COUNT) {
|
|
|
+ if(subghz_protocol_bin_raw_check_remote_controller(instance)) {
|
|
|
+ bin_raw_debug_tag(TAG, "Sequence found\r\n");
|
|
|
+ bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data");
|
|
|
+ uint16_t i = 0;
|
|
|
+ while((i < BIN_RAW_MAX_MARKUP_COUNT) &&
|
|
|
+ (instance->data_markup[i].bit_count != 0)) {
|
|
|
+ instance->generic.data_count_bit += instance->data_markup[i].bit_count;
|
|
|
+#ifdef BIN_RAW_DEBUG
|
|
|
+ bin_raw_debug(
|
|
|
+ "\r\n\t%d\t%d\t%d :\t",
|
|
|
+ i,
|
|
|
+ instance->data_markup[i].byte_bias,
|
|
|
+ instance->data_markup[i].bit_count);
|
|
|
+ for(uint16_t y = instance->data_markup[i].byte_bias;
|
|
|
+ y < instance->data_markup[i].byte_bias +
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(
|
|
|
+ instance->data_markup[i].bit_count);
|
|
|
+ y++) {
|
|
|
+ bin_raw_debug("%02X ", instance->data[y]);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ bin_raw_debug("\r\n");
|
|
|
+ if(instance->base.callback)
|
|
|
+ instance->base.callback(&instance->base, instance->base.context);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ //if instance->decoder.parser_step == BinRAWDecoderStepNoParse or others, restore the initial state
|
|
|
+ if(rssi < instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI) {
|
|
|
+ instance->decoder.parser_step = BinRAWDecoderStepReset;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+uint8_t subghz_protocol_decoder_bin_raw_get_hash_data(void* context) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = context;
|
|
|
+ return subghz_protocol_blocks_add_bytes(
|
|
|
+ instance->data + instance->data_markup[0].byte_bias,
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(instance->data_markup[0].bit_count));
|
|
|
+}
|
|
|
+
|
|
|
+bool subghz_protocol_decoder_bin_raw_serialize(
|
|
|
+ void* context,
|
|
|
+ FlipperFormat* flipper_format,
|
|
|
+ SubGhzRadioPreset* preset) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = context;
|
|
|
+
|
|
|
+ bool res = false;
|
|
|
+ FuriString* temp_str;
|
|
|
+ temp_str = furi_string_alloc();
|
|
|
+ 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", &preset->frequency, 1)) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add Frequency");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ subghz_block_generic_get_preset_name(furi_string_get_cstr(preset->name), temp_str);
|
|
|
+ if(!flipper_format_write_string_cstr(
|
|
|
+ flipper_format, "Preset", furi_string_get_cstr(temp_str))) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add Preset");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
|
|
|
+ if(!flipper_format_write_string_cstr(
|
|
|
+ flipper_format, "Custom_preset_module", "CC1101")) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add Custom_preset_module");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if(!flipper_format_write_hex(
|
|
|
+ flipper_format, "Custom_preset_data", preset->data, preset->data_size)) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add Custom_preset_data");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!flipper_format_write_string_cstr(
|
|
|
+ flipper_format, "Protocol", instance->generic.protocol_name)) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add Protocol");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ uint32_t temp = instance->generic.data_count_bit;
|
|
|
+ if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add Bit");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add TE");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ uint16_t i = 0;
|
|
|
+ while((i < BIN_RAW_MAX_MARKUP_COUNT) && (instance->data_markup[i].bit_count != 0)) {
|
|
|
+ temp = instance->data_markup[i].bit_count;
|
|
|
+ if(!flipper_format_write_uint32(flipper_format, "Bit_RAW", &temp, 1)) {
|
|
|
+ FURI_LOG_E(TAG, "Bit_RAW");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if(!flipper_format_write_hex(
|
|
|
+ flipper_format,
|
|
|
+ "Data_RAW",
|
|
|
+ instance->data + instance->data_markup[i].byte_bias,
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count))) {
|
|
|
+ FURI_LOG_E(TAG, "Unable to add Data_RAW");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ res = true;
|
|
|
+ } while(false);
|
|
|
+ furi_string_free(temp_str);
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = context;
|
|
|
+
|
|
|
+ bool res = false;
|
|
|
+ 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->generic.data_count_bit = (uint16_t)temp_data;
|
|
|
+
|
|
|
+ if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) {
|
|
|
+ FURI_LOG_E(TAG, "Missing TE");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ temp_data = 0;
|
|
|
+ uint16_t ind = 0;
|
|
|
+ uint16_t byte_bias = 0;
|
|
|
+ uint16_t byte_count = 0;
|
|
|
+ memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup));
|
|
|
+ while(flipper_format_read_uint32(flipper_format, "Bit_RAW", (uint32_t*)&temp_data, 1)) {
|
|
|
+ if(ind >= BIN_RAW_MAX_MARKUP_COUNT) {
|
|
|
+ FURI_LOG_E(TAG, "Markup overflow");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ byte_count += subghz_protocol_bin_raw_get_full_byte(temp_data);
|
|
|
+ if(byte_count > BIN_RAW_BUF_DATA_SIZE) {
|
|
|
+ FURI_LOG_E(TAG, "Receive buffer overflow");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ instance->data_markup[ind].bit_count = temp_data;
|
|
|
+ instance->data_markup[ind].byte_bias = byte_bias;
|
|
|
+ byte_bias += subghz_protocol_bin_raw_get_full_byte(temp_data);
|
|
|
+
|
|
|
+ if(!flipper_format_read_hex(
|
|
|
+ flipper_format,
|
|
|
+ "Data_RAW",
|
|
|
+ instance->data + instance->data_markup[ind].byte_bias,
|
|
|
+ subghz_protocol_bin_raw_get_full_byte(temp_data))) {
|
|
|
+ instance->data_markup[ind].bit_count = 0;
|
|
|
+ FURI_LOG_E(TAG, "Missing Data_RAW");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ ind++;
|
|
|
+ }
|
|
|
+
|
|
|
+ res = true;
|
|
|
+ } while(0);
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+void subghz_protocol_decoder_bin_raw_get_string(void* context, FuriString* output) {
|
|
|
+ furi_assert(context);
|
|
|
+ SubGhzProtocolDecoderBinRAW* instance = context;
|
|
|
+ furi_string_cat_printf(
|
|
|
+ output,
|
|
|
+ "%s %dbit\r\n"
|
|
|
+ "Key:",
|
|
|
+ instance->generic.protocol_name,
|
|
|
+ instance->generic.data_count_bit);
|
|
|
+
|
|
|
+ uint16_t byte_count = subghz_protocol_bin_raw_get_full_byte(instance->generic.data_count_bit);
|
|
|
+ for(size_t i = 0; (byte_count < 36 ? i < byte_count : i < 36); i++) {
|
|
|
+ furi_string_cat_printf(output, "%02X", instance->data[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ furi_string_cat_printf(output, "\r\nTe:%luus\r\n", instance->te);
|
|
|
+}
|