diff --git a/DMRGateway.cpp b/DMRGateway.cpp index 0564932..5dd3080 100644 --- a/DMRGateway.cpp +++ b/DMRGateway.cpp @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "MMDVMNetworkNew.h" #include "RewriteType.h" #include "DMRSlotType.h" #include "RewriteSrc.h" @@ -1315,7 +1316,7 @@ bool CDMRGateway::createMMDVM() LogInfo(" Local Address: %s", localAddress.c_str()); LogInfo(" Local Port: %u", localPort); - m_repeater = new CMMDVMNetwork(rptAddress, rptPort, localAddress, localPort, debug); + m_repeater = new CMMDVMNetworkNew(rptAddress, rptPort, localAddress, localPort, debug); bool ret = m_repeater->open(); if (!ret) { diff --git a/DMRGateway.h b/DMRGateway.h index d872389..4beea4d 100644 --- a/DMRGateway.h +++ b/DMRGateway.h @@ -56,7 +56,7 @@ public: private: CConf m_conf; DMRGW_STATUS* m_status; - CMMDVMNetwork* m_repeater; + IMMDVMNetwork* m_repeater; unsigned char* m_config; unsigned int m_configLen; CDMRNetwork* m_dmrNetwork1; diff --git a/DMRGateway.vcxproj b/DMRGateway.vcxproj index 6436d99..056b770 100644 --- a/DMRGateway.vcxproj +++ b/DMRGateway.vcxproj @@ -173,6 +173,8 @@ + + @@ -219,6 +221,8 @@ + + diff --git a/DMRGateway.vcxproj.filters b/DMRGateway.vcxproj.filters index 3f9fdc3..6083433 100644 --- a/DMRGateway.vcxproj.filters +++ b/DMRGateway.vcxproj.filters @@ -146,6 +146,12 @@ Header Files + + Header Files + + + Header Files + @@ -274,5 +280,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/MMDVMNetwork.cpp b/MMDVMNetwork.cpp index 09d7303..6ff3d00 100644 --- a/MMDVMNetwork.cpp +++ b/MMDVMNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020,2021 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 @@ -18,280 +18,6 @@ #include "MMDVMNetwork.h" -#include "StopWatch.h" -#include "Utils.h" -#include "Log.h" - -#include -#include - -const unsigned int BUFFER_LENGTH = 500U; - -const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; - - -CMMDVMNetwork::CMMDVMNetwork(const std::string& rptAddress, unsigned int rptPort, const std::string& localAddress, unsigned int localPort, bool debug) : -m_rptAddr(), -m_rptAddrLen(0U), -m_id(0U), -m_netId(NULL), -m_debug(debug), -m_socket(localAddress, localPort), -m_buffer(NULL), -m_rxData(1000U, "MMDVM Network"), -m_configData(NULL), -m_configLen(0U), -m_radioPositionData(NULL), -m_radioPositionLen(0U), -m_talkerAliasData(NULL), -m_talkerAliasLen(0U) +IMMDVMNetwork::~IMMDVMNetwork() { - assert(!rptAddress.empty()); - assert(rptPort > 0U); - - if (CUDPSocket::lookup(rptAddress, rptPort, m_rptAddr, m_rptAddrLen) != 0) - m_rptAddrLen = 0U; - - m_buffer = new unsigned char[BUFFER_LENGTH]; - m_netId = new unsigned char[4U]; - - m_radioPositionData = new unsigned char[50U]; - m_talkerAliasData = new unsigned char[50U]; - - CStopWatch stopWatch; - ::srand(stopWatch.start()); -} - -CMMDVMNetwork::~CMMDVMNetwork() -{ - delete[] m_netId; - delete[] m_buffer; - delete[] m_configData; - delete[] m_radioPositionData; - delete[] m_talkerAliasData; -} - -unsigned int CMMDVMNetwork::getShortConfig(unsigned char* config) const -{ - if (m_configData == 0U) - return 0U; - - ::memcpy(config, m_configData, m_configLen); - - return m_configLen; -} - -unsigned int CMMDVMNetwork::getId() const -{ - return m_id; -} - -bool CMMDVMNetwork::open() -{ - if (m_rptAddrLen == 0U) { - LogError("Could not lookup the address of the MMDVM Host"); - return false; - } - - LogMessage("MMDVM Network, Opening"); - - return m_socket.open(m_rptAddr); -} - -bool CMMDVMNetwork::read(CDMRData& data) -{ - if (m_rxData.isEmpty()) - return false; - - unsigned char length = 0U; - - m_rxData.getData(&length, 1U); - m_rxData.getData(m_buffer, length); - - // Is this a data packet? - if (::memcmp(m_buffer, "DMRD", 4U) != 0) - return false; - - unsigned char seqNo = m_buffer[4U]; - - unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); - - unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); - - unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; - - FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; - - unsigned int streamId; - ::memcpy(&streamId, m_buffer + 16U, 4U); - - unsigned char ber = m_buffer[53U]; - - unsigned char rssi = m_buffer[54U]; - - data.setSeqNo(seqNo); - data.setSlotNo(slotNo); - data.setSrcId(srcId); - data.setDstId(dstId); - data.setFLCO(flco); - data.setStreamId(streamId); - data.setBER(ber); - data.setRSSI(rssi); - - bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; - bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; - - if (dataSync) { - unsigned char dataType = m_buffer[15U] & 0x0FU; - data.setData(m_buffer + 20U); - data.setDataType(dataType); - data.setN(0U); - } else if (voiceSync) { - data.setData(m_buffer + 20U); - data.setDataType(DT_VOICE_SYNC); - data.setN(0U); - } else { - unsigned char n = m_buffer[15U] & 0x0FU; - data.setData(m_buffer + 20U); - data.setDataType(DT_VOICE); - data.setN(n); - } - - return true; -} - -bool CMMDVMNetwork::write(const CDMRData& data) -{ - unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; - ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); - - buffer[0U] = 'D'; - buffer[1U] = 'M'; - buffer[2U] = 'R'; - buffer[3U] = 'D'; - - unsigned int srcId = data.getSrcId(); - buffer[5U] = srcId >> 16; - buffer[6U] = srcId >> 8; - buffer[7U] = srcId >> 0; - - unsigned int dstId = data.getDstId(); - buffer[8U] = dstId >> 16; - buffer[9U] = dstId >> 8; - buffer[10U] = dstId >> 0; - - ::memcpy(buffer + 11U, m_netId, 4U); - - unsigned int slotNo = data.getSlotNo(); - - buffer[15U] = slotNo == 1U ? 0x00U : 0x80U; - - FLCO flco = data.getFLCO(); - buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U; - - unsigned char dataType = data.getDataType(); - if (dataType == DT_VOICE_SYNC) { - buffer[15U] |= 0x10U; - } else if (dataType == DT_VOICE) { - buffer[15U] |= data.getN(); - } else { - buffer[15U] |= (0x20U | dataType); - } - - buffer[4U] = data.getSeqNo(); - - unsigned int streamId = data.getStreamId(); - ::memcpy(buffer + 16U, &streamId, 4U); - - data.getData(buffer + 20U); - - buffer[53U] = data.getBER(); - - buffer[54U] = data.getRSSI(); - - if (m_debug) - CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH); - - m_socket.write(buffer, HOMEBREW_DATA_PACKET_LENGTH, m_rptAddr, m_rptAddrLen); - - return true; -} - -bool CMMDVMNetwork::readRadioPosition(unsigned char* data, unsigned int& length) -{ - if (m_radioPositionLen == 0U) - return false; - - ::memcpy(data, m_radioPositionData, m_radioPositionLen); - length = m_radioPositionLen; - - m_radioPositionLen = 0U; - - return true; -} - -bool CMMDVMNetwork::readTalkerAlias(unsigned char* data, unsigned int& length) -{ - if (m_talkerAliasLen == 0U) - return false; - - ::memcpy(data, m_talkerAliasData, m_talkerAliasLen); - length = m_talkerAliasLen; - - m_talkerAliasLen = 0U; - - return true; -} - -bool CMMDVMNetwork::writeBeacon() -{ - return m_socket.write((unsigned char*)"DMRB", 4U, m_rptAddr, m_rptAddrLen); -} - -void CMMDVMNetwork::close() -{ - LogMessage("MMDVM Network, Closing"); - - m_socket.close(); -} - -void CMMDVMNetwork::clock(unsigned int ms) -{ - sockaddr_storage address; - unsigned int addrlen; - int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen); - if (length <= 0) - return; - - if (!CUDPSocket::match(m_rptAddr, address)) { - LogMessage("MMDVM packet received from an invalid source"); - return; - } - - if (m_debug) - CUtils::dump(1U, "Network Received", m_buffer, length); - - if (::memcmp(m_buffer, "DMRD", 4U) == 0) { - unsigned char len = length; - m_rxData.addData(&len, 1U); - m_rxData.addData(m_buffer, len); - } else if (::memcmp(m_buffer, "DMRG", 4U) == 0) { - ::memcpy(m_radioPositionData, m_buffer, length); - m_radioPositionLen = length; - } else if (::memcmp(m_buffer, "DMRA", 4U) == 0) { - ::memcpy(m_talkerAliasData, m_buffer, length); - m_talkerAliasLen = length; - } else if (::memcmp(m_buffer, "DMRC", 4U) == 0) { - m_id = (m_buffer[4U] << 24) | (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); - - if (m_configData == NULL) { - m_configLen = length - 8U; - m_configData = new unsigned char[m_configLen]; - ::memcpy(m_configData, m_buffer + 8U, m_configLen); - } - - m_socket.write((unsigned char*)"DMRP", 4U, m_rptAddr, m_rptAddrLen); - } else { - CUtils::dump("Unknown packet from the MMDVM", m_buffer, length); - } } diff --git a/MMDVMNetwork.h b/MMDVMNetwork.h index 89dc762..ec99790 100644 --- a/MMDVMNetwork.h +++ b/MMDVMNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020,2021 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 @@ -19,55 +19,36 @@ #if !defined(MMDVMNetwork_H) #define MMDVMNetwork_H -#include "UDPSocket.h" -#include "Timer.h" -#include "RingBuffer.h" #include "DMRData.h" -#include #include -class CMMDVMNetwork +class IMMDVMNetwork { public: - CMMDVMNetwork(const std::string& rptAddress, unsigned int rptPort, const std::string& localAddress, unsigned int localPort, bool debug); - ~CMMDVMNetwork(); + virtual ~IMMDVMNetwork() = 0; - unsigned int getShortConfig(unsigned char* config) const; + virtual unsigned int getShortConfig(unsigned char* config) const = 0; - unsigned int getId() const; + virtual unsigned int getId() const = 0; - bool open(); + virtual bool open() = 0; - bool read(CDMRData& data); + virtual bool read(CDMRData& data) = 0; - bool write(const CDMRData& data); + virtual bool write(const CDMRData& data) = 0; - bool readRadioPosition(unsigned char* data, unsigned int& length); + virtual bool readRadioPosition(unsigned char* data, unsigned int& length) = 0; - bool readTalkerAlias(unsigned char* data, unsigned int& length); + virtual bool readTalkerAlias(unsigned char* data, unsigned int& length) = 0; - bool writeBeacon(); + virtual bool writeBeacon() = 0; - void clock(unsigned int ms); + virtual void clock(unsigned int ms) = 0; - void close(); + virtual void close() = 0; private: - sockaddr_storage m_rptAddr; - unsigned int m_rptAddrLen; - unsigned int m_id; - unsigned char* m_netId; - bool m_debug; - CUDPSocket m_socket; - unsigned char* m_buffer; - CRingBuffer m_rxData; - unsigned char* m_configData; - unsigned int m_configLen; - unsigned char* m_radioPositionData; - unsigned int m_radioPositionLen; - unsigned char* m_talkerAliasData; - unsigned int m_talkerAliasLen; }; #endif diff --git a/MMDVMNetworkNew.cpp b/MMDVMNetworkNew.cpp new file mode 100644 index 0000000..0e837f0 --- /dev/null +++ b/MMDVMNetworkNew.cpp @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2015,2016,2017,2018,2020,2021 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 "MMDVMNetworkNew.h" + +#include "StopWatch.h" +#include "Utils.h" +#include "Log.h" + +#include +#include + +const unsigned int BUFFER_LENGTH = 500U; + +const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; + + +CMMDVMNetworkNew::CMMDVMNetworkNew(const std::string& rptAddress, unsigned int rptPort, const std::string& localAddress, unsigned int localPort, bool debug) : +m_rptAddr(), +m_rptAddrLen(0U), +m_id(0U), +m_netId(NULL), +m_debug(debug), +m_socket(localAddress, localPort), +m_buffer(NULL), +m_rxData(1000U, "MMDVM Network"), +m_configData(NULL), +m_configLen(0U), +m_radioPositionData(NULL), +m_radioPositionLen(0U), +m_talkerAliasData(NULL), +m_talkerAliasLen(0U) +{ + assert(!rptAddress.empty()); + assert(rptPort > 0U); + + if (CUDPSocket::lookup(rptAddress, rptPort, m_rptAddr, m_rptAddrLen) != 0) + m_rptAddrLen = 0U; + + m_buffer = new unsigned char[BUFFER_LENGTH]; + m_netId = new unsigned char[4U]; + + m_radioPositionData = new unsigned char[50U]; + m_talkerAliasData = new unsigned char[50U]; + + CStopWatch stopWatch; + ::srand(stopWatch.start()); +} + +CMMDVMNetworkNew::~CMMDVMNetworkNew() +{ + delete[] m_netId; + delete[] m_buffer; + delete[] m_configData; + delete[] m_radioPositionData; + delete[] m_talkerAliasData; +} + +unsigned int CMMDVMNetworkNew::getShortConfig(unsigned char* config) const +{ + if (m_configData == 0U) + return 0U; + + ::memcpy(config, m_configData, m_configLen); + + return m_configLen; +} + +unsigned int CMMDVMNetworkNew::getId() const +{ + return m_id; +} + +bool CMMDVMNetworkNew::open() +{ + if (m_rptAddrLen == 0U) { + LogError("Could not lookup the address of the MMDVM Host"); + return false; + } + + LogMessage("MMDVM Network, Opening"); + + return m_socket.open(m_rptAddr); +} + +bool CMMDVMNetworkNew::read(CDMRData& data) +{ + if (m_rxData.isEmpty()) + return false; + + unsigned char length = 0U; + + m_rxData.getData(&length, 1U); + m_rxData.getData(m_buffer, length); + + // Is this a data packet? + if (::memcmp(m_buffer, "DMRD", 4U) != 0) + return false; + + unsigned char seqNo = m_buffer[4U]; + + unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + + unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); + + unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; + + FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; + + unsigned int streamId; + ::memcpy(&streamId, m_buffer + 16U, 4U); + + unsigned char ber = m_buffer[53U]; + + unsigned char rssi = m_buffer[54U]; + + data.setSeqNo(seqNo); + data.setSlotNo(slotNo); + data.setSrcId(srcId); + data.setDstId(dstId); + data.setFLCO(flco); + data.setStreamId(streamId); + data.setBER(ber); + data.setRSSI(rssi); + + bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; + bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; + + if (dataSync) { + unsigned char dataType = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(dataType); + data.setN(0U); + } else if (voiceSync) { + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE_SYNC); + data.setN(0U); + } else { + unsigned char n = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE); + data.setN(n); + } + + return true; +} + +bool CMMDVMNetworkNew::write(const CDMRData& data) +{ + unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; + ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); + + buffer[0U] = 'D'; + buffer[1U] = 'M'; + buffer[2U] = 'R'; + buffer[3U] = 'D'; + + unsigned int srcId = data.getSrcId(); + buffer[5U] = srcId >> 16; + buffer[6U] = srcId >> 8; + buffer[7U] = srcId >> 0; + + unsigned int dstId = data.getDstId(); + buffer[8U] = dstId >> 16; + buffer[9U] = dstId >> 8; + buffer[10U] = dstId >> 0; + + ::memcpy(buffer + 11U, m_netId, 4U); + + unsigned int slotNo = data.getSlotNo(); + + buffer[15U] = slotNo == 1U ? 0x00U : 0x80U; + + FLCO flco = data.getFLCO(); + buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U; + + unsigned char dataType = data.getDataType(); + if (dataType == DT_VOICE_SYNC) { + buffer[15U] |= 0x10U; + } else if (dataType == DT_VOICE) { + buffer[15U] |= data.getN(); + } else { + buffer[15U] |= (0x20U | dataType); + } + + buffer[4U] = data.getSeqNo(); + + unsigned int streamId = data.getStreamId(); + ::memcpy(buffer + 16U, &streamId, 4U); + + data.getData(buffer + 20U); + + buffer[53U] = data.getBER(); + + buffer[54U] = data.getRSSI(); + + if (m_debug) + CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH); + + m_socket.write(buffer, HOMEBREW_DATA_PACKET_LENGTH, m_rptAddr, m_rptAddrLen); + + return true; +} + +bool CMMDVMNetworkNew::readRadioPosition(unsigned char* data, unsigned int& length) +{ + if (m_radioPositionLen == 0U) + return false; + + ::memcpy(data, m_radioPositionData, m_radioPositionLen); + length = m_radioPositionLen; + + m_radioPositionLen = 0U; + + return true; +} + +bool CMMDVMNetworkNew::readTalkerAlias(unsigned char* data, unsigned int& length) +{ + if (m_talkerAliasLen == 0U) + return false; + + ::memcpy(data, m_talkerAliasData, m_talkerAliasLen); + length = m_talkerAliasLen; + + m_talkerAliasLen = 0U; + + return true; +} + +bool CMMDVMNetworkNew::writeBeacon() +{ + return m_socket.write((unsigned char*)"DMRB", 4U, m_rptAddr, m_rptAddrLen); +} + +void CMMDVMNetworkNew::close() +{ + LogMessage("MMDVM Network, Closing"); + + m_socket.close(); +} + +void CMMDVMNetworkNew::clock(unsigned int ms) +{ + sockaddr_storage address; + unsigned int addrlen; + int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen); + if (length <= 0) + return; + + if (!CUDPSocket::match(m_rptAddr, address)) { + LogMessage("MMDVM packet received from an invalid source"); + return; + } + + if (m_debug) + CUtils::dump(1U, "Network Received", m_buffer, length); + + if (::memcmp(m_buffer, "DMRD", 4U) == 0) { + unsigned char len = length; + m_rxData.addData(&len, 1U); + m_rxData.addData(m_buffer, len); + } else if (::memcmp(m_buffer, "DMRG", 4U) == 0) { + ::memcpy(m_radioPositionData, m_buffer, length); + m_radioPositionLen = length; + } else if (::memcmp(m_buffer, "DMRA", 4U) == 0) { + ::memcpy(m_talkerAliasData, m_buffer, length); + m_talkerAliasLen = length; + } else if (::memcmp(m_buffer, "DMRC", 4U) == 0) { + m_id = (m_buffer[4U] << 24) | (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + + if (m_configData == NULL) { + m_configLen = length - 8U; + m_configData = new unsigned char[m_configLen]; + ::memcpy(m_configData, m_buffer + 8U, m_configLen); + } + + m_socket.write((unsigned char*)"DMRP", 4U, m_rptAddr, m_rptAddrLen); + } else { + CUtils::dump("Unknown packet from the MMDVM", m_buffer, length); + } +} diff --git a/MMDVMNetworkNew.h b/MMDVMNetworkNew.h new file mode 100644 index 0000000..cad3bf3 --- /dev/null +++ b/MMDVMNetworkNew.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015,2016,2017,2018,2020,2021 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(MMDVMNetworkNew_H) +#define MMDVMNetworkNew_H + +#include "MMDVMNetwork.h" +#include "UDPSocket.h" +#include "Timer.h" +#include "RingBuffer.h" + +#include +#include + +class CMMDVMNetworkNew : public IMMDVMNetwork +{ +public: + CMMDVMNetworkNew(const std::string& rptAddress, unsigned int rptPort, const std::string& localAddress, unsigned int localPort, bool debug); + virtual ~CMMDVMNetworkNew(); + + virtual unsigned int getShortConfig(unsigned char* config) const; + + virtual unsigned int getId() const; + + virtual bool open(); + + virtual bool read(CDMRData& data); + + virtual bool write(const CDMRData& data); + + virtual bool readRadioPosition(unsigned char* data, unsigned int& length); + + virtual bool readTalkerAlias(unsigned char* data, unsigned int& length); + + virtual bool writeBeacon(); + + virtual void clock(unsigned int ms); + + virtual void close(); + +private: + sockaddr_storage m_rptAddr; + unsigned int m_rptAddrLen; + unsigned int m_id; + unsigned char* m_netId; + bool m_debug; + CUDPSocket m_socket; + unsigned char* m_buffer; + CRingBuffer m_rxData; + unsigned char* m_configData; + unsigned int m_configLen; + unsigned char* m_radioPositionData; + unsigned int m_radioPositionLen; + unsigned char* m_talkerAliasData; + unsigned int m_talkerAliasLen; +}; + +#endif diff --git a/MMDVMNetworkOld.cpp b/MMDVMNetworkOld.cpp new file mode 100644 index 0000000..57fef0f --- /dev/null +++ b/MMDVMNetworkOld.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2015,2016,2017,2018,2021 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 "MMDVMNetworkOld.h" + +#include "StopWatch.h" +#include "SHA256.h" +#include "Utils.h" +#include "Log.h" + +#include +#include + +const unsigned int BUFFER_LENGTH = 500U; + +const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; + + +CMMDVMNetworkOld::CMMDVMNetworkOld(const std::string& rptAddress, unsigned int rptPort, const std::string& localAddress, unsigned int localPort, bool debug) : +m_rptAddr(), +m_rptAddrLen(0U), +m_id(0U), +m_netId(NULL), +m_debug(debug), +m_socket(localAddress, localPort), +m_buffer(NULL), +m_rxData(1000U, "MMDVM Network"), +m_options(), +m_configData(NULL), +m_configLen(0U), +m_radioPositionData(NULL), +m_radioPositionLen(0U), +m_talkerAliasData(NULL), +m_talkerAliasLen(0U), +m_homePositionData(NULL), +m_homePositionLen(0U) +{ + assert(!rptAddress.empty()); + assert(rptPort > 0U); + + if (CUDPSocket::lookup(rptAddress, rptPort, m_rptAddr, m_rptAddrLen) != 0) + m_rptAddrLen = 0U; + + m_buffer = new unsigned char[BUFFER_LENGTH]; + m_netId = new unsigned char[4U]; + + m_radioPositionData = new unsigned char[50U]; + m_talkerAliasData = new unsigned char[50U]; + m_homePositionData = new unsigned char[50U]; + + CStopWatch stopWatch; + ::srand(stopWatch.start()); +} + +CMMDVMNetworkOld::~CMMDVMNetworkOld() +{ + delete[] m_netId; + delete[] m_buffer; + delete[] m_configData; + delete[] m_radioPositionData; + delete[] m_talkerAliasData; + delete[] m_homePositionData; +} + +std::string CMMDVMNetworkOld::getOptions() const +{ + return m_options; +} + +unsigned int CMMDVMNetworkOld::getConfig(unsigned char* config) const +{ + if (m_configData == 0U) + return 0U; + + ::memcpy(config, m_configData, m_configLen); + + return m_configLen; +} + +unsigned int CMMDVMNetworkOld::getId() const +{ + return m_id; +} + +bool CMMDVMNetworkOld::open() +{ + if (m_rptAddrLen == 0U) { + LogError("Could not lookup the address of the MMDVM Host"); + return false; + } + + LogMessage("MMDVM Network, Opening"); + + return m_socket.open(); +} + +bool CMMDVMNetworkOld::read(CDMRData& data) +{ + if (m_rxData.isEmpty()) + return false; + + unsigned char length = 0U; + + m_rxData.getData(&length, 1U); + m_rxData.getData(m_buffer, length); + + // Is this a data packet? + if (::memcmp(m_buffer, "DMRD", 4U) != 0) + return false; + + unsigned char seqNo = m_buffer[4U]; + + unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + + unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); + + unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; + + FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; + + unsigned int streamId; + ::memcpy(&streamId, m_buffer + 16U, 4U); + + unsigned char ber = m_buffer[53U]; + + unsigned char rssi = m_buffer[54U]; + + data.setSeqNo(seqNo); + data.setSlotNo(slotNo); + data.setSrcId(srcId); + data.setDstId(dstId); + data.setFLCO(flco); + data.setStreamId(streamId); + data.setBER(ber); + data.setRSSI(rssi); + + bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; + bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; + + if (dataSync) { + unsigned char dataType = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(dataType); + data.setN(0U); + } else if (voiceSync) { + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE_SYNC); + data.setN(0U); + } else { + unsigned char n = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE); + data.setN(n); + } + + return true; +} + +bool CMMDVMNetworkOld::write(const CDMRData& data) +{ + unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; + ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); + + buffer[0U] = 'D'; + buffer[1U] = 'M'; + buffer[2U] = 'R'; + buffer[3U] = 'D'; + + unsigned int srcId = data.getSrcId(); + buffer[5U] = srcId >> 16; + buffer[6U] = srcId >> 8; + buffer[7U] = srcId >> 0; + + unsigned int dstId = data.getDstId(); + buffer[8U] = dstId >> 16; + buffer[9U] = dstId >> 8; + buffer[10U] = dstId >> 0; + + ::memcpy(buffer + 11U, m_netId, 4U); + + unsigned int slotNo = data.getSlotNo(); + + buffer[15U] = slotNo == 1U ? 0x00U : 0x80U; + + FLCO flco = data.getFLCO(); + buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U; + + unsigned char dataType = data.getDataType(); + if (dataType == DT_VOICE_SYNC) { + buffer[15U] |= 0x10U; + } else if (dataType == DT_VOICE) { + buffer[15U] |= data.getN(); + } else { + buffer[15U] |= (0x20U | dataType); + } + + buffer[4U] = data.getSeqNo(); + + unsigned int streamId = data.getStreamId(); + ::memcpy(buffer + 16U, &streamId, 4U); + + data.getData(buffer + 20U); + + buffer[53U] = data.getBER(); + + buffer[54U] = data.getRSSI(); + + if (m_debug) + CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH); + + m_socket.write(buffer, HOMEBREW_DATA_PACKET_LENGTH, m_rptAddr, m_rptAddrLen); + + return true; +} + +bool CMMDVMNetworkOld::readRadioPosition(unsigned char* data, unsigned int& length) +{ + if (m_radioPositionLen == 0U) + return false; + + ::memcpy(data, m_radioPositionData, m_radioPositionLen); + length = m_radioPositionLen; + + m_radioPositionLen = 0U; + + return true; +} + +bool CMMDVMNetworkOld::readTalkerAlias(unsigned char* data, unsigned int& length) +{ + if (m_talkerAliasLen == 0U) + return false; + + ::memcpy(data, m_talkerAliasData, m_talkerAliasLen); + length = m_talkerAliasLen; + + m_talkerAliasLen = 0U; + + return true; +} + +bool CMMDVMNetworkOld::readHomePosition(unsigned char* data, unsigned int& length) +{ + if (m_homePositionLen == 0U) + return false; + + ::memcpy(data, m_homePositionData, m_homePositionLen); + length = m_homePositionLen; + + m_homePositionLen = 0U; + + return true; +} + +bool CMMDVMNetworkOld::writeBeacon() +{ + unsigned char buffer[20U]; + ::memcpy(buffer + 0U, "RPTSBKN", 7U); + ::memcpy(buffer + 7U, m_netId, 4U); + + return m_socket.write(buffer, 11U, m_rptAddr, m_rptAddrLen); +} + +void CMMDVMNetworkOld::close() +{ + unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; + ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); + + LogMessage("MMDVM Network, Closing"); + + ::memcpy(buffer + 0U, "MSTCL", 5U); + ::memcpy(buffer + 5U, m_netId, 4U); + + m_socket.write(buffer, HOMEBREW_DATA_PACKET_LENGTH, m_rptAddr, m_rptAddrLen); + m_socket.close(); +} + +void CMMDVMNetworkOld::clock(unsigned int ms) +{ + sockaddr_storage address; + unsigned int addrlen; + int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen); + if (length < 0) { + LogError("MMDVM Network, Socket has failed, reopening"); + close(); + open(); + return; + } + + if (!CUDPSocket::match(m_rptAddr, address)) { + LogMessage("MMDVM packet received from an invalid source"); + return; + } + + if (m_debug && length > 0) + CUtils::dump(1U, "Network Received", m_buffer, length); + + if (length > 0) { + if (::memcmp(m_buffer, "DMRD", 4U) == 0) { + if (m_debug) + CUtils::dump(1U, "Network Received", m_buffer, length); + + unsigned char len = length; + m_rxData.addData(&len, 1U); + m_rxData.addData(m_buffer, len); + } else if (::memcmp(m_buffer, "DMRG", 4U) == 0) { + ::memcpy(m_radioPositionData, m_buffer, length); + m_radioPositionLen = length; + } else if (::memcmp(m_buffer, "DMRA", 4U) == 0) { + ::memcpy(m_talkerAliasData, m_buffer, length); + m_talkerAliasLen = length; + } else if (::memcmp(m_buffer, "RPTG", 4U) == 0) { + ::memcpy(m_homePositionData, m_buffer, length); + m_homePositionLen = length; + } else if (::memcmp(m_buffer, "RPTL", 4U) == 0) { + m_id = (m_buffer[4U] << 24) | (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + ::memcpy(m_netId, m_buffer + 4U, 4U); + + unsigned char ack[10U]; + ::memcpy(ack + 0U, "RPTACK", 6U); + + uint32_t salt = 1U; + ::memcpy(ack + 6U, &salt, sizeof(uint32_t)); + + m_socket.write(ack, 10U, m_rptAddr, m_rptAddrLen); + } else if (::memcmp(m_buffer, "RPTK", 4U) == 0) { + unsigned char ack[10U]; + ::memcpy(ack + 0U, "RPTACK", 6U); + ::memcpy(ack + 6U, m_netId, 4U); + m_socket.write(ack, 10U, m_rptAddr, m_rptAddrLen); + } else if (::memcmp(m_buffer, "RPTCL", 5U) == 0) { + ::LogMessage("MMDVM Network, The connected MMDVM is closing down"); + } else if (::memcmp(m_buffer, "RPTC", 4U) == 0) { + m_configLen = length - 8U; + m_configData = new unsigned char[m_configLen]; + ::memcpy(m_configData, m_buffer + 8U, m_configLen); + + unsigned char ack[10U]; + ::memcpy(ack + 0U, "RPTACK", 6U); + ::memcpy(ack + 6U, m_netId, 4U); + m_socket.write(ack, 10U, m_rptAddr, m_rptAddrLen); + } else if (::memcmp(m_buffer, "RPTO", 4U) == 0) { + m_options = std::string((char*)(m_buffer + 8U), length - 8U); + + unsigned char ack[10U]; + ::memcpy(ack + 0U, "RPTACK", 6U); + ::memcpy(ack + 6U, m_netId, 4U); + m_socket.write(ack, 10U, m_rptAddr, m_rptAddrLen); + } else if (::memcmp(m_buffer, "RPTPING", 7U) == 0) { + unsigned char pong[11U]; + ::memcpy(pong + 0U, "MSTPONG", 7U); + ::memcpy(pong + 7U, m_netId, 4U); + m_socket.write(pong, 11U, m_rptAddr, m_rptAddrLen); + } else { + CUtils::dump("Unknown packet from the master", m_buffer, length); + } + } +} diff --git a/MMDVMNetworkOld.h b/MMDVMNetworkOld.h new file mode 100644 index 0000000..27b1ee0 --- /dev/null +++ b/MMDVMNetworkOld.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015,2016,2017,2018,2021 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(MMDVMNetworkOld_H) +#define MMDVMNetworkOld_H + +#include "MMDVMNetwork.h" +#include "UDPSocket.h" +#include "Timer.h" +#include "RingBuffer.h" + +#include +#include + +class CMMDVMNetworkOld : public IMMDVMNetwork +{ +public: + CMMDVMNetworkOld(const std::string& rptAddress, unsigned int rptPort, const std::string& localAddress, unsigned int localPort, bool debug); + virtual ~CMMDVMNetworkOld(); + + virtual std::string getOptions() const; + + virtual unsigned int getConfig(unsigned char* config) const; + + virtual unsigned int getId() const; + + virtual bool open(); + + virtual bool read(CDMRData& data); + + virtual bool write(const CDMRData& data); + + virtual bool readRadioPosition(unsigned char* data, unsigned int& length); + + virtual bool readTalkerAlias(unsigned char* data, unsigned int& length); + + virtual bool readHomePosition(unsigned char* data, unsigned int& length); + + virtual bool writeBeacon(); + + virtual void clock(unsigned int ms); + + virtual void close(); + +private: + sockaddr_storage m_rptAddr; + unsigned int m_rptAddrLen; + unsigned int m_id; + unsigned char* m_netId; + bool m_debug; + CUDPSocket m_socket; + unsigned char* m_buffer; + CRingBuffer m_rxData; + std::string m_options; + unsigned char* m_configData; + unsigned int m_configLen; + unsigned char* m_radioPositionData; + unsigned int m_radioPositionLen; + unsigned char* m_talkerAliasData; + unsigned int m_talkerAliasLen; + unsigned char* m_homePositionData; + unsigned int m_homePositionLen; +}; + +#endif diff --git a/Makefile b/Makefile index 06cd120..3f3b12b 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,9 @@ LIBS = -lpthread LDFLAGS = -g OBJECTS = APRSWriter.o BPTC19696.o Conf.o CRC.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREmbeddedData.o DMREMB.o DMRFullLC.o DMRGateway.o \ - DMRLC.o DMRNetwork.o DMRSlotType.o DynVoice.o Golay2087.o GPSD.o Hamming.o Log.o MMDVMNetwork.o PassAllPC.o PassAllTG.o \ - QR1676.o Reflectors.o Rewrite.o RewriteDstId.o RewriteDynTGNet.o RewriteDynTGRF.o RewritePC.o RewriteSrc.o RewriteSrcId.o \ - RewriteTG.o RewriteType.o RS129.o SHA256.o StopWatch.o Sync.o Thread.o Timer.o UDPSocket.o Utils.o XLXVoice.o + DMRLC.o DMRNetwork.o DMRSlotType.o DynVoice.o Golay2087.o GPSD.o Hamming.o Log.o MMDVMNetwork.o MMDVMNetworkNew.o MMDVMNetworkOld.o \ + PassAllPC.o PassAllTG.o QR1676.o Reflectors.o Rewrite.o RewriteDstId.o RewriteDynTGNet.o RewriteDynTGRF.o RewritePC.o RewriteSrc.o \ + RewriteSrcId.o RewriteTG.o RewriteType.o RS129.o SHA256.o StopWatch.o Sync.o Thread.o Timer.o UDPSocket.o Utils.o XLXVoice.o all: DMRGateway