diff --git a/SerialPort.cpp b/SerialPort.cpp index e6ec9d2..9aa0954 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -228,7 +228,7 @@ void CSerialPort::getVersion() uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) { - if (length < 16U) + if (length < 17U) return 4U; bool rxInvert = (data[0U] & 0x01U) == 0x01U; @@ -283,6 +283,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) uint8_t nxdnTXLevel = data[15U]; + uint8_t ysfTXHang = data[16U]; + m_modemState = modemState; m_dstarEnable = dstarEnable; @@ -304,7 +306,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) dmrDMORX.setColorCode(colorCode); dmrIdleRX.setColorCode(colorCode); - ysfTX.setLoDev(ysfLoDev); + ysfTX.setParams(ysfLoDev, ysfTXHang); io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, txDCOffset, rxDCOffset); diff --git a/YSFTX.cpp b/YSFTX.cpp index 65ee21a..5790334 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2018 by Jonathan Naylor G4KLX * Copyright (C) 2017 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify @@ -41,6 +41,7 @@ const q15_t YSF_LEVELD_LO = -948; const uint8_t YSF_START_SYNC = 0x77U; const uint8_t YSF_END_SYNC = 0xFFU; +const uint8_t YSF_HANG = 0x00U; CYSFTX::CYSFTX() : m_buffer(4000U), @@ -50,7 +51,9 @@ m_poBuffer(), m_poLen(0U), m_poPtr(0U), m_txDelay(240U), // 200ms -m_loDev(false) +m_loDev(false), +m_txHang(4800U), // 4s +m_txCount(0U) { ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); @@ -60,12 +63,14 @@ m_loDev(false) m_modFilter.pState = m_modState; } + void CYSFTX::process() { - if (m_buffer.getData() == 0U && m_poLen == 0U) + if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U) return; - if (m_poLen == 0U) { + // If we have YSF data to transmit, do so. + if (m_poLen == 0U && m_buffer.getData() > 0U) { if (!m_tx) { for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = YSF_START_SYNC; @@ -80,20 +85,37 @@ void CYSFTX::process() } if (m_poLen > 0U) { + // Transmit YSF data. uint16_t space = io.getSpace(); - + while (space > (4U * YSF_RADIO_SYMBOL_LENGTH)) { uint8_t c = m_poBuffer[m_poPtr++]; writeByte(c); + // Reduce space and reset the hang timer. space -= 4U * YSF_RADIO_SYMBOL_LENGTH; - + if (m_duplex) + m_txCount = m_txHang; + if (m_poPtr >= m_poLen) { m_poPtr = 0U; m_poLen = 0U; return; } } + } else if (m_txCount > 0U) { + // Transmit silence until the hang timer has expired. + uint16_t space = io.getSpace(); + + while (space > (4U * YSF_RADIO_SYMBOL_LENGTH)) { + writeSilence(); + + space -= 4U * YSF_RADIO_SYMBOL_LENGTH; + m_txCount--; + + if (m_txCount == 0U) + return; + } } } @@ -141,6 +163,16 @@ void CYSFTX::writeByte(uint8_t c) io.write(STATE_YSF, outBuffer, YSF_RADIO_SYMBOL_LENGTH * 4U); } +void CYSFTX::writeSilence() +{ + q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U}; + q15_t 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); +} + void CYSFTX::setTXDelay(uint8_t delay) { m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay @@ -154,8 +186,9 @@ uint8_t CYSFTX::getSpace() const return m_buffer.getSpace() / YSF_FRAME_LENGTH_BYTES; } -void CYSFTX::setLoDev(bool on) +void CYSFTX::setParams(bool on, uint8_t txHang) { - m_loDev = on; + m_loDev = on; + m_txHang = txHang * 1200U; } diff --git a/YSFTX.h b/YSFTX.h index 01211a5..647767c 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -35,7 +35,7 @@ public: uint8_t getSpace() const; - void setLoDev(bool on); + void setParams(bool on, uint8_t txHang); private: CSerialRB m_buffer; @@ -46,8 +46,11 @@ private: uint16_t m_poPtr; uint16_t m_txDelay; bool m_loDev; + uint32_t m_txHang; + uint32_t m_txCount; void writeByte(uint8_t c); + void writeSilence(); }; #endif