* SubGhz: add protocol DataRAW (binarization of data quantized by the minimum correlated duration) * SubGhz: fix name history * SubGhz: add encoder Data_RAW protocol * SubGhz: decreasing the size of the LevelDuration structure * SubGhz: history, added check that there is free RAM * SubGhz: checking for free memory, support to pass without gap * SubGhz: add running average to average the result, auto cut noise at the end of a burst * SubGhz: support for repeating sequences * SubGhz: fix secplus_v2 decoder * SubGhz: bin_RAW fix add history * SubGhz: add debug * SubGhz: debug refactoring * FURI_LOG: add FURI_LOG_RAW_x formatted string output like printf * SubGhz: fix new FURI_LOG metod * FURI_LOG: fix unit test * SubGhz: add enable/disable BinRAW protocol decoding * SubGhz: fix PVS * SubGhz: forcibly turn off the speaker when exiting SubGhz * SubGhz: adaptive adjustment to the noise level Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
		
			
				
	
	
		
			1121 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1121 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#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);
 | 
						|
}
 |