mirror of https://github.com/hmatuschek/libsdr
Implemented POCSAG decoder.
parent
0b7bc758d5
commit
0ad4ec8634
@ -0,0 +1,71 @@
|
|||||||
|
#include "autocast.hh"
|
||||||
|
#include "portaudio.hh"
|
||||||
|
#include "wavfile.hh"
|
||||||
|
#include "afsk.hh"
|
||||||
|
#include "utils.hh"
|
||||||
|
#include "pocsag.hh"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
static void __sigint_handler(int signo) {
|
||||||
|
// On SIGINT -> stop queue properly
|
||||||
|
Queue::get().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (2 != argc) {
|
||||||
|
std::cerr << "Usage: sdr_posag FILENAME" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdr::Logger::get().addHandler(
|
||||||
|
new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG));
|
||||||
|
|
||||||
|
// Register handler:
|
||||||
|
signal(SIGINT, __sigint_handler);
|
||||||
|
|
||||||
|
PortAudio::init();
|
||||||
|
|
||||||
|
Queue &queue = Queue::get();
|
||||||
|
|
||||||
|
WavSource src(argv[1]);
|
||||||
|
PortSink sink;
|
||||||
|
AutoCast<int16_t> cast;
|
||||||
|
ASKDetector<int16_t> detector;
|
||||||
|
BitStream bits(1200, BitStream::NORMAL);
|
||||||
|
POCSAG pocsag;
|
||||||
|
|
||||||
|
//BitDump dump;
|
||||||
|
|
||||||
|
// Playback
|
||||||
|
//src.connect(&sink);
|
||||||
|
// Cast to int16
|
||||||
|
src.connect(&cast);
|
||||||
|
// ASK detector
|
||||||
|
cast.connect(&detector);
|
||||||
|
detector.connect(&bits);
|
||||||
|
// Baudot decoder
|
||||||
|
// dump to std::cerr
|
||||||
|
bits.connect(&pocsag);
|
||||||
|
|
||||||
|
// on idle -> read next buffer from input file
|
||||||
|
queue.addIdle(&src, &WavSource::next);
|
||||||
|
// on end-of-file -> stop queue
|
||||||
|
src.addEOS(&queue, &Queue::stop);
|
||||||
|
|
||||||
|
// Start queue
|
||||||
|
queue.start();
|
||||||
|
// wait for queue to exit
|
||||||
|
queue.wait();
|
||||||
|
|
||||||
|
// terminate port audio system properly
|
||||||
|
PortAudio::terminate();
|
||||||
|
|
||||||
|
// quit.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,213 @@
|
|||||||
|
#include "bch31_21.hh"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the code used by POCSAG is a (n=31,k=21) BCH Code with dmin=5,
|
||||||
|
* thus it could correct two bit errors in a 31-Bit codeword.
|
||||||
|
* It is a systematic code.
|
||||||
|
* The generator polynomial is:
|
||||||
|
* g(x) = x^10+x^9+x^8+x^6+x^5+x^3+1
|
||||||
|
* The parity check polynomial is:
|
||||||
|
* h(x) = x^21+x^20+x^18+x^16+x^14+x^13+x^12+x^11+x^8+x^5+x^3+1
|
||||||
|
* g(x) * h(x) = x^n+1
|
||||||
|
*/
|
||||||
|
#define BCH_POLY 03551 /* octal */
|
||||||
|
#define BCH_N 31
|
||||||
|
#define BCH_K 21
|
||||||
|
|
||||||
|
static inline unsigned char even_parity(uint32_t data)
|
||||||
|
{
|
||||||
|
unsigned int temp = data ^ (data >> 16);
|
||||||
|
|
||||||
|
temp = temp ^ (temp >> 8);
|
||||||
|
temp = temp ^ (temp >> 4);
|
||||||
|
temp = temp ^ (temp >> 2);
|
||||||
|
temp = temp ^ (temp >> 1);
|
||||||
|
return temp & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
pocsag_syndrome(uint32_t data)
|
||||||
|
{
|
||||||
|
uint32_t shreg = data >> 1; /* throw away parity bit */
|
||||||
|
uint32_t mask = 1L << (BCH_N-1), coeff = BCH_POLY << (BCH_K-1);
|
||||||
|
int n = BCH_K;
|
||||||
|
|
||||||
|
for(; n > 0; mask >>= 1, coeff >>= 1, n--) {
|
||||||
|
if (shreg & mask) { shreg ^= coeff; }
|
||||||
|
}
|
||||||
|
if (even_parity(data)) {
|
||||||
|
shreg |= (1 << (BCH_N - BCH_K));
|
||||||
|
}
|
||||||
|
return shreg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bitslice_syndrome(uint32_t *slices)
|
||||||
|
{
|
||||||
|
const int firstBit = BCH_N - 1;
|
||||||
|
int i, n;
|
||||||
|
uint32_t paritymask = slices[0];
|
||||||
|
|
||||||
|
// do the parity and shift together
|
||||||
|
for (i = 1; i < 32; ++i) {
|
||||||
|
paritymask ^= slices[i];
|
||||||
|
slices[i-1] = slices[i];
|
||||||
|
}
|
||||||
|
slices[31] = 0;
|
||||||
|
|
||||||
|
// BCH_POLY << (BCH_K - 1) is
|
||||||
|
// 20 21 22 23
|
||||||
|
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ONE, 0, 0, ONE,
|
||||||
|
// 24 25 26 27 28 29 30 31
|
||||||
|
// 0, ONE, ONE, 0, ONE, ONE, ONE, 0
|
||||||
|
|
||||||
|
for (n = 0; n < BCH_K; ++n) {
|
||||||
|
// one line here for every '1' bit in coeff (above)
|
||||||
|
const int bit = firstBit - n;
|
||||||
|
slices[20 - n] ^= slices[bit];
|
||||||
|
slices[23 - n] ^= slices[bit];
|
||||||
|
slices[25 - n] ^= slices[bit];
|
||||||
|
slices[26 - n] ^= slices[bit];
|
||||||
|
slices[28 - n] ^= slices[bit];
|
||||||
|
slices[29 - n] ^= slices[bit];
|
||||||
|
slices[30 - n] ^= slices[bit];
|
||||||
|
slices[31 - n] ^= slices[bit];
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply the parity mask we built up
|
||||||
|
slices[BCH_N - BCH_K] |= paritymask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
transpose_n(int n, uint32_t *matrix)
|
||||||
|
{
|
||||||
|
uint32_t out = 0;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < 32; ++j) {
|
||||||
|
if (matrix[j] & (1<<n)) {
|
||||||
|
out |= (1<<j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t *
|
||||||
|
transpose_clone(uint32_t src, uint32_t *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!out) { out = (uint32_t *)malloc(sizeof(uint32_t)*32); }
|
||||||
|
for (i = 0; i < 32; ++i) {
|
||||||
|
if (src & (1<<i)) {
|
||||||
|
out[i] = 0xffffffff;
|
||||||
|
} else {
|
||||||
|
out[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This might not be elegant, yet effective!
|
||||||
|
// Error correction via bruteforce ;)
|
||||||
|
//
|
||||||
|
// It's a pragmatic solution since this was much faster to implement
|
||||||
|
// than understanding the math to solve it while being as effective.
|
||||||
|
// Besides that the overhead is neglectable.
|
||||||
|
int
|
||||||
|
sdr::pocsag_repair(uint32_t &data)
|
||||||
|
{
|
||||||
|
// Check if data is correct
|
||||||
|
if (0 == pocsag_syndrome(data)) { return 0; }
|
||||||
|
|
||||||
|
int i, n, b1, b2;
|
||||||
|
uint32_t res;
|
||||||
|
uint32_t *xpose = 0, *in = 0;
|
||||||
|
|
||||||
|
// check for single bit errors
|
||||||
|
xpose = (uint32_t *) malloc(sizeof(uint32_t)*32);
|
||||||
|
in = (uint32_t *) malloc(sizeof(uint32_t)*32);
|
||||||
|
|
||||||
|
transpose_clone(data, xpose);
|
||||||
|
for (i = 0; i < 32; ++i) { xpose[i] ^= (1<<i); }
|
||||||
|
bitslice_syndrome(xpose);
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
for (i = 0; i < 32; ++i) { res |= xpose[i]; }
|
||||||
|
res = ~res;
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
int n = 0;
|
||||||
|
while (res) { ++n; res >>= 1; }
|
||||||
|
--n;
|
||||||
|
data ^= (1<<n);
|
||||||
|
goto returnfree;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check for two bit errors
|
||||||
|
n = 0;
|
||||||
|
transpose_clone(data, xpose);
|
||||||
|
|
||||||
|
for (b1 = 0; b1 < 32; ++b1) {
|
||||||
|
for (b2 = b1; b2 < 32; ++b2) {
|
||||||
|
xpose[b1] ^= (1<<n);
|
||||||
|
xpose[b2] ^= (1<<n);
|
||||||
|
|
||||||
|
if (++n == 32) {
|
||||||
|
memcpy(in, xpose, sizeof(uint32_t)*32);
|
||||||
|
bitslice_syndrome(xpose);
|
||||||
|
res = 0;
|
||||||
|
for (i = 0; i < 32; ++i) { res |= xpose[i]; }
|
||||||
|
res = ~res;
|
||||||
|
if (res) {
|
||||||
|
int n = 0;
|
||||||
|
while (res) { ++n; res >>= 1; }
|
||||||
|
--n;
|
||||||
|
|
||||||
|
data = transpose_n(n, in);
|
||||||
|
goto returnfree;
|
||||||
|
}
|
||||||
|
|
||||||
|
transpose_clone(data, xpose);
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
memcpy(in, xpose, sizeof(uint32_t)*32);
|
||||||
|
|
||||||
|
bitslice_syndrome(xpose);
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
for (i = 0; i < 32; ++i) { res |= xpose[i]; }
|
||||||
|
res = ~res;
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
int n = 0;
|
||||||
|
while (res) { ++n; res >>= 1; }
|
||||||
|
--n;
|
||||||
|
|
||||||
|
data = transpose_n(n, in);
|
||||||
|
goto returnfree;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xpose) { free(xpose); }
|
||||||
|
if (in) { free(in); }
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
returnfree:
|
||||||
|
if (xpose)
|
||||||
|
free(xpose);
|
||||||
|
if (in)
|
||||||
|
free(in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __SDR_BCH31_21_HH__
|
||||||
|
#define __SDR_BCH31_21_HH__
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
namespace sdr {
|
||||||
|
|
||||||
|
/** Checks and repairs a POCSAG message with its
|
||||||
|
* BCH(31,21) ECC. */
|
||||||
|
int pocsag_repair(uint32_t &data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __SDR_BCH31_21_HH__
|
||||||
@ -0,0 +1,195 @@
|
|||||||
|
#include "pocsag.hh"
|
||||||
|
#include "bch31_21.hh"
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
inline bool is_address(uint32_t word) {
|
||||||
|
return (0 == (0x80000000 & word));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
POCSAG::POCSAG()
|
||||||
|
: Sink<uint8_t>()
|
||||||
|
{
|
||||||
|
// pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::config(const Config &src_cfg) {
|
||||||
|
if (! src_cfg.hasType()) { return; }
|
||||||
|
// Check if buffer type matches
|
||||||
|
if (Config::typeId<uint8_t>() != src_cfg.type()) {
|
||||||
|
ConfigError err;
|
||||||
|
err << "Can not configure POCSAG: Invalid type " << src_cfg.type()
|
||||||
|
<< ", expected " << Config::typeId<uint8_t>();
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
_state = WAIT;
|
||||||
|
_bits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::process(const Buffer<uint8_t> &buffer, bool allow_overwrite)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<buffer.size(); i++)
|
||||||
|
{
|
||||||
|
// put bit into shift register
|
||||||
|
_bits = ( (_bits<<1) | (buffer[i] & 0x01) );
|
||||||
|
|
||||||
|
// Dispatch by state
|
||||||
|
if (WAIT == _state) {
|
||||||
|
// Wait for the sync word to appear
|
||||||
|
uint32_t word = (_bits & 0xffffffff);
|
||||||
|
if ( (0 == pocsag_repair(word)) && (0x7cd215d8 == word)) {
|
||||||
|
// init messages
|
||||||
|
_reset_all_messages();
|
||||||
|
_state = RECEIVE; _bitcount = 0; _slot = 0;
|
||||||
|
}
|
||||||
|
} else if (RECEIVE == _state) {
|
||||||
|
// Receive 64 bit (2 words)
|
||||||
|
_bitcount++;
|
||||||
|
if (64 == _bitcount) {
|
||||||
|
_bitcount=0;
|
||||||
|
|
||||||
|
// get and check 1st word bits
|
||||||
|
uint32_t word = ( (_bits>>32) & 0xffffffff );
|
||||||
|
if (0 == pocsag_repair(word)) { _process_word(word); }
|
||||||
|
|
||||||
|
// get and check 2nd word bits
|
||||||
|
word = ( _bits & 0xffffffff );
|
||||||
|
if (0 == pocsag_repair(word)) { _process_word(word); }
|
||||||
|
|
||||||
|
// Advance slot counter
|
||||||
|
_slot++;
|
||||||
|
if (8 == _slot) {
|
||||||
|
// If all slots (8) has been processed -> wait for continuation
|
||||||
|
_state = CHECK_CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (CHECK_CONTINUE == _state) {
|
||||||
|
// Wait for an immediate sync word
|
||||||
|
_bitcount++;
|
||||||
|
if (32 == _bitcount) {
|
||||||
|
uint32_t word = (_bits&0xffffffff);
|
||||||
|
if ( (0 == pocsag_repair(word)) && (0x7cd215d8 == word)) {
|
||||||
|
// If a sync word has been received -> continue with reception of slot 0
|
||||||
|
_state = RECEIVE; _slot = 0; _bitcount = 0;
|
||||||
|
} else {
|
||||||
|
// Otherwise -> end of transmission, wait for next sync
|
||||||
|
_finish_all_messages(); _state = WAIT;
|
||||||
|
this->handleMessages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::_process_word(uint32_t word)
|
||||||
|
{
|
||||||
|
// Check if slot is skipped
|
||||||
|
if (0x7A89C197 == word) { // Skip slot
|
||||||
|
_finish_message(_slot); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if word is an address word
|
||||||
|
if (is_address(word)) {
|
||||||
|
_finish_message(_slot);
|
||||||
|
// Assemble address
|
||||||
|
uint32_t addr = (((word>>13) & 0x03ffff)<<3) | (_slot & 0x03);
|
||||||
|
uint8_t func = ((word>>11) & 0x03);
|
||||||
|
_messages[_slot] = Message(addr, func);
|
||||||
|
} else {
|
||||||
|
if (_messages[_slot].isEmpty()) {
|
||||||
|
std::cerr << "Oops: Payload w/o address in slot " << int(_slot)
|
||||||
|
<< " word: " << std::hex << word << std::dec << std::endl;
|
||||||
|
}
|
||||||
|
_messages[_slot].addPayload(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::_reset_message(uint8_t slot) {
|
||||||
|
_messages[slot] = Message();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::_reset_all_messages() {
|
||||||
|
for (uint8_t i=0; i<8; i++) {
|
||||||
|
_reset_message(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::_finish_message(uint8_t slot) {
|
||||||
|
if (_messages[slot].isEmpty()) { return; }
|
||||||
|
_queue.push_back(_messages[slot]);
|
||||||
|
_reset_message(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::_finish_all_messages() {
|
||||||
|
for (uint8_t i=0; i<8; i++) {
|
||||||
|
_finish_message(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::handleMessages() {
|
||||||
|
// You may re-implement this virutal method to process the queued messages in _queue.
|
||||||
|
while (_queue.size()) {
|
||||||
|
Message msg = _queue.back(); _queue.pop_back();
|
||||||
|
std::cerr << "POCSAG: @" << msg.address()
|
||||||
|
<< ", F=" << int(msg.function())
|
||||||
|
<< ", bits=" << msg.bits() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
POCSAG::Message::Message()
|
||||||
|
: _address(0), _function(0), _empty(true), _bits(0)
|
||||||
|
{
|
||||||
|
// pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
POCSAG::Message::Message(uint32_t addr, uint8_t func)
|
||||||
|
: _address(addr), _function(func), _empty(false), _bits(0)
|
||||||
|
{
|
||||||
|
// pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
POCSAG::Message::Message(const Message &other)
|
||||||
|
: _address(other._address), _function(other._function), _empty(other._empty),
|
||||||
|
_bits(other._bits), _payload(other._payload)
|
||||||
|
{
|
||||||
|
// pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
POCSAG::Message &
|
||||||
|
POCSAG::Message::operator =(const Message &other) {
|
||||||
|
_address = other._address;
|
||||||
|
_function = other._function;
|
||||||
|
_empty = other._empty;
|
||||||
|
_bits = other._bits;
|
||||||
|
_payload = other._payload;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
POCSAG::Message::addPayload(uint32_t word) {
|
||||||
|
// Add 20 LSB bits from data to payload vector
|
||||||
|
uint32_t mask = 0x40000000;
|
||||||
|
for (size_t i=0; i<20; i++) {
|
||||||
|
// on new byte
|
||||||
|
if (0 == (_bits % 8)) { _payload.push_back(0x00); }
|
||||||
|
// add bit to last byte of payload
|
||||||
|
_payload.back() = ((_payload.back()<<1)|(word&mask));
|
||||||
|
// Increment bit counter and update mask
|
||||||
|
_bits++; mask = (mask>>1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
#ifndef __SDR_POSAG_HH__
|
||||||
|
#define __SDR_POSAG_HH__
|
||||||
|
|
||||||
|
#include "node.hh"
|
||||||
|
|
||||||
|
namespace sdr {
|
||||||
|
|
||||||
|
/** Implements a POCSAG decoder.
|
||||||
|
* In conjecture with the @c FSKDetector or @c AFSDetector and the @c BitStream nodes, this node
|
||||||
|
* can be used to receive and process POCSAG (pages) messages.
|
||||||
|
*
|
||||||
|
* The POCSAG protocol is defined as followig:
|
||||||
|
*
|
||||||
|
* 1) at least 576 bits of alternating value (1 0 1 0 ...)
|
||||||
|
* 2) a 32-bit sync word (0x7CD215D8)
|
||||||
|
* 3) 16 data words (each 32 bit)
|
||||||
|
*
|
||||||
|
* Unused data words are send as 0x7A89C197. Each dataword is either a address word (bit 31 = 0)
|
||||||
|
* or message word (bit 31 = 1).
|
||||||
|
*
|
||||||
|
* Address word:
|
||||||
|
*
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | 0 | Address (18bits) |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | ... |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | ... | F1 F0 | ECC ... |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | ... (10 bits) | P |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
*
|
||||||
|
* Message word
|
||||||
|
*
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | 0 | Data (20bits) |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | ... |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | ... | ECC ... |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
* | ... (10 bits) | P |
|
||||||
|
* +---+---+---+---+---+---+---+---+
|
||||||
|
*
|
||||||
|
* @ingroup datanodes */
|
||||||
|
class POCSAG: public Sink<uint8_t>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Message {
|
||||||
|
public:
|
||||||
|
Message();
|
||||||
|
Message(uint32_t addr, uint8_t func);
|
||||||
|
Message(const Message &other);
|
||||||
|
|
||||||
|
Message &operator=(const Message &other);
|
||||||
|
|
||||||
|
inline bool isEmpty() const { return _empty; }
|
||||||
|
inline uint32_t address() const { return _address; }
|
||||||
|
inline uint8_t function() const { return _function; }
|
||||||
|
inline uint32_t bits() const { return _bits; }
|
||||||
|
void addPayload(uint32_t word);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t _address;
|
||||||
|
uint8_t _function;
|
||||||
|
bool _empty;
|
||||||
|
uint32_t _bits;
|
||||||
|
std::vector<uint8_t> _payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef enum {
|
||||||
|
WAIT,
|
||||||
|
RECEIVE,
|
||||||
|
CHECK_CONTINUE
|
||||||
|
} State;
|
||||||
|
|
||||||
|
public:
|
||||||
|
POCSAG();
|
||||||
|
|
||||||
|
void config(const Config &src_cfg);
|
||||||
|
void process(const Buffer<uint8_t> &buffer, bool allow_overwrite);
|
||||||
|
|
||||||
|
virtual void handleMessages();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _process_word(uint32_t word);
|
||||||
|
void _reset_all_messages();
|
||||||
|
void _reset_message(uint8_t slot);
|
||||||
|
void _finish_all_messages();
|
||||||
|
void _finish_message(uint8_t slot);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
State _state;
|
||||||
|
uint64_t _bits;
|
||||||
|
uint8_t _bitcount;
|
||||||
|
uint8_t _slot;
|
||||||
|
|
||||||
|
Message _messages[8];
|
||||||
|
std::list<Message> _queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // POSAG_HH
|
||||||
Loading…
Reference in New Issue