From a49871cd8b0c24d24b2e477aa0817df07e8359fe Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Sat, 1 Apr 2017 01:16:56 -0300 Subject: [PATCH] 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); };