From b5fff36498205fc4a82e4dd08c6f6bbec953220e Mon Sep 17 00:00:00 2001 From: jlaughter <53415135+jlaughter@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:19:02 -0400 Subject: [PATCH] subghz: fix Allstar Firefly serialize/deserialize to use standard block_generic format --- lib/subghz/protocols/allstar_firefly.c | 163 ++++++++++++------------- 1 file changed, 75 insertions(+), 88 deletions(-) diff --git a/lib/subghz/protocols/allstar_firefly.c b/lib/subghz/protocols/allstar_firefly.c index cbec4a36e..29fa86d15 100644 --- a/lib/subghz/protocols/allstar_firefly.c +++ b/lib/subghz/protocols/allstar_firefly.c @@ -2,9 +2,18 @@ * allstar_firefly.c -- Allstar Firefly 318ALD31K native SubGHz protocol * * 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 - * the proven FAP implementation; only the framing (alloc/free/serialize/etc.) - * changes to match the native SubGHz plugin interface. + * 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). + * + * 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. */ @@ -12,6 +21,7 @@ #include "allstar_firefly.h" #include +#include #include #include @@ -20,8 +30,6 @@ #define TAG "AllstarFirefly" -/* --- Decoder instance ------------------------------------------------------ */ - typedef enum { AfRxState_WaitGap, AfRxState_Receiving, @@ -29,6 +37,7 @@ typedef enum { typedef struct { SubGhzProtocolDecoderBase base; + SubGhzBlockGeneric generic; AfRxState rx_state; uint8_t rx_syms[AF_SYM_COUNT]; uint8_t rx_count; @@ -37,6 +46,7 @@ typedef struct { typedef struct { SubGhzProtocolEncoderBase base; + SubGhzBlockGeneric generic; char dip[AF_BIT_COUNT + 1]; uint32_t tx_buf[AF_TX_BUF_SIZE]; uint32_t tx_size; @@ -64,8 +74,8 @@ static bool af_dip_valid(const char* dip) { return (dip[AF_BIT_COUNT] == '\0'); } -static uint32_t af_dip_to_uint32(const char* dip) { - uint32_t val = 0; +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; @@ -74,6 +84,17 @@ static uint32_t af_dip_to_uint32(const char* dip) { 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) { uint32_t pos = 0; 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; } + static void* subghz_protocol_decoder_allstar_firefly_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolDecoderAllstarFirefly* instance = malloc(sizeof(SubGhzProtocolDecoderAllstarFirefly)); - instance->base.protocol = &subghz_protocol_allstar_firefly; - instance->rx_state = AfRxState_WaitGap; - instance->rx_count = 0; + 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'; + instance->dip[AF_BIT_COUNT] = '\0'; return instance; } @@ -139,9 +164,8 @@ static void subghz_protocol_decoder_allstar_firefly_feed( instance->rx_count = 0; return; } - if(instance->rx_count < AF_SYM_COUNT) { + if(instance->rx_count < AF_SYM_COUNT) instance->rx_syms[instance->rx_count++] = sym; - } } } else { if(duration >= AF_FRAME_THRESH_US) { @@ -150,11 +174,10 @@ static void subghz_protocol_decoder_allstar_firefly_feed( char decoded[AF_BIT_COUNT + 1]; if(af_decode_symbols(instance->rx_syms, decoded)) { memcpy(instance->dip, decoded, AF_BIT_COUNT + 1); - if(instance->base.callback) { - instance->base.callback( - &instance->base, - instance->base.context); - } + 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; @@ -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]; return hash; } + static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { - furi_assert(context); SubGhzProtocolDecoderAllstarFirefly* instance = context; - if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { - 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; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } static SubGhzProtocolStatus subghz_protocol_decoder_allstar_firefly_deserialize( void* context, FlipperFormat* flipper_format) { - furi_assert(context); SubGhzProtocolDecoderAllstarFirefly* instance = context; - FuriString* key_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Key", key_str)) { - FURI_LOG_E(TAG, "Missing Key field"); - furi_string_free(key_str); - 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); + 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; } static void subghz_protocol_decoder_allstar_firefly_get_string( void* context, FuriString* output) { - furi_assert(context); SubGhzProtocolDecoderAllstarFirefly* instance = context; - uint32_t code = af_dip_to_uint32(instance->dip); furi_string_cat_printf( output, "%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" "%c %c %c %c %c %c %c %c %c", SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME, - (unsigned long)code, + (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]); } + 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->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; + instance->dip[AF_BIT_COUNT] = '\0'; + instance->tx_size = 0; + instance->tx_pos = 0; return instance; } @@ -263,23 +261,13 @@ static void subghz_protocol_encoder_allstar_firefly_stop(void* context) { static SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize( void* context, FlipperFormat* flipper_format) { - furi_assert(context); SubGhzProtocolEncoderAllstarFirefly* instance = context; - FuriString* key_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Key", key_str)) { - FURI_LOG_E(TAG, "Encoder: missing Key field"); - furi_string_free(key_str); - 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); + 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; @@ -288,22 +276,21 @@ static SubGhzProtocolStatus subghz_protocol_encoder_allstar_firefly_deserialize( 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(); - } + 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, + .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 = { @@ -317,10 +304,10 @@ const SubGhzProtocolEncoder subghz_protocol_encoder_allstar_firefly = { const SubGhzProtocol subghz_protocol_allstar_firefly = { .name = SUBGHZ_PROTOCOL_ALLSTAR_FIREFLY_NAME, .type = SubGhzProtocolTypeStatic, - .flag = SubGhzProtocolFlag_AM | + .flag = SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Load | - SubGhzProtocolFlag_Save | + SubGhzProtocolFlag_Load | + SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, .decoder = &subghz_protocol_decoder_allstar_firefly, .encoder = &subghz_protocol_encoder_allstar_firefly,