Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Commit

Permalink
Better pocsag receiver. (#438)
Browse files Browse the repository at this point in the history
  • Loading branch information
Willy-JL authored Nov 2, 2023
2 parents 4b5919c + 189ac5e commit 1beb8f2
Showing 1 changed file with 62 additions and 6 deletions.
68 changes: 62 additions & 6 deletions lib/subghz/protocols/pocsag.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,19 @@ static const SubGhzBlockConst pocsag_const = {
.te_short = 833,
.te_delta = 100,
};
static const SubGhzBlockConst pocsag512_const = {
.te_short = 1950,
.te_long = 1950,
.te_delta = 120,
};
static const SubGhzBlockConst pocsag2400_const = {
.te_short = 410,
.te_long = 410,
.te_delta = 60,
};

// Minimal amount of sync bits (interleaving zeros and ones)
#define POCSAG_MIN_SYNC_BITS 32
#define POCSAG_MIN_SYNC_BITS 24
#define POCSAG_CW_BITS 32
#define POCSAG_CW_MASK 0xFFFFFFFF
#define POCSAG_FRAME_SYNC_CODE 0x7CD215D8
Expand Down Expand Up @@ -45,6 +55,9 @@ struct SubGhzProtocolDecoderPocsag {

// Done messages, ready to be serialized/deserialized
FuriString* done_msg;

SubGhzBlockConst* pocsag_timing;
uint32_t version;
};

typedef struct SubGhzProtocolDecoderPocsag SubGhzProtocolDecoderPocsag;
Expand All @@ -64,6 +77,7 @@ void* subghz_protocol_decoder_pocsag_alloc(SubGhzEnvironment* environment) {
instance->generic.protocol_name = instance->base.protocol->name;
instance->msg = furi_string_alloc();
instance->done_msg = furi_string_alloc();
instance->pocsag_timing = NULL; //not synced yet
if(instance->generic.result_msg == NULL) {
instance->generic.result_msg = furi_string_alloc();
}
Expand Down Expand Up @@ -179,6 +193,38 @@ void subghz_protocol_decoder_pocsag_feed(void* context, bool level, uint32_t dur
// reset state - waiting for 32 bits of interleaving 1s and 0s
if(instance->decoder.parser_step == PocsagDecoderStepReset) {
if(DURATION_DIFF(duration, pocsag_const.te_short) < pocsag_const.te_delta) {
if(instance->pocsag_timing != &pocsag_const) {
//timing changed, so reset before, and override
subghz_protocol_decoder_pocsag_reset(context);
instance->pocsag_timing = (SubGhzBlockConst*)&pocsag_const;
instance->version = 1200;
}
// POCSAG signals are inverted
subghz_protocol_blocks_add_bit(&instance->decoder, !level);

if(instance->decoder.decode_count_bit == POCSAG_MIN_SYNC_BITS) {
instance->decoder.parser_step = PocsagDecoderStepFoundSync;
}
} else if(DURATION_DIFF(duration, pocsag512_const.te_short) < pocsag512_const.te_delta) {
if(instance->pocsag_timing != &pocsag512_const) {
//timing changed, so reset before, and override
subghz_protocol_decoder_pocsag_reset(context);
instance->pocsag_timing = (SubGhzBlockConst*)&pocsag512_const;
instance->version = 512;
}
// POCSAG signals are inverted
subghz_protocol_blocks_add_bit(&instance->decoder, !level);

if(instance->decoder.decode_count_bit == POCSAG_MIN_SYNC_BITS) {
instance->decoder.parser_step = PocsagDecoderStepFoundSync;
}
} else if(DURATION_DIFF(duration, pocsag2400_const.te_short) < pocsag2400_const.te_delta) {
if(instance->pocsag_timing != &pocsag2400_const) {
//timing changed, so reset before, and override
subghz_protocol_decoder_pocsag_reset(context);
instance->pocsag_timing = (SubGhzBlockConst*)&pocsag2400_const;
instance->version = 2400;
}
// POCSAG signals are inverted
subghz_protocol_blocks_add_bit(&instance->decoder, !level);

Expand All @@ -191,12 +237,12 @@ void subghz_protocol_decoder_pocsag_feed(void* context, bool level, uint32_t dur
return;
}

int bits_count = duration / pocsag_const.te_short;
uint32_t extra = duration - pocsag_const.te_short * bits_count;
int bits_count = duration / instance->pocsag_timing->te_short;
uint32_t extra = duration - instance->pocsag_timing->te_short * bits_count;

if(DURATION_DIFF(extra, pocsag_const.te_short) < pocsag_const.te_delta)
if(DURATION_DIFF(extra, instance->pocsag_timing->te_short) < instance->pocsag_timing->te_delta)
bits_count++;
else if(extra > pocsag_const.te_delta) {
else if(extra > instance->pocsag_timing->te_delta) {
// in non-reset state we faced the error signal - we reached the end of the packet, flush data
if(furi_string_size(instance->done_msg) > 0) {
if(instance->base.callback)
Expand Down Expand Up @@ -305,6 +351,11 @@ SubGhzProtocolStatus subghz_protocol_decoder_pocsag_serialize(
return SubGhzProtocolStatusError;
}

if(!flipper_format_write_uint32(flipper_format, "PocsagVer", &instance->version, 1)) {
FURI_LOG_E(TAG, "Error adding PocsagVer");
return SubGhzProtocolStatusError;
}

uint8_t* s = (uint8_t*)furi_string_get_cstr(instance->done_msg);
if(!flipper_format_write_hex(flipper_format, "Msg", s, msg_len)) {
FURI_LOG_E(TAG, "Error adding Msg");
Expand All @@ -331,6 +382,9 @@ SubGhzProtocolStatus
FURI_LOG_E(TAG, "Missing MsgLen");
break;
}
//optional, so compatible backwards
instance->version = 1200;
flipper_format_read_uint32(flipper_format, "PocsagVer", &instance->version, 1);

buf = malloc(msg_len);
if(!flipper_format_read_hex(flipper_format, "Msg", buf, msg_len)) {
Expand All @@ -349,7 +403,9 @@ SubGhzProtocolStatus
void subhz_protocol_decoder_pocsag_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderPocsag* instance = context;
furi_string_cat_printf(output, "%s\r\n", instance->generic.protocol_name);
furi_string_cat_printf(
output, "%s %lu\r\n", instance->generic.protocol_name, instance->version);
furi_string_cat_printf(output, "Addr: %lu\r\n", instance->ric);
furi_string_cat(output, instance->done_msg);
}

Expand Down

0 comments on commit 1beb8f2

Please sign in to comment.