From 3788ad540f30ce8d904eb4414b23fd489bfc9e6f Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 01:52:34 -0300 Subject: [PATCH 01/13] 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); From f1fe27940873d728106afb102fe16018dec873fb Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 11:36:40 -0300 Subject: [PATCH 02/13] Add PA8 as NXDN LED pin for all boards --- IO.h | 1 + IOArduino.cpp | 10 ++++++++++ IOSTM.cpp | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/IO.h b/IO.h index a52db83..51c19c3 100644 --- a/IO.h +++ b/IO.h @@ -75,6 +75,7 @@ public: void DMR_pin(bool on); void YSF_pin(bool on); void P25_pin(bool on); + void NXDN_pin(bool on); void COS_pin(bool on); void interrupt(void); #if defined(DUPLEX) diff --git a/IOArduino.cpp b/IOArduino.cpp index cc80f8f..d31a3c1 100644 --- a/IOArduino.cpp +++ b/IOArduino.cpp @@ -47,6 +47,7 @@ #define PIN_DMR_LED PB13 #define PIN_YSF_LED PB1 #define PIN_P25_LED PB0 +#define PIN_NXDN_LED PA8 #define PIN_PTT_LED PB14 #define PIN_COS_LED PB15 @@ -69,6 +70,7 @@ #define PIN_DMR_LED PB13 #define PIN_YSF_LED PB1 #define PIN_P25_LED PB0 +#define PIN_NXDN_LED PA8 #define PIN_PTT_LED PB14 #define PIN_COS_LED PB15 @@ -93,6 +95,7 @@ #define PIN_DMR_LED 17 #define PIN_YSF_LED 18 #define PIN_P25_LED 19 +#define PIN_NXDN_LED 20 #define PIN_PTT_LED 14 #define PIN_COS_LED 15 @@ -113,6 +116,7 @@ #define PIN_DMR_LED 15 #define PIN_YSF_LED 16 #define PIN_P25_LED 17 +#define PIN_NXDN_LED 18 #define PIN_PTT_LED 9 #define PIN_COS_LED 10 @@ -163,6 +167,7 @@ void CIO::Init() pinMode(PIN_DMR_LED, OUTPUT); pinMode(PIN_YSF_LED, OUTPUT); pinMode(PIN_P25_LED, OUTPUT); + pinMode(PIN_NXDN_LED, OUTPUT); pinMode(PIN_PTT_LED, OUTPUT); pinMode(PIN_COS_LED, OUTPUT); @@ -306,6 +311,11 @@ void CIO::P25_pin(bool on) digitalWrite(PIN_P25_LED, on ? HIGH : LOW); } +void CIO::NXDN_pin(bool on) +{ + digitalWrite(PIN_NXDN_LED, on ? HIGH : LOW); +} + void CIO::PTT_pin(bool on) { digitalWrite(PIN_PTT_LED, on ? HIGH : LOW); diff --git a/IOSTM.cpp b/IOSTM.cpp index af0fc74..d2bd437 100644 --- a/IOSTM.cpp +++ b/IOSTM.cpp @@ -80,6 +80,9 @@ #define PIN_P25_LED GPIO_Pin_12 #define PORT_P25_LED GPIOA +#define PIN_NXDN_LED GPIO_Pin_8 +#define PORT_NXDN_LED GPIOA + #define PIN_PTT_LED GPIO_Pin_12 #define PORT_PTT_LED GPIOB @@ -140,6 +143,9 @@ #define PIN_P25_LED GPIO_Pin_0 #define PORT_P25_LED GPIOB +#define PIN_NXDN_LED GPIO_Pin_8 +#define PORT_NXDN_LED GPIOA + #define PIN_PTT_LED GPIO_Pin_14 #define PORT_PTT_LED GPIOB @@ -209,6 +215,9 @@ #define PIN_P25_LED GPIO_Pin_0 #define PORT_P25_LED GPIOB +#define PIN_NXDN_LED GPIO_Pin_8 +#define PORT_NXDN_LED GPIOA + #define PIN_PTT_LED GPIO_Pin_14 #define PORT_PTT_LED GPIOB @@ -413,6 +422,12 @@ void CIO::Init() GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(PORT_P25_LED, &GPIO_InitStruct); + // NXDN LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_NXDN_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_NXDN_LED, &GPIO_InitStruct); + // PTT LED GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Pin = PIN_PTT_LED; @@ -627,6 +642,11 @@ void CIO::P25_pin(bool on) GPIO_WriteBit(PORT_P25_LED, PIN_P25_LED, on ? Bit_SET : Bit_RESET); } +void CIO::NXDN_pin(bool on) +{ + GPIO_WriteBit(PORT_NXDN_LED, PIN_NXDN_LED, on ? Bit_SET : Bit_RESET); +} + void CIO::PTT_pin(bool on) { GPIO_WriteBit(PORT_PTT_LED, PIN_PTT_LED, on ? Bit_SET : Bit_RESET); From ae4431c884060cdba2ef96e71d16c6260bb301ba Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 13:30:06 -0300 Subject: [PATCH 03/13] Add dummy register values for ADF7021 --- ADF7021.cpp | 6 ++++++ ADF7021.h | 24 +++++++++++++++++++++++- IO.h | 5 +++-- Utils.cpp | 1 + Utils.h | 1 + 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/ADF7021.cpp b/ADF7021.cpp index dc4fa24..d5ebf54 100644 --- a/ADF7021.cpp +++ b/ADF7021.cpp @@ -865,6 +865,11 @@ uint16_t CIO::devP25() return (uint16_t)((ADF7021_PFD * ADF7021_DEV_P25) / (f_div * 65536)); } +uint16_t CIO::devNXDN() +{ + return (uint16_t)((ADF7021_PFD * ADF7021_DEV_NXDN) / (f_div * 65536)); +} + void CIO::printConf() { DEBUG1("MMDVM_HS FW configuration:"); @@ -876,6 +881,7 @@ void CIO::printConf() DEBUG2("YSF_H +1 sym dev (Hz):", devYSF_H()); DEBUG2("YSF_L +1 sym dev (Hz):", devYSF_L()); DEBUG2("P25 +1 sym dev (Hz):", devP25()); + DEBUG2("NXDN +1 sym dev (Hz):", devNXDN()); } #endif diff --git a/ADF7021.h b/ADF7021.h index 1b10245..4e1881b 100644 --- a/ADF7021.h +++ b/ADF7021.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 by Jim McLaughlin KI6ZUM - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * Copyright (C) 2017 by Danilo DB4PLE * * Some of the code is based on work of Guus Van Dooren PE1PLM: @@ -84,6 +84,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #else #define ADF7021_DEV_P25 22U #endif +#define ADF7021_DEV_NXDN 22U // TX/RX CLOCK register (REG 03) #define ADF7021_REG3_DSTAR 0x2A4C4193 @@ -92,11 +93,13 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_REG3_YSF_L 0x2A4C04D3 #define ADF7021_REG3_YSF_H 0x2A4C0493 #define ADF7021_REG3_P25 0x2A4C04D3 +#define ADF7021_REG3_NXDN 0x2A4C04D3 #else #define ADF7021_REG3_DMR 0x2A4C80D3 #define ADF7021_REG3_YSF_L 0x2A4C80D3 #define ADF7021_REG3_YSF_H 0x2A4CC093 #define ADF7021_REG3_P25 0x2A4C80D3 +#define ADF7021_REG3_NXDN 0x2A4C80D3 #endif // Discriminator bandwith, demodulator (REG 04) @@ -106,12 +109,14 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_DISC_BW_YSF_L 393U // K=32 #define ADF7021_DISC_BW_YSF_H 516U // K=28 #define ADF7021_DISC_BW_P25 394U // K=32 +#define ADF7021_DISC_BW_NXDN 394U // K=32 // Post demodulator bandwith (REG 04) #define ADF7021_POST_BW_DSTAR 10U #define ADF7021_POST_BW_DMR 150U #define ADF7021_POST_BW_YSF 20U #define ADF7021_POST_BW_P25 6U +#define ADF7021_POST_BW_NXDN 6U // IF filter (REG 05) #define ADF7021_REG5 0x000024F5 @@ -126,22 +131,27 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_REG10_DMR 0x01FE473A #define ADF7021_REG10_YSF 0x01FE473A #define ADF7021_REG10_P25 0x01FE473A +#define ADF7021_REG10_NXDN 0x01FE473A #if defined(ADF7021_AFC_POS) #define AFC_OFFSET_DMR -250 #define AFC_OFFSET_YSF -250 #define AFC_OFFSET_P25 -250 +#define AFC_OFFSET_NXDN -250 #else #define AFC_OFFSET_DMR 250 #define AFC_OFFSET_YSF 250 #define AFC_OFFSET_P25 250 +#define AFC_OFFSET_NXDN 250 #endif #else #define ADF7021_REG10_DMR 0x049E472A #define ADF7021_REG10_YSF 0x049E472A #define ADF7021_REG10_P25 0x049E472A +#define ADF7021_REG10_NXDN 0x049E472A #define AFC_OFFSET_DMR 0 #define AFC_OFFSET_YSF 0 #define AFC_OFFSET_P25 0 +#define AFC_OFFSET_NXDN 0 #endif /****** Support for 12.2880 MHz TCXO ******/ @@ -168,6 +178,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #else #define ADF7021_DEV_P25 13U #endif +#define ADF7021_DEV_NXDN 13U // TX/RX CLOCK register (REG 03) #define ADF7021_REG3_DSTAR 0x29EC4153 @@ -176,11 +187,13 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_REG3_YSF_L 0x29EC0493 #define ADF7021_REG3_YSF_H 0x29EC0493 #define ADF7021_REG3_P25 0x29EC0493 +#define ADF7021_REG3_NXDN 0x29EC0493 #else #define ADF7021_REG3_DMR 0x29ECA093 #define ADF7021_REG3_YSF_L 0x29ECA093 #define ADF7021_REG3_YSF_H 0x29ECA093 #define ADF7021_REG3_P25 0x29ECA093 +#define ADF7021_REG3_NXDN 0x29ECA093 #endif // Discriminator bandwith, demodulator (REG 04) @@ -190,12 +203,14 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_DISC_BW_YSF_L 491U // K=32 #define ADF7021_DISC_BW_YSF_H 430U // K=28 #define ADF7021_DISC_BW_P25 493U // K=32 +#define ADF7021_DISC_BW_NXDN 493U // K=32 // Post demodulator bandwith (REG 04) #define ADF7021_POST_BW_DSTAR 10U #define ADF7021_POST_BW_DMR 150U #define ADF7021_POST_BW_YSF 20U #define ADF7021_POST_BW_P25 6U +#define ADF7021_POST_BW_NXDN 6U // IF filter (REG 05) #define ADF7021_REG5 0x00001ED5 @@ -210,22 +225,27 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_REG10_DMR 0x01FE557A #define ADF7021_REG10_YSF 0x01FE557A #define ADF7021_REG10_P25 0x01FE557A +#define ADF7021_REG10_NXDN 0x01FE557A #if defined(ADF7021_AFC_POS) #define AFC_OFFSET_DMR -250 #define AFC_OFFSET_YSF -250 #define AFC_OFFSET_P25 -250 +#define AFC_OFFSET_NXDN -250 #else #define AFC_OFFSET_DMR 250 #define AFC_OFFSET_YSF 250 #define AFC_OFFSET_P25 250 +#define AFC_OFFSET_NXDN 250 #endif #else #define ADF7021_REG10_DMR 0x049E556A #define ADF7021_REG10_YSF 0x049E556A #define ADF7021_REG10_P25 0x049E556A +#define ADF7021_REG10_NXDN 0x049E556A #define AFC_OFFSET_DMR 0 #define AFC_OFFSET_YSF 0 #define AFC_OFFSET_P25 0 +#define AFC_OFFSET_NXDN 0 #endif #endif @@ -238,6 +258,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_SLICER_TH_YSF_L 35U #define ADF7021_SLICER_TH_YSF_H 69U #define ADF7021_SLICER_TH_P25 43U +#define ADF7021_SLICER_TH_NXDN 43U #else @@ -246,6 +267,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_SLICER_TH_YSF_L 38U #define ADF7021_SLICER_TH_YSF_H 75U #define ADF7021_SLICER_TH_P25 47U +#define ADF7021_SLICER_TH_NXDN 47U #endif diff --git a/IO.h b/IO.h index 51c19c3..2c610a8 100644 --- a/IO.h +++ b/IO.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * Copyright (C) 2017 by Danilo DB4PLE * This program is free software; you can redistribute it and/or modify @@ -127,6 +127,7 @@ public: uint16_t devYSF_H(void); uint16_t devYSF_L(void); uint16_t devP25(void); + uint16_t devNXDN(void); void printConf(); private: @@ -144,7 +145,7 @@ private: uint32_t m_scanPauseCnt; uint8_t m_scanPos; uint8_t m_TotalModes; - MMDVM_STATE m_Modes[4]; + MMDVM_STATE m_Modes[5]; bool m_ledValue; volatile uint32_t m_watchdog; diff --git a/Utils.cpp b/Utils.cpp index be1badf..4e756dc 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 by Jonathan Naylor G4KLX + * Copyright (C) 2017 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 diff --git a/Utils.h b/Utils.h index b574872..1226ce2 100644 --- a/Utils.h +++ b/Utils.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2017 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 From bc0f7bcc871a59dac85cfe48a60620041edf836f Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 13:50:56 -0300 Subject: [PATCH 04/13] More support for NXDN --- ADF7021.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++-- IO.cpp | 16 +++++++++++++-- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/ADF7021.cpp b/ADF7021.cpp index d5ebf54..a09fb64 100644 --- a/ADF7021.cpp +++ b/ADF7021.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 by Jim McLaughlin KI6ZUM - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * Copyright (C) 2017 by Danilo DB4PLE * * Some of the code is based on work of Guus Van Dooren PE1PLM: @@ -232,6 +232,9 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) case STATE_P25: AFC_OFFSET = AFC_OFFSET_P25; break; + case STATE_NXDN: + AFC_OFFSET = AFC_OFFSET_NXDN; + break; default: break; } @@ -409,6 +412,33 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) #endif break; + case STATE_NXDN: + // Dev: +1 symb 600 Hz, symb rate = 4800 + + ADF7021_REG3 = ADF7021_REG3_NXDN; + ADF7021_REG10 = ADF7021_REG10_NXDN; + + // K=32 + ADF7021_REG4 = (uint32_t) 0b0100 << 0; // register 4 + ADF7021_REG4 |= (uint32_t) 0b011 << 4; // mode, 4FSK + ADF7021_REG4 |= (uint32_t) 0b0 << 7; + ADF7021_REG4 |= (uint32_t) 0b11 << 8; + ADF7021_REG4 |= (uint32_t) ADF7021_DISC_BW_NXDN << 10; // Disc BW + ADF7021_REG4 |= (uint32_t) ADF7021_POST_BW_NXDN << 20; // Post dem BW + ADF7021_REG4 |= (uint32_t) 0b00 << 30; // IF filter (12.5 kHz) + + ADF7021_REG13 = (uint32_t) 0b1101 << 0; // register 13 + ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_NXDN << 4; // slicer threshold + + ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5) + ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_NXDN / div2) << 19; // deviation +#if defined(ADF7021_DISABLE_RC_4FSK) + ADF7021_REG2 |= (uint32_t) 0b011 << 4; // modulation (4FSK) +#else + ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK) +#endif + break; + default: break; } @@ -593,7 +623,30 @@ void CIO::ifConf2(MMDVM_STATE modemState) ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_P25 / div2) << 19; // deviation ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK) break; - + + case STATE_NXDN: + // Dev: +1 symb 600 Hz, symb rate = 4800 + + ADF7021_REG3 = ADF7021_REG3_NXDN; + ADF7021_REG10 = ADF7021_REG10_NXDN; + + // K=32 + ADF7021_REG4 = (uint32_t) 0b0100 << 0; // register 4 + ADF7021_REG4 |= (uint32_t) 0b011 << 4; // mode, 4FSK + ADF7021_REG4 |= (uint32_t) 0b0 << 7; + ADF7021_REG4 |= (uint32_t) 0b11 << 8; + ADF7021_REG4 |= (uint32_t) ADF7021_DISC_BW_NXDN << 10; // Disc BW + ADF7021_REG4 |= (uint32_t) ADF7021_POST_BW_NXDN << 20; // Post dem BW + ADF7021_REG4 |= (uint32_t) 0b00 << 30; // IF filter (12.5 kHz) + + ADF7021_REG13 = (uint32_t) 0b1101 << 0; // register 13 + ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_NXDN << 4; // slicer threshold + + ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5) + ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_NXDN / div2) << 19; // deviation + ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK) + break; + default: break; } diff --git a/IO.cpp b/IO.cpp index ea0f491..c428392 100644 --- a/IO.cpp +++ b/IO.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * Copyright (C) 2017 by Danilo DB4PLE * This program is free software; you can redistribute it and/or modify @@ -47,6 +47,7 @@ m_watchdog(0U) DMR_pin(LOW); YSF_pin(LOW); P25_pin(LOW); + NXDN_pin(LOW); COS_pin(LOW); DEB_pin(LOW); @@ -83,6 +84,7 @@ void CIO::selfTest() DMR_pin(ledValue); YSF_pin(ledValue); P25_pin(ledValue); + NXDN_pin(ledValue); COS_pin(ledValue); blinks++; @@ -104,7 +106,7 @@ void CIO::process() if (m_started) { // Two seconds timeout if (m_watchdog >= 19200U) { - if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25) { + if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN) { m_modemState = STATE_IDLE; setMode(m_modemState); } @@ -144,6 +146,8 @@ void CIO::process() scantime = SCAN_TIME; else if(m_modemState_prev == STATE_P25) scantime = SCAN_TIME; + else if(m_modemState_prev == STATE_NXDN) + scantime = SCAN_TIME; else scantime = SCAN_TIME; @@ -184,6 +188,9 @@ void CIO::process() case STATE_P25: p25RX.databit(bit); break; + case STATE_NXDN: + nxdnRX.databit(bit); + break; default: break; } @@ -211,6 +218,10 @@ void CIO::start() m_Modes[m_TotalModes] = STATE_P25; m_TotalModes++; } + if(m_nxdnEnable) { + m_Modes[m_TotalModes] = STATE_NXDN; + m_TotalModes++; + } #if defined(ENABLE_SCAN_MODE) if(m_TotalModes > 1) @@ -291,6 +302,7 @@ void CIO::setMode(MMDVM_STATE modemState) DMR_pin(modemState == STATE_DMR); YSF_pin(modemState == STATE_YSF); P25_pin(modemState == STATE_P25); + NXDN_pin(modemState == STATE_NXDN); } void CIO::setDecode(bool dcd) From 93bcd17e214c9b7225c73897a2b2a88661a8d3fa Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 18:57:20 -0300 Subject: [PATCH 05/13] Preliminary register values for NXDN with TCXO = 14.7456 MHz --- ADF7021.cpp | 4 ++-- ADF7021.h | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ADF7021.cpp b/ADF7021.cpp index a09fb64..fe8b6a7 100644 --- a/ADF7021.cpp +++ b/ADF7021.cpp @@ -413,7 +413,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) break; case STATE_NXDN: - // Dev: +1 symb 600 Hz, symb rate = 4800 + // Dev: +1 symb 350 Hz, symb rate = 2400 ADF7021_REG3 = ADF7021_REG3_NXDN; ADF7021_REG10 = ADF7021_REG10_NXDN; @@ -625,7 +625,7 @@ void CIO::ifConf2(MMDVM_STATE modemState) break; case STATE_NXDN: - // Dev: +1 symb 600 Hz, symb rate = 4800 + // Dev: +1 symb 350 Hz, symb rate = 2400 ADF7021_REG3 = ADF7021_REG3_NXDN; ADF7021_REG10 = ADF7021_REG10_NXDN; diff --git a/ADF7021.h b/ADF7021.h index 4e1881b..d6d7a1f 100644 --- a/ADF7021.h +++ b/ADF7021.h @@ -66,6 +66,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf // DEMOD_CLK = 2.4576 MHz (DSTAR) // DEMOD_CLK = 4.9152 MHz (DMR, YSF_L, P25) // DEMOD_CLK = 7.3728 MHz (YSF_H) +// DEMOD CLK = 3.6864 MHz (NXDN) #define ADF7021_PFD 3686400.0 // PLL (REG 01) @@ -84,7 +85,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #else #define ADF7021_DEV_P25 22U #endif -#define ADF7021_DEV_NXDN 22U +#define ADF7021_DEV_NXDN 13U // TX/RX CLOCK register (REG 03) #define ADF7021_REG3_DSTAR 0x2A4C4193 @@ -99,7 +100,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_REG3_YSF_L 0x2A4C80D3 #define ADF7021_REG3_YSF_H 0x2A4CC093 #define ADF7021_REG3_P25 0x2A4C80D3 -#define ADF7021_REG3_NXDN 0x2A4C80D3 +#define ADF7021_REG3_NXDN 0x2A4CC113 #endif // Discriminator bandwith, demodulator (REG 04) @@ -109,14 +110,14 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_DISC_BW_YSF_L 393U // K=32 #define ADF7021_DISC_BW_YSF_H 516U // K=28 #define ADF7021_DISC_BW_P25 394U // K=32 -#define ADF7021_DISC_BW_NXDN 394U // K=32 +#define ADF7021_DISC_BW_NXDN 295U // K=32 // Post demodulator bandwith (REG 04) #define ADF7021_POST_BW_DSTAR 10U #define ADF7021_POST_BW_DMR 150U #define ADF7021_POST_BW_YSF 20U #define ADF7021_POST_BW_P25 6U -#define ADF7021_POST_BW_NXDN 6U +#define ADF7021_POST_BW_NXDN 7U // IF filter (REG 05) #define ADF7021_REG5 0x000024F5 @@ -258,7 +259,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_SLICER_TH_YSF_L 35U #define ADF7021_SLICER_TH_YSF_H 69U #define ADF7021_SLICER_TH_P25 43U -#define ADF7021_SLICER_TH_NXDN 43U +#define ADF7021_SLICER_TH_NXDN 26U #else @@ -267,7 +268,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_SLICER_TH_YSF_L 38U #define ADF7021_SLICER_TH_YSF_H 75U #define ADF7021_SLICER_TH_P25 47U -#define ADF7021_SLICER_TH_NXDN 47U +#define ADF7021_SLICER_TH_NXDN 26U #endif From 3a27213c413c9a46d8b154f6e37dd88918e14692 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 19:30:30 -0300 Subject: [PATCH 06/13] Preliminary register values for NXDN with TCXO = 12.2880 MHz --- ADF7021.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ADF7021.h b/ADF7021.h index d6d7a1f..3fcecb9 100644 --- a/ADF7021.h +++ b/ADF7021.h @@ -161,6 +161,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf // R = 2 // DEMOD_CLK = 2.4576 MHz (DSTAR) // DEMOD_CLK = 6.1440 MHz (DMR, YSF_H, YSF_L, P25) +// DEMOD_CLK = 3.0720 MHz (NXDN) #define ADF7021_PFD 6144000.0 // PLL (REG 01) @@ -179,7 +180,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #else #define ADF7021_DEV_P25 13U #endif -#define ADF7021_DEV_NXDN 13U +#define ADF7021_DEV_NXDN 8U // TX/RX CLOCK register (REG 03) #define ADF7021_REG3_DSTAR 0x29EC4153 @@ -194,7 +195,7 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_REG3_YSF_L 0x29ECA093 #define ADF7021_REG3_YSF_H 0x29ECA093 #define ADF7021_REG3_P25 0x29ECA093 -#define ADF7021_REG3_NXDN 0x29ECA093 +#define ADF7021_REG3_NXDN 0x29ECA113 #endif // Discriminator bandwith, demodulator (REG 04) @@ -204,14 +205,14 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define ADF7021_DISC_BW_YSF_L 491U // K=32 #define ADF7021_DISC_BW_YSF_H 430U // K=28 #define ADF7021_DISC_BW_P25 493U // K=32 -#define ADF7021_DISC_BW_NXDN 493U // K=32 +#define ADF7021_DISC_BW_NXDN 246U // K=32 // Post demodulator bandwith (REG 04) #define ADF7021_POST_BW_DSTAR 10U #define ADF7021_POST_BW_DMR 150U #define ADF7021_POST_BW_YSF 20U #define ADF7021_POST_BW_P25 6U -#define ADF7021_POST_BW_NXDN 6U +#define ADF7021_POST_BW_NXDN 8U // IF filter (REG 05) #define ADF7021_REG5 0x00001ED5 From 44b36684a6f1e452e006a93d5b241545062b061b Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 20:24:55 -0300 Subject: [PATCH 07/13] Adding NXDN TX preamble --- NXDNTX.cpp | 26 ++++++++++++++++++++------ NXDNTX.h | 3 ++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/NXDNTX.cpp b/NXDNTX.cpp index 71c7753..0f3938c 100644 --- a/NXDNTX.cpp +++ b/NXDNTX.cpp @@ -32,7 +32,9 @@ m_poBuffer(), m_poLen(0U), m_poPtr(0U), m_txDelay(240U), // 200ms -m_count(0U) +m_count(0U), +m_delay(false), +m_preamble(false) { } @@ -44,10 +46,12 @@ void CNXDNTX::process() if (m_poLen == 0U) { if (!m_tx) { m_delay = true; + m_preamble = false; m_count = 0U; m_poLen = m_txDelay; } else { m_delay = false; + m_preamble = false; for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) m_poBuffer[m_poLen++] = m_buffer.get(); } @@ -60,8 +64,10 @@ void CNXDNTX::process() while (space > 8U) { if (m_delay) { - m_poPtr++; writeByte(NXDN_SYNC); + m_poPtr++; + } else if (m_preamble) { + writeByte(NXDN_PREAMBLE[m_poPtr++]); } else writeByte(m_poBuffer[m_poPtr++]); @@ -69,10 +75,18 @@ void CNXDNTX::process() space -= 8U; if (m_poPtr >= m_poLen) { - m_poPtr = 0U; - m_poLen = 0U; - m_delay = false; - return; + if (m_delay) { + m_preamble = true; + m_delay = false; + m_poPtr = 0U; + m_poLen = 3U; + } else { + m_poPtr = 0U; + m_poLen = 0U; + m_preamble = false; + m_delay = false; + return; + } } } } diff --git a/NXDNTX.h b/NXDNTX.h index cefe27d..c17ab37 100644 --- a/NXDNTX.h +++ b/NXDNTX.h @@ -42,7 +42,8 @@ private: uint16_t m_txDelay; uint32_t m_count; bool m_delay; - + bool m_preamble; + void writeByte(uint8_t c); }; From 725c905da0334474dc22e0e6b0cdb03b570cbe6b Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 20:59:42 -0300 Subject: [PATCH 08/13] Fixing some signed / unsigned --- ADF7021.cpp | 62 +++++++++++++++++++++++++------------------------- IO.cpp | 24 +++++++++---------- SerialPort.cpp | 18 +++++++-------- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/ADF7021.cpp b/ADF7021.cpp index fe8b6a7..e9d81b9 100644 --- a/ADF7021.cpp +++ b/ADF7021.cpp @@ -33,7 +33,7 @@ volatile bool totx_request = false; volatile bool torx_request = false; volatile bool even = true; -static uint32_t last_clk = 2; +static uint32_t last_clk = 2U; volatile uint32_t AD7021_control_word; @@ -100,7 +100,7 @@ void Send_AD7021_control2(bool doSle) uint16_t CIO::readRSSI() { uint32_t AD7021_RB; - uint16_t RB_word = 0; + uint16_t RB_word = 0U; int AD7021_counter; uint8_t RB_code, gain_code, gain_corr; @@ -145,22 +145,22 @@ uint16_t CIO::readRSSI() switch(gain_code) { case 0b1010: - gain_corr = 0; + gain_corr = 0U; break; case 0b0110: - gain_corr = 24; + gain_corr = 24U; break; case 0b0101: - gain_corr = 38; + gain_corr = 38U; break; case 0b0100: - gain_corr = 58; + gain_corr = 58U; break; case 0b0000: - gain_corr = 86; + gain_corr = 86U; break; default: - gain_corr = 0; + gain_corr = 0U; break; } @@ -173,12 +173,12 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) { float divider; - uint32_t ADF7021_REG2 = 0; - uint32_t ADF7021_REG3 = 0; - uint32_t ADF7021_REG4 = 0; - uint32_t ADF7021_REG10 = 0; - uint32_t ADF7021_REG13 = 0; - uint32_t AFC_OFFSET = 0; + uint32_t ADF7021_REG2 = 0U; + uint32_t ADF7021_REG3 = 0U; + uint32_t ADF7021_REG4 = 0U; + uint32_t ADF7021_REG10 = 0U; + uint32_t ADF7021_REG13 = 0U; + int32_t AFC_OFFSET = 0; if(modemState != STATE_CWID) m_modemState_prev = modemState; @@ -525,11 +525,11 @@ if(m_duplex && (modemState != STATE_CWID)) #if defined(DUPLEX) void CIO::ifConf2(MMDVM_STATE modemState) { - uint32_t ADF7021_REG2 = 0; - uint32_t ADF7021_REG3 = 0; - uint32_t ADF7021_REG4 = 0; - uint32_t ADF7021_REG10 = 0; - uint32_t ADF7021_REG13 = 0; + uint32_t ADF7021_REG2 = 0U; + uint32_t ADF7021_REG3 = 0U; + uint32_t ADF7021_REG4 = 0U; + uint32_t ADF7021_REG10 = 0U; + uint32_t ADF7021_REG13 = 0U; switch (modemState) { case STATE_DSTAR: @@ -717,7 +717,7 @@ void CIO::ifConf2(MMDVM_STATE modemState) void CIO::interrupt() { - uint8_t bit = 0; + uint8_t bit = 0U; if (!m_started) return; @@ -740,7 +740,7 @@ void CIO::interrupt() } // we set the TX bit at TXD low, sampling of ADF7021 happens at rising clock - if (m_tx && clk == 0) { + if (m_tx && clk == 0U) { m_txBuffer.get(bit, m_control); even = !even; @@ -782,19 +782,19 @@ void CIO::interrupt() } // we sample the RX bit at rising TXD clock edge, so TXD must be 1 and we are not in tx mode - if (!m_tx && clk == 1 && !m_duplex) { + if (!m_tx && clk == 1U && !m_duplex) { if(RXD_pin()) - bit = 1; + bit = 1U; else - bit = 0; + bit = 0U; m_rxBuffer.put(bit, m_control); } - if (torx_request == true && even == ADF7021_EVEN_BIT && m_tx && clk == 0) { + if (torx_request == true && even == ADF7021_EVEN_BIT && m_tx && clk == 0U) { // that is absolutely crucial in 4FSK, see datasheet: // enable sle after 1/4 tBit == 26uS when sending MSB (even == false) and clock is low - delay_us(26); + delay_us(26U); // SLE Pulse, should be moved out of here into class method SLE_pin(HIGH); @@ -817,22 +817,22 @@ void CIO::interrupt() m_modeTimerCnt++; if(m_scanPauseCnt >= SCAN_PAUSE) - m_scanPauseCnt = 0; + m_scanPauseCnt = 0U; - if(m_scanPauseCnt != 0) + if(m_scanPauseCnt != 0U) m_scanPauseCnt++; } #if defined(DUPLEX) void CIO::interrupt2() { - uint8_t bit = 0; + uint8_t bit = 0U; if(m_duplex) { if(RXD2_pin()) - bit = 1; + bit = 1U; else - bit = 0; + bit = 0U; m_rxBuffer.put(bit, m_control); } diff --git a/IO.cpp b/IO.cpp index c428392..f9d1a0c 100644 --- a/IO.cpp +++ b/IO.cpp @@ -61,18 +61,18 @@ m_watchdog(0U) selfTest(); - m_modeTimerCnt = 0; + m_modeTimerCnt = 0U; } void CIO::selfTest() { bool ledValue = false; - uint32_t ledCount = 0; - uint32_t blinks = 0; + uint32_t ledCount = 0U; + uint32_t blinks = 0U; while(true) { ledCount++; - delay_us(1000); + delay_us(1000U); if(ledCount >= 125U) { ledCount = 0U; @@ -89,7 +89,7 @@ void CIO::selfTest() blinks++; - if(blinks > 5) + if(blinks > 5U) break; } } @@ -141,7 +141,7 @@ void CIO::process() if(m_modemState_prev == STATE_DSTAR) scantime = SCAN_TIME; else if(m_modemState_prev == STATE_DMR) - scantime = SCAN_TIME*2; + scantime = SCAN_TIME * 2U; else if(m_modemState_prev == STATE_YSF) scantime = SCAN_TIME; else if(m_modemState_prev == STATE_P25) @@ -152,9 +152,9 @@ void CIO::process() scantime = SCAN_TIME; if(m_modeTimerCnt >= scantime) { - m_modeTimerCnt = 0; - if( (m_modemState == STATE_IDLE) && (m_scanPauseCnt == 0) && m_scanEnable && !m_cwid_state) { - m_scanPos = (m_scanPos + 1) % m_TotalModes; + m_modeTimerCnt = 0U; + if( (m_modemState == STATE_IDLE) && (m_scanPauseCnt == 0U) && m_scanEnable && !m_cwid_state) { + m_scanPos = (m_scanPos + 1U) % m_TotalModes; #if !defined(QUIET_MODE_LEDS) setMode(m_Modes[m_scanPos]); #endif @@ -200,7 +200,7 @@ void CIO::process() void CIO::start() { - m_TotalModes = 0; + m_TotalModes = 0U; if(m_dstarEnable) { m_Modes[m_TotalModes] = STATE_DSTAR; @@ -224,7 +224,7 @@ void CIO::start() } #if defined(ENABLE_SCAN_MODE) - if(m_TotalModes > 1) + if(m_TotalModes > 1U) m_scanEnable = true; else { m_scanEnable = false; @@ -308,7 +308,7 @@ void CIO::setMode(MMDVM_STATE modemState) void CIO::setDecode(bool dcd) { if (dcd != m_dcd) { - m_scanPauseCnt = 1; + m_scanPauseCnt = 1U; COS_pin(dcd ? true : false); } diff --git a/SerialPort.cpp b/SerialPort.cpp index f6881de..3a7ada4 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -317,17 +317,17 @@ uint8_t CSerialPort::setFreq(const uint8_t* data, uint8_t length) // New MMDVMHost, set power from MMDVM.ini if (length == 10U) - rf_power = data[9]; + rf_power = data[9U]; - freq_rx = data[1] * 1; - freq_rx += data[2] * 256; - freq_rx += data[3] * 65536; - freq_rx += data[4] * 16777216; + freq_rx = data[1U] * 1U; + freq_rx += data[2U] * 256U; + freq_rx += data[3U] * 65536U; + freq_rx += data[4U] * 16777216U; - freq_tx = data[5] * 1; - freq_tx += data[6] * 256; - freq_tx += data[7] * 65536; - freq_tx += data[8] * 16777216; + freq_tx = data[5U] * 1U; + freq_tx += data[6U] * 256U; + freq_tx += data[7U] * 65536U; + freq_tx += data[8U] * 16777216U; return io.setFreq(freq_rx, freq_tx, rf_power); } From 4fdf4254b2ee09909a8f384628ed22b98d6d07e7 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 21:00:05 -0300 Subject: [PATCH 09/13] Reduce false FSW detection in NXDN --- NXDNRX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NXDNRX.cpp b/NXDNRX.cpp index 5eb1724..85756f8 100644 --- a/NXDNRX.cpp +++ b/NXDNRX.cpp @@ -22,8 +22,8 @@ #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 uint8_t MAX_FSW_BIT_START_ERRS = 0U; +const uint8_t MAX_FSW_BIT_RUN_ERRS = 2U; const unsigned int MAX_FSW_FRAMES = 5U + 1U; From 115806c57072f61175c677cedff30f2809ae926f Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 21:16:46 -0300 Subject: [PATCH 10/13] Add more NXDN support --- SerialPort.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/SerialPort.cpp b/SerialPort.cpp index 3a7ada4..8d4e9f9 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -124,6 +124,8 @@ void CSerialPort::getStatus() reply[3U] |= 0x04U; if (m_p25Enable) reply[3U] |= 0x08U; + if (m_nxdnEnable) + reply[3U] |= 0x10U; reply[4U] = uint8_t(m_modemState); @@ -168,6 +170,11 @@ void CSerialPort::getStatus() else reply[10U] = 0U; + if (m_nxdnEnable) + reply[11U] = nxdnTX.getSpace(); + else + reply[11U] = 0U; + writeInt(1U, reply, 11); } @@ -241,12 +248,14 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) m_dmrEnable = dmrEnable; m_ysfEnable = ysfEnable; m_p25Enable = p25Enable; + m_nxdnEnable = nxdnEnable; m_duplex = !simplex; dstarTX.setTXDelay(txDelay); ysfTX.setTXDelay(txDelay); p25TX.setTXDelay(txDelay); + nxdnTX.setTXDelay(txDelay); dmrDMOTX.setTXDelay(txDelay); #if defined(DUPLEX) @@ -268,6 +277,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) io.ifConf(STATE_YSF, true); else if(m_p25Enable) io.ifConf(STATE_P25, true); + else if(m_nxdnEnable) + io.ifConf(STATE_NXDN, true); io.start(); io.printConf(); @@ -340,6 +351,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) dstarRX.reset(); ysfRX.reset(); p25RX.reset(); + nxdnRX.reset(); cwIdTX.reset(); break; case STATE_DSTAR: @@ -351,6 +363,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) dmrDMORX.reset(); ysfRX.reset(); p25RX.reset(); + nxdnRX.reset(); cwIdTX.reset(); break; case STATE_YSF: @@ -362,6 +375,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) dmrDMORX.reset(); dstarRX.reset(); p25RX.reset(); + nxdnRX.reset(); cwIdTX.reset(); break; case STATE_P25: @@ -373,6 +387,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) dmrDMORX.reset(); dstarRX.reset(); ysfRX.reset(); + nxdnRX.reset(); cwIdTX.reset(); break; case STATE_NXDN: From db1d88561413c64f0096ff917766a555d13e16e3 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 21:41:27 -0300 Subject: [PATCH 11/13] Restoring FSW run errors number for NXDN --- NXDNRX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNRX.cpp b/NXDNRX.cpp index 85756f8..ac9e3c7 100644 --- a/NXDNRX.cpp +++ b/NXDNRX.cpp @@ -23,7 +23,7 @@ #include "Utils.h" const uint8_t MAX_FSW_BIT_START_ERRS = 0U; -const uint8_t MAX_FSW_BIT_RUN_ERRS = 2U; +const uint8_t MAX_FSW_BIT_RUN_ERRS = 3U; const unsigned int MAX_FSW_FRAMES = 5U + 1U; From 0bd287bc8967ee895694cd989bd49b9721cbe63d Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 22:14:46 -0300 Subject: [PATCH 12/13] Updating version --- version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version.h b/version.h index 614b035..8c1d812 100644 --- a/version.h +++ b/version.h @@ -23,9 +23,9 @@ #include "ADF7021.h" #define VER_MAJOR "1" -#define VER_MINOR "1" -#define VER_REV "3" -#define VERSION_DATE "20180127" +#define VER_MINOR "2" +#define VER_REV "0" +#define VERSION_DATE "20180213" #if defined(ZUMSPOT_ADF7021) #define BOARD_INFO "ZUMspot" From 95037e713a6613099e1c045d5c6e53ff1816dada Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Tue, 13 Feb 2018 22:23:27 -0300 Subject: [PATCH 13/13] Updating docs --- BUILD.md | 3 +++ README.md | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/BUILD.md b/BUILD.md index 0ef375e..834fe63 100644 --- a/BUILD.md +++ b/BUILD.md @@ -618,6 +618,7 @@ Status LEDs: COS_LED PB15 PTT_LED PB14 + NXDN_LED PA8 P25_LED PB0 YSF_LED PB1 DMR_LED PB13 @@ -657,6 +658,7 @@ Status LEDs: COS_LED 10 PTT_LED 9 + NXDN_LED 18 P25_LED 17 YSF_LED 16 DMR_LED 15 @@ -698,6 +700,7 @@ Status LEDs: COS_LED 15 PTT_LED 14 + NXDN_LED 20 P25_LED 19 YSF_LED 18 DMR_LED 17 diff --git a/README.md b/README.md index 3b00667..8a54b59 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Introduction -This is the source code of ZUMspot/MMDVM_HS, personal hotspot (ADF7021 version of the MMDVM firmware), based on Jonathan G4KLX's [MMDVM](https://github.com/g4klx/MMDVM) software. This firmware supports D-Star, DMR, System Fusion and P25 digital modes. +This is the source code of ZUMspot/MMDVM_HS, personal hotspot (ADF7021 version of the MMDVM firmware), based on Jonathan G4KLX's [MMDVM](https://github.com/g4klx/MMDVM) software. This firmware supports D-Star, DMR, System Fusion, P25 and NXDN digital modes. This software is intended to be run on STM32F103 microcontroller. Also, Arduino with 3.3 V I/O (Arduino Due and Zero) and Teensy (3.1, 3.2, 3.5 or 3.6) are supported. You can build this code using Arduino IDE with Roger Clark's [STM32duino](https://github.com/rogerclarkmelbourne/Arduino_STM32/tree/ZUMspot) package, or using command line tools with ARM GCC tools. The preferred method under Windows is using STM32duino, and under Linux or macOS (command line) is using [STM32F10X_Lib](https://github.com/juribeparada/STM32F10X_Lib). @@ -8,7 +8,7 @@ This software is licenced under the GPL v2 and is intended for amateur and educa # Features -- Supported modes: D-Star, DMR, Yaesu Fusion and P25 Phase 1 +- Supported modes: D-Star, DMR, Yaesu Fusion, P25 Phase 1 and NXDN - Automatic mode detection (scanning) - G4KLX software suite: [MMDVMHost](https://github.com/g4klx/MMDVMHost), [ircDDBGateway](https://github.com/dl5di/OpenDV), [YSFGateway](https://github.com/g4klx/YSFClients), [P25Gateway](https://github.com/g4klx/P25Clients) and [DMRGateway](https://github.com/g4klx/DMRGateway) - Bands: 144, 220, 430 and 900 MHz (VHF requires external inductor) @@ -31,7 +31,7 @@ VHF (144-148 MHz) support for ZUMSpot is added by an external 18 nH inductor bet Dual ADF7021 for full duplex operation (#define DUPLEX in Config.h) will work only with a big RX/TX frequency separation (5 MHz or more in UHF band for example) and proper antenna filtering. At the moment #define LIBRE_KIT_ADF7021 (Config.h) with STM32F103 platform is supported. Please see [BUILD.md](BUILD.md) for pinout details. -If you can't decode any 4FSK modulation (DMR, YSF and P25) with your ZUMspot, the common solution is to adjust RX frequency offset (RXOffset) in your MMDVM.ini file. Please try with steps of +-100 Hz until you get low BER. If you don't have test equipment, the only procedure is trial and error. In some cases TXOffset adjustment is also required for proper radio decoding. If you have test equipment, enable TEST_TX feature (see "Hidden functions" in [BUILD.md](BUILD.md) document). +If you can't decode any 4FSK modulation (DMR, YSF, P25 or NXDN) with your ZUMspot, the common solution is to adjust RX frequency offset (RXOffset) in your MMDVM.ini file. Please try with steps of +-100 Hz until you get low BER. If you don't have test equipment, the only procedure is trial and error. In some cases TXOffset adjustment is also required for proper radio decoding. If you have test equipment, enable TEST_TX feature (see "Hidden functions" in [BUILD.md](BUILD.md) document). # Quick start