diff --git a/Conf.cpp b/Conf.cpp index aa16ce3..8f3ffce 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -177,6 +177,13 @@ m_p25GatewayPort(0U), m_p25LocalPort(0U), m_p25NetworkModeHang(3U), m_p25NetworkDebug(false), +m_nxdnNetworkEnabled(false), +m_nxdnNetworkMyAddress(), +m_nxdnNetworkMyPort(0U), +m_nxdnNetworkGatewayAddress(), +m_nxdnNetworkGatewayPort(0U), +m_nxdnNetworkModeHang(3U), +m_nxdnNetworkDebug(false), m_tftSerialPort("/dev/ttyAMA0"), m_tftSerialBrightness(50U), m_hd44780Rows(2U), @@ -601,6 +608,21 @@ bool CConf::read() m_p25NetworkModeHang = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) m_p25NetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_NXDN_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_nxdnNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "LocalAddress") == 0) + m_nxdnNetworkMyAddress = value; + else if (::strcmp(key, "LocalPort") == 0) + m_nxdnNetworkMyPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "GatewayAddress") == 0) + m_nxdnNetworkGatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_nxdnNetworkGatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "ModeHang") == 0) + m_nxdnNetworkModeHang = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_nxdnNetworkDebug = ::atoi(value) == 1; } else if (section == SECTION_TFTSERIAL) { if (::strcmp(key, "Port") == 0) m_tftSerialPort = value; @@ -1281,6 +1303,41 @@ bool CConf::getP25NetworkDebug() const return m_p25NetworkDebug; } +bool CConf::getNXDNNetworkEnabled() const +{ + return m_nxdnNetworkEnabled; +} + +std::string CConf::getNXDNNetworkMyAddress() const +{ + return m_nxdnNetworkMyAddress; +} + +unsigned int CConf::getNXDNNetworkMyPort() const +{ + return m_nxdnNetworkMyPort; +} + +std::string CConf::getNXDNNetworkGatewayAddress() const +{ + return m_nxdnNetworkGatewayAddress; +} + +unsigned int CConf::getNXDNNetworkGatewayPort() const +{ + return m_nxdnNetworkGatewayPort; +} + +unsigned int CConf::getNXDNNetworkModeHang() const +{ + return m_nxdnNetworkModeHang; +} + +bool CConf::getNXDNNetworkDebug() const +{ + return m_nxdnNetworkDebug; +} + std::string CConf::getTFTSerialPort() const { return m_tftSerialPort; diff --git a/Conf.h b/Conf.h index 5f1049d..3a48efb 100644 --- a/Conf.h +++ b/Conf.h @@ -183,6 +183,15 @@ public: unsigned int getP25NetworkModeHang() const; bool getP25NetworkDebug() const; + // The NXDN Network section + bool getNXDNNetworkEnabled() const; + std::string getNXDNNetworkMyAddress() const; + unsigned int getNXDNNetworkMyPort() const; + std::string getNXDNNetworkGatewayAddress() const; + unsigned int getNXDNNetworkGatewayPort() const; + unsigned int getNXDNNetworkModeHang() const; + bool getNXDNNetworkDebug() const; + // The TFTSERIAL section std::string getTFTSerialPort() const; unsigned int getTFTSerialBrightness() const; @@ -360,6 +369,14 @@ private: unsigned int m_p25NetworkModeHang; bool m_p25NetworkDebug; + bool m_nxdnNetworkEnabled; + std::string m_nxdnNetworkMyAddress; + unsigned int m_nxdnNetworkMyPort; + std::string m_nxdnNetworkGatewayAddress; + unsigned int m_nxdnNetworkGatewayPort; + unsigned int m_nxdnNetworkModeHang; + bool m_nxdnNetworkDebug; + std::string m_tftSerialPort; unsigned int m_tftSerialBrightness; diff --git a/MMDVM.ini b/MMDVM.ini index a52ba47..01c78b1 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -151,6 +151,15 @@ LocalPort=32010 # ModeHang=3 Debug=0 +[NXDN Network] +Enable=1 +LocalAddress=127.0.0.1 +LocalPort=3300 +GatewayAddress=127.0.0.1 +GatewayPort=4300 +# ModeHang=3 +Debug=0 + [TFT Serial] # Port=modem Port=/dev/ttyAMA0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index c482d90..4bdb1f5 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -133,6 +133,7 @@ m_dstarNetwork(NULL), m_dmrNetwork(NULL), m_ysfNetwork(NULL), m_p25Network(NULL), +m_nxdnNetwork(NULL), m_display(NULL), m_ump(NULL), m_mode(MODE_IDLE), @@ -300,6 +301,12 @@ int CMMDVMHost::run() return 1; } + if (m_nxdnEnabled && m_conf.getNXDNNetworkEnabled()) { + ret = createNXDNNetwork(); + if (!ret) + return 1; + } + if (m_conf.getCWIdEnabled()) { unsigned int time = m_conf.getCWIdTime(); m_cwCallsign = m_conf.getCWIdCallsign(); @@ -478,9 +485,9 @@ int CMMDVMHost::run() LogInfo(" RAN: %u", ran); LogInfo(" Self Only: %s", selfOnly ? "yes" : "no"); LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no"); - LogInfo(" Mode Hang: %us", m_p25RFModeHang); + LogInfo(" Mode Hang: %us", m_nxdnRFModeHang); - nxdn = new CNXDNControl(ran, id, selfOnly, NULL, m_display, m_timeout, m_duplex, m_lookup, remoteGateway, rssi); + nxdn = new CNXDNControl(ran, id, selfOnly, m_nxdnNetwork, m_display, m_timeout, m_duplex, remoteGateway, rssi); } setMode(MODE_IDLE); @@ -813,6 +820,8 @@ int CMMDVMHost::run() m_ysfNetwork->clock(ms); if (m_p25Network != NULL) m_p25Network->clock(ms); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->clock(ms); m_cwIdTimer.clock(ms); if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) { @@ -881,6 +890,11 @@ int CMMDVMHost::run() delete m_p25Network; } + if (m_nxdnNetwork != NULL) { + m_nxdnNetwork->close(); + delete m_nxdnNetwork; + } + delete dstar; delete dmr; delete ysf; @@ -940,7 +954,7 @@ bool CMMDVMHost::createModem() LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset); m_modem = new CModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); - m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEabled); + m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled); m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel); m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel); m_modem->setDMRParams(colorCode); @@ -1113,6 +1127,36 @@ bool CMMDVMHost::createP25Network() return true; } +bool CMMDVMHost::createNXDNNetwork() +{ + std::string myAddress = m_conf.getNXDNNetworkMyAddress(); + unsigned int myPort = m_conf.getNXDNNetworkMyPort(); + std::string gatewayAddress = m_conf.getNXDNNetworkGatewayAddress(); + unsigned int gatewayPort = m_conf.getNXDNNetworkGatewayPort(); + m_nxdnNetModeHang = m_conf.getNXDNNetworkModeHang(); + bool debug = m_conf.getNXDNNetworkDebug(); + + LogInfo("NXDN Network Parameters"); + LogInfo(" Local Address: %s", myAddress.c_str()); + LogInfo(" Local Port: %u", myPort); + LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); + LogInfo(" Gateway Port: %u", gatewayPort); + LogInfo(" Mode Hang: %us", m_nxdnNetModeHang); + + m_nxdnNetwork = new CNXDNNetwork(myAddress, myPort, gatewayAddress, gatewayPort, m_callsign, debug); + + bool ret = m_nxdnNetwork->open(); + if (!ret) { + delete m_nxdnNetwork; + m_nxdnNetwork = NULL; + return false; + } + + m_nxdnNetwork->enable(true); + + return true; +} + void CMMDVMHost::readParams() { m_dstarEnabled = m_conf.getDStarEnabled(); @@ -1304,6 +1348,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_ysfNetwork->enable(false); if (m_p25Network != NULL) m_p25Network->enable(false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); m_modem->setMode(MODE_DSTAR); if (m_ump != NULL) m_ump->setMode(MODE_DSTAR); @@ -1319,6 +1365,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_ysfNetwork->enable(false); if (m_p25Network != NULL) m_p25Network->enable(false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); m_modem->setMode(MODE_DMR); if (m_ump != NULL) m_ump->setMode(MODE_DMR); @@ -1338,6 +1386,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_dmrNetwork->enable(false); if (m_p25Network != NULL) m_p25Network->enable(false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); m_modem->setMode(MODE_YSF); if (m_ump != NULL) m_ump->setMode(MODE_YSF); @@ -1353,6 +1403,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_dmrNetwork->enable(false); if (m_ysfNetwork != NULL) m_ysfNetwork->enable(false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); m_modem->setMode(MODE_P25); if (m_ump != NULL) m_ump->setMode(MODE_P25); @@ -1388,6 +1440,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_ysfNetwork->enable(false); if (m_p25Network != NULL) m_p25Network->enable(false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -1411,6 +1465,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_ysfNetwork->enable(false); if (m_p25Network != NULL) m_p25Network->enable(false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); @@ -1432,6 +1488,8 @@ void CMMDVMHost::setMode(unsigned char mode) m_ysfNetwork->enable(true); if (m_p25Network != NULL) m_p25Network->enable(true); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { m_modem->writeDMRStart(false); m_dmrTXTimer.stop(); diff --git a/MMDVMHost.h b/MMDVMHost.h index 8c5b3a2..c0faa1b 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -20,6 +20,7 @@ #define MMDVMHOST_H #include "DStarNetwork.h" +#include "NXDNNetwork.h" #include "YSFNetwork.h" #include "P25Network.h" #include "DMRNetwork.h" @@ -47,6 +48,7 @@ private: CDMRNetwork* m_dmrNetwork; CYSFNetwork* m_ysfNetwork; CP25Network* m_p25Network; + CNXDNNetwork* m_nxdnNetwork; CDisplay* m_display; CUMP* m_ump; unsigned char m_mode; @@ -82,6 +84,7 @@ private: bool createDMRNetwork(); bool createYSFNetwork(); bool createP25Network(); + bool createNXDNNetwork(); void createDisplay(); void setMode(unsigned char mode); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 9a73755..6feb302 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -195,6 +195,7 @@ + @@ -268,6 +269,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 49d3d1e..1d5a94c 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -236,6 +236,9 @@ Header Files + + Header Files + @@ -439,5 +442,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/NXDNControl.cpp b/NXDNControl.cpp index 8dfdde0..11021e4 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -23,9 +23,9 @@ // #define DUMP_NXDN -CNXDNControl::CNXDNControl(const std::string& callsign, bool selfOnly, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper) : -m_callsign(NULL), -m_selfCallsign(NULL), +CNXDNControl::CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper) : +m_ran(ran), +m_id(id), m_selfOnly(selfOnly), m_network(network), m_display(display), diff --git a/NXDNControl.h b/NXDNControl.h index 2c77ffb..7ef8aaf 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -20,7 +20,7 @@ #define NXDNControl_H #include "RSSIInterpolator.h" -// #include "YSFNetwork.h" +#include "NXDNNetwork.h" #include "NXDNDefines.h" // #include "YSFPayload.h" #include "RingBuffer.h" @@ -35,7 +35,7 @@ class CNXDNControl { public: - CNXDNControl(const std::string& callsign, bool selfOnly, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper); + CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper); ~CNXDNControl(); bool writeModem(unsigned char* data, unsigned int len); @@ -45,10 +45,10 @@ public: void clock(unsigned int ms); private: - unsigned char* m_callsign; - unsigned char* m_selfCallsign; + unsigned int m_ran; + unsigned int m_id; bool m_selfOnly; - CYSFNetwork* m_network; + CNXDNNetwork* m_network; CDisplay* m_display; bool m_duplex; bool m_remoteGateway; diff --git a/NXDNNetwork.cpp b/NXDNNetwork.cpp new file mode 100644 index 0000000..8f35e7c --- /dev/null +++ b/NXDNNetwork.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2009-2014,2016,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. + */ + +#include "NXDNDefines.h" +#include "NXDNNetwork.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 200U; + +CNXDNNetwork::CNXDNNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug) : +m_socket(myAddress, myPort), +m_address(), +m_port(gatewayPort), +m_debug(debug), +m_enabled(false), +m_buffer(1000U, "NXDN Network"), +m_pollTimer(1000U, 5U) +{ + m_address = CUDPSocket::lookup(gatewayAddress); +} + +CNXDNNetwork::~CNXDNNetwork() +{ +} + +bool CNXDNNetwork::open() +{ + LogMessage("Opening NXDN network connection"); + + if (m_address.s_addr == INADDR_NONE) + return false; + + m_pollTimer.start(); + + return m_socket.open(); +} + +bool CNXDNNetwork::write(const unsigned char* src, const unsigned char* dest, const unsigned char* data, unsigned int count, bool end) +{ + assert(data != NULL); + + unsigned char buffer[200U]; + + buffer[0U] = 'N'; + buffer[1U] = 'X'; + buffer[2U] = 'D'; + buffer[3U] = 'N'; + buffer[4U] = 'D'; + + buffer[5U] = end ? 0x01U : 0x00U; + buffer[5U] |= (count & 0x7FU) << 1; + + ::memcpy(buffer + 6U, data, NXDN_FRAME_LENGTH_BYTES); + + if (m_debug) + CUtils::dump(1U, "NXDN Network Data Sent", buffer, 54U); + + return m_socket.write(buffer, 54U, m_address, m_port); +} + +bool CNXDNNetwork::writePoll() +{ + unsigned char buffer[20U]; + + buffer[0U] = 'N'; + buffer[1U] = 'X'; + buffer[2U] = 'D'; + buffer[3U] = 'N'; + buffer[4U] = 'P'; + + if (m_debug) + CUtils::dump(1U, "NXDN Network Poll Sent", buffer, 5U); + + return m_socket.write(buffer, 5U, m_address, m_port); +} + +void CNXDNNetwork::clock(unsigned int ms) +{ + m_pollTimer.clock(ms); + if (m_pollTimer.hasExpired()) { + writePoll(); + m_pollTimer.start(); + } + + unsigned char buffer[BUFFER_LENGTH]; + + in_addr address; + unsigned int port; + int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return; + + // Check if the data is for us + if (m_address.s_addr != address.s_addr || m_port != port) { + LogMessage("NXDN packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); + return; + } + + // Ignore incoming polls + if (::memcmp(buffer, "NXDNP", 5U) == 0) + return; + + // Invalid packet type? + if (::memcmp(buffer, "NXDND", 5U) != 0) + return; + + if (!m_enabled) + return; + + if (m_debug) + CUtils::dump(1U, "NXDN Network Data Received", buffer, length); + + m_buffer.addData(buffer, 54U); +} + +unsigned int CNXDNNetwork::read(unsigned char* data) +{ + assert(data != NULL); + + if (m_buffer.isEmpty()) + return 0U; + + m_buffer.getData(data, 54U); + + return 155U; +} + +void CNXDNNetwork::reset() +{ +} + +void CNXDNNetwork::close() +{ + m_socket.close(); + + LogMessage("Closing NXDN network connection"); +} + +void CNXDNNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + + m_enabled = enabled; +} diff --git a/NXDNNetwork.h b/NXDNNetwork.h new file mode 100644 index 0000000..1b4742d --- /dev/null +++ b/NXDNNetwork.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009-2014,2016,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. + */ + +#ifndef NXDNNetwork_H +#define NXDNNetwork_H + +#include "NXDNDefines.h" +#include "RingBuffer.h" +#include "UDPSocket.h" +#include "Timer.h" + +#include +#include + +class CNXDNNetwork { +public: + CNXDNNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug); + ~CNXDNNetwork(); + + bool open(); + + void enable(bool enabled); + + bool write(const unsigned char* src, const unsigned char* dest, const unsigned char* data, unsigned int count, bool end); + + unsigned int read(unsigned char* data); + + void reset(); + + void close(); + + void clock(unsigned int ms); + +private: + CUDPSocket m_socket; + in_addr m_address; + unsigned int m_port; + bool m_debug; + bool m_enabled; + CRingBuffer m_buffer; + CTimer m_pollTimer; + + bool writePoll(); +}; + +#endif