From 3788ad540f30ce8d904eb4414b23fd489bfc9e6f Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 01:52:34 -0300 Subject: [PATCH] Add NXDN, first commit --- Globals.h | 7 +++ MMDVM_HS.cpp | 7 +++ MMDVM_HS.ino | 7 +++ NXDNDefines.h | 50 ++++++++++++++++++ NXDNRX.cpp | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ NXDNRX.h | 54 +++++++++++++++++++ NXDNTX.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++ NXDNTX.h | 50 ++++++++++++++++++ SerialPort.cpp | 84 ++++++++++++++++++++++++++++-- SerialPort.h | 6 ++- 10 files changed, 518 insertions(+), 6 deletions(-) create mode 100644 NXDNDefines.h create mode 100644 NXDNRX.cpp create mode 100644 NXDNRX.h create mode 100644 NXDNTX.cpp create mode 100644 NXDNTX.h diff --git a/Globals.h b/Globals.h index 06b3c19..8549e1b 100644 --- a/Globals.h +++ b/Globals.h @@ -33,6 +33,7 @@ enum MMDVM_STATE { STATE_DMR = 2, STATE_YSF = 3, STATE_P25 = 4, + STATE_NXDN = 5, // Dummy states start at 90 STATE_CWID = 97 @@ -62,6 +63,8 @@ const uint8_t MARK_NONE = 0x00U; #include "YSFTX.h" #include "P25RX.h" #include "P25TX.h" +#include "NXDNRX.h" +#include "NXDNTX.h" #include "CWIdTX.h" #include "Debug.h" #include "Utils.h" @@ -81,6 +84,7 @@ extern bool m_dstarEnable; extern bool m_dmrEnable; extern bool m_ysfEnable; extern bool m_p25Enable; +extern bool m_nxdnEnable; extern bool m_duplex; @@ -110,6 +114,9 @@ extern CYSFTX ysfTX; extern CP25RX p25RX; extern CP25TX p25TX; +extern CNXDNRX nxdnRX; +extern CNXDNTX nxdnTX; + extern CCWIdTX cwIdTX; #endif diff --git a/MMDVM_HS.cpp b/MMDVM_HS.cpp index 5aa9086..629a816 100644 --- a/MMDVM_HS.cpp +++ b/MMDVM_HS.cpp @@ -38,6 +38,7 @@ bool m_dstarEnable = true; bool m_dmrEnable = true; bool m_ysfEnable = true; bool m_p25Enable = true; +bool m_nxdnEnable = true; bool m_duplex = false; @@ -64,6 +65,9 @@ CYSFTX ysfTX; CP25RX p25RX; CP25TX p25TX; +CNXDNRX nxdnRX; +CNXDNTX nxdnTX; + CCWIdTX cwIdTX; CSerialPort serial; @@ -101,6 +105,9 @@ void loop() if (m_p25Enable && m_modemState == STATE_P25) p25TX.process(); + if (m_nxdnEnable && m_modemState == STATE_NXDN) + nxdnTX.process(); + if (m_modemState == STATE_IDLE) cwIdTX.process(); } diff --git a/MMDVM_HS.ino b/MMDVM_HS.ino index 7e3269c..0ae28c2 100644 --- a/MMDVM_HS.ino +++ b/MMDVM_HS.ino @@ -34,6 +34,7 @@ bool m_dstarEnable = true; bool m_dmrEnable = true; bool m_ysfEnable = true; bool m_p25Enable = true; +bool m_nxdnEnable = true; bool m_duplex = false; @@ -60,6 +61,9 @@ CYSFTX ysfTX; CP25RX p25RX; CP25TX p25TX; +CNXDNRX nxdnRX; +CNXDNTX nxdnTX; + CCWIdTX cwIdTX; CSerialPort serial; @@ -96,6 +100,9 @@ void loop() if (m_p25Enable && m_modemState == STATE_P25) p25TX.process(); + if (m_nxdnEnable && m_modemState == STATE_NXDN) + nxdnTX.process(); + if (m_modemState == STATE_IDLE) cwIdTX.process(); } diff --git a/NXDNDefines.h b/NXDNDefines.h new file mode 100644 index 0000000..a98166f --- /dev/null +++ b/NXDNDefines.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016,2017,2018 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(NXDNDEFINES_H) +#define NXDNDEFINES_H + +const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate + +const unsigned int NXDN_FRAME_LENGTH_BITS = 384U; +const unsigned int NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U; +const unsigned int NXDN_FRAME_LENGTH_SYMBOLS = NXDN_FRAME_LENGTH_BITS / 2U; +const unsigned int NXDN_FRAME_LENGTH_SAMPLES = NXDN_FRAME_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH; + +const unsigned int NXDN_FSW_LENGTH_BITS = 20U; +const unsigned int NXDN_FSW_LENGTH_SYMBOLS = NXDN_FSW_LENGTH_BITS / 2U; +const unsigned int NXDN_FSW_LENGTH_SAMPLES = NXDN_FSW_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH; + +const uint8_t NXDN_FSW_BYTES[] = {0xCDU, 0xF5U, 0x90U}; +const uint8_t NXDN_FSW_BYTES_MASK[] = {0xFFU, 0xFFU, 0xF0U}; +const uint8_t NXDN_FSW_BYTES_LENGTH = 3U; + +const uint32_t NXDN_FSW_BITS = 0x000CDF59U; +const uint32_t NXDN_FSW_BITS_MASK = 0x000FFFFFU; + +// C D F 5 9 +// 11 00 11 01 11 11 01 01 10 01 +// -3 +1 -3 +3 -3 -3 +3 +3 -1 +3 + +const int8_t NXDN_FSW_SYMBOLS_VALUES[] = {-3, +1, -3, +3, -3, -3, +3, +3, -1, +3}; + +const uint16_t NXDN_FSW_SYMBOLS = 0x014DU; +const uint16_t NXDN_FSW_SYMBOLS_MASK = 0x03FFU; + +#endif + diff --git a/NXDNRX.cpp b/NXDNRX.cpp new file mode 100644 index 0000000..5eb1724 --- /dev/null +++ b/NXDNRX.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009-2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU + * + * 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. + */ + +#include "Config.h" +#include "Globals.h" +#include "NXDNRX.h" +#include "Utils.h" + +const uint8_t MAX_FSW_BIT_START_ERRS = 1U; +const uint8_t MAX_FSW_BIT_RUN_ERRS = 3U; + +const unsigned int MAX_FSW_FRAMES = 5U + 1U; + +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]) + +CNXDNRX::CNXDNRX() : +m_prev(false), +m_state(NXDNRXS_NONE), +m_bitBuffer(0x00U), +m_outBuffer(), +m_buffer(NULL), +m_bufferPtr(0U), +m_lostCount(0U) +{ + m_buffer = m_outBuffer + 1U; +} + +void CNXDNRX::reset() +{ + m_prev = false; + m_state = NXDNRXS_NONE; + m_bitBuffer = 0x00U; + m_bufferPtr = 0U; + m_lostCount = 0U; +} + +void CNXDNRX::databit(bool bit) +{ + if (m_state == NXDNRXS_NONE) + processNone(bit); + else + processData(bit); +} + +void CNXDNRX::processNone(bool bit) +{ + m_bitBuffer <<= 1; + if (bit) + m_bitBuffer |= 0x01U; + + // Fuzzy matching of the data sync bit sequence + if (countBits64((m_bitBuffer & NXDN_FSW_BITS_MASK) ^ NXDN_FSW_BITS) <= MAX_FSW_BIT_START_ERRS) { + DEBUG1("NXDNRX: sync found in None"); + for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++) + m_buffer[i] = NXDN_FSW_BYTES[i]; + + m_lostCount = MAX_FSW_FRAMES; + m_bufferPtr = NXDN_FSW_LENGTH_BITS; + m_state = NXDNRXS_DATA; + + io.setDecode(true); + + } + +} + +void CNXDNRX::processData(bool bit) +{ + m_bitBuffer <<= 1; + if (bit) + m_bitBuffer |= 0x01U; + + WRITE_BIT1(m_buffer, m_bufferPtr, bit); + m_bufferPtr++; + + // Only search for a sync in the right place +-2 symbols + if (m_bufferPtr >= (NXDN_FSW_LENGTH_BITS - 2U) && m_bufferPtr <= (NXDN_FSW_LENGTH_BITS + 2U)) { + // Fuzzy matching of the data sync bit sequence + if (countBits64((m_bitBuffer & NXDN_FSW_BITS_MASK) ^ NXDN_FSW_BITS) <= MAX_FSW_BIT_RUN_ERRS) { + DEBUG2("NXDNRX: found sync in Data, pos", m_bufferPtr - NXDN_FSW_LENGTH_BITS); + m_lostCount = MAX_FSW_FRAMES; + m_bufferPtr = NXDN_FSW_LENGTH_BITS; + } + } + + // Send a data frame to the host if the required number of bits have been received + if (m_bufferPtr == NXDN_FRAME_LENGTH_BITS) { + // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE + m_lostCount--; + if (m_lostCount == 0U) { + DEBUG1("NXDNRX: sync timed out, lost lock"); + io.setDecode(false); + + serial.writeNXDNLost(); + + m_state = NXDNRXS_NONE; + } else { + m_outBuffer[0U] = m_lostCount == (MAX_FSW_FRAMES - 1U) ? 0x01U : 0x00U; + + writeRSSIData(m_outBuffer); + + // Start the next frame + ::memset(m_outBuffer, 0x00U, NXDN_FRAME_LENGTH_BYTES + 3U); + m_bufferPtr = 0U; + } + } +} + +void CNXDNRX::writeRSSIData(uint8_t* data) +{ +#if defined(SEND_RSSI_DATA) + uint16_t rssi = io.readRSSI(); + + data[49U] = (rssi >> 8) & 0xFFU; + data[50U] = (rssi >> 0) & 0xFFU; + + serial.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 3U); +#else + serial.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 1U); +#endif +} diff --git a/NXDNRX.h b/NXDNRX.h new file mode 100644 index 0000000..9b3e1cf --- /dev/null +++ b/NXDNRX.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU + * + * 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(NXDNRX_H) +#define NXDNRX_H + +#include "NXDNDefines.h" + +enum NXDNRX_STATE { + NXDNRXS_NONE, + NXDNRXS_DATA +}; + +class CNXDNRX { +public: + CNXDNRX(); + + void databit(bool bit); + + void reset(); + +private: + bool m_prev; + NXDNRX_STATE m_state; + uint64_t m_bitBuffer; + uint8_t m_outBuffer[NXDN_FRAME_LENGTH_BYTES + 3U]; + uint8_t* m_buffer; + uint16_t m_bufferPtr; + uint16_t m_lostCount; + + void processNone(bool bit); + void processData(bool bit); + void writeRSSIData(uint8_t* data); + +}; + +#endif + diff --git a/NXDNTX.cpp b/NXDNTX.cpp new file mode 100644 index 0000000..71c7753 --- /dev/null +++ b/NXDNTX.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2009-2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU + * + * 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. + */ + +#include "Config.h" +#include "Globals.h" +#include "NXDNTX.h" + +#include "NXDNDefines.h" + +const uint8_t NXDN_PREAMBLE[] = {0x57U, 0x75U, 0xFDU}; +const uint8_t NXDN_SYNC = 0x5FU; + +CNXDNTX::CNXDNTX() : +m_buffer(1500U), +m_poBuffer(), +m_poLen(0U), +m_poPtr(0U), +m_txDelay(240U), // 200ms +m_count(0U) +{ +} + +void CNXDNTX::process() +{ + if (m_buffer.getData() == 0U && m_poLen == 0U) + return; + + if (m_poLen == 0U) { + if (!m_tx) { + m_delay = true; + m_count = 0U; + m_poLen = m_txDelay; + } else { + m_delay = false; + for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) + m_poBuffer[m_poLen++] = m_buffer.get(); + } + + m_poPtr = 0U; + } + + if (m_poLen > 0U) { + uint16_t space = io.getSpace(); + + while (space > 8U) { + if (m_delay) { + m_poPtr++; + writeByte(NXDN_SYNC); + } + else + writeByte(m_poBuffer[m_poPtr++]); + + space -= 8U; + + if (m_poPtr >= m_poLen) { + m_poPtr = 0U; + m_poLen = 0U; + m_delay = false; + return; + } + } + } +} + +uint8_t CNXDNTX::writeData(const uint8_t* data, uint8_t length) +{ + if (length != (NXDN_FRAME_LENGTH_BYTES + 1U)) + return 4U; + + uint16_t space = m_buffer.getSpace(); + if (space < NXDN_FRAME_LENGTH_BYTES) + return 5U; + + for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) + m_buffer.put(data[i + 1U]); + + return 0U; +} + +void CNXDNTX::writeByte(uint8_t c) +{ + uint8_t bit; + uint8_t mask = 0x80U; + + for (uint8_t i = 0U; i < 8U; i++, c <<= 1) { + if ((c & mask) == mask) + bit = 1U; + else + bit = 0U; + + io.write(&bit, 1); + } +} + +void CNXDNTX::setTXDelay(uint8_t delay) +{ + m_txDelay = 300U + uint16_t(delay) * 6U; // 500ms + tx delay +} + +uint16_t CNXDNTX::getSpace() const +{ + return m_buffer.getSpace() / NXDN_FRAME_LENGTH_BYTES; +} + diff --git a/NXDNTX.h b/NXDNTX.h new file mode 100644 index 0000000..cefe27d --- /dev/null +++ b/NXDNTX.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU + * + * 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(NXDNTX_H) +#define NXDNTX_H + +#include "SerialRB.h" + +class CNXDNTX { +public: + CNXDNTX(); + + uint8_t writeData(const uint8_t* data, uint8_t length); + + void process(); + + void setTXDelay(uint8_t delay); + + uint16_t getSpace() const; + +private: + CSerialRB m_buffer; + uint8_t m_poBuffer[60U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; + uint32_t m_count; + bool m_delay; + + void writeByte(uint8_t c); +}; + +#endif + diff --git a/SerialPort.cpp b/SerialPort.cpp index 5d86f05..f6881de 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -1,7 +1,7 @@ /* - * Copyright (C) 2013,2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2013,2015,2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * * 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 @@ -55,6 +55,9 @@ const uint8_t MMDVM_P25_HDR = 0x30U; const uint8_t MMDVM_P25_LDU = 0x31U; const uint8_t MMDVM_P25_LOST = 0x32U; +const uint8_t MMDVM_NXDN_DATA = 0x40U; +const uint8_t MMDVM_NXDN_LOST = 0x41U; + const uint8_t MMDVM_ACK = 0x70U; const uint8_t MMDVM_NAK = 0x7FU; @@ -201,6 +204,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) bool dmrEnable = (data[1U] & 0x02U) == 0x02U; bool ysfEnable = (data[1U] & 0x04U) == 0x04U; bool p25Enable = (data[1U] & 0x08U) == 0x08U; + bool nxdnEnable = (data[1U] & 0x10U) == 0x10U; uint8_t txDelay = data[2U]; if (txDelay > 50U) @@ -208,7 +212,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) MMDVM_STATE modemState = MMDVM_STATE(data[3U]); - if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25) + if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN) return 4U; if (modemState == STATE_DSTAR && !dstarEnable) return 4U; @@ -218,6 +222,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) return 4U; if (modemState == STATE_P25 && !p25Enable) return 4U; + if (modemState == STATE_NXDN && !nxdnEnable) + return 4U; uint8_t colorCode = data[6U]; if (colorCode > 15U) @@ -279,7 +285,7 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length) if (modemState == m_modemState) return 0U; - if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25) + if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN) return 4U; if (modemState == STATE_DSTAR && !m_dstarEnable) return 4U; @@ -289,7 +295,9 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length) return 4U; if (modemState == STATE_P25 && !m_p25Enable) return 4U; - + if (modemState == STATE_NXDN && !m_nxdnEnable) + return 4U; + setMode(modemState); return 0U; @@ -367,6 +375,18 @@ void CSerialPort::setMode(MMDVM_STATE modemState) ysfRX.reset(); cwIdTX.reset(); break; + case STATE_NXDN: + DEBUG1("Mode set to NXDN"); +#if defined(DUPLEX) + dmrIdleRX.reset(); + dmrRX.reset(); +#endif + dmrDMORX.reset(); + dstarRX.reset(); + ysfRX.reset(); + p25RX.reset(); + cwIdTX.reset(); + break; default: DEBUG1("Mode set to Idle"); // STATE_IDLE @@ -639,6 +659,20 @@ void CSerialPort::process() } break; + case MMDVM_NXDN_DATA: + if (m_nxdnEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN) + err = nxdnTX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_NXDN); + } else { + DEBUG2("Received invalid NXDN data", err); + sendNAK(err); + } + break; + #if defined(SERIAL_REPEATER) || defined(SERIAL_REPEATER_USART1) case MMDVM_SERIAL: writeInt(3U, m_buffer + 3U, m_len - 3U); @@ -891,6 +925,46 @@ void CSerialPort::writeP25Lost() writeInt(1U, reply, 3); } +void CSerialPort::writeNXDNData(const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_NXDN && m_modemState != STATE_IDLE) + return; + + if (!m_nxdnEnable) + return; + + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_NXDN_DATA; + + uint8_t count = 3U; + for (uint8_t i = 0U; i < length; i++, count++) + reply[count] = data[i]; + + reply[1U] = count; + + writeInt(1U, reply, count); +} + +void CSerialPort::writeNXDNLost() +{ + if (m_modemState != STATE_NXDN && m_modemState != STATE_IDLE) + return; + + if (!m_nxdnEnable) + return; + + uint8_t reply[3U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 3U; + reply[2U] = MMDVM_NXDN_LOST; + + writeInt(1U, reply, 3); +} + void CSerialPort::writeDebug(const char* text) { if (!m_debug) diff --git a/SerialPort.h b/SerialPort.h index e771591..2ee9765 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2018 by Andy Uribe CA6JAU * * 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 @@ -44,6 +45,9 @@ public: void writeP25Ldu(const uint8_t* data, uint8_t length); void writeP25Lost(); + void writeNXDNData(const uint8_t* data, uint8_t length); + void writeNXDNLost(); + void writeDebug(const char* text); void writeDebug(const char* text, int16_t n1); void writeDebugI(const char* text, int32_t n1);