diff --git a/CalDStarRX.cpp b/CalDStarRX.cpp index 895dbf6..1648d08 100644 --- a/CalDStarRX.cpp +++ b/CalDStarRX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2016,2020 by Jonathan Naylor G4KLX * * 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 @@ -27,7 +27,7 @@ const unsigned int BUFFER_LENGTH = 200U; const uint32_t PLLMAX = 0x10000U; -const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH; +const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_SYMBOL_LENGTH; const uint32_t INC = PLLINC / 32U; // D-Star bit order version of 0x55 0x2D 0x16 diff --git a/CalDStarRX.h b/CalDStarRX.h index ddaebee..9c10f6e 100644 --- a/CalDStarRX.h +++ b/CalDStarRX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX * * 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 diff --git a/Config.h b/Config.h index 2664fda..49172af 100644 --- a/Config.h +++ b/Config.h @@ -22,34 +22,32 @@ // Allow for the selection of which modes to compile into the firmware. This is particularly useful for processors // which have limited code space and processing power like the STM32F103, which is found on older/cheaper boards. -// Enable D-Star support, the D-Star correlator improves the sensitivity of D-Star enormously but uses quite a lot -// of processing power. +// Enable D-Star support. #define MODE_DSTAR -#define USE_DSTAR_CORRELATOR -// Enable DMR support +// Enable DMR support. #define MODE_DMR -// Enable System Fusion support +// Enable System Fusion support. #define MODE_YSF // Enable P25 phase 1 support. #define MODE_P25 -// Enable NXDN support, the boxcar filter sometimes improves the performance of P25 receive on some systems +// Enable NXDN support, the boxcar filter sometimes improves the performance of NXDN receive on some systems. #define MODE_NXDN #define USE_NXDN_BOXCAR -// Enable M17 support +// Enable M17 support. #define MODE_M17 -// Enable POCSAG support +// Enable POCSAG support. #define MODE_POCSAG -// Enable FM support +// Enable FM support. #define MODE_FM -// Enable AX.25 support, this is only enabled if MODE_FM is also defined. +// Enable AX.25 support, this is only enabled if FM is also enabled. #define MODE_AX25 // Allow for the use of high quality external clock oscillators diff --git a/DStarDefines.h b/DStarDefines.h index 6255028..09f2632 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2015,2017,2020 by Jonathan Naylor G4KLX * * 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 @@ -19,30 +19,50 @@ #if !defined(DSTARDEFINES_H) #define DSTARDEFINES_H -const unsigned int DSTAR_RADIO_BIT_LENGTH = 5U; // At 24 kHz sample rate +const unsigned int DSTAR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate -const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U; -const unsigned int DSTAR_HEADER_LENGTH_BITS = DSTAR_HEADER_LENGTH_BYTES * 8U; +const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U; -const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U; -const unsigned int DSTAR_FEC_SECTION_LENGTH_BITS = 660U; +const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U; +const unsigned int DSTAR_FEC_SECTION_LENGTH_SYMBOLS = 660U; +const unsigned int DSTAR_FEC_SECTION_LENGTH_SAMPLES = DSTAR_FEC_SECTION_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH; -const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U; -const unsigned int DSTAR_DATA_LENGTH_BITS = DSTAR_DATA_LENGTH_BYTES * 8U; +const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U; +const unsigned int DSTAR_DATA_LENGTH_SYMBOLS = DSTAR_DATA_LENGTH_BYTES * 8U; +const unsigned int DSTAR_DATA_LENGTH_SAMPLES = DSTAR_DATA_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH; -const uint8_t DSTAR_EOT_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const unsigned int DSTAR_EOT_LENGTH_BYTES = 6U; -const unsigned int DSTAR_EOT_LENGTH_BITS = DSTAR_EOT_LENGTH_BYTES * 8U; +const unsigned int DSTAR_END_SYNC_LENGTH_BYTES = 6U; +const unsigned int DSTAR_END_SYNC_LENGTH_BITS = DSTAR_END_SYNC_LENGTH_BYTES * 8U; -const uint8_t DSTAR_DATA_SYNC_LENGTH_BYTES = 3U; -const uint8_t DSTAR_DATA_SYNC_LENGTH_BITS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U; +const unsigned int DSTAR_FRAME_SYNC_LENGTH_BYTES = 3U; +const unsigned int DSTAR_FRAME_SYNC_LENGTH_SYMBOLS = DSTAR_FRAME_SYNC_LENGTH_BYTES * 8U; +const unsigned int DSTAR_FRAME_SYNC_LENGTH_SAMPLES = DSTAR_FRAME_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH; -const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16}; +const unsigned int DSTAR_DATA_SYNC_LENGTH_BYTES = 3U; +const unsigned int DSTAR_DATA_SYNC_LENGTH_SYMBOLS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U; +const unsigned int DSTAR_DATA_SYNC_LENGTH_SAMPLES = DSTAR_DATA_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH; -const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U; -const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U; +const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16}; -const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U}; +// D-Star bit order version of 0x55 0x6E 0x0A +const uint32_t DSTAR_FRAME_SYNC_DATA = 0x00557650U; +const uint32_t DSTAR_FRAME_SYNC_MASK = 0x00FFFFFFU; +const bool DSTAR_FRAME_SYNC_SYMBOLS[] = {false, true, false, true, false, true, false, true, false, true, true, true, false, true, true, false, false, true, false, true, false, false, false, false}; + +// D-Star bit order version of 0x55 0x2D 0x16 +const uint32_t DSTAR_DATA_SYNC_DATA = 0x00AAB468U; +const uint32_t DSTAR_DATA_SYNC_MASK = 0x00FFFFFFU; +const bool DSTAR_DATA_SYNC_SYMBOLS[] = {true, false, true, false, true, false, true, false, true, false, true, true, false, true, false, false, false, true, true, false, true, false, false, false}; + +// D-Star bit order version of 0x55 0x55 0xC8 0x7A +const uint32_t DSTAR_END_SYNC_DATA = 0xAAAA135EU; +const uint32_t DSTAR_END_SYNC_MASK = 0xFFFFFFFFU; +const uint8_t DSTAR_END_SYNC_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U; +const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U; + +const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U}; #endif diff --git a/DStarRX.cpp b/DStarRX.cpp index a4a3e1d..737b8c7 100644 --- a/DStarRX.cpp +++ b/DStarRX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2017 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify @@ -25,18 +25,12 @@ #include "DStarRX.h" #include "Utils.h" -const unsigned int BUFFER_LENGTH = 200U; - -const uint32_t PLLMAX = 0x10000U; -const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH; -const uint32_t INC = PLLINC / 32U; - -const unsigned int MAX_SYNC_BITS = 100U * DSTAR_DATA_LENGTH_BITS; +const unsigned int MAX_FRAMES = 150U; // D-Star bit order version of 0x55 0x55 0x6E 0x0A const uint32_t FRAME_SYNC_DATA = 0x00557650U; const uint32_t FRAME_SYNC_MASK = 0x00FFFFFFU; -const uint8_t FRAME_SYNC_ERRS = 2U; +const uint8_t FRAME_SYNC_ERRS = 1U; // D-Star bit order version of 0x55 0x2D 0x16 const uint32_t DATA_SYNC_DATA = 0x00AAB468U; @@ -240,14 +234,24 @@ const uint16_t CCITT_TABLE[] = { 0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U, 0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U}; +const uint16_t NOENDPTR = 9999U; + CDStarRX::CDStarRX() : -m_pll(0U), -m_prev(false), m_rxState(DSRXS_NONE), -m_patternBuffer(0x00U), -m_rxBuffer(), -m_rxBufferBits(0U), -m_dataBits(0U), +m_bitBuffer(), +m_headerBuffer(), +m_dataBuffer(), +m_bitPtr(0U), +m_headerPtr(0U), +m_dataPtr(0U), +m_startPtr(NOENDPTR), +m_syncPtr(NOENDPTR), +m_minSyncPtr(NOENDPTR), +m_maxSyncPtr(NOENDPTR), +m_maxFrameCorr(0), +m_maxDataCorr(0), +m_frameCount(0U), +m_countdown(0U), m_mar(0U), m_pathMetric(), m_pathMemory0(), @@ -262,14 +266,20 @@ m_rssiCount(0U) void CDStarRX::reset() { - m_pll = 0U; - m_prev = false; - m_rxState = DSRXS_NONE; - m_patternBuffer = 0x00U; - m_rxBufferBits = 0U; - m_dataBits = 0U; - m_rssiAccum = 0U; - m_rssiCount = 0U; + m_rxState = DSRXS_NONE; + m_headerPtr = 0U; + m_dataPtr = 0U; + m_bitPtr = 0U; + m_maxFrameCorr = 0; + m_maxDataCorr = 0; + m_startPtr = NOENDPTR; + m_syncPtr = NOENDPTR; + m_minSyncPtr = NOENDPTR; + m_maxSyncPtr = NOENDPTR; + m_frameCount = 0U; + m_countdown = 0U; + m_rssiAccum = 0U; + m_rssiCount = 0U; } void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length) @@ -278,125 +288,117 @@ void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t lengt m_rssiAccum += rssi[i]; m_rssiCount++; - bool bit = samples[i] < 0; + q15_t sample = samples[i]; - if (bit != m_prev) { - if (m_pll < (PLLMAX / 2U)) - m_pll += INC; - else - m_pll -= INC; + m_bitBuffer[m_bitPtr] <<= 1; + if (sample < 0) + m_bitBuffer[m_bitPtr] |= 0x01U; + + m_dataBuffer[m_dataPtr] = sample; + + switch (m_rxState) { + case DSRXS_HEADER: + processHeader(sample); + break; + case DSRXS_DATA: + processData(); + break; + default: + processNone(sample); + break; } - m_prev = bit; + m_dataPtr++; + if (m_dataPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_dataPtr = 0U; - m_pll += PLLINC; - - if (m_pll >= PLLMAX) { - m_pll -= PLLMAX; - - switch (m_rxState) { - case DSRXS_NONE: - processNone(bit); - break; - case DSRXS_HEADER: - processHeader(bit); - break; - case DSRXS_DATA: - processData(bit); - break; - default: - break; - } - } + m_bitPtr++; + if (m_bitPtr >= DSTAR_RADIO_SYMBOL_LENGTH) + m_bitPtr = 0U; } } -void CDStarRX::processNone(bool bit) +void CDStarRX::processNone(q15_t sample) { - m_patternBuffer <<= 1; - if (bit) - m_patternBuffer |= 0x01U; - // Fuzzy matching of the frame sync sequence - if (countBits32((m_patternBuffer & FRAME_SYNC_MASK) ^ FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) { - DEBUG1("DStarRX: found frame sync in None"); + bool ret = correlateFrameSync(); + if (ret) { + m_countdown = 5U; - ::memset(m_rxBuffer, 0x00U, DSTAR_FEC_SECTION_LENGTH_BYTES); - m_rxBufferBits = 0U; + m_headerBuffer[m_headerPtr] = sample; + m_headerPtr++; m_rssiAccum = 0U; m_rssiCount = 0U; m_rxState = DSRXS_HEADER; + return; } - // Exact matching of the data sync bit sequence - if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) == 0U) { + // Fuzzy matching of the data sync bit sequence + ret = correlateDataSync(); + if (ret) { DEBUG1("DStarRX: found data sync in None"); io.setDecode(true); io.setADCDetection(true); - // Suppress RSSI on the dummy sync message - m_rssiAccum = 0U; - m_rssiCount = 0U; - - ::memcpy(m_rxBuffer, DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES); - writeRSSIData(m_rxBuffer); - - ::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U); - m_rxBufferBits = 0U; - - m_dataBits = MAX_SYNC_BITS; - m_rxState = DSRXS_DATA; - return; + m_rxState = DSRXS_DATA; } } -void CDStarRX::processHeader(bool bit) +void CDStarRX::processHeader(q15_t sample) { - m_patternBuffer <<= 1; - if (bit) - m_patternBuffer |= 0x01U; + if (m_countdown > 0U) { + correlateFrameSync(); + m_countdown--; + } - WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit); - m_rxBufferBits++; + m_headerBuffer[m_headerPtr] = sample; + m_headerPtr++; // A full FEC header - if (m_rxBufferBits == DSTAR_FEC_SECTION_LENGTH_BITS) { - // Process the scrambling, interleaving and FEC, then return if the chcksum was correct - unsigned char header[DSTAR_HEADER_LENGTH_BYTES]; - bool ok = rxHeader(m_rxBuffer, header); - if (ok) { + if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH)) { + uint8_t buffer[DSTAR_FEC_SECTION_LENGTH_BYTES]; + samplesToBits(m_headerBuffer, DSTAR_RADIO_SYMBOL_LENGTH, DSTAR_FEC_SECTION_LENGTH_SYMBOLS, buffer, DSTAR_FEC_SECTION_LENGTH_SAMPLES); + + // Process the scrambling, interleaving and FEC, then return true if the chcksum was correct + uint8_t header[DSTAR_HEADER_LENGTH_BYTES]; + bool ok = rxHeader(buffer, header); + if (!ok) { + // The checksum failed, return to looking for syncs + m_rxState = DSRXS_NONE; + m_maxFrameCorr = 0; + m_maxDataCorr = 0; + } else { io.setDecode(true); io.setADCDetection(true); writeRSSIHeader(header); - - ::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U); - m_rxBufferBits = 0U; - - m_rxState = DSRXS_DATA; - m_dataBits = MAX_SYNC_BITS; - } else { - // The checksum failed, return to looking for syncs - m_rxState = DSRXS_NONE; } } + + // Ready to start the first data section + if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH)) { + m_frameCount = 0U; + m_dataPtr = 0U; + + m_startPtr = 476U; + m_syncPtr = 471U; + m_maxSyncPtr = 472U; + m_minSyncPtr = 470U; + + DEBUG5("DStarRX: calc start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr); + + m_rxState = DSRXS_DATA; + } } -void CDStarRX::processData(bool bit) +void CDStarRX::processData() { - m_patternBuffer <<= 1; - if (bit) - m_patternBuffer |= 0x01U; - - WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit); - m_rxBufferBits++; - // Fuzzy matching of the end frame sequences - if (countBits32((m_patternBuffer & END_SYNC_MASK) ^ END_SYNC_DATA) <= END_SYNC_ERRS) { + if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_END_SYNC_MASK) ^ DSTAR_END_SYNC_DATA) <= END_SYNC_ERRS) { DEBUG1("DStarRX: Found end sync in Data"); io.setDecode(false); @@ -404,35 +406,24 @@ void CDStarRX::processData(bool bit) serial.writeDStarEOT(); + m_maxFrameCorr = 0; + m_maxDataCorr = 0; + m_rxState = DSRXS_NONE; return; } // Fuzzy matching of the data sync bit sequence - bool syncSeen = false; - if (m_rxBufferBits >= (DSTAR_DATA_LENGTH_BITS - 3U)) { - if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) <= DATA_SYNC_ERRS) { - m_rxBufferBits = DSTAR_DATA_LENGTH_BITS; - m_dataBits = MAX_SYNC_BITS; - syncSeen = true; - } + if (m_minSyncPtr < m_maxSyncPtr) { + if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr) + correlateDataSync(); + } else { + if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr) + correlateDataSync(); } - // Check to see if the sync is arriving late - if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS && !syncSeen) { - for (uint8_t i = 1U; i <= 3U; i++) { - uint32_t syncMask = DATA_SYNC_MASK >> i; - uint32_t syncData = DATA_SYNC_DATA >> i; - if (countBits32((m_patternBuffer & syncMask) ^ syncData) <= DATA_SYNC_ERRS) { - m_rxBufferBits -= i; - break; - } - } - } - - m_dataBits--; - - if (m_dataBits == 0U) { + // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE + if (m_frameCount >= MAX_FRAMES) { DEBUG1("DStarRX: data sync timed out, lost lock"); io.setDecode(false); @@ -440,24 +431,35 @@ void CDStarRX::processData(bool bit) serial.writeDStarLost(); + m_maxFrameCorr = 0; + m_maxDataCorr = 0; + m_rxState = DSRXS_NONE; return; } - // Send a data frame to the host if the required number of bits have been received, or if a data sync has been seen - if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS) { - if (syncSeen) { - m_rxBuffer[9U] = DSTAR_DATA_SYNC_BYTES[9U]; - m_rxBuffer[10U] = DSTAR_DATA_SYNC_BYTES[10U]; - m_rxBuffer[11U] = DSTAR_DATA_SYNC_BYTES[11U]; - writeRSSIData(m_rxBuffer); - } else { - serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES); - } + // Send a data frame to the host if the required number of bits have been received + if (m_dataPtr == m_maxSyncPtr) { + uint8_t buffer[DSTAR_DATA_LENGTH_BYTES + 2U]; + samplesToBits(m_dataBuffer, m_startPtr, DSTAR_DATA_LENGTH_SYMBOLS, buffer, DSTAR_DATA_LENGTH_SAMPLES); - // Start the next frame - ::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U); - m_rxBufferBits = 0U; + if ((m_frameCount % 21U) == 0U) { + if (m_frameCount == 0U) { + buffer[9U] = DSTAR_DATA_SYNC_BYTES[9U]; + buffer[10U] = DSTAR_DATA_SYNC_BYTES[10U]; + buffer[11U] = DSTAR_DATA_SYNC_BYTES[11U]; + DEBUG5("DStarRX: found start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr); + } + + writeRSSIData(buffer); + } else { + serial.writeDStarData(buffer, DSTAR_DATA_LENGTH_BYTES); + } + + m_frameCount++; + + m_maxFrameCorr = 0; + m_maxDataCorr = 0; } } @@ -503,6 +505,105 @@ void CDStarRX::writeRSSIData(unsigned char* data) m_rssiCount = 0U; } +bool CDStarRX::correlateFrameSync() +{ + if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_FRAME_SYNC_MASK) ^ DSTAR_FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) { + uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_FRAME_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH; + if (ptr >= DSTAR_DATA_LENGTH_SAMPLES) + ptr -= DSTAR_DATA_LENGTH_SAMPLES; + + q31_t corr = 0; + + for (uint8_t i = 0U; i < DSTAR_FRAME_SYNC_LENGTH_SYMBOLS; i++) { + q15_t val = m_dataBuffer[ptr]; + + if (DSTAR_FRAME_SYNC_SYMBOLS[i]) + corr -= val; + else + corr += val; + + ptr += DSTAR_RADIO_SYMBOL_LENGTH; + if (ptr >= DSTAR_DATA_LENGTH_SAMPLES) + ptr -= DSTAR_DATA_LENGTH_SAMPLES; + } + + if (corr > m_maxFrameCorr) { + m_maxFrameCorr = corr; + m_headerPtr = 0U; + return true; + } + } + + return false; +} + +bool CDStarRX::correlateDataSync() +{ + uint8_t maxErrs = 0U; + if (m_rxState == DSRXS_DATA) + maxErrs = DATA_SYNC_ERRS; + + if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_DATA_SYNC_MASK) ^ DSTAR_DATA_SYNC_DATA) <= maxErrs) { + uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_DATA_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH; + if (ptr >= DSTAR_DATA_LENGTH_SAMPLES) + ptr -= DSTAR_DATA_LENGTH_SAMPLES; + + q31_t corr = 0; + + for (uint8_t i = 0U; i < DSTAR_DATA_SYNC_LENGTH_SYMBOLS; i++) { + q15_t val = m_dataBuffer[ptr]; + + if (DSTAR_DATA_SYNC_SYMBOLS[i]) + corr -= val; + else + corr += val; + + ptr += DSTAR_RADIO_SYMBOL_LENGTH; + if (ptr >= DSTAR_DATA_LENGTH_SAMPLES) + ptr -= DSTAR_DATA_LENGTH_SAMPLES; + } + + if (corr > m_maxDataCorr) { + m_maxDataCorr = corr; + m_frameCount = 0U; + + m_syncPtr = m_dataPtr; + + m_startPtr = m_dataPtr + DSTAR_RADIO_SYMBOL_LENGTH; + if (m_startPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_startPtr -= DSTAR_DATA_LENGTH_SAMPLES; + + m_maxSyncPtr = m_syncPtr + 1U; + if (m_maxSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_maxSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES; + + m_minSyncPtr = m_syncPtr + DSTAR_DATA_LENGTH_SAMPLES - 1U; + if (m_minSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_minSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES; + + return true; + } + } + + return false; +} + +void CDStarRX::samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit) +{ + for (uint16_t i = 0U; i < count; i++) { + q15_t sample = inBuffer[start]; + + if (sample < 0) + WRITE_BIT2(outBuffer, i, true); + else + WRITE_BIT2(outBuffer, i, false); + + start += DSTAR_RADIO_SYMBOL_LENGTH; + if (start >= limit) + start -= limit; + } +} + bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out) { int i; diff --git a/DStarRX.h b/DStarRX.h index 3088b6d..d67541a 100644 --- a/DStarRX.h +++ b/DStarRX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX * * 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 @@ -40,13 +40,21 @@ public: void reset(); private: - uint32_t m_pll; - bool m_prev; DSRX_STATE m_rxState; - uint32_t m_patternBuffer; - uint8_t m_rxBuffer[100U]; - unsigned int m_rxBufferBits; - unsigned int m_dataBits; + uint32_t m_bitBuffer[DSTAR_RADIO_SYMBOL_LENGTH]; + q15_t m_headerBuffer[DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH]; + q15_t m_dataBuffer[DSTAR_DATA_LENGTH_SAMPLES]; + uint16_t m_bitPtr; + uint16_t m_headerPtr; + uint16_t m_dataPtr; + uint16_t m_startPtr; + uint16_t m_syncPtr; + uint16_t m_minSyncPtr; + uint16_t m_maxSyncPtr; + q31_t m_maxFrameCorr; + q31_t m_maxDataCorr; + uint16_t m_frameCount; + uint8_t m_countdown; unsigned int m_mar; int m_pathMetric[4U]; unsigned int m_pathMemory0[42U]; @@ -57,9 +65,12 @@ private: uint32_t m_rssiAccum; uint16_t m_rssiCount; - void processNone(bool bit); - void processHeader(bool bit); - void processData(bool bit); + void processNone(q15_t sample); + void processHeader(q15_t sample); + void processData(); + bool correlateFrameSync(); + bool correlateDataSync(); + void samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit); void writeRSSIHeader(unsigned char* header); void writeRSSIData(unsigned char* data); bool rxHeader(uint8_t* in, uint8_t* out); diff --git a/DStarTX.cpp b/DStarTX.cpp index cbd4c52..3ffc183 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -201,7 +201,7 @@ m_txDelay(60U) // 100ms { ::memset(m_modState, 0x00U, 20U * sizeof(q15_t)); - m_modFilter.L = DSTAR_RADIO_BIT_LENGTH; + m_modFilter.L = DSTAR_RADIO_SYMBOL_LENGTH; m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN; m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER; m_modFilter.pState = m_modState; @@ -219,8 +219,8 @@ void CDStarTX::process() for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = BIT_SYNC; } else { - uint8_t dummy; // Pop the type byte off + uint8_t dummy; m_buffer.get(dummy); uint8_t header[DSTAR_HEADER_LENGTH_BYTES]; @@ -258,8 +258,8 @@ void CDStarTX::process() m_buffer.get(dummy); for (uint8_t j = 0U; j < 3U; j++) { - for (uint8_t i = 0U; i < DSTAR_EOT_LENGTH_BYTES; i++) - m_poBuffer[m_poLen++] = DSTAR_EOT_BYTES[i]; + for (uint8_t i = 0U; i < DSTAR_END_SYNC_LENGTH_BYTES; i++) + m_poBuffer[m_poLen++] = DSTAR_END_SYNC_BYTES[i]; } m_poPtr = 0U; @@ -268,11 +268,11 @@ void CDStarTX::process() if (m_poLen > 0U) { uint16_t space = io.getSpace(); - while (space > (8U * DSTAR_RADIO_BIT_LENGTH)) { + while (space > (8U * DSTAR_RADIO_SYMBOL_LENGTH)) { uint8_t c = m_poBuffer[m_poPtr++]; writeByte(c); - space -= 8U * DSTAR_RADIO_BIT_LENGTH; + space -= 8U * DSTAR_RADIO_SYMBOL_LENGTH; if (m_poPtr >= m_poLen) { m_poPtr = 0U; @@ -418,7 +418,7 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const void CDStarTX::writeByte(uint8_t c) { q15_t inBuffer[8U]; - q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; + q15_t outBuffer[DSTAR_RADIO_SYMBOL_LENGTH * 8U]; uint8_t mask = 0x01U; @@ -433,7 +433,7 @@ void CDStarTX::writeByte(uint8_t c) ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U); - io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); + io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_SYMBOL_LENGTH * 8U); } void CDStarTX::setTXDelay(uint8_t delay)