More work on integrating the Kenwood NXDN protocol.

This commit is contained in:
Jonathan Naylor 2020-05-27 12:07:21 +01:00
parent 45eafe3672
commit 924baeacd1
9 changed files with 130 additions and 68 deletions

View File

@ -236,6 +236,7 @@ m_p25LocalPort(0U),
m_p25NetworkModeHang(3U),
m_p25NetworkDebug(false),
m_nxdnNetworkEnabled(false),
m_nxdnNetworkProtocol("Icom"),
m_nxdnGatewayAddress(),
m_nxdnGatewayPort(0U),
m_nxdnLocalAddress(),
@ -842,6 +843,8 @@ bool CConf::read()
} else if (section == SECTION_NXDN_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_nxdnNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Protocol") == 0)
m_nxdnNetworkProtocol = value;
else if (::strcmp(key, "LocalAddress") == 0)
m_nxdnLocalAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
@ -1832,6 +1835,11 @@ bool CConf::getNXDNNetworkEnabled() const
return m_nxdnNetworkEnabled;
}
std::string CConf::getNXDNNetworkProtocol() const
{
return m_nxdnNetworkProtocol;
}
std::string CConf::getNXDNGatewayAddress() const
{
return m_nxdnGatewayAddress;

2
Conf.h
View File

@ -244,6 +244,7 @@ public:
// The NXDN Network section
bool getNXDNNetworkEnabled() const;
std::string getNXDNNetworkProtocol() const;
std::string getNXDNGatewayAddress() const;
unsigned int getNXDNGatewayPort() const;
std::string getNXDNLocalAddress() const;
@ -509,6 +510,7 @@ private:
bool m_p25NetworkDebug;
bool m_nxdnNetworkEnabled;
std::string m_nxdnNetworkProtocol;
std::string m_nxdnGatewayAddress;
unsigned int m_nxdnGatewayPort;
std::string m_nxdnLocalAddress;

View File

@ -17,6 +17,8 @@
*/
#include "MMDVMHost.h"
#include "NXDNKenwoodNetwork.h"
#include "NXDNIcomNetwork.h"
#include "RSSIInterpolator.h"
#include "SerialController.h"
#include "Version.h"
@ -1472,6 +1474,7 @@ bool CMMDVMHost::createP25Network()
bool CMMDVMHost::createNXDNNetwork()
{
std::string protocol = m_conf.getNXDNNetworkProtocol();
std::string gatewayAddress = m_conf.getNXDNGatewayAddress();
unsigned int gatewayPort = m_conf.getNXDNGatewayPort();
std::string localAddress = m_conf.getNXDNLocalAddress();
@ -1480,13 +1483,17 @@ bool CMMDVMHost::createNXDNNetwork()
bool debug = m_conf.getNXDNNetworkDebug();
LogInfo("NXDN Network Parameters");
LogInfo(" Protocol: %s", protocol.c_str());
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %u", gatewayPort);
LogInfo(" Local Address: %s", localAddress.c_str());
LogInfo(" Local Port: %u", localPort);
LogInfo(" Mode Hang: %us", m_nxdnNetModeHang);
m_nxdnNetwork = new CNXDNNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug);
if (protocol == "Kenwood")
m_nxdnNetwork = new CNXDNKenwoodNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug);
else
m_nxdnNetwork = new CNXDNIcomNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug);
bool ret = m_nxdnNetwork->open();
if (!ret) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2019 Jonathan Naylor, G4KLX
* Copyright (C) 2015-2020 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
@ -39,7 +39,7 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04
#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])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CNXDNControl::CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper) :
CNXDNControl::CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper) :
m_ran(ran),
m_id(id),
m_selfOnly(selfOnly),

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -36,7 +36,7 @@
class CNXDNControl {
public:
CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper);
CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper);
~CNXDNControl();
bool writeModem(unsigned char* data, unsigned int len);
@ -53,7 +53,7 @@ private:
unsigned int m_ran;
unsigned int m_id;
bool m_selfOnly;
CNXDNNetwork* m_network;
INXDNNetwork* m_network;
CDisplay* m_display;
bool m_duplex;
bool m_remoteGateway;

View File

@ -16,7 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "KenwoodNetwork.h"
#include "NXDNKenwoodNetwork.h"
#include "NXDNCRC.h"
#include "Utils.h"
#include "Log.h"
@ -33,12 +33,12 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04
const unsigned int BUFFER_LENGTH = 200U;
CKenwoodNetwork::CKenwoodNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug) :
m_rtpSocket(localPort + 0U),
m_rtcpSocket(localPort + 1U),
CNXDNKenwoodNetwork::CNXDNKenwoodNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gwyAddress, unsigned int gwyPort, bool debug) :
m_rtpSocket(localAddress, localPort + 0U),
m_rtcpSocket(localAddress, localPort + 1U),
m_address(),
m_rtcpPort(rptPort + 1U),
m_rtpPort(rptPort + 0U),
m_rtcpPort(gwyPort + 1U),
m_rtpPort(gwyPort + 0U),
m_headerSeen(false),
m_seen1(false),
m_seen2(false),
@ -58,20 +58,20 @@ m_hangSrc(0U),
m_hangDst(0U)
{
assert(localPort > 0U);
assert(!rptAddress.empty());
assert(rptPort > 0U);
assert(!gwyAddress.empty());
assert(gwyPort > 0U);
m_sacch = new unsigned char[10U];
m_address = CUDPSocket::lookup(rptAddress);
m_address = CUDPSocket::lookup(gwyAddress);
}
CKenwoodNetwork::~CKenwoodNetwork()
CNXDNKenwoodNetwork::~CNXDNKenwoodNetwork()
{
delete[] m_sacch;
}
bool CKenwoodNetwork::open()
bool CNXDNKenwoodNetwork::open()
{
LogMessage("Opening Kenwood connection");
@ -91,23 +91,27 @@ bool CKenwoodNetwork::open()
return true;
}
bool CKenwoodNetwork::write(const unsigned char* data, unsigned int length)
bool CNXDNKenwoodNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type)
{
assert(data != NULL);
switch (data[0U]) {
case 0x81U: // Voice header or trailer
case 0x83U:
switch (type) {
case NNMT_VOICE_HEADER: // Voice header or trailer
case NNMT_VOICE_TRAILER:
case NNMT_DATA_TRAILER: // Data trailer
return processIcomVoiceHeader(data);
case 0xACU: // Voice data
case 0xAEU:
case NNMT_VOICE_BODY: // Voice data
return processIcomVoiceData(data);
case NNMT_DATA_HEADER: // Voice header or trailer
return processIcomDataHeader(data);
case NNMT_DATA_BODY: // Voice data
return processIcomDataData(data);
default:
return false;
}
}
bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData)
bool CNXDNKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData)
{
assert(inData != NULL);
@ -151,7 +155,7 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData)
}
}
bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData)
bool CNXDNKenwoodNetwork::processIcomVoiceData(const unsigned char* inData)
{
assert(inData != NULL);
@ -231,7 +235,7 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData)
return writeRTPVoiceData(outData);
}
bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data)
bool CNXDNKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data)
{
assert(data != NULL);
@ -278,7 +282,7 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data)
return m_rtpSocket.write(buffer, 47U, m_address, m_rtpPort);
}
bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data)
bool CNXDNKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data)
{
assert(data != NULL);
@ -324,7 +328,7 @@ bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data)
return m_rtpSocket.write(buffer, 47U, m_address, m_rtpPort);
}
bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data)
bool CNXDNKenwoodNetwork::writeRTPVoiceData(const unsigned char* data)
{
assert(data != NULL);
@ -370,7 +374,7 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data)
return m_rtpSocket.write(buffer, 59U, m_address, m_rtpPort);
}
bool CKenwoodNetwork::writeRTCPStart()
bool CNXDNKenwoodNetwork::writeRTCPStart()
{
#if defined(_WIN32) || defined(_WIN64)
time_t now;
@ -430,7 +434,7 @@ bool CKenwoodNetwork::writeRTCPStart()
return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort);
}
bool CKenwoodNetwork::writeRTCPPing()
bool CNXDNKenwoodNetwork::writeRTCPPing()
{
unsigned char buffer[30U];
::memset(buffer, 0x00U, 30U);
@ -472,7 +476,7 @@ bool CKenwoodNetwork::writeRTCPPing()
return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort);
}
bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst)
bool CNXDNKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst)
{
m_hangType = type;
m_hangSrc = src;
@ -481,7 +485,7 @@ bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsi
return writeRTCPHang();
}
bool CKenwoodNetwork::writeRTCPHang()
bool CNXDNKenwoodNetwork::writeRTCPHang()
{
unsigned char buffer[30U];
::memset(buffer, 0x00U, 30U);
@ -515,7 +519,7 @@ bool CKenwoodNetwork::writeRTCPHang()
return m_rtcpSocket.write(buffer, 20U, m_address, m_rtcpPort);
}
unsigned int CKenwoodNetwork::read(unsigned char* data)
bool CNXDNKenwoodNetwork::read(unsigned char* data)
{
assert(data != NULL);
@ -525,7 +529,7 @@ unsigned int CKenwoodNetwork::read(unsigned char* data)
unsigned int len = readRTP(data);
switch (len) {
case 0U: // Nothing received
return 0U;
return false;
case 35U: // Voice header or trailer
return processKenwoodVoiceHeader(data);
case 47U: // Voice data
@ -537,11 +541,11 @@ unsigned int CKenwoodNetwork::read(unsigned char* data)
return processKenwoodData(data);
default:
CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len);
return 0U;
return false;
}
}
unsigned int CKenwoodNetwork::readRTP(unsigned char* data)
unsigned int CNXDNKenwoodNetwork::readRTP(unsigned char* data)
{
assert(data != NULL);
@ -567,7 +571,7 @@ unsigned int CKenwoodNetwork::readRTP(unsigned char* data)
return length - 12U;
}
unsigned int CKenwoodNetwork::readRTCP(unsigned char* data)
unsigned int CNXDNKenwoodNetwork::readRTCP(unsigned char* data)
{
assert(data != NULL);
@ -598,7 +602,11 @@ unsigned int CKenwoodNetwork::readRTCP(unsigned char* data)
return length - 12U;
}
void CKenwoodNetwork::close()
void CNXDNKenwoodNetwork::reset()
{
}
void CNXDNKenwoodNetwork::close()
{
m_rtcpSocket.close();
m_rtpSocket.close();
@ -606,7 +614,7 @@ void CKenwoodNetwork::close()
LogMessage("Closing Kenwood connection");
}
void CKenwoodNetwork::clock(unsigned int ms)
void CNXDNKenwoodNetwork::clock(unsigned int ms)
{
m_rtcpTimer.clock(ms);
if (m_rtcpTimer.isRunning() && m_rtcpTimer.hasExpired()) {
@ -624,7 +632,7 @@ void CKenwoodNetwork::clock(unsigned int ms)
}
}
unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData)
bool CNXDNKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData)
{
assert(inData != NULL);
@ -667,7 +675,7 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData)
m_seen2 = false;
m_seen3 = false;
m_seen4 = false;
return 33U;
return true;
case 0x08U:
::memcpy(inData, outData, 33U);
m_headerSeen = false;
@ -675,13 +683,13 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData)
m_seen2 = false;
m_seen3 = false;
m_seen4 = false;
return 33U;
return true;
default:
return 0U;
return false;
}
}
unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData)
bool CNXDNKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData)
{
assert(inData != NULL);
@ -764,17 +772,18 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData)
::memcpy(inData, outData, 33U);
return 33U;
return true;
}
unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData)
bool CNXDNKenwoodNetwork::processKenwoodData(unsigned char* inData)
{
if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U)
return 0U;
return false;
unsigned char outData[50U];
if (inData[7U] == 0x09U || inData[7U] == 0x08U) {
// XXX
outData[0U] = 0x90U;
outData[1U] = inData[8U];
outData[2U] = inData[7U];
@ -783,7 +792,7 @@ unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData)
outData[5U] = inData[12U];
outData[6U] = inData[11U];
::memcpy(inData, outData, 7U);
return 7U;
return true;
} else {
outData[0U] = 0x90U;
outData[1U] = inData[8U];
@ -810,11 +819,11 @@ unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData)
outData[22U] = inData[27U];
outData[23U] = inData[29U];
::memcpy(inData, outData, 24U);
return 24U;
return true;
}
}
unsigned long CKenwoodNetwork::getTimeStamp() const
unsigned long CNXDNKenwoodNetwork::getTimeStamp() const
{
unsigned long timeStamp = 0UL;
@ -845,7 +854,7 @@ unsigned long CKenwoodNetwork::getTimeStamp() const
return timeStamp;
}
unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData)
bool CNXDNKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData)
{
assert(inData != NULL);
@ -899,7 +908,7 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData
}
if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4)
return 0U;
return false;
// Create a dummy header
// Header SACCH

View File

@ -16,28 +16,32 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef KenwoodNetwork_H
#define KenwoodNetwork_H
#ifndef NXDNKenwoodNetwork_H
#define NXDNKenwoodNetwork_H
#include "RptNetwork.h"
#include "NXDNNetwork.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CKenwoodNetwork : public IRptNetwork {
class CNXDNKenwoodNetwork : public INXDNNetwork {
public:
CKenwoodNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug);
virtual ~CKenwoodNetwork();
CNXDNKenwoodNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gwyAddress, unsigned int gwyPort, bool debug);
virtual ~CNXDNKenwoodNetwork();
virtual bool open();
virtual bool write(const unsigned char* data, unsigned int length);
virtual void enable(bool enabled);
virtual unsigned int read(unsigned char* data);
virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type);
virtual void close();
virtual bool read(unsigned char* data);
virtual void reset();
virtual void close();
virtual void clock(unsigned int ms);
@ -67,10 +71,12 @@ private:
bool processIcomVoiceHeader(const unsigned char* data);
bool processIcomVoiceData(const unsigned char* data);
unsigned int processKenwoodVoiceHeader(unsigned char* data);
unsigned int processKenwoodVoiceData(unsigned char* data);
unsigned int processKenwoodVoiceLateEntry(unsigned char* data);
unsigned int processKenwoodData(unsigned char* data);
bool processIcomDataHeader(const unsigned char* data);
bool processIcomDataData(const unsigned char* data);
bool processKenwoodVoiceHeader(unsigned char* data);
bool processKenwoodVoiceData(unsigned char* data);
bool processKenwoodVoiceLateEntry(unsigned char* data);
bool processKenwoodData(unsigned char* data);
bool writeRTPVoiceHeader(const unsigned char* data);
bool writeRTPVoiceData(const unsigned char* data);
bool writeRTPVoiceTrailer(const unsigned char* data);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -258,3 +258,31 @@ void CUDPSocket::close()
::close(m_fd);
#endif
}
unsigned long CUDPSocket::getLocalAddress() const
{
unsigned long address = 0UL;
char hostname[80U];
int ret = ::gethostname(hostname, 80);
if (ret == -1)
return 0UL;
struct hostent* phe = ::gethostbyname(hostname);
if (phe == NULL)
return 0UL;
if (phe->h_addrtype != AF_INET)
return 0UL;
for (unsigned int i = 0U; phe->h_addr_list[i] != NULL; i++) {
struct in_addr addr;
::memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
if (addr.s_addr != INADDR_LOOPBACK) {
address = addr.s_addr;
break;
}
}
return address;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -47,7 +47,9 @@ public:
void close();
static in_addr lookup(const std::string& hostName);
unsigned long getLocalAddress() const;
static in_addr lookup(const std::string& hostName);
private:
std::string m_address;