diff --git a/AX25RX.h b/AX25RX.h index 6ab6d1c..3416b81 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -29,6 +29,8 @@ public: void samples(q15_t* samples, uint8_t length); + void setParams(int8_t twist); + private: arm_fir_instance_q15 m_filter; q15_t m_state[160U]; // NoTaps + BlockSize - 1, 132 + 20 - 1 plus some spare diff --git a/AX25TX.h b/AX25TX.h new file mode 100644 index 0000000..ffe31be --- /dev/null +++ b/AX25TX.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(AX25TX_H) +#define AX25TX_H + +#include "Config.h" + +class CAX25TX { +public: + CAX25TX(); + + uint8_t writeData(const uint8_t* data, uint16_t length); + + void process(); + + void setParams(int8_t twist); + + void setTXDelay(uint8_t delay); + + uint8_t getSpace() const; + +private: +}; + +#endif + diff --git a/Globals.h b/Globals.h index 4d25617..045f628 100644 --- a/Globals.h +++ b/Globals.h @@ -98,6 +98,7 @@ enum MMDVM_STATE { #include "CalRSSI.h" #include "CWIdTX.h" #include "AX25RX.h" +#include "AX25TX.h" #include "Debug.h" #include "IO.h" #include "FM.h" @@ -159,6 +160,7 @@ extern CPOCSAGTX pocsagTX; extern CFM fm; extern CAX25RX ax25RX; +extern CAX25TX ax25TX; extern CCalDStarRX calDStarRX; extern CCalDStarTX calDStarTX; diff --git a/IO.cpp b/IO.cpp index 6962f08..27e54b0 100644 --- a/IO.cpp +++ b/IO.cpp @@ -81,6 +81,7 @@ m_p25TXLevel(128 * 128), m_nxdnTXLevel(128 * 128), m_pocsagTXLevel(128 * 128), m_fmTXLevel(128 * 128), +m_ax25TXLevel(128 * 128), m_rxDCOffset(DC_OFFSET), m_txDCOffset(DC_OFFSET), m_ledCount(0U), @@ -489,6 +490,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t case STATE_FM: txLevel = m_fmTXLevel; break; + case STATE_AX25: + txLevel = m_ax25TXLevel; + break; default: txLevel = m_cwIdTXLevel; break; @@ -541,7 +545,7 @@ void CIO::setMode() #endif } -void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset) +void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset) { m_pttInvert = pttInvert; @@ -554,6 +558,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx m_nxdnTXLevel = q15_t(nxdnTXLevel * 128); m_pocsagTXLevel = q15_t(pocsagTXLevel * 128); m_fmTXLevel = q15_t(fmTXLevel * 128); + m_ax25TXLevel = q15_t(ax25TXLevel * 128); m_rxDCOffset = DC_OFFSET + rxDCOffset; m_txDCOffset = DC_OFFSET + txDCOffset; diff --git a/IO.h b/IO.h index 07ed700..d32be95 100644 --- a/IO.h +++ b/IO.h @@ -42,7 +42,7 @@ public: void interrupt(); - void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset); + void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset); void getOverflow(bool& adcOverflow, bool& dacOverflow); @@ -87,6 +87,7 @@ private: q15_t m_nxdnTXLevel; q15_t m_pocsagTXLevel; q15_t m_fmTXLevel; + q15_t m_ax25TXLevel; uint16_t m_rxDCOffset; uint16_t m_txDCOffset; diff --git a/MMDVM.cpp b/MMDVM.cpp index 5b5bc4b..e80cacf 100644 --- a/MMDVM.cpp +++ b/MMDVM.cpp @@ -63,6 +63,7 @@ CPOCSAGTX pocsagTX; CFM fm; CAX25RX ax25RX; +CAX25TX ax25TX; CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; @@ -112,6 +113,9 @@ void loop() if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy())) pocsagTX.process(); + if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM)) + ax25TX.process(); + if (m_fmEnable && m_modemState == STATE_FM) fm.process(); diff --git a/MMDVM.ino b/MMDVM.ino index f1073dd..5785e15 100644 --- a/MMDVM.ino +++ b/MMDVM.ino @@ -60,6 +60,7 @@ CPOCSAGTX pocsagTX; CFM fm; CAX25RX ax25RX; +CAX25 ax25TX; CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; @@ -109,6 +110,9 @@ void loop() if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy())) pocsagTX.process(); + if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM)) + ax25TX.process(); + if (m_fmEnable && m_modemState == STATE_FM) fm.process(); diff --git a/SerialPort.cpp b/SerialPort.cpp index 8918dff..e8c09b1 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -105,7 +105,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200617 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200621 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -244,7 +244,12 @@ void CSerialPort::getStatus() else reply[12U] = 0U; - writeInt(1U, reply, 13); + if (m_ax25Enable) + reply[13U] = ax25TX.getSpace(); + else + reply[13U] = 0U; + + writeInt(1U, reply, 14); } void CSerialPort::getVersion() @@ -268,7 +273,7 @@ void CSerialPort::getVersion() uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) { - if (length < 21U) + if (length < 24U) return 4U; bool rxInvert = (data[0U] & 0x01U) == 0x01U; @@ -340,6 +345,16 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) uint8_t nxdnTXHang = data[20U]; + uint8_t ax25TXLevel = data[21U]; + + int8_t ax25RXTwist = int8_t(data[22U]) - 128; + if (ax25RXTwist < -4 || ax25RXTwist > 10) + return 4U; + + int8_t ax25TXTwist = int8_t(data[23U]) - 128; + if (ax25TXTwist < -4 || ax25TXTwist > 10) + return 4U; + setMode(modemState); m_dstarEnable = dstarEnable; @@ -358,6 +373,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) dmrDMOTX.setTXDelay(txDelay); nxdnTX.setTXDelay(txDelay); pocsagTX.setTXDelay(txDelay); + ax25TX.setTXDelay(txDelay); dmrTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); @@ -368,8 +384,10 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) ysfTX.setParams(ysfLoDev, ysfTXHang); p25TX.setParams(p25TXHang); nxdnTX.setParams(nxdnTXHang); + ax25RX.setParams(ax25RXTwist); + ax25TX.setParams(ax25TXTwist); - io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, txDCOffset, rxDCOffset); + io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset); io.start(); @@ -936,6 +954,17 @@ void CSerialPort::processMessage(const uint8_t* buffer, uint16_t length) } break; + case MMDVM_AX25_DATA: + if (m_ax25Enable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_FM) + err = ax25TX.writeData(buffer, length); + } + if (err != 0U) { + DEBUG2("Received invalid AX.25 data", err); + sendNAK(err); + } + break; + case MMDVM_TRANSPARENT: case MMDVM_QSO_INFO: // Do nothing on the MMDVM.