mirror of https://github.com/g4klx/MMDVM.git
Add the EMB correlator for DMR.
This commit is contained in:
parent
9e91a52793
commit
17f212db3b
|
@ -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
|
||||||
|
|
||||||
|
|
101
DMRSlotRX.cpp
101
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])
|
#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) {
|
||||||
|
|
10
DMRSlotRX.h
10
DMRSlotRX.h
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue