mirror of
https://github.com/g4klx/MMDVMHost
synced 2025-12-23 00:35:53 +08:00
Remove the direct network access to DMR Masters.
This commit is contained in:
46
Conf.cpp
46
Conf.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2022 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2015-2022,2023 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
|
||||
@@ -246,13 +246,10 @@ m_dstarLocalPort(0U),
|
||||
m_dstarNetworkModeHang(3U),
|
||||
m_dstarNetworkDebug(false),
|
||||
m_dmrNetworkEnabled(false),
|
||||
m_dmrNetworkType("Gateway"),
|
||||
m_dmrNetworkRemoteAddress(),
|
||||
m_dmrNetworkRemotePort(0U),
|
||||
m_dmrNetworkGatewayAddress(),
|
||||
m_dmrNetworkGatewayPort(0U),
|
||||
m_dmrNetworkLocalAddress(),
|
||||
m_dmrNetworkLocalPort(0U),
|
||||
m_dmrNetworkPassword(),
|
||||
m_dmrNetworkOptions(),
|
||||
m_dmrNetworkDebug(false),
|
||||
m_dmrNetworkJitter(360U),
|
||||
m_dmrNetworkSlot1(true),
|
||||
@@ -948,20 +945,14 @@ bool CConf::read()
|
||||
} else if (section == SECTION_DMR_NETWORK) {
|
||||
if (::strcmp(key, "Enable") == 0)
|
||||
m_dmrNetworkEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Type") == 0)
|
||||
m_dmrNetworkType = value;
|
||||
else if (::strcmp(key, "RemoteAddress") == 0)
|
||||
m_dmrNetworkRemoteAddress = value;
|
||||
else if (::strcmp(key, "RemotePort") == 0)
|
||||
m_dmrNetworkRemotePort = (unsigned short)::atoi(value);
|
||||
else if (::strcmp(key, "GatewayAddress") == 0)
|
||||
m_dmrNetworkGatewayAddress = value;
|
||||
else if (::strcmp(key, "GatewayPort") == 0)
|
||||
m_dmrNetworkGatewayPort = (unsigned short)::atoi(value);
|
||||
else if (::strcmp(key, "LocalAddress") == 0)
|
||||
m_dmrNetworkLocalAddress = value;
|
||||
else if (::strcmp(key, "LocalPort") == 0)
|
||||
m_dmrNetworkLocalPort = (unsigned short)::atoi(value);
|
||||
else if (::strcmp(key, "Password") == 0)
|
||||
m_dmrNetworkPassword = value;
|
||||
else if (::strcmp(key, "Options") == 0)
|
||||
m_dmrNetworkOptions = value;
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_dmrNetworkDebug = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Jitter") == 0)
|
||||
@@ -2067,19 +2058,14 @@ bool CConf::getDMRNetworkEnabled() const
|
||||
return m_dmrNetworkEnabled;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkType() const
|
||||
std::string CConf::getDMRNetworkGatewayAddress() const
|
||||
{
|
||||
return m_dmrNetworkType;
|
||||
return m_dmrNetworkGatewayAddress;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkRemoteAddress() const
|
||||
unsigned short CConf::getDMRNetworkGatewayPort() const
|
||||
{
|
||||
return m_dmrNetworkRemoteAddress;
|
||||
}
|
||||
|
||||
unsigned short CConf::getDMRNetworkRemotePort() const
|
||||
{
|
||||
return m_dmrNetworkRemotePort;
|
||||
return m_dmrNetworkGatewayPort;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkLocalAddress() const
|
||||
@@ -2092,16 +2078,6 @@ unsigned short CConf::getDMRNetworkLocalPort() const
|
||||
return m_dmrNetworkLocalPort;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkPassword() const
|
||||
{
|
||||
return m_dmrNetworkPassword;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkOptions() const
|
||||
{
|
||||
return m_dmrNetworkOptions;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRNetworkModeHang() const
|
||||
{
|
||||
return m_dmrNetworkModeHang;
|
||||
|
||||
16
Conf.h
16
Conf.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2022 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2015-2023 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
|
||||
@@ -248,13 +248,10 @@ public:
|
||||
|
||||
// The DMR Network section
|
||||
bool getDMRNetworkEnabled() const;
|
||||
std::string getDMRNetworkType() const;
|
||||
std::string getDMRNetworkRemoteAddress() const;
|
||||
unsigned short getDMRNetworkRemotePort() const;
|
||||
std::string getDMRNetworkGatewayAddress() const;
|
||||
unsigned short getDMRNetworkGatewayPort() const;
|
||||
std::string getDMRNetworkLocalAddress() const;
|
||||
unsigned short getDMRNetworkLocalPort() const;
|
||||
std::string getDMRNetworkPassword() const;
|
||||
std::string getDMRNetworkOptions() const;
|
||||
bool getDMRNetworkDebug() const;
|
||||
unsigned int getDMRNetworkJitter() const;
|
||||
bool getDMRNetworkSlot1() const;
|
||||
@@ -577,13 +574,10 @@ private:
|
||||
bool m_dstarNetworkDebug;
|
||||
|
||||
bool m_dmrNetworkEnabled;
|
||||
std::string m_dmrNetworkType;
|
||||
std::string m_dmrNetworkRemoteAddress;
|
||||
unsigned short m_dmrNetworkRemotePort;
|
||||
std::string m_dmrNetworkGatewayAddress;
|
||||
unsigned short m_dmrNetworkGatewayPort;
|
||||
std::string m_dmrNetworkLocalAddress;
|
||||
unsigned short m_dmrNetworkLocalPort;
|
||||
std::string m_dmrNetworkPassword;
|
||||
std::string m_dmrNetworkOptions;
|
||||
bool m_dmrNetworkDebug;
|
||||
unsigned int m_dmrNetworkJitter;
|
||||
bool m_dmrNetworkSlot1;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 Jonathan Naylor, G4KLX
|
||||
* Copyright (C) 2015-2021,2023 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
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) :
|
||||
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) :
|
||||
m_colorCode(colorCode),
|
||||
m_modem(modem),
|
||||
m_network(network),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2015-2021,2023 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
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
class CDMRControl {
|
||||
public:
|
||||
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm);
|
||||
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm);
|
||||
~CDMRControl();
|
||||
|
||||
bool processWakeup(const unsigned char* data);
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
private:
|
||||
unsigned int m_colorCode;
|
||||
CModem* m_modem;
|
||||
IDMRNetwork* m_network;
|
||||
CDMRNetwork* m_network;
|
||||
CDMRSlot m_slot1;
|
||||
CDMRSlot m_slot2;
|
||||
CDMRLookup* m_lookup;
|
||||
|
||||
@@ -1,644 +0,0 @@
|
||||
/*
|
||||
* 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 "DMRDirectNetwork.h"
|
||||
|
||||
#include "SHA256.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 500U;
|
||||
|
||||
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
|
||||
|
||||
|
||||
CDMRDirectNetwork::CDMRDirectNetwork(const std::string& address, unsigned short port, const std::string& localAddress, unsigned short localPort, unsigned int id, const std::string& password, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) :
|
||||
m_address(address),
|
||||
m_port(port),
|
||||
m_addr(),
|
||||
m_addrLen(0U),
|
||||
m_id(NULL),
|
||||
m_password(password),
|
||||
m_duplex(duplex),
|
||||
m_version(version),
|
||||
m_debug(debug),
|
||||
m_socket(localAddress, localPort),
|
||||
m_enabled(false),
|
||||
m_slot1(slot1),
|
||||
m_slot2(slot2),
|
||||
m_hwType(hwType),
|
||||
m_status(WAITING_CONNECT),
|
||||
m_retryTimer(1000U, 10U),
|
||||
m_timeoutTimer(1000U, 60U),
|
||||
m_buffer(NULL),
|
||||
m_streamId(NULL),
|
||||
m_salt(NULL),
|
||||
m_rxData(1000U, "DMR Network"),
|
||||
m_options(),
|
||||
m_random(),
|
||||
m_callsign(),
|
||||
m_rxFrequency(0U),
|
||||
m_txFrequency(0U),
|
||||
m_power(0U),
|
||||
m_colorCode(0U),
|
||||
m_latitude(0.0F),
|
||||
m_longitude(0.0F),
|
||||
m_height(0),
|
||||
m_location(),
|
||||
m_description(),
|
||||
m_url(),
|
||||
m_beacon(false)
|
||||
{
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
assert(id > 1000U);
|
||||
assert(!password.empty());
|
||||
|
||||
m_buffer = new unsigned char[BUFFER_LENGTH];
|
||||
m_salt = new unsigned char[sizeof(uint32_t)];
|
||||
m_id = new uint8_t[4U];
|
||||
m_streamId = new uint32_t[2U];
|
||||
|
||||
m_id[0U] = id >> 24;
|
||||
m_id[1U] = id >> 16;
|
||||
m_id[2U] = id >> 8;
|
||||
m_id[3U] = id >> 0;
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
m_random = mt;
|
||||
|
||||
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
|
||||
m_streamId[0U] = dist(m_random);
|
||||
m_streamId[1U] = dist(m_random);
|
||||
}
|
||||
|
||||
CDMRDirectNetwork::~CDMRDirectNetwork()
|
||||
{
|
||||
delete[] m_streamId;
|
||||
delete[] m_buffer;
|
||||
delete[] m_salt;
|
||||
delete[] m_id;
|
||||
}
|
||||
|
||||
void CDMRDirectNetwork::setOptions(const std::string& options)
|
||||
{
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
void CDMRDirectNetwork::setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url)
|
||||
{
|
||||
m_callsign = callsign;
|
||||
m_rxFrequency = rxFrequency;
|
||||
m_txFrequency = txFrequency;
|
||||
m_power = power;
|
||||
m_colorCode = colorCode;
|
||||
m_latitude = latitude;
|
||||
m_longitude = longitude;
|
||||
m_height = height;
|
||||
m_location = location;
|
||||
m_description = description;
|
||||
m_url = url;
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::open()
|
||||
{
|
||||
if (CUDPSocket::lookup(m_address, m_port, m_addr, m_addrLen) != 0) {
|
||||
LogError("DMR, Could not lookup the address of the DMR Network");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMessage("Opening DMR Network");
|
||||
|
||||
m_status = WAITING_CONNECT;
|
||||
m_timeoutTimer.stop();
|
||||
m_retryTimer.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDMRDirectNetwork::enable(bool enabled)
|
||||
{
|
||||
if (!enabled && m_enabled)
|
||||
m_rxData.clear();
|
||||
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::read(CDMRData& data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
// DMO mode slot disabling
|
||||
if (slotNo == 1U && !m_duplex)
|
||||
return false;
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return false;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return false;
|
||||
|
||||
FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP;
|
||||
|
||||
data.setSeqNo(seqNo);
|
||||
data.setSlotNo(slotNo);
|
||||
data.setSrcId(srcId);
|
||||
data.setDstId(dstId);
|
||||
data.setFLCO(flco);
|
||||
|
||||
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 CDMRDirectNetwork::write(const CDMRData& data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
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_id, 4U);
|
||||
|
||||
unsigned int slotNo = data.getSlotNo();
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return false;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return false;
|
||||
|
||||
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
|
||||
|
||||
FLCO flco = data.getFLCO();
|
||||
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
|
||||
|
||||
unsigned int slotIndex = slotNo - 1U;
|
||||
|
||||
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
|
||||
unsigned char dataType = data.getDataType();
|
||||
if (dataType == DT_VOICE_SYNC) {
|
||||
buffer[15U] |= 0x10U;
|
||||
} else if (dataType == DT_VOICE) {
|
||||
buffer[15U] |= data.getN();
|
||||
} else {
|
||||
if (dataType == DT_VOICE_LC_HEADER)
|
||||
m_streamId[slotIndex] = dist(m_random);
|
||||
|
||||
if (dataType == DT_CSBK || dataType == DT_DATA_HEADER)
|
||||
m_streamId[slotIndex] = dist(m_random);
|
||||
|
||||
buffer[15U] |= (0x20U | dataType);
|
||||
}
|
||||
|
||||
buffer[4U] = data.getSeqNo();
|
||||
|
||||
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
|
||||
|
||||
data.getData(buffer + 20U);
|
||||
|
||||
buffer[53U] = data.getBER();
|
||||
|
||||
buffer[54U] = data.getRSSI();
|
||||
|
||||
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::writeRadioPosition(unsigned int id, const unsigned char* data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRG", 4U);
|
||||
|
||||
buffer[4U] = id >> 16;
|
||||
buffer[5U] = id >> 8;
|
||||
buffer[6U] = id >> 0;
|
||||
|
||||
::memcpy(buffer + 7U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 14U);
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRA", 4U);
|
||||
|
||||
buffer[4U] = id >> 16;
|
||||
buffer[5U] = id >> 8;
|
||||
buffer[6U] = id >> 0;
|
||||
|
||||
buffer[7U] = type;
|
||||
|
||||
::memcpy(buffer + 8U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 15U);
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::isConnected() const
|
||||
{
|
||||
return (m_status == RUNNING);
|
||||
}
|
||||
|
||||
void CDMRDirectNetwork::close(bool sayGoodbye)
|
||||
{
|
||||
LogMessage("Closing DMR Network");
|
||||
|
||||
if (sayGoodbye && (m_status == RUNNING)) {
|
||||
unsigned char buffer[9U];
|
||||
::memcpy(buffer + 0U, "RPTCL", 5U);
|
||||
::memcpy(buffer + 5U, m_id, 4U);
|
||||
write(buffer, 9U);
|
||||
}
|
||||
|
||||
m_socket.close();
|
||||
|
||||
m_retryTimer.stop();
|
||||
m_timeoutTimer.stop();
|
||||
}
|
||||
|
||||
void CDMRDirectNetwork::clock(unsigned int ms)
|
||||
{
|
||||
m_retryTimer.clock(ms);
|
||||
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
|
||||
switch (m_status) {
|
||||
case WAITING_CONNECT:
|
||||
if (m_socket.open(m_addr.ss_family)) {
|
||||
if (writeLogin()) {
|
||||
m_status = WAITING_LOGIN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WAITING_LOGIN:
|
||||
writeLogin();
|
||||
break;
|
||||
case WAITING_AUTHORISATION:
|
||||
writeAuthorisation();
|
||||
break;
|
||||
case WAITING_OPTIONS:
|
||||
writeOptions();
|
||||
break;
|
||||
case WAITING_CONFIG:
|
||||
writeConfig();
|
||||
break;
|
||||
case RUNNING:
|
||||
writePing();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_retryTimer.start();
|
||||
}
|
||||
|
||||
sockaddr_storage address;
|
||||
unsigned int addrlen;
|
||||
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen);
|
||||
if (length < 0) {
|
||||
LogError("DMR, Socket has failed, retrying connection to the master");
|
||||
close(false);
|
||||
open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
if (!CUDPSocket::match(m_addr, address)) {
|
||||
LogMessage("DMR, packet received from an invalid source");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "DMR, Network Received", m_buffer, length);
|
||||
|
||||
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
|
||||
if (m_enabled) {
|
||||
unsigned char len = length;
|
||||
m_rxData.addData(&len, 1U);
|
||||
m_rxData.addData(m_buffer, len);
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) {
|
||||
if (m_status == RUNNING) {
|
||||
LogWarning("DMR, Login to the master has failed, retrying login ...");
|
||||
m_status = WAITING_LOGIN;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
} else {
|
||||
/* Once the modem death spiral has been prevented in Modem.cpp
|
||||
the Network sometimes times out and reaches here.
|
||||
We want it to reconnect so... */
|
||||
LogError("DMR, Login to the master has failed, retrying network ...");
|
||||
close(false);
|
||||
open();
|
||||
return;
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "RPTACK", 6U) == 0) {
|
||||
switch (m_status) {
|
||||
case WAITING_LOGIN:
|
||||
LogDebug("DMR, Sending authorisation");
|
||||
::memcpy(m_salt, m_buffer + 6U, sizeof(uint32_t));
|
||||
writeAuthorisation();
|
||||
m_status = WAITING_AUTHORISATION;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_AUTHORISATION:
|
||||
LogDebug("DMR, Sending configuration");
|
||||
writeConfig();
|
||||
m_status = WAITING_CONFIG;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_CONFIG:
|
||||
if (m_options.empty()) {
|
||||
LogMessage("DMR, Logged into the master successfully");
|
||||
m_status = RUNNING;
|
||||
} else {
|
||||
LogDebug("DMR, Sending options");
|
||||
writeOptions();
|
||||
m_status = WAITING_OPTIONS;
|
||||
}
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_OPTIONS:
|
||||
LogMessage("DMR, Logged into the master successfully");
|
||||
m_status = RUNNING;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) {
|
||||
LogError("DMR, Master is closing down");
|
||||
close(false);
|
||||
open();
|
||||
} else if (::memcmp(m_buffer, "MSTPONG", 7U) == 0) {
|
||||
m_timeoutTimer.start();
|
||||
} else if (::memcmp(m_buffer, "RPTSBKN", 7U) == 0) {
|
||||
m_beacon = true;
|
||||
} else {
|
||||
CUtils::dump("DMR, Unknown packet from the master", m_buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
m_timeoutTimer.clock(ms);
|
||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||
LogError("DMR, Connection to the master has timed out, retrying connection");
|
||||
close(false);
|
||||
open();
|
||||
}
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::writeLogin()
|
||||
{
|
||||
unsigned char buffer[8U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTL", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
return write(buffer, 8U);
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::writeAuthorisation()
|
||||
{
|
||||
size_t size = m_password.size();
|
||||
|
||||
unsigned char* in = new unsigned char[size + sizeof(uint32_t)];
|
||||
::memcpy(in, m_salt, sizeof(uint32_t));
|
||||
for (size_t i = 0U; i < size; i++)
|
||||
in[i + sizeof(uint32_t)] = m_password.at(i);
|
||||
|
||||
unsigned char out[40U];
|
||||
::memcpy(out + 0U, "RPTK", 4U);
|
||||
::memcpy(out + 4U, m_id, 4U);
|
||||
|
||||
CSHA256 sha256;
|
||||
sha256.buffer(in, (unsigned int)(size + sizeof(uint32_t)), out + 8U);
|
||||
|
||||
delete[] in;
|
||||
|
||||
return write(out, 40U);
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::writeOptions()
|
||||
{
|
||||
char buffer[300U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTO", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
::strcpy(buffer + 8U, m_options.c_str());
|
||||
|
||||
return write((unsigned char*)buffer, (unsigned int)m_options.length() + 8U);
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::writeConfig()
|
||||
{
|
||||
const char* software;
|
||||
char slots = '0';
|
||||
if (m_duplex) {
|
||||
if (m_slot1 && m_slot2)
|
||||
slots = '3';
|
||||
else if (m_slot1 && !m_slot2)
|
||||
slots = '1';
|
||||
else if (!m_slot1 && m_slot2)
|
||||
slots = '2';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
case HWT_MMDVM_HS_DUAL_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||
break;
|
||||
case HWT_NANO_HOTSPOT:
|
||||
software = "MMDVM_Nano_hotSPOT";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
slots = '4';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM_DMO";
|
||||
break;
|
||||
case HWT_DVMEGA:
|
||||
software = "MMDVM_DVMega";
|
||||
break;
|
||||
case HWT_MMDVM_ZUMSPOT:
|
||||
software = "MMDVM_ZUMspot";
|
||||
break;
|
||||
case HWT_MMDVM_HS_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Hat";
|
||||
break;
|
||||
case HWT_MMDVM_HS_DUAL_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||
break;
|
||||
case HWT_NANO_HOTSPOT:
|
||||
software = "MMDVM_Nano_hotSPOT";
|
||||
break;
|
||||
case HWT_NANO_DV:
|
||||
software = "MMDVM_Nano_DV";
|
||||
break;
|
||||
case HWT_D2RG_MMDVM_HS:
|
||||
software = "MMDVM_D2RG_MMDVM_HS";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char buffer[400U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTC", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
char latitude[20U];
|
||||
::sprintf(latitude, "%08f", m_latitude);
|
||||
|
||||
char longitude[20U];
|
||||
::sprintf(longitude, "%09f", m_longitude);
|
||||
|
||||
unsigned int power = m_power;
|
||||
if (power > 99U)
|
||||
power = 99U;
|
||||
|
||||
int height = m_height;
|
||||
if (height > 999)
|
||||
height = 999;
|
||||
|
||||
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%8.8s%9.9s%03d%-20.20s%-19.19s%c%-124.124s%-40.40s%-40.40s", m_callsign.c_str(),
|
||||
m_rxFrequency, m_txFrequency, power, m_colorCode, latitude, longitude, height, m_location.c_str(),
|
||||
m_description.c_str(), slots, m_url.c_str(), m_version, software);
|
||||
|
||||
return write((unsigned char*)buffer, 302U);
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::writePing()
|
||||
{
|
||||
unsigned char buffer[11U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTPING", 7U);
|
||||
::memcpy(buffer + 7U, m_id, 4U);
|
||||
|
||||
return write(buffer, 11U);
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::wantsBeacon()
|
||||
{
|
||||
bool beacon = m_beacon;
|
||||
|
||||
m_beacon = false;
|
||||
|
||||
return beacon;
|
||||
}
|
||||
|
||||
bool CDMRDirectNetwork::write(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "DMR Network Transmitted", data, length);
|
||||
|
||||
bool ret = m_socket.write(data, length, m_addr, m_addrLen);
|
||||
if (!ret) {
|
||||
LogError("DMR, Socket has failed when writing data to the master, retrying connection");
|
||||
close(false);
|
||||
open();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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(DMRDirectNetwork_H)
|
||||
#define DMRDirectNetwork_H
|
||||
|
||||
#include "DMRNetwork.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "DMRData.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
class CDMRDirectNetwork : public IDMRNetwork
|
||||
{
|
||||
public:
|
||||
CDMRDirectNetwork(const std::string& remoteAddress, unsigned short remotePort, const std::string& localAddress, unsigned short localPort, unsigned int id, const std::string& password, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug);
|
||||
virtual ~CDMRDirectNetwork();
|
||||
|
||||
virtual void setOptions(const std::string& options);
|
||||
|
||||
virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url);
|
||||
|
||||
virtual bool open();
|
||||
|
||||
virtual void enable(bool enabled);
|
||||
|
||||
virtual bool read(CDMRData& data);
|
||||
|
||||
virtual bool write(const CDMRData& data);
|
||||
|
||||
virtual bool writeRadioPosition(unsigned int id, const unsigned char* data);
|
||||
|
||||
virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
|
||||
|
||||
virtual bool wantsBeacon();
|
||||
|
||||
virtual void clock(unsigned int ms);
|
||||
|
||||
virtual bool isConnected() const;
|
||||
|
||||
virtual void close(bool sayGoodbye);
|
||||
|
||||
private:
|
||||
std::string m_address;
|
||||
unsigned short m_port;
|
||||
sockaddr_storage m_addr;
|
||||
unsigned int m_addrLen;
|
||||
uint8_t* m_id;
|
||||
std::string m_password;
|
||||
bool m_duplex;
|
||||
const char* m_version;
|
||||
bool m_debug;
|
||||
CUDPSocket m_socket;
|
||||
bool m_enabled;
|
||||
bool m_slot1;
|
||||
bool m_slot2;
|
||||
HW_TYPE m_hwType;
|
||||
|
||||
enum STATUS {
|
||||
WAITING_CONNECT,
|
||||
WAITING_LOGIN,
|
||||
WAITING_AUTHORISATION,
|
||||
WAITING_CONFIG,
|
||||
WAITING_OPTIONS,
|
||||
RUNNING
|
||||
};
|
||||
|
||||
STATUS m_status;
|
||||
CTimer m_retryTimer;
|
||||
CTimer m_timeoutTimer;
|
||||
unsigned char* m_buffer;
|
||||
uint32_t* m_streamId;
|
||||
unsigned char* m_salt;
|
||||
|
||||
CRingBuffer<unsigned char> m_rxData;
|
||||
|
||||
std::string m_options;
|
||||
|
||||
std::mt19937 m_random;
|
||||
std::string m_callsign;
|
||||
unsigned int m_rxFrequency;
|
||||
unsigned int m_txFrequency;
|
||||
unsigned int m_power;
|
||||
unsigned int m_colorCode;
|
||||
float m_latitude;
|
||||
float m_longitude;
|
||||
int m_height;
|
||||
std::string m_location;
|
||||
std::string m_description;
|
||||
std::string m_url;
|
||||
bool m_beacon;
|
||||
|
||||
bool writeLogin();
|
||||
bool writeAuthorisation();
|
||||
bool writeOptions();
|
||||
bool writeConfig();
|
||||
bool writePing();
|
||||
|
||||
bool write(const unsigned char* data, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,450 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015-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 "DMRGatewayNetwork.h"
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 500U;
|
||||
|
||||
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
|
||||
|
||||
|
||||
CDMRGatewayNetwork::CDMRGatewayNetwork(const std::string& address, unsigned short port, const std::string& localAddress, unsigned short localPort, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) :
|
||||
m_addressStr(address),
|
||||
m_addr(),
|
||||
m_addrLen(0U),
|
||||
m_port(port),
|
||||
m_id(NULL),
|
||||
m_duplex(duplex),
|
||||
m_version(version),
|
||||
m_debug(debug),
|
||||
m_socket(localAddress, localPort),
|
||||
m_enabled(false),
|
||||
m_slot1(slot1),
|
||||
m_slot2(slot2),
|
||||
m_hwType(hwType),
|
||||
m_buffer(NULL),
|
||||
m_streamId(NULL),
|
||||
m_rxData(1000U, "DMR Network"),
|
||||
m_beacon(false),
|
||||
m_random(),
|
||||
m_callsign(),
|
||||
m_rxFrequency(0U),
|
||||
m_txFrequency(0U),
|
||||
m_power(0U),
|
||||
m_colorCode(0U),
|
||||
m_pingTimer(1000U, 10U)
|
||||
{
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
assert(id > 1000U);
|
||||
|
||||
if (CUDPSocket::lookup(m_addressStr, m_port, m_addr, m_addrLen) != 0)
|
||||
m_addrLen = 0U;
|
||||
|
||||
m_buffer = new unsigned char[BUFFER_LENGTH];
|
||||
m_id = new uint8_t[4U];
|
||||
m_streamId = new uint32_t[2U];
|
||||
|
||||
m_id[0U] = id >> 24;
|
||||
m_id[1U] = id >> 16;
|
||||
m_id[2U] = id >> 8;
|
||||
m_id[3U] = id >> 0;
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
m_random = mt;
|
||||
|
||||
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
|
||||
m_streamId[0U] = dist(m_random);
|
||||
m_streamId[1U] = dist(m_random);
|
||||
}
|
||||
|
||||
CDMRGatewayNetwork::~CDMRGatewayNetwork()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
delete[] m_streamId;
|
||||
delete[] m_id;
|
||||
}
|
||||
|
||||
void CDMRGatewayNetwork::setConfig(const std::string & callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url)
|
||||
{
|
||||
m_callsign = callsign;
|
||||
m_rxFrequency = rxFrequency;
|
||||
m_txFrequency = txFrequency;
|
||||
m_power = power;
|
||||
m_colorCode = colorCode;
|
||||
}
|
||||
|
||||
void CDMRGatewayNetwork::setOptions(const std::string& options)
|
||||
{
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::open()
|
||||
{
|
||||
if (m_addrLen == 0U) {
|
||||
LogError("Unable to resolve the address of the DMR Network");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMessage("DMR, Opening DMR Network");
|
||||
|
||||
bool ret = m_socket.open(m_addr);
|
||||
if (ret)
|
||||
m_pingTimer.start();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CDMRGatewayNetwork::enable(bool enabled)
|
||||
{
|
||||
if (!enabled && m_enabled)
|
||||
m_rxData.clear();
|
||||
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::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;
|
||||
|
||||
// DMO mode slot disabling
|
||||
if (slotNo == 1U && !m_duplex)
|
||||
return false;
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return false;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return false;
|
||||
|
||||
FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP;
|
||||
|
||||
data.setSeqNo(seqNo);
|
||||
data.setSlotNo(slotNo);
|
||||
data.setSrcId(srcId);
|
||||
data.setDstId(dstId);
|
||||
data.setFLCO(flco);
|
||||
|
||||
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 CDMRGatewayNetwork::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_id, 4U);
|
||||
|
||||
unsigned int slotNo = data.getSlotNo();
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return false;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return false;
|
||||
|
||||
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
|
||||
|
||||
FLCO flco = data.getFLCO();
|
||||
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
|
||||
|
||||
unsigned int slotIndex = slotNo - 1U;
|
||||
|
||||
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
|
||||
unsigned char dataType = data.getDataType();
|
||||
if (dataType == DT_VOICE_SYNC) {
|
||||
buffer[15U] |= 0x10U;
|
||||
} else if (dataType == DT_VOICE) {
|
||||
buffer[15U] |= data.getN();
|
||||
} else {
|
||||
if (dataType == DT_VOICE_LC_HEADER)
|
||||
m_streamId[slotIndex] = dist(m_random);
|
||||
|
||||
if (dataType == DT_CSBK || dataType == DT_DATA_HEADER)
|
||||
m_streamId[slotIndex] = dist(m_random);
|
||||
|
||||
buffer[15U] |= (0x20U | dataType);
|
||||
}
|
||||
|
||||
buffer[4U] = data.getSeqNo();
|
||||
|
||||
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
|
||||
|
||||
data.getData(buffer + 20U);
|
||||
|
||||
buffer[53U] = data.getBER();
|
||||
|
||||
buffer[54U] = data.getRSSI();
|
||||
|
||||
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::writeRadioPosition(unsigned int id, const unsigned char* data)
|
||||
{
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRG", 4U);
|
||||
|
||||
buffer[4U] = id >> 16;
|
||||
buffer[5U] = id >> 8;
|
||||
buffer[6U] = id >> 0;
|
||||
|
||||
::memcpy(buffer + 7U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 14U);
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
|
||||
{
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRA", 4U);
|
||||
|
||||
buffer[4U] = id >> 16;
|
||||
buffer[5U] = id >> 8;
|
||||
buffer[6U] = id >> 0;
|
||||
|
||||
buffer[7U] = type;
|
||||
|
||||
::memcpy(buffer + 8U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 15U);
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::isConnected() const
|
||||
{
|
||||
return (m_addrLen != 0);
|
||||
}
|
||||
|
||||
void CDMRGatewayNetwork::close(bool sayGoodbye)
|
||||
{
|
||||
LogMessage("DMR, Closing DMR Network");
|
||||
|
||||
m_socket.close();
|
||||
}
|
||||
|
||||
void CDMRGatewayNetwork::clock(unsigned int ms)
|
||||
{
|
||||
m_pingTimer.clock(ms);
|
||||
if (m_pingTimer.isRunning() && m_pingTimer.hasExpired()) {
|
||||
writeConfig();
|
||||
m_pingTimer.start();
|
||||
}
|
||||
|
||||
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_addr, address)) {
|
||||
LogMessage("DMR, packet received from an invalid source");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "DMR Network Received", m_buffer, length);
|
||||
|
||||
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
|
||||
if (m_enabled) {
|
||||
unsigned char len = length;
|
||||
m_rxData.addData(&len, 1U);
|
||||
m_rxData.addData(m_buffer, len);
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "DMRP", 4U) == 0) {
|
||||
;
|
||||
} else if (::memcmp(m_buffer, "DMRB", 4U) == 0) {
|
||||
m_beacon = true;
|
||||
} else {
|
||||
CUtils::dump("DMR, unknown packet from the DMR Network", m_buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::writeConfig()
|
||||
{
|
||||
const char* software;
|
||||
char slots = '0';
|
||||
if (m_duplex) {
|
||||
if (m_slot1 && m_slot2)
|
||||
slots = '3';
|
||||
else if (m_slot1 && !m_slot2)
|
||||
slots = '1';
|
||||
else if (!m_slot1 && m_slot2)
|
||||
slots = '2';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
case HWT_MMDVM_HS_DUAL_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||
break;
|
||||
case HWT_NANO_HOTSPOT:
|
||||
software = "MMDVM_Nano_hotSPOT";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
slots = '4';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM_DMO";
|
||||
break;
|
||||
case HWT_DVMEGA:
|
||||
software = "MMDVM_DVMega";
|
||||
break;
|
||||
case HWT_MMDVM_ZUMSPOT:
|
||||
software = "MMDVM_ZUMspot";
|
||||
break;
|
||||
case HWT_MMDVM_HS_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Hat";
|
||||
break;
|
||||
case HWT_MMDVM_HS_DUAL_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||
break;
|
||||
case HWT_NANO_HOTSPOT:
|
||||
software = "MMDVM_Nano_hotSPOT";
|
||||
break;
|
||||
case HWT_NANO_DV:
|
||||
software = "MMDVM_Nano_DV";
|
||||
break;
|
||||
case HWT_D2RG_MMDVM_HS:
|
||||
software = "MMDVM_D2RG_MMDVM_HS";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
case HWT_OPENGD77_HS:
|
||||
software = "MMDVM_OpenGD77_HS";
|
||||
break;
|
||||
case HWT_SKYBRIDGE:
|
||||
software = "MMDVM_SkyBridge";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int power = m_power;
|
||||
if (power > 99U)
|
||||
power = 99U;
|
||||
|
||||
char buffer[150U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRC", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%c%-40.40s%-40.40s",
|
||||
m_callsign.c_str(), m_rxFrequency, m_txFrequency, power, m_colorCode, slots, m_version,
|
||||
software);
|
||||
|
||||
return write((unsigned char*)buffer, 119U);
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::wantsBeacon()
|
||||
{
|
||||
bool beacon = m_beacon;
|
||||
|
||||
m_beacon = false;
|
||||
|
||||
return beacon;
|
||||
}
|
||||
|
||||
bool CDMRGatewayNetwork::write(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "DMR Network Transmitted", data, length);
|
||||
|
||||
bool ret = m_socket.write(data, length, m_addr, m_addrLen);
|
||||
if (!ret) {
|
||||
LogError("DMR, socket error when writing to the DMR Network");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* 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(DMRGatewayNetwork_H)
|
||||
#define DMRGatewayNetwork_H
|
||||
|
||||
#include "DMRNetwork.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "DMRData.h"
|
||||
#include "Defines.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
class CDMRGatewayNetwork : public IDMRNetwork
|
||||
{
|
||||
public:
|
||||
CDMRGatewayNetwork(const std::string& remoteAddress, unsigned short remotePort, const std::string& localAddress, unsigned short localPort, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug);
|
||||
virtual ~CDMRGatewayNetwork();
|
||||
|
||||
virtual void setOptions(const std::string& options);
|
||||
|
||||
virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url);
|
||||
|
||||
virtual bool open();
|
||||
|
||||
virtual void enable(bool enabled);
|
||||
|
||||
virtual bool read(CDMRData& data);
|
||||
|
||||
virtual bool write(const CDMRData& data);
|
||||
|
||||
virtual bool writeRadioPosition(unsigned int id, const unsigned char* data);
|
||||
|
||||
virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
|
||||
|
||||
virtual bool wantsBeacon();
|
||||
|
||||
virtual void clock(unsigned int ms);
|
||||
|
||||
virtual bool isConnected() const;
|
||||
|
||||
virtual void close(bool sayGoodbye);
|
||||
|
||||
private:
|
||||
std::string m_addressStr;
|
||||
sockaddr_storage m_addr;
|
||||
unsigned int m_addrLen;
|
||||
unsigned short m_port;
|
||||
uint8_t* m_id;
|
||||
bool m_duplex;
|
||||
const char* m_version;
|
||||
bool m_debug;
|
||||
CUDPSocket m_socket;
|
||||
bool m_enabled;
|
||||
bool m_slot1;
|
||||
bool m_slot2;
|
||||
HW_TYPE m_hwType;
|
||||
unsigned char* m_buffer;
|
||||
uint32_t* m_streamId;
|
||||
CRingBuffer<unsigned char> m_rxData;
|
||||
bool m_beacon;
|
||||
std::mt19937 m_random;
|
||||
std::string m_callsign;
|
||||
unsigned int m_rxFrequency;
|
||||
unsigned int m_txFrequency;
|
||||
unsigned int m_power;
|
||||
unsigned int m_colorCode;
|
||||
CTimer m_pingTimer;
|
||||
|
||||
bool writeConfig();
|
||||
|
||||
bool write(const unsigned char* data, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
||||
427
DMRNetwork.cpp
427
DMRNetwork.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2015-2021,2023 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,6 +18,429 @@
|
||||
|
||||
#include "DMRNetwork.h"
|
||||
|
||||
IDMRNetwork::~IDMRNetwork()
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 500U;
|
||||
|
||||
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
|
||||
|
||||
|
||||
CDMRNetwork::CDMRNetwork(const std::string& address, unsigned short port, const std::string& localAddress, unsigned short localPort, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) :
|
||||
m_addressStr(address),
|
||||
m_addr(),
|
||||
m_addrLen(0U),
|
||||
m_port(port),
|
||||
m_id(NULL),
|
||||
m_duplex(duplex),
|
||||
m_version(version),
|
||||
m_debug(debug),
|
||||
m_socket(localAddress, localPort),
|
||||
m_enabled(false),
|
||||
m_slot1(slot1),
|
||||
m_slot2(slot2),
|
||||
m_hwType(hwType),
|
||||
m_buffer(NULL),
|
||||
m_streamId(NULL),
|
||||
m_rxData(1000U, "DMR Network"),
|
||||
m_beacon(false),
|
||||
m_random(),
|
||||
m_callsign(),
|
||||
m_rxFrequency(0U),
|
||||
m_txFrequency(0U),
|
||||
m_power(0U),
|
||||
m_colorCode(0U),
|
||||
m_pingTimer(1000U, 10U)
|
||||
{
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
assert(id > 1000U);
|
||||
|
||||
if (CUDPSocket::lookup(m_addressStr, m_port, m_addr, m_addrLen) != 0)
|
||||
m_addrLen = 0U;
|
||||
|
||||
m_buffer = new unsigned char[BUFFER_LENGTH];
|
||||
m_id = new uint8_t[4U];
|
||||
m_streamId = new uint32_t[2U];
|
||||
|
||||
m_id[0U] = id >> 24;
|
||||
m_id[1U] = id >> 16;
|
||||
m_id[2U] = id >> 8;
|
||||
m_id[3U] = id >> 0;
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
m_random = mt;
|
||||
|
||||
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
|
||||
m_streamId[0U] = dist(m_random);
|
||||
m_streamId[1U] = dist(m_random);
|
||||
}
|
||||
|
||||
CDMRNetwork::~CDMRNetwork()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
delete[] m_streamId;
|
||||
delete[] m_id;
|
||||
}
|
||||
|
||||
void CDMRNetwork::setConfig(const std::string & callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode)
|
||||
{
|
||||
m_callsign = callsign;
|
||||
m_rxFrequency = rxFrequency;
|
||||
m_txFrequency = txFrequency;
|
||||
m_power = power;
|
||||
m_colorCode = colorCode;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::open()
|
||||
{
|
||||
if (m_addrLen == 0U) {
|
||||
LogError("Unable to resolve the address of the DMR Network");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMessage("DMR, Opening DMR Network");
|
||||
|
||||
bool ret = m_socket.open(m_addr);
|
||||
if (ret)
|
||||
m_pingTimer.start();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CDMRNetwork::enable(bool enabled)
|
||||
{
|
||||
if (!enabled && m_enabled)
|
||||
m_rxData.clear();
|
||||
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::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;
|
||||
|
||||
// DMO mode slot disabling
|
||||
if (slotNo == 1U && !m_duplex)
|
||||
return false;
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return false;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return false;
|
||||
|
||||
FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP;
|
||||
|
||||
data.setSeqNo(seqNo);
|
||||
data.setSlotNo(slotNo);
|
||||
data.setSrcId(srcId);
|
||||
data.setDstId(dstId);
|
||||
data.setFLCO(flco);
|
||||
|
||||
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 CDMRNetwork::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_id, 4U);
|
||||
|
||||
unsigned int slotNo = data.getSlotNo();
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return false;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return false;
|
||||
|
||||
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
|
||||
|
||||
FLCO flco = data.getFLCO();
|
||||
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
|
||||
|
||||
unsigned int slotIndex = slotNo - 1U;
|
||||
|
||||
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
|
||||
unsigned char dataType = data.getDataType();
|
||||
if (dataType == DT_VOICE_SYNC) {
|
||||
buffer[15U] |= 0x10U;
|
||||
} else if (dataType == DT_VOICE) {
|
||||
buffer[15U] |= data.getN();
|
||||
} else {
|
||||
if (dataType == DT_VOICE_LC_HEADER)
|
||||
m_streamId[slotIndex] = dist(m_random);
|
||||
|
||||
if (dataType == DT_CSBK || dataType == DT_DATA_HEADER)
|
||||
m_streamId[slotIndex] = dist(m_random);
|
||||
|
||||
buffer[15U] |= (0x20U | dataType);
|
||||
}
|
||||
|
||||
buffer[4U] = data.getSeqNo();
|
||||
|
||||
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
|
||||
|
||||
data.getData(buffer + 20U);
|
||||
|
||||
buffer[53U] = data.getBER();
|
||||
|
||||
buffer[54U] = data.getRSSI();
|
||||
|
||||
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeRadioPosition(unsigned int id, const unsigned char* data)
|
||||
{
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRG", 4U);
|
||||
|
||||
buffer[4U] = id >> 16;
|
||||
buffer[5U] = id >> 8;
|
||||
buffer[6U] = id >> 0;
|
||||
|
||||
::memcpy(buffer + 7U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 14U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
|
||||
{
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRA", 4U);
|
||||
|
||||
buffer[4U] = id >> 16;
|
||||
buffer[5U] = id >> 8;
|
||||
buffer[6U] = id >> 0;
|
||||
|
||||
buffer[7U] = type;
|
||||
|
||||
::memcpy(buffer + 8U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 15U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::isConnected() const
|
||||
{
|
||||
return (m_addrLen != 0);
|
||||
}
|
||||
|
||||
void CDMRNetwork::close(bool sayGoodbye)
|
||||
{
|
||||
LogMessage("DMR, Closing DMR Network");
|
||||
|
||||
m_socket.close();
|
||||
}
|
||||
|
||||
void CDMRNetwork::clock(unsigned int ms)
|
||||
{
|
||||
m_pingTimer.clock(ms);
|
||||
if (m_pingTimer.isRunning() && m_pingTimer.hasExpired()) {
|
||||
writeConfig();
|
||||
m_pingTimer.start();
|
||||
}
|
||||
|
||||
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_addr, address)) {
|
||||
LogMessage("DMR, packet received from an invalid source");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "DMR Network Received", m_buffer, length);
|
||||
|
||||
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
|
||||
if (m_enabled) {
|
||||
unsigned char len = length;
|
||||
m_rxData.addData(&len, 1U);
|
||||
m_rxData.addData(m_buffer, len);
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "DMRP", 4U) == 0) {
|
||||
;
|
||||
} else if (::memcmp(m_buffer, "DMRB", 4U) == 0) {
|
||||
m_beacon = true;
|
||||
} else {
|
||||
CUtils::dump("DMR, unknown packet from the DMR Network", m_buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeConfig()
|
||||
{
|
||||
const char* software;
|
||||
char slots = '0';
|
||||
if (m_duplex) {
|
||||
if (m_slot1 && m_slot2)
|
||||
slots = '3';
|
||||
else if (m_slot1 && !m_slot2)
|
||||
slots = '1';
|
||||
else if (!m_slot1 && m_slot2)
|
||||
slots = '2';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
case HWT_MMDVM_HS_DUAL_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||
break;
|
||||
case HWT_NANO_HOTSPOT:
|
||||
software = "MMDVM_Nano_hotSPOT";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
slots = '4';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM_DMO";
|
||||
break;
|
||||
case HWT_DVMEGA:
|
||||
software = "MMDVM_DVMega";
|
||||
break;
|
||||
case HWT_MMDVM_ZUMSPOT:
|
||||
software = "MMDVM_ZUMspot";
|
||||
break;
|
||||
case HWT_MMDVM_HS_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Hat";
|
||||
break;
|
||||
case HWT_MMDVM_HS_DUAL_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||
break;
|
||||
case HWT_NANO_HOTSPOT:
|
||||
software = "MMDVM_Nano_hotSPOT";
|
||||
break;
|
||||
case HWT_NANO_DV:
|
||||
software = "MMDVM_Nano_DV";
|
||||
break;
|
||||
case HWT_D2RG_MMDVM_HS:
|
||||
software = "MMDVM_D2RG_MMDVM_HS";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
case HWT_OPENGD77_HS:
|
||||
software = "MMDVM_OpenGD77_HS";
|
||||
break;
|
||||
case HWT_SKYBRIDGE:
|
||||
software = "MMDVM_SkyBridge";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int power = m_power;
|
||||
if (power > 99U)
|
||||
power = 99U;
|
||||
|
||||
char buffer[150U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRC", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%c%-40.40s%-40.40s",
|
||||
m_callsign.c_str(), m_rxFrequency, m_txFrequency, power, m_colorCode, slots, m_version,
|
||||
software);
|
||||
|
||||
return write((unsigned char*)buffer, 119U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::wantsBeacon()
|
||||
{
|
||||
bool beacon = m_beacon;
|
||||
|
||||
m_beacon = false;
|
||||
|
||||
return beacon;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::write(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "DMR Network Transmitted", data, length);
|
||||
|
||||
bool ret = m_socket.write(data, length, m_addr, m_addrLen);
|
||||
if (!ret) {
|
||||
LogError("DMR, socket error when writing to the DMR Network");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
65
DMRNetwork.h
65
DMRNetwork.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2015,2016,2017,2018,2020,2021,2023 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,40 +19,73 @@
|
||||
#if !defined(DMRNetwork_H)
|
||||
#define DMRNetwork_H
|
||||
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "DMRData.h"
|
||||
#include "Defines.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
class IDMRNetwork
|
||||
class CDMRNetwork
|
||||
{
|
||||
public:
|
||||
virtual ~IDMRNetwork() = 0;
|
||||
CDMRNetwork(const std::string& gatewayAddress, unsigned short gatewayPort, const std::string& localAddress, unsigned short localPort, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug);
|
||||
~CDMRNetwork();
|
||||
|
||||
virtual void setOptions(const std::string& options) = 0;
|
||||
void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode);
|
||||
|
||||
virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url) = 0;
|
||||
bool open();
|
||||
|
||||
virtual bool open() = 0;
|
||||
void enable(bool enabled);
|
||||
|
||||
virtual void enable(bool enabled) = 0;
|
||||
bool read(CDMRData& data);
|
||||
|
||||
virtual bool read(CDMRData& data) = 0;
|
||||
bool write(const CDMRData& data);
|
||||
|
||||
virtual bool write(const CDMRData& data) = 0;
|
||||
bool writeRadioPosition(unsigned int id, const unsigned char* data);
|
||||
|
||||
virtual bool writeRadioPosition(unsigned int id, const unsigned char* data) = 0;
|
||||
bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
|
||||
|
||||
virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data) = 0;
|
||||
bool wantsBeacon();
|
||||
|
||||
virtual bool wantsBeacon() = 0;
|
||||
void clock(unsigned int ms);
|
||||
|
||||
virtual void clock(unsigned int ms) = 0;
|
||||
bool isConnected() const;
|
||||
|
||||
virtual bool isConnected() const = 0;
|
||||
|
||||
virtual void close(bool sayGoodbye) = 0;
|
||||
void close(bool sayGoodbye);
|
||||
|
||||
private:
|
||||
std::string m_addressStr;
|
||||
sockaddr_storage m_addr;
|
||||
unsigned int m_addrLen;
|
||||
unsigned short m_port;
|
||||
uint8_t* m_id;
|
||||
bool m_duplex;
|
||||
const char* m_version;
|
||||
bool m_debug;
|
||||
CUDPSocket m_socket;
|
||||
bool m_enabled;
|
||||
bool m_slot1;
|
||||
bool m_slot2;
|
||||
HW_TYPE m_hwType;
|
||||
unsigned char* m_buffer;
|
||||
uint32_t* m_streamId;
|
||||
CRingBuffer<unsigned char> m_rxData;
|
||||
bool m_beacon;
|
||||
std::mt19937 m_random;
|
||||
std::string m_callsign;
|
||||
unsigned int m_rxFrequency;
|
||||
unsigned int m_txFrequency;
|
||||
unsigned int m_power;
|
||||
unsigned int m_colorCode;
|
||||
CTimer m_pingTimer;
|
||||
|
||||
bool writeConfig();
|
||||
|
||||
bool write(const unsigned char* data, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@ bool CDMRSlot::m_embeddedLCOnly = false;
|
||||
bool CDMRSlot::m_dumpTAData = true;
|
||||
|
||||
CModem* CDMRSlot::m_modem = NULL;
|
||||
IDMRNetwork* CDMRSlot::m_network = NULL;
|
||||
CDMRNetwork* CDMRSlot::m_network = NULL;
|
||||
CDisplay* CDMRSlot::m_display = NULL;
|
||||
bool CDMRSlot::m_duplex = true;
|
||||
CDMRLookup* CDMRSlot::m_lookup = NULL;
|
||||
@@ -2015,7 +2015,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data)
|
||||
m_queue.addData(data, len);
|
||||
}
|
||||
|
||||
void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm)
|
||||
void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm)
|
||||
{
|
||||
assert(modem != NULL);
|
||||
assert(display != NULL);
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
void enable(bool enabled);
|
||||
|
||||
static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm);
|
||||
static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm);
|
||||
|
||||
private:
|
||||
unsigned int m_slotNo;
|
||||
@@ -120,7 +120,7 @@ private:
|
||||
static bool m_dumpTAData;
|
||||
|
||||
static CModem* m_modem;
|
||||
static IDMRNetwork* m_network;
|
||||
static CDMRNetwork* m_network;
|
||||
static CDisplay* m_display;
|
||||
static bool m_duplex;
|
||||
static CDMRLookup* m_lookup;
|
||||
|
||||
@@ -231,18 +231,13 @@ Debug=0
|
||||
|
||||
[DMR Network]
|
||||
Enable=1
|
||||
# Type may be either 'Direct' or 'Gateway'. When Direct you must provide the Master's
|
||||
# address as well as the Password, and for DMR+, Options also.
|
||||
Type=Gateway
|
||||
LocalAddress=127.0.0.1
|
||||
LocalPort=62032
|
||||
RemoteAddress=127.0.0.1
|
||||
RemotePort=62031
|
||||
# Password=P@ssw0rd1234
|
||||
GatewayAddress=127.0.0.1
|
||||
GatewayPort=62031
|
||||
Jitter=360
|
||||
Slot1=1
|
||||
Slot2=1
|
||||
# Options=
|
||||
# ModeHang=3
|
||||
Debug=0
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
*/
|
||||
|
||||
#include "MMDVMHost.h"
|
||||
#include "DMRDirectNetwork.h"
|
||||
#include "DMRGatewayNetwork.h"
|
||||
#include "NXDNKenwoodNetwork.h"
|
||||
#include "NXDNIcomNetwork.h"
|
||||
#include "RSSIInterpolator.h"
|
||||
@@ -82,7 +80,7 @@ static void sigHandler2(int signum)
|
||||
const char* HEADER1 = "This software is for use on amateur radio networks only,";
|
||||
const char* HEADER2 = "it is to be used for educational purposes only. Its use on";
|
||||
const char* HEADER3 = "commercial networks is strictly prohibited.";
|
||||
const char* HEADER4 = "Copyright(C) 2015-2021 by Jonathan Naylor, G4KLX and others";
|
||||
const char* HEADER4 = "Copyright(C) 2015-2023 by Jonathan Naylor, G4KLX and others";
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
@@ -1648,26 +1646,21 @@ bool CMMDVMHost::createDStarNetwork()
|
||||
|
||||
bool CMMDVMHost::createDMRNetwork()
|
||||
{
|
||||
std::string remoteAddress = m_conf.getDMRNetworkRemoteAddress();
|
||||
unsigned short remotePort = m_conf.getDMRNetworkRemotePort();
|
||||
std::string gatewayAddress = m_conf.getDMRNetworkGatewayAddress();
|
||||
unsigned short gatewayPort = m_conf.getDMRNetworkGatewayPort();
|
||||
std::string localAddress = m_conf.getDMRNetworkLocalAddress();
|
||||
unsigned short localPort = m_conf.getDMRNetworkLocalPort();
|
||||
unsigned int id = m_conf.getDMRId();
|
||||
std::string password = m_conf.getDMRNetworkPassword();
|
||||
bool debug = m_conf.getDMRNetworkDebug();
|
||||
unsigned int jitter = m_conf.getDMRNetworkJitter();
|
||||
bool slot1 = m_conf.getDMRNetworkSlot1();
|
||||
bool slot2 = m_conf.getDMRNetworkSlot2();
|
||||
HW_TYPE hwType = m_modem->getHWType();
|
||||
m_dmrNetModeHang = m_conf.getDMRNetworkModeHang();
|
||||
std::string options = m_conf.getDMRNetworkOptions();
|
||||
|
||||
std::string type = m_conf.getDMRNetworkType();
|
||||
|
||||
LogInfo("DMR Network Parameters");
|
||||
LogInfo(" Type: %s", type.c_str());
|
||||
LogInfo(" Remote Address: %s", remoteAddress.c_str());
|
||||
LogInfo(" Remote Port: %hu", remotePort);
|
||||
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
|
||||
LogInfo(" Gateway Port: %hu", gatewayPort);
|
||||
LogInfo(" Local Address: %s", localAddress.c_str());
|
||||
LogInfo(" Local Port: %hu", localPort);
|
||||
LogInfo(" Jitter: %ums", jitter);
|
||||
@@ -1675,10 +1668,7 @@ bool CMMDVMHost::createDMRNetwork()
|
||||
LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled");
|
||||
LogInfo(" Mode Hang: %us", m_dmrNetModeHang);
|
||||
|
||||
if (type == "Direct")
|
||||
m_dmrNetwork = new CDMRDirectNetwork(remoteAddress, remotePort, localAddress, localPort, id, password, m_duplex, VERSION, slot1, slot2, hwType, debug);
|
||||
else
|
||||
m_dmrNetwork = new CDMRGatewayNetwork(remoteAddress, remotePort, localAddress, localPort, id, m_duplex, VERSION, slot1, slot2, hwType, debug);
|
||||
m_dmrNetwork = new CDMRNetwork(gatewayAddress, gatewayPort, localAddress, localPort, id, m_duplex, VERSION, slot1, slot2, hwType, debug);
|
||||
|
||||
unsigned int rxFrequency = m_conf.getRXFrequency();
|
||||
unsigned int txFrequency = m_conf.getTXFrequency();
|
||||
@@ -1691,31 +1681,7 @@ bool CMMDVMHost::createDMRNetwork()
|
||||
LogInfo(" TX Frequency: %uHz", txFrequency);
|
||||
LogInfo(" Power: %uW", power);
|
||||
|
||||
if (type == "Direct") {
|
||||
float latitude = m_conf.getLatitude();
|
||||
float longitude = m_conf.getLongitude();
|
||||
int height = m_conf.getHeight();
|
||||
std::string location = m_conf.getLocation();
|
||||
std::string description = m_conf.getDescription();
|
||||
std::string url = m_conf.getURL();
|
||||
|
||||
LogInfo(" Latitude: %fdeg N", latitude);
|
||||
LogInfo(" Longitude: %fdeg E", longitude);
|
||||
LogInfo(" Height: %um", height);
|
||||
LogInfo(" Location: \"%s\"", location.c_str());
|
||||
LogInfo(" Description: \"%s\"", description.c_str());
|
||||
LogInfo(" URL: \"%s\"", url.c_str());
|
||||
|
||||
m_dmrNetwork->setConfig(m_callsign, rxFrequency, txFrequency, power, colorCode, latitude, longitude, height, location, description, url);
|
||||
} else {
|
||||
m_dmrNetwork->setConfig(m_callsign, rxFrequency, txFrequency, power, colorCode, 0.0F, 0.0F, 0, "", "", "");
|
||||
}
|
||||
|
||||
if (!options.empty()) {
|
||||
LogInfo(" Options: %s", options.c_str());
|
||||
|
||||
m_dmrNetwork->setOptions(options);
|
||||
}
|
||||
m_dmrNetwork->setConfig(m_callsign, rxFrequency, txFrequency, power, colorCode);
|
||||
|
||||
bool ret = m_dmrNetwork->open();
|
||||
if (!ret) {
|
||||
@@ -2747,7 +2713,7 @@ void CMMDVMHost::processModeCommand(unsigned char mode, unsigned int timeout)
|
||||
|
||||
void CMMDVMHost::processEnableCommand(bool& mode, bool enabled)
|
||||
{
|
||||
LogDebug("Setting mode current=%s new=%s",mode ? "true" : "false",enabled ? "true" : "false");
|
||||
LogDebug("Setting mode current=%s new=%s", mode ? "true" : "false", enabled ? "true" : "false");
|
||||
|
||||
mode = enabled;
|
||||
|
||||
@@ -2794,7 +2760,7 @@ void CMMDVMHost::buildNetworkHostsString(std::string &str)
|
||||
}
|
||||
}
|
||||
str += std::string("dstar:\"") + ((dstarReflector.length() == 0) ? "NONE" : dstarReflector) + "\"";
|
||||
str += std::string(" dmr:\"") + ((m_dmrEnabled && (m_dmrNetwork != NULL)) ? m_conf.getDMRNetworkRemoteAddress() : "NONE") + "\"";
|
||||
str += std::string(" dmr:\"") + ((m_dmrEnabled && (m_dmrNetwork != NULL)) ? m_conf.getDMRNetworkGatewayAddress() : "NONE") + "\"";
|
||||
str += std::string(" ysf:\"") + ((m_ysfEnabled && (m_ysfNetwork != NULL)) ? m_conf.getFusionNetworkGatewayAddress() : "NONE") + "\"";
|
||||
str += std::string(" p25:\"") + ((m_p25Enabled && (m_p25Network != NULL)) ? m_conf.getP25GatewayAddress() : "NONE") + "\"";
|
||||
str += std::string(" nxdn:\"") + ((m_nxdnEnabled && (m_nxdnNetwork != NULL)) ? m_conf.getNXDNGatewayAddress() : "NONE") + "\"";
|
||||
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
CFMControl* m_fm;
|
||||
CAX25Control* m_ax25;
|
||||
CDStarNetwork* m_dstarNetwork;
|
||||
IDMRNetwork* m_dmrNetwork;
|
||||
CDMRNetwork* m_dmrNetwork;
|
||||
CYSFNetwork* m_ysfNetwork;
|
||||
CP25Network* m_p25Network;
|
||||
INXDNNetwork* m_nxdnNetwork;
|
||||
|
||||
@@ -169,11 +169,9 @@
|
||||
<ClInclude Include="DMRData.h" />
|
||||
<ClInclude Include="DMRDataHeader.h" />
|
||||
<ClInclude Include="DMRDefines.h" />
|
||||
<ClInclude Include="DMRDirectNetwork.h" />
|
||||
<ClInclude Include="DMREMB.h" />
|
||||
<ClInclude Include="DMREmbeddedData.h" />
|
||||
<ClInclude Include="DMRFullLC.h" />
|
||||
<ClInclude Include="DMRGatewayNetwork.h" />
|
||||
<ClInclude Include="DMRLC.h" />
|
||||
<ClInclude Include="DMRNetwork.h" />
|
||||
<ClInclude Include="DMRShortLC.h" />
|
||||
@@ -281,11 +279,9 @@
|
||||
<ClCompile Include="DMRCSBK.cpp" />
|
||||
<ClCompile Include="DMRData.cpp" />
|
||||
<ClCompile Include="DMRDataHeader.cpp" />
|
||||
<ClCompile Include="DMRDirectNetwork.cpp" />
|
||||
<ClCompile Include="DMREMB.cpp" />
|
||||
<ClCompile Include="DMREmbeddedData.cpp" />
|
||||
<ClCompile Include="DMRFullLC.cpp" />
|
||||
<ClCompile Include="DMRGatewayNetwork.cpp" />
|
||||
<ClCompile Include="DMRLC.cpp" />
|
||||
<ClCompile Include="DMRLookup.cpp" />
|
||||
<ClCompile Include="DMRNetwork.cpp" />
|
||||
|
||||
@@ -323,12 +323,6 @@
|
||||
<ClInclude Include="PseudoTTYController.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRDirectNetwork.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRGatewayNetwork.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SHA256.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -631,12 +625,6 @@
|
||||
<ClCompile Include="PseudoTTYController.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRDirectNetwork.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRGatewayNetwork.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SHA256.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
2
Makefile
2
Makefile
@@ -8,7 +8,7 @@ LDFLAGS = -g -L/usr/local/lib
|
||||
|
||||
OBJECTS = \
|
||||
AMBEFEC.o BCH.o AX25Control.o AX25Network.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
|
||||
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \
|
||||
Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \
|
||||
MQTTPublisher.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \
|
||||
|
||||
@@ -9,7 +9,7 @@ LDFLAGS = -g -L/usr/local/lib
|
||||
|
||||
OBJECTS = \
|
||||
AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
|
||||
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \
|
||||
Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \
|
||||
MMDVMHost.o MQTTPublisher.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \
|
||||
|
||||
@@ -8,7 +8,7 @@ LDFLAGS = -g -L/usr/local/lib
|
||||
|
||||
OBJECTS = \
|
||||
AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
|
||||
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \
|
||||
Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \
|
||||
MMDVMHost.o MQTTPublisher.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \
|
||||
|
||||
@@ -8,7 +8,7 @@ LDFLAGS = -g -L/usr/local/lib
|
||||
|
||||
OBJECTS = \
|
||||
AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
|
||||
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \
|
||||
Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \
|
||||
MQTTPublisher.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \
|
||||
|
||||
@@ -12,7 +12,7 @@ LDFLAGS = -g -L/usr/local/lib
|
||||
|
||||
OBJECTS = \
|
||||
AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
|
||||
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \
|
||||
Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \
|
||||
MQTTPublisher.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \
|
||||
|
||||
@@ -9,7 +9,7 @@ LDFLAGS = -g -L/usr/local/lib
|
||||
|
||||
OBJECTS = \
|
||||
AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
|
||||
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \
|
||||
DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \
|
||||
Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \
|
||||
MMDVMHost.o MQTTPublisher.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \
|
||||
|
||||
Reference in New Issue
Block a user