diff --git a/DMRDMORX.cpp b/DMRDMORX.cpp new file mode 100644 index 0000000..c81b37b --- /dev/null +++ b/DMRDMORX.cpp @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2009-2016 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "DMRDMORX.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 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; +const uint8_t CONTROL_VOICE = 0x20U; +const uint8_t CONTROL_DATA = 0x40U; + +CDMRDMORX::CDMRDMORX() : +m_bitBuffer(), +m_buffer(), +m_bitPtr(0U), +m_dataPtr(0U), +m_syncPtr(0U), +m_startPtr(0U), +m_endPtr(NOENDPTR), +m_maxCorr(0), +m_centre(), +m_threshold(), +m_averagePtr(0U), +m_control(CONTROL_NONE), +m_syncCount(0U), +m_colorCode(0U), +m_state(DMORXS_NONE), +m_n(0U), +m_type(0U), +m_rssiCount(0U), +m_rssi(0U) +{ +} + +void CDMRDMORX::start() +{ + m_dataPtr = 0U; + m_bitPtr = 0U; + m_maxCorr = 0; + m_control = CONTROL_NONE; +} + +void CDMRDMORX::reset() +{ + m_syncPtr = 0U; + m_dataPtr = 0U; + m_bitPtr = 0U; + m_maxCorr = 0; + m_control = CONTROL_NONE; + m_syncCount = 0U; + m_state = DMORXS_NONE; + m_startPtr = 0U; + m_endPtr = NOENDPTR; + m_rssiCount = 0U; +} + +void CDMRDMORX::samples(const q15_t* samples, uint8_t length) +{ + bool dcd = false; + + for (uint8_t i = 0U; i < length; i++) + dcd = processSample(samples[i]); + + io.setDecode(dcd); +} + +bool CDMRDMORX::processSample(q15_t sample) +{ + if (m_state != DMORXS_NONE) { + if (m_dataPtr > m_startPtr && m_dataPtr < m_endPtr) + io.setADCDetection(true); + else + io.setADCDetection(false); + } else { + io.setADCDetection(false); + } + + m_buffer[m_dataPtr] = sample; + + m_bitBuffer[m_bitPtr] <<= 1; + if (sample < 0) + m_bitBuffer[m_bitPtr] |= 0x01U; + + if (m_state == DMORXS_NONE) { + correlateSync(true); + } else { +#if defined(SEND_RSSI_DATA) + // Grab the RSSI data during the frame + if (m_state == DMORXS_VOICE && m_dataPtr == m_syncPtr && m_rssiCount == 2U) + m_rssi = io.getRSSIValue(); +#endif + uint16_t min = m_syncPtr - 1U; + uint16_t max = m_syncPtr + 1U; + if (m_dataPtr >= min && m_dataPtr <= max) + correlateSync(false); + } + + 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); + + if (m_control == CONTROL_DATA) { + // Data sync + uint8_t colorCode; + uint8_t dataType; + CDMRSlotType slotType; + slotType.decode(frame + 1U, colorCode, dataType); + + if (colorCode == m_colorCode) { + m_syncCount = 0U; + m_n = 0U; + + frame[0U] |= dataType; + + switch (dataType) { + case DT_DATA_HEADER: + DEBUG4("DMRDMORX: data header found pos/centre/threshold", m_syncPtr, centre, threshold); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMORXS_DATA; + m_type = 0x00U; + break; + case DT_RATE_12_DATA: + case DT_RATE_34_DATA: + case DT_RATE_1_DATA: + if (m_state == DMORXS_DATA) { + DEBUG4("DMRDMORX: data payload found pos/centre/threshold", m_syncPtr, centre, threshold); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_type = dataType; + } + break; + case DT_VOICE_LC_HEADER: + DEBUG4("DMRDMORX: voice header found pos/centre/threshold", m_syncPtr, centre, threshold); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMORXS_VOICE; + break; + case DT_VOICE_PI_HEADER: + if (m_state == DMORXS_VOICE) { + DEBUG4("DMRDMORX: voice pi header found pos/centre/threshold", m_syncPtr, centre, threshold); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } + m_state = DMORXS_VOICE; + break; + case DT_TERMINATOR_WITH_LC: + if (m_state == DMORXS_VOICE) { + DEBUG4("DMRDMORX: voice terminator found pos/centre/threshold", m_syncPtr, centre, threshold); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMORXS_NONE; + m_endPtr = NOENDPTR; + } + break; + default: // DT_CSBK + DEBUG4("DMRDMORX: csbk found pos/centre/threshold", m_syncPtr, centre, threshold); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMORXS_NONE; + m_endPtr = NOENDPTR; + break; + } + } + } else if (m_control == CONTROL_VOICE) { + // Voice sync + DEBUG4("DMRDMORX: voice sync found pos/centre/threshold", m_syncPtr, centre, threshold); +#if defined(SEND_RSSI_DATA) + // Send RSSI data approximately every second + if (m_rssiCount == 2U) { + frame[34U] = (m_rssi >> 8) & 0xFFU; + frame[35U] = (m_rssi >> 0) & 0xFFU; + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 3U); + } else { + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } + + m_rssiCount++; + if (m_rssiCount >= 16U) + m_rssiCount = 0U; +#else + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); +#endif + m_state = DMORXS_VOICE; + m_syncCount = 0U; + m_n = 0U; + } else { + if (m_state != DMORXS_NONE) { + m_syncCount++; + if (m_syncCount >= MAX_SYNC_LOST_FRAMES) { + serial.writeDMRLost(true); + m_state = DMORXS_NONE; + m_endPtr = NOENDPTR; + } + } + + if (m_state == DMORXS_VOICE) { + if (m_n >= 5U) { + frame[0U] = CONTROL_VOICE; + m_n = 0U; + } else { + frame[0U] = ++m_n; + } +#if defined(SEND_RSSI_DATA) + // Send RSSI data approximately every second + if (m_rssiCount == 2U) { + frame[34U] = (m_rssi >> 8) & 0xFFU; + frame[35U] = (m_rssi >> 0) & 0xFFU; + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 3U); + } else { + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } + + m_rssiCount++; + if (m_rssiCount >= 16U) + m_rssiCount = 0U; +#else + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); +#endif + } else if (m_state == DMORXS_DATA) { + if (m_type != 0x00U) { + frame[0U] = CONTROL_DATA | m_type; + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } + } + } + } + + m_dataPtr++; + if (m_dataPtr >= DMO_BUFFER_SIZE) + m_dataPtr = 0U; + + m_bitPtr++; + if (m_bitPtr >= DMR_RADIO_SYMBOL_LENGTH) + m_bitPtr = 0U; + + return m_state != DMORXS_NONE; +} + +void CDMRDMORX::correlateSync(bool first) +{ + uint8_t errs = countBits32((m_bitBuffer[m_bitPtr] & DMR_SYNC_SYMBOLS_MASK) ^ DMR_S2_DATA_SYNC_SYMBOLS); + + // 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)); + + 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; + + uint32_t mask = 0x00800000U; + for (uint8_t i = 0U; i < DMR_SYNC_LENGTH_SYMBOLS; i++, mask >>= 1) { + bool b = (DMR_MS_DATA_SYNC_SYMBOLS & mask) == mask; + + if (m_buffer[ptr] > max) + max = m_buffer[ptr]; + if (m_buffer[ptr] < min) + min = m_buffer[ptr]; + + if (data) + corr += b ? -m_buffer[ptr] : m_buffer[ptr]; + else // if (voice) + corr += b ? m_buffer[ptr] : -m_buffer[ptr]; + + 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_S2_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; + m_rssiCount = 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_S2_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; + m_rssiCount = 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; + } + } + } + } +} + +void CDMRDMORX::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) { + q15_t sample = m_buffer[start] - centre; + + 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++; + } + } +} + +void CDMRDMORX::setColorCode(uint8_t colorCode) +{ + m_colorCode = colorCode; +} + diff --git a/DMRDMORX.h b/DMRDMORX.h new file mode 100644 index 0000000..a2051e6 --- /dev/null +++ b/DMRDMORX.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(DMRDMORX_H) +#define DMRDMORX_H + +#include "Config.h" +#include "DMRDefines.h" + +const uint16_t DMO_BUFFER_SIZE = 1440U; // 60ms at 24 kHz + +enum DMORX_STATE { + DMORXS_NONE, + DMORXS_VOICE, + DMORXS_DATA +}; + +class CDMRDMORX { +public: + CDMRDMORX(); + + void start(); + + void samples(const q15_t* samples, uint8_t length); + + void setColorCode(uint8_t colorCode); + + void reset(); + +private: + uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; + q15_t m_buffer[DMO_BUFFER_SIZE]; + uint16_t m_bitPtr; + uint16_t m_dataPtr; + uint16_t m_syncPtr; + uint16_t m_startPtr; + uint16_t m_endPtr; + 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; + DMORX_STATE m_state; + uint8_t m_n; + uint8_t m_type; + uint16_t m_rssiCount; + uint16_t m_rssi; + + bool processSample(q15_t sample); + void correlateSync(bool first); + void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); +}; + +#endif + diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index ac5df61..3ba6830 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -48,7 +48,9 @@ m_modFilter(), m_modState(), m_poBuffer(), m_poLen(0U), -m_poPtr(0U) +m_poPtr(0U), +m_txDelay(240U), // 200ms +m_count(0U) { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -57,16 +59,20 @@ m_poPtr(0U) m_modFilter.pCoeffs = DMR_C4FSK_FILTER; } -void CDMRTX::process() +void CDMRDMOTX::process() { if (m_poLen == 0U && m_fifo.getData() > 0U) { - for (unsigned int i = 0U; i < 72U; i++) - m_poBuffer[i] = 0x00U; + if (!m_tx) { + for (uint16_t i = 0U; i < m_txDelay; i++) + m_poBuffer[m_poLen++] = 0x00U; + } else { + for (unsigned int i = 0U; i < 72U; i++) + m_poBuffer[m_poLen++] = 0x00U; - for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i] = m_fifo.get(); + for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_poBuffer[i] = m_fifo.get(); + } - m_poLen = 72U; m_poPtr = 0U; } @@ -89,7 +95,7 @@ void CDMRTX::process() } } -uint8_t CDMRTX::writeData(const uint8_t* data, uint8_t length) +uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length) { if (length != (DMR_FRAME_LENGTH_BYTES + 1U)) return 4U; @@ -104,7 +110,7 @@ uint8_t CDMRTX::writeData(const uint8_t* data, uint8_t length) return 0U; } -void CDMRTX::writeByte(uint8_t c) +void CDMRDMOTX::writeByte(uint8_t c) { q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U + 1U]; q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U + 1U]; @@ -152,8 +158,13 @@ void CDMRTX::writeByte(uint8_t c) io.write(STATE_DMR, outBuffer, blockSize); } -uint16_t CDMRTX::getSpace() const +uint16_t CDMRDMOTX::getSpace() const { return m_fifo.getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U); } +void CDMRDMOTX::setTXDelay(uint8_t delay) +{ + m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay +} + diff --git a/DMRDMOTX.h b/DMRDMOTX.h index a081f22..3650d0d 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -33,6 +33,8 @@ public: void process(); + void setTXDelay(uint8_t delay); + uint16_t getSpace() const; private: @@ -42,6 +44,8 @@ private: uint8_t m_poBuffer[80U]; uint16_t m_poLen; uint16_t m_poPtr; + uint16_t m_txDelay; + uint32_t m_count; void writeByte(uint8_t c); }; diff --git a/DMRDefines.h b/DMRDefines.h index 23de540..9379ec3 100644 --- a/DMRDefines.h +++ b/DMRDefines.h @@ -57,18 +57,30 @@ const uint8_t DMR_MS_DATA_SYNC_BYTES[] = {0x0DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0 const uint8_t DMR_MS_VOICE_SYNC_BYTES[] = {0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U}; const uint8_t DMR_BS_DATA_SYNC_BYTES[] = {0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U}; const uint8_t DMR_BS_VOICE_SYNC_BYTES[] = {0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U}; +const uint8_t DMR_S1_DATA_SYNC_BYTES[] = {0x0FU, 0x7FU, 0xDDU, 0x5DU, 0xDFU, 0xD5U, 0x50U}; +const uint8_t DMR_S1_VOICE_SYNC_BYTES[] = {0x05U, 0xD5U, 0x77U, 0xF7U, 0x75U, 0x7FU, 0xF0U}; +const uint8_t DMR_S2_DATA_SYNC_BYTES[] = {0x0DU, 0x75U, 0x57U, 0xF5U, 0xFFU, 0x7FU, 0x50U}; +const uint8_t DMR_S2_VOICE_SYNC_BYTES[] = {0x07U, 0xDFU, 0xFDU, 0x5FU, 0x55U, 0xD5U, 0xF0U}; const uint8_t DMR_SYNC_BYTES_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U}; const uint64_t DMR_MS_DATA_SYNC_BITS = 0x0000D5D7F77FD757U; const uint64_t DMR_MS_VOICE_SYNC_BITS = 0x00007F7D5DD57DFDU; const uint64_t DMR_BS_DATA_SYNC_BITS = 0x0000DFF57D75DF5DU; const uint64_t DMR_BS_VOICE_SYNC_BITS = 0x0000755FD7DF75F7U; +const uint64_t DMR_S1_DATA_SYNC_BITS = 0x0000F7FDD5DDFD55U; +const uint64_t DMR_S1_VOICE_SYNC_BITS = 0x00005D577F7757FFU; +const uint64_t DMR_S2_DATA_SYNC_BITS = 0x0000D7557F5FF7F5U; +const uint64_t DMR_S2_VOICE_SYNC_BITS = 0x00007DFFD5F55D5FU; const uint64_t DMR_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU; const uint32_t DMR_MS_DATA_SYNC_SYMBOLS = 0x0076286EU; const uint32_t DMR_MS_VOICE_SYNC_SYMBOLS = 0x0089D791U; const uint32_t DMR_BS_DATA_SYNC_SYMBOLS = 0x00439B4DU; const uint32_t DMR_BS_VOICE_SYNC_SYMBOLS = 0x00BC64B2U; +const uint32_t DMR_S1_DATA_SYNC_SYMBOLS = 0x0021751FU; +const uint32_t DMR_S1_VOICE_SYNC_SYMBOLS = 0x00DE8AE0U; +const uint32_t DMR_S2_DATA_SYNC_SYMBOLS = 0x006F8C23U; +const uint32_t DMR_S2_VOICE_SYNC_SYMBOLS = 0x009073DCU; const uint32_t DMR_SYNC_SYMBOLS_MASK = 0x00FFFFFFU; const uint8_t DT_VOICE_PI_HEADER = 0U; diff --git a/IO.cpp b/IO.cpp index 46a4dd0..696a823 100644 --- a/IO.cpp +++ b/IO.cpp @@ -387,7 +387,7 @@ void CIO::process() else dmrIdleRX.samples(C4FSKVals, blockSize); } else { - dmrDMORX.samples(c4FSKVals, blockSize); + dmrDMORX.samples(C4FSKVals, blockSize); } } } else if (m_modemState == STATE_YSF) { diff --git a/SerialPort.cpp b/SerialPort.cpp index 4983c5b..f8ead0a 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -153,7 +153,7 @@ void CSerialPort::getStatus() reply[7U] = dmrTX.getSpace1(); reply[8U] = dmrTX.getSpace2(); } else { - reply[7U] = 0U; + reply[7U] = 10U; reply[8U] = dmrDMOTX.getSpace(); } } else { @@ -196,7 +196,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) bool rxInvert = (data[0U] & 0x01U) == 0x01U; bool txInvert = (data[0U] & 0x02U) == 0x02U; bool pttInvert = (data[0U] & 0x04U) == 0x04U; - bool duplex = (data[0U] & 0x80U) == 0x80U; + bool simplex = (data[0U] & 0x80U) == 0x80U; bool dstarEnable = (data[1U] & 0x01U) == 0x01U; bool dmrEnable = (data[1U] & 0x02U) == 0x02U; @@ -246,10 +246,11 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) m_dstarEnable = dstarEnable; m_dmrEnable = dmrEnable; m_ysfEnable = ysfEnable; - m_duplex = duplex; + m_duplex = !simplex; dstarTX.setTXDelay(txDelay); ysfTX.setTXDelay(txDelay); + dmrDMOTX.setTXDelay(txDelay); dmrTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); @@ -300,6 +301,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) case STATE_DSTAR: DEBUG1("Mode set to D-Star"); dmrIdleRX.reset(); + dmrDMORX.reset(); dmrRX.reset(); ysfRX.reset(); cwIdTX.reset(); @@ -307,6 +309,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) case STATE_YSF: DEBUG1("Mode set to System Fusion"); dmrIdleRX.reset(); + dmrDMORX.reset(); dmrRX.reset(); dstarRX.reset(); cwIdTX.reset(); @@ -314,6 +317,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) case STATE_DSTARCAL: DEBUG1("Mode set to D-Star Calibrate"); dmrIdleRX.reset(); + dmrDMORX.reset(); dmrRX.reset(); dstarRX.reset(); ysfRX.reset(); @@ -322,6 +326,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) case STATE_DMRCAL: DEBUG1("Mode set to DMR Calibrate"); dmrIdleRX.reset(); + dmrDMORX.reset(); dmrRX.reset(); dstarRX.reset(); ysfRX.reset();