Add the EMB correlator for DMR.

This commit is contained in:
Jonathan Naylor 2016-03-23 18:51:52 +00:00
parent 9e91a52793
commit 17f212db3b
3 changed files with 107 additions and 44 deletions

View File

@ -76,8 +76,10 @@ const uint8_t DT_VOICE_LC_HEADER = 1U;
const uint8_t DT_TERMINATOR_WITH_LC = 2U; const uint8_t DT_TERMINATOR_WITH_LC = 2U;
const uint8_t DT_CSBK = 3U; const uint8_t DT_CSBK = 3U;
const uint8_t DT_DATA_HEADER = 6U; 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; const uint8_t DT_IDLE = 9U;
// All others are for data transfer const uint8_t DT_RATE_1_DATA = 10U;
#endif #endif

View File

@ -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]) #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; const uint16_t NOENDPTR = 9999U;
CDMRSlotRX::CDMRSlotRX(bool slot) : CDMRSlotRX::CDMRSlotRX(bool slot) :
@ -53,6 +71,7 @@ m_control(0x00U),
m_syncCount(0U), m_syncCount(0U),
m_colorCode(0U), m_colorCode(0U),
m_delay(0U), m_delay(0U),
m_state(DMRRXS_NONE),
m_n(0U) m_n(0U)
{ {
} }
@ -77,6 +96,7 @@ void CDMRSlotRX::reset()
m_syncCount = 0U; m_syncCount = 0U;
m_threshold = 0; m_threshold = 0;
m_centre = 0; m_centre = 0;
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR; m_endPtr = NOENDPTR;
} }
@ -84,11 +104,11 @@ bool CDMRSlotRX::processSample(q15_t sample)
{ {
m_delayPtr++; m_delayPtr++;
if (m_delayPtr < m_delay) if (m_delayPtr < m_delay)
return m_endPtr != NOENDPTR; return m_state != DMRRXS_NONE;
// Ensure that the buffer doesn't overflow // Ensure that the buffer doesn't overflow
if (m_dataPtr > m_endPtr || m_dataPtr >= 900U) if (m_dataPtr > m_endPtr || m_dataPtr >= 900U)
return m_endPtr != NOENDPTR; return m_state != DMRRXS_NONE;
m_buffer[m_dataPtr] = sample; m_buffer[m_dataPtr] = sample;
@ -96,15 +116,23 @@ bool CDMRSlotRX::processSample(q15_t sample)
if (sample < 0) if (sample < 0)
m_bitBuffer[m_bitPtr] |= 0x01U; m_bitBuffer[m_bitPtr] |= 0x01U;
// The approximate position of the sync samples if (m_state == DMRRXS_VOICE) {
if (m_endPtr != NOENDPTR) { uint16_t min = m_syncPtr - 2U;
uint16_t min = m_syncPtr - 5U; uint16_t max = m_syncPtr + 2U;
uint16_t max = m_syncPtr + 5U; 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) if (m_dataPtr >= min && m_dataPtr <= max)
correlateSync(sample); correlateSync();
} else { } else {
if (m_dataPtr >= 420U && m_dataPtr <= 500U) if (m_dataPtr >= 420U && m_dataPtr <= 500U)
correlateSync(sample); correlateSync();
} }
if (m_dataPtr == m_endPtr) { if (m_dataPtr == m_endPtr) {
@ -129,27 +157,21 @@ bool CDMRSlotRX::processSample(q15_t sample)
switch (dataType) { switch (dataType) {
case DT_DATA_HEADER: case DT_DATA_HEADER:
DEBUG3("DMRSlotRX: data header for slot/data type", m_slot ? 2U : 1U, dataType); case DT_RATE_12_DATA:
m_endPtr = NOENDPTR; case DT_RATE_34_DATA:
case DT_RATE_1_DATA:
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRRXS_DATA;
break; break;
case DT_VOICE_LC_HEADER: 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: 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); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRRXS_VOICE;
break; break;
default: 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); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR;
break; break;
} }
} }
@ -157,25 +179,28 @@ bool CDMRSlotRX::processSample(q15_t sample)
// Voice sync // Voice sync
DEBUG2("DMRSlotRX: voice sync for slot", m_slot ? 2U : 1U); DEBUG2("DMRSlotRX: voice sync for slot", m_slot ? 2U : 1U);
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRRXS_VOICE;
m_syncCount = 0U; m_syncCount = 0U;
m_n = 0U; m_n = 0U;
} else { } else {
m_syncCount++; m_syncCount++;
if (m_syncCount >= MAX_SYNC_LOST_FRAMES) { if (m_syncCount >= MAX_SYNC_LOST_FRAMES) {
DEBUG2("DMRSlotRX: lost for slot", m_slot ? 2U : 1U);
serial.writeDMRLost(m_slot); serial.writeDMRLost(m_slot);
m_syncCount = 0U; m_syncCount = 0U;
m_threshold = 0; m_threshold = 0;
m_centre = 0; m_centre = 0;
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR; m_endPtr = NOENDPTR;
return false; return false;
} }
// Voice data // Voice data
if (m_state == DMRRXS_VOICE) {
frame[0U] |= ++m_n; frame[0U] |= ++m_n;
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
} }
} }
}
m_dataPtr++; m_dataPtr++;
@ -183,10 +208,10 @@ bool CDMRSlotRX::processSample(q15_t sample)
if (m_bitPtr >= DMR_RADIO_SYMBOL_LENGTH) if (m_bitPtr >= DMR_RADIO_SYMBOL_LENGTH)
m_bitPtr = 0U; 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); 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) 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) { for (uint8_t i = 0U; i < count; i++, start += DMR_RADIO_SYMBOL_LENGTH) {

View File

@ -22,6 +22,12 @@
#include "Config.h" #include "Config.h"
#include "DMRDefines.h" #include "DMRDefines.h"
enum DMRRX_STATE {
DMRRXS_NONE,
DMRRXS_VOICE,
DMRRXS_DATA
};
class CDMRSlotRX { class CDMRSlotRX {
public: public:
CDMRSlotRX(bool slot); CDMRSlotRX(bool slot);
@ -51,9 +57,11 @@ private:
uint8_t m_syncCount; uint8_t m_syncCount;
uint8_t m_colorCode; uint8_t m_colorCode;
uint16_t m_delay; uint16_t m_delay;
DMRRX_STATE m_state;
uint8_t m_n; 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); void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
}; };