diff --git a/lib/subghz/protocols/pocsag.c b/lib/subghz/protocols/pocsag.c new file mode 100644 index 000000000..07716eccc --- /dev/null +++ b/lib/subghz/protocols/pocsag.c @@ -0,0 +1,142 @@ +#include "pocsag.h" + +#include +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + + +#define TAG "POCSAG" + +static const SubGhzBlockConst pocsag_const = { + .te_short = 833, + .te_delta = 100, +}; + +// Minimal amount of sync bits (interleaving zeros and ones) +#define POCSAG_MIN_SYNC_BITS 32 + +struct SubGhzProtocolDecoderPocsag { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + + bool debug; +}; + +typedef struct SubGhzProtocolDecoderPocsag SubGhzProtocolDecoderPocsag; + +typedef enum { + PocsagDecoderStepReset = 0, + PocsagDecoderStepFoundSync, + PocsagDecoderStepFoundPreamble, +} PocsagDecoderStep; + + +void* subghz_protocol_decoder_pocsag_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + + SubGhzProtocolDecoderPocsag* instance = malloc(sizeof(SubGhzProtocolDecoderPocsag)); + instance->base.protocol = &subghz_protocol_pocsag; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_pocsag_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPocsag* instance = context; + free(instance); +} + +void subghz_protocol_decoder_pocsag_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPocsag* instance = context; + + instance->decoder.parser_step = PocsagDecoderStepReset; + instance->decoder.decode_data = 0UL; + instance->decoder.decode_count_bit = 0; + instance->debug = false; +} + +void subghz_protocol_decoder_pocsag_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderPocsag* instance = context; + + // 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) { + // 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; + FURI_LOG_I(TAG, "Sync found"); + } + } + else { + subghz_protocol_decoder_pocsag_reset(context); + } + return; + } + + int bits_count = duration / pocsag_const.te_short; + uint32_t extra = duration - pocsag_const.te_short * bits_count; + + if (DURATION_DIFF(extra, pocsag_const.te_short) < pocsag_const.te_delta) + bits_count++; + else if (extra > pocsag_const.te_delta) { + subghz_protocol_decoder_pocsag_reset(context); + return; + } + + if (level) + FURI_LOG_I(TAG, "1 * %d", bits_count); + else + FURI_LOG_I(TAG, "0 * %d", bits_count); +// +// // as we found sync bits of 32 bits (in fact it is longer), we have to do proper decoding +// // of 1200-bod signal. As it could be any sequence of 1s and 0s, duration might be the +// // multiple of 833 us +// while (true) { +// // signal is too short, but not shorter than delta - something is wrong, reset +//// if (duration < pocsag_const.te_short && +//// DURATION_DIFF(duration, pocsag_const.te_short) > pocsag_const.te_delta) +//// { +//// subghz_protocol_decoder_pocsag_reset(context); +//// return; +//// } +// +// subghz_protocol_blocks_add_bit(&instance->decoder, !level); +// +// // new bit arrived, update the decoding state machine +// switch(instance->decoder.parser_step) { +// case PocsagDecoderStepFoundSync: +// if (instance->decoder.decode_count_bit == 64) { +// FURI_LOG_I(TAG, "%" PRIx64, instance->decoder.decode_data); +// instance->decoder.decode_count_bit = 0; +// } +// break; +// } +// +// if (duration < pocsag_const.te_short) +// break; +// duration -= pocsag_const.te_short; +// } +} + +const SubGhzProtocolDecoder subghz_protocol_pocsag_decoder = { + .alloc = subghz_protocol_decoder_pocsag_alloc, + .free = subghz_protocol_decoder_pocsag_free, + .reset = subghz_protocol_decoder_pocsag_reset, + .feed = subghz_protocol_decoder_pocsag_feed, +}; + +const SubGhzProtocol subghz_protocol_pocsag = { + .name = SUBGHZ_PROTOCOL_POCSAG, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable, + + .decoder = &subghz_protocol_pocsag_decoder, +}; \ No newline at end of file diff --git a/lib/subghz/protocols/pocsag.h b/lib/subghz/protocols/pocsag.h new file mode 100644 index 000000000..a33cc090f --- /dev/null +++ b/lib/subghz/protocols/pocsag.h @@ -0,0 +1,7 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_POCSAG "POCSAG" + +extern const SubGhzProtocol subghz_protocol_pocsag; \ No newline at end of file diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index ebf9b93e4..2794a6ca5 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -12,7 +12,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = { &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, &subghz_protocol_honeywell_wdb, &subghz_protocol_magellan, &subghz_protocol_intertechno_v3, - &subghz_protocol_clemsa, + &subghz_protocol_clemsa, &subghz_protocol_pocsag, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 23aa71be0..cacee3cff 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -35,5 +35,6 @@ #include "magellan.h" #include "intertechno_v3.h" #include "clemsa.h" +#include "pocsag.h" extern const SubGhzProtocolRegistry subghz_protocol_registry;