diff --git a/DMRDefines.h b/DMRDefines.h index 2592500..23de540 100644 --- a/DMRDefines.h +++ b/DMRDefines.h @@ -76,8 +76,10 @@ const uint8_t DT_VOICE_LC_HEADER = 1U; const uint8_t DT_TERMINATOR_WITH_LC = 2U; const uint8_t DT_CSBK = 3U; const uint8_t DT_DATA_HEADER = 6U; +const uint8_t DT_RATE_12_DATA = 7U; +const uint8_t DT_RATE_34_DATA = 8U; const uint8_t DT_IDLE = 9U; -// All others are for data transfer +const uint8_t DT_RATE_1_DATA = 10U; #endif diff --git a/DMRSlotRX.cpp b/DMRSlotRX.cpp index bc7c40f..9eef38a 100644 --- a/DMRSlotRX.cpp +++ b/DMRSlotRX.cpp @@ -35,6 +35,24 @@ const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02 #define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +const int8_t EMB_SYMBOLS[16U][5U][DMR_EMB_LENGTH_SYMBOLS] = { + {{+1, +1, +1, -1, +3, -3, +1, -3}, {+1, +1, +3, -1, -1, +3, +3, -1}, {+1, +1, +3, -1, -1, +3, +3, -1}, {+1, +1, +3, +1, -3, -1, +3, +3}, {+1, +1, +1, +1, +1, +1, +1, +1}}, + {{+1, +3, +1, -3, -1, +3, +1, +3}, {+1, +3, +3, -3, +3, -3, +3, +1}, {+1, +3, +3, -3, +3, -3, +3, +1}, {+1, +3, +3, +3, +1, +1, +3, -3}, {+1, +3, +1, +3, -3, -1, +1, -1}}, + {{+1, -1, +1, -3, -3, +1, +3, +1}, {+1, -1, +3, -3, +1, -1, +1, +3}, {+1, -1, +3, -3, +1, -1, +1, +3}, {+1, -1, +3, +3, +3, +3, +1, -1}, {+1, -1, +1, +3, -1, -3, +3, -3}}, + {{+1, -3, +1, -1, +1, -1, +3, -1}, {+1, -3, +3, -1, -3, +1, +1, -3}, {+1, -3, +3, -1, -3, +1, +1, -3}, {+1, -3, +3, +1, -1, -3, +1, +1}, {+1, -3, +1, +1, +3, +3, +3, +3}}, + {{+3, +1, +1, -3, +3, -1, -3, +3}, {+3, +1, +3, -3, -1, +1, -1, +1}, {+3, +1, +3, -3, -1, +1, -1, +1}, {+3, +1, +3, +3, -3, -3, -1, -3}, {+3, +1, +1, +3, +1, +3, -3, -1}}, + {{+3, +3, +1, -1, -1, +1, -3, -3}, {+3, +3, +3, -1, +3, -1, -1, -1}, {+3, +3, +3, -1, +3, -1, -1, -1}, {+3, +3, +3, +1, +1, +3, -1, +3}, {+3, +3, +1, +1, -3, -3, -3, +1}}, + {{+3, -1, +1, -1, -3, +3, -1, -1}, {+3, -1, +3, -1, +1, -3, -3, -3}, {+3, -1, +3, -1, +1, -3, -3, -3}, {+3, -1, +3, +1, +3, +1, -3, +1}, {+3, -1, +1, +1, -1, -1, -1, +3}}, + {{+3, -3, +1, -3, +1, -3, -1, +1}, {+3, -3, +3, -3, -3, +3, -3, +3}, {+3, -3, +3, -3, -3, +3, -3, +3}, {+3, -3, +3, +3, -1, -1, -3, -1}, {+3, -3, +1, +3, +3, +1, -1, -3}}, + {{-1, +1, +1, -1, +1, -3, -3, +1}, {-1, +1, +3, -1, -3, +3, -1, +3}, {-1, +1, +3, -1, -3, +3, -1, +3}, {-1, +1, +3, +1, -1, -1, -1, -1}, {-1, +1, +1, +1, +3, +1, -3, -3}}, + {{-1, +3, +1, -3, -3, +3, -3, -1}, {-1, +3, +3, -3, +1, -3, -1, -3}, {-1, +3, +3, -3, +1, -3, -1, -3}, {-1, +3, +3, +3, +3, +1, -1, +1}, {-1, +3, +1, +3, -1, -1, -3, +3}}, + {{-1, -1, +1, -3, -1, +1, -1, -3}, {-1, -1, +3, -3, +3, -1, -3, -1}, {-1, -1, +3, -3, +3, -1, -3, -1}, {-1, -1, +3, +3, +1, +3, -3, +3}, {-1, -1, +1, +3, -3, -3, -1, +1}}, + {{-1, -3, +1, -1, +3, -1, -1, +3}, {-1, -3, +3, -1, -1, +1, -3, +1}, {-1, -3, +3, -1, -1, +1, -3, +1}, {-1, -3, +3, +1, -3, -3, -3, -3}, {-1, -3, +1, +1, +1, +3, -1, -1}}, + {{-3, +1, +1, -3, +1, -1, +1, -1}, {-3, +1, +3, -3, -3, +1, +3, -3}, {-3, +1, +3, -3, -3, +1, +3, -3}, {-3, +1, +3, +3, -1, -3, +3, +1}, {-3, +1, +1, +3, +3, +3, +1, +3}}, + {{-3, +3, +1, -1, -3, +1, +1, +1}, {-3, +3, +3, -1, +1, -1, +3, +3}, {-3, +3, +3, -1, +1, -1, +3, +3}, {-3, +3, +3, +1, +3, +3, +3, -1}, {-3, +3, +1, +1, -1, -3, +1, -3}}, + {{-3, -1, +1, -1, -1, +3, +3, +3}, {-3, -1, +3, -1, +3, -3, +1, +1}, {-3, -1, +3, -1, +3, -3, +1, +1}, {-3, -1, +3, +1, +1, +1, +1, -3}, {-3, -1, +1, +1, -3, -1, +3, -1}}, + {{-3, -3, +1, -3, +3, -3, +3, -3}, {-3, -3, +3, -3, -1, +3, +1, -1}, {-3, -3, +3, -3, -1, +3, +1, -1}, {-3, -3, +3, +3, -3, -1, +1, +3}, {-3, -3, +1, +3, +1, +1, +3, +1}}}; + const uint16_t NOENDPTR = 9999U; CDMRSlotRX::CDMRSlotRX(bool slot) : @@ -53,6 +71,7 @@ m_control(0x00U), m_syncCount(0U), m_colorCode(0U), m_delay(0U), +m_state(DMRRXS_NONE), m_n(0U) { } @@ -77,6 +96,7 @@ void CDMRSlotRX::reset() m_syncCount = 0U; m_threshold = 0; m_centre = 0; + m_state = DMRRXS_NONE; m_endPtr = NOENDPTR; } @@ -84,11 +104,11 @@ bool CDMRSlotRX::processSample(q15_t sample) { m_delayPtr++; if (m_delayPtr < m_delay) - return m_endPtr != NOENDPTR; + return m_state != DMRRXS_NONE; // Ensure that the buffer doesn't overflow if (m_dataPtr > m_endPtr || m_dataPtr >= 900U) - return m_endPtr != NOENDPTR; + return m_state != DMRRXS_NONE; m_buffer[m_dataPtr] = sample; @@ -96,15 +116,23 @@ bool CDMRSlotRX::processSample(q15_t sample) if (sample < 0) m_bitBuffer[m_bitPtr] |= 0x01U; - // The approximate position of the sync samples - if (m_endPtr != NOENDPTR) { - uint16_t min = m_syncPtr - 5U; - uint16_t max = m_syncPtr + 5U; + if (m_state == DMRRXS_VOICE) { + uint16_t min = m_syncPtr - 2U; + uint16_t max = m_syncPtr + 2U; + if (m_dataPtr >= min && m_dataPtr <= max) { + if (m_n >= 5U) + correlateSync(); + else + correlateEMB(); + } + } else if (m_state == DMRRXS_DATA) { + uint16_t min = m_syncPtr - 2U; + uint16_t max = m_syncPtr + 2U; if (m_dataPtr >= min && m_dataPtr <= max) - correlateSync(sample); + correlateSync(); } else { if (m_dataPtr >= 420U && m_dataPtr <= 500U) - correlateSync(sample); + correlateSync(); } if (m_dataPtr == m_endPtr) { @@ -129,27 +157,21 @@ bool CDMRSlotRX::processSample(q15_t sample) switch (dataType) { case DT_DATA_HEADER: - DEBUG3("DMRSlotRX: data header for slot/data type", m_slot ? 2U : 1U, dataType); - m_endPtr = NOENDPTR; + case DT_RATE_12_DATA: + case DT_RATE_34_DATA: + case DT_RATE_1_DATA: serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMRRXS_DATA; break; case DT_VOICE_LC_HEADER: - DEBUG3("DMRSlotRX: voice header for slot/data type", m_slot ? 2U : 1U, dataType); - serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); - break; case DT_VOICE_PI_HEADER: - DEBUG3("DMRSlotRX: pi header for slot/data type", m_slot ? 2U : 1U, dataType); - serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); - break; - case DT_TERMINATOR_WITH_LC: - DEBUG2("DMRSlotRX: terminator for slot", m_slot ? 2U : 1U); - m_endPtr = NOENDPTR; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMRRXS_VOICE; break; default: - DEBUG3("DMRSlotRX: data sync for slot/data type", m_slot ? 2U : 1U, dataType); - m_endPtr = NOENDPTR; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMRRXS_NONE; + m_endPtr = NOENDPTR; break; } } @@ -157,23 +179,26 @@ bool CDMRSlotRX::processSample(q15_t sample) // Voice sync DEBUG2("DMRSlotRX: voice sync for slot", m_slot ? 2U : 1U); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMRRXS_VOICE; m_syncCount = 0U; m_n = 0U; } else { m_syncCount++; if (m_syncCount >= MAX_SYNC_LOST_FRAMES) { - DEBUG2("DMRSlotRX: lost for slot", m_slot ? 2U : 1U); serial.writeDMRLost(m_slot); m_syncCount = 0U; m_threshold = 0; m_centre = 0; + m_state = DMRRXS_NONE; m_endPtr = NOENDPTR; return false; } // Voice data - frame[0U] |= ++m_n; - serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); + if (m_state == DMRRXS_VOICE) { + frame[0U] |= ++m_n; + serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } } } @@ -183,10 +208,10 @@ bool CDMRSlotRX::processSample(q15_t sample) if (m_bitPtr >= DMR_RADIO_SYMBOL_LENGTH) m_bitPtr = 0U; - return m_endPtr != NOENDPTR; + return m_state != DMRRXS_NONE; } -void CDMRSlotRX::correlateSync(q15_t sample) +void CDMRSlotRX::correlateSync() { uint8_t errs = countBits32((m_bitBuffer[m_bitPtr] & DMR_SYNC_SYMBOLS_MASK) ^ DMR_MS_DATA_SYNC_SYMBOLS); @@ -271,6 +296,34 @@ void CDMRSlotRX::correlateSync(q15_t sample) } } +void CDMRSlotRX::correlateEMB() +{ + uint8_t n = 0U; + q31_t corr = 0; + + // The beginning of the first section of the EMB is at the same place as the beginning of the sync + uint16_t ptr = m_dataPtr - DMR_SYNC_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH; + for (uint8_t i = 0U; i < (DMR_EMB_LENGTH_SYMBOLS / 2U); i++, n++) { + corr += EMB_SYMBOLS[m_colorCode][m_n][n] * m_buffer[ptr]; + ptr += DMR_RADIO_SYMBOL_LENGTH; + } + + ptr = m_dataPtr - (DMR_EMB_LENGTH_SAMPLES / 2U) + DMR_RADIO_SYMBOL_LENGTH; + for (uint8_t i = 0U; i < (DMR_EMB_LENGTH_SYMBOLS / 2U); i++, n++) { + corr += EMB_SYMBOLS[m_colorCode][m_n][n] * m_buffer[ptr]; + ptr += DMR_RADIO_SYMBOL_LENGTH; + } + + if (corr > m_maxCorr) { +#if defined(WANT_DEBUG) + DEBUG3("DMRSlotRX: emb found slot/rel pos", m_slot ? 2U : 1U, int16_t(m_dataPtr) - int16_t(m_syncPtr)); +#endif + m_maxCorr = corr; + m_syncPtr = m_dataPtr; + m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_SAMPLES / 2U + DMR_INFO_LENGTH_SAMPLES / 2U - 1U; + } +} + void CDMRSlotRX::samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold) { for (uint8_t i = 0U; i < count; i++, start += DMR_RADIO_SYMBOL_LENGTH) { diff --git a/DMRSlotRX.h b/DMRSlotRX.h index aacbe2a..dbbfc59 100644 --- a/DMRSlotRX.h +++ b/DMRSlotRX.h @@ -22,6 +22,12 @@ #include "Config.h" #include "DMRDefines.h" +enum DMRRX_STATE { + DMRRXS_NONE, + DMRRXS_VOICE, + DMRRXS_DATA +}; + class CDMRSlotRX { public: CDMRSlotRX(bool slot); @@ -36,24 +42,26 @@ public: void reset(); private: - bool m_slot; - uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; - q15_t m_buffer[900U]; - uint16_t m_bitPtr; - uint16_t m_dataPtr; - uint16_t m_syncPtr; - uint16_t m_endPtr; - uint16_t m_delayPtr; - q31_t m_maxCorr; - q15_t m_centre; - q15_t m_threshold; - uint8_t m_control; - uint8_t m_syncCount; - uint8_t m_colorCode; - uint16_t m_delay; - uint8_t m_n; + bool m_slot; + uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; + q15_t m_buffer[900U]; + uint16_t m_bitPtr; + uint16_t m_dataPtr; + uint16_t m_syncPtr; + uint16_t m_endPtr; + uint16_t m_delayPtr; + q31_t m_maxCorr; + q15_t m_centre; + q15_t m_threshold; + uint8_t m_control; + uint8_t m_syncCount; + uint8_t m_colorCode; + uint16_t m_delay; + DMRRX_STATE m_state; + uint8_t m_n; - void correlateSync(q15_t sample); + void correlateSync(); + void correlateEMB(); void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); };