diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index ddec7af8..7a395123 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -431,7 +431,6 @@ DeclareTargets(POOK ook) set(MODE_CPPSRC proc_pocsag.cpp - extract_frame_pager.cpp ) DeclareTargets(PPOC pocsag) diff --git a/firmware/baseband/extract_frame_pager.cpp b/firmware/baseband/extract_frame_pager.cpp deleted file mode 100644 index 62a2a02f..00000000 --- a/firmware/baseband/extract_frame_pager.cpp +++ /dev/null @@ -1,451 +0,0 @@ -#include "extract_frame_pager.hpp" -#include // std::max -#include - -#define BAUD_STABLE (104) -#define MAX_CONSEC_SAME (32) -#define MAX_WITHOUT_SINGLE (64) -#define MAX_BAD_TRANS (10) - -#define M_SYNC (0x7cd215d8) -#define M_NOTSYNC (0x832dea27) - -#define M_IDLE (0x7a89c197) - -// ==================================================================== -// -// ==================================================================== -inline int bitsDiff(unsigned long left, unsigned long right) -{ - unsigned long xord = left ^ right; - int count = 0; - for (int i = 0; i < 32; i++) - { - if ((xord & 0x01) != 0) ++count; - xord = xord >> 1; - } - return(count); - -} - - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// -extract_frame_pager::extract_frame_pager() -{ - init(); -} - -// ==================================================================== -// -// ==================================================================== -extract_frame_pager::~extract_frame_pager() -{ -} - -// ==================================================================== -// -// ==================================================================== -void extract_frame_pager::init() -{ - m_averageSymbolLen_1024 = m_maxSymSamples_1024; - m_lastStableSymbolLen_1024 = m_minSymSamples_1024; - - m_badTransitions = 0; - m_bitsStart = 0; - m_bitsEnd = 0; - m_inverted = false; - - resetVals(); -} - -// ==================================================================== -// -// ==================================================================== -void extract_frame_pager::resetVals() -{ - // Set up the xtraction mode - m_detectionMode = DM_DYNAMIC; - - // Reset the parameters - // -------------------- - m_goodTransitions = 0; - m_badTransitions = 0; - m_averageSymbolLen_1024 = m_maxSymSamples_1024; - m_shortestGoodTrans_1024 = m_maxSymSamples_1024; - m_valMid = 0; - - // And reset the counts - // -------------------- - m_lastTransPos_1024 = 0; - m_lastBitPos_1024 = 0; - m_lastSample = 0; - m_sampleNo = 0; - m_nextBitPos_1024 = m_maxSymSamples_1024; - m_nextBitPosInt = (long)m_nextBitPos_1024; - - // Extraction - m_fifo.numBits = 0; - m_gotSync = false; - m_numCode = 0; -} - -// ==================================================================== -// -// ==================================================================== -void extract_frame_pager::setFrameExtractParams(long a_samplesPerSec, long a_maxBaud, long a_minBaud, long maxRunOfSameValue) -{ - m_samplesPerSec = a_samplesPerSec; - m_minSymSamples_1024 = (uint32_t)(1024.0f * (float)a_samplesPerSec / (float)a_maxBaud); - m_maxSymSamples_1024 = (uint32_t)(1024.0f*(float)a_samplesPerSec / (float)a_minBaud); - m_maxRunOfSameValue = maxRunOfSameValue; - - m_shortestGoodTrans_1024 = m_maxSymSamples_1024; - m_averageSymbolLen_1024 = m_maxSymSamples_1024; - m_lastStableSymbolLen_1024 = m_minSymSamples_1024; - - m_nextBitPos_1024 = m_averageSymbolLen_1024 / 2; - m_nextBitPosInt = m_nextBitPos_1024 >> 10; - - init(); -} - -// ==================================================================== -// -// ==================================================================== -int extract_frame_pager::processDemodulatedSamples(float * sampleBuff, int noOfSamples) -{ - bool transition = false; - uint32_t samplePos_1024 = 0; - uint32_t len_1024 = 0; - - // Loop through the block of data - // ------------------------------ - for (int pos = 0; pos < noOfSamples; ++pos) - { - m_sample = sampleBuff[pos]; - m_valMid += (m_sample - m_valMid) / 1024.0f; - - ++m_sampleNo; - - // Detect Transition - // ----------------- - transition = ! ((m_lastSample < m_valMid) ^ (m_sample >= m_valMid)); // use XOR for speed - - // If this is a transition - // ----------------------- - if (transition) - { - // Calculate samples since last trans - // ---------------------------------- - int32_t fractional_1024 = (int32_t)(((m_sample - m_valMid)*1024) / (m_sample - m_lastSample)); - if (fractional_1024 < 0) { fractional_1024 = -fractional_1024; } - - samplePos_1024 = (m_sampleNo<<10)-fractional_1024; - len_1024 = samplePos_1024 - m_lastTransPos_1024; - m_lastTransPos_1024 = samplePos_1024; - - // If symbol is large enough to be valid - // ------------------------------------- - if (len_1024 > m_minSymSamples_1024) - { - // Check for shortest good transition - // ---------------------------------- - if ((len_1024 < m_shortestGoodTrans_1024) && - (m_goodTransitions < BAUD_STABLE)) // detect change of symbol size - { - int32_t fractionOfShortest_1024 = (len_1024<<10) / m_shortestGoodTrans_1024; - - // If currently at half the baud rate - // ---------------------------------- - if ((fractionOfShortest_1024 > 410) && (fractionOfShortest_1024 < 614)) // 0.4 and 0.6 - { - m_averageSymbolLen_1024 /= 2; - m_shortestGoodTrans_1024 = len_1024; - } - // If currently at the wrong baud rate - // ----------------------------------- - else if (fractionOfShortest_1024 < 768) // 0.75 - { - m_averageSymbolLen_1024 = len_1024; - m_shortestGoodTrans_1024 = len_1024; - m_goodTransitions = 0; - m_lastSingleBitPos_1024 = samplePos_1024 - len_1024; - } - } - - // Calc the number of bits since events - // ------------------------------------ - int32_t halfSymbol_1024 = m_averageSymbolLen_1024 / 2; - int bitsSinceLastTrans = max((uint32_t)1, (len_1024+halfSymbol_1024) / m_averageSymbolLen_1024 ); - int bitsSinceLastSingle = (((m_sampleNo<<10)-m_lastSingleBitPos_1024) + halfSymbol_1024) / m_averageSymbolLen_1024; - - // Check for single bit - // -------------------- - if (bitsSinceLastTrans == 1) - { - m_lastSingleBitPos_1024 = samplePos_1024; - } - - // If too long since last transition - // --------------------------------- - if (bitsSinceLastTrans > MAX_CONSEC_SAME) - { - resetVals(); - } - // If too long sice last single bit - // -------------------------------- - else if (bitsSinceLastSingle > MAX_WITHOUT_SINGLE) - { - resetVals(); - } - else - { - // If this is a good transition - // ---------------------------- - int32_t offsetFromExtectedTransition_1024 = len_1024 - (bitsSinceLastTrans*m_averageSymbolLen_1024); - if (offsetFromExtectedTransition_1024 < 0) { offsetFromExtectedTransition_1024 = -offsetFromExtectedTransition_1024; } - if (offsetFromExtectedTransition_1024 < (m_averageSymbolLen_1024 / 4)) // Has to be within 1/4 of symbol to be good - { - ++m_goodTransitions; - uint32_t bitsCount = min((uint32_t)BAUD_STABLE, m_goodTransitions); - - uint32_t propFromPrevious = m_averageSymbolLen_1024*bitsCount; - uint32_t propFromCurrent = (len_1024 / bitsSinceLastTrans); - m_averageSymbolLen_1024 = (propFromPrevious + propFromCurrent) / (bitsCount + 1); - m_badTransitions = 0; - //if ( len < m_shortestGoodTrans ){m_shortestGoodTrans = len;} - // Store the old symbol size - if (m_goodTransitions >= BAUD_STABLE) - { - m_lastStableSymbolLen_1024 = m_averageSymbolLen_1024; - } - } - // Not a good transition - // --------------------- - else - { - // m_goodTransitions = 0; - } - } - - // Set the point of the last bit if not yet stable - // ----------------------------------------------- - if ((m_goodTransitions < BAUD_STABLE) || (m_badTransitions > 0)) - { - m_lastBitPos_1024 = samplePos_1024 - (m_averageSymbolLen_1024 / 2); - } - - // Calculate the exact positiom of the next bit - // -------------------------------------------- - int32_t thisPlusHalfsymbol_1024 = samplePos_1024 + (m_averageSymbolLen_1024/2); - int32_t lastPlusSymbol = m_lastBitPos_1024 + m_averageSymbolLen_1024; - m_nextBitPos_1024 = lastPlusSymbol + ((thisPlusHalfsymbol_1024 - lastPlusSymbol) / 16); - - // Check for bad pos error - // ----------------------- - if (m_nextBitPos_1024 < samplePos_1024) m_nextBitPos_1024 += m_averageSymbolLen_1024; - - // Calculate integer sample after next bit - // --------------------------------------- - m_nextBitPosInt = (m_nextBitPos_1024>>10) + 1; - - } // symbol is large enough to be valid - else - { - // Bad transition, so reset the counts - // ----------------------------------- - ++m_badTransitions; - if (m_badTransitions > MAX_BAD_TRANS) - { - resetVals(); - } - } - } // end of if transition - else - { - //TRACE("Len too small %f",len); - } - - // Reached the point of the next bit - // --------------------------------- - if (m_sampleNo >= m_nextBitPosInt) - { - // Everything is good so extract a bit - // ----------------------------------- - if (m_goodTransitions > 20) - { - // Store value at the center of bit - // -------------------------------- - storeBit(); - } - // Check for long 1 or zero - // ------------------------ - int bitsSinceLastTrans = ((m_sampleNo<<10) - m_lastTransPos_1024) / m_averageSymbolLen_1024; - if (bitsSinceLastTrans > m_maxRunOfSameValue) - { - resetVals(); - } - - // Store the point of the last bit - // ------------------------------- - m_lastBitPos_1024 = m_nextBitPos_1024; - - // Calculate the exact point of the next bit - // ----------------------------------------- - m_nextBitPos_1024 += m_averageSymbolLen_1024; - - // Look for the bit after the next bit pos - // --------------------------------------- - m_nextBitPosInt = (m_nextBitPos_1024>>10) + 1; - - } // Reached the point of the next bit - - m_lastSample = m_sample; - - } // Loop through the block of data - - return getNoOfBits(); -} - -// ==================================================================== -// -// ==================================================================== -void extract_frame_pager::storeBit() -{ - if (++m_bitsStart >= BIT_BUF_SIZE) { m_bitsStart = 0; } - - // Calculate the bit value - float sample = (m_sample + m_lastSample) / 2; - //int32_t sample_1024 = m_sample_1024; - bool bit = sample > m_valMid; - - // If buffer not full - if (m_bitsStart != m_bitsEnd) - { - // Decide on output val - if (bit) - { - m_bits[m_bitsStart] = 0; - } - else - { - m_bits[m_bitsStart] = 1; - } - } - // Throw away bits if the buffer is full - else - { - if (--m_bitsStart <= -1) - { - m_bitsStart = BIT_BUF_SIZE - 1; - } - } -} - -// ==================================================================== -// -// ==================================================================== -int extract_frame_pager::extractFrames() -{ - int msgCnt = 0; - // While there is unread data in the bits buffer - //---------------------------------------------- - while (getNoOfBits() > 0) - { - m_fifo.codeword = (m_fifo.codeword << 1) + getBit(); - m_fifo.numBits++; - - // If number of bits in fifo equals 32 - //------------------------------------ - if (m_fifo.numBits >= 32) - { - // Not got sync - // ------------ - if (!m_gotSync) - { - if (bitsDiff(m_fifo.codeword, M_SYNC) <= 2) - { - m_inverted = false; - m_gotSync = true; - m_numCode = -1; - m_fifo.numBits = 0; - //TRACE("SYNC %x %d\n", m_fifo.codeword, m_numCode); - } - else if (bitsDiff(m_fifo.codeword, M_NOTSYNC) <= 2) - { - m_inverted = true; - m_gotSync = true; - m_numCode = -1; - m_fifo.numBits = 0; - //TRACE("ISYNC %x %d\n", m_fifo.codeword, m_numCode); - } - else - { - // Cause it to load one more bit - m_fifo.numBits = 31; - } - } // Not got sync - else - { - // Increment the word count - // ------------------------ - ++m_numCode; // It got set to -1 when a sync was found, now count the 16 words - uint32_t val = m_inverted ? ~m_fifo.codeword : m_fifo.codeword; - OnDataWord(val, m_numCode); - //TRACE("WORD %x %d\n", m_fifo.codeword, m_numCode); - - // If at the end of a 16 word block - // -------------------------------- - if (m_numCode >= 15) - { - msgCnt += OnDataFrame(m_numCode+1, (m_samplesPerSec<<10) / m_lastStableSymbolLen_1024); - m_gotSync = false; - m_numCode = -1; - } - m_fifo.numBits = 0; - } - } // If number of bits in fifo equals 32 - } // While there is unread data in the bits buffer - return msgCnt; -} // extractFrames - -// ==================================================================== -// -// ==================================================================== -// -// ==================================================================== -short extract_frame_pager::getBit() -{ - if (m_bitsEnd != m_bitsStart) - { - if (++m_bitsEnd >= BIT_BUF_SIZE) - { - m_bitsEnd = 0; - } - return m_bits[m_bitsEnd]; - } - else - { - return -1; - } -} - -// ==================================================================== -// -// ==================================================================== -int extract_frame_pager::getNoOfBits() -{ - int bits = m_bitsEnd - m_bitsStart; - if (bits < 0) { bits += BIT_BUF_SIZE; } - return bits; -} - -// ==================================================================== -// -// ==================================================================== -uint32_t extract_frame_pager::getRate() -{ - return ((m_samplesPerSec<<10)+512) / m_lastStableSymbolLen_1024; -} diff --git a/firmware/baseband/extract_frame_pager.hpp b/firmware/baseband/extract_frame_pager.hpp deleted file mode 100644 index 6642c2e7..00000000 --- a/firmware/baseband/extract_frame_pager.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __EXTRACT_FRAME_PAGER_H__ -#define __EXTRACT_FRAME_PAGER_H__ - -#include -using namespace std; - -// This class extracts a POCSAG message from a FM demodulated sample stream -// TODO extend to also process FLEX frames -#define MAX_CODEWORDS (16) -class extract_frame_pager -{ -public: - struct FIFOStruct { - unsigned long codeword; - int numBits; - }; - -#define BIT_BUF_SIZE (64) - enum BitsState { BS_SEARCHING, BS_SYNC, BS_LOCKED }; - enum DetectionMode { DM_STATIC, DM_DYNAMIC, DM_DIFFERENTIAL }; - - extract_frame_pager(); - virtual ~extract_frame_pager(); - - - void resetVals(); - void setFrameExtractParams(long a_samplesPerSec, long a_maxBaud = 8000, long a_minBaud = 200, long maxRunOfSameValue = 32); - - int processDemodulatedSamples(float * sampleBuff, int noOfSamples); - int extractFrames(); - virtual int OnDataFrame(int len, int baud) = 0; - virtual int OnDataWord(uint32_t word, int pos) = 0; - - void init(); - void storeBit(); - short getBit(); - - int getNoOfBits(); - uint32_t getRate(); - -protected: - uint32_t m_averageSymbolLen_1024; - uint32_t m_lastStableSymbolLen_1024; - - uint32_t m_samplesPerSec; - uint32_t m_goodTransitions; - uint32_t m_badTransitions; - -private: - uint32_t m_sampleNo; - float m_sample; - float m_valMid; - float m_lastSample; - - BitsState m_state; - uint32_t m_lastTransPos_1024; - uint32_t m_lastSingleBitPos_1024; - - uint32_t m_nextBitPosInt; // Integer rounded up version to save on ops - uint32_t m_nextBitPos_1024; - uint32_t m_lastBitPos_1024; - - uint32_t m_shortestGoodTrans_1024; - uint32_t m_minSymSamples_1024; - uint32_t m_maxSymSamples_1024; - uint32_t m_maxRunOfSameValue; - - bitset<(size_t)BIT_BUF_SIZE> m_bits; - long m_bitsStart; - long m_bitsEnd; - DetectionMode m_detectionMode; - - FIFOStruct m_fifo; - bool m_gotSync; - int m_numCode; - bool m_inverted; -}; - -#endif/*__EXTRACT_FRAME_PAGER_H__*/ diff --git a/firmware/baseband/proc_pocsag.cpp b/firmware/baseband/proc_pocsag.cpp index 9baab52f..4f45fb2b 100644 --- a/firmware/baseband/proc_pocsag.cpp +++ b/firmware/baseband/proc_pocsag.cpp @@ -28,6 +28,9 @@ #include #include +#include // std::max +#include + void POCSAGProcessor::execute(const buffer_c8_t& buffer) { // This is called at 1500Hz @@ -74,10 +77,10 @@ int POCSAGProcessor::OnDataFrame(int len, int baud) void POCSAGProcessor::on_message(const Message* const message) { if (message->id == Message::ID::POCSAGConfigure) - configure(*reinterpret_cast(message)); + configure(); } -void POCSAGProcessor::configure(const POCSAGConfigureMessage& message) { +void POCSAGProcessor::configure() { constexpr size_t decim_0_input_fs = baseband_fs; constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0.decimation_factor; @@ -105,6 +108,430 @@ void POCSAGProcessor::configure(const POCSAGConfigureMessage& message) { configured = true; } + + +// ----------------------------- +// Frame extractraction methods +// ----------------------------- +#define BAUD_STABLE (104) +#define MAX_CONSEC_SAME (32) +#define MAX_WITHOUT_SINGLE (64) +#define MAX_BAD_TRANS (10) + +#define M_SYNC (0x7cd215d8) +#define M_NOTSYNC (0x832dea27) + +#define M_IDLE (0x7a89c197) + +// ==================================================================== +// +// ==================================================================== +inline int bitsDiff(unsigned long left, unsigned long right) +{ + unsigned long xord = left ^ right; + int count = 0; + for (int i = 0; i < 32; i++) + { + if ((xord & 0x01) != 0) ++count; + xord = xord >> 1; + } + return(count); + +} + + +// ==================================================================== +// +// ==================================================================== +void POCSAGProcessor::initFrameExtraction() +{ + m_averageSymbolLen_1024 = m_maxSymSamples_1024; + m_lastStableSymbolLen_1024 = m_minSymSamples_1024; + + m_badTransitions = 0; + m_bitsStart = 0; + m_bitsEnd = 0; + m_inverted = false; + + resetVals(); +} + +// ==================================================================== +// +// ==================================================================== +void POCSAGProcessor::resetVals() +{ + // Reset the parameters + // -------------------- + m_goodTransitions = 0; + m_badTransitions = 0; + m_averageSymbolLen_1024 = m_maxSymSamples_1024; + m_shortestGoodTrans_1024 = m_maxSymSamples_1024; + m_valMid = 0; + + // And reset the counts + // -------------------- + m_lastTransPos_1024 = 0; + m_lastBitPos_1024 = 0; + m_lastSample = 0; + m_sampleNo = 0; + m_nextBitPos_1024 = m_maxSymSamples_1024; + m_nextBitPosInt = (long)m_nextBitPos_1024; + + // Extraction + m_fifo.numBits = 0; + m_gotSync = false; + m_numCode = 0; +} + +// ==================================================================== +// +// ==================================================================== +void POCSAGProcessor::setFrameExtractParams(long a_samplesPerSec, long a_maxBaud, long a_minBaud, long maxRunOfSameValue) +{ + m_samplesPerSec = a_samplesPerSec; + m_minSymSamples_1024 = (uint32_t)(1024.0f * (float)a_samplesPerSec / (float)a_maxBaud); + m_maxSymSamples_1024 = (uint32_t)(1024.0f*(float)a_samplesPerSec / (float)a_minBaud); + m_maxRunOfSameValue = maxRunOfSameValue; + + m_shortestGoodTrans_1024 = m_maxSymSamples_1024; + m_averageSymbolLen_1024 = m_maxSymSamples_1024; + m_lastStableSymbolLen_1024 = m_minSymSamples_1024; + + m_nextBitPos_1024 = m_averageSymbolLen_1024 / 2; + m_nextBitPosInt = m_nextBitPos_1024 >> 10; + + initFrameExtraction(); +} + +// ==================================================================== +// +// ==================================================================== +int POCSAGProcessor::processDemodulatedSamples(float * sampleBuff, int noOfSamples) +{ + bool transition = false; + uint32_t samplePos_1024 = 0; + uint32_t len_1024 = 0; + + // Loop through the block of data + // ------------------------------ + for (int pos = 0; pos < noOfSamples; ++pos) + { + m_sample = sampleBuff[pos]; + m_valMid += (m_sample - m_valMid) / 1024.0f; + + ++m_sampleNo; + + // Detect Transition + // ----------------- + transition = ! ((m_lastSample < m_valMid) ^ (m_sample >= m_valMid)); // use XOR for speed + + // If this is a transition + // ----------------------- + if (transition) + { + // Calculate samples since last trans + // ---------------------------------- + int32_t fractional_1024 = (int32_t)(((m_sample - m_valMid)*1024) / (m_sample - m_lastSample)); + if (fractional_1024 < 0) { fractional_1024 = -fractional_1024; } + + samplePos_1024 = (m_sampleNo<<10)-fractional_1024; + len_1024 = samplePos_1024 - m_lastTransPos_1024; + m_lastTransPos_1024 = samplePos_1024; + + // If symbol is large enough to be valid + // ------------------------------------- + if (len_1024 > m_minSymSamples_1024) + { + // Check for shortest good transition + // ---------------------------------- + if ((len_1024 < m_shortestGoodTrans_1024) && + (m_goodTransitions < BAUD_STABLE)) // detect change of symbol size + { + int32_t fractionOfShortest_1024 = (len_1024<<10) / m_shortestGoodTrans_1024; + + // If currently at half the baud rate + // ---------------------------------- + if ((fractionOfShortest_1024 > 410) && (fractionOfShortest_1024 < 614)) // 0.4 and 0.6 + { + m_averageSymbolLen_1024 /= 2; + m_shortestGoodTrans_1024 = len_1024; + } + // If currently at the wrong baud rate + // ----------------------------------- + else if (fractionOfShortest_1024 < 768) // 0.75 + { + m_averageSymbolLen_1024 = len_1024; + m_shortestGoodTrans_1024 = len_1024; + m_goodTransitions = 0; + m_lastSingleBitPos_1024 = samplePos_1024 - len_1024; + } + } + + // Calc the number of bits since events + // ------------------------------------ + int32_t halfSymbol_1024 = m_averageSymbolLen_1024 / 2; + int bitsSinceLastTrans = max((uint32_t)1, (len_1024+halfSymbol_1024) / m_averageSymbolLen_1024 ); + int bitsSinceLastSingle = (((m_sampleNo<<10)-m_lastSingleBitPos_1024) + halfSymbol_1024) / m_averageSymbolLen_1024; + + // Check for single bit + // -------------------- + if (bitsSinceLastTrans == 1) + { + m_lastSingleBitPos_1024 = samplePos_1024; + } + + // If too long since last transition + // --------------------------------- + if (bitsSinceLastTrans > MAX_CONSEC_SAME) + { + resetVals(); + } + // If too long sice last single bit + // -------------------------------- + else if (bitsSinceLastSingle > MAX_WITHOUT_SINGLE) + { + resetVals(); + } + else + { + // If this is a good transition + // ---------------------------- + int32_t offsetFromExtectedTransition_1024 = len_1024 - (bitsSinceLastTrans*m_averageSymbolLen_1024); + if (offsetFromExtectedTransition_1024 < 0) { offsetFromExtectedTransition_1024 = -offsetFromExtectedTransition_1024; } + if (offsetFromExtectedTransition_1024 < ((int32_t)m_averageSymbolLen_1024 / 4)) // Has to be within 1/4 of symbol to be good + { + ++m_goodTransitions; + uint32_t bitsCount = min((uint32_t)BAUD_STABLE, m_goodTransitions); + + uint32_t propFromPrevious = m_averageSymbolLen_1024*bitsCount; + uint32_t propFromCurrent = (len_1024 / bitsSinceLastTrans); + m_averageSymbolLen_1024 = (propFromPrevious + propFromCurrent) / (bitsCount + 1); + m_badTransitions = 0; + //if ( len < m_shortestGoodTrans ){m_shortestGoodTrans = len;} + // Store the old symbol size + if (m_goodTransitions >= BAUD_STABLE) + { + m_lastStableSymbolLen_1024 = m_averageSymbolLen_1024; + } + } + } + + // Set the point of the last bit if not yet stable + // ----------------------------------------------- + if ((m_goodTransitions < BAUD_STABLE) || (m_badTransitions > 0)) + { + m_lastBitPos_1024 = samplePos_1024 - (m_averageSymbolLen_1024 / 2); + } + + // Calculate the exact positiom of the next bit + // -------------------------------------------- + int32_t thisPlusHalfsymbol_1024 = samplePos_1024 + (m_averageSymbolLen_1024/2); + int32_t lastPlusSymbol = m_lastBitPos_1024 + m_averageSymbolLen_1024; + m_nextBitPos_1024 = lastPlusSymbol + ((thisPlusHalfsymbol_1024 - lastPlusSymbol) / 16); + + // Check for bad pos error + // ----------------------- + if (m_nextBitPos_1024 < samplePos_1024) m_nextBitPos_1024 += m_averageSymbolLen_1024; + + // Calculate integer sample after next bit + // --------------------------------------- + m_nextBitPosInt = (m_nextBitPos_1024>>10) + 1; + + } // symbol is large enough to be valid + else + { + // Bad transition, so reset the counts + // ----------------------------------- + ++m_badTransitions; + if (m_badTransitions > MAX_BAD_TRANS) + { + resetVals(); + } + } + } // end of if transition + + // Reached the point of the next bit + // --------------------------------- + if (m_sampleNo >= m_nextBitPosInt) + { + // Everything is good so extract a bit + // ----------------------------------- + if (m_goodTransitions > 20) + { + // Store value at the center of bit + // -------------------------------- + storeBit(); + } + // Check for long 1 or zero + // ------------------------ + uint32_t bitsSinceLastTrans = ((m_sampleNo<<10) - m_lastTransPos_1024) / m_averageSymbolLen_1024; + if (bitsSinceLastTrans > m_maxRunOfSameValue) + { + resetVals(); + } + + // Store the point of the last bit + // ------------------------------- + m_lastBitPos_1024 = m_nextBitPos_1024; + + // Calculate the exact point of the next bit + // ----------------------------------------- + m_nextBitPos_1024 += m_averageSymbolLen_1024; + + // Look for the bit after the next bit pos + // --------------------------------------- + m_nextBitPosInt = (m_nextBitPos_1024>>10) + 1; + + } // Reached the point of the next bit + + m_lastSample = m_sample; + + } // Loop through the block of data + + return getNoOfBits(); +} + +// ==================================================================== +// +// ==================================================================== +void POCSAGProcessor::storeBit() +{ + if (++m_bitsStart >= BIT_BUF_SIZE) { m_bitsStart = 0; } + + // Calculate the bit value + float sample = (m_sample + m_lastSample) / 2; + //int32_t sample_1024 = m_sample_1024; + bool bit = sample > m_valMid; + + // If buffer not full + if (m_bitsStart != m_bitsEnd) + { + // Decide on output val + if (bit) + { + m_bits[m_bitsStart] = 0; + } + else + { + m_bits[m_bitsStart] = 1; + } + } + // Throw away bits if the buffer is full + else + { + if (--m_bitsStart <= -1) + { + m_bitsStart = BIT_BUF_SIZE - 1; + } + } +} + +// ==================================================================== +// +// ==================================================================== +int POCSAGProcessor::extractFrames() +{ + int msgCnt = 0; + // While there is unread data in the bits buffer + //---------------------------------------------- + while (getNoOfBits() > 0) + { + m_fifo.codeword = (m_fifo.codeword << 1) + getBit(); + m_fifo.numBits++; + + // If number of bits in fifo equals 32 + //------------------------------------ + if (m_fifo.numBits >= 32) + { + // Not got sync + // ------------ + if (!m_gotSync) + { + if (bitsDiff(m_fifo.codeword, M_SYNC) <= 2) + { + m_inverted = false; + m_gotSync = true; + m_numCode = -1; + m_fifo.numBits = 0; + } + else if (bitsDiff(m_fifo.codeword, M_NOTSYNC) <= 2) + { + m_inverted = true; + m_gotSync = true; + m_numCode = -1; + m_fifo.numBits = 0; + } + else + { + // Cause it to load one more bit + m_fifo.numBits = 31; + } + } // Not got sync + else + { + // Increment the word count + // ------------------------ + ++m_numCode; // It got set to -1 when a sync was found, now count the 16 words + uint32_t val = m_inverted ? ~m_fifo.codeword : m_fifo.codeword; + OnDataWord(val, m_numCode); + + // If at the end of a 16 word block + // -------------------------------- + if (m_numCode >= 15) + { + msgCnt += OnDataFrame(m_numCode+1, (m_samplesPerSec<<10) / m_lastStableSymbolLen_1024); + m_gotSync = false; + m_numCode = -1; + } + m_fifo.numBits = 0; + } + } // If number of bits in fifo equals 32 + } // While there is unread data in the bits buffer + return msgCnt; +} // extractFrames + +// ==================================================================== +// +// ==================================================================== +short POCSAGProcessor::getBit() +{ + if (m_bitsEnd != m_bitsStart) + { + if (++m_bitsEnd >= BIT_BUF_SIZE) + { + m_bitsEnd = 0; + } + return m_bits[m_bitsEnd]; + } + else + { + return -1; + } +} + +// ==================================================================== +// +// ==================================================================== +int POCSAGProcessor::getNoOfBits() +{ + int bits = m_bitsEnd - m_bitsStart; + if (bits < 0) { bits += BIT_BUF_SIZE; } + return bits; +} + +// ==================================================================== +// +// ==================================================================== +uint32_t POCSAGProcessor::getRate() +{ + return ((m_samplesPerSec<<10)+512) / m_lastStableSymbolLen_1024; +} + + +// ==================================================================== +// +// ==================================================================== int main() { EventDispatcher event_dispatcher { std::make_unique() }; event_dispatcher.run(); diff --git a/firmware/baseband/proc_pocsag.hpp b/firmware/baseband/proc_pocsag.hpp index f82a9387..f5f7ec14 100644 --- a/firmware/baseband/proc_pocsag.hpp +++ b/firmware/baseband/proc_pocsag.hpp @@ -33,7 +33,6 @@ #include "dsp_demodulate.hpp" #include "pocsag_packet.hpp" -#include "extract_frame_pager.hpp" #include "pocsag.hpp" #include "message.hpp" @@ -41,8 +40,11 @@ #include "portapack_shared_memory.hpp" #include +#include +using namespace std; - +// Class used to smooth demodulated waveform prior to decoding +// ----------------------------------------------------------- template class SmoothVals { @@ -121,14 +123,15 @@ public: // -------------------------------------------------- // Class to process base band data to pocsag frames // -------------------------------------------------- -class POCSAGProcessor : public BasebandProcessor, extract_frame_pager { +class POCSAGProcessor : public BasebandProcessor{ public: + void execute(const buffer_c8_t& buffer) override; void on_message(const Message* const message) override; - virtual int OnDataFrame(int len, int baud); - virtual int OnDataWord(uint32_t word, int pos); + int OnDataFrame(int len, int baud); + int OnDataWord(uint32_t word, int pos); private: static constexpr size_t baseband_fs = 3072000; @@ -157,8 +160,65 @@ private: bool configured = false; pocsag::POCSAGPacket packet { }; - - void configure(const POCSAGConfigureMessage& message); + + void configure(); + + // ---------------------------------------- + // Frame extractraction methods and members + // ---------------------------------------- +private: + void initFrameExtraction(); + struct FIFOStruct { + unsigned long codeword; + int numBits; + }; + + #define BIT_BUF_SIZE (64) + + void resetVals(); + void setFrameExtractParams(long a_samplesPerSec, long a_maxBaud = 8000, long a_minBaud = 200, long maxRunOfSameValue = 32); + + int processDemodulatedSamples(float * sampleBuff, int noOfSamples); + int extractFrames(); + + void storeBit(); + short getBit(); + + int getNoOfBits(); + uint32_t getRate(); + + uint32_t m_averageSymbolLen_1024{0}; + uint32_t m_lastStableSymbolLen_1024{0}; + + uint32_t m_samplesPerSec{0}; + uint32_t m_goodTransitions{0}; + uint32_t m_badTransitions{0}; + + uint32_t m_sampleNo{0}; + float m_sample{0}; + float m_valMid{0.0f}; + float m_lastSample{0.0f}; + + uint32_t m_lastTransPos_1024{0}; + uint32_t m_lastSingleBitPos_1024{0}; + + uint32_t m_nextBitPosInt{0}; // Integer rounded up version to save on ops + uint32_t m_nextBitPos_1024{0}; + uint32_t m_lastBitPos_1024{0}; + + uint32_t m_shortestGoodTrans_1024{0}; + uint32_t m_minSymSamples_1024{0}; + uint32_t m_maxSymSamples_1024{0}; + uint32_t m_maxRunOfSameValue{0}; + + bitset<(size_t)BIT_BUF_SIZE> m_bits{0}; + long m_bitsStart{0}; + long m_bitsEnd{0}; + + FIFOStruct m_fifo{0,0}; + bool m_gotSync{false}; + int m_numCode{0}; + bool m_inverted{false}; };