Remake to use other protocols codebase

Also remake DIP UI and funcs
This commit is contained in:
MX
2026-04-21 01:56:55 +03:00
parent b5fff36498
commit d5fad4f38b
2 changed files with 412 additions and 268 deletions
+308 -246
View File
@@ -4,7 +4,7 @@
* Implements the SubGhzProtocol vtable for the Supertex ED-9 based gate remote.
* Uses subghz_block_generic_serialize / deserialize for standard-format .sub
* files, encoding the 9-position trinary DIP code as a uint64 (base-3, MSB
* first: '+' = 2, '0' = 1, '-' = 0).
* first: '+' = 2, '0' = 3, '-' = 0).
*
* Saved file format:
* Filetype: Flipper SubGhz Key File
@@ -20,295 +20,357 @@
#include "allstar_firefly.h"
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/blocks/generic.h>
#include <furi.h>
#include <furi_hal.h>
#include <flipper_format/flipper_format.h>
#include <string.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "AllstarFirefly"
typedef enum {
AfRxState_WaitGap,
AfRxState_Receiving,
} AfRxState;
#define DIP_P 0b11 //(+)
#define DIP_O 0b10 //(0)
#define DIP_N 0b00 //(-)
typedef struct {
#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c"
#define SHOW_DIP_P(dip, check_dip) \
((((dip >> 0x10) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_')
static const SubGhzBlockConst subghz_protocol_allstar_firefly_const = {
.te_short = 600,
.te_long = 4000,
.te_delta = 300,
.min_count_bit_for_found = 18,
};
struct SubGhzProtocolDecoderAllstarFirefly {
SubGhzProtocolDecoderBase base;
SubGhzBlockGeneric generic;
AfRxState rx_state;
uint8_t rx_syms[AF_SYM_COUNT];
uint8_t rx_count;
char dip[AF_BIT_COUNT + 1];
} SubGhzProtocolDecoderAllstarFirefly;
typedef struct {
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderAllstarFirefly {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
char dip[AF_BIT_COUNT + 1];
uint32_t tx_buf[AF_TX_BUF_SIZE];
uint32_t tx_size;
uint32_t tx_pos;
} SubGhzProtocolEncoderAllstarFirefly;
};
static bool af_decode_symbols(const uint8_t* syms, char* dip) {
for(uint8_t i = 0; i < AF_BIT_COUNT; i++) {
uint8_t a = syms[i * 2];
uint8_t b = syms[i * 2 + 1];
if (a == 1 && b == 1) dip[i] = '+';
else if (a == 0 && b == 0) dip[i] = '-';
else if (a == 1 && b == 0) dip[i] = '0';
else return false;
}
dip[AF_BIT_COUNT] = '\0';
return true;
}
typedef enum {
AllstarFireflyDecoderStepReset = 0,
AllstarFireflyDecoderStepSaveDuration,
AllstarFireflyDecoderStepCheckDuration,
} AllstarFireflyDecoderStep;
static bool af_dip_valid(const char* dip) {
if(!dip) return false;
for(uint8_t i = 0; i < AF_BIT_COUNT; i++) {
if(dip[i] != '+' && dip[i] != '-' && dip[i] != '0') return false;
}
return (dip[AF_BIT_COUNT] == '\0');
}
const SubGhzProtocolDecoder subghz_protocol_allstar_firefly_decoder = {
.alloc = subghz_protocol_decoder_allstar_firefly_alloc,
.free = subghz_protocol_decoder_allstar_firefly_free,
static uint64_t af_dip_to_uint64(const char* dip) {
uint64_t val = 0;
for(uint8_t i = 0; i < AF_BIT_COUNT; i++) {
val *= 3;
if (dip[i] == '+') val += 2;
else if(dip[i] == '0') val += 1;
}
return val;
}
.feed = subghz_protocol_decoder_allstar_firefly_feed,
.reset = subghz_protocol_decoder_allstar_firefly_reset,
static void af_uint64_to_dip(uint64_t val, char* dip) {
for(int8_t i = AF_BIT_COUNT - 1; i >= 0; i--) {
uint8_t rem = (uint8_t)(val % 3);
val /= 3;
if (rem == 2) dip[i] = '+';
else if(rem == 1) dip[i] = '0';
else dip[i] = '-';
}
dip[AF_BIT_COUNT] = '\0';
}
.get_hash_data = subghz_protocol_decoder_allstar_firefly_get_hash_data,
.serialize = subghz_protocol_decoder_allstar_firefly_serialize,
.deserialize = subghz_protocol_decoder_allstar_firefly_deserialize,
.get_string = subghz_protocol_decoder_allstar_firefly_get_string,
};
static uint32_t af_build_tx_buf(const char* dip, uint32_t* buf) {
uint32_t pos = 0;
for(uint32_t rep = 0; rep < AF_TX_REPEAT; rep++) {
for(uint32_t bit = 0; bit < AF_BIT_COUNT; bit++) {
bool last = (bit == AF_BIT_COUNT - 1);
char c = dip[bit];
uint32_t p0, g0, p1, g1;
if(c == '+') {
p0 = AF_LONG_PULSE_US; g0 = AF_SHORT_GAP_US;
p1 = AF_LONG_PULSE_US; g1 = AF_SHORT_GAP_US;
} else if(c == '-') {
p0 = AF_SHORT_PULSE_US; g0 = AF_LONG_GAP_US;
p1 = AF_SHORT_PULSE_US; g1 = AF_LONG_GAP_US;
} else {
p0 = AF_LONG_PULSE_US; g0 = AF_SHORT_GAP_US;
p1 = AF_SHORT_PULSE_US; g1 = AF_LONG_GAP_US;
}
if(last) g1 = AF_INTERFRAME_US;
buf[pos++] = p0; buf[pos++] = g0;
buf[pos++] = p1; buf[pos++] = g1;
}
}
return pos;
}
const SubGhzProtocolEncoder subghz_protocol_allstar_firefly_encoder = {
.alloc = subghz_protocol_encoder_allstar_firefly_alloc,
.free = subghz_protocol_encoder_allstar_firefly_free,
static void* subghz_protocol_decoder_allstar_firefly_alloc(SubGhzEnvironment* environment) {
.deserialize = subghz_protocol_encoder_allstar_firefly_deserialize,
.stop = subghz_protocol_encoder_allstar_firefly_stop,
.yield = subghz_protocol_encoder_allstar_firefly_yield,
};
const SubGhzProtocol subghz_protocol_allstar_firefly = {
.name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_allstar_firefly_decoder,
.encoder = &subghz_protocol_allstar_firefly_encoder,
};
void* subghz_protocol_encoder_allstar_firefly_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderAllstarFirefly* instance =
malloc(sizeof(SubGhzProtocolDecoderAllstarFirefly));
instance->base.protocol = &subghz_protocol_allstar_firefly;
instance->generic.protocol_name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME;
instance->generic.data = 0;
instance->generic.data_count_bit = AF_SYM_COUNT;
instance->rx_state = AfRxState_WaitGap;
instance->rx_count = 0;
memset(instance->dip, '-', AF_BIT_COUNT);
instance->dip[AF_BIT_COUNT] = '\0';
SubGhzProtocolEncoderAllstarFirefly* instance =
malloc(sizeof(SubGhzProtocolEncoderAllstarFirefly));
instance->base.protocol = &subghz_protocol_allstar_firefly;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 5;
instance->encoder.size_upload = 256;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
static void subghz_protocol_decoder_allstar_firefly_free(void* context) {
furi_assert(context); free(context);
void subghz_protocol_encoder_allstar_firefly_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderAllstarFirefly* instance = context;
free(instance->encoder.upload);
free(instance);
}
static void subghz_protocol_decoder_allstar_firefly_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
instance->rx_state = AfRxState_WaitGap;
instance->rx_count = 0;
}
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderAllstarFirefly instance
*/
static void subghz_protocol_encoder_allstar_firefly_get_upload(
SubGhzProtocolEncoderAllstarFirefly* instance) {
furi_assert(instance);
size_t index = 0;
static void subghz_protocol_decoder_allstar_firefly_feed(
void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
if(level) {
if(instance->rx_state == AfRxState_Receiving) {
uint8_t sym;
if(duration >= AF_LONG_PULSE_MIN && duration <= AF_LONG_PULSE_MAX) {
sym = 1u;
} else if(duration >= AF_SHORT_PULSE_MIN && duration <= AF_SHORT_PULSE_MAX) {
sym = 0u;
// Send key and GAP
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
// Send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_allstar_firefly_const.te_long);
if(i == 1) {
//Send gap if bit was last
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)(subghz_protocol_allstar_firefly_const.te_short * 50) + 400);
} else {
instance->rx_state = AfRxState_WaitGap;
instance->rx_count = 0;
return;
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_allstar_firefly_const.te_short);
}
if(instance->rx_count < AF_SYM_COUNT)
instance->rx_syms[instance->rx_count++] = sym;
}
} else {
if(duration >= AF_FRAME_THRESH_US) {
if(instance->rx_state == AfRxState_Receiving &&
instance->rx_count == AF_SYM_COUNT) {
char decoded[AF_BIT_COUNT + 1];
if(af_decode_symbols(instance->rx_syms, decoded)) {
memcpy(instance->dip, decoded, AF_BIT_COUNT + 1);
instance->generic.data = af_dip_to_uint64(decoded);
instance->generic.data_count_bit = AF_SYM_COUNT;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->rx_state = AfRxState_WaitGap;
instance->rx_count = 0;
} else if(instance->rx_state == AfRxState_WaitGap) {
instance->rx_state = AfRxState_Receiving;
instance->rx_count = 0;
} else {
// Send bit 0
instance->encoder.upload[index++] = level_duration_make(
true, (uint32_t)subghz_protocol_allstar_firefly_const.te_short);
if(i == 1) {
//Send gap if bit was last
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)(subghz_protocol_allstar_firefly_const.te_short * 50) + 400);
} else {
instance->rx_state = AfRxState_WaitGap;
instance->rx_count = 0;
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_allstar_firefly_const.te_long);
}
}
}
instance->encoder.size_upload = index;
return;
}
static uint8_t subghz_protocol_decoder_allstar_firefly_get_hash_data(void* context) {
SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize(
void* context,
FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderAllstarFirefly* instance = context;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do {
ret = subghz_block_generic_deserialize_check_count_bit(
&instance->generic,
flipper_format,
subghz_protocol_allstar_firefly_const.min_count_bit_for_found);
if(ret != SubGhzProtocolStatusOk) {
break;
}
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
subghz_protocol_encoder_allstar_firefly_get_upload(instance);
instance->encoder.is_running = true;
} while(false);
return ret;
}
void subghz_protocol_encoder_allstar_firefly_stop(void* context) {
SubGhzProtocolEncoderAllstarFirefly* instance = context;
instance->encoder.is_running = false;
}
LevelDuration subghz_protocol_encoder_allstar_firefly_yield(void* context) {
SubGhzProtocolEncoderAllstarFirefly* 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) {
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
instance->encoder.front = 0;
}
return ret;
}
void* subghz_protocol_decoder_allstar_firefly_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderAllstarFirefly* instance =
malloc(sizeof(SubGhzProtocolDecoderAllstarFirefly));
instance->base.protocol = &subghz_protocol_allstar_firefly;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_allstar_firefly_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
uint8_t hash = 0;
for(uint8_t i = 0; i < AF_BIT_COUNT; i++) hash ^= (uint8_t)instance->dip[i];
return hash;
free(instance);
}
static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_serialize(
void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) {
void subghz_protocol_decoder_allstar_firefly_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
instance->decoder.parser_step = AllstarFireflyDecoderStepReset;
}
void subghz_protocol_decoder_allstar_firefly_feed(
void* context,
bool level,
volatile uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
// Allstar Firefly Decoder
// 2026 - by @jlaughter
// Remake to match other protocols code base - @xMasterX (MMX)
switch(instance->decoder.parser_step) {
case AllstarFireflyDecoderStepReset:
if((!level) &&
(DURATION_DIFF(duration, subghz_protocol_allstar_firefly_const.te_short * 50) <
subghz_protocol_allstar_firefly_const.te_delta * 5)) {
// 30k us
// Found GAP
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->decoder.parser_step = AllstarFireflyDecoderStepSaveDuration;
}
break;
case AllstarFireflyDecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = AllstarFireflyDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = AllstarFireflyDecoderStepReset;
}
break;
case AllstarFireflyDecoderStepCheckDuration:
if(!level) {
// Bit 1 is long and short timing = 4000us HIGH (te_last) and 600us LOW
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_allstar_firefly_const.te_long) <
subghz_protocol_allstar_firefly_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_allstar_firefly_const.te_short) <
subghz_protocol_allstar_firefly_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = AllstarFireflyDecoderStepSaveDuration;
// Bit 0 is short and long timing = 600us HIGH (te_last) and 4000us LOW
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_allstar_firefly_const.te_short) <
subghz_protocol_allstar_firefly_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_allstar_firefly_const.te_long) <
subghz_protocol_allstar_firefly_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = AllstarFireflyDecoderStepSaveDuration;
} else if(
// End of the key
DURATION_DIFF(duration, subghz_protocol_allstar_firefly_const.te_short * 50) <
subghz_protocol_allstar_firefly_const.te_delta * 5) {
// Found next GAP and add bit 0 or 1
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_allstar_firefly_const.te_long) <
subghz_protocol_allstar_firefly_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
}
if((DURATION_DIFF(
instance->decoder.te_last,
subghz_protocol_allstar_firefly_const.te_short) <
subghz_protocol_allstar_firefly_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
}
// If got 18 bits key reading is finished
if(instance->decoder.decode_count_bit ==
subghz_protocol_allstar_firefly_const.min_count_bit_for_found) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->decoder.parser_step = AllstarFireflyDecoderStepReset;
} else {
instance->decoder.parser_step = AllstarFireflyDecoderStepReset;
}
} else {
instance->decoder.parser_step = AllstarFireflyDecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_decoder_allstar_firefly_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
}
static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_deserialize(
void* context, FlipperFormat* flipper_format) {
SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_deserialize(
void* context,
FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
SubGhzProtocolStatus status = subghz_block_generic_deserialize_check_count_bit(
&instance->generic, flipper_format, AF_SYM_COUNT);
if(status != SubGhzProtocolStatusOk) return status;
af_uint64_to_dip(instance->generic.data, instance->dip);
if(!af_dip_valid(instance->dip)) return SubGhzProtocolStatusErrorParserOthers;
return SubGhzProtocolStatusOk;
return subghz_block_generic_deserialize_check_count_bit(
&instance->generic,
flipper_format,
subghz_protocol_allstar_firefly_const.min_count_bit_for_found);
}
static void subghz_protocol_decoder_allstar_firefly_get_string(
void* context, FuriString* output) {
void subghz_protocol_decoder_allstar_firefly_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context;
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
furi_string_cat_printf(
output,
"%s\r\n0x%04lX\r\n"
"Freq: 318MHz OOK\r\n"
"1 2 3 4 5 6 7 8 9\r\n"
"%c %c %c %c %c %c %c %c %c",
SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME,
(unsigned long)(instance->generic.data),
instance->dip[0], instance->dip[1], instance->dip[2],
instance->dip[3], instance->dip[4], instance->dip[5],
instance->dip[6], instance->dip[7], instance->dip[8]);
"%s %db\r\n"
"Key:0x%05lX Yek:0x%05lX\r\n"
" +: " DIP_PATTERN "\r\n"
" o: " DIP_PATTERN "\r\n"
" -: " DIP_PATTERN "\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data & 0xFFFFF),
(uint32_t)(code_found_reverse & 0xFFFFF),
SHOW_DIP_P(instance->generic.data, DIP_P),
SHOW_DIP_P(instance->generic.data, DIP_O),
SHOW_DIP_P(instance->generic.data, DIP_N));
}
static void* subghz_protocol_encoder_allstar_firefly_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolEncoderAllstarFirefly* instance =
malloc(sizeof(SubGhzProtocolEncoderAllstarFirefly));
instance->base.protocol = &subghz_protocol_allstar_firefly;
instance->generic.protocol_name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME;
instance->generic.data = 0;
instance->generic.data_count_bit = AF_SYM_COUNT;
memset(instance->dip, '-', AF_BIT_COUNT);
instance->dip[AF_BIT_COUNT] = '\0';
instance->tx_size = 0;
instance->tx_pos = 0;
return instance;
}
static void subghz_protocol_encoder_allstar_firefly_free(void* context) {
furi_assert(context); free(context);
}
static void subghz_protocol_encoder_allstar_firefly_stop(void* context) {
UNUSED(context);
}
static SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize(
void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderAllstarFirefly* instance = context;
SubGhzProtocolStatus status = subghz_block_generic_deserialize_check_count_bit(
&instance->generic, flipper_format, AF_SYM_COUNT);
if(status != SubGhzProtocolStatusOk) return status;
af_uint64_to_dip(instance->generic.data, instance->dip);
if(!af_dip_valid(instance->dip)) return SubGhzProtocolStatusErrorParserOthers;
instance->tx_size = af_build_tx_buf(instance->dip, instance->tx_buf);
instance->tx_pos = 0;
return SubGhzProtocolStatusOk;
}
static LevelDuration subghz_protocol_encoder_allstar_firefly_yield(void* context) {
furi_assert(context);
SubGhzProtocolEncoderAllstarFirefly* instance = context;
if(instance->tx_pos >= instance->tx_size) return level_duration_reset();
bool lv = (instance->tx_pos % 2 == 0);
uint32_t dur = instance->tx_buf[instance->tx_pos++];
return level_duration_make(lv, dur);
}
const SubGhzProtocolDecoder subghz_protocol_decoder_allstar_firefly = {
.alloc = subghz_protocol_decoder_allstar_firefly_alloc,
.free = subghz_protocol_decoder_allstar_firefly_free,
.feed = subghz_protocol_decoder_allstar_firefly_feed,
.reset = subghz_protocol_decoder_allstar_firefly_reset,
.get_hash_data = subghz_protocol_decoder_allstar_firefly_get_hash_data,
.serialize = subghz_protocol_decoder_allstar_firefly_serialize,
.deserialize = subghz_protocol_decoder_allstar_firefly_deserialize,
.get_string = subghz_protocol_decoder_allstar_firefly_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_encoder_allstar_firefly = {
.alloc = subghz_protocol_encoder_allstar_firefly_alloc,
.free = subghz_protocol_encoder_allstar_firefly_free,
.deserialize = subghz_protocol_encoder_allstar_firefly_deserialize,
.stop = subghz_protocol_encoder_allstar_firefly_stop,
.yield = subghz_protocol_encoder_allstar_firefly_yield,
};
const SubGhzProtocol subghz_protocol_allstar_firefly = {
.name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Save |
SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_decoder_allstar_firefly,
.encoder = &subghz_protocol_encoder_allstar_firefly,
};
+104 -22
View File
@@ -31,31 +31,113 @@
* &subghz_protocol_allstar_firefly, (in the protocol array)
*/
#include <lib/subghz/protocols/base.h>
#include "base.h"
/* Protocol name (must match what is written to .sub files) */
#define SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME "Allstar Firefly"
#define SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME "Allstar Firefly"
/* Timing constants (from 37-frame analysis of two captures) */
#define AF_FREQ 318000000UL
#define AF_BIT_COUNT 9u
#define AF_SYM_COUNT 18u
typedef struct SubGhzProtocolDecoderAllstarFirefly SubGhzProtocolDecoderAllstarFirefly;
typedef struct SubGhzProtocolEncoderAllstarFirefly SubGhzProtocolEncoderAllstarFirefly;
#define AF_LONG_PULSE_US 4045u
#define AF_SHORT_PULSE_US 530u
#define AF_SHORT_GAP_US 607u
#define AF_LONG_GAP_US 4139u
#define AF_INTERFRAME_US 30440u
extern const SubGhzProtocolDecoder subghz_protocol_allstar_firefly_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_allstar_firefly_encoder;
extern const SubGhzProtocol subghz_protocol_allstar_firefly;
#define AF_SHORT_PULSE_MIN 300u
#define AF_SHORT_PULSE_MAX 1200u
#define AF_LONG_PULSE_MIN 2500u
#define AF_LONG_PULSE_MAX 5500u
#define AF_FRAME_THRESH_US 20000u
#define AF_TX_REPEAT 20u
#define AF_TX_BUF_SIZE (AF_TX_REPEAT * AF_SYM_COUNT * 2u + 8u)
/**
* Allocate SubGhzProtocolEncoderAllstarFirefly.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolEncoderAllstarFirefly* pointer to a SubGhzProtocolEncoderAllstarFirefly instance
*/
void* subghz_protocol_encoder_allstar_firefly_alloc(SubGhzEnvironment* environment);
/* Protocol vtable entries */
extern const SubGhzProtocolDecoder subghz_protocol_decoder_allstar_firefly;
extern const SubGhzProtocolEncoder subghz_protocol_encoder_allstar_firefly;
extern const SubGhzProtocol subghz_protocol_allstar_firefly;
/**
* Free SubGhzProtocolEncoderAllstarFirefly.
* @param context Pointer to a SubGhzProtocolEncoderAllstarFirefly instance
*/
void subghz_protocol_encoder_allstar_firefly_free(void* context);
/**
* Deserialize and generating an upload to send.
* @param context Pointer to a SubGhzProtocolEncoderAllstarFirefly instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize(
void* context,
FlipperFormat* flipper_format);
/**
* Forced transmission stop.
* @param context Pointer to a SubGhzProtocolEncoderAllstarFirefly instance
*/
void subghz_protocol_encoder_allstar_firefly_stop(void* context);
/**
* Getting the level and duration of the upload to be loaded into DMA.
* @param context Pointer to a SubGhzProtocolEncoderAllstarFirefly instance
* @return LevelDuration
*/
LevelDuration subghz_protocol_encoder_allstar_firefly_yield(void* context);
/**
* Allocate SubGhzProtocolDecoderAllstarFirefly.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderAllstarFirefly* pointer to a SubGhzProtocolDecoderAllstarFirefly instance
*/
void* subghz_protocol_decoder_allstar_firefly_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderAllstarFirefly.
* @param context Pointer to a SubGhzProtocolDecoderAllstarFirefly instance
*/
void subghz_protocol_decoder_allstar_firefly_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderAllstarFirefly.
* @param context Pointer to a SubGhzProtocolDecoderAllstarFirefly instance
*/
void subghz_protocol_decoder_allstar_firefly_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderAllstarFirefly instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_allstar_firefly_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderAllstarFirefly instance
* @return hash Hash sum
*/
uint8_t subghz_protocol_decoder_allstar_firefly_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderAllstarFirefly.
* @param context Pointer to a SubGhzProtocolDecoderAllstarFirefly instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderAllstarFirefly.
* @param context Pointer to a SubGhzProtocolDecoderAllstarFirefly instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_deserialize(
void* context,
FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderAllstarFirefly instance
* @param output Resulting text
*/
void subghz_protocol_decoder_allstar_firefly_get_string(void* context, FuriString* output);