subghz: fix Allstar Firefly serialize/deserialize to use standard block_generic format

This commit is contained in:
jlaughter
2026-04-19 23:19:02 -04:00
committed by GitHub
parent fd4e552c70
commit b5fff36498
+75 -88
View File
@@ -2,9 +2,18 @@
* allstar_firefly.c -- Allstar Firefly 318ALD31K native SubGHz protocol * allstar_firefly.c -- Allstar Firefly 318ALD31K native SubGHz protocol
* *
* Implements the SubGhzProtocol vtable for the Supertex ED-9 based gate remote. * Implements the SubGhzProtocol vtable for the Supertex ED-9 based gate remote.
* Both the decoder state machine and encoder TX buffer are ported directly from * Uses subghz_block_generic_serialize / deserialize for standard-format .sub
* the proven FAP implementation; only the framing (alloc/free/serialize/etc.) * files, encoding the 9-position trinary DIP code as a uint64 (base-3, MSB
* changes to match the native SubGHz plugin interface. * first: '+' = 2, '0' = 1, '-' = 0).
*
* Saved file format:
* Filetype: Flipper SubGhz Key File
* Version: 1
* Frequency: 318000000
* Preset: FuriHalSubGhzPresetOok650Async
* Protocol: Allstar Firefly
* Key: 00 00 00 00 00 00 34 B9
* Bit: 18
* *
* See allstar_firefly.h for full protocol documentation. * See allstar_firefly.h for full protocol documentation.
*/ */
@@ -12,6 +21,7 @@
#include "allstar_firefly.h" #include "allstar_firefly.h"
#include <lib/subghz/protocols/base.h> #include <lib/subghz/protocols/base.h>
#include <lib/subghz/blocks/generic.h>
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
@@ -20,8 +30,6 @@
#define TAG "AllstarFirefly" #define TAG "AllstarFirefly"
/* --- Decoder instance ------------------------------------------------------ */
typedef enum { typedef enum {
AfRxState_WaitGap, AfRxState_WaitGap,
AfRxState_Receiving, AfRxState_Receiving,
@@ -29,6 +37,7 @@ typedef enum {
typedef struct { typedef struct {
SubGhzProtocolDecoderBase base; SubGhzProtocolDecoderBase base;
SubGhzBlockGeneric generic;
AfRxState rx_state; AfRxState rx_state;
uint8_t rx_syms[AF_SYM_COUNT]; uint8_t rx_syms[AF_SYM_COUNT];
uint8_t rx_count; uint8_t rx_count;
@@ -37,6 +46,7 @@ typedef struct {
typedef struct { typedef struct {
SubGhzProtocolEncoderBase base; SubGhzProtocolEncoderBase base;
SubGhzBlockGeneric generic;
char dip[AF_BIT_COUNT + 1]; char dip[AF_BIT_COUNT + 1];
uint32_t tx_buf[AF_TX_BUF_SIZE]; uint32_t tx_buf[AF_TX_BUF_SIZE];
uint32_t tx_size; uint32_t tx_size;
@@ -64,8 +74,8 @@ static bool af_dip_valid(const char* dip) {
return (dip[AF_BIT_COUNT] == '\0'); return (dip[AF_BIT_COUNT] == '\0');
} }
static uint32_t af_dip_to_uint32(const char* dip) { static uint64_t af_dip_to_uint64(const char* dip) {
uint32_t val = 0; uint64_t val = 0;
for(uint8_t i = 0; i < AF_BIT_COUNT; i++) { for(uint8_t i = 0; i < AF_BIT_COUNT; i++) {
val *= 3; val *= 3;
if (dip[i] == '+') val += 2; if (dip[i] == '+') val += 2;
@@ -74,6 +84,17 @@ static uint32_t af_dip_to_uint32(const char* dip) {
return val; return val;
} }
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';
}
static uint32_t af_build_tx_buf(const char* dip, uint32_t* buf) { static uint32_t af_build_tx_buf(const char* dip, uint32_t* buf) {
uint32_t pos = 0; uint32_t pos = 0;
for(uint32_t rep = 0; rep < AF_TX_REPEAT; rep++) { for(uint32_t rep = 0; rep < AF_TX_REPEAT; rep++) {
@@ -98,15 +119,19 @@ static uint32_t af_build_tx_buf(const char* dip, uint32_t* buf) {
} }
return pos; return pos;
} }
static void* subghz_protocol_decoder_allstar_firefly_alloc(SubGhzEnvironment* environment) { static void* subghz_protocol_decoder_allstar_firefly_alloc(SubGhzEnvironment* environment) {
UNUSED(environment); UNUSED(environment);
SubGhzProtocolDecoderAllstarFirefly* instance = SubGhzProtocolDecoderAllstarFirefly* instance =
malloc(sizeof(SubGhzProtocolDecoderAllstarFirefly)); malloc(sizeof(SubGhzProtocolDecoderAllstarFirefly));
instance->base.protocol = &subghz_protocol_allstar_firefly; instance->base.protocol = &subghz_protocol_allstar_firefly;
instance->rx_state = AfRxState_WaitGap; instance->generic.protocol_name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME;
instance->rx_count = 0; 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); memset(instance->dip, '-', AF_BIT_COUNT);
instance->dip[AF_BIT_COUNT] = '\0'; instance->dip[AF_BIT_COUNT] = '\0';
return instance; return instance;
} }
@@ -139,9 +164,8 @@ static void subghz_protocol_decoder_allstar_firefly_feed(
instance->rx_count = 0; instance->rx_count = 0;
return; return;
} }
if(instance->rx_count < AF_SYM_COUNT) { if(instance->rx_count < AF_SYM_COUNT)
instance->rx_syms[instance->rx_count++] = sym; instance->rx_syms[instance->rx_count++] = sym;
}
} }
} else { } else {
if(duration >= AF_FRAME_THRESH_US) { if(duration >= AF_FRAME_THRESH_US) {
@@ -150,11 +174,10 @@ static void subghz_protocol_decoder_allstar_firefly_feed(
char decoded[AF_BIT_COUNT + 1]; char decoded[AF_BIT_COUNT + 1];
if(af_decode_symbols(instance->rx_syms, decoded)) { if(af_decode_symbols(instance->rx_syms, decoded)) {
memcpy(instance->dip, decoded, AF_BIT_COUNT + 1); memcpy(instance->dip, decoded, AF_BIT_COUNT + 1);
if(instance->base.callback) { instance->generic.data = af_dip_to_uint64(decoded);
instance->base.callback( instance->generic.data_count_bit = AF_SYM_COUNT;
&instance->base, if(instance->base.callback)
instance->base.context); instance->base.callback(&instance->base, instance->base.context);
}
} }
instance->rx_state = AfRxState_WaitGap; instance->rx_state = AfRxState_WaitGap;
instance->rx_count = 0; instance->rx_count = 0;
@@ -176,59 +199,30 @@ static uint8_t subghz_protocol_decoder_allstar_firefly_get_hash_data(void* conte
for(uint8_t i = 0; i < AF_BIT_COUNT; i++) hash ^= (uint8_t)instance->dip[i]; for(uint8_t i = 0; i < AF_BIT_COUNT; i++) hash ^= (uint8_t)instance->dip[i];
return hash; return hash;
} }
static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_serialize( static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_serialize(
void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) {
furi_assert(context); furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context; SubGhzProtocolDecoderAllstarFirefly* instance = context;
if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
FURI_LOG_E(TAG, "Failed to write Frequency");
return SubGhzProtocolStatusErrorParserOthers;
}
if(!flipper_format_write_string(flipper_format, "Preset", preset->name)) {
FURI_LOG_E(TAG, "Failed to write Preset");
return SubGhzProtocolStatusErrorParserOthers;
}
if(!flipper_format_write_string_cstr(
flipper_format, "Protocol", SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME)) {
FURI_LOG_E(TAG, "Failed to write Protocol");
return SubGhzProtocolStatusErrorParserOthers;
}
if(!flipper_format_write_string_cstr(flipper_format, "Key", instance->dip)) {
FURI_LOG_E(TAG, "Failed to write Key");
return SubGhzProtocolStatusErrorParserOthers;
}
return SubGhzProtocolStatusOk;
} }
static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_deserialize( static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_deserialize(
void* context, FlipperFormat* flipper_format) { void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context; SubGhzProtocolDecoderAllstarFirefly* instance = context;
FuriString* key_str = furi_string_alloc(); SubGhzProtocolStatus status = subghz_block_generic_deserialize_check_count_bit(
if(!flipper_format_read_string(flipper_format, "Key", key_str)) { &instance->generic, flipper_format, AF_SYM_COUNT);
FURI_LOG_E(TAG, "Missing Key field"); if(status != SubGhzProtocolStatusOk) return status;
furi_string_free(key_str); af_uint64_to_dip(instance->generic.data, instance->dip);
return SubGhzProtocolStatusErrorParserOthers; if(!af_dip_valid(instance->dip)) return SubGhzProtocolStatusErrorParserOthers;
}
const char* key_cstr = furi_string_get_cstr(key_str);
if(strlen(key_cstr) != AF_BIT_COUNT || !af_dip_valid(key_cstr)) {
FURI_LOG_E(TAG, "Invalid Key value: %s", key_cstr);
furi_string_free(key_str);
return SubGhzProtocolStatusErrorParserOthers;
}
memcpy(instance->dip, key_cstr, AF_BIT_COUNT + 1);
furi_string_free(key_str);
return SubGhzProtocolStatusOk; return SubGhzProtocolStatusOk;
} }
static void subghz_protocol_decoder_allstar_firefly_get_string( static void subghz_protocol_decoder_allstar_firefly_get_string(
void* context, FuriString* output) { void* context, FuriString* output) {
furi_assert(context); furi_assert(context);
SubGhzProtocolDecoderAllstarFirefly* instance = context; SubGhzProtocolDecoderAllstarFirefly* instance = context;
uint32_t code = af_dip_to_uint32(instance->dip);
furi_string_cat_printf( furi_string_cat_printf(
output, output,
"%s\r\n0x%04lX\r\n" "%s\r\n0x%04lX\r\n"
@@ -236,20 +230,24 @@ static void subghz_protocol_decoder_allstar_firefly_get_string(
"1 2 3 4 5 6 7 8 9\r\n" "1 2 3 4 5 6 7 8 9\r\n"
"%c %c %c %c %c %c %c %c %c", "%c %c %c %c %c %c %c %c %c",
SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME, SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME,
(unsigned long)code, (unsigned long)(instance->generic.data),
instance->dip[0], instance->dip[1], instance->dip[2], instance->dip[0], instance->dip[1], instance->dip[2],
instance->dip[3], instance->dip[4], instance->dip[5], instance->dip[3], instance->dip[4], instance->dip[5],
instance->dip[6], instance->dip[7], instance->dip[8]); instance->dip[6], instance->dip[7], instance->dip[8]);
} }
static void* subghz_protocol_encoder_allstar_firefly_alloc(SubGhzEnvironment* environment) { static void* subghz_protocol_encoder_allstar_firefly_alloc(SubGhzEnvironment* environment) {
UNUSED(environment); UNUSED(environment);
SubGhzProtocolEncoderAllstarFirefly* instance = SubGhzProtocolEncoderAllstarFirefly* instance =
malloc(sizeof(SubGhzProtocolEncoderAllstarFirefly)); malloc(sizeof(SubGhzProtocolEncoderAllstarFirefly));
instance->base.protocol = &subghz_protocol_allstar_firefly; 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); memset(instance->dip, '-', AF_BIT_COUNT);
instance->dip[AF_BIT_COUNT] = '\0'; instance->dip[AF_BIT_COUNT] = '\0';
instance->tx_size = 0; instance->tx_size = 0;
instance->tx_pos = 0; instance->tx_pos = 0;
return instance; return instance;
} }
@@ -263,23 +261,13 @@ static void subghz_protocol_encoder_allstar_firefly_stop(void* context) {
static SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize( static SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize(
void* context, FlipperFormat* flipper_format) { void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
SubGhzProtocolEncoderAllstarFirefly* instance = context; SubGhzProtocolEncoderAllstarFirefly* instance = context;
FuriString* key_str = furi_string_alloc(); SubGhzProtocolStatus status = subghz_block_generic_deserialize_check_count_bit(
if(!flipper_format_read_string(flipper_format, "Key", key_str)) { &instance->generic, flipper_format, AF_SYM_COUNT);
FURI_LOG_E(TAG, "Encoder: missing Key field"); if(status != SubGhzProtocolStatusOk) return status;
furi_string_free(key_str); af_uint64_to_dip(instance->generic.data, instance->dip);
return SubGhzProtocolStatusErrorParserOthers; if(!af_dip_valid(instance->dip)) return SubGhzProtocolStatusErrorParserOthers;
}
const char* key_cstr = furi_string_get_cstr(key_str);
if(strlen(key_cstr) != AF_BIT_COUNT || !af_dip_valid(key_cstr)) {
FURI_LOG_E(TAG, "Encoder: invalid Key: %s", key_cstr);
furi_string_free(key_str);
return SubGhzProtocolStatusErrorParserOthers;
}
memcpy(instance->dip, key_cstr, AF_BIT_COUNT + 1);
furi_string_free(key_str);
instance->tx_size = af_build_tx_buf(instance->dip, instance->tx_buf); instance->tx_size = af_build_tx_buf(instance->dip, instance->tx_buf);
instance->tx_pos = 0; instance->tx_pos = 0;
return SubGhzProtocolStatusOk; return SubGhzProtocolStatusOk;
@@ -288,22 +276,21 @@ static SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize(
static LevelDuration subghz_protocol_encoder_allstar_firefly_yield(void* context) { static LevelDuration subghz_protocol_encoder_allstar_firefly_yield(void* context) {
furi_assert(context); furi_assert(context);
SubGhzProtocolEncoderAllstarFirefly* instance = context; SubGhzProtocolEncoderAllstarFirefly* instance = context;
if(instance->tx_pos >= instance->tx_size) { if(instance->tx_pos >= instance->tx_size) return level_duration_reset();
return level_duration_reset();
}
bool lv = (instance->tx_pos % 2 == 0); bool lv = (instance->tx_pos % 2 == 0);
uint32_t dur = instance->tx_buf[instance->tx_pos++]; uint32_t dur = instance->tx_buf[instance->tx_pos++];
return level_duration_make(lv, dur); return level_duration_make(lv, dur);
} }
const SubGhzProtocolDecoder subghz_protocol_decoder_allstar_firefly = { const SubGhzProtocolDecoder subghz_protocol_decoder_allstar_firefly = {
.alloc = subghz_protocol_decoder_allstar_firefly_alloc, .alloc = subghz_protocol_decoder_allstar_firefly_alloc,
.free = subghz_protocol_decoder_allstar_firefly_free, .free = subghz_protocol_decoder_allstar_firefly_free,
.feed = subghz_protocol_decoder_allstar_firefly_feed, .feed = subghz_protocol_decoder_allstar_firefly_feed,
.reset = subghz_protocol_decoder_allstar_firefly_reset, .reset = subghz_protocol_decoder_allstar_firefly_reset,
.get_hash_data = subghz_protocol_decoder_allstar_firefly_get_hash_data, .get_hash_data = subghz_protocol_decoder_allstar_firefly_get_hash_data,
.serialize = subghz_protocol_decoder_allstar_firefly_serialize, .serialize = subghz_protocol_decoder_allstar_firefly_serialize,
.deserialize = subghz_protocol_decoder_allstar_firefly_deserialize, .deserialize = subghz_protocol_decoder_allstar_firefly_deserialize,
.get_string = subghz_protocol_decoder_allstar_firefly_get_string, .get_string = subghz_protocol_decoder_allstar_firefly_get_string,
}; };
const SubGhzProtocolEncoder subghz_protocol_encoder_allstar_firefly = { const SubGhzProtocolEncoder subghz_protocol_encoder_allstar_firefly = {
@@ -317,10 +304,10 @@ const SubGhzProtocolEncoder subghz_protocol_encoder_allstar_firefly = {
const SubGhzProtocol subghz_protocol_allstar_firefly = { const SubGhzProtocol subghz_protocol_allstar_firefly = {
.name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME, .name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME,
.type = SubGhzProtocolTypeStatic, .type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_AM | .flag = SubGhzProtocolFlag_AM |
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Save |
SubGhzProtocolFlag_Send, SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_decoder_allstar_firefly, .decoder = &subghz_protocol_decoder_allstar_firefly,
.encoder = &subghz_protocol_encoder_allstar_firefly, .encoder = &subghz_protocol_encoder_allstar_firefly,