From 8c970b26db1bf98c3a9496be98b78ab8fde7c225 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Mar 2017 20:36:44 +0000 Subject: [PATCH 01/33] Change size of space in transmit routines. --- DMRDMOTX.cpp | 4 ++-- DMRDMOTX.h | 4 ++-- DMRTX.cpp | 6 +++--- DMRTX.h | 6 +++--- DStarTX.cpp | 2 +- DStarTX.h | 2 +- P25TX.cpp | 4 ++-- P25TX.h | 2 +- YSFTX.cpp | 4 ++-- YSFTX.h | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 3ba6830..5068f0a 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -158,7 +158,7 @@ void CDMRDMOTX::writeByte(uint8_t c) io.write(STATE_DMR, outBuffer, blockSize); } -uint16_t CDMRDMOTX::getSpace() const +uint8_t CDMRDMOTX::getSpace() const { return m_fifo.getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U); } diff --git a/DMRDMOTX.h b/DMRDMOTX.h index d904ca6..9afafde 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -35,7 +35,7 @@ public: void setTXDelay(uint8_t delay); - uint16_t getSpace() const; + uint8_t getSpace() const; private: CSerialRB m_fifo; diff --git a/DMRTX.cpp b/DMRTX.cpp index 684f659..68ef0c3 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -301,12 +301,12 @@ void CDMRTX::writeByte(uint8_t c, uint8_t control) io.write(STATE_DMR, outBuffer, blockSize, controlBuffer); } -uint16_t CDMRTX::getSpace1() const +uint8_t CDMRTX::getSpace1() const { return m_fifo[0U].getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U); } -uint16_t CDMRTX::getSpace2() const +uint8_t CDMRTX::getSpace2() const { return m_fifo[1U].getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U); } diff --git a/DMRTX.h b/DMRTX.h index 599b8fe..7dce628 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -49,8 +49,8 @@ public: void process(); - uint16_t getSpace1() const; - uint16_t getSpace2() const; + uint8_t getSpace1() const; + uint8_t getSpace2() const; void setColorCode(uint8_t colorCode); diff --git a/DStarTX.cpp b/DStarTX.cpp index 3e08aa9..d9170e3 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -460,7 +460,7 @@ void CDStarTX::setTXDelay(uint8_t delay) m_txDelay = 300U + uint16_t(delay) * 6U; // 250ms + tx delay } -uint16_t CDStarTX::getSpace() const +uint8_t CDStarTX::getSpace() const { return m_buffer.getSpace() / (DSTAR_DATA_LENGTH_BYTES + 1U); } diff --git a/DStarTX.h b/DStarTX.h index 24bb7af..aaecadf 100644 --- a/DStarTX.h +++ b/DStarTX.h @@ -35,7 +35,7 @@ public: void setTXDelay(uint8_t delay); - uint16_t getSpace() const; + uint8_t getSpace() const; private: CSerialRB m_buffer; diff --git a/P25TX.cpp b/P25TX.cpp index 909fb56..3f6e1fa 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017 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 @@ -189,7 +189,7 @@ void CP25TX::setTXDelay(uint8_t delay) m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay } -uint16_t CP25TX::getSpace() const +uint8_t CP25TX::getSpace() const { return m_buffer.getSpace() / P25_LDU_FRAME_LENGTH_BYTES; } diff --git a/P25TX.h b/P25TX.h index 4340d35..3a10776 100644 --- a/P25TX.h +++ b/P25TX.h @@ -33,7 +33,7 @@ public: void setTXDelay(uint8_t delay); - uint16_t getSpace() const; + uint8_t getSpace() const; private: CSerialRB m_buffer; diff --git a/YSFTX.cpp b/YSFTX.cpp index d3e20a3..47db1a8 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017 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 @@ -169,7 +169,7 @@ void CYSFTX::setTXDelay(uint8_t delay) m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay } -uint16_t CYSFTX::getSpace() const +uint8_t CYSFTX::getSpace() const { return m_buffer.getSpace() / YSF_FRAME_LENGTH_BYTES; } diff --git a/YSFTX.h b/YSFTX.h index 21fcabc..a7f7c55 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -33,7 +33,7 @@ public: void setTXDelay(uint8_t delay); - uint16_t getSpace() const; + uint8_t getSpace() const; private: CSerialRB m_buffer; From a9b761d1dc2538812e61dda1273d3f656905c14f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Mar 2017 20:42:37 +0000 Subject: [PATCH 02/33] Change the P25 TX and RX filters and add a DMR TX data holdoff counter. --- DMRTX.cpp | 13 +++++++++++-- DMRTX.h | 1 + IO.cpp | 30 +++++++++++++++++++++++------- IO.h | 2 ++ P25TX.cpp | 16 +++++++--------- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/DMRTX.cpp b/DMRTX.cpp index 68ef0c3..a8df799 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -61,6 +61,8 @@ 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 READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) +const uint32_t STARTUP_COUNT = 20U; + CDMRTX::CDMRTX() : m_fifo(), m_modFilter(), @@ -75,6 +77,7 @@ m_poBuffer(), m_poLen(0U), m_poPtr(0U), m_count(0U), +m_frameCount(0U), m_abort() { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -233,6 +236,8 @@ void CDMRTX::setStart(bool start) m_count = 0U; + m_frameCount = 0U; + m_abort[0U] = false; m_abort[1U] = false; } @@ -313,7 +318,7 @@ uint8_t CDMRTX::getSpace2() const void CDMRTX::createData(uint8_t slotIndex) { - if (m_fifo[slotIndex].getData()> 0U) { + if (m_fifo[slotIndex].getData() > 0U && m_frameCount >= STARTUP_COUNT) { for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) { m_poBuffer[i] = m_fifo[slotIndex].get(); m_markBuffer[i] = MARK_NONE; @@ -344,6 +349,8 @@ void CDMRTX::createCal() void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex) { + m_frameCount++; + if (m_cachPtr >= 12U) m_cachPtr = 0U; @@ -359,7 +366,9 @@ void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex) m_markBuffer[1U] = MARK_NONE; m_markBuffer[2U] = rxSlotIndex == 1U ? MARK_SLOT1 : MARK_SLOT2; - bool at = m_fifo[rxSlotIndex].getData() > 0U; + bool at = false; + if (m_frameCount >= STARTUP_COUNT) + m_fifo[rxSlotIndex].getData() > 0U; bool tc = txSlotIndex == 1U; bool ls0 = true; // For 1 and 2 bool ls1 = true; diff --git a/DMRTX.h b/DMRTX.h index 7dce628..1c0b076 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -68,6 +68,7 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint32_t m_count; + uint32_t m_frameCount; bool m_abort[2U]; void createData(uint8_t slotIndex); diff --git a/IO.cpp b/IO.cpp index 61f4bd8..ca098de 100644 --- a/IO.cpp +++ b/IO.cpp @@ -41,6 +41,10 @@ const uint16_t C4FSK_FILTER_LEN = 42U; static q15_t GMSK_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0}; const uint16_t GMSK_FILTER_LEN = 12U; +// One symbol boxcar filter +static q15_t P25_FILTER[] = {3000, 3000, 3000, 3000, 3000, 0}; +const uint16_t P25_FILTER_LEN = 6U; + const uint16_t DC_OFFSET = 2048U; CIO::CIO() : @@ -50,8 +54,10 @@ m_txBuffer(TX_RINGBUFFER_SIZE), m_rssiBuffer(RX_RINGBUFFER_SIZE), m_C4FSKFilter(), m_GMSKFilter(), +m_P25Filter(), m_C4FSKState(), m_GMSKState(), +m_P25State(), m_pttInvert(false), m_rxLevel(128 * 128), m_cwIdTXLevel(128 * 128), @@ -70,6 +76,7 @@ m_lockout(false) { ::memset(m_C4FSKState, 0x00U, 70U * sizeof(q15_t)); ::memset(m_GMSKState, 0x00U, 40U * sizeof(q15_t)); + ::memset(m_P25State, 0x00U, 30U * sizeof(q15_t)); m_C4FSKFilter.numTaps = C4FSK_FILTER_LEN; m_C4FSKFilter.pState = m_C4FSKState; @@ -79,6 +86,10 @@ m_lockout(false) m_GMSKFilter.pState = m_GMSKState; m_GMSKFilter.pCoeffs = GMSK_FILTER; + m_P25Filter.numTaps = P25_FILTER_LEN; + m_P25Filter.pState = m_P25State; + m_P25Filter.pCoeffs = P25_FILTER; + initInt(); } @@ -187,7 +198,15 @@ void CIO::process() dstarRX.samples(GMSKVals, rssi, blockSize); } - if (m_dmrEnable || m_ysfEnable || m_p25Enable) { + + if (m_p25Enable) { + q15_t P25Vals[RX_BLOCK_SIZE + 1U]; + ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, blockSize); + + p25RX.samples(P25Vals, rssi, blockSize); + } + + if (m_dmrEnable || m_ysfEnable) { q15_t C4FSKVals[RX_BLOCK_SIZE + 1U]; ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, blockSize); @@ -200,9 +219,6 @@ void CIO::process() if (m_ysfEnable) ysfRX.samples(C4FSKVals, rssi, blockSize); - - if (m_p25Enable) - p25RX.samples(C4FSKVals, rssi, blockSize); } } else if (m_modemState == STATE_DSTAR) { if (m_dstarEnable) { @@ -235,10 +251,10 @@ void CIO::process() } } else if (m_modemState == STATE_P25) { if (m_p25Enable) { - q15_t C4FSKVals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, blockSize); + q15_t P25Vals[RX_BLOCK_SIZE + 1U]; + ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, blockSize); - p25RX.samples(C4FSKVals, rssi, blockSize); + p25RX.samples(P25Vals, rssi, blockSize); } } else if (m_modemState == STATE_DSTARCAL) { q15_t GMSKVals[RX_BLOCK_SIZE + 1U]; diff --git a/IO.h b/IO.h index d1ec266..59bd323 100644 --- a/IO.h +++ b/IO.h @@ -62,8 +62,10 @@ private: arm_fir_instance_q15 m_C4FSKFilter; arm_fir_instance_q15 m_GMSKFilter; + arm_fir_instance_q15 m_P25Filter; q15_t m_C4FSKState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare q15_t m_GMSKState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare + q15_t m_P25State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare bool m_pttInvert; q15_t m_rxLevel; diff --git a/P25TX.cpp b/P25TX.cpp index 3f6e1fa..4f053d9 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -25,16 +25,14 @@ #include "P25Defines.h" #if defined(WIDE_C4FSK_FILTERS_TX) -// Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t P25_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t P25_C4FSK_FILTER_LEN = 22U; +// Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB +static q15_t P25_C4FSK_FILTER[] = {-1393, -2602, -3044, -2238, 0, 3460, 7543, 11400, 14152, 15152, 14152, 11400, 7543, 3460, 0, -2238, -3044, -2602, -1393, 0}; +const uint16_t P25_C4FSK_FILTER_LEN = 20U; #else -// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t P25_C4FSK_FILTER[] = {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, 0}; -const uint16_t P25_C4FSK_FILTER_LEN = 42U; +// Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB +static q15_t P25_C4FSK_FILTER[] = {0, -413, -750, -845, -587, 0, 741, 1347, 1520, 1062, 0, -1383, -2582, -3021, -2222, 0, 3434, 7487, 11318, 14054, 15044, 14054, + 11318, 7487, 3434, 0, -2222, -3021, -2582, -1383, 0, 1062, 1520, 1347, 741, 0, -587, -845, -750, -413}; +const uint16_t P25_C4FSK_FILTER_LEN = 40U; #endif // Generated in MATLAB using the following commands, and then normalised for unity gain From df1210eaeaf7f9ce33dfbfba8fa273a45a9ed92f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 7 Mar 2017 20:41:54 +0000 Subject: [PATCH 03/33] Remove the OscOffset parameter. --- DMRDMOTX.cpp | 29 +++------------- DMRDMOTX.h | 1 - DMRTX.cpp | 38 +++------------------ DMRTX.h | 1 - DStarTX.cpp | 34 +++---------------- DStarTX.h | 1 - Globals.h | 3 -- IO.cpp | 89 ++++++++++++++++++-------------------------------- IO.h | 2 -- MMDVM.cpp | 5 +-- MMDVM.ino | 5 +-- P25TX.cpp | 35 ++++---------------- P25TX.h | 1 - SerialPort.cpp | 12 ------- YSFTX.cpp | 31 +++--------------- YSFTX.h | 1 - 16 files changed, 61 insertions(+), 227 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 5068f0a..d7aa0f0 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -49,8 +49,7 @@ m_modState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(240U), // 200ms -m_count(0U) +m_txDelay(240U) // 200ms { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -112,8 +111,8 @@ uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length) void CDMRDMOTX::writeByte(uint8_t c) { - q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U + 1U]; - q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U + 1U]; + q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; + q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; @@ -135,27 +134,9 @@ void CDMRDMOTX::writeByte(uint8_t c) } } - uint16_t blockSize = DMR_RADIO_SYMBOL_LENGTH * 4U; + ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); - // Handle the case of the oscillator not being accurate enough - if (m_sampleCount > 0U) { - m_count += DMR_RADIO_SYMBOL_LENGTH * 4U; - - if (m_count >= m_sampleCount) { - if (m_sampleInsert) { - inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U] = inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U - 1U]; - blockSize++; - } else { - blockSize--; - } - - m_count -= m_sampleCount; - } - } - - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, blockSize); - - io.write(STATE_DMR, outBuffer, blockSize); + io.write(STATE_DMR, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); } uint8_t CDMRDMOTX::getSpace() const diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 9afafde..d88b4d5 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -45,7 +45,6 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint16_t m_txDelay; - uint32_t m_count; void writeByte(uint8_t c); }; diff --git a/DMRTX.cpp b/DMRTX.cpp index a8df799..f42aba9 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -76,7 +76,6 @@ m_markBuffer(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_count(0U), m_frameCount(0U), m_abort() { @@ -234,8 +233,6 @@ void CDMRTX::setStart(bool start) { m_state = start ? DMRTXSTATE_SLOT1 : DMRTXSTATE_IDLE; - m_count = 0U; - m_frameCount = 0U; m_abort[0U] = false; @@ -245,14 +242,12 @@ void CDMRTX::setStart(bool start) void CDMRTX::setCal(bool start) { m_state = start ? DMRTXSTATE_CAL : DMRTXSTATE_IDLE; - - m_count = 0U; } void CDMRTX::writeByte(uint8_t c, uint8_t control) { - q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U + 1U]; - q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U + 1U]; + q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; + q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; @@ -274,36 +269,13 @@ void CDMRTX::writeByte(uint8_t c, uint8_t control) } } - uint16_t blockSize = DMR_RADIO_SYMBOL_LENGTH * 4U; - - uint8_t controlBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U + 1U]; + 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; - // Handle the case of the oscillator not being accurate enough - if (m_sampleCount > 0U) { - m_count += DMR_RADIO_SYMBOL_LENGTH * 4U; + ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); - if (m_count >= m_sampleCount) { - if (m_sampleInsert) { - inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U] = inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U - 1U]; - for (int8_t i = DMR_RADIO_SYMBOL_LENGTH * 4U - 1; i >= 0; i--) - controlBuffer[i + 1] = controlBuffer[i]; - blockSize++; - } else { - controlBuffer[DMR_RADIO_SYMBOL_LENGTH * 2U - 1U] = control; - for (uint8_t i = 0U; i < (DMR_RADIO_SYMBOL_LENGTH * 4U - 1U); i++) - controlBuffer[i] = controlBuffer[i + 1U]; - blockSize--; - } - - m_count -= m_sampleCount; - } - } - - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, blockSize); - - io.write(STATE_DMR, outBuffer, blockSize, controlBuffer); + io.write(STATE_DMR, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U, controlBuffer); } uint8_t CDMRTX::getSpace1() const diff --git a/DMRTX.h b/DMRTX.h index 1c0b076..69cf06a 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -67,7 +67,6 @@ private: uint8_t m_poBuffer[40U]; uint16_t m_poLen; uint16_t m_poPtr; - uint32_t m_count; uint32_t m_frameCount; bool m_abort[2U]; diff --git a/DStarTX.cpp b/DStarTX.cpp index d9170e3..b4c89e5 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -195,8 +195,7 @@ m_modState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(60U), // 100ms -m_count(0U) +m_txDelay(60U) // 100ms { ::memset(m_modState, 0x00U, 60U * sizeof(q15_t)); @@ -214,8 +213,6 @@ void CDStarTX::process() if (type == DSTAR_HEADER && m_poLen == 0U) { if (!m_tx) { - m_count = 0U; - for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = BIT_SYNC; } else { @@ -241,9 +238,6 @@ void CDStarTX::process() } if (type == DSTAR_DATA && m_poLen == 0U) { - if (!m_tx) - m_count = 0U; - // Pop the type byte off m_buffer.get(); @@ -417,8 +411,8 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const void CDStarTX::writeByte(uint8_t c) { - q15_t inBuffer[DSTAR_RADIO_BIT_LENGTH * 8U + 1U]; - q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U + 1U]; + q15_t inBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; + q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; uint8_t mask = 0x01U; @@ -432,27 +426,9 @@ void CDStarTX::writeByte(uint8_t c) mask <<= 1; } - uint16_t blockSize = DSTAR_RADIO_BIT_LENGTH * 8U; + ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); - // Handle the case of the oscillator not being accurate enough - if (m_sampleCount > 0U) { - m_count += DSTAR_RADIO_BIT_LENGTH * 8U; - - if (m_count >= m_sampleCount) { - if (m_sampleInsert) { - inBuffer[DSTAR_RADIO_BIT_LENGTH * 8U] = inBuffer[DSTAR_RADIO_BIT_LENGTH * 8U - 1U]; - blockSize++; - } else { - blockSize--; - } - - m_count -= m_sampleCount; - } - } - - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, blockSize); - - io.write(STATE_DSTAR, outBuffer, blockSize); + io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); } void CDStarTX::setTXDelay(uint8_t delay) diff --git a/DStarTX.h b/DStarTX.h index aaecadf..17855f8 100644 --- a/DStarTX.h +++ b/DStarTX.h @@ -45,7 +45,6 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint16_t m_txDelay; // In bytes - uint32_t m_count; void txHeader(const uint8_t* in, uint8_t* out) const; void writeByte(uint8_t c); diff --git a/Globals.h b/Globals.h index d3bde54..a0f0676 100644 --- a/Globals.h +++ b/Globals.h @@ -90,9 +90,6 @@ extern bool m_duplex; extern bool m_tx; extern bool m_dcd; -extern uint32_t m_sampleCount; -extern bool m_sampleInsert; - extern CSerialPort serial; extern CIO io; diff --git a/IO.cpp b/IO.cpp index ca098de..22163d9 100644 --- a/IO.cpp +++ b/IO.cpp @@ -70,7 +70,6 @@ m_ledValue(true), m_detect(false), m_adcOverflow(0U), m_dacOverflow(0U), -m_count(0U), m_watchdog(0U), m_lockout(false) { @@ -100,7 +99,6 @@ void CIO::start() startInt(); - m_count = 0U; m_started = true; setMode(); @@ -147,11 +145,9 @@ void CIO::process() } if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) { - q15_t samples[RX_BLOCK_SIZE + 1U]; - uint8_t control[RX_BLOCK_SIZE + 1U]; - uint16_t rssi[RX_BLOCK_SIZE + 1U]; - - uint8_t blockSize = RX_BLOCK_SIZE; + q15_t samples[RX_BLOCK_SIZE]; + uint8_t control[RX_BLOCK_SIZE]; + uint16_t rssi[RX_BLOCK_SIZE]; for (uint16_t i = 0U; i < RX_BLOCK_SIZE; i++) { uint16_t sample; @@ -167,102 +163,81 @@ void CIO::process() samples[i] = q15_t(__SSAT((res2 >> 15), 16)); } - // Handle the case of the oscillator not being accurate enough - if (m_sampleCount > 0U) { - m_count += RX_BLOCK_SIZE; - - if (m_count >= m_sampleCount) { - if (m_sampleInsert) { - blockSize++; - samples[RX_BLOCK_SIZE] = 0; - for (int8_t i = RX_BLOCK_SIZE - 1; i >= 0; i--) - control[i + 1] = control[i]; - } else { - blockSize--; - for (uint8_t i = 0U; i < (RX_BLOCK_SIZE - 1U); i++) - control[i] = control[i + 1U]; - } - - m_count -= m_sampleCount; - } - } - if (m_lockout) return; if (m_modemState == STATE_IDLE) { if (m_dstarEnable) { - q15_t GMSKVals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, blockSize); + q15_t GMSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, RX_BLOCK_SIZE); - dstarRX.samples(GMSKVals, rssi, blockSize); + dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE); } - if (m_p25Enable) { - q15_t P25Vals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, blockSize); + q15_t P25Vals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, RX_BLOCK_SIZE); - p25RX.samples(P25Vals, rssi, blockSize); + p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE); } if (m_dmrEnable || m_ysfEnable) { - q15_t C4FSKVals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, blockSize); + q15_t C4FSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); if (m_dmrEnable) { if (m_duplex) - dmrIdleRX.samples(C4FSKVals, blockSize); + dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE); else - dmrDMORX.samples(C4FSKVals, rssi, blockSize); + dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); } if (m_ysfEnable) - ysfRX.samples(C4FSKVals, rssi, blockSize); + ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_DSTAR) { if (m_dstarEnable) { - q15_t GMSKVals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, blockSize); + q15_t GMSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, RX_BLOCK_SIZE); - dstarRX.samples(GMSKVals, rssi, blockSize); + dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_DMR) { if (m_dmrEnable) { - q15_t C4FSKVals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, blockSize); + q15_t C4FSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); if (m_duplex) { // If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs if (m_tx) - dmrRX.samples(C4FSKVals, rssi, control, blockSize); + dmrRX.samples(C4FSKVals, rssi, control, RX_BLOCK_SIZE); else - dmrIdleRX.samples(C4FSKVals, blockSize); + dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE); } else { - dmrDMORX.samples(C4FSKVals, rssi, blockSize); + dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); } } } else if (m_modemState == STATE_YSF) { if (m_ysfEnable) { - q15_t C4FSKVals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, blockSize); + q15_t C4FSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); - ysfRX.samples(C4FSKVals, rssi, blockSize); + ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_P25) { if (m_p25Enable) { - q15_t P25Vals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, blockSize); + q15_t P25Vals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, RX_BLOCK_SIZE); - p25RX.samples(P25Vals, rssi, blockSize); + p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_DSTARCAL) { - q15_t GMSKVals[RX_BLOCK_SIZE + 1U]; - ::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, blockSize); + q15_t GMSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, RX_BLOCK_SIZE); - calDStarRX.samples(GMSKVals, blockSize); + calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE); } else if (m_modemState == STATE_RSSICAL) { - calRSSI.samples(rssi, blockSize); + calRSSI.samples(rssi, RX_BLOCK_SIZE); } } } diff --git a/IO.h b/IO.h index 59bd323..25559c7 100644 --- a/IO.h +++ b/IO.h @@ -83,8 +83,6 @@ private: uint16_t m_adcOverflow; uint16_t m_dacOverflow; - uint32_t m_count; - volatile uint32_t m_watchdog; bool m_lockout; diff --git a/MMDVM.cpp b/MMDVM.cpp index 85b74e0..9cf9d4d 100644 --- a/MMDVM.cpp +++ b/MMDVM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Mathis Schmieder DB9MAT * Copyright (C) 2016 by Colin Durbridge G4EML * @@ -36,9 +36,6 @@ bool m_duplex = true; bool m_tx = false; bool m_dcd = false; -uint32_t m_sampleCount = 0U; -bool m_sampleInsert = false; - CDStarRX dstarRX; CDStarTX dstarTX; diff --git a/MMDVM.ino b/MMDVM.ino index c370a2f..0aaedb4 100644 --- a/MMDVM.ino +++ b/MMDVM.ino @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -33,9 +33,6 @@ bool m_duplex = true; bool m_tx = false; bool m_dcd = false; -uint32_t m_sampleCount = 0U; -bool m_sampleInsert = false; - CDStarRX dstarRX; CDStarTX dstarTX; diff --git a/P25TX.cpp b/P25TX.cpp index 4f053d9..0acc5da 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -60,8 +60,7 @@ m_lpState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(240U), // 200ms -m_count(0U) +m_txDelay(240U) // 200ms { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); ::memset(m_lpState, 0x00U, 70U * sizeof(q15_t)); @@ -82,8 +81,6 @@ void CP25TX::process() if (m_poLen == 0U) { if (!m_tx) { - m_count = 0U; - for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = P25_START_SYNC; } else { @@ -133,9 +130,9 @@ uint8_t CP25TX::writeData(const uint8_t* data, uint8_t length) void CP25TX::writeByte(uint8_t c) { - q15_t inBuffer[P25_RADIO_SYMBOL_LENGTH * 4U + 1U]; - q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U + 1U]; - q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U + 1U]; + q15_t inBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; + q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; + q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; @@ -157,29 +154,11 @@ void CP25TX::writeByte(uint8_t c) } } - uint16_t blockSize = P25_RADIO_SYMBOL_LENGTH * 4U; + ::arm_fir_fast_q15(&m_modFilter, inBuffer, intBuffer, P25_RADIO_SYMBOL_LENGTH * 4U); - // Handle the case of the oscillator not being accurate enough - if (m_sampleCount > 0U) { - m_count += P25_RADIO_SYMBOL_LENGTH * 4U; + ::arm_fir_fast_q15(&m_lpFilter, intBuffer, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U); - if (m_count >= m_sampleCount) { - if (m_sampleInsert) { - inBuffer[P25_RADIO_SYMBOL_LENGTH * 4U] = inBuffer[P25_RADIO_SYMBOL_LENGTH * 4U - 1U]; - blockSize++; - } else { - blockSize--; - } - - m_count -= m_sampleCount; - } - } - - ::arm_fir_fast_q15(&m_modFilter, inBuffer, intBuffer, blockSize); - - ::arm_fir_fast_q15(&m_lpFilter, intBuffer, outBuffer, blockSize); - - io.write(STATE_P25, outBuffer, blockSize); + io.write(STATE_P25, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U); } void CP25TX::setTXDelay(uint8_t delay) diff --git a/P25TX.h b/P25TX.h index 3a10776..99db19d 100644 --- a/P25TX.h +++ b/P25TX.h @@ -45,7 +45,6 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint16_t m_txDelay; - uint32_t m_count; void writeByte(uint8_t c); }; diff --git a/SerialPort.cpp b/SerialPort.cpp index b3a4654..fd981af 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -248,18 +248,6 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) uint8_t dmrDelay = data[7U]; - int8_t oscOffset = int8_t(data[8U]) - 128; - if (oscOffset < 0) { - m_sampleCount = 1000000U / uint32_t(-oscOffset); - m_sampleInsert = false; - } else if (oscOffset > 0) { - m_sampleCount = 1000000U / uint32_t(oscOffset); - m_sampleInsert = true; - } else { - m_sampleCount = 0U; - m_sampleInsert = false; - } - uint8_t cwIdTXLevel = data[5U]; uint8_t dstarTXLevel = data[9U]; uint8_t dmrTXLevel = data[10U]; diff --git a/YSFTX.cpp b/YSFTX.cpp index 47db1a8..fcdcb87 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -52,8 +52,7 @@ m_modState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(240U), // 200ms -m_count(0U) +m_txDelay(240U) // 200ms { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -69,8 +68,6 @@ void CYSFTX::process() if (m_poLen == 0U) { if (!m_tx) { - m_count = 0U; - for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = YSF_START_SYNC; } else { @@ -118,8 +115,8 @@ uint8_t CYSFTX::writeData(const uint8_t* data, uint8_t length) void CYSFTX::writeByte(uint8_t c) { - q15_t inBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U + 1U]; - q15_t outBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U + 1U]; + q15_t inBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U]; + q15_t outBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; @@ -141,27 +138,9 @@ void CYSFTX::writeByte(uint8_t c) } } - uint16_t blockSize = YSF_RADIO_SYMBOL_LENGTH * 4U; + ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); - // Handle the case of the oscillator not being accurate enough - if (m_sampleCount > 0U) { - m_count += YSF_RADIO_SYMBOL_LENGTH * 4U; - - if (m_count >= m_sampleCount) { - if (m_sampleInsert) { - inBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U] = inBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U - 1U]; - blockSize++; - } else { - blockSize--; - } - - m_count -= m_sampleCount; - } - } - - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, blockSize); - - io.write(STATE_YSF, outBuffer, blockSize); + io.write(STATE_YSF, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); } void CYSFTX::setTXDelay(uint8_t delay) diff --git a/YSFTX.h b/YSFTX.h index a7f7c55..b51d5b7 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -43,7 +43,6 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint16_t m_txDelay; - uint32_t m_count; void writeByte(uint8_t c); }; From 9110f5404f964706635ba36201a6ebea921e2bbc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 7 Mar 2017 20:44:41 +0000 Subject: [PATCH 04/33] Add the Raised Cosine filter to P25 RX and change YSF to use the Raised Cosine filter on RX also. --- IO.cpp | 93 ++++++++++++++++++++++++++++++++++++---------------------- IO.h | 6 ++-- 2 files changed, 62 insertions(+), 37 deletions(-) diff --git a/IO.cpp b/IO.cpp index 22163d9..448b836 100644 --- a/IO.cpp +++ b/IO.cpp @@ -26,15 +26,26 @@ #if defined(WIDE_C4FSK_FILTERS_RX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t C4FSK_FILTER_LEN = 22U; +static q15_t RRC_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, + 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; +const uint16_t RRC_FILTER_LEN = 22U; + +// Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB +static q15_t RC_FILTER[] = {-1393, -2602, -3044, -2238, 0, 3460, 7543, 11400, 14152, 15152, 14152, 11400, + 7543, 3460, 0, -2238, -3044, -2602, -1393, 0}; +const uint16_t RC_FILTER_LEN = 20U; #else // Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t C4FSK_FILTER[] = {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, 0}; -const uint16_t C4FSK_FILTER_LEN = 42U; +static q15_t RRC_FILTER[] = {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, 0}; +const uint16_t RRC_FILTER_LEN = 42U; + +// Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB +static q15_t RC_FILTER[] = {0, -413, -750, -845, -587, 0, 741, 1347, 1520, 1062, 0, -1383, -2582, -3021, -2222, 0, 3434, 7487, 11318, + 14054, 15044, 14054, 11318, 7487, 3434, 0, -2222, -3021, -2582, -1383, 0, 1062, 1520, 1347, 741, 0, -587, + -845, -750, -413}; +const uint16_t RC_FILTER_LEN = 40U; #endif // Generated using gaussfir(0.5, 4, 5) in MATLAB @@ -52,10 +63,12 @@ m_started(false), m_rxBuffer(RX_RINGBUFFER_SIZE), m_txBuffer(TX_RINGBUFFER_SIZE), m_rssiBuffer(RX_RINGBUFFER_SIZE), -m_C4FSKFilter(), +m_RRCFilter(), +m_RCFilter(), m_GMSKFilter(), m_P25Filter(), -m_C4FSKState(), +m_RRCState(), +m_RCState(), m_GMSKState(), m_P25State(), m_pttInvert(false), @@ -73,13 +86,18 @@ m_dacOverflow(0U), m_watchdog(0U), m_lockout(false) { - ::memset(m_C4FSKState, 0x00U, 70U * sizeof(q15_t)); - ::memset(m_GMSKState, 0x00U, 40U * sizeof(q15_t)); - ::memset(m_P25State, 0x00U, 30U * sizeof(q15_t)); + ::memset(m_RRCState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_RCState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_GMSKState, 0x00U, 40U * sizeof(q15_t)); + ::memset(m_P25State, 0x00U, 30U * sizeof(q15_t)); - m_C4FSKFilter.numTaps = C4FSK_FILTER_LEN; - m_C4FSKFilter.pState = m_C4FSKState; - m_C4FSKFilter.pCoeffs = C4FSK_FILTER; + m_RRCFilter.numTaps = RRC_FILTER_LEN; + m_RRCFilter.pState = m_RRCState; + m_RRCFilter.pCoeffs = RRC_FILTER; + + m_RCFilter.numTaps = RC_FILTER_LEN; + m_RCFilter.pState = m_RCState; + m_RCFilter.pCoeffs = RC_FILTER; m_GMSKFilter.numTaps = GMSK_FILTER_LEN; m_GMSKFilter.pState = m_GMSKState; @@ -178,22 +196,27 @@ void CIO::process() q15_t P25Vals[RX_BLOCK_SIZE]; ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, RX_BLOCK_SIZE); - p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE); + q15_t RCVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_RCFilter, P25Vals, RCVals, RX_BLOCK_SIZE); + + p25RX.samples(RCVals, rssi, RX_BLOCK_SIZE); } - if (m_dmrEnable || m_ysfEnable) { - q15_t C4FSKVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); + if (m_ysfEnable) { + q15_t RCVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_RCFilter, samples, RCVals, RX_BLOCK_SIZE); - if (m_dmrEnable) { - if (m_duplex) - dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE); - else - dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); - } + ysfRX.samples(RCVals, rssi, RX_BLOCK_SIZE); + } - if (m_ysfEnable) - ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); + if (m_dmrEnable) { + q15_t RRCVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_RRCFilter, samples, RRCVals, RX_BLOCK_SIZE); + + if (m_duplex) + dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE); + else + dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_DSTAR) { if (m_dstarEnable) { @@ -204,25 +227,25 @@ void CIO::process() } } else if (m_modemState == STATE_DMR) { if (m_dmrEnable) { - q15_t C4FSKVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); + q15_t RRCVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_RRCFilter, samples, RRCVals, RX_BLOCK_SIZE); if (m_duplex) { // If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs if (m_tx) - dmrRX.samples(C4FSKVals, rssi, control, RX_BLOCK_SIZE); + dmrRX.samples(RRCVals, rssi, control, RX_BLOCK_SIZE); else - dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE); + dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE); } else { - dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); + dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE); } } } else if (m_modemState == STATE_YSF) { if (m_ysfEnable) { - q15_t C4FSKVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); + q15_t RCVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_RCFilter, samples, RCVals, RX_BLOCK_SIZE); - ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); + ysfRX.samples(RCVals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_P25) { if (m_p25Enable) { diff --git a/IO.h b/IO.h index 25559c7..97abf2c 100644 --- a/IO.h +++ b/IO.h @@ -60,10 +60,12 @@ private: CSampleRB m_txBuffer; CRSSIRB m_rssiBuffer; - arm_fir_instance_q15 m_C4FSKFilter; + arm_fir_instance_q15 m_RRCFilter; + arm_fir_instance_q15 m_RCFilter; arm_fir_instance_q15 m_GMSKFilter; arm_fir_instance_q15 m_P25Filter; - q15_t m_C4FSKState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare + q15_t m_RRCState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare + q15_t m_RCState[70U]; // NoTaps + BlockSize - 1, 40 + 20 - 1 plus some spare q15_t m_GMSKState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare q15_t m_P25State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare From 90111dc43dc5b7e6c7c90d283383b4372a7674a0 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 7 Mar 2017 20:48:39 +0000 Subject: [PATCH 05/33] Use the Raised Cosine filter on YSF TX. --- YSFTX.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/YSFTX.cpp b/YSFTX.cpp index fcdcb87..7036450 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -25,16 +25,16 @@ #include "YSFDefines.h" #if defined(WIDE_C4FSK_FILTERS_TX) -// Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 22U; +// Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB +static q15_t YSF_C4FSK_FILTER[] = {-1393, -2602, -3044, -2238, 0, 3460, 7543, 11400, 14152, 15152, 14152, 11400, + 7543, 3460, 0, -2238, -3044, -2602, -1393, 0}; +const uint16_t YSF_C4FSK_FILTER_LEN = 20U; #else -// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {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, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 42U; +// Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB +static q15_t YSF_C4FSK_FILTER[] = {0, -413, -750, -845, -587, 0, 741, 1347, 1520, 1062, 0, -1383, -2582, -3021, -2222, 0, 3434, 7487, 11318, + 14054, 15044, 14054, 11318, 7487, 3434, 0, -2222, -3021, -2582, -1383, 0, 1062, 1520, 1347, 741, 0, -587, + -845, -750, -413}; +const uint16_t YSF_C4FSK_FILTER_LEN = 40U; #endif const q15_t YSF_LEVELA[] = { 809, 809, 809, 809, 809}; From bcbfb661312498e36c23d8125c9fae34c65d8209 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 10 Mar 2017 18:18:36 +0000 Subject: [PATCH 06/33] Roll back the YSF changes and simplify the P25 code. --- IO.cpp | 93 +++++++++++++++++++++---------------------------------- IO.h | 6 ++-- YSFTX.cpp | 18 +++++------ 3 files changed, 46 insertions(+), 71 deletions(-) diff --git a/IO.cpp b/IO.cpp index 448b836..af819d3 100644 --- a/IO.cpp +++ b/IO.cpp @@ -26,26 +26,15 @@ #if defined(WIDE_C4FSK_FILTERS_RX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t RRC_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t RRC_FILTER_LEN = 22U; - -// Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB -static q15_t RC_FILTER[] = {-1393, -2602, -3044, -2238, 0, 3460, 7543, 11400, 14152, 15152, 14152, 11400, - 7543, 3460, 0, -2238, -3044, -2602, -1393, 0}; -const uint16_t RC_FILTER_LEN = 20U; +static q15_t C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, + 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; +const uint16_t C4FSK_FILTER_LEN = 22U; #else // Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t RRC_FILTER[] = {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, 0}; -const uint16_t RRC_FILTER_LEN = 42U; - -// Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB -static q15_t RC_FILTER[] = {0, -413, -750, -845, -587, 0, 741, 1347, 1520, 1062, 0, -1383, -2582, -3021, -2222, 0, 3434, 7487, 11318, - 14054, 15044, 14054, 11318, 7487, 3434, 0, -2222, -3021, -2582, -1383, 0, 1062, 1520, 1347, 741, 0, -587, - -845, -750, -413}; -const uint16_t RC_FILTER_LEN = 40U; +static q15_t C4FSK_FILTER[] = {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, 0}; +const uint16_t C4FSK_FILTER_LEN = 42U; #endif // Generated using gaussfir(0.5, 4, 5) in MATLAB @@ -63,12 +52,10 @@ m_started(false), m_rxBuffer(RX_RINGBUFFER_SIZE), m_txBuffer(TX_RINGBUFFER_SIZE), m_rssiBuffer(RX_RINGBUFFER_SIZE), -m_RRCFilter(), -m_RCFilter(), +m_C4FSKFilter(), m_GMSKFilter(), m_P25Filter(), -m_RRCState(), -m_RCState(), +m_C4FSKState(), m_GMSKState(), m_P25State(), m_pttInvert(false), @@ -86,18 +73,13 @@ m_dacOverflow(0U), m_watchdog(0U), m_lockout(false) { - ::memset(m_RRCState, 0x00U, 70U * sizeof(q15_t)); - ::memset(m_RCState, 0x00U, 70U * sizeof(q15_t)); - ::memset(m_GMSKState, 0x00U, 40U * sizeof(q15_t)); - ::memset(m_P25State, 0x00U, 30U * sizeof(q15_t)); + ::memset(m_C4FSKState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_GMSKState, 0x00U, 40U * sizeof(q15_t)); + ::memset(m_P25State, 0x00U, 30U * sizeof(q15_t)); - m_RRCFilter.numTaps = RRC_FILTER_LEN; - m_RRCFilter.pState = m_RRCState; - m_RRCFilter.pCoeffs = RRC_FILTER; - - m_RCFilter.numTaps = RC_FILTER_LEN; - m_RCFilter.pState = m_RCState; - m_RCFilter.pCoeffs = RC_FILTER; + m_C4FSKFilter.numTaps = C4FSK_FILTER_LEN; + m_C4FSKFilter.pState = m_C4FSKState; + m_C4FSKFilter.pCoeffs = C4FSK_FILTER; m_GMSKFilter.numTaps = GMSK_FILTER_LEN; m_GMSKFilter.pState = m_GMSKState; @@ -196,27 +178,22 @@ void CIO::process() q15_t P25Vals[RX_BLOCK_SIZE]; ::arm_fir_fast_q15(&m_P25Filter, samples, P25Vals, RX_BLOCK_SIZE); - q15_t RCVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_RCFilter, P25Vals, RCVals, RX_BLOCK_SIZE); - - p25RX.samples(RCVals, rssi, RX_BLOCK_SIZE); + p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE); } - if (m_ysfEnable) { - q15_t RCVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_RCFilter, samples, RCVals, RX_BLOCK_SIZE); + if (m_dmrEnable || m_ysfEnable) { + q15_t C4FSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); - ysfRX.samples(RCVals, rssi, RX_BLOCK_SIZE); - } + if (m_dmrEnable) { + if (m_duplex) + dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE); + else + dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); + } - if (m_dmrEnable) { - q15_t RRCVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_RRCFilter, samples, RRCVals, RX_BLOCK_SIZE); - - if (m_duplex) - dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE); - else - dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE); + if (m_ysfEnable) + ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_DSTAR) { if (m_dstarEnable) { @@ -227,25 +204,25 @@ void CIO::process() } } else if (m_modemState == STATE_DMR) { if (m_dmrEnable) { - q15_t RRCVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_RRCFilter, samples, RRCVals, RX_BLOCK_SIZE); + q15_t C4FSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); if (m_duplex) { // If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs if (m_tx) - dmrRX.samples(RRCVals, rssi, control, RX_BLOCK_SIZE); + dmrRX.samples(C4FSKVals, rssi, control, RX_BLOCK_SIZE); else - dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE); + dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE); } else { - dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE); + dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); } } } else if (m_modemState == STATE_YSF) { if (m_ysfEnable) { - q15_t RCVals[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_RCFilter, samples, RCVals, RX_BLOCK_SIZE); + q15_t C4FSKVals[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, RX_BLOCK_SIZE); - ysfRX.samples(RCVals, rssi, RX_BLOCK_SIZE); + ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); } } else if (m_modemState == STATE_P25) { if (m_p25Enable) { diff --git a/IO.h b/IO.h index 97abf2c..25559c7 100644 --- a/IO.h +++ b/IO.h @@ -60,12 +60,10 @@ private: CSampleRB m_txBuffer; CRSSIRB m_rssiBuffer; - arm_fir_instance_q15 m_RRCFilter; - arm_fir_instance_q15 m_RCFilter; + arm_fir_instance_q15 m_C4FSKFilter; arm_fir_instance_q15 m_GMSKFilter; arm_fir_instance_q15 m_P25Filter; - q15_t m_RRCState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - q15_t m_RCState[70U]; // NoTaps + BlockSize - 1, 40 + 20 - 1 plus some spare + q15_t m_C4FSKState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare q15_t m_GMSKState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare q15_t m_P25State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare diff --git a/YSFTX.cpp b/YSFTX.cpp index 7036450..fcdcb87 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -25,16 +25,16 @@ #include "YSFDefines.h" #if defined(WIDE_C4FSK_FILTERS_TX) -// Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {-1393, -2602, -3044, -2238, 0, 3460, 7543, 11400, 14152, 15152, 14152, 11400, - 7543, 3460, 0, -2238, -3044, -2602, -1393, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 20U; +// Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB +static q15_t YSF_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, + 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; +const uint16_t YSF_C4FSK_FILTER_LEN = 22U; #else -// Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {0, -413, -750, -845, -587, 0, 741, 1347, 1520, 1062, 0, -1383, -2582, -3021, -2222, 0, 3434, 7487, 11318, - 14054, 15044, 14054, 11318, 7487, 3434, 0, -2222, -3021, -2582, -1383, 0, 1062, 1520, 1347, 741, 0, -587, - -845, -750, -413}; -const uint16_t YSF_C4FSK_FILTER_LEN = 40U; +// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB +static q15_t YSF_C4FSK_FILTER[] = {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, 0}; +const uint16_t YSF_C4FSK_FILTER_LEN = 42U; #endif const q15_t YSF_LEVELA[] = { 809, 809, 809, 809, 809}; From 3814d4243cb71e7c36e80549f198e91b1dfb9f3c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 12 Mar 2017 18:36:41 +0000 Subject: [PATCH 07/33] Add extra idle frames at the start of a DMR DMO transmission. --- DMRDMOTX.cpp | 40 ++++++++++++++++++++++++++++++++++------ DMRDMOTX.h | 6 +++++- SerialPort.cpp | 1 + 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index d7aa0f0..3b763f0 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -41,6 +41,12 @@ const q15_t DMR_LEVELB[] = { 213, 213, 213, 213, 213}; const q15_t DMR_LEVELC[] = {-213, -213, -213, -213, -213}; const q15_t DMR_LEVELD[] = {-640, -640, -640, -640, -640}; +// The PR FILL and Data Sync pattern. +const uint8_t IDLE_DATA[] = + {0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U, + 0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U, + 0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U}; + CDMRDMOTX::CDMRDMOTX() : m_fifo(), @@ -49,7 +55,9 @@ m_modState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(240U) // 200ms +m_txDelay(14U), // 240ms +m_idle(), +m_frameCount(0U) { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -62,14 +70,26 @@ void CDMRDMOTX::process() { if (m_poLen == 0U && m_fifo.getData() > 0U) { if (!m_tx) { - for (uint16_t i = 0U; i < m_txDelay; i++) - m_poBuffer[m_poLen++] = 0x00U; - } else { + m_frameCount = 0U; + 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(); + m_poBuffer[i] = m_idle[i]; + } else { + for (unsigned int i = 0U; i < 72U; i++) + m_poBuffer[m_poLen++] = 0x00U; + + if (m_frameCount >= m_txDelay) { + for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_poBuffer[i] = m_fifo.get(); + } else { + for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_poBuffer[i] = m_idle[i]; + } + + m_frameCount++; } m_poPtr = 0U; @@ -146,6 +166,14 @@ uint8_t CDMRDMOTX::getSpace() const void CDMRDMOTX::setTXDelay(uint8_t delay) { - m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay + m_txDelay = 10U + uint32_t(delay) / 6U; +} + +void CDMRDMOTX::setColorCode(uint8_t colorCode) +{ + ::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES); + + CDMRSlotType slotType; + slotType.encode(colorCode, DT_IDLE, m_idle); } diff --git a/DMRDMOTX.h b/DMRDMOTX.h index d88b4d5..8fc4630 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -37,6 +37,8 @@ public: uint8_t getSpace() const; + void setColorCode(uint8_t colorCode); + private: CSerialRB m_fifo; arm_fir_instance_q15 m_modFilter; @@ -44,7 +46,9 @@ private: uint8_t m_poBuffer[1200U]; uint16_t m_poLen; uint16_t m_poPtr; - uint16_t m_txDelay; + uint32_t m_txDelay; + uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; + uint32_t m_frameCount; void writeByte(uint8_t c); }; diff --git a/SerialPort.cpp b/SerialPort.cpp index 37d19ed..64d8663 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -270,6 +270,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) dmrDMOTX.setTXDelay(txDelay); dmrTX.setColorCode(colorCode); + dmrDMOTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); dmrRX.setDelay(dmrDelay); dmrDMORX.setColorCode(colorCode); From 38516074dd81bf2fdfc7b1e125956b9419b6cc04 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 13 Mar 2017 08:24:35 +0000 Subject: [PATCH 08/33] Forgot to set the at variable within the CACH. --- DMRTX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DMRTX.cpp b/DMRTX.cpp index f42aba9..51cd60d 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -340,7 +340,7 @@ void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex) bool at = false; if (m_frameCount >= STARTUP_COUNT) - m_fifo[rxSlotIndex].getData() > 0U; + at = m_fifo[rxSlotIndex].getData() > 0U; bool tc = txSlotIndex == 1U; bool ls0 = true; // For 1 and 2 bool ls1 = true; From e17d771d41aa6b9521a7f786f39afb056fea17ca Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 18 Mar 2017 09:22:55 +0000 Subject: [PATCH 09/33] Reduce the number of diffs. --- IO.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IO.cpp b/IO.cpp index af819d3..22163d9 100644 --- a/IO.cpp +++ b/IO.cpp @@ -27,13 +27,13 @@ #if defined(WIDE_C4FSK_FILTERS_RX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB static q15_t C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; + 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; const uint16_t C4FSK_FILTER_LEN = 22U; #else // Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB static q15_t C4FSK_FILTER[] = {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, 0}; + 11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112, + -553, -847, -731, -340, 104, 401, 0}; const uint16_t C4FSK_FILTER_LEN = 42U; #endif From e04057a5b59d013b31c330765691d2b3c2aceabc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 18 Mar 2017 11:35:31 +0000 Subject: [PATCH 10/33] Update P25 raised cosine filter coefficients. --- P25TX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/P25TX.cpp b/P25TX.cpp index 0acc5da..42cbfc3 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -26,12 +26,12 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB -static q15_t P25_C4FSK_FILTER[] = {-1393, -2602, -3044, -2238, 0, 3460, 7543, 11400, 14152, 15152, 14152, 11400, 7543, 3460, 0, -2238, -3044, -2602, -1393, 0}; +static q15_t P25_C4FSK_FILTER[] = {-1392, -2602, -3043, -2238, 0, 3460, 7543, 11400, 14153, 15152, 14153, 11400, 7543, 3460, 0, -2238, -3043, -2602, -1392, 0}; const uint16_t P25_C4FSK_FILTER_LEN = 20U; #else // Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB -static q15_t P25_C4FSK_FILTER[] = {0, -413, -750, -845, -587, 0, 741, 1347, 1520, 1062, 0, -1383, -2582, -3021, -2222, 0, 3434, 7487, 11318, 14054, 15044, 14054, - 11318, 7487, 3434, 0, -2222, -3021, -2582, -1383, 0, 1062, 1520, 1347, 741, 0, -587, -845, -750, -413}; +static q15_t P25_C4FSK_FILTER[] = {-413, -751, -845, -587, 0, 740, 1348, 1520, 1063, 0, -1383, -2583, -3021, -2222, 0, 3435, 7488, 11318, 14053, 15044, 14053, + 11318, 7488, 3435, 0, -2222, -3021, -2583, -1383, 0, 1063, 1520, 1348, 740, 0, -587, -845, -751, -413, 0}; const uint16_t P25_C4FSK_FILTER_LEN = 40U; #endif From e697a9171000d1b13d901f4453dca85931bf14a0 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 19 Mar 2017 09:35:46 +0000 Subject: [PATCH 11/33] Revert the DMR DMO transmitter changes. --- DMRDMOTX.cpp | 38 +++++--------------------------------- DMRDMOTX.h | 4 ---- SerialPort.cpp | 1 - 3 files changed, 5 insertions(+), 38 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 3b763f0..73aa008 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -41,12 +41,6 @@ const q15_t DMR_LEVELB[] = { 213, 213, 213, 213, 213}; const q15_t DMR_LEVELC[] = {-213, -213, -213, -213, -213}; const q15_t DMR_LEVELD[] = {-640, -640, -640, -640, -640}; -// The PR FILL and Data Sync pattern. -const uint8_t IDLE_DATA[] = - {0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U, - 0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U, - 0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U}; - CDMRDMOTX::CDMRDMOTX() : m_fifo(), @@ -55,9 +49,7 @@ m_modState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(14U), // 240ms -m_idle(), -m_frameCount(0U) +m_txDelay(240U) // 200ms { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -70,26 +62,14 @@ void CDMRDMOTX::process() { if (m_poLen == 0U && m_fifo.getData() > 0U) { if (!m_tx) { - m_frameCount = 0U; - - for (unsigned int i = 0U; i < 72U; i++) + for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = 0x00U; - - for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i] = m_idle[i]; } else { for (unsigned int i = 0U; i < 72U; i++) m_poBuffer[m_poLen++] = 0x00U; - if (m_frameCount >= m_txDelay) { - for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i] = m_fifo.get(); - } else { - for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i] = m_idle[i]; - } - - m_frameCount++; + for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_poBuffer[i] = m_fifo.get(); } m_poPtr = 0U; @@ -166,14 +146,6 @@ uint8_t CDMRDMOTX::getSpace() const void CDMRDMOTX::setTXDelay(uint8_t delay) { - m_txDelay = 10U + uint32_t(delay) / 6U; -} - -void CDMRDMOTX::setColorCode(uint8_t colorCode) -{ - ::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES); - - CDMRSlotType slotType; - slotType.encode(colorCode, DT_IDLE, m_idle); + m_txDelay = 240U + uint16_t(delay) * 12U; // 200ms + tx delay } diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 8fc4630..92ae011 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -37,8 +37,6 @@ public: uint8_t getSpace() const; - void setColorCode(uint8_t colorCode); - private: CSerialRB m_fifo; arm_fir_instance_q15 m_modFilter; @@ -47,8 +45,6 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint32_t m_txDelay; - uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; - uint32_t m_frameCount; void writeByte(uint8_t c); }; diff --git a/SerialPort.cpp b/SerialPort.cpp index 64d8663..37d19ed 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -270,7 +270,6 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) dmrDMOTX.setTXDelay(txDelay); dmrTX.setColorCode(colorCode); - dmrDMOTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); dmrRX.setDelay(dmrDelay); dmrDMORX.setColorCode(colorCode); From 12dc9183da5a05c4123f9df89189502be2bee6ee Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Mar 2017 20:27:23 +0000 Subject: [PATCH 12/33] Add YSF low deviation mode. --- SerialPort.cpp | 3 +++ YSFTX.cpp | 29 ++++++++++++++++++++--------- YSFTX.h | 3 +++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index 37d19ed..fd2678f 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -218,6 +218,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 ysfLoDev = (data[0U] & 0x08U) == 0x08U; bool simplex = (data[0U] & 0x80U) == 0x80U; bool dstarEnable = (data[1U] & 0x01U) == 0x01U; @@ -275,6 +276,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) dmrDMORX.setColorCode(colorCode); dmrIdleRX.setColorCode(colorCode); + ysfTX.setLoDev(ysfLoDev); + io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel); io.start(); diff --git a/YSFTX.cpp b/YSFTX.cpp index fcdcb87..5ed0a0b 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -37,10 +37,15 @@ static q15_t YSF_C4FSK_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1 const uint16_t YSF_C4FSK_FILTER_LEN = 42U; #endif -const q15_t YSF_LEVELA[] = { 809, 809, 809, 809, 809}; -const q15_t YSF_LEVELB[] = { 269, 269, 269, 269, 269}; -const q15_t YSF_LEVELC[] = {-269, -269, -269, -269, -269}; -const q15_t YSF_LEVELD[] = {-809, -809, -809, -809, -809}; +const q15_t YSF_LEVELA_HI[] = { 809, 809, 809, 809, 809}; +const q15_t YSF_LEVELB_HI[] = { 269, 269, 269, 269, 269}; +const q15_t YSF_LEVELC_HI[] = {-269, -269, -269, -269, -269}; +const q15_t YSF_LEVELD_HI[] = {-809, -809, -809, -809, -809}; + +const q15_t YSF_LEVELA_LO[] = { 405, 405, 405, 405, 405}; +const q15_t YSF_LEVELB_LO[] = { 135, 135, 135, 135, 135}; +const q15_t YSF_LEVELC_LO[] = {-135, -135, -135, -135, -135}; +const q15_t YSF_LEVELD_LO[] = {-405, -405, -405, -405, -405}; const uint8_t YSF_START_SYNC = 0x77U; const uint8_t YSF_END_SYNC = 0xFFU; @@ -52,7 +57,8 @@ m_modState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(240U) // 200ms +m_txDelay(240U), // 200ms +m_loDev(false) { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -124,16 +130,16 @@ void CYSFTX::writeByte(uint8_t c) for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += YSF_RADIO_SYMBOL_LENGTH) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, YSF_LEVELA, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + ::memcpy(p, m_loDev ? YSF_LEVELA_LO : YSF_LEVELA_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); break; case 0x80U: - ::memcpy(p, YSF_LEVELB, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + ::memcpy(p, m_loDev ? YSF_LEVELB_LO : YSF_LEVELB_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); break; case 0x00U: - ::memcpy(p, YSF_LEVELC, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + ::memcpy(p, m_loDev ? YSF_LEVELC_LO : YSF_LEVELC_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); break; default: - ::memcpy(p, YSF_LEVELD, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + ::memcpy(p, m_loDev ? YSF_LEVELD_LO : YSF_LEVELD_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); break; } } @@ -153,3 +159,8 @@ uint8_t CYSFTX::getSpace() const return m_buffer.getSpace() / YSF_FRAME_LENGTH_BYTES; } +void CYSFTX::setLoDev(bool on) +{ + m_loDev = on; +} + diff --git a/YSFTX.h b/YSFTX.h index b51d5b7..c38cf96 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -35,6 +35,8 @@ public: uint8_t getSpace() const; + void setLoDev(bool on); + private: CSerialRB m_buffer; arm_fir_instance_q15 m_modFilter; @@ -43,6 +45,7 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint16_t m_txDelay; + bool m_loDev; void writeByte(uint8_t c); }; From c9b553bc2e2bb528c1d0d32eaafcf2b350d9b6a2 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 29 Mar 2017 20:36:02 +0100 Subject: [PATCH 13/33] Follow the ETSI standard for DMO operation. --- DMRDMOTX.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++----- DMRDMOTX.h | 4 +++- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 73aa008..4b186a3 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -41,6 +41,21 @@ const q15_t DMR_LEVELB[] = { 213, 213, 213, 213, 213}; const q15_t DMR_LEVELC[] = {-213, -213, -213, -213, -213}; const q15_t DMR_LEVELD[] = {-640, -640, -640, -640, -640}; +const uint8_t CACH_INTERLEAVE[] = + {1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U, + 25U, 26U, 27U, 29U, 30U, 31U, 33U, 34U, 35U, 37U, 39U, 40U, 41U, 43U, 44U, 45U, 47U, + 49U, 50U, 51U, 53U, 54U, 55U, 57U, 58U, 59U, 61U, 63U, 64U, 65U, 67U, 68U, 69U, 71U, + 73U, 74U, 75U, 77U, 78U, 79U, 81U, 82U, 83U, 85U, 87U, 88U, 89U, 91U, 92U, 93U, 95U}; + +const uint8_t EMPTY_SHORT_LC[] = + {0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; + +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]) +#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +const uint8_t DMR_SYNC = 0x77U; CDMRDMOTX::CDMRDMOTX() : m_fifo(), @@ -49,7 +64,8 @@ m_modState(), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(240U) // 200ms +m_txDelay(240U), // 200ms +m_cachPtr(0U) { ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); @@ -63,13 +79,17 @@ void CDMRDMOTX::process() if (m_poLen == 0U && m_fifo.getData() > 0U) { if (!m_tx) { for (uint16_t i = 0U; i < m_txDelay; i++) - m_poBuffer[m_poLen++] = 0x00U; + m_poBuffer[i] = DMR_SYNC; + + m_poLen = m_txDelay; } else { - for (unsigned int i = 0U; i < 72U; i++) - m_poBuffer[m_poLen++] = 0x00U; + createCACH(m_poBuffer + 0U, 0U); + createCACH(m_poBuffer + 36U, 1U); for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i] = m_fifo.get(); + m_poBuffer[i + 3U] = m_poBuffer[i + 39U] = m_fifo.get(); + + m_poLen = 72U; } m_poPtr = 0U; @@ -149,3 +169,34 @@ void CDMRDMOTX::setTXDelay(uint8_t delay) m_txDelay = 240U + uint16_t(delay) * 12U; // 200ms + tx delay } +void CDMRDMOTX::createCACH(uint8_t* buffer, uint8_t slotIndex) +{ + if (m_cachPtr >= 12U) + m_cachPtr = 0U; + + ::memcpy(buffer, EMPTY_SHORT_LC + m_cachPtr, 3U); + + bool at = true; + bool tc = slotIndex == 1U; + bool ls0 = true; // For 1 and 2 + bool ls1 = true; + + if (m_cachPtr == 0U) // For 0 + ls1 = false; + else if (m_cachPtr == 9U) // For 3 + ls0 = false; + + bool h0 = at ^ tc ^ ls1; + bool h1 = tc ^ ls1 ^ ls0; + bool h2 = at ^ tc ^ ls0; + + buffer[0U] |= at ? 0x80U : 0x00U; + buffer[0U] |= tc ? 0x08U : 0x00U; + buffer[1U] |= ls1 ? 0x80U : 0x00U; + buffer[1U] |= ls0 ? 0x08U : 0x00U; + buffer[1U] |= h0 ? 0x02U : 0x00U; + buffer[2U] |= h1 ? 0x20U : 0x00U; + buffer[2U] |= h2 ? 0x02U : 0x00U; + + m_cachPtr += 3U; +} diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 92ae011..ba4dc2c 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -41,11 +41,13 @@ private: CSerialRB m_fifo; arm_fir_instance_q15 m_modFilter; q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - uint8_t m_poBuffer[1200U]; + uint8_t m_poBuffer[800U]; uint16_t m_poLen; uint16_t m_poPtr; uint32_t m_txDelay; + uint8_t m_cachPtr; + void createCACH(uint8_t* buffer, uint8_t slotIndex); void writeByte(uint8_t c); }; From aee9cac54688ccbeb0e7a5270caddb4710fa5217 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Thu, 30 Mar 2017 01:09:03 -0300 Subject: [PATCH 14/33] New YSF filter for TX --- YSFTX.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/YSFTX.cpp b/YSFTX.cpp index 5ed0a0b..dc209cc 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -30,11 +30,11 @@ static q15_t YSF_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; const uint16_t YSF_C4FSK_FILTER_LEN = 22U; #else -// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {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, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 42U; +// Generated using rcosdesign(0.2, 8, 4, 'sqrt') in MATLAB +static q15_t YSF_C4FSK_FILTER[] = {448, 0, -622, -954, -619, 349, 1391, 1704, 764, -1182, -3028, -3279, -861, + 4135, 10280, 15335, 17288, 15335, 10280, 4135, -861, -3279, -3028, -1182, + 764, 1704, 1391, 349, -619, -954, -622, 0, 448, 0}; +const uint16_t YSF_C4FSK_FILTER_LEN = 34U; #endif const q15_t YSF_LEVELA_HI[] = { 809, 809, 809, 809, 809}; From a033ee66fd1d7aac94b948dfc05afb964df60581 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Fri, 31 Mar 2017 01:25:45 -0300 Subject: [PATCH 15/33] Restoring original TX filter for YSF, fixing symbol generation (zero padding for FIR interpolation) --- YSFTX.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/YSFTX.cpp b/YSFTX.cpp index dc209cc..b53684b 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -30,22 +30,22 @@ static q15_t YSF_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; const uint16_t YSF_C4FSK_FILTER_LEN = 22U; #else -// Generated using rcosdesign(0.2, 8, 4, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {448, 0, -622, -954, -619, 349, 1391, 1704, 764, -1182, -3028, -3279, -861, - 4135, 10280, 15335, 17288, 15335, 10280, 4135, -861, -3279, -3028, -1182, - 764, 1704, 1391, 349, -619, -954, -622, 0, 448, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 34U; +// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB +static q15_t YSF_C4FSK_FILTER[] = {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, 0}; +const uint16_t YSF_C4FSK_FILTER_LEN = 42U; #endif -const q15_t YSF_LEVELA_HI[] = { 809, 809, 809, 809, 809}; -const q15_t YSF_LEVELB_HI[] = { 269, 269, 269, 269, 269}; -const q15_t YSF_LEVELC_HI[] = {-269, -269, -269, -269, -269}; -const q15_t YSF_LEVELD_HI[] = {-809, -809, -809, -809, -809}; +const q15_t YSF_LEVELA_HI[] = { 4035, 0, 0, 0, 0}; +const q15_t YSF_LEVELB_HI[] = { 1345, 0, 0, 0, 0}; +const q15_t YSF_LEVELC_HI[] = {-1345, 0, 0, 0, 0}; +const q15_t YSF_LEVELD_HI[] = {-4035, 0, 0, 0, 0}; -const q15_t YSF_LEVELA_LO[] = { 405, 405, 405, 405, 405}; -const q15_t YSF_LEVELB_LO[] = { 135, 135, 135, 135, 135}; -const q15_t YSF_LEVELC_LO[] = {-135, -135, -135, -135, -135}; -const q15_t YSF_LEVELD_LO[] = {-405, -405, -405, -405, -405}; +const q15_t YSF_LEVELA_LO[] = { 2019, 0, 0, 0, 0}; +const q15_t YSF_LEVELB_LO[] = { 673, 0, 0, 0, 0}; +const q15_t YSF_LEVELC_LO[] = { -673, 0, 0, 0, 0}; +const q15_t YSF_LEVELD_LO[] = {-2019, 0, 0, 0, 0}; const uint8_t YSF_START_SYNC = 0x77U; const uint8_t YSF_END_SYNC = 0xFFU; @@ -143,7 +143,7 @@ void CYSFTX::writeByte(uint8_t c) break; } } - + ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); io.write(STATE_YSF, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); From 546243eec6318bd1d5de21ef8a8f4f80b93bbe76 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Fri, 31 Mar 2017 01:26:07 -0300 Subject: [PATCH 16/33] Fixing symbol generation (zero padding for FIR interpolation) --- DMRTX.cpp | 8 ++++---- DStarTX.cpp | 4 ++-- P25TX.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DMRTX.cpp b/DMRTX.cpp index 51cd60d..196e967 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -36,10 +36,10 @@ static q15_t DMR_C4FSK_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1 const uint16_t DMR_C4FSK_FILTER_LEN = 42U; #endif -const q15_t DMR_LEVELA[] = { 640, 640 , 640, 640, 640}; -const q15_t DMR_LEVELB[] = { 213, 213, 213, 213, 213}; -const q15_t DMR_LEVELC[] = {-213, -213, -213, -213, -213}; -const q15_t DMR_LEVELD[] = {-640, -640, -640, -640, -640}; +const q15_t DMR_LEVELA[] = { 3195, 0 , 0, 0, 0}; +const q15_t DMR_LEVELB[] = { 1065, 0 , 0, 0, 0}; +const q15_t DMR_LEVELC[] = {-1065, 0 , 0, 0, 0}; +const q15_t DMR_LEVELD[] = {-3195, 0 , 0, 0, 0}; // The PR FILL and Data Sync pattern. const uint8_t IDLE_DATA[] = diff --git a/DStarTX.cpp b/DStarTX.cpp index b4c89e5..d4640d1 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -32,8 +32,8 @@ const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U}; static q15_t DSTAR_GMSK_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0}; const uint16_t DSTAR_GMSK_FILTER_LEN = 12U; -const q15_t DSTAR_LEVEL0[] = {-800, -800, -800, -800, -800}; -const q15_t DSTAR_LEVEL1[] = { 800, 800, 800, 800, 800}; +const q15_t DSTAR_LEVEL0[] = {-4000, 0, 0, 0, 0}; +const q15_t DSTAR_LEVEL1[] = { 4000, 0, 0, 0, 0}; const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; diff --git a/P25TX.cpp b/P25TX.cpp index 42cbfc3..1cb7488 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -44,10 +44,10 @@ static q15_t P25_LP_FILTER[] = {170, 401, 340, -203, -715, -478, 281, 419, -440, 281, -478, -715, -203, 340, 401, 170}; const uint16_t P25_LP_FILTER_LEN = 44U; -const q15_t P25_LEVELA[] = { 495, 495, 495, 495, 495}; -const q15_t P25_LEVELB[] = { 165, 165, 165, 165, 165}; -const q15_t P25_LEVELC[] = {-165, -165, -165, -165, -165}; -const q15_t P25_LEVELD[] = {-495, -495, -495, -495, -495}; +const q15_t P25_LEVELA[] = { 2475, 0, 0, 0, 0}; +const q15_t P25_LEVELB[] = { 825, 0, 0, 0, 0}; +const q15_t P25_LEVELC[] = {-825, 0, 0, 0, 0}; +const q15_t P25_LEVELD[] = {-2475, 0, 0, 0, 0}; const uint8_t P25_START_SYNC = 0x77U; From 4039f576aea8274f6be0bb86671bccb08b09a5bb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 31 Mar 2017 08:16:13 +0100 Subject: [PATCH 17/33] Use the DMR changes from Andy in the DMR DMO TX. --- DMRDMOTX.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 4b186a3..bd9752d 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -36,10 +36,10 @@ static q15_t DMR_C4FSK_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1 const uint16_t DMR_C4FSK_FILTER_LEN = 42U; #endif -const q15_t DMR_LEVELA[] = { 640, 640 , 640, 640, 640}; -const q15_t DMR_LEVELB[] = { 213, 213, 213, 213, 213}; -const q15_t DMR_LEVELC[] = {-213, -213, -213, -213, -213}; -const q15_t DMR_LEVELD[] = {-640, -640, -640, -640, -640}; +const q15_t DMR_LEVELA[] = { 3195, 0 , 0, 0, 0}; +const q15_t DMR_LEVELB[] = { 1065, 0 , 0, 0, 0}; +const q15_t DMR_LEVELC[] = {-1065, 0 , 0, 0, 0}; +const q15_t DMR_LEVELD[] = {-3195, 0 , 0, 0, 0}; const uint8_t CACH_INTERLEAVE[] = {1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U, From 9bcaba0419a2d3ed16391f088e514632b926874a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 31 Mar 2017 08:33:01 +0100 Subject: [PATCH 18/33] Change the start sync sequence. --- DMRDMOTX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index bd9752d..8dcccb0 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -55,7 +55,7 @@ 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 READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -const uint8_t DMR_SYNC = 0x77U; +const uint8_t DMR_SYNC = 0x5FU; CDMRDMOTX::CDMRDMOTX() : m_fifo(), From 78f5d3437376811842673d79f31141de332b3884 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sat, 1 Apr 2017 01:16:56 -0300 Subject: [PATCH 19/33] Using CMSIS FIR interpolator for all modulators --- DMRDMOTX.cpp | 43 +++++++++++++++++++++---------------------- DMRDMOTX.h | 14 +++++++------- DMRTX.cpp | 42 +++++++++++++++++++++--------------------- DMRTX.h | 28 ++++++++++++++-------------- DStarTX.cpp | 28 ++++++++++++++-------------- DStarTX.h | 14 +++++++------- P25TX.cpp | 36 +++++++++++++++++++----------------- P25TX.h | 18 +++++++++--------- YSFTX.cpp | 52 ++++++++++++++++++++++++++-------------------------- YSFTX.h | 16 ++++++++-------- 10 files changed, 146 insertions(+), 145 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 73aa008..c47d33c 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -25,22 +25,21 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t DMR_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 22U; +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[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, +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, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 42U; + -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[] = { 640, 640 , 640, 640, 640}; -const q15_t DMR_LEVELB[] = { 213, 213, 213, 213, 213}; -const q15_t DMR_LEVELC[] = {-213, -213, -213, -213, -213}; -const q15_t DMR_LEVELD[] = {-640, -640, -640, -640, -640}; - +const q15_t DMR_LEVELA = 3195; +const q15_t DMR_LEVELB = 1065; +const q15_t DMR_LEVELC = -1065; +const q15_t DMR_LEVELD = -3195; CDMRDMOTX::CDMRDMOTX() : m_fifo(), @@ -51,11 +50,12 @@ m_poLen(0U), m_poPtr(0U), m_txDelay(240U) // 200ms { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); - m_modFilter.numTaps = DMR_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + 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; } void CDMRDMOTX::process() @@ -111,30 +111,29 @@ uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length) void CDMRDMOTX::writeByte(uint8_t c) { - q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += DMR_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, DMR_LEVELA, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELA; break; case 0x80U: - ::memcpy(p, DMR_LEVELB, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELB; break; case 0x00U: - ::memcpy(p, DMR_LEVELC, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELC; break; default: - ::memcpy(p, DMR_LEVELD, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELD; break; } } - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U); io.write(STATE_DMR, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); } diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 92ae011..62ef2c1 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -38,13 +38,13 @@ public: uint8_t getSpace() const; private: - CSerialRB m_fifo; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - uint8_t m_poBuffer[1200U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint32_t m_txDelay; + CSerialRB m_fifo; + arm_fir_interpolate_instance_q15 m_modFilter; + q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare + uint8_t m_poBuffer[1200U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint32_t m_txDelay; void writeByte(uint8_t c); }; diff --git a/DMRTX.cpp b/DMRTX.cpp index 196e967..de7ab7e 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -25,21 +25,21 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t DMR_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 22U; +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[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, +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, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 42U; + -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[] = { 3195, 0 , 0, 0, 0}; -const q15_t DMR_LEVELB[] = { 1065, 0 , 0, 0, 0}; -const q15_t DMR_LEVELC[] = {-1065, 0 , 0, 0, 0}; -const q15_t DMR_LEVELD[] = {-3195, 0 , 0, 0, 0}; +const q15_t DMR_LEVELA = 3195; +const q15_t DMR_LEVELB = 1065; +const q15_t DMR_LEVELC = -1065; +const q15_t DMR_LEVELD = -3195; // The PR FILL and Data Sync pattern. const uint8_t IDLE_DATA[] = @@ -79,11 +79,12 @@ m_poPtr(0U), m_frameCount(0U), m_abort() { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); - m_modFilter.numTaps = DMR_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + 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); @@ -246,25 +247,24 @@ void CDMRTX::setCal(bool start) void CDMRTX::writeByte(uint8_t c, uint8_t control) { - q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += DMR_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, DMR_LEVELA, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELA; break; case 0x80U: - ::memcpy(p, DMR_LEVELB, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELB; break; case 0x00U: - ::memcpy(p, DMR_LEVELC, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELC; break; default: - ::memcpy(p, DMR_LEVELD, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELD; break; } } @@ -273,7 +273,7 @@ void CDMRTX::writeByte(uint8_t c, uint8_t control) ::memset(controlBuffer, MARK_NONE, DMR_RADIO_SYMBOL_LENGTH * 4U * sizeof(uint8_t)); controlBuffer[DMR_RADIO_SYMBOL_LENGTH * 2U] = control; - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U); io.write(STATE_DMR, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U, controlBuffer); } diff --git a/DMRTX.h b/DMRTX.h index 69cf06a..de271d3 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -55,20 +55,20 @@ public: void setColorCode(uint8_t colorCode); private: - CSerialRB m_fifo[2U]; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - DMRTXSTATE m_state; - uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; - uint8_t m_cachPtr; - uint8_t m_shortLC[12U]; - uint8_t m_newShortLC[12U]; - uint8_t m_markBuffer[40U]; - uint8_t m_poBuffer[40U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint32_t m_frameCount; - bool m_abort[2U]; + 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; + uint8_t m_shortLC[12U]; + uint8_t m_newShortLC[12U]; + uint8_t m_markBuffer[40U]; + uint8_t m_poBuffer[40U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint32_t m_frameCount; + bool m_abort[2U]; void createData(uint8_t slotIndex); void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex); diff --git a/DStarTX.cpp b/DStarTX.cpp index d4640d1..4f81574 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -29,11 +29,11 @@ const uint8_t BIT_SYNC = 0xAAU; const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U}; // Generated using gaussfir(0.5, 4, 5) in MATLAB -static q15_t DSTAR_GMSK_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0}; -const uint16_t DSTAR_GMSK_FILTER_LEN = 12U; +static q15_t DSTAR_GMSK_FILTER[] = {0, 0, 0, 0, 8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8}; // numTaps = 15, L = 5 +const uint16_t DSTAR_GMSK_FILTER_PHASE_LEN = 3U; // phaseLength = numTaps/L -const q15_t DSTAR_LEVEL0[] = {-4000, 0, 0, 0, 0}; -const q15_t DSTAR_LEVEL1[] = { 4000, 0, 0, 0, 0}; +const q15_t DSTAR_LEVEL0 = -4000; +const q15_t DSTAR_LEVEL1 = 4000; const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; @@ -197,11 +197,12 @@ m_poLen(0U), m_poPtr(0U), m_txDelay(60U) // 100ms { - ::memset(m_modState, 0x00U, 60U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 20U * sizeof(q15_t)); - m_modFilter.numTaps = DSTAR_GMSK_FILTER_LEN; - m_modFilter.pState = m_modState; + m_modFilter.L = DSTAR_RADIO_BIT_LENGTH; + m_modFilter.phaseLength = DSTAR_GMSK_FILTER_PHASE_LEN; m_modFilter.pCoeffs = DSTAR_GMSK_FILTER; + m_modFilter.pState = m_modState; } void CDStarTX::process() @@ -411,23 +412,22 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const void CDStarTX::writeByte(uint8_t c) { - q15_t inBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; + q15_t inBuffer[8U]; q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; uint8_t mask = 0x01U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 8U; i++, p += DSTAR_RADIO_BIT_LENGTH) { + for (uint8_t i = 0U; i < 8U; i++) { if ((c & mask) == mask) - ::memcpy(p, DSTAR_LEVEL0, DSTAR_RADIO_BIT_LENGTH * sizeof(q15_t)); + inBuffer[i] = DSTAR_LEVEL0; else - ::memcpy(p, DSTAR_LEVEL1, DSTAR_RADIO_BIT_LENGTH * sizeof(q15_t)); + inBuffer[i] = DSTAR_LEVEL1; mask <<= 1; } - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); - + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U); + io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); } diff --git a/DStarTX.h b/DStarTX.h index 17855f8..24876d7 100644 --- a/DStarTX.h +++ b/DStarTX.h @@ -38,13 +38,13 @@ public: uint8_t getSpace() const; private: - CSerialRB m_buffer; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[60U]; // NoTaps + BlockSize - 1, 12 + 40 - 1 plus some spare - uint8_t m_poBuffer[600U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint16_t m_txDelay; // In bytes + CSerialRB m_buffer; + arm_fir_interpolate_instance_q15 m_modFilter; + q15_t m_modState[20U]; // blockSize + phaseLength - 1, 8 + 9 - 1 plus some spare + uint8_t m_poBuffer[600U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; // In bytes void txHeader(const uint8_t* in, uint8_t* out) const; void writeByte(uint8_t c); diff --git a/P25TX.cpp b/P25TX.cpp index 1cb7488..8f92b3c 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -26,13 +26,15 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB +// numTaps = 20, L = 5 static q15_t P25_C4FSK_FILTER[] = {-1392, -2602, -3043, -2238, 0, 3460, 7543, 11400, 14153, 15152, 14153, 11400, 7543, 3460, 0, -2238, -3043, -2602, -1392, 0}; -const uint16_t P25_C4FSK_FILTER_LEN = 20U; +const uint16_t P25_C4FSK_FILTER_PHASE_LEN = 4U; // phaseLength = numTaps/L #else // Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB +// numTaps = 40, L = 5 static q15_t P25_C4FSK_FILTER[] = {-413, -751, -845, -587, 0, 740, 1348, 1520, 1063, 0, -1383, -2583, -3021, -2222, 0, 3435, 7488, 11318, 14053, 15044, 14053, 11318, 7488, 3435, 0, -2222, -3021, -2583, -1383, 0, 1063, 1520, 1348, 740, 0, -587, -845, -751, -413, 0}; -const uint16_t P25_C4FSK_FILTER_LEN = 40U; +const uint16_t P25_C4FSK_FILTER_PHASE_LEN = 8U; // phaseLength = numTaps/L #endif // Generated in MATLAB using the following commands, and then normalised for unity gain @@ -44,10 +46,10 @@ static q15_t P25_LP_FILTER[] = {170, 401, 340, -203, -715, -478, 281, 419, -440, 281, -478, -715, -203, 340, 401, 170}; const uint16_t P25_LP_FILTER_LEN = 44U; -const q15_t P25_LEVELA[] = { 2475, 0, 0, 0, 0}; -const q15_t P25_LEVELB[] = { 825, 0, 0, 0, 0}; -const q15_t P25_LEVELC[] = {-825, 0, 0, 0, 0}; -const q15_t P25_LEVELD[] = {-2475, 0, 0, 0, 0}; +const q15_t P25_LEVELA = 2475; +const q15_t P25_LEVELB = 825; +const q15_t P25_LEVELC = -825; +const q15_t P25_LEVELD = -2475; const uint8_t P25_START_SYNC = 0x77U; @@ -62,12 +64,13 @@ m_poLen(0U), m_poPtr(0U), m_txDelay(240U) // 200ms { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); ::memset(m_lpState, 0x00U, 70U * sizeof(q15_t)); - m_modFilter.numTaps = P25_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + m_modFilter.L = P25_RADIO_SYMBOL_LENGTH; + m_modFilter.phaseLength = P25_C4FSK_FILTER_PHASE_LEN; m_modFilter.pCoeffs = P25_C4FSK_FILTER; + m_modFilter.pState = m_modState; m_lpFilter.numTaps = P25_LP_FILTER_LEN; m_lpFilter.pState = m_lpState; @@ -130,31 +133,30 @@ uint8_t CP25TX::writeData(const uint8_t* data, uint8_t length) void CP25TX::writeByte(uint8_t c) { - q15_t inBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += P25_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, P25_LEVELA, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELA; break; case 0x80U: - ::memcpy(p, P25_LEVELB, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELB; break; case 0x00U: - ::memcpy(p, P25_LEVELC, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELC; break; default: - ::memcpy(p, P25_LEVELD, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELD; break; } } - ::arm_fir_fast_q15(&m_modFilter, inBuffer, intBuffer, P25_RADIO_SYMBOL_LENGTH * 4U); + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U); ::arm_fir_fast_q15(&m_lpFilter, intBuffer, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U); diff --git a/P25TX.h b/P25TX.h index 99db19d..61f6a87 100644 --- a/P25TX.h +++ b/P25TX.h @@ -36,15 +36,15 @@ public: uint8_t getSpace() const; private: - CSerialRB m_buffer; - arm_fir_instance_q15 m_modFilter; - arm_fir_instance_q15 m_lpFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - q15_t m_lpState[70U]; // NoTaps + BlockSize - 1, 44 + 20 - 1 plus some spare - uint8_t m_poBuffer[1200U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint16_t m_txDelay; + CSerialRB m_buffer; + arm_fir_interpolate_instance_q15 m_modFilter; + arm_fir_instance_q15 m_lpFilter; + q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare + q15_t m_lpState[70U]; // NoTaps + BlockSize - 1, 44 + 20 - 1 plus some spare + uint8_t m_poBuffer[1200U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; void writeByte(uint8_t c); }; diff --git a/YSFTX.cpp b/YSFTX.cpp index b53684b..d1c5d76 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -26,26 +26,26 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 22U; +static q15_t YSF_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 YSF_C4FSK_FILTER_PHASE_LEN = 5U; // phaseLength = numTaps/L #else // Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, +static q15_t YSF_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, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 42U; + -553, -847, -731, -340, 104, 401}; // numTaps = 45, L = 5 +const uint16_t YSF_C4FSK_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L #endif -const q15_t YSF_LEVELA_HI[] = { 4035, 0, 0, 0, 0}; -const q15_t YSF_LEVELB_HI[] = { 1345, 0, 0, 0, 0}; -const q15_t YSF_LEVELC_HI[] = {-1345, 0, 0, 0, 0}; -const q15_t YSF_LEVELD_HI[] = {-4035, 0, 0, 0, 0}; +const q15_t YSF_LEVELA_HI = 4035; +const q15_t YSF_LEVELB_HI = 1345; +const q15_t YSF_LEVELC_HI = -1345; +const q15_t YSF_LEVELD_HI = -4035; -const q15_t YSF_LEVELA_LO[] = { 2019, 0, 0, 0, 0}; -const q15_t YSF_LEVELB_LO[] = { 673, 0, 0, 0, 0}; -const q15_t YSF_LEVELC_LO[] = { -673, 0, 0, 0, 0}; -const q15_t YSF_LEVELD_LO[] = {-2019, 0, 0, 0, 0}; +const q15_t YSF_LEVELA_LO = 2019; +const q15_t YSF_LEVELB_LO = 673; +const q15_t YSF_LEVELC_LO = -673; +const q15_t YSF_LEVELD_LO = -2019; const uint8_t YSF_START_SYNC = 0x77U; const uint8_t YSF_END_SYNC = 0xFFU; @@ -60,11 +60,12 @@ m_poPtr(0U), m_txDelay(240U), // 200ms m_loDev(false) { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); - m_modFilter.numTaps = YSF_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + m_modFilter.L = YSF_RADIO_SYMBOL_LENGTH; + m_modFilter.phaseLength = YSF_C4FSK_FILTER_PHASE_LEN; m_modFilter.pCoeffs = YSF_C4FSK_FILTER; + m_modFilter.pState = m_modState; } void CYSFTX::process() @@ -121,30 +122,29 @@ uint8_t CYSFTX::writeData(const uint8_t* data, uint8_t length) void CYSFTX::writeByte(uint8_t c) { - q15_t inBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t outBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += YSF_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, m_loDev ? YSF_LEVELA_LO : YSF_LEVELA_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELA_LO : YSF_LEVELA_HI; break; case 0x80U: - ::memcpy(p, m_loDev ? YSF_LEVELB_LO : YSF_LEVELB_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELB_LO : YSF_LEVELB_HI; break; case 0x00U: - ::memcpy(p, m_loDev ? YSF_LEVELC_LO : YSF_LEVELC_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELC_LO : YSF_LEVELC_HI; break; default: - ::memcpy(p, m_loDev ? YSF_LEVELD_LO : YSF_LEVELD_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELD_LO : YSF_LEVELD_HI; break; } } - - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); + + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U); io.write(STATE_YSF, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); } diff --git a/YSFTX.h b/YSFTX.h index c38cf96..01211a5 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -38,14 +38,14 @@ public: void setLoDev(bool on); private: - CSerialRB m_buffer; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - uint8_t m_poBuffer[1200U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint16_t m_txDelay; - bool m_loDev; + CSerialRB m_buffer; + arm_fir_interpolate_instance_q15 m_modFilter; + q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare + uint8_t m_poBuffer[1200U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; + bool m_loDev; void writeByte(uint8_t c); }; From a49871cd8b0c24d24b2e477aa0817df07e8359fe Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sat, 1 Apr 2017 01:16:56 -0300 Subject: [PATCH 20/33] Using CMSIS FIR interpolator for all modulators --- DMRDMOTX.cpp | 42 +++++++++++++++++++++--------------------- DMRDMOTX.h | 17 +++++++++-------- DMRTX.cpp | 42 +++++++++++++++++++++--------------------- DMRTX.h | 28 ++++++++++++++-------------- DStarTX.cpp | 28 ++++++++++++++-------------- DStarTX.h | 14 +++++++------- P25TX.cpp | 36 +++++++++++++++++++----------------- P25TX.h | 18 +++++++++--------- YSFTX.cpp | 52 ++++++++++++++++++++++++++-------------------------- YSFTX.h | 16 ++++++++-------- 10 files changed, 148 insertions(+), 145 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 8dcccb0..7dfd8d5 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -25,21 +25,21 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t DMR_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 22U; +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[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, +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, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 42U; + -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[] = { 3195, 0 , 0, 0, 0}; -const q15_t DMR_LEVELB[] = { 1065, 0 , 0, 0, 0}; -const q15_t DMR_LEVELC[] = {-1065, 0 , 0, 0, 0}; -const q15_t DMR_LEVELD[] = {-3195, 0 , 0, 0, 0}; +const q15_t DMR_LEVELA = 3195; +const q15_t DMR_LEVELB = 1065; +const q15_t DMR_LEVELC = -1065; +const q15_t DMR_LEVELD = -3195; const uint8_t CACH_INTERLEAVE[] = {1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U, @@ -67,11 +67,12 @@ m_poPtr(0U), m_txDelay(240U), // 200ms m_cachPtr(0U) { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); - m_modFilter.numTaps = DMR_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + 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; } void CDMRDMOTX::process() @@ -131,30 +132,29 @@ uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length) void CDMRDMOTX::writeByte(uint8_t c) { - q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += DMR_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, DMR_LEVELA, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELA; break; case 0x80U: - ::memcpy(p, DMR_LEVELB, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELB; break; case 0x00U: - ::memcpy(p, DMR_LEVELC, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELC; break; default: - ::memcpy(p, DMR_LEVELD, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELD; break; } } - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U); io.write(STATE_DMR, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); } diff --git a/DMRDMOTX.h b/DMRDMOTX.h index ba4dc2c..022ecd0 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -38,14 +38,15 @@ public: uint8_t getSpace() const; private: - CSerialRB m_fifo; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - uint8_t m_poBuffer[800U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint32_t m_txDelay; - uint8_t m_cachPtr; + + CSerialRB m_fifo; + arm_fir_interpolate_instance_q15 m_modFilter; + q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare + uint8_t m_poBuffer[800U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint32_t m_txDelay; + uint8_t m_cachPtr; void createCACH(uint8_t* buffer, uint8_t slotIndex); void writeByte(uint8_t c); diff --git a/DMRTX.cpp b/DMRTX.cpp index 196e967..de7ab7e 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -25,21 +25,21 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t DMR_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 22U; +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[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, +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, 0}; -const uint16_t DMR_C4FSK_FILTER_LEN = 42U; + -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[] = { 3195, 0 , 0, 0, 0}; -const q15_t DMR_LEVELB[] = { 1065, 0 , 0, 0, 0}; -const q15_t DMR_LEVELC[] = {-1065, 0 , 0, 0, 0}; -const q15_t DMR_LEVELD[] = {-3195, 0 , 0, 0, 0}; +const q15_t DMR_LEVELA = 3195; +const q15_t DMR_LEVELB = 1065; +const q15_t DMR_LEVELC = -1065; +const q15_t DMR_LEVELD = -3195; // The PR FILL and Data Sync pattern. const uint8_t IDLE_DATA[] = @@ -79,11 +79,12 @@ m_poPtr(0U), m_frameCount(0U), m_abort() { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); - m_modFilter.numTaps = DMR_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + 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); @@ -246,25 +247,24 @@ void CDMRTX::setCal(bool start) void CDMRTX::writeByte(uint8_t c, uint8_t control) { - q15_t inBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t outBuffer[DMR_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += DMR_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, DMR_LEVELA, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELA; break; case 0x80U: - ::memcpy(p, DMR_LEVELB, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELB; break; case 0x00U: - ::memcpy(p, DMR_LEVELC, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELC; break; default: - ::memcpy(p, DMR_LEVELD, DMR_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = DMR_LEVELD; break; } } @@ -273,7 +273,7 @@ void CDMRTX::writeByte(uint8_t c, uint8_t control) ::memset(controlBuffer, MARK_NONE, DMR_RADIO_SYMBOL_LENGTH * 4U * sizeof(uint8_t)); controlBuffer[DMR_RADIO_SYMBOL_LENGTH * 2U] = control; - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U); + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U); io.write(STATE_DMR, outBuffer, DMR_RADIO_SYMBOL_LENGTH * 4U, controlBuffer); } diff --git a/DMRTX.h b/DMRTX.h index 69cf06a..de271d3 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -55,20 +55,20 @@ public: void setColorCode(uint8_t colorCode); private: - CSerialRB m_fifo[2U]; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - DMRTXSTATE m_state; - uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; - uint8_t m_cachPtr; - uint8_t m_shortLC[12U]; - uint8_t m_newShortLC[12U]; - uint8_t m_markBuffer[40U]; - uint8_t m_poBuffer[40U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint32_t m_frameCount; - bool m_abort[2U]; + 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; + uint8_t m_shortLC[12U]; + uint8_t m_newShortLC[12U]; + uint8_t m_markBuffer[40U]; + uint8_t m_poBuffer[40U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint32_t m_frameCount; + bool m_abort[2U]; void createData(uint8_t slotIndex); void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex); diff --git a/DStarTX.cpp b/DStarTX.cpp index d4640d1..4f81574 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -29,11 +29,11 @@ const uint8_t BIT_SYNC = 0xAAU; const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U}; // Generated using gaussfir(0.5, 4, 5) in MATLAB -static q15_t DSTAR_GMSK_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0}; -const uint16_t DSTAR_GMSK_FILTER_LEN = 12U; +static q15_t DSTAR_GMSK_FILTER[] = {0, 0, 0, 0, 8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8}; // numTaps = 15, L = 5 +const uint16_t DSTAR_GMSK_FILTER_PHASE_LEN = 3U; // phaseLength = numTaps/L -const q15_t DSTAR_LEVEL0[] = {-4000, 0, 0, 0, 0}; -const q15_t DSTAR_LEVEL1[] = { 4000, 0, 0, 0, 0}; +const q15_t DSTAR_LEVEL0 = -4000; +const q15_t DSTAR_LEVEL1 = 4000; const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; @@ -197,11 +197,12 @@ m_poLen(0U), m_poPtr(0U), m_txDelay(60U) // 100ms { - ::memset(m_modState, 0x00U, 60U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 20U * sizeof(q15_t)); - m_modFilter.numTaps = DSTAR_GMSK_FILTER_LEN; - m_modFilter.pState = m_modState; + m_modFilter.L = DSTAR_RADIO_BIT_LENGTH; + m_modFilter.phaseLength = DSTAR_GMSK_FILTER_PHASE_LEN; m_modFilter.pCoeffs = DSTAR_GMSK_FILTER; + m_modFilter.pState = m_modState; } void CDStarTX::process() @@ -411,23 +412,22 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const void CDStarTX::writeByte(uint8_t c) { - q15_t inBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; + q15_t inBuffer[8U]; q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; uint8_t mask = 0x01U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 8U; i++, p += DSTAR_RADIO_BIT_LENGTH) { + for (uint8_t i = 0U; i < 8U; i++) { if ((c & mask) == mask) - ::memcpy(p, DSTAR_LEVEL0, DSTAR_RADIO_BIT_LENGTH * sizeof(q15_t)); + inBuffer[i] = DSTAR_LEVEL0; else - ::memcpy(p, DSTAR_LEVEL1, DSTAR_RADIO_BIT_LENGTH * sizeof(q15_t)); + inBuffer[i] = DSTAR_LEVEL1; mask <<= 1; } - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); - + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U); + io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); } diff --git a/DStarTX.h b/DStarTX.h index 17855f8..24876d7 100644 --- a/DStarTX.h +++ b/DStarTX.h @@ -38,13 +38,13 @@ public: uint8_t getSpace() const; private: - CSerialRB m_buffer; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[60U]; // NoTaps + BlockSize - 1, 12 + 40 - 1 plus some spare - uint8_t m_poBuffer[600U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint16_t m_txDelay; // In bytes + CSerialRB m_buffer; + arm_fir_interpolate_instance_q15 m_modFilter; + q15_t m_modState[20U]; // blockSize + phaseLength - 1, 8 + 9 - 1 plus some spare + uint8_t m_poBuffer[600U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; // In bytes void txHeader(const uint8_t* in, uint8_t* out) const; void writeByte(uint8_t c); diff --git a/P25TX.cpp b/P25TX.cpp index 1cb7488..8f92b3c 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -26,13 +26,15 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'normal') in MATLAB +// numTaps = 20, L = 5 static q15_t P25_C4FSK_FILTER[] = {-1392, -2602, -3043, -2238, 0, 3460, 7543, 11400, 14153, 15152, 14153, 11400, 7543, 3460, 0, -2238, -3043, -2602, -1392, 0}; -const uint16_t P25_C4FSK_FILTER_LEN = 20U; +const uint16_t P25_C4FSK_FILTER_PHASE_LEN = 4U; // phaseLength = numTaps/L #else // Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB +// numTaps = 40, L = 5 static q15_t P25_C4FSK_FILTER[] = {-413, -751, -845, -587, 0, 740, 1348, 1520, 1063, 0, -1383, -2583, -3021, -2222, 0, 3435, 7488, 11318, 14053, 15044, 14053, 11318, 7488, 3435, 0, -2222, -3021, -2583, -1383, 0, 1063, 1520, 1348, 740, 0, -587, -845, -751, -413, 0}; -const uint16_t P25_C4FSK_FILTER_LEN = 40U; +const uint16_t P25_C4FSK_FILTER_PHASE_LEN = 8U; // phaseLength = numTaps/L #endif // Generated in MATLAB using the following commands, and then normalised for unity gain @@ -44,10 +46,10 @@ static q15_t P25_LP_FILTER[] = {170, 401, 340, -203, -715, -478, 281, 419, -440, 281, -478, -715, -203, 340, 401, 170}; const uint16_t P25_LP_FILTER_LEN = 44U; -const q15_t P25_LEVELA[] = { 2475, 0, 0, 0, 0}; -const q15_t P25_LEVELB[] = { 825, 0, 0, 0, 0}; -const q15_t P25_LEVELC[] = {-825, 0, 0, 0, 0}; -const q15_t P25_LEVELD[] = {-2475, 0, 0, 0, 0}; +const q15_t P25_LEVELA = 2475; +const q15_t P25_LEVELB = 825; +const q15_t P25_LEVELC = -825; +const q15_t P25_LEVELD = -2475; const uint8_t P25_START_SYNC = 0x77U; @@ -62,12 +64,13 @@ m_poLen(0U), m_poPtr(0U), m_txDelay(240U) // 200ms { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); ::memset(m_lpState, 0x00U, 70U * sizeof(q15_t)); - m_modFilter.numTaps = P25_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + m_modFilter.L = P25_RADIO_SYMBOL_LENGTH; + m_modFilter.phaseLength = P25_C4FSK_FILTER_PHASE_LEN; m_modFilter.pCoeffs = P25_C4FSK_FILTER; + m_modFilter.pState = m_modState; m_lpFilter.numTaps = P25_LP_FILTER_LEN; m_lpFilter.pState = m_lpState; @@ -130,31 +133,30 @@ uint8_t CP25TX::writeData(const uint8_t* data, uint8_t length) void CP25TX::writeByte(uint8_t c) { - q15_t inBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += P25_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, P25_LEVELA, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELA; break; case 0x80U: - ::memcpy(p, P25_LEVELB, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELB; break; case 0x00U: - ::memcpy(p, P25_LEVELC, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELC; break; default: - ::memcpy(p, P25_LEVELD, P25_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = P25_LEVELD; break; } } - ::arm_fir_fast_q15(&m_modFilter, inBuffer, intBuffer, P25_RADIO_SYMBOL_LENGTH * 4U); + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U); ::arm_fir_fast_q15(&m_lpFilter, intBuffer, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U); diff --git a/P25TX.h b/P25TX.h index 99db19d..61f6a87 100644 --- a/P25TX.h +++ b/P25TX.h @@ -36,15 +36,15 @@ public: uint8_t getSpace() const; private: - CSerialRB m_buffer; - arm_fir_instance_q15 m_modFilter; - arm_fir_instance_q15 m_lpFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - q15_t m_lpState[70U]; // NoTaps + BlockSize - 1, 44 + 20 - 1 plus some spare - uint8_t m_poBuffer[1200U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint16_t m_txDelay; + CSerialRB m_buffer; + arm_fir_interpolate_instance_q15 m_modFilter; + arm_fir_instance_q15 m_lpFilter; + q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare + q15_t m_lpState[70U]; // NoTaps + BlockSize - 1, 44 + 20 - 1 plus some spare + uint8_t m_poBuffer[1200U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; void writeByte(uint8_t c); }; diff --git a/YSFTX.cpp b/YSFTX.cpp index b53684b..d1c5d76 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -26,26 +26,26 @@ #if defined(WIDE_C4FSK_FILTERS_TX) // Generated using rcosdesign(0.2, 4, 5, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {688, -680, -2158, -3060, -2724, -775, 2684, 7041, 11310, 14425, 15565, 14425, - 11310, 7041, 2684, -775, -2724, -3060, -2158, -680, 688, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 22U; +static q15_t YSF_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 YSF_C4FSK_FILTER_PHASE_LEN = 5U; // phaseLength = numTaps/L #else // Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB -static q15_t YSF_C4FSK_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, +static q15_t YSF_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, 0}; -const uint16_t YSF_C4FSK_FILTER_LEN = 42U; + -553, -847, -731, -340, 104, 401}; // numTaps = 45, L = 5 +const uint16_t YSF_C4FSK_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L #endif -const q15_t YSF_LEVELA_HI[] = { 4035, 0, 0, 0, 0}; -const q15_t YSF_LEVELB_HI[] = { 1345, 0, 0, 0, 0}; -const q15_t YSF_LEVELC_HI[] = {-1345, 0, 0, 0, 0}; -const q15_t YSF_LEVELD_HI[] = {-4035, 0, 0, 0, 0}; +const q15_t YSF_LEVELA_HI = 4035; +const q15_t YSF_LEVELB_HI = 1345; +const q15_t YSF_LEVELC_HI = -1345; +const q15_t YSF_LEVELD_HI = -4035; -const q15_t YSF_LEVELA_LO[] = { 2019, 0, 0, 0, 0}; -const q15_t YSF_LEVELB_LO[] = { 673, 0, 0, 0, 0}; -const q15_t YSF_LEVELC_LO[] = { -673, 0, 0, 0, 0}; -const q15_t YSF_LEVELD_LO[] = {-2019, 0, 0, 0, 0}; +const q15_t YSF_LEVELA_LO = 2019; +const q15_t YSF_LEVELB_LO = 673; +const q15_t YSF_LEVELC_LO = -673; +const q15_t YSF_LEVELD_LO = -2019; const uint8_t YSF_START_SYNC = 0x77U; const uint8_t YSF_END_SYNC = 0xFFU; @@ -60,11 +60,12 @@ m_poPtr(0U), m_txDelay(240U), // 200ms m_loDev(false) { - ::memset(m_modState, 0x00U, 70U * sizeof(q15_t)); + ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); - m_modFilter.numTaps = YSF_C4FSK_FILTER_LEN; - m_modFilter.pState = m_modState; + m_modFilter.L = YSF_RADIO_SYMBOL_LENGTH; + m_modFilter.phaseLength = YSF_C4FSK_FILTER_PHASE_LEN; m_modFilter.pCoeffs = YSF_C4FSK_FILTER; + m_modFilter.pState = m_modState; } void CYSFTX::process() @@ -121,30 +122,29 @@ uint8_t CYSFTX::writeData(const uint8_t* data, uint8_t length) void CYSFTX::writeByte(uint8_t c) { - q15_t inBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U]; + q15_t inBuffer[4U]; q15_t outBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U]; const uint8_t MASK = 0xC0U; - q15_t* p = inBuffer; - for (uint8_t i = 0U; i < 4U; i++, c <<= 2, p += YSF_RADIO_SYMBOL_LENGTH) { + for (uint8_t i = 0U; i < 4U; i++, c <<= 2) { switch (c & MASK) { case 0xC0U: - ::memcpy(p, m_loDev ? YSF_LEVELA_LO : YSF_LEVELA_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELA_LO : YSF_LEVELA_HI; break; case 0x80U: - ::memcpy(p, m_loDev ? YSF_LEVELB_LO : YSF_LEVELB_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELB_LO : YSF_LEVELB_HI; break; case 0x00U: - ::memcpy(p, m_loDev ? YSF_LEVELC_LO : YSF_LEVELC_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELC_LO : YSF_LEVELC_HI; break; default: - ::memcpy(p, m_loDev ? YSF_LEVELD_LO : YSF_LEVELD_HI, YSF_RADIO_SYMBOL_LENGTH * sizeof(q15_t)); + inBuffer[i] = m_loDev ? YSF_LEVELD_LO : YSF_LEVELD_HI; break; } } - - ::arm_fir_fast_q15(&m_modFilter, inBuffer, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); + + ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U); io.write(STATE_YSF, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); } diff --git a/YSFTX.h b/YSFTX.h index c38cf96..01211a5 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -38,14 +38,14 @@ public: void setLoDev(bool on); private: - CSerialRB m_buffer; - arm_fir_instance_q15 m_modFilter; - q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare - uint8_t m_poBuffer[1200U]; - uint16_t m_poLen; - uint16_t m_poPtr; - uint16_t m_txDelay; - bool m_loDev; + CSerialRB m_buffer; + arm_fir_interpolate_instance_q15 m_modFilter; + q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare + uint8_t m_poBuffer[1200U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; + bool m_loDev; void writeByte(uint8_t c); }; From ab50521f7432a47a85dae89cd327ccb639e1ed93 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sat, 1 Apr 2017 11:52:34 -0300 Subject: [PATCH 21/33] Testing new serial port buffer size for STM32F4 --- SerialSTM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SerialSTM.cpp b/SerialSTM.cpp index b55a946..e69a805 100644 --- a/SerialSTM.cpp +++ b/SerialSTM.cpp @@ -38,8 +38,8 @@ UART5 - TXD PC12 - RXD PD2 (Discovery, Pi and Nucleo with Morpho header) #if defined(STM32F4XX) || defined(STM32F4) -#define TX_SERIAL_FIFO_SIZE 256U -#define RX_SERIAL_FIFO_SIZE 256U +#define TX_SERIAL_FIFO_SIZE 1024U +#define RX_SERIAL_FIFO_SIZE 1024U extern "C" { void USART1_IRQHandler(); From db1c01f4dc9c651e08a8706b8c6f958c1504a45e Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sat, 1 Apr 2017 15:04:05 -0300 Subject: [PATCH 22/33] New serial port buffer size for STM32F4 --- SerialSTM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SerialSTM.cpp b/SerialSTM.cpp index e69a805..8fdb127 100644 --- a/SerialSTM.cpp +++ b/SerialSTM.cpp @@ -38,8 +38,8 @@ UART5 - TXD PC12 - RXD PD2 (Discovery, Pi and Nucleo with Morpho header) #if defined(STM32F4XX) || defined(STM32F4) -#define TX_SERIAL_FIFO_SIZE 1024U -#define RX_SERIAL_FIFO_SIZE 1024U +#define TX_SERIAL_FIFO_SIZE 512U +#define RX_SERIAL_FIFO_SIZE 512U extern "C" { void USART1_IRQHandler(); From fcdbb8cda0fb4d5e6801f68e9599fb6cf308cff1 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sat, 1 Apr 2017 21:52:02 -0300 Subject: [PATCH 23/33] Compensate DMR deviation to match old adjustments (K=0.904) --- DMRDMOTX.cpp | 8 ++++---- DMRTX.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 7dfd8d5..c30f50e 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -36,10 +36,10 @@ static q15_t DMR_C4FSK_FILTER[] = {0, 0, 0, 0, 401, 104, -340, -731, -847, -553, const uint16_t DMR_C4FSK_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L #endif -const q15_t DMR_LEVELA = 3195; -const q15_t DMR_LEVELB = 1065; -const q15_t DMR_LEVELC = -1065; -const q15_t DMR_LEVELD = -3195; +const q15_t DMR_LEVELA = 2889; +const q15_t DMR_LEVELB = 963; +const q15_t DMR_LEVELC = -963; +const q15_t DMR_LEVELD = -2889; const uint8_t CACH_INTERLEAVE[] = {1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U, diff --git a/DMRTX.cpp b/DMRTX.cpp index de7ab7e..e3568e4 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -36,10 +36,10 @@ static q15_t DMR_C4FSK_FILTER[] = {0, 0, 0, 0, 401, 104, -340, -731, -847, -553, const uint16_t DMR_C4FSK_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L #endif -const q15_t DMR_LEVELA = 3195; -const q15_t DMR_LEVELB = 1065; -const q15_t DMR_LEVELC = -1065; -const q15_t DMR_LEVELD = -3195; +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 Data Sync pattern. const uint8_t IDLE_DATA[] = From c0941c4856f150d47df6e338864db5c9d1d7a020 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 2 Apr 2017 13:48:40 +0100 Subject: [PATCH 24/33] Add TX Delay buffer protection. --- DMRDMOTX.cpp | 5 ++++- DMRDMOTX.h | 2 +- DStarTX.cpp | 3 +++ P25TX.cpp | 3 +++ YSFTX.cpp | 3 +++ 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index c30f50e..b0175c8 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -166,7 +166,10 @@ uint8_t CDMRDMOTX::getSpace() const void CDMRDMOTX::setTXDelay(uint8_t delay) { - m_txDelay = 240U + uint16_t(delay) * 12U; // 200ms + tx delay + m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay + + if (m_txDelay > 1200U) + m_txDelay = 1200U; } void CDMRDMOTX::createCACH(uint8_t* buffer, uint8_t slotIndex) diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 022ecd0..98ffdb0 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -42,7 +42,7 @@ private: CSerialRB m_fifo; arm_fir_interpolate_instance_q15 m_modFilter; q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare - uint8_t m_poBuffer[800U]; + uint8_t m_poBuffer[1200U]; uint16_t m_poLen; uint16_t m_poPtr; uint32_t m_txDelay; diff --git a/DStarTX.cpp b/DStarTX.cpp index 4f81574..92fb6d5 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -434,6 +434,9 @@ void CDStarTX::writeByte(uint8_t c) void CDStarTX::setTXDelay(uint8_t delay) { m_txDelay = 300U + uint16_t(delay) * 6U; // 250ms + tx delay + + if (m_txDelay > 600U) + m_txDelay = 600U; } uint8_t CDStarTX::getSpace() const diff --git a/P25TX.cpp b/P25TX.cpp index 8f92b3c..7edbeb5 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -166,6 +166,9 @@ void CP25TX::writeByte(uint8_t c) void CP25TX::setTXDelay(uint8_t delay) { m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay + + if (m_txDelay > 1200U) + m_txDelay = 1200U; } uint8_t CP25TX::getSpace() const diff --git a/YSFTX.cpp b/YSFTX.cpp index d1c5d76..ab3f953 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -152,6 +152,9 @@ void CYSFTX::writeByte(uint8_t c) void CYSFTX::setTXDelay(uint8_t delay) { m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay + + if (m_txDelay > 1200U) + m_txDelay = 1200U; } uint8_t CYSFTX::getSpace() const From bb6a554919ca3c22528f424f4886581c3e0d2628 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sun, 2 Apr 2017 13:13:15 -0300 Subject: [PATCH 25/33] New deviation values for P25 (not tested) --- P25TX.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/P25TX.cpp b/P25TX.cpp index 8f92b3c..0b7f279 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -46,10 +46,10 @@ static q15_t P25_LP_FILTER[] = {170, 401, 340, -203, -715, -478, 281, 419, -440, 281, -478, -715, -203, 340, 401, 170}; const uint16_t P25_LP_FILTER_LEN = 44U; -const q15_t P25_LEVELA = 2475; -const q15_t P25_LEVELB = 825; -const q15_t P25_LEVELC = -825; -const q15_t P25_LEVELD = -2475; +const q15_t P25_LEVELA = 1698; +const q15_t P25_LEVELB = 566; +const q15_t P25_LEVELC = -566; +const q15_t P25_LEVELD = -1698; const uint8_t P25_START_SYNC = 0x77U; From 555197b0a2d8cd6a220ab6981ef9a29851eb4bc7 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sun, 2 Apr 2017 13:13:33 -0300 Subject: [PATCH 26/33] New deviation value for YSF --- YSFTX.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/YSFTX.cpp b/YSFTX.cpp index d1c5d76..e7fb862 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -37,15 +37,15 @@ static q15_t YSF_C4FSK_FILTER[] = {0, 0, 0, 0, 401, 104, -340, -731, -847, -553, const uint16_t YSF_C4FSK_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L #endif -const q15_t YSF_LEVELA_HI = 4035; -const q15_t YSF_LEVELB_HI = 1345; -const q15_t YSF_LEVELC_HI = -1345; -const q15_t YSF_LEVELD_HI = -4035; +const q15_t YSF_LEVELA_HI = 3900; +const q15_t YSF_LEVELB_HI = 1300; +const q15_t YSF_LEVELC_HI = -1300; +const q15_t YSF_LEVELD_HI = -3900; -const q15_t YSF_LEVELA_LO = 2019; -const q15_t YSF_LEVELB_LO = 673; -const q15_t YSF_LEVELC_LO = -673; -const q15_t YSF_LEVELD_LO = -2019; +const q15_t YSF_LEVELA_LO = 1950; +const q15_t YSF_LEVELB_LO = 650; +const q15_t YSF_LEVELC_LO = -650; +const q15_t YSF_LEVELD_LO = -1950; const uint8_t YSF_START_SYNC = 0x77U; const uint8_t YSF_END_SYNC = 0xFFU; From 6f29fe62b1a04749e5b221319d3cc0db2cdfbcf4 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sun, 2 Apr 2017 16:48:50 -0300 Subject: [PATCH 27/33] Fix for Arduino 1.6 compilation error --- system_stm32f1xx/system_stm32f1xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system_stm32f1xx/system_stm32f1xx.c b/system_stm32f1xx/system_stm32f1xx.c index fa46661..dd6c344 100644 --- a/system_stm32f1xx/system_stm32f1xx.c +++ b/system_stm32f1xx/system_stm32f1xx.c @@ -84,6 +84,7 @@ * ****************************************************************************** */ +#if !defined(ARDUINO) /** @addtogroup CMSIS * @{ @@ -220,6 +221,7 @@ static void SetSysClock(void) /** * @} */ - + +#endif /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 7a042c10ad2bfdc173f691ddc1a05eae103274f8 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sun, 2 Apr 2017 18:02:33 -0300 Subject: [PATCH 28/33] Better fix for Arduino IDE compilation error, now including STM32F4 --- system_stm32f1xx/system_stm32f1xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system_stm32f1xx/system_stm32f1xx.c b/system_stm32f1xx/system_stm32f1xx.c index dd6c344..b18e9bf 100644 --- a/system_stm32f1xx/system_stm32f1xx.c +++ b/system_stm32f1xx/system_stm32f1xx.c @@ -84,7 +84,7 @@ * ****************************************************************************** */ -#if !defined(ARDUINO) +#if defined(STM32F105xC) /** @addtogroup CMSIS * @{ From dffc6f0a5a02c65e92d1c3857cd28ef833fd30eb Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sun, 2 Apr 2017 18:03:36 -0300 Subject: [PATCH 29/33] New filter for D-Star, BT=0.35 --- DStarTX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DStarTX.cpp b/DStarTX.cpp index 92fb6d5..5ba86cb 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -28,8 +28,8 @@ const uint8_t BIT_SYNC = 0xAAU; const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U}; -// Generated using gaussfir(0.5, 4, 5) in MATLAB -static q15_t DSTAR_GMSK_FILTER[] = {0, 0, 0, 0, 8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8}; // numTaps = 15, L = 5 +// Generated using gaussfir(0.35, 1, 5) in MATLAB +static q15_t DSTAR_GMSK_FILTER[] = {0, 0, 0, 0, 212, 743, 1974, 3965, 6026, 6929, 6026, 3965, 1974, 743, 212}; // numTaps = 15, L = 5 const uint16_t DSTAR_GMSK_FILTER_PHASE_LEN = 3U; // phaseLength = numTaps/L const q15_t DSTAR_LEVEL0 = -4000; From f2c50083d88646bd7d3657e66dc91dab4ef6199b Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sun, 2 Apr 2017 22:17:09 -0300 Subject: [PATCH 30/33] Adding conditional compilation for Arduino 1.6.7 fix --- system_stm32f1xx/startup_stm32f105xc.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system_stm32f1xx/startup_stm32f105xc.S b/system_stm32f1xx/startup_stm32f105xc.S index a3a7fed..72acb22 100644 --- a/system_stm32f1xx/startup_stm32f105xc.S +++ b/system_stm32f1xx/startup_stm32f105xc.S @@ -30,6 +30,8 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------*/ +#if defined(STM32F105xC) + .syntax unified .arch armv7-m @@ -421,3 +423,5 @@ Default_Handler: def_irq_handler OTG_FS_IRQHandler .end + +#endif From 9d4779e4c3710a461b0f62028dd99413f00b515e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 5 Apr 2017 14:19:25 +0100 Subject: [PATCH 31/33] Put idle into the second DMO slot instead of the repeat of the data. MD380/390 bug workaround. --- DMRDMOTX.cpp | 24 ++++++++++++++++++++++-- DMRDMOTX.h | 4 +++- SerialPort.cpp | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index b0175c8..476fd42 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -41,6 +41,12 @@ const q15_t DMR_LEVELB = 963; const q15_t DMR_LEVELC = -963; const q15_t DMR_LEVELD = -2889; +// The PR FILL and Data Sync pattern. +const uint8_t IDLE_DATA[] = + {0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U, + 0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U, + 0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U}; + const uint8_t CACH_INTERLEAVE[] = {1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U, 25U, 26U, 27U, 29U, 30U, 31U, 33U, 34U, 35U, 37U, 39U, 40U, 41U, 43U, 44U, 45U, 47U, @@ -65,6 +71,7 @@ m_poBuffer(), m_poLen(0U), m_poPtr(0U), m_txDelay(240U), // 200ms +m_idle(), m_cachPtr(0U) { ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); @@ -84,11 +91,15 @@ void CDMRDMOTX::process() m_poLen = m_txDelay; } else { - createCACH(m_poBuffer + 0U, 0U); + createCACH(m_poBuffer + 0U, 0U); + + for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_poBuffer[i + 3U] = m_fifo.get(); + createCACH(m_poBuffer + 36U, 1U); for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i + 3U] = m_poBuffer[i + 39U] = m_fifo.get(); + m_poBuffer[i + 39U] = m_idle[i]; m_poLen = 72U; } @@ -203,3 +214,12 @@ void CDMRDMOTX::createCACH(uint8_t* buffer, uint8_t slotIndex) m_cachPtr += 3U; } + +void CDMRDMOTX::setColorCode(uint8_t colorCode) +{ + ::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES); + + CDMRSlotType slotType; + slotType.encode(colorCode, DT_IDLE, m_idle); +} + diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 98ffdb0..2e49ff7 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -37,8 +37,9 @@ public: uint8_t getSpace() const; -private: + void setColorCode(uint8_t colorCode); +private: CSerialRB m_fifo; arm_fir_interpolate_instance_q15 m_modFilter; q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare @@ -46,6 +47,7 @@ private: uint16_t m_poLen; uint16_t m_poPtr; uint32_t m_txDelay; + uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; uint8_t m_cachPtr; void createCACH(uint8_t* buffer, uint8_t slotIndex); diff --git a/SerialPort.cpp b/SerialPort.cpp index fd2678f..75b99b3 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -273,6 +273,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) dmrTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); dmrRX.setDelay(dmrDelay); + dmrDMOTX.setColorCode(colorCode); dmrDMORX.setColorCode(colorCode); dmrIdleRX.setColorCode(colorCode); From 06ef230ad5754067bdf0f4dd0aa2de874009ae96 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 5 Apr 2017 14:24:29 +0100 Subject: [PATCH 32/33] Reduce the YSF deviations(s) by 10%. --- YSFTX.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/YSFTX.cpp b/YSFTX.cpp index a5a8b92..25ed282 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -37,15 +37,15 @@ static q15_t YSF_C4FSK_FILTER[] = {0, 0, 0, 0, 401, 104, -340, -731, -847, -553, const uint16_t YSF_C4FSK_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L #endif -const q15_t YSF_LEVELA_HI = 3900; -const q15_t YSF_LEVELB_HI = 1300; -const q15_t YSF_LEVELC_HI = -1300; -const q15_t YSF_LEVELD_HI = -3900; +const q15_t YSF_LEVELA_HI = 3510; +const q15_t YSF_LEVELB_HI = 1170; +const q15_t YSF_LEVELC_HI = -1170; +const q15_t YSF_LEVELD_HI = -3510; -const q15_t YSF_LEVELA_LO = 1950; -const q15_t YSF_LEVELB_LO = 650; -const q15_t YSF_LEVELC_LO = -650; -const q15_t YSF_LEVELD_LO = -1950; +const q15_t YSF_LEVELA_LO = 1755; +const q15_t YSF_LEVELB_LO = 585; +const q15_t YSF_LEVELC_LO = -585; +const q15_t YSF_LEVELD_LO = -1755; const uint8_t YSF_START_SYNC = 0x77U; const uint8_t YSF_END_SYNC = 0xFFU; From ee3f2a0e6d03e6b4518c04e530df0c6b75cd41dc Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sun, 9 Apr 2017 14:35:08 -0300 Subject: [PATCH 33/33] Filter for DC level estimation for D-Star --- DStarRX.cpp | 22 ++++++++++++++++++++-- DStarRX.h | 5 ++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/DStarRX.cpp b/DStarRX.cpp index 4ec7199..d4178c0 100644 --- a/DStarRX.cpp +++ b/DStarRX.cpp @@ -35,7 +35,9 @@ const unsigned int SYNC_POS = 21U * DSTAR_DATA_LENGTH_BITS; const unsigned int SYNC_SCAN_START = SYNC_POS - 3U; const unsigned int SYNC_SCAN_END = SYNC_POS + 3U; -const q15_t THRESHOLD = 0; +// Generated using [b, a] = butter(1, 0.002) in MATLAB +static q15_t DC_FILTER[] = {103, 0, 103, 0, 32563, 0}; // {b0, 0, b1, b2, -a1, -a2} +const uint16_t DC_FILTER_STAGES = 1U; // One Biquad stage // D-Star bit order version of 0x55 0x55 0x6E 0x0A const uint32_t FRAME_SYNC_DATA = 0x00557650U; @@ -262,6 +264,12 @@ m_fecOutput(), m_rssiAccum(0U), m_rssiCount(0U) { + ::memset(m_DCState, 0x00U, 4U * sizeof(q15_t)); + + m_DCFilter.numStages = DC_FILTER_STAGES; + m_DCFilter.pState = m_DCState; + m_DCFilter.pCoeffs = DC_FILTER; + m_DCFilter.postShift = 0; } void CDStarRX::reset() @@ -278,11 +286,21 @@ void CDStarRX::reset() void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length) { + q31_t dc_level = 0; + q15_t DCVals[20]; + + ::arm_biquad_cascade_df1_q15(&m_DCFilter, (q15_t*)samples, DCVals, length); + + for (uint8_t i = 0U; i < length; i++) + dc_level += (q31_t)DCVals[i]; + + dc_level /= length; + for (uint16_t i = 0U; i < length; i++) { m_rssiAccum += rssi[i]; m_rssiCount++; - bool bit = samples[i] < THRESHOLD; + bool bit = samples[i] < (q15_t)dc_level; if (bit != m_prev) { if (m_pll < (PLLMAX / 2U)) diff --git a/DStarRX.h b/DStarRX.h index 53d9bdf..b374b44 100644 --- a/DStarRX.h +++ b/DStarRX.h @@ -53,7 +53,10 @@ private: uint8_t m_fecOutput[42U]; uint32_t m_rssiAccum; uint16_t m_rssiCount; - + + arm_biquad_casd_df1_inst_q15 m_DCFilter; + q15_t m_DCState[4]; + void processNone(bool bit); void processHeader(bool bit); void processData(bool bit);