diff --git a/DStarDefines.h b/DStarDefines.h index 970fe5a..2983c9e 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -24,21 +24,23 @@ 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_FEC_SECTION_LENGTH_BYTES = 83U; -const unsigned int DSTAR_FEC_SECTION_LENGTH_BITS = 660U; -const unsigned int DSTAR_FEC_SECTION_LENGTH_SAMPLES = DSTAR_FEC_SECTION_LENGTH_BITS * DSTAR_RADIO_SYMBOL_LENGTH; +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_SAMPLES = DSTAR_DATA_LENGTH_BITS * DSTAR_RADIO_SYMBOL_LENGTH; +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 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 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 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_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16}; diff --git a/DStarRX.cpp b/DStarRX.cpp index cec0dc4..3d10ddc 100644 --- a/DStarRX.cpp +++ b/DStarRX.cpp @@ -22,19 +22,15 @@ #include "DStarRX.h" #include "Utils.h" -const unsigned int MAX_SYNC_BITS = 50U * DSTAR_DATA_LENGTH_BITS; - -const unsigned int SYNC_POS = 21U * DSTAR_DATA_LENGTH_BITS; -const unsigned int SYNC_SCAN_START = SYNC_POS - 2U; -const unsigned int SYNC_SCAN_END = SYNC_POS + 2U; +const unsigned int MAX_FRAMES = 75U; // Generated using [b, a] = butter(1, 0.001) in MATLAB static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2} const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage -const uint8_t MAX_FRAME_SYNC_SYMBOL_ERRS = 2U; -const uint8_t MAX_DATA_SYNC_SYMBOL_ERRS = 2U; -const uint8_t MAX_END_SYNC_SYMBOL_ERRS = 3U; +const uint8_t MAX_FRAME_SYNC_BIT_ERRS = 2U; +const uint8_t MAX_DATA_SYNC_BIT_ERRS = 2U; +const uint8_t MAX_END_SYNC_BIT_ERRS = 3U; const uint8_t BIT_MASK_TABLE0[] = {0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFEU}; const uint8_t BIT_MASK_TABLE1[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; @@ -239,13 +235,11 @@ m_bitPtr(0U), m_headerPtr(0U), m_dataPtr(0U), m_startPtr(NOENDPTR), -m_endPtr(NOENDPTR), -m_syncPtr(NOENDPTR), m_minSyncPtr(NOENDPTR), m_maxSyncPtr(NOENDPTR), m_maxFrameCorr(0), m_maxDataCorr(0), -m_lostCount(0U), +m_frameCount(0U), m_countdown(0U), m_mar(0U), m_pathMetric(), @@ -276,11 +270,9 @@ void CDStarRX::reset() m_maxFrameCorr = 0; m_maxDataCorr = 0; m_startPtr = NOENDPTR; - m_endPtr = NOENDPTR; - m_syncPtr = NOENDPTR; m_minSyncPtr = NOENDPTR; m_maxSyncPtr = NOENDPTR; - m_lostCount = 0U; + m_frameCount = 0U; m_countdown = 0U; m_rssiAccum = 0U; m_rssiCount = 0U; @@ -343,8 +335,8 @@ void CDStarRX::processNone(q15_t sample) m_countdown = 5U; - m_headerBuffer[0U] = sample; - m_headerPtr = 1U; + m_headerBuffer[m_headerPtr] = sample; + m_headerPtr++; m_rssiAccum = 0U; m_rssiCount = 0U; @@ -362,18 +354,7 @@ void CDStarRX::processNone(q15_t sample) 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 = 0U; - m_rxState = DSRXS_DATA; + m_rxState = DSRXS_DATA; } } @@ -389,31 +370,47 @@ void CDStarRX::processHeader(q15_t sample) // A full FEC header if (m_headerPtr == DSTAR_FEC_SECTION_LENGTH_SAMPLES) { - // Process the scrambling, interleaving and FEC, then return if the chcksum was correct uint8_t buffer[DSTAR_FEC_SECTION_LENGTH_BYTES]; - samplesToBits(m_headerBuffer, m_startPtr, DSTAR_FEC_SECTION_LENGTH_SYMBOLS, buffer, DSTAR_FEC_SECTION_LENGTH_SAMPLES); + samplesToBits(m_headerBuffer, 0U, 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) { - io.setDecode(true); - io.setADCDetection(true); - - writeRSSIHeader(header); - - m_rxState = DSRXS_DATA; - m_dataBits = SYNC_POS - DSTAR_DATA_LENGTH_BITS + 1U; - } else { + if (!ok) { // The checksum failed, return to looking for syncs m_rxState = DSRXS_NONE; + m_maxFrameCorr = 0; + m_maxDataCorr = 0; } } + + // Reday to start the first data section + if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH)) { + m_frameCount = 0U; + + m_startPtr = m_dataPtr; + + m_maxSyncPtr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_DATA_SYNC_LENGTH_SAMPLES + 2U; + if (m_maxSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_maxSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES; + + m_minSyncPtr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_DATA_SYNC_LENGTH_SAMPLES - 2U; + if (m_minSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_minSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES; + } + + // Reday to start the first data section + if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH + DSTAR_RADIO_SYMBOL_LENGTH)) { + m_rxState = DSRXS_DATA; + m_maxFrameCorr = 0; + m_maxDataCorr = 0; + } } void CDStarRX::processData() { // Fuzzy matching of the end frame sequences - if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_END_SYNC_MASK) ^ DSTAR_END_SYNC_DATA) <= MAX_END_SYNC_SYMBOL_ERRS) { + if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_END_SYNC_MASK) ^ DSTAR_END_SYNC_DATA) <= MAX_END_SYNC_BIT_ERRS) { DEBUG1("DStarRX: Found end sync in Data"); io.setDecode(false); @@ -421,16 +418,26 @@ void CDStarRX::processData() serial.writeDStarEOT(); + m_maxFrameCorr = 0; + m_maxDataCorr = 0; + m_rxState = DSRXS_NONE; return; } // Fuzzy matching of the data sync bit sequence - - // Check to see if the sync is arriving late + if ((m_frameCount % 21U) == 0U) { + 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(); + } + } // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE - if (m_dataBits >= MAX_SYNC_BITS) { + if (m_frameCount >= MAX_FRAMES) { DEBUG1("DStarRX: data sync timed out, lost lock"); io.setDecode(false); @@ -438,15 +445,19 @@ void CDStarRX::processData() 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 - if (m_dataPtr == m_endPtr) { + 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); - if (syncSeen) { + + 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]; @@ -454,6 +465,11 @@ void CDStarRX::processData() } else { serial.writeDStarData(buffer, DSTAR_DATA_LENGTH_BYTES); } + + m_frameCount++; + + m_maxFrameCorr = 0; + m_maxDataCorr = 0; } } @@ -501,8 +517,8 @@ void CDStarRX::writeRSSIData(unsigned char* data) bool CDStarRX::correlateFrameSync() { - if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_FRAME_SYNC_MASK) ^ DSTAR_FRAME_SYNC_DATA) <= MAX_FRAME_SYNC_SYMBOLS_ERRS) { - uint16_t ptr = m_dataPtr + DSTAR_FRAME_LENGTH_SAMPLES - DSTAR_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH; + if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_FRAME_SYNC_MASK) ^ DSTAR_FRAME_SYNC_DATA) <= MAX_FRAME_SYNC_BIT_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; @@ -522,21 +538,8 @@ bool CDStarRX::correlateFrameSync() } if (corr > m_maxFrameCorr) { - uint16_t startPtr = m_dataPtr + DSTAR_FRAME_LENGTH_SAMPLES - DSTAR_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH; - if (startPtr >= DSTAR_FRAME_LENGTH_SAMPLES) - startPtr -= DSTAR_FRAME_LENGTH_SAMPLES; - m_maxFrameCorr = corr; - m_lostCount = MAX_SYNC_FRAMES; - m_syncPtr = m_dataPtr; m_headerPtr = 0U; - - m_startPtr = startPtr; - - m_endPtr = m_dataPtr + DSTAR_FRAME_LENGTH_SAMPLES - DSTAR_SYNC_LENGTH_SAMPLES - 1U; - if (m_endPtr >= DSTAR_FRAME_LENGTH_SAMPLES) - m_endPtr -= DSTAR_FRAME_LENGTH_SAMPLES; - return true; } } @@ -546,8 +549,8 @@ bool CDStarRX::correlateFrameSync() bool CDStarRX::correlateDataSync() { - if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_DATA_SYNC_MASK) ^ DSTAR_DATA_SYNC_DATA) <= MAX_DATA_SYNC_SYMBOLS_ERRS) { - uint16_t ptr = m_dataPtr + DSTAR_FRAME_LENGTH_SAMPLES - DSTAR_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH; + if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_DATA_SYNC_MASK) ^ DSTAR_DATA_SYNC_DATA) <= MAX_DATA_SYNC_BIT_ERRS) { + 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; @@ -567,19 +570,20 @@ bool CDStarRX::correlateDataSync() } if (corr > m_maxDataCorr) { - uint16_t startPtr = m_dataPtr + DSTAR_FRAME_LENGTH_SAMPLES - DSTAR_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH; - if (startPtr >= DSTAR_DATA_LENGTH_SAMPLES) - startPtr -= DSTAR_DATA_LENGTH_SAMPLES; - m_maxDataCorr = corr; - m_lostCount = MAX_SYNC_FRAMES; - m_syncPtr = m_dataPtr; + m_frameCount = 0U; - m_startPtr = startPtr; + m_startPtr = m_dataPtr + DSTAR_RADIO_SYMBOL_LENGTH; + if (m_startPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_startPtr -= DSTAR_DATA_LENGTH_SAMPLES; - m_endPtr = m_dataPtr + 2U; - if (m_endPtr >= DSTAR_DATA_LENGTH_SAMPLES) - m_endPtr -= DSTAR_DATA_LENGTH_SAMPLES; + m_maxSyncPtr = m_startPtr + DSTAR_DATA_LENGTH_SAMPLES + 2U; + if (m_maxSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_maxSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES; + + m_minSyncPtr = m_startPtr + DSTAR_DATA_LENGTH_SAMPLES - 2U; + if (m_minSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES) + m_minSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES; return true; } @@ -588,7 +592,7 @@ bool CDStarRX::correlateDataSync() return false; } -void CDStarRX::samplesToBits(const uint8_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit) +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]; diff --git a/DStarRX.h b/DStarRX.h index 5c76890..4630e94 100644 --- a/DStarRX.h +++ b/DStarRX.h @@ -39,19 +39,17 @@ public: private: DSRX_STATE m_rxState; uint32_t m_bitBuffer[DSTAR_RADIO_SYMBOL_LENGTH]; - q15_t m_headerBuffer[DSTAR_FEC_SECTION_LENGTH_SAMPLES]; + q15_t m_headerBuffer[DSTAR_FEC_SECTION_LENGTH_SAMPLES + 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_endPtr; uint16_t m_minSyncPtr; uint16_t m_maxSyncPtr; - uint16_t m_syncPtr; q31_t m_maxFrameCorr; q31_t m_maxDataCorr; - uint16_t m_lostCount; + uint16_t m_frameCount; uint8_t m_countdown; unsigned int m_mar; int m_pathMetric[4U]; @@ -70,7 +68,7 @@ private: void processData(); bool correlateFrameSync(); bool correlateDataSync(); - void samplesToBits(const uint8_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit); + 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 031d75d..e2b3eb1 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -198,7 +198,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; @@ -252,8 +252,8 @@ void CDStarTX::process() m_buffer.get(); 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; @@ -262,11 +262,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; @@ -412,7 +412,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; @@ -427,7 +427,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)