From e86e1bfdd230369d9aac5925970b6923fb758d7b Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sat, 29 Apr 2017 23:05:03 -0300 Subject: [PATCH] Adapting original duplex DMR code to MMDVM_HS --- ADF7021.cpp | 5 +- BitRB.cpp | 14 +-- BitRB.h | 5 +- DMRIdleRX.cpp | 169 ++++++++--------------------------- DMRIdleRX.h | 17 ++-- DMRRX.cpp | 30 +++---- DMRRX.h | 6 +- DMRSlotRX.cpp | 237 +++++++++++-------------------------------------- DMRSlotRX.h | 18 ++-- DMRTX.cpp | 92 ++++--------------- DMRTX.h | 8 +- Globals.h | 17 ++++ IO.cpp | 15 ++-- IO.h | 2 +- MMDVM_HS.cpp | 18 +++- MMDVM_HS.ino | 16 +++- SerialPort.cpp | 2 + 17 files changed, 216 insertions(+), 455 deletions(-) diff --git a/ADF7021.cpp b/ADF7021.cpp index 027050d..078ab7d 100644 --- a/ADF7021.cpp +++ b/ADF7021.cpp @@ -425,6 +425,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) void CIO::interrupt() { uint8_t bit = 0; + uint8_t control = MARK_NONE; if (!m_started) return; @@ -449,7 +450,7 @@ void CIO::interrupt() // we set the TX bit at TXD low, sampling of ADF7021 happens at rising clock if (m_tx && clk == 0) { - m_txBuffer.get(bit); + m_txBuffer.get(bit, control); even = !even; // use this for tracking issues @@ -498,7 +499,7 @@ void CIO::interrupt() else bit = 0; - m_rxBuffer.put(bit); + m_rxBuffer.put(bit, control); } if (torx_request == true && even == false && m_tx && clk == 0) { diff --git a/BitRB.cpp b/BitRB.cpp index 891d3dc..de00b1f 100644 --- a/BitRB.cpp +++ b/BitRB.cpp @@ -24,12 +24,14 @@ Boston, MA 02110-1301, USA. CBitRB::CBitRB(uint16_t length) : m_length(length), m_bits(NULL), +m_control(NULL), m_head(0U), m_tail(0U), m_full(false), m_overflow(false) { - m_bits = new uint8_t[length]; + m_bits = new uint8_t[length]; + m_control = new uint8_t[length]; } uint16_t CBitRB::getSpace() const @@ -59,14 +61,15 @@ uint16_t CBitRB::getData() const return m_length - m_tail + m_head; } -bool CBitRB::put(uint8_t bit) +bool CBitRB::put(uint8_t bit, uint8_t control) { if (m_full) { m_overflow = true; return false; } - m_bits[m_head] = bit; + m_bits[m_head] = bit; + m_control[m_head] = control; m_head++; if (m_head >= m_length) @@ -78,12 +81,13 @@ bool CBitRB::put(uint8_t bit) return true; } -bool CBitRB::get(uint8_t& bit) +bool CBitRB::get(uint8_t& bit, uint8_t& control) { if (m_head == m_tail && !m_full) return false; - bit = m_bits[m_tail]; + bit = m_bits[m_tail]; + control = m_control[m_tail]; m_full = false; diff --git a/BitRB.h b/BitRB.h index 3b191b2..b734abc 100644 --- a/BitRB.h +++ b/BitRB.h @@ -37,15 +37,16 @@ public: uint16_t getData() const; - bool put(uint8_t bit); + bool put(uint8_t bit, uint8_t control); - bool get(uint8_t& bit); + bool get(uint8_t& bit, uint8_t& control); bool hasOverflowed(); private: uint16_t m_length; volatile uint8_t* m_bits; + volatile uint8_t* m_control; volatile uint16_t m_head; volatile uint16_t m_tail; volatile bool m_full; diff --git a/DMRIdleRX.cpp b/DMRIdleRX.cpp index 5141aa3..d87ee75 100644 --- a/DMRIdleRX.cpp +++ b/DMRIdleRX.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2017 by Andy Uribe CA6JAU * * 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 @@ -16,39 +17,29 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(DUPLEX) - #define WANT_DEBUG #include "Config.h" + +#if defined(DUPLEX) + #include "Globals.h" #include "DMRIdleRX.h" #include "DMRSlotType.h" #include "Utils.h" -const q15_t SCALING_FACTOR = 19505; // Q15(0.60) - const uint8_t MAX_SYNC_SYMBOLS_ERRS = 2U; const uint8_t MAX_SYNC_BYTES_ERRS = 3U; -const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; - -#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 uint16_t NOENDPTR = 9999U; const uint8_t CONTROL_IDLE = 0x80U; const uint8_t CONTROL_DATA = 0x40U; CDMRIdleRX::CDMRIdleRX() : -m_bitBuffer(), m_buffer(), -m_bitPtr(0U), m_dataPtr(0U), m_endPtr(NOENDPTR), -m_maxCorr(0), -m_centre(0), -m_threshold(0), m_colorCode(0U) { } @@ -56,102 +47,33 @@ m_colorCode(0U) void CDMRIdleRX::reset() { m_dataPtr = 0U; - m_bitPtr = 0U; - m_maxCorr = 0; - m_threshold = 0; - m_centre = 0; m_endPtr = NOENDPTR; } -void CDMRIdleRX::samples(const q15_t* samples, uint8_t length) +void CDMRIdleRX::databit(bool bit) { - for (uint8_t i = 0U; i < length; i++) - processSample(samples[i]); -} - -void CDMRIdleRX::processSample(q15_t sample) -{ - m_bitBuffer[m_bitPtr] <<= 1; - if (sample < 0) - m_bitBuffer[m_bitPtr] |= 0x01U; - - m_buffer[m_dataPtr] = sample; - - if (countBits32((m_bitBuffer[m_bitPtr] & DMR_SYNC_SYMBOLS_MASK) ^ DMR_MS_DATA_SYNC_SYMBOLS) <= MAX_SYNC_SYMBOLS_ERRS) { - uint16_t ptr = m_dataPtr + DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH; - if (ptr >= DMR_FRAME_LENGTH_SAMPLES) - ptr -= DMR_FRAME_LENGTH_SAMPLES; - - q31_t corr = 0; - q15_t max = -16000; - q15_t min = 16000; - - for (uint8_t i = 0U; i < DMR_SYNC_LENGTH_SYMBOLS; i++) { - q15_t val = m_buffer[ptr]; - - if (val > max) - max = val; - if (val < min) - min = val; - - switch (DMR_MS_DATA_SYNC_SYMBOLS_VALUES[i]) { - case +3: - corr -= (val + val + val); - break; - case +1: - corr -= val; - break; - case -1: - corr += val; - break; - default: // -3 - corr += (val + val + val); - break; - } - - ptr += DMR_RADIO_SYMBOL_LENGTH; - if (ptr >= DMR_FRAME_LENGTH_SAMPLES) - ptr -= DMR_FRAME_LENGTH_SAMPLES; - } - - if (corr > m_maxCorr) { - q15_t centre = (max + min) >> 1; - - q31_t v1 = (max - centre) * SCALING_FACTOR; - q15_t threshold = q15_t(v1 >> 15); - - uint8_t sync[DMR_SYNC_BYTES_LENGTH]; - - uint16_t ptr = m_dataPtr + DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH; - if (ptr >= DMR_FRAME_LENGTH_SAMPLES) - ptr -= DMR_FRAME_LENGTH_SAMPLES; - - samplesToBits(ptr, DMR_SYNC_LENGTH_SYMBOLS, sync, 4U, centre, threshold); - - uint8_t errs = 0U; - for (uint8_t i = 0U; i < DMR_SYNC_BYTES_LENGTH; i++) - errs += countBits8((sync[i] & DMR_SYNC_BYTES_MASK[i]) ^ DMR_MS_DATA_SYNC_BYTES[i]); - - if (errs <= MAX_SYNC_BYTES_ERRS) { - DEBUG3("DMRIdleRX: data sync found centre/threshold", centre, threshold); - m_maxCorr = corr; - m_centre = centre; - m_threshold = threshold; - - m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_SAMPLES / 2U + DMR_INFO_LENGTH_SAMPLES / 2U - 1U; - if (m_endPtr >= DMR_FRAME_LENGTH_SAMPLES) - m_endPtr -= DMR_FRAME_LENGTH_SAMPLES; - } - } + m_buffer[m_dataPtr] = bit; + + m_patternBuffer <<= 1; + if (bit) + m_patternBuffer |= 0x01U; + + if (countBits64((m_patternBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) { + m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U; + if (m_endPtr >= DMR_FRAME_LENGTH_BITS) + m_endPtr -= DMR_FRAME_LENGTH_BITS; + + DEBUG3("SYNC MS Data found pos/end:", m_dataPtr, m_endPtr); } if (m_dataPtr == m_endPtr) { - uint16_t ptr = m_endPtr + DMR_RADIO_SYMBOL_LENGTH + 1U; - if (ptr >= DMR_FRAME_LENGTH_SAMPLES) - ptr -= DMR_FRAME_LENGTH_SAMPLES; + uint16_t ptr = m_endPtr + 2; + + if (ptr >= DMR_FRAME_LENGTH_BITS) + ptr -= DMR_FRAME_LENGTH_BITS; uint8_t frame[DMR_FRAME_LENGTH_BYTES + 1U]; - samplesToBits(ptr, DMR_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centre, m_threshold); + bitsToBytes(ptr, DMR_FRAME_LENGTH_BITS, frame + 1U); uint8_t colorCode; uint8_t dataType; @@ -164,48 +86,29 @@ void CDMRIdleRX::processSample(q15_t sample) } m_endPtr = NOENDPTR; - m_maxCorr = 0; } m_dataPtr++; - if (m_dataPtr >= DMR_FRAME_LENGTH_SAMPLES) + if (m_dataPtr >= DMR_FRAME_LENGTH_BITS) m_dataPtr = 0U; - - m_bitPtr++; - if (m_bitPtr >= DMR_RADIO_SYMBOL_LENGTH) - m_bitPtr = 0U; } -void CDMRIdleRX::samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold) +void CDMRIdleRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer) { for (uint8_t i = 0U; i < count; i++) { - q15_t sample = m_buffer[start] - centre; + buffer[i] = 0U; + buffer[i] |= ((m_buffer[start + 0U] & 0x01) << 7); + buffer[i] |= ((m_buffer[start + 1U] & 0x01) << 6); + buffer[i] |= ((m_buffer[start + 2U] & 0x01) << 5); + buffer[i] |= ((m_buffer[start + 3U] & 0x01) << 4); + buffer[i] |= ((m_buffer[start + 4U] & 0x01) << 3); + buffer[i] |= ((m_buffer[start + 5U] & 0x01) << 2); + buffer[i] |= ((m_buffer[start + 6U] & 0x01) << 1); + buffer[i] |= ((m_buffer[start + 7U] & 0x01) << 0); - if (sample < -threshold) { - WRITE_BIT1(buffer, offset, false); - offset++; - WRITE_BIT1(buffer, offset, true); - offset++; - } else if (sample < 0) { - WRITE_BIT1(buffer, offset, false); - offset++; - WRITE_BIT1(buffer, offset, false); - offset++; - } else if (sample < threshold) { - WRITE_BIT1(buffer, offset, true); - offset++; - WRITE_BIT1(buffer, offset, false); - offset++; - } else { - WRITE_BIT1(buffer, offset, true); - offset++; - WRITE_BIT1(buffer, offset, true); - offset++; - } - - start += DMR_RADIO_SYMBOL_LENGTH; - if (start >= DMR_FRAME_LENGTH_SAMPLES) - start -= DMR_FRAME_LENGTH_SAMPLES; + start += 8U; + if (start >= DMR_FRAME_LENGTH_BITS) + start -= DMR_FRAME_LENGTH_BITS; } } diff --git a/DMRIdleRX.h b/DMRIdleRX.h index 3bb6d15..87c5e73 100644 --- a/DMRIdleRX.h +++ b/DMRIdleRX.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 by Jonathan Naylor G4KLX + * Copyright (C) 2017 by Andy Uribe CA6JAU * * 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,34 +20,30 @@ #if !defined(DMRIDLERX_H) #define DMRIDLERX_H +#include "Config.h" + #if defined(DUPLEX) -#include "Config.h" #include "DMRDefines.h" class CDMRIdleRX { public: CDMRIdleRX(); - void samples(const q15_t* samples, uint8_t length); + void databit(bool bit); void setColorCode(uint8_t colorCode); void reset(); private: - uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; - q15_t m_buffer[DMR_FRAME_LENGTH_SAMPLES]; - uint16_t m_bitPtr; + uint64_t m_patternBuffer; + uint8_t m_buffer[DMR_FRAME_LENGTH_BITS]; uint16_t m_dataPtr; uint16_t m_endPtr; - q31_t m_maxCorr; - q15_t m_centre; - q15_t m_threshold; uint8_t m_colorCode; - void processSample(q15_t sample); - void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); + void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer); }; #endif diff --git a/DMRRX.cpp b/DMRRX.cpp index d6ee22c..1b1aa47 100644 --- a/DMRRX.cpp +++ b/DMRRX.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2017 by Andy Uribe CA6JAU * * 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 @@ -16,9 +17,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "Config.h" + #if defined(DUPLEX) -#include "Config.h" #include "Globals.h" #include "DMRRX.h" @@ -28,25 +30,23 @@ m_slot2RX(true) { } -void CDMRRX::samples(const q15_t* samples, const uint16_t* rssi, const uint8_t* control, uint8_t length) +void CDMRRX::databit(bool bit, const uint8_t control) { bool dcd1 = false; bool dcd2 = false; - for (uint16_t i = 0U; i < length; i++) { - switch (control[i]) { - case MARK_SLOT1: - m_slot1RX.start(); - break; - case MARK_SLOT2: - m_slot2RX.start(); - break; - default: - break; - } + switch (control) { + case MARK_SLOT1: + m_slot1RX.start(); + break; + case MARK_SLOT2: + m_slot2RX.start(); + break; + default: + break; - dcd1 = m_slot1RX.processSample(samples[i], rssi[i]); - dcd2 = m_slot2RX.processSample(samples[i], rssi[i]); + dcd1 = m_slot1RX.databit(bit); + dcd2 = m_slot2RX.databit(bit); } io.setDecode(dcd1 || dcd2); diff --git a/DMRRX.h b/DMRRX.h index ccd1cbd..822cb13 100644 --- a/DMRRX.h +++ b/DMRRX.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2017 by Andy Uribe CA6JAU * * 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,16 +20,17 @@ #if !defined(DMRRX_H) #define DMRRX_H +#include "Config.h" + #if defined(DUPLEX) -#include "Config.h" #include "DMRSlotRX.h" class CDMRRX { public: CDMRRX(); - void samples(const q15_t* samples, const uint16_t* rssi, const uint8_t* control, uint8_t length); + void databit(bool bit, const uint8_t control); void setColorCode(uint8_t colorCode); void setDelay(uint8_t delay); diff --git a/DMRSlotRX.cpp b/DMRSlotRX.cpp index 84f057c..965bf39 100644 --- a/DMRSlotRX.cpp +++ b/DMRSlotRX.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2017 by Andy Uribe CA6JAU * * 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 @@ -16,11 +17,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(DUPLEX) - #define WANT_DEBUG #include "Config.h" + +#if defined(DUPLEX) + #include "Globals.h" #include "DMRSlotRX.h" #include "DMRSlotType.h" @@ -29,17 +31,10 @@ const uint16_t SCAN_START = 400U; const uint16_t SCAN_END = 490U; -const q15_t SCALING_FACTOR = 19505; // Q15(0.60) - -const uint8_t MAX_SYNC_SYMBOLS_ERRS = 2U; -const uint8_t MAX_SYNC_BYTES_ERRS = 3U; +const uint8_t MAX_SYNC_BYTES_ERRS = 1U; const uint8_t MAX_SYNC_LOST_FRAMES = 13U; -const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; - -#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 uint16_t NOENDPTR = 9999U; const uint8_t CONTROL_NONE = 0x00U; @@ -48,26 +43,20 @@ const uint8_t CONTROL_DATA = 0x40U; CDMRSlotRX::CDMRSlotRX(bool slot) : m_slot(slot), -m_bitBuffer(), +m_patternBuffer(0x00U), m_buffer(), -m_bitPtr(0U), m_dataPtr(0U), m_syncPtr(0U), m_startPtr(0U), m_endPtr(NOENDPTR), m_delayPtr(0U), -m_maxCorr(0), -m_centre(), -m_threshold(), -m_averagePtr(0U), m_control(CONTROL_NONE), m_syncCount(0U), m_colorCode(0U), m_delay(0U), m_state(DMRRXS_NONE), m_n(0U), -m_type(0U), -m_rssi() +m_type(0U) { } @@ -75,8 +64,6 @@ void CDMRSlotRX::start() { m_dataPtr = 0U; m_delayPtr = 0U; - m_bitPtr = 0U; - m_maxCorr = 0; m_control = CONTROL_NONE; } @@ -85,8 +72,6 @@ void CDMRSlotRX::reset() m_syncPtr = 0U; m_dataPtr = 0U; m_delayPtr = 0U; - m_bitPtr = 0U; - m_maxCorr = 0; m_control = CONTROL_NONE; m_syncCount = 0U; m_state = DMRRXS_NONE; @@ -94,7 +79,7 @@ void CDMRSlotRX::reset() m_endPtr = NOENDPTR; } -bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi) +bool CDMRSlotRX::databit(bool bit) { m_delayPtr++; if (m_delayPtr < m_delay) @@ -104,12 +89,11 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi) if (m_dataPtr > m_endPtr || m_dataPtr >= 900U) return m_state != DMRRXS_NONE; - m_buffer[m_dataPtr] = sample; - m_rssi[m_dataPtr] = rssi; + m_buffer[m_dataPtr] = bit; - m_bitBuffer[m_bitPtr] <<= 1; - if (sample < 0) - m_bitBuffer[m_bitPtr] |= 0x01U; + m_patternBuffer <<= 1; + if (bit) + m_patternBuffer |= 0x01U; if (m_state == DMRRXS_NONE) { if (m_dataPtr >= SCAN_START && m_dataPtr <= SCAN_END) @@ -123,15 +107,10 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi) } if (m_dataPtr == m_endPtr) { - // Find the average centre and threshold values - q15_t centre = (m_centre[0U] + m_centre[1U] + m_centre[2U] + m_centre[3U]) >> 2; - q15_t threshold = (m_threshold[0U] + m_threshold[1U] + m_threshold[2U] + m_threshold[3U]) >> 2; - uint8_t frame[DMR_FRAME_LENGTH_BYTES + 3U]; frame[0U] = m_control; - uint16_t ptr = m_endPtr - DMR_FRAME_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH + 1U; - samplesToBits(ptr, DMR_FRAME_LENGTH_SYMBOLS, frame, 8U, centre, threshold); + bitsToBytes(m_startPtr, DMR_FRAME_LENGTH_BYTES, frame + 1U); if (m_control == CONTROL_DATA) { // Data sync @@ -148,7 +127,7 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi) switch (dataType) { case DT_DATA_HEADER: - DEBUG5("DMRSlotRX: data header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); + DEBUG3("DMRSlotRX: data header found slot/pos", m_slot ? 2U : 1U, m_syncPtr); writeRSSIData(frame); m_state = DMRRXS_DATA; m_type = 0x00U; @@ -157,33 +136,33 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi) case DT_RATE_34_DATA: case DT_RATE_1_DATA: if (m_state == DMRRXS_DATA) { - DEBUG5("DMRSlotRX: data payload found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); + DEBUG3("DMRSlotRX: data payload found slot/pos", m_slot ? 2U : 1U, m_syncPtr); writeRSSIData(frame); m_type = dataType; } break; case DT_VOICE_LC_HEADER: - DEBUG5("DMRSlotRX: voice header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); + DEBUG3("DMRSlotRX: voice header found slot/pos", m_slot ? 2U : 1U, m_syncPtr); writeRSSIData(frame); m_state = DMRRXS_VOICE; break; case DT_VOICE_PI_HEADER: if (m_state == DMRRXS_VOICE) { - DEBUG5("DMRSlotRX: voice pi header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); + DEBUG3("DMRSlotRX: voice pi header found slot/pos", m_slot ? 2U : 1U, m_syncPtr); writeRSSIData(frame); } m_state = DMRRXS_VOICE; break; case DT_TERMINATOR_WITH_LC: if (m_state == DMRRXS_VOICE) { - DEBUG5("DMRSlotRX: voice terminator found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); + DEBUG3("DMRSlotRX: voice terminator found slot/pos", m_slot ? 2U : 1U, m_syncPtr); writeRSSIData(frame); m_state = DMRRXS_NONE; m_endPtr = NOENDPTR; } break; default: // DT_CSBK - DEBUG5("DMRSlotRX: csbk found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); + DEBUG3("DMRSlotRX: csbk found slot/pos", m_slot ? 2U : 1U, m_syncPtr); writeRSSIData(frame); m_state = DMRRXS_NONE; m_endPtr = NOENDPTR; @@ -192,7 +171,7 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi) } } else if (m_control == CONTROL_VOICE) { // Voice sync - DEBUG5("DMRSlotRX: voice sync found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); + DEBUG3("DMRSlotRX: voice sync found slot/pos", m_slot ? 2U : 1U, m_syncPtr); writeRSSIData(frame); m_state = DMRRXS_VOICE; m_syncCount = 0U; @@ -227,151 +206,43 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi) m_dataPtr++; - m_bitPtr++; - if (m_bitPtr >= DMR_RADIO_SYMBOL_LENGTH) - m_bitPtr = 0U; - return m_state != DMRRXS_NONE; } void CDMRSlotRX::correlateSync(bool first) -{ - uint8_t errs = countBits32((m_bitBuffer[m_bitPtr] & DMR_SYNC_SYMBOLS_MASK) ^ DMR_MS_DATA_SYNC_SYMBOLS); +{ + if (countBits64((m_patternBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) { - // The voice sync is the complement of the data sync - bool data = (errs <= MAX_SYNC_SYMBOLS_ERRS); - bool voice = (errs >= (DMR_SYNC_LENGTH_SYMBOLS - MAX_SYNC_SYMBOLS_ERRS)); + m_control = CONTROL_DATA; + m_syncPtr = m_dataPtr; + m_startPtr = m_dataPtr - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1; + m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U; + DEBUG4("SYNC MS Data found pos/start/end:", m_dataPtr, m_startPtr, m_endPtr); + + } else if (countBits64((m_patternBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) { - if (data || voice) { - uint16_t ptr = m_dataPtr - DMR_SYNC_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH; - - q31_t corr = 0; - q15_t min = 16000; - q15_t max = -16000; - - for (uint8_t i = 0U; i < DMR_SYNC_LENGTH_SYMBOLS; i++) { - q15_t val = m_buffer[ptr]; - - if (val > max) - max = val; - if (val < min) - min = val; - - int8_t corrVal; - if (data) - corrVal = DMR_MS_DATA_SYNC_SYMBOLS_VALUES[i]; - else - corrVal = DMR_MS_VOICE_SYNC_SYMBOLS_VALUES[i]; - - switch (corrVal) { - case +3: - corr -= (val + val + val); - break; - case +1: - corr -= val; - break; - case -1: - corr += val; - break; - default: // -3 - corr += (val + val + val); - break; - } - - ptr += DMR_RADIO_SYMBOL_LENGTH; - } - - if (corr > m_maxCorr) { - q15_t centre = (max + min) >> 1; - - q31_t v1 = (max - centre) * SCALING_FACTOR; - q15_t threshold = q15_t(v1 >> 15); - - uint8_t sync[DMR_SYNC_BYTES_LENGTH]; - uint16_t ptr = m_dataPtr - DMR_SYNC_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH; - samplesToBits(ptr, DMR_SYNC_LENGTH_SYMBOLS, sync, 4U, centre, threshold); - - if (data) { - uint8_t errs = 0U; - for (uint8_t i = 0U; i < DMR_SYNC_BYTES_LENGTH; i++) - errs += countBits8((sync[i] & DMR_SYNC_BYTES_MASK[i]) ^ DMR_MS_DATA_SYNC_BYTES[i]); - - if (errs <= MAX_SYNC_BYTES_ERRS) { - if (first) { - m_threshold[0U] = m_threshold[1U] = m_threshold[2U] = m_threshold[3U] = threshold; - m_centre[0U] = m_centre[1U] = m_centre[2U] = m_centre[3U] = centre; - m_averagePtr = 0U; - } else { - m_threshold[m_averagePtr] = threshold; - m_centre[m_averagePtr] = centre; - - m_averagePtr++; - if (m_averagePtr >= 4U) - m_averagePtr = 0U; - } - - m_maxCorr = corr; - m_control = CONTROL_DATA; - m_syncPtr = m_dataPtr; - m_startPtr = m_dataPtr - DMR_SLOT_TYPE_LENGTH_SAMPLES / 2U - DMR_INFO_LENGTH_SAMPLES / 2U - DMR_SYNC_LENGTH_SAMPLES; - m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_SAMPLES / 2U + DMR_INFO_LENGTH_SAMPLES / 2U - 1U; - } - } else { // if (voice) - uint8_t errs = 0U; - for (uint8_t i = 0U; i < DMR_SYNC_BYTES_LENGTH; i++) - errs += countBits8((sync[i] & DMR_SYNC_BYTES_MASK[i]) ^ DMR_MS_VOICE_SYNC_BYTES[i]); - - if (errs <= MAX_SYNC_BYTES_ERRS) { - if (first) { - m_threshold[0U] = m_threshold[1U] = m_threshold[2U] = m_threshold[3U] = threshold; - m_centre[0U] = m_centre[1U] = m_centre[2U] = m_centre[3U] = centre; - m_averagePtr = 0U; - } else { - m_threshold[m_averagePtr] = threshold; - m_centre[m_averagePtr] = centre; - - m_averagePtr++; - if (m_averagePtr >= 4U) - m_averagePtr = 0U; - } - - m_maxCorr = corr; - m_control = CONTROL_VOICE; - m_syncPtr = m_dataPtr; - m_startPtr = m_dataPtr - DMR_SLOT_TYPE_LENGTH_SAMPLES / 2U - DMR_INFO_LENGTH_SAMPLES / 2U - DMR_SYNC_LENGTH_SAMPLES; - m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_SAMPLES / 2U + DMR_INFO_LENGTH_SAMPLES / 2U - 1U; - } - } - } + m_control = CONTROL_VOICE; + m_syncPtr = m_dataPtr; + m_startPtr = m_dataPtr - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1; + m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U; + DEBUG4("SYNC MS Voice found pos/start/end: ", m_dataPtr, m_startPtr, m_endPtr); } } -void CDMRSlotRX::samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold) +void CDMRSlotRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer) { - for (uint8_t i = 0U; i < count; i++, start += DMR_RADIO_SYMBOL_LENGTH) { - q15_t sample = m_buffer[start] - centre; + for (uint8_t i = 0U; i < count; i++) { + buffer[i] = 0U; + buffer[i] |= ((m_buffer[start + 0U] & 0x01) << 7); + buffer[i] |= ((m_buffer[start + 1U] & 0x01) << 6); + buffer[i] |= ((m_buffer[start + 2U] & 0x01) << 5); + buffer[i] |= ((m_buffer[start + 3U] & 0x01) << 4); + buffer[i] |= ((m_buffer[start + 4U] & 0x01) << 3); + buffer[i] |= ((m_buffer[start + 5U] & 0x01) << 2); + buffer[i] |= ((m_buffer[start + 6U] & 0x01) << 1); + buffer[i] |= ((m_buffer[start + 7U] & 0x01) << 0); - if (sample < -threshold) { - WRITE_BIT1(buffer, offset, false); - offset++; - WRITE_BIT1(buffer, offset, true); - offset++; - } else if (sample < 0) { - WRITE_BIT1(buffer, offset, false); - offset++; - WRITE_BIT1(buffer, offset, false); - offset++; - } else if (sample < threshold) { - WRITE_BIT1(buffer, offset, true); - offset++; - WRITE_BIT1(buffer, offset, false); - offset++; - } else { - WRITE_BIT1(buffer, offset, true); - offset++; - WRITE_BIT1(buffer, offset, true); - offset++; - } + start += 8U; } } @@ -388,17 +259,11 @@ void CDMRSlotRX::setDelay(uint8_t delay) void CDMRSlotRX::writeRSSIData(uint8_t* frame) { #if defined(SEND_RSSI_DATA) - // Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end - uint16_t start = m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U; - - uint32_t accum = 0U; - for (uint16_t i = 0U; i < (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES); i++) - accum += m_rssi[start++]; - - uint16_t avg = accum / (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES); - frame[34U] = (avg >> 8) & 0xFFU; - frame[35U] = (avg >> 0) & 0xFFU; - + uint16_t rssi = io.readRSSI(); + + frame[34U] = (rssi >> 8) & 0xFFU; + frame[35U] = (rssi >> 0) & 0xFFU; + serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 3U); #else serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); diff --git a/DMRSlotRX.h b/DMRSlotRX.h index 6e0719e..145d6d9 100644 --- a/DMRSlotRX.h +++ b/DMRSlotRX.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX + * Copyright (C) 2017 by Andy Uribe CA6JAU * * 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,9 +20,10 @@ #if !defined(DMRSLOTRX_H) #define DMRSLOTRX_H +#include "Config.h" + #if defined(DUPLEX) -#include "Config.h" #include "DMRDefines.h" enum DMRRX_STATE { @@ -36,7 +38,7 @@ public: void start(); - bool processSample(q15_t sample, uint16_t rssi); + bool databit(bool bit); void setColorCode(uint8_t colorCode); void setDelay(uint8_t delay); @@ -45,18 +47,13 @@ public: private: bool m_slot; - uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; - q15_t m_buffer[900U]; - uint16_t m_bitPtr; + uint64_t m_patternBuffer; + uint8_t m_buffer[900U]; uint16_t m_dataPtr; uint16_t m_syncPtr; uint16_t m_startPtr; uint16_t m_endPtr; uint16_t m_delayPtr; - q31_t m_maxCorr; - q15_t m_centre[4U]; - q15_t m_threshold[4U]; - uint8_t m_averagePtr; uint8_t m_control; uint8_t m_syncCount; uint8_t m_colorCode; @@ -64,10 +61,9 @@ private: DMRRX_STATE m_state; uint8_t m_n; uint8_t m_type; - uint16_t m_rssi[900U]; void correlateSync(bool first); - void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); + void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer); void writeRSSIData(uint8_t* frame); }; diff --git a/DMRTX.cpp b/DMRTX.cpp index ada927f..061385d 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -18,32 +18,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(DUPLEX) - // #define WANT_DEBUG #include "Config.h" + +#if defined(DUPLEX) + #include "Globals.h" #include "DMRSlotType.h" -#if defined(WIDE_C4FSK_FILTERS_TX) -// Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t DMR_C4FSK_FILTER[] = {0, 0, 0, 0, 688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688}; // numTaps = 25, L = 5 -const uint16_t DMR_C4FSK_FILTER_PHASE_LEN = 5U; // phaseLength = numTaps/L -#else -// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t DMR_C4FSK_FILTER[] = {0, 0, 0, 0, 401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, - 11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112, - -553, -847, -731, -340, 104, 401}; // numTaps = 45, L = 5 -const uint16_t DMR_C4FSK_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L -#endif - -const q15_t DMR_LEVELA = 2889; -const q15_t DMR_LEVELB = 963; -const q15_t DMR_LEVELC = -963; -const q15_t DMR_LEVELD = -2889; - // The PR FILL and BS Data Sync pattern. const uint8_t IDLE_DATA[] = {0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U, @@ -68,8 +51,6 @@ const uint32_t STARTUP_COUNT = 20U; CDMRTX::CDMRTX() : m_fifo(), -m_modFilter(), -m_modState(), m_state(DMRTXSTATE_IDLE), m_idle(), m_cachPtr(0U), @@ -82,13 +63,6 @@ m_poPtr(0U), m_frameCount(0U), m_abort() { - ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); - - m_modFilter.L = DMR_RADIO_SYMBOL_LENGTH; - m_modFilter.phaseLength = DMR_C4FSK_FILTER_PHASE_LEN; - m_modFilter.pCoeffs = DMR_C4FSK_FILTER; - m_modFilter.pState = m_modState; - ::memcpy(m_newShortLC, EMPTY_SHORT_LC, 12U); ::memcpy(m_shortLC, EMPTY_SHORT_LC, 12U); @@ -119,7 +93,6 @@ void CDMRTX::process() break; case DMRTXSTATE_CAL: - createCal(); break; default: @@ -132,14 +105,14 @@ void CDMRTX::process() if (m_poLen > 0U) { uint16_t space = io.getSpace(); - while (space > (4U * DMR_RADIO_SYMBOL_LENGTH)) { + while (space > 8U) { uint8_t c = m_poBuffer[m_poPtr]; uint8_t m = m_markBuffer[m_poPtr]; m_poPtr++; writeByte(c, m); - space -= 4U * DMR_RADIO_SYMBOL_LENGTH; + space -= 8U; if (m_poPtr >= m_poLen) { m_poPtr = 0U; @@ -243,42 +216,22 @@ void CDMRTX::setStart(bool start) m_abort[1U] = false; } -void CDMRTX::setCal(bool start) -{ - m_state = start ? DMRTXSTATE_CAL : DMRTXSTATE_IDLE; -} - void CDMRTX::writeByte(uint8_t c, uint8_t control) { - q15_t inBuffer[4U]; - q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; + uint8_t bit; + uint8_t mask = 0x80U; - const uint8_t MASK = 0xC0U; - - for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { - switch (c & MASK) { - case 0xC0U: - inBuffer[i] = DMR_LEVELA; - break; - case 0x80U: - inBuffer[i] = DMR_LEVELB; - break; - case 0x00U: - inBuffer[i] = DMR_LEVELC; - break; - default: - inBuffer[i] = DMR_LEVELD; - break; - } + for (uint8_t i = 0U; i < 8U; i++, c <<= 1) { + if ((c & mask) == mask) + bit = 1U; + else + bit = 0U; + + if( i != 3U) + control = MARK_NONE; + + io.write(&bit, 1, &control); } - - uint8_t controlBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; - ::memset(controlBuffer, MARK_NONE, DMR_RADIO_SYMBOL_LENGTH * 4U * sizeof(uint8_t)); - controlBuffer[DMR_RADIO_SYMBOL_LENGTH * 2U] = control; - - ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U); - - io.write(STATE_DMR, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U, controlBuffer); } uint8_t CDMRTX::getSpace1() const @@ -311,17 +264,6 @@ void CDMRTX::createData(uint8_t slotIndex) m_poPtr = 0U; } -void CDMRTX::createCal() -{ - for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) { - m_poBuffer[i] = 0x5FU; // +3, +3, -3, -3 pattern for deviation cal. - m_markBuffer[i] = MARK_NONE; - } - - m_poLen = DMR_FRAME_LENGTH_BYTES; - m_poPtr = 0U; -} - void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex) { m_frameCount++; diff --git a/DMRTX.h b/DMRTX.h index 23de3fd..ae6734f 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML + * Copyright (C) 2017 by Andy Uribe CA6JAU * * 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 @@ -20,9 +21,10 @@ #if !defined(DMRTX_H) #define DMRTX_H +#include "Config.h" + #if defined(DUPLEX) -#include "Config.h" #include "DMRDefines.h" #include "SerialRB.h" @@ -47,7 +49,6 @@ public: uint8_t writeAbort(const uint8_t* data, uint8_t length); void setStart(bool start); - void setCal(bool start); void process(); @@ -58,8 +59,6 @@ public: private: CSerialRB m_fifo[2U]; - arm_fir_interpolate_instance_q15 m_modFilter; - q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare DMRTXSTATE m_state; uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; uint8_t m_cachPtr; @@ -74,7 +73,6 @@ private: void createData(uint8_t slotIndex); void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex); - void createCal(); void writeByte(uint8_t c, uint8_t control); }; diff --git a/Globals.h b/Globals.h index 5b4fcc6..60c5bf4 100644 --- a/Globals.h +++ b/Globals.h @@ -35,10 +35,21 @@ enum MMDVM_STATE { STATE_P25 = 4 }; +const uint8_t MARK_SLOT1 = 0x08U; +const uint8_t MARK_SLOT2 = 0x04U; +const uint8_t MARK_NONE = 0x00U; + #include "IO.h" #include "SerialPort.h" #include "DMRDMORX.h" #include "DMRDMOTX.h" + +#if defined(DUPLEX) +#include "DMRIdleRX.h" +#include "DMRRX.h" +#include "DMRTX.h" +#endif + #include "DStarRX.h" #include "DStarTX.h" #include "YSFRX.h" @@ -69,6 +80,12 @@ extern CSerialPort serial; extern CDStarRX dstarRX; extern CDStarTX dstarTX; +#if defined(DUPLEX) +extern CDMRIdleRX dmrIdleRX; +extern CDMRRX dmrRX; +extern CDMRTX dmrTX; +#endif + extern CDMRDMORX dmrDMORX; extern CDMRDMOTX dmrDMOTX; diff --git a/IO.cpp b/IO.cpp index bf9ca06..e46dd03 100644 --- a/IO.cpp +++ b/IO.cpp @@ -63,6 +63,7 @@ void CIO::process() { uint8_t bit; uint32_t scantime; + uint8_t control; m_ledCount++; @@ -116,7 +117,7 @@ void CIO::process() } if (m_rxBuffer.getData() >= 1U) { - m_rxBuffer.get(bit); + m_rxBuffer.get(bit, control); switch (m_modemState_prev) { case STATE_DSTAR: @@ -179,14 +180,18 @@ void CIO::start() m_started = true; } -void CIO::write(uint8_t* data, uint16_t length) +void CIO::write(uint8_t* data, uint16_t length, const uint8_t* control) { if (!m_started) return; - for (uint16_t i = 0U; i < length; i++) - m_txBuffer.put(data[i]); - + for (uint16_t i = 0U; i < length; i++) { + if (control == NULL) + m_txBuffer.put(data[i], MARK_NONE); + else + m_txBuffer.put(data[i], control[i]); + } + // Switch the transmitter on if needed if (!m_tx) { setTX(); diff --git a/IO.h b/IO.h index dae9e47..b97b95b 100644 --- a/IO.h +++ b/IO.h @@ -78,7 +78,7 @@ public: #endif // IO API - void write(uint8_t* data, uint16_t length); + void write(uint8_t* data, uint16_t length, const uint8_t* control = NULL); uint16_t getSpace(void) const; void process(void); bool hasTXOverflow(void); diff --git a/MMDVM_HS.cpp b/MMDVM_HS.cpp index ab3f8a5..3443d2f 100644 --- a/MMDVM_HS.cpp +++ b/MMDVM_HS.cpp @@ -42,6 +42,12 @@ bool m_dcd = false; CDStarRX dstarRX; CDStarTX dstarTX; +#if defined(DUPLEX) +CDMRIdleRX dmrIdleRX; +CDMRRX dmrRX; +CDMRTX dmrTX; +#endif + CDMRDMORX dmrDMORX; CDMRDMOTX dmrDMOTX; @@ -69,9 +75,17 @@ void loop() if (m_dstarEnable && m_modemState == STATE_DSTAR) dstarTX.process(); - if (m_dmrEnable && m_modemState == STATE_DMR) + if (m_dmrEnable && m_modemState == STATE_DMR) { +#if defined(DUPLEX) + if (m_duplex) + dmrTX.process(); + else + dmrDMOTX.process(); +#else dmrDMOTX.process(); - +#endif + } + if (m_ysfEnable && m_modemState == STATE_YSF) ysfTX.process(); diff --git a/MMDVM_HS.ino b/MMDVM_HS.ino index 17e957f..060eacf 100644 --- a/MMDVM_HS.ino +++ b/MMDVM_HS.ino @@ -38,6 +38,12 @@ bool m_dcd = false; CDStarRX dstarRX; CDStarTX dstarTX; +#if defined(DUPLEX) +CDMRIdleRX dmrIdleRX; +CDMRRX dmrRX; +CDMRTX dmrTX; +#endif + CDMRDMORX dmrDMORX; CDMRDMOTX dmrDMOTX; @@ -64,8 +70,16 @@ void loop() if (m_dstarEnable && m_modemState == STATE_DSTAR) dstarTX.process(); - if (m_dmrEnable && m_modemState == STATE_DMR) + if (m_dmrEnable && m_modemState == STATE_DMR) { +#if defined(DUPLEX) + if (m_duplex) + dmrTX.process(); + else + dmrDMOTX.process(); +#else dmrDMOTX.process(); +#endif + } if (m_ysfEnable && m_modemState == STATE_YSF) ysfTX.process(); diff --git a/SerialPort.cpp b/SerialPort.cpp index 6bd8b31..e9331e9 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -230,6 +230,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) uint8_t colorCode = data[6U]; if (colorCode > 15U) return 4U; + + uint8_t dmrDelay = data[7U]; m_modemState = modemState;