mirror of
https://github.com/ShaYmez/NXDNClients.git
synced 2025-07-31 12:12:24 -04:00
Add the Kenwood protocol.
This commit is contained in:
parent
b294435e9a
commit
06cee5c744
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -48,6 +48,7 @@ m_logFileRoot(),
|
|||||||
m_networkPort(0U),
|
m_networkPort(0U),
|
||||||
m_networkDebug(false),
|
m_networkDebug(false),
|
||||||
m_nxCoreEnabled(false),
|
m_nxCoreEnabled(false),
|
||||||
|
m_nxCoreProtocol("Icom"),
|
||||||
m_nxCoreAddress(),
|
m_nxCoreAddress(),
|
||||||
m_nxCoreTGEnable(0U),
|
m_nxCoreTGEnable(0U),
|
||||||
m_nxCoreTGDisable(0U),
|
m_nxCoreTGDisable(0U),
|
||||||
@ -123,6 +124,8 @@ bool CConf::read()
|
|||||||
} else if (section == SECTION_NXCORE) {
|
} else if (section == SECTION_NXCORE) {
|
||||||
if (::strcmp(key, "Enabled") == 0)
|
if (::strcmp(key, "Enabled") == 0)
|
||||||
m_nxCoreEnabled = ::atoi(value) == 1;
|
m_nxCoreEnabled = ::atoi(value) == 1;
|
||||||
|
else if (::strcmp(key, "Protocol") == 0)
|
||||||
|
m_nxCoreProtocol = value;
|
||||||
else if (::strcmp(key, "Address") == 0)
|
else if (::strcmp(key, "Address") == 0)
|
||||||
m_nxCoreAddress = value;
|
m_nxCoreAddress = value;
|
||||||
else if (::strcmp(key, "TGEnable") == 0)
|
else if (::strcmp(key, "TGEnable") == 0)
|
||||||
@ -194,6 +197,11 @@ bool CConf::getNXCoreEnabled() const
|
|||||||
return m_nxCoreEnabled;
|
return m_nxCoreEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CConf::getNXCoreProtocol() const
|
||||||
|
{
|
||||||
|
return m_nxCoreProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CConf::getNXCoreAddress() const
|
std::string CConf::getNXCoreAddress() const
|
||||||
{
|
{
|
||||||
return m_nxCoreAddress;
|
return m_nxCoreAddress;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -50,6 +50,7 @@ public:
|
|||||||
|
|
||||||
// The NXCore section
|
// The NXCore section
|
||||||
bool getNXCoreEnabled() const;
|
bool getNXCoreEnabled() const;
|
||||||
|
std::string getNXCoreProtocol() const;
|
||||||
std::string getNXCoreAddress() const;
|
std::string getNXCoreAddress() const;
|
||||||
unsigned short getNXCoreTGEnable() const;
|
unsigned short getNXCoreTGEnable() const;
|
||||||
unsigned short getNXCoreTGDisable() const;
|
unsigned short getNXCoreTGDisable() const;
|
||||||
@ -72,6 +73,7 @@ private:
|
|||||||
bool m_networkDebug;
|
bool m_networkDebug;
|
||||||
|
|
||||||
bool m_nxCoreEnabled;
|
bool m_nxCoreEnabled;
|
||||||
|
std::string m_nxCoreProtocol;
|
||||||
std::string m_nxCoreAddress;
|
std::string m_nxCoreAddress;
|
||||||
unsigned short m_nxCoreTGEnable;
|
unsigned short m_nxCoreTGEnable;
|
||||||
unsigned short m_nxCoreTGDisable;
|
unsigned short m_nxCoreTGDisable;
|
||||||
|
23
NXDNReflector/CoreNetwork.cpp
Normal file
23
NXDNReflector/CoreNetwork.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016,2018,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
|
||||||
|
* 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 "CoreNetwork.h"
|
||||||
|
|
||||||
|
ICoreNetwork::~ICoreNetwork()
|
||||||
|
{
|
||||||
|
}
|
55
NXDNReflector/CoreNetwork.h
Normal file
55
NXDNReflector/CoreNetwork.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016,2018,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
|
||||||
|
* 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 CoreNetwork_H
|
||||||
|
#define CoreNetwork_H
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#else
|
||||||
|
#include <winsock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class ICoreNetwork {
|
||||||
|
public:
|
||||||
|
virtual ~ICoreNetwork() = 0;
|
||||||
|
|
||||||
|
virtual bool open() = 0;
|
||||||
|
|
||||||
|
virtual bool write(const unsigned char* data, unsigned int length) = 0;
|
||||||
|
|
||||||
|
virtual unsigned int read(unsigned char* data) = 0;
|
||||||
|
|
||||||
|
virtual void close() = 0;
|
||||||
|
|
||||||
|
virtual void clock(unsigned int ms) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -16,7 +16,7 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "NXCoreNetwork.h"
|
#include "IcomNetwork.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
@ -26,10 +26,10 @@
|
|||||||
|
|
||||||
const unsigned int BUFFER_LENGTH = 200U;
|
const unsigned int BUFFER_LENGTH = 200U;
|
||||||
|
|
||||||
const unsigned int NXCORE_PORT = 41300U;
|
const unsigned int ICOM_PORT = 41300U;
|
||||||
|
|
||||||
CNXCoreNetwork::CNXCoreNetwork(const std::string& address, bool debug) :
|
CIcomNetwork::CIcomNetwork(const std::string& address, bool debug) :
|
||||||
m_socket(NXCORE_PORT),
|
m_socket(ICOM_PORT),
|
||||||
m_address(),
|
m_address(),
|
||||||
m_debug(debug)
|
m_debug(debug)
|
||||||
{
|
{
|
||||||
@ -38,13 +38,13 @@ m_debug(debug)
|
|||||||
m_address = CUDPSocket::lookup(address);
|
m_address = CUDPSocket::lookup(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
CNXCoreNetwork::~CNXCoreNetwork()
|
CIcomNetwork::~CIcomNetwork()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CNXCoreNetwork::open()
|
bool CIcomNetwork::open()
|
||||||
{
|
{
|
||||||
LogMessage("Opening NXCore network connection");
|
LogMessage("Opening Icom network connection");
|
||||||
|
|
||||||
if (m_address.s_addr == INADDR_NONE)
|
if (m_address.s_addr == INADDR_NONE)
|
||||||
return false;
|
return false;
|
||||||
@ -52,7 +52,7 @@ bool CNXCoreNetwork::open()
|
|||||||
return m_socket.open();
|
return m_socket.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CNXCoreNetwork::write(const unsigned char* data, unsigned int len)
|
bool CIcomNetwork::write(const unsigned char* data, unsigned int len)
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
@ -81,12 +81,12 @@ bool CNXCoreNetwork::write(const unsigned char* data, unsigned int len)
|
|||||||
::memcpy(buffer + 40U, data + 10U, 33U);
|
::memcpy(buffer + 40U, data + 10U, 33U);
|
||||||
|
|
||||||
if (m_debug)
|
if (m_debug)
|
||||||
CUtils::dump(1U, "NXCore Network Data Sent", buffer, 102U);
|
CUtils::dump(1U, "Icom Network Data Sent", buffer, 102U);
|
||||||
|
|
||||||
return m_socket.write(buffer, 102U, m_address, NXCORE_PORT);
|
return m_socket.write(buffer, 102U, m_address, ICOM_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CNXCoreNetwork::read(unsigned char* data)
|
unsigned int CIcomNetwork::read(unsigned char* data)
|
||||||
{
|
{
|
||||||
unsigned char buffer[BUFFER_LENGTH];
|
unsigned char buffer[BUFFER_LENGTH];
|
||||||
|
|
||||||
@ -97,8 +97,8 @@ unsigned int CNXCoreNetwork::read(unsigned char* data)
|
|||||||
return 0U;
|
return 0U;
|
||||||
|
|
||||||
// Check if the data is for us
|
// Check if the data is for us
|
||||||
if (m_address.s_addr != address.s_addr || port != NXCORE_PORT) {
|
if (m_address.s_addr != address.s_addr || port != ICOM_PORT) {
|
||||||
LogMessage("NXCore packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, NXCORE_PORT, port);
|
LogMessage("Icom packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, ICOM_PORT, port);
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,16 +110,20 @@ unsigned int CNXCoreNetwork::read(unsigned char* data)
|
|||||||
return 0U;
|
return 0U;
|
||||||
|
|
||||||
if (m_debug)
|
if (m_debug)
|
||||||
CUtils::dump(1U, "NXCore Network Data Received", buffer, length);
|
CUtils::dump(1U, "Icom Network Data Received", buffer, length);
|
||||||
|
|
||||||
::memcpy(data, buffer + 40U, 33U);
|
::memcpy(data, buffer + 40U, 33U);
|
||||||
|
|
||||||
return 33U;
|
return 33U;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNXCoreNetwork::close()
|
void CIcomNetwork::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIcomNetwork::close()
|
||||||
{
|
{
|
||||||
m_socket.close();
|
m_socket.close();
|
||||||
|
|
||||||
LogMessage("Closing NXCore network connection");
|
LogMessage("Closing Icom network connection");
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -16,27 +16,30 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NXCoreNetwork_H
|
#ifndef IcomNetwork_H
|
||||||
#define NXCoreNetwork_H
|
#define IcomNetwork_H
|
||||||
|
|
||||||
|
#include "CoreNetwork.h"
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class CNXCoreNetwork {
|
class CIcomNetwork : public ICoreNetwork {
|
||||||
public:
|
public:
|
||||||
CNXCoreNetwork(const std::string& address, bool debug);
|
CIcomNetwork(const std::string& address, bool debug);
|
||||||
~CNXCoreNetwork();
|
virtual ~CIcomNetwork();
|
||||||
|
|
||||||
bool open();
|
virtual bool open();
|
||||||
|
|
||||||
bool write(const unsigned char* data, unsigned int len);
|
virtual bool write(const unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
unsigned int read(unsigned char* data);
|
virtual unsigned int read(unsigned char* data);
|
||||||
|
|
||||||
void close();
|
virtual void close();
|
||||||
|
|
||||||
|
virtual void clock(unsigned int ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CUDPSocket m_socket;
|
CUDPSocket m_socket;
|
645
NXDNReflector/KenwoodNetwork.cpp
Normal file
645
NXDNReflector/KenwoodNetwork.cpp
Normal file
@ -0,0 +1,645 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016,2018,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
|
||||||
|
* 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 "KenwoodNetwork.h"
|
||||||
|
#include "NXDNCRC.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||||
|
|
||||||
|
#define WRITE_BIT(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_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||||
|
|
||||||
|
const unsigned int BUFFER_LENGTH = 200U;
|
||||||
|
|
||||||
|
const unsigned int RTP_PORT = 64000U;
|
||||||
|
const unsigned int RTCP_PORT = 64001U;
|
||||||
|
|
||||||
|
CKenwoodNetwork::CKenwoodNetwork(const std::string& address, bool debug) :
|
||||||
|
m_rtcpSocket(RTCP_PORT),
|
||||||
|
m_rtpSocket(RTP_PORT),
|
||||||
|
m_stopWatch(),
|
||||||
|
m_address(),
|
||||||
|
m_seqNo(0U),
|
||||||
|
m_timeStamp(0U),
|
||||||
|
m_ssrc(0U),
|
||||||
|
m_debug(debug),
|
||||||
|
m_timer(1000U, 0U, 200U)
|
||||||
|
{
|
||||||
|
assert(!address.empty());
|
||||||
|
|
||||||
|
m_address = CUDPSocket::lookup(address);
|
||||||
|
|
||||||
|
::srand((unsigned int)m_stopWatch.time());
|
||||||
|
}
|
||||||
|
|
||||||
|
CKenwoodNetwork::~CKenwoodNetwork()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::open()
|
||||||
|
{
|
||||||
|
LogMessage("Opening Kenwood connection");
|
||||||
|
|
||||||
|
if (m_address.s_addr == INADDR_NONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_rtcpSocket.open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_rtpSocket.open()) {
|
||||||
|
m_rtcpSocket.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ssrc = ::rand();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::write(const unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
switch (data[0U]) {
|
||||||
|
case 0x81U: // Voice header or trailer
|
||||||
|
case 0x83U:
|
||||||
|
return processIcomVoiceHeader(data);
|
||||||
|
case 0xACU: // Voice data
|
||||||
|
case 0xAEU:
|
||||||
|
return processIcomVoiceData(data);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData)
|
||||||
|
{
|
||||||
|
assert(inData != NULL);
|
||||||
|
|
||||||
|
unsigned char outData[30U];
|
||||||
|
::memset(outData, 0x00U, 30U);
|
||||||
|
|
||||||
|
// SACCH
|
||||||
|
outData[0U] = inData[2U];
|
||||||
|
outData[1U] = inData[1U];
|
||||||
|
outData[2U] = inData[4U] & 0xC0U;
|
||||||
|
outData[3U] = inData[3U];
|
||||||
|
|
||||||
|
// FACCH 1+2
|
||||||
|
outData[4U] = outData[14U] = inData[6U];
|
||||||
|
outData[5U] = outData[15U] = inData[5U];
|
||||||
|
outData[6U] = outData[16U] = inData[8U];
|
||||||
|
outData[7U] = outData[17U] = inData[7U];
|
||||||
|
outData[8U] = outData[18U] = inData[10U];
|
||||||
|
outData[9U] = outData[19U] = inData[9U];
|
||||||
|
outData[10U] = outData[20U] = inData[12U];
|
||||||
|
outData[11U] = outData[21U] = inData[11U];
|
||||||
|
|
||||||
|
unsigned short src = (inData[8U] << 8) + (inData[9U] << 0);
|
||||||
|
unsigned short dst = (inData[10U] << 8) + (inData[11U] << 0);
|
||||||
|
unsigned char type = (inData[7U] >> 5) & 0x07U;
|
||||||
|
|
||||||
|
switch (inData[5U] & 0x3FU) {
|
||||||
|
case 0x01U:
|
||||||
|
m_timer.start();
|
||||||
|
writeRTCPData(type, src, dst);
|
||||||
|
return writeRTPVoiceHeader(outData);
|
||||||
|
case 0x08U:
|
||||||
|
m_timer.stop();
|
||||||
|
writeRTCPData(type, src, dst);
|
||||||
|
return writeRTPVoiceTrailer(outData);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData)
|
||||||
|
{
|
||||||
|
assert(inData != NULL);
|
||||||
|
|
||||||
|
unsigned char outData[40U], temp[10U];
|
||||||
|
::memset(outData, 0x00U, 40U);
|
||||||
|
|
||||||
|
// SACCH
|
||||||
|
outData[0U] = inData[2U];
|
||||||
|
outData[1U] = inData[1U];
|
||||||
|
outData[2U] = inData[4U] & 0xC0U;
|
||||||
|
outData[3U] = inData[3U];
|
||||||
|
|
||||||
|
// Audio 1
|
||||||
|
::memset(temp, 0x00U, 10U);
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
unsigned int offset = (5U * 8U) + i;
|
||||||
|
bool b = READ_BIT(inData, offset);
|
||||||
|
WRITE_BIT(temp, i, b);
|
||||||
|
}
|
||||||
|
outData[4U] = temp[1U];
|
||||||
|
outData[5U] = temp[0U];
|
||||||
|
outData[6U] = temp[3U];
|
||||||
|
outData[7U] = temp[2U];
|
||||||
|
outData[8U] = temp[5U];
|
||||||
|
outData[9U] = temp[4U];
|
||||||
|
outData[10U] = temp[7U];
|
||||||
|
outData[11U] = temp[6U];
|
||||||
|
|
||||||
|
// Audio 2
|
||||||
|
::memset(temp, 0x00U, 10U);
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
unsigned int offset = (5U * 8U) + 49U + i;
|
||||||
|
bool b = READ_BIT(inData, offset);
|
||||||
|
WRITE_BIT(temp, i, b);
|
||||||
|
}
|
||||||
|
outData[12U] = temp[1U];
|
||||||
|
outData[13U] = temp[0U];
|
||||||
|
outData[14U] = temp[3U];
|
||||||
|
outData[15U] = temp[2U];
|
||||||
|
outData[16U] = temp[5U];
|
||||||
|
outData[17U] = temp[4U];
|
||||||
|
outData[18U] = temp[7U];
|
||||||
|
outData[19U] = temp[6U];
|
||||||
|
|
||||||
|
// Audio 3
|
||||||
|
::memset(temp, 0x00U, 10U);
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
unsigned int offset = (19U * 8U) + i;
|
||||||
|
bool b = READ_BIT(inData, offset);
|
||||||
|
WRITE_BIT(temp, i, b);
|
||||||
|
}
|
||||||
|
outData[20U] = temp[1U];
|
||||||
|
outData[21U] = temp[0U];
|
||||||
|
outData[22U] = temp[3U];
|
||||||
|
outData[23U] = temp[2U];
|
||||||
|
outData[24U] = temp[5U];
|
||||||
|
outData[25U] = temp[4U];
|
||||||
|
outData[26U] = temp[7U];
|
||||||
|
outData[27U] = temp[6U];
|
||||||
|
|
||||||
|
// Audio 4
|
||||||
|
::memset(temp, 0x00U, 10U);
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
unsigned int offset = (19U * 8U) + 49U + i;
|
||||||
|
bool b = READ_BIT(inData, offset);
|
||||||
|
WRITE_BIT(temp, i, b);
|
||||||
|
}
|
||||||
|
outData[28U] = temp[1U];
|
||||||
|
outData[29U] = temp[0U];
|
||||||
|
outData[30U] = temp[3U];
|
||||||
|
outData[31U] = temp[2U];
|
||||||
|
outData[32U] = temp[5U];
|
||||||
|
outData[33U] = temp[4U];
|
||||||
|
outData[34U] = temp[7U];
|
||||||
|
outData[35U] = temp[6U];
|
||||||
|
|
||||||
|
return writeRTPVoiceData(outData);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[50U];
|
||||||
|
::memset(buffer, 0x00U, 50U);
|
||||||
|
|
||||||
|
buffer[0U] = 0x80U;
|
||||||
|
buffer[1U] = 0x66U;
|
||||||
|
|
||||||
|
buffer[2U] = (m_seqNo >> 8) & 0xFFU;
|
||||||
|
buffer[3U] = (m_seqNo >> 0) & 0xFFU;
|
||||||
|
m_seqNo++;
|
||||||
|
|
||||||
|
m_timeStamp = (unsigned long)m_stopWatch.time();
|
||||||
|
|
||||||
|
buffer[4U] = (m_timeStamp >> 24) & 0xFFU;
|
||||||
|
buffer[5U] = (m_timeStamp >> 16) & 0xFFU;
|
||||||
|
buffer[6U] = (m_timeStamp >> 8) & 0xFFU;
|
||||||
|
buffer[7U] = (m_timeStamp >> 0) & 0xFFU;
|
||||||
|
m_timeStamp += 640U;
|
||||||
|
|
||||||
|
buffer[8U] = (m_ssrc >> 24) & 0xFFU;
|
||||||
|
buffer[9U] = (m_ssrc >> 16) & 0xFFU;
|
||||||
|
buffer[10U] = (m_ssrc >> 8) & 0xFFU;
|
||||||
|
buffer[11U] = (m_ssrc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[16U] = 0x03U;
|
||||||
|
buffer[17U] = 0x03U;
|
||||||
|
buffer[18U] = 0x04U;
|
||||||
|
buffer[19U] = 0x04U;
|
||||||
|
buffer[20U] = 0x0AU;
|
||||||
|
buffer[21U] = 0x05U;
|
||||||
|
buffer[22U] = 0x0AU;
|
||||||
|
|
||||||
|
::memcpy(buffer + 23U, data, 24U);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U);
|
||||||
|
|
||||||
|
return m_rtpSocket.write(buffer, 47U, m_address, RTP_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[50U];
|
||||||
|
::memset(buffer, 0x00U, 50U);
|
||||||
|
|
||||||
|
buffer[0U] = 0x80U;
|
||||||
|
buffer[1U] = 0x66U;
|
||||||
|
|
||||||
|
buffer[2U] = (m_seqNo >> 8) & 0xFFU;
|
||||||
|
buffer[3U] = (m_seqNo >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[4U] = (m_timeStamp >> 24) & 0xFFU;
|
||||||
|
buffer[5U] = (m_timeStamp >> 16) & 0xFFU;
|
||||||
|
buffer[6U] = (m_timeStamp >> 8) & 0xFFU;
|
||||||
|
buffer[7U] = (m_timeStamp >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[8U] = (m_ssrc >> 24) & 0xFFU;
|
||||||
|
buffer[9U] = (m_ssrc >> 16) & 0xFFU;
|
||||||
|
buffer[10U] = (m_ssrc >> 8) & 0xFFU;
|
||||||
|
buffer[11U] = (m_ssrc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[16U] = 0x03U;
|
||||||
|
buffer[17U] = 0x03U;
|
||||||
|
buffer[18U] = 0x04U;
|
||||||
|
buffer[19U] = 0x04U;
|
||||||
|
buffer[20U] = 0x0AU;
|
||||||
|
buffer[21U] = 0x05U;
|
||||||
|
buffer[22U] = 0x0AU;
|
||||||
|
|
||||||
|
::memcpy(buffer + 23U, data, 24U);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U);
|
||||||
|
|
||||||
|
return m_rtpSocket.write(buffer, 47U, m_address, RTP_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[60U];
|
||||||
|
::memset(buffer, 0x00U, 60U);
|
||||||
|
|
||||||
|
buffer[0U] = 0x80U;
|
||||||
|
buffer[1U] = 0x66U;
|
||||||
|
|
||||||
|
buffer[2U] = (m_seqNo >> 8) & 0xFFU;
|
||||||
|
buffer[3U] = (m_seqNo >> 0) & 0xFFU;
|
||||||
|
m_seqNo++;
|
||||||
|
|
||||||
|
buffer[4U] = (m_timeStamp >> 24) & 0xFFU;
|
||||||
|
buffer[5U] = (m_timeStamp >> 16) & 0xFFU;
|
||||||
|
buffer[6U] = (m_timeStamp >> 8) & 0xFFU;
|
||||||
|
buffer[7U] = (m_timeStamp >> 0) & 0xFFU;
|
||||||
|
m_timeStamp += 640U;
|
||||||
|
|
||||||
|
buffer[8U] = (m_ssrc >> 24) & 0xFFU;
|
||||||
|
buffer[9U] = (m_ssrc >> 16) & 0xFFU;
|
||||||
|
buffer[10U] = (m_ssrc >> 8) & 0xFFU;
|
||||||
|
buffer[11U] = (m_ssrc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[16U] = 0x03U;
|
||||||
|
buffer[17U] = 0x02U;
|
||||||
|
buffer[18U] = 0x04U;
|
||||||
|
buffer[19U] = 0x07U;
|
||||||
|
buffer[20U] = 0x10U;
|
||||||
|
buffer[21U] = 0x08U;
|
||||||
|
buffer[22U] = 0x10U;
|
||||||
|
|
||||||
|
::memcpy(buffer + 23U, data, 36U);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 59U);
|
||||||
|
|
||||||
|
return m_rtpSocket.write(buffer, 59U, m_address, RTP_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::writeRTCPPing()
|
||||||
|
{
|
||||||
|
unsigned char buffer[30U];
|
||||||
|
::memset(buffer, 0x00U, 30U);
|
||||||
|
|
||||||
|
buffer[0U] = 0x8AU;
|
||||||
|
buffer[1U] = 0xCCU;
|
||||||
|
|
||||||
|
buffer[3U] = 0x06U;
|
||||||
|
|
||||||
|
buffer[4U] = (m_ssrc >> 24) & 0xFFU;
|
||||||
|
buffer[5U] = (m_ssrc >> 16) & 0xFFU;
|
||||||
|
buffer[6U] = (m_ssrc >> 8) & 0xFFU;
|
||||||
|
buffer[7U] = (m_ssrc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[8U] = 'K';
|
||||||
|
buffer[9U] = 'W';
|
||||||
|
buffer[10U] = 'N';
|
||||||
|
buffer[11U] = 'E';
|
||||||
|
|
||||||
|
buffer[22U] = 0x02U;
|
||||||
|
|
||||||
|
buffer[24U] = 0x01U;
|
||||||
|
buffer[25U] = 0x01U;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U);
|
||||||
|
|
||||||
|
return m_rtcpSocket.write(buffer, 28U, m_address, RTCP_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::writeRTCPData(unsigned char type, unsigned short src, unsigned short dst)
|
||||||
|
{
|
||||||
|
unsigned char buffer[20U];
|
||||||
|
::memset(buffer, 0x00U, 20U);
|
||||||
|
|
||||||
|
buffer[0U] = 0x8BU;
|
||||||
|
buffer[1U] = 0xCCU;
|
||||||
|
|
||||||
|
buffer[3U] = 0x04U;
|
||||||
|
|
||||||
|
buffer[4U] = (m_ssrc >> 24) & 0xFFU;
|
||||||
|
buffer[5U] = (m_ssrc >> 16) & 0xFFU;
|
||||||
|
buffer[6U] = (m_ssrc >> 8) & 0xFFU;
|
||||||
|
buffer[7U] = (m_ssrc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[8U] = 'K';
|
||||||
|
buffer[9U] = 'W';
|
||||||
|
buffer[10U] = 'N';
|
||||||
|
buffer[11U] = 'E';
|
||||||
|
|
||||||
|
buffer[12U] = (src >> 8) & 0xFFU;
|
||||||
|
buffer[13U] = (src >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[14U] = (dst >> 8) & 0xFFU;
|
||||||
|
buffer[15U] = (dst >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[16U] = type;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U);
|
||||||
|
|
||||||
|
return m_rtcpSocket.write(buffer, 20U, m_address, RTCP_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CKenwoodNetwork::read(unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char dummy[BUFFER_LENGTH];
|
||||||
|
readRTCP(dummy);
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
unsigned int len = readRTP(data);
|
||||||
|
if (len > 0U) {
|
||||||
|
switch (data[9U]) {
|
||||||
|
case 0x05U: // Voice header or trailer
|
||||||
|
ret = processKenwoodVoiceHeader(data);
|
||||||
|
if (!ret)
|
||||||
|
return 0U;
|
||||||
|
return 33U;
|
||||||
|
case 0x08U: // Voice data
|
||||||
|
processKenwoodVoiceData(data);
|
||||||
|
return 33U;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len);
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CKenwoodNetwork::readRTP(unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[BUFFER_LENGTH];
|
||||||
|
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
int length = m_rtpSocket.read(buffer, BUFFER_LENGTH, address, port);
|
||||||
|
if (length <= 0)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
// Check if the data is for us
|
||||||
|
if (m_address.s_addr != address.s_addr || port != RTP_PORT) {
|
||||||
|
LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTP_PORT, port);
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length);
|
||||||
|
|
||||||
|
if (length != 47 && length != 59) {
|
||||||
|
LogError("Invalid RTP length of %d", length);
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
::memcpy(data, buffer + 12U, length - 12U);
|
||||||
|
|
||||||
|
return length - 12U;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CKenwoodNetwork::readRTCP(unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[BUFFER_LENGTH];
|
||||||
|
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
int length = m_rtcpSocket.read(buffer, BUFFER_LENGTH, address, port);
|
||||||
|
if (length <= 0)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
// Check if the data is for us
|
||||||
|
if (m_address.s_addr != address.s_addr || port != RTCP_PORT) {
|
||||||
|
LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTCP_PORT, port);
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length);
|
||||||
|
|
||||||
|
if (length != 20 && length != 28) {
|
||||||
|
LogError("Invalid RTCP length of %d", length);
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) {
|
||||||
|
LogError("Missing RTCP KWNE signature");
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
::memcpy(data, buffer + 12U, length - 12U);
|
||||||
|
|
||||||
|
return length - 12U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CKenwoodNetwork::close()
|
||||||
|
{
|
||||||
|
m_rtcpSocket.close();
|
||||||
|
m_rtpSocket.close();
|
||||||
|
|
||||||
|
LogMessage("Closing Kenwood connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CKenwoodNetwork::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
m_timer.clock(ms);
|
||||||
|
if (m_timer.isRunning() && m_timer.hasExpired()) {
|
||||||
|
writeRTCPPing();
|
||||||
|
m_timer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData)
|
||||||
|
{
|
||||||
|
assert(inData != NULL);
|
||||||
|
|
||||||
|
unsigned char outData[50U], temp[20U];
|
||||||
|
::memset(outData, 0x00U, 50U);
|
||||||
|
|
||||||
|
// LICH
|
||||||
|
outData[0U] = 0x83U;
|
||||||
|
|
||||||
|
// SACCH
|
||||||
|
::memset(temp, 0x00U, 20U);
|
||||||
|
temp[0U] = inData[12U];
|
||||||
|
temp[1U] = inData[11U];
|
||||||
|
temp[2U] = inData[14U];
|
||||||
|
temp[3U] = inData[13U];
|
||||||
|
CNXDNCRC::encodeCRC6(temp, 26U);
|
||||||
|
::memcpy(outData + 1U, temp, 4U);
|
||||||
|
|
||||||
|
// FACCH 1+2
|
||||||
|
::memset(temp, 0x00U, 20U);
|
||||||
|
temp[0U] = inData[16U];
|
||||||
|
temp[1U] = inData[15U];
|
||||||
|
temp[2U] = inData[18U];
|
||||||
|
temp[3U] = inData[17U];
|
||||||
|
temp[4U] = inData[20U];
|
||||||
|
temp[5U] = inData[19U];
|
||||||
|
temp[6U] = inData[22U];
|
||||||
|
temp[7U] = inData[21U];
|
||||||
|
temp[8U] = inData[24U];
|
||||||
|
temp[9U] = inData[23U];
|
||||||
|
CNXDNCRC::encodeCRC12(temp, 80U);
|
||||||
|
::memcpy(outData + 5U, temp, 12U);
|
||||||
|
::memcpy(outData + 19U, temp, 12U);
|
||||||
|
|
||||||
|
switch (outData[5U] & 0x3FU) {
|
||||||
|
case 0x01U:
|
||||||
|
case 0x08U:
|
||||||
|
::memcpy(inData, outData, 33U);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData)
|
||||||
|
{
|
||||||
|
assert(inData != NULL);
|
||||||
|
|
||||||
|
unsigned char outData[50U], temp[20U];
|
||||||
|
::memset(outData, 0x00U, 50U);
|
||||||
|
|
||||||
|
// LICH
|
||||||
|
outData[0U] = 0xAEU;
|
||||||
|
|
||||||
|
// SACCH
|
||||||
|
::memset(temp, 0x00U, 20U);
|
||||||
|
temp[0U] = inData[12U];
|
||||||
|
temp[1U] = inData[11U];
|
||||||
|
temp[2U] = inData[14U];
|
||||||
|
temp[3U] = inData[13U];
|
||||||
|
CNXDNCRC::encodeCRC6(temp, 26U);
|
||||||
|
::memcpy(outData + 1U, temp, 4U);
|
||||||
|
|
||||||
|
// AMBE 1+2
|
||||||
|
unsigned int n = 5U * 8U;
|
||||||
|
|
||||||
|
temp[0U] = inData[16U];
|
||||||
|
temp[1U] = inData[15U];
|
||||||
|
temp[2U] = inData[18U];
|
||||||
|
temp[3U] = inData[17U];
|
||||||
|
temp[4U] = inData[20U];
|
||||||
|
temp[5U] = inData[19U];
|
||||||
|
temp[6U] = inData[22U];
|
||||||
|
temp[7U] = inData[21U];
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++, n++) {
|
||||||
|
bool b = READ_BIT(temp, i);
|
||||||
|
WRITE_BIT(outData, n, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
temp[0U] = inData[24U];
|
||||||
|
temp[1U] = inData[23U];
|
||||||
|
temp[2U] = inData[26U];
|
||||||
|
temp[3U] = inData[25U];
|
||||||
|
temp[4U] = inData[28U];
|
||||||
|
temp[5U] = inData[27U];
|
||||||
|
temp[6U] = inData[30U];
|
||||||
|
temp[7U] = inData[29U];
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++, n++) {
|
||||||
|
bool b = READ_BIT(temp, i);
|
||||||
|
WRITE_BIT(outData, n, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AMBE 3+4
|
||||||
|
n = 19U * 8U;
|
||||||
|
|
||||||
|
temp[0U] = inData[32U];
|
||||||
|
temp[1U] = inData[31U];
|
||||||
|
temp[2U] = inData[34U];
|
||||||
|
temp[3U] = inData[33U];
|
||||||
|
temp[4U] = inData[36U];
|
||||||
|
temp[5U] = inData[35U];
|
||||||
|
temp[6U] = inData[38U];
|
||||||
|
temp[7U] = inData[37U];
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++, n++) {
|
||||||
|
bool b = READ_BIT(temp, i);
|
||||||
|
WRITE_BIT(outData, n, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
temp[0U] = inData[40U];
|
||||||
|
temp[1U] = inData[39U];
|
||||||
|
temp[2U] = inData[42U];
|
||||||
|
temp[3U] = inData[41U];
|
||||||
|
temp[4U] = inData[44U];
|
||||||
|
temp[5U] = inData[43U];
|
||||||
|
temp[6U] = inData[46U];
|
||||||
|
temp[7U] = inData[45U];
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++, n++) {
|
||||||
|
bool b = READ_BIT(temp, i);
|
||||||
|
WRITE_BIT(outData, n, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
::memcpy(inData, outData, 33U);
|
||||||
|
}
|
69
NXDNReflector/KenwoodNetwork.h
Normal file
69
NXDNReflector/KenwoodNetwork.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016,2018,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
|
||||||
|
* 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 KenwoodNetwork_H
|
||||||
|
#define KenwoodNetwork_H
|
||||||
|
|
||||||
|
#include "CoreNetwork.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "UDPSocket.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CKenwoodNetwork : public ICoreNetwork {
|
||||||
|
public:
|
||||||
|
CKenwoodNetwork(const std::string& address, bool debug);
|
||||||
|
virtual ~CKenwoodNetwork();
|
||||||
|
|
||||||
|
virtual bool open();
|
||||||
|
|
||||||
|
virtual bool write(const unsigned char* data, unsigned int length);
|
||||||
|
|
||||||
|
virtual unsigned int read(unsigned char* data);
|
||||||
|
|
||||||
|
virtual void close();
|
||||||
|
|
||||||
|
virtual void clock(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CUDPSocket m_rtpSocket;
|
||||||
|
CUDPSocket m_rtcpSocket;
|
||||||
|
CStopWatch m_stopWatch;
|
||||||
|
in_addr m_address;
|
||||||
|
unsigned short m_seqNo;
|
||||||
|
unsigned long m_timeStamp;
|
||||||
|
unsigned int m_ssrc;
|
||||||
|
bool m_debug;
|
||||||
|
CTimer m_timer;
|
||||||
|
|
||||||
|
bool processIcomVoiceHeader(const unsigned char* data);
|
||||||
|
bool processIcomVoiceData(const unsigned char* data);
|
||||||
|
bool processKenwoodVoiceHeader(unsigned char* data);
|
||||||
|
void processKenwoodVoiceData(unsigned char* data);
|
||||||
|
bool writeRTPVoiceHeader(const unsigned char* data);
|
||||||
|
bool writeRTPVoiceData(const unsigned char* data);
|
||||||
|
bool writeRTPVoiceTrailer(const unsigned char* data);
|
||||||
|
bool writeRTCPPing();
|
||||||
|
bool writeRTCPData(unsigned char type, unsigned short src, unsigned short dst);
|
||||||
|
unsigned int readRTP(unsigned char* data);
|
||||||
|
unsigned int readRTCP(unsigned char* data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -4,7 +4,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread
|
|||||||
LIBS = -lpthread
|
LIBS = -lpthread
|
||||||
LDFLAGS = -g
|
LDFLAGS = -g
|
||||||
|
|
||||||
OBJECTS = Conf.o Log.o Mutex.o NXCoreNetwork.o NXDNLookup.o NXDNNetwork.o NXDNReflector.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o
|
OBJECTS = Conf.o CoreNetwork.o IcomNetwork.o KenwoodNetwork.o Log.o Mutex.o NXDNCRC.o NXDNLookup.o NXDNNetwork.o NXDNReflector.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o
|
||||||
|
|
||||||
all: NXDNReflector
|
all: NXDNReflector
|
||||||
|
|
||||||
|
185
NXDNReflector/NXDNCRC.cpp
Normal file
185
NXDNReflector/NXDNCRC.cpp
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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 "NXDNCRC.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||||
|
|
||||||
|
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7])
|
||||||
|
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7])
|
||||||
|
|
||||||
|
bool CNXDNCRC::checkCRC6(const unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
|
uint8_t crc = createCRC6(in, length);
|
||||||
|
|
||||||
|
uint8_t temp[1U];
|
||||||
|
temp[0U] = 0x00U;
|
||||||
|
unsigned int j = length;
|
||||||
|
for (unsigned int i = 2U; i < 8U; i++, j++) {
|
||||||
|
bool b = READ_BIT1(in, j);
|
||||||
|
WRITE_BIT1(temp, i, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc == temp[0U];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNXDNCRC::encodeCRC6(unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
|
uint8_t crc[1U];
|
||||||
|
crc[0U] = createCRC6(in, length);
|
||||||
|
|
||||||
|
unsigned int n = length;
|
||||||
|
for (unsigned int i = 2U; i < 8U; i++, n++) {
|
||||||
|
bool b = READ_BIT1(crc, i);
|
||||||
|
WRITE_BIT1(in, n, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNXDNCRC::checkCRC12(const unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
|
uint16_t crc = createCRC12(in, length);
|
||||||
|
uint8_t temp1[2U];
|
||||||
|
temp1[0U] = (crc >> 8) & 0xFFU;
|
||||||
|
temp1[1U] = (crc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
uint8_t temp2[2U];
|
||||||
|
temp2[0U] = 0x00U;
|
||||||
|
temp2[1U] = 0x00U;
|
||||||
|
unsigned int j = length;
|
||||||
|
for (unsigned int i = 4U; i < 16U; i++, j++) {
|
||||||
|
bool b = READ_BIT1(in, j);
|
||||||
|
WRITE_BIT1(temp2, i, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNXDNCRC::encodeCRC12(unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
|
uint16_t crc = createCRC12(in, length);
|
||||||
|
|
||||||
|
uint8_t temp[2U];
|
||||||
|
temp[0U] = (crc >> 8) & 0xFFU;
|
||||||
|
temp[1U] = (crc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
unsigned int n = length;
|
||||||
|
for (unsigned int i = 4U; i < 16U; i++, n++) {
|
||||||
|
bool b = READ_BIT1(temp, i);
|
||||||
|
WRITE_BIT1(in, n, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNXDNCRC::checkCRC15(const unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
|
uint16_t crc = createCRC15(in, length);
|
||||||
|
uint8_t temp1[2U];
|
||||||
|
temp1[0U] = (crc >> 8) & 0xFFU;
|
||||||
|
temp1[1U] = (crc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
uint8_t temp2[2U];
|
||||||
|
temp2[0U] = 0x00U;
|
||||||
|
temp2[1U] = 0x00U;
|
||||||
|
unsigned int j = length;
|
||||||
|
for (unsigned int i = 1U; i < 16U; i++, j++) {
|
||||||
|
bool b = READ_BIT1(in, j);
|
||||||
|
WRITE_BIT1(temp2, i, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNXDNCRC::encodeCRC15(unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
|
uint16_t crc = createCRC15(in, length);
|
||||||
|
|
||||||
|
uint8_t temp[2U];
|
||||||
|
temp[0U] = (crc >> 8) & 0xFFU;
|
||||||
|
temp[1U] = (crc >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
unsigned int n = length;
|
||||||
|
for (unsigned int i = 1U; i < 16U; i++, n++) {
|
||||||
|
bool b = READ_BIT1(temp, i);
|
||||||
|
WRITE_BIT1(in, n, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CNXDNCRC::createCRC6(const unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
uint8_t crc = 0x3FU;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < length; i++) {
|
||||||
|
bool bit1 = READ_BIT1(in, i) != 0x00U;
|
||||||
|
bool bit2 = (crc & 0x20U) == 0x20U;
|
||||||
|
|
||||||
|
crc <<= 1;
|
||||||
|
|
||||||
|
if (bit1 ^ bit2)
|
||||||
|
crc ^= 0x27U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc & 0x3FU;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CNXDNCRC::createCRC12(const unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
uint16_t crc = 0x0FFFU;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < length; i++) {
|
||||||
|
bool bit1 = READ_BIT1(in, i) != 0x00U;
|
||||||
|
bool bit2 = (crc & 0x0800U) == 0x0800U;
|
||||||
|
|
||||||
|
crc <<= 1;
|
||||||
|
|
||||||
|
if (bit1 ^ bit2)
|
||||||
|
crc ^= 0x080FU;
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc & 0x0FFFU;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CNXDNCRC::createCRC15(const unsigned char* in, unsigned int length)
|
||||||
|
{
|
||||||
|
uint16_t crc = 0x7FFFU;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < length; i++) {
|
||||||
|
bool bit1 = READ_BIT1(in, i) != 0x00U;
|
||||||
|
bool bit2 = (crc & 0x4000U) == 0x4000U;
|
||||||
|
|
||||||
|
crc <<= 1;
|
||||||
|
|
||||||
|
if (bit1 ^ bit2)
|
||||||
|
crc ^= 0x4CC5U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc & 0x7FFFU;
|
||||||
|
}
|
42
NXDNReflector/NXDNCRC.h
Normal file
42
NXDNReflector/NXDNCRC.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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(NXDNCRC_H)
|
||||||
|
#define NXDNCRC_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class CNXDNCRC
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool checkCRC6(const unsigned char* in, unsigned int length);
|
||||||
|
static void encodeCRC6(unsigned char* in, unsigned int length);
|
||||||
|
|
||||||
|
static bool checkCRC12(const unsigned char* in, unsigned int length);
|
||||||
|
static void encodeCRC12(unsigned char* in, unsigned int length);
|
||||||
|
|
||||||
|
static bool checkCRC15(const unsigned char* in, unsigned int length);
|
||||||
|
static void encodeCRC15(unsigned char* in, unsigned int length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uint8_t createCRC6(const unsigned char* in, unsigned int length);
|
||||||
|
static uint16_t createCRC12(const unsigned char* in, unsigned int length);
|
||||||
|
static uint16_t createCRC15(const unsigned char* in, unsigned int length);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -16,8 +16,10 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "KenwoodNetwork.h"
|
||||||
#include "NXDNReflector.h"
|
#include "NXDNReflector.h"
|
||||||
#include "NXDNNetwork.h"
|
#include "NXDNNetwork.h"
|
||||||
|
#include "IcomNetwork.h"
|
||||||
#include "NXDNLookup.h"
|
#include "NXDNLookup.h"
|
||||||
#include "StopWatch.h"
|
#include "StopWatch.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
@ -410,6 +412,9 @@ void CNXDNReflector::run()
|
|||||||
dumpTimer.start();
|
dumpTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_nxCoreNetwork != NULL)
|
||||||
|
m_nxCoreNetwork->clock(ms);
|
||||||
|
|
||||||
if (ms < 5U)
|
if (ms < 5U)
|
||||||
CThread::sleep(5U);
|
CThread::sleep(5U);
|
||||||
}
|
}
|
||||||
@ -454,7 +459,11 @@ void CNXDNReflector::dumpRepeaters() const
|
|||||||
|
|
||||||
bool CNXDNReflector::openNXCore()
|
bool CNXDNReflector::openNXCore()
|
||||||
{
|
{
|
||||||
m_nxCoreNetwork = new CNXCoreNetwork(m_conf.getNXCoreAddress(), m_conf.getNXCoreDebug());
|
std::string protocol = m_conf.getNXCoreProtocol();
|
||||||
|
if (protocol == "Kenwood")
|
||||||
|
m_nxCoreNetwork = new CKenwoodNetwork(m_conf.getNXCoreAddress(), m_conf.getNXCoreDebug());
|
||||||
|
else
|
||||||
|
m_nxCoreNetwork = new CIcomNetwork(m_conf.getNXCoreAddress(), m_conf.getNXCoreDebug());
|
||||||
bool ret = m_nxCoreNetwork->open();
|
bool ret = m_nxCoreNetwork->open();
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
delete m_nxCoreNetwork;
|
delete m_nxCoreNetwork;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -19,7 +19,7 @@
|
|||||||
#if !defined(NXDNReflector_H)
|
#if !defined(NXDNReflector_H)
|
||||||
#define NXDNReflector_H
|
#define NXDNReflector_H
|
||||||
|
|
||||||
#include "NXCoreNetwork.h"
|
#include "CoreNetwork.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "Conf.h"
|
#include "Conf.h"
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
CConf m_conf;
|
CConf m_conf;
|
||||||
CNXCoreNetwork* m_nxCoreNetwork;
|
ICoreNetwork* m_nxCoreNetwork;
|
||||||
std::vector<CNXDNRepeater*> m_repeaters;
|
std::vector<CNXDNRepeater*> m_repeaters;
|
||||||
|
|
||||||
CNXDNRepeater* findRepeater(const in_addr& address, unsigned int port) const;
|
CNXDNRepeater* findRepeater(const in_addr& address, unsigned int port) const;
|
||||||
|
@ -19,6 +19,7 @@ Debug=0
|
|||||||
|
|
||||||
[NXCore]
|
[NXCore]
|
||||||
Enabled=0
|
Enabled=0
|
||||||
|
Protocol=Icom
|
||||||
# Address=208.111.3.45
|
# Address=208.111.3.45
|
||||||
Address=44.131.4.1
|
Address=44.131.4.1
|
||||||
# TGEnable=1234
|
# TGEnable=1234
|
||||||
|
@ -20,7 +20,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Conf.h" />
|
<ClInclude Include="Conf.h" />
|
||||||
<ClInclude Include="NXCoreNetwork.h" />
|
<ClInclude Include="CoreNetwork.h" />
|
||||||
|
<ClInclude Include="IcomNetwork.h" />
|
||||||
|
<ClInclude Include="KenwoodNetwork.h" />
|
||||||
|
<ClInclude Include="NXDNCRC.h" />
|
||||||
<ClInclude Include="NXDNLookup.h" />
|
<ClInclude Include="NXDNLookup.h" />
|
||||||
<ClInclude Include="Log.h" />
|
<ClInclude Include="Log.h" />
|
||||||
<ClInclude Include="Mutex.h" />
|
<ClInclude Include="Mutex.h" />
|
||||||
@ -35,7 +38,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Conf.cpp" />
|
<ClCompile Include="Conf.cpp" />
|
||||||
<ClCompile Include="NXCoreNetwork.cpp" />
|
<ClCompile Include="CoreNetwork.cpp" />
|
||||||
|
<ClCompile Include="IcomNetwork.cpp" />
|
||||||
|
<ClCompile Include="KenwoodNetwork.cpp" />
|
||||||
|
<ClCompile Include="NXDNCRC.cpp" />
|
||||||
<ClCompile Include="NXDNLookup.cpp" />
|
<ClCompile Include="NXDNLookup.cpp" />
|
||||||
<ClCompile Include="Log.cpp" />
|
<ClCompile Include="Log.cpp" />
|
||||||
<ClCompile Include="Mutex.cpp" />
|
<ClCompile Include="Mutex.cpp" />
|
||||||
|
@ -47,7 +47,16 @@
|
|||||||
<ClInclude Include="NXDNNetwork.h">
|
<ClInclude Include="NXDNNetwork.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="NXCoreNetwork.h">
|
<ClInclude Include="IcomNetwork.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="KenwoodNetwork.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CoreNetwork.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="NXDNCRC.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -85,7 +94,16 @@
|
|||||||
<ClCompile Include="NXDNNetwork.cpp">
|
<ClCompile Include="NXDNNetwork.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="NXCoreNetwork.cpp">
|
<ClCompile Include="IcomNetwork.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="KenwoodNetwork.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CoreNetwork.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="NXDNCRC.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -19,6 +19,6 @@
|
|||||||
#if !defined(VERSION_H)
|
#if !defined(VERSION_H)
|
||||||
#define VERSION_H
|
#define VERSION_H
|
||||||
|
|
||||||
const char* VERSION = "20180517";
|
const char* VERSION = "20200420";
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user