Compare commits

..

No commits in common. "master" and "EOF" have entirely different histories.
master ... EOF

164 changed files with 30218 additions and 610 deletions

1
.gitignore vendored
View file

@ -17,4 +17,3 @@ RemoteCommand
.vs
*.ambe
GitVersion.h
.vscode

80
.vscode/settings.json vendored
View file

@ -1,80 +0,0 @@
{
"files.associations": {
"fstream": "cpp",
"cstring": "cpp",
"string": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"hash_map": "cpp",
"strstream": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cfenv": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp"
}
}

252
AX25Control.cpp Normal file
View file

@ -0,0 +1,252 @@
/*
* Copyright (C) 2020 Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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.
*/
#include "AX25Control.h"
#include "AX25Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <ctime>
// #define DUMP_AX25
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CAX25Control::CAX25Control(CAX25Network* network, bool trace) :
m_network(network),
m_trace(trace),
m_enabled(true),
m_fp(NULL)
{
}
CAX25Control::~CAX25Control()
{
}
bool CAX25Control::writeModem(unsigned char *data, unsigned int len)
{
assert(data != NULL);
if (!m_enabled)
return false;
if (m_trace)
decode(data, len);
CUtils::dump(1U, "AX.25 received packet", data, len);
if (m_network == NULL)
return true;
return m_network->write(data, len);
}
unsigned int CAX25Control::readModem(unsigned char* data)
{
assert(data != NULL);
if (m_network == NULL)
return 0U;
if (!m_enabled)
return 0U;
unsigned int length = m_network->read(data, 500U);
if (length > 0U)
CUtils::dump(1U, "AX.25 transmitted packet", data, length);
return length;
}
bool CAX25Control::openFile()
{
if (m_fp != NULL)
return true;
time_t t;
::time(&t);
struct tm* tm = ::localtime(&t);
char name[100U];
::sprintf(name, "AX25_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
m_fp = ::fopen(name, "wb");
if (m_fp == NULL)
return false;
::fwrite("AX25", 1U, 4U, m_fp);
return true;
}
bool CAX25Control::writeFile(const unsigned char* data, unsigned int length)
{
if (m_fp == NULL)
return false;
::fwrite(&length, 1U, sizeof(unsigned int), m_fp);
::fwrite(data, 1U, length, m_fp);
return true;
}
void CAX25Control::closeFile()
{
if (m_fp != NULL) {
::fclose(m_fp);
m_fp = NULL;
}
}
void CAX25Control::enable(bool enabled)
{
m_enabled = enabled;
}
void CAX25Control::decode(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length >= 15U);
std::string text;
bool more = decodeAddress(data + 7U, text);
text += '>';
decodeAddress(data + 0U, text);
unsigned int n = 14U;
while (more && n < length) {
text += ',';
more = decodeAddress(data + n, text, true);
n += 7U;
}
text += ' ';
if ((data[n] & 0x01U) == 0x00U) {
// I frame
char t[20U];
::sprintf(t, "<I S%u R%u>", (data[n] >> 1) & 0x07U, (data[n] >> 5) & 0x07U);
text += t;
} else {
if ((data[n] & 0x02U) == 0x00U) {
// S frame
char t[20U];
switch (data[n] & 0x0FU) {
case 0x01U:
sprintf(t, "<RR R%u>", (data[n] >> 5) & 0x07U);
break;
case 0x05U:
sprintf(t, "<RNR R%u>", (data[n] >> 5) & 0x07U);
break;
case 0x09U:
sprintf(t, "<REJ R%u>", (data[n] >> 5) & 0x07U);
break;
case 0x0DU:
sprintf(t, "<SREJ R%u>", (data[n] >> 5) & 0x07U);
break;
default:
sprintf(t, "<Unknown R%u>", (data[n] >> 5) & 0x07U);
break;
}
text += t;
LogMessage("AX.25, %s", text.c_str());
return;
} else {
// U frame
switch (data[n] & 0xEFU) {
case 0x6FU:
text += "<SABME>";
break;
case 0x2FU:
text += "<SABM>";
break;
case 0x43U:
text += "<DISC>";
break;
case 0x0FU:
text += "<DM>";
break;
case 0x63U:
text += "<UA>";
break;
case 0x87U:
text += "<FRMR>";
break;
case 0x03U:
text += "<UI>";
break;
case 0xAFU:
text += "<XID>";
break;
case 0xE3U:
text += "<TEST>";
break;
default:
text += "<Unknown>";
break;
}
if ((data[n] & 0xEFU) != 0x03U) {
LogMessage("AX.25, %s", text.c_str());
return;
}
}
}
n += 2U;
LogMessage("AX.25, %s %.*s", text.c_str(), length - n, data + n);
}
bool CAX25Control::decodeAddress(const unsigned char* data, std::string& text, bool isDigi) const
{
assert(data != NULL);
for (unsigned int i = 0U; i < 6U; i++) {
char c = data[i] >> 1;
if (c != ' ')
text += c;
}
unsigned char ssid = (data[6U] >> 1) & 0x0FU;
if (ssid > 0U) {
text += '-';
if (ssid >= 10U) {
text += '1';
text += '0' + ssid - 10U;
}
else {
text += '0' + ssid;
}
}
if (isDigi) {
if ((data[6U] & 0x80U) == 0x80U)
text += '*';
}
return (data[6U] & 0x01U) == 0x00U;
}

50
AX25Control.h Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright (C) 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.
*/
#if !defined(AX25Control_H)
#define AX25Control_H
#include "AX25Network.h"
#include <string>
class CAX25Control {
public:
CAX25Control(CAX25Network* network, bool trace);
~CAX25Control();
bool writeModem(unsigned char* data, unsigned int len);
unsigned int readModem(unsigned char* data);
void enable(bool enabled);
private:
CAX25Network* m_network;
bool m_trace;
bool m_enabled;
FILE* m_fp;
void decode(const unsigned char* data, unsigned int length);
bool decodeAddress(const unsigned char* data, std::string& text, bool isDigi = false) const;
bool openFile();
bool writeFile(const unsigned char* data, unsigned int length);
void closeFile();
};
#endif

39
AX25Defines.h Normal file
View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 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.
*/
#if !defined(AX25Defines_H)
#define AX25Defines_H
const unsigned int AX25_CALLSIGN_TEXT_LENGTH = 6U;
const unsigned int AX25_SSID_LENGTH = 1U;
const unsigned int AX25_CALLSIGN_LENGTH = 7U;
const unsigned int AX25_MAX_DIGIPEATERS = 6U;
const unsigned char AX25_PID_NOL3 = 0xF0U;
const unsigned int AX25_MAX_FRAME_LENGTH_BYTES = 330U; // Callsign (7) + Callsign (7) + 8 Digipeaters (56) +
// Control (1) + PID (1) + Data (256) + Checksum (2)
const unsigned char AX25_KISS_DATA = 0x00U;
const unsigned char AX25_FEND = 0xC0U;
const unsigned char AX25_FESC = 0xDBU;
const unsigned char AX25_TFEND = 0xDCU;
const unsigned char AX25_TFESC = 0xDDU;
#endif

183
AX25Network.cpp Normal file
View file

@ -0,0 +1,183 @@
/*
* Copyright (C) 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 "AX25Network.h"
#include "AX25Defines.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 500U;
CAX25Network::CAX25Network(const std::string& port, unsigned int speed, bool debug) :
m_serial(port, speed, false),
m_txData(NULL),
m_rxData(NULL),
m_rxLength(0U),
m_rxLastChar(0U),
m_debug(debug),
m_enabled(false)
{
assert(!port.empty());
assert(speed > 0U);
m_txData = new unsigned char[BUFFER_LENGTH];
m_rxData = new unsigned char[BUFFER_LENGTH];
}
CAX25Network::~CAX25Network()
{
delete[] m_txData;
delete[] m_rxData;
}
bool CAX25Network::open()
{
LogMessage("Opening AX25 network connection");
return m_serial.open();
}
bool CAX25Network::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
if (!m_enabled)
return true;
unsigned int txLength = 0U;
m_txData[txLength++] = AX25_FEND;
m_txData[txLength++] = AX25_KISS_DATA;
for (unsigned int i = 0U; i < length; i++) {
unsigned char c = data[i];
switch (c) {
case AX25_FEND:
m_txData[txLength++] = AX25_FESC;
m_txData[txLength++] = AX25_TFEND;
break;
case AX25_FESC:
m_txData[txLength++] = AX25_FESC;
m_txData[txLength++] = AX25_TFESC;
break;
default:
m_txData[txLength++] = c;
break;
}
}
m_txData[txLength++] = AX25_FEND;
if (m_debug)
CUtils::dump(1U, "AX25 Network Data Sent", m_txData, txLength);
return m_serial.write(m_txData, txLength);
}
unsigned int CAX25Network::read(unsigned char* data, unsigned int length)
{
assert(data != NULL);
bool complete = false;
unsigned char c;
while (m_serial.read(&c, 1U) > 0) {
if (m_rxLength == 0U && c == AX25_FEND)
m_rxData[m_rxLength++] = c;
else if (m_rxLength > 0U)
m_rxData[m_rxLength++] = c;
if (m_rxLength > 1U && c == AX25_FEND) {
complete = true;
break;
}
}
if (!m_enabled)
return 0U;
if (!complete)
return 0U;
if (m_rxLength == 0U)
return 0U;
if (m_rxData[1U] != AX25_KISS_DATA) {
m_rxLength = 0U;
return 0U;
}
complete = false;
unsigned int dataLen = 0U;
for (unsigned int i = 2U; i < m_rxLength; i++) {
unsigned char c = m_rxData[i];
if (c == AX25_FEND) {
complete = true;
break;
} else if (c == AX25_TFEND && m_rxLastChar == AX25_FESC) {
data[dataLen++] = AX25_FEND;
} else if (c == AX25_TFESC && m_rxLastChar == AX25_FESC) {
data[dataLen++] = AX25_FESC;
} else {
data[dataLen++] = c;
}
m_rxLastChar = c;
}
if (!complete)
return 0U;
if (m_debug)
CUtils::dump(1U, "AX25 Network Data Received", m_rxData, m_rxLength);
m_rxLength = 0U;
m_rxLastChar = 0U;
return dataLen;
}
void CAX25Network::reset()
{
}
void CAX25Network::close()
{
m_serial.close();
LogMessage("Closing AX25 network connection");
}
void CAX25Network::enable(bool enabled)
{
m_enabled = enabled;
if (enabled != m_enabled) {
m_rxLastChar = 0U;
m_rxLength = 0U;
}
}

62
AX25Network.h Normal file
View file

@ -0,0 +1,62 @@
/*
* Copyright (C) 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.
*/
#ifndef AX25Network_H
#define AX25Network_H
#if defined(_WIN32) || defined(_WIN64)
#include "UARTController.h"
#else
#include "PseudoTTYController.h"
#endif
#include <cstdint>
#include <string>
class CAX25Network {
public:
CAX25Network(const std::string& port, unsigned int speed, bool debug);
~CAX25Network();
bool open();
void enable(bool enabled);
bool write(const unsigned char* data, unsigned int length);
unsigned int read(unsigned char* data, unsigned int length);
void reset();
void close();
private:
#if defined(_WIN32) || defined(_WIN64)
CUARTController m_serial;
#else
CPseudoTTYController m_serial;
#endif
unsigned char* m_txData;
unsigned char* m_rxData;
unsigned int m_rxLength;
unsigned char m_rxLastChar;
bool m_debug;
bool m_enabled;
};
#endif

View file

@ -76,6 +76,20 @@ void CCASTInfo::setQuitInt()
{
}
void CCASTInfo::setFMInt()
{
}
void CCASTInfo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{
if (m_modem != NULL)
m_modem->writeDStarInfo(my1, my2, your, type, reflector);
}
void CCASTInfo::clearDStarInt()
{
}
void CCASTInfo::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
{
if (m_modem != NULL)
@ -86,6 +100,56 @@ void CCASTInfo::clearDMRInt(unsigned int slotNo)
{
}
void CCASTInfo::writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin)
{
if (m_modem != NULL)
m_modem->writeYSFInfo(source, dest, dgid, type, origin);
}
void CCASTInfo::clearFusionInt()
{
}
void CCASTInfo::writeP25Int(const char* source, bool group, unsigned int dest, const char* type)
{
if (m_modem != NULL)
m_modem->writeP25Info(source, group, dest, type);
}
void CCASTInfo::clearP25Int()
{
}
void CCASTInfo::writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type)
{
if (m_modem != NULL)
m_modem->writeNXDNInfo(source, group, dest, type);
}
void CCASTInfo::clearNXDNInt()
{
}
void CCASTInfo::writeM17Int(const char* source, const char* dest, const char* type)
{
if (m_modem != NULL)
m_modem->writeM17Info(source, dest, type);
}
void CCASTInfo::clearM17Int()
{
}
void CCASTInfo::writePOCSAGInt(uint32_t ric, const std::string& message)
{
if (m_modem != NULL)
m_modem->writePOCSAGInfo(ric, message);
}
void CCASTInfo::clearPOCSAGInt()
{
}
void CCASTInfo::writeCWInt()
{
}

View file

@ -41,10 +41,29 @@ protected:
virtual void setErrorInt(const char* text);
virtual void setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt();
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
virtual void clearDMRInt(unsigned int slotNo);
virtual void writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin);
virtual void clearFusionInt();
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
virtual void clearP25Int();
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
virtual void clearNXDNInt();
virtual void writeM17Int(const char* source, const char* dest, const char* type);
virtual void clearM17Int();
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);
virtual void clearPOCSAGInt();
virtual void writeCWInt();
virtual void clearCWInt();

1344
Conf.cpp

File diff suppressed because it is too large Load diff

350
Conf.h
View file

@ -65,6 +65,10 @@ public:
std::string getDMRIdLookupFile() const;
unsigned int getDMRIdLookupTime() const;
// The NXDN Id section
std::string getNXDNIdLookupFile() const;
unsigned int getNXDNIdLookupTime() const;
// The Modem section
std::string getModemProtocol() const;
std::string getModemUARTPort() const;
@ -108,7 +112,20 @@ public:
unsigned short getTransparentLocalPort() const;
unsigned int getTransparentSendFrameType() const;
// The DMR section
// The D-Star section
bool getDStarEnabled() const;
std::string getDStarModule() const;
bool getDStarSelfOnly() const;
std::vector<std::string> getDStarBlackList() const;
std::vector<std::string> getDStarWhiteList() const;
bool getDStarAckReply() const;
unsigned int getDStarAckTime() const;
DSTAR_ACK_MESSAGE getDStarAckMessage() const;
bool getDStarErrorReply() const;
bool getDStarRemoteGateway() const;
unsigned int getDStarModeHang() const;
// The DMR section
bool getDMREnabled() const;
DMR_BEACONS getDMRBeacons() const;
unsigned int getDMRBeaconInterval() const;
@ -128,7 +145,101 @@ public:
unsigned int getDMRModeHang() const;
DMR_OVCM_TYPES getDMROVCM() const;
// The DMR Network section
// The System Fusion section
bool getFusionEnabled() const;
bool getFusionLowDeviation() const;
bool getFusionRemoteGateway() const;
bool getFusionSelfOnly() const;
unsigned int getFusionTXHang() const;
unsigned int getFusionModeHang() const;
// The P25 section
bool getP25Enabled() const;
unsigned int getP25Id() const;
unsigned int getP25NAC() const;
bool getP25SelfOnly() const;
bool getP25OverrideUID() const;
bool getP25RemoteGateway() const;
unsigned int getP25TXHang() const;
unsigned int getP25ModeHang() const;
// The NXDN section
bool getNXDNEnabled() const;
unsigned int getNXDNId() const;
unsigned int getNXDNRAN() const;
bool getNXDNSelfOnly() const;
bool getNXDNRemoteGateway() const;
unsigned int getNXDNTXHang() const;
unsigned int getNXDNModeHang() const;
// The M17 section
bool getM17Enabled() const;
unsigned int getM17CAN() const;
bool getM17SelfOnly() const;
bool getM17AllowEncryption() const;
unsigned int getM17TXHang() const;
unsigned int getM17ModeHang() const;
// The POCSAG section
bool getPOCSAGEnabled() const;
unsigned int getPOCSAGFrequency() const;
// The AX.25 section
bool getAX25Enabled() const;
unsigned int getAX25TXDelay() const;
int getAX25RXTwist() const;
unsigned int getAX25SlotTime() const;
unsigned int getAX25PPersist() const;
bool getAX25Trace() const;
// The FM Section
bool getFMEnabled() const;
std::string getFMCallsign() const;
unsigned int getFMCallsignSpeed() const;
unsigned int getFMCallsignFrequency() const;
unsigned int getFMCallsignTime() const;
unsigned int getFMCallsignHoldoff() const;
float getFMCallsignHighLevel() const;
float getFMCallsignLowLevel() const;
bool getFMCallsignAtStart() const;
bool getFMCallsignAtEnd() const;
bool getFMCallsignAtLatch() const;
std::string getFMRFAck() const;
std::string getFMExtAck() const;
unsigned int getFMAckSpeed() const;
unsigned int getFMAckFrequency() const;
unsigned int getFMAckMinTime() const;
unsigned int getFMAckDelay() const;
float getFMAckLevel() const;
unsigned int getFMTimeout() const;
float getFMTimeoutLevel() const;
float getFMCTCSSFrequency() const;
unsigned int getFMCTCSSHighThreshold() const;
unsigned int getFMCTCSSLowThreshold() const;
float getFMCTCSSLevel() const;
unsigned int getFMKerchunkTime() const;
unsigned int getFMHangTime() const;
unsigned int getFMAccessMode() const;
bool getFMLinkMode() const;
bool getFMCOSInvert() const;
bool getFMNoiseSquelch() const;
unsigned int getFMSquelchHighThreshold() const;
unsigned int getFMSquelchLowThreshold() const;
unsigned int getFMRFAudioBoost() const;
float getFMMaxDevLevel() const;
unsigned int getFMExtAudioBoost() const;
unsigned int getFMModeHang() const;
// The D-Star Network section
bool getDStarNetworkEnabled() const;
std::string getDStarGatewayAddress() const;
unsigned short getDStarGatewayPort() const;
std::string getDStarLocalAddress() const;
unsigned short getDStarLocalPort() const;
unsigned int getDStarNetworkModeHang() const;
bool getDStarNetworkDebug() const;
// The DMR Network section
bool getDMRNetworkEnabled() const;
std::string getDMRNetworkType() const;
std::string getDMRNetworkRemoteAddress() const;
@ -143,7 +254,73 @@ public:
bool getDMRNetworkSlot2() const;
unsigned int getDMRNetworkModeHang() const;
// The TFTSERIAL section
// The System Fusion Network section
bool getFusionNetworkEnabled() const;
std::string getFusionNetworkLocalAddress() const;
unsigned short getFusionNetworkLocalPort() const;
std::string getFusionNetworkGatewayAddress() const;
unsigned short getFusionNetworkGatewayPort() const;
unsigned int getFusionNetworkModeHang() const;
bool getFusionNetworkDebug() const;
// The P25 Network section
bool getP25NetworkEnabled() const;
std::string getP25GatewayAddress() const;
unsigned short getP25GatewayPort() const;
std::string getP25LocalAddress() const;
unsigned short getP25LocalPort() const;
unsigned int getP25NetworkModeHang() const;
bool getP25NetworkDebug() const;
// The NXDN Network section
bool getNXDNNetworkEnabled() const;
std::string getNXDNNetworkProtocol() const;
std::string getNXDNGatewayAddress() const;
unsigned short getNXDNGatewayPort() const;
std::string getNXDNLocalAddress() const;
unsigned short getNXDNLocalPort() const;
unsigned int getNXDNNetworkModeHang() const;
bool getNXDNNetworkDebug() const;
// The M17 Network section
bool getM17NetworkEnabled() const;
std::string getM17GatewayAddress() const;
unsigned short getM17GatewayPort() const;
std::string getM17LocalAddress() const;
unsigned short getM17LocalPort() const;
unsigned int getM17NetworkModeHang() const;
bool getM17NetworkDebug() const;
// The POCSAG Network section
bool getPOCSAGNetworkEnabled() const;
std::string getPOCSAGGatewayAddress() const;
unsigned short getPOCSAGGatewayPort() const;
std::string getPOCSAGLocalAddress() const;
unsigned short getPOCSAGLocalPort() const;
unsigned int getPOCSAGNetworkModeHang() const;
bool getPOCSAGNetworkDebug() const;
// The FM Network section
bool getFMNetworkEnabled() const;
std::string getFMNetworkProtocol() const;
std::string getFMGatewayAddress() const;
unsigned short getFMGatewayPort() const;
std::string getFMLocalAddress() const;
unsigned short getFMLocalPort() const;
bool getFMPreEmphasis() const;
bool getFMDeEmphasis() const;
float getFMTXAudioGain() const;
float getFMRXAudioGain() const;
unsigned int getFMNetworkModeHang() const;
bool getFMNetworkDebug() const;
// The AX.25 Network section
bool getAX25NetworkEnabled() const;
std::string getAX25NetworkPort() const;
unsigned int getAX25NetworkSpeed() const;
bool getAX25NetworkDebug() const;
// The TFTSERIAL section
std::string getTFTSerialPort() const;
unsigned int getTFTSerialBrightness() const;
@ -249,7 +426,15 @@ private:
float m_modemRFLevel;
float m_modemRXLevel;
float m_modemCWIdTXLevel;
float m_modemDStarTXLevel;
float m_modemDMRTXLevel;
float m_modemYSFTXLevel;
float m_modemP25TXLevel;
float m_modemNXDNTXLevel;
float m_modemM17TXLevel;
float m_modemPOCSAGTXLevel;
float m_modemFMTXLevel;
float m_modemAX25TXLevel;
std::string m_modemRSSIMappingFile;
bool m_modemUseCOSAsLockout;
bool m_modemTrace;
@ -261,6 +446,18 @@ private:
unsigned short m_transparentLocalPort;
unsigned int m_transparentSendFrameType;
bool m_dstarEnabled;
std::string m_dstarModule;
bool m_dstarSelfOnly;
std::vector<std::string> m_dstarBlackList;
std::vector<std::string> m_dstarWhiteList;
bool m_dstarAckReply;
unsigned int m_dstarAckTime;
DSTAR_ACK_MESSAGE m_dstarAckMessage;
bool m_dstarErrorReply;
bool m_dstarRemoteGateway;
unsigned int m_dstarModeHang;
bool m_dmrEnabled;
DMR_BEACONS m_dmrBeacons;
unsigned int m_dmrBeaconInterval;
@ -280,6 +477,92 @@ private:
unsigned int m_dmrModeHang;
DMR_OVCM_TYPES m_dmrOVCM;
bool m_fusionEnabled;
bool m_fusionLowDeviation;
bool m_fusionRemoteGateway;
bool m_fusionSelfOnly;
unsigned int m_fusionTXHang;
unsigned int m_fusionModeHang;
bool m_p25Enabled;
unsigned int m_p25Id;
unsigned int m_p25NAC;
bool m_p25SelfOnly;
bool m_p25OverrideUID;
bool m_p25RemoteGateway;
unsigned int m_p25TXHang;
unsigned int m_p25ModeHang;
bool m_nxdnEnabled;
unsigned int m_nxdnId;
unsigned int m_nxdnRAN;
bool m_nxdnSelfOnly;
bool m_nxdnRemoteGateway;
unsigned int m_nxdnTXHang;
unsigned int m_nxdnModeHang;
bool m_m17Enabled;
unsigned int m_m17CAN;
bool m_m17SelfOnly;
bool m_m17AllowEncryption;
unsigned int m_m17TXHang;
unsigned int m_m17ModeHang;
bool m_pocsagEnabled;
unsigned int m_pocsagFrequency;
bool m_fmEnabled;
std::string m_fmCallsign;
unsigned int m_fmCallsignSpeed;
unsigned int m_fmCallsignFrequency;
unsigned int m_fmCallsignTime;
unsigned int m_fmCallsignHoldoff;
float m_fmCallsignHighLevel;
float m_fmCallsignLowLevel;
bool m_fmCallsignAtStart;
bool m_fmCallsignAtEnd;
bool m_fmCallsignAtLatch;
std::string m_fmRFAck;
std::string m_fmExtAck;
unsigned int m_fmAckSpeed;
unsigned int m_fmAckFrequency;
unsigned int m_fmAckMinTime;
unsigned int m_fmAckDelay;
float m_fmAckLevel;
unsigned int m_fmTimeout;
float m_fmTimeoutLevel;
float m_fmCTCSSFrequency;
unsigned int m_fmCTCSSHighThreshold;
unsigned int m_fmCTCSSLowThreshold;
float m_fmCTCSSLevel;
unsigned int m_fmKerchunkTime;
unsigned int m_fmHangTime;
unsigned int m_fmAccessMode;
bool m_fmLinkMode;
bool m_fmCOSInvert;
bool m_fmNoiseSquelch;
unsigned int m_fmSquelchHighThreshold;
unsigned int m_fmSquelchLowThreshold;
unsigned int m_fmRFAudioBoost;
float m_fmMaxDevLevel;
unsigned int m_fmExtAudioBoost;
unsigned int m_fmModeHang;
bool m_ax25Enabled;
unsigned int m_ax25TXDelay;
int m_ax25RXTwist;
unsigned int m_ax25SlotTime;
unsigned int m_ax25PPersist;
bool m_ax25Trace;
bool m_dstarNetworkEnabled;
std::string m_dstarGatewayAddress;
unsigned short m_dstarGatewayPort;
std::string m_dstarLocalAddress;
unsigned short m_dstarLocalPort;
unsigned int m_dstarNetworkModeHang;
bool m_dstarNetworkDebug;
bool m_dmrNetworkEnabled;
std::string m_dmrNetworkType;
std::string m_dmrNetworkRemoteAddress;
@ -294,7 +577,66 @@ private:
bool m_dmrNetworkSlot2;
unsigned int m_dmrNetworkModeHang;
std::string m_tftSerialPort;
bool m_fusionNetworkEnabled;
std::string m_fusionNetworkLocalAddress;
unsigned short m_fusionNetworkLocalPort;
std::string m_fusionNetworkGatewayAddress;
unsigned short m_fusionNetworkGatewayPort;
unsigned int m_fusionNetworkModeHang;
bool m_fusionNetworkDebug;
bool m_p25NetworkEnabled;
std::string m_p25GatewayAddress;
unsigned short m_p25GatewayPort;
std::string m_p25LocalAddress;
unsigned short m_p25LocalPort;
unsigned int m_p25NetworkModeHang;
bool m_p25NetworkDebug;
bool m_nxdnNetworkEnabled;
std::string m_nxdnNetworkProtocol;
std::string m_nxdnGatewayAddress;
unsigned short m_nxdnGatewayPort;
std::string m_nxdnLocalAddress;
unsigned short m_nxdnLocalPort;
unsigned int m_nxdnNetworkModeHang;
bool m_nxdnNetworkDebug;
bool m_m17NetworkEnabled;
std::string m_m17GatewayAddress;
unsigned short m_m17GatewayPort;
std::string m_m17LocalAddress;
unsigned short m_m17LocalPort;
unsigned int m_m17NetworkModeHang;
bool m_m17NetworkDebug;
bool m_pocsagNetworkEnabled;
std::string m_pocsagGatewayAddress;
unsigned short m_pocsagGatewayPort;
std::string m_pocsagLocalAddress;
unsigned short m_pocsagLocalPort;
unsigned int m_pocsagNetworkModeHang;
bool m_pocsagNetworkDebug;
bool m_fmNetworkEnabled;
std::string m_fmNetworkProtocol;
std::string m_fmGatewayAddress;
unsigned short m_fmGatewayPort;
std::string m_fmLocalAddress;
unsigned short m_fmLocalPort;
bool m_fmPreEmphasis;
bool m_fmDeEmphasis;
float m_fmTXAudioGain;
float m_fmRXAudioGain;
unsigned int m_fmNetworkModeHang;
bool m_fmNetworkDebug;
bool m_ax25NetworkEnabled;
std::string m_ax25NetworkPort;
unsigned int m_ax25NetworkSpeed;
bool m_ax25NetworkDebug;
std::string m_tftSerialPort;
unsigned int m_tftSerialBrightness;
unsigned int m_hd44780Rows;

View file

@ -61,7 +61,7 @@ bool CDMRAccessControl::validateSrcId(unsigned int id)
return false;
unsigned int prefix = id / 10000U;
if (prefix == 0U || prefix > 9999U)
if (prefix == 0U || prefix > 999U)
return false;
if (!m_prefixes.empty()) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020,2021,2022 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2019 by Patrick Maier DK5MP
*
* This program is free software; you can redistribute it and/or modify
@ -34,8 +34,7 @@ m_bsId(0U),
m_srcId(0U),
m_dstId(0U),
m_dataContent(false),
m_CBF(0U),
m_OVCM(false)
m_CBF(0U)
{
m_data = new unsigned char[12U];
}
@ -82,7 +81,6 @@ bool CDMRCSBK::put(const unsigned char* bytes)
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false;
m_CBF = 0U;
m_OVCM = (m_data[2U] & 0x04U) == 0x04U;
CUtils::dump(1U, "Unit to Unit Service Request CSBK", m_data, 12U);
break;
@ -92,7 +90,6 @@ bool CDMRCSBK::put(const unsigned char* bytes)
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false;
m_CBF = 0U;
m_OVCM = (m_data[2U] & 0x04U) == 0x04U;
CUtils::dump(1U, "Unit to Unit Service Answer Response CSBK", m_data, 12U);
break;
@ -132,21 +129,6 @@ bool CDMRCSBK::put(const unsigned char* bytes)
CUtils::dump(1U, "Call Alert Ack CSBK", m_data, 12U);
break;
case CSBKO_RADIO_CHECK:
m_GI = false;
if (m_data[3U] == 0x80) {
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
CUtils::dump(1U, "Radio Check Req CSBK", m_data, 12U);
} else {
m_srcId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_dstId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
CUtils::dump(1U, "Radio Check Ack CSBK", m_data, 12U);
}
m_dataContent = false;
m_CBF = 0U;
break;
default:
m_GI = false;
m_srcId = 0U;
@ -188,21 +170,31 @@ unsigned char CDMRCSBK::getFID() const
bool CDMRCSBK::getOVCM() const
{
return m_OVCM;
bool bOVCM = false;
// Service options informations are only available in
// "Unit to Unit Voice Service Request CSBK" and
// "Unit to Unit Voice Service Answer Response CSBK"
if ((m_CSBKO == CSBKO_UUVREQ) || (m_CSBKO == CSBKO_UUANSRSP))
bOVCM = (m_data[2U] & 0x04U) == 0x04U;
return bOVCM;
}
void CDMRCSBK::setOVCM(bool ovcm)
{
if (m_CSBKO == CSBKO_UUVREQ || m_CSBKO == CSBKO_UUANSRSP) {
m_OVCM = ovcm;
// Set OVCM only in CSBKs having the service options information
if ((m_CSBKO == CSBKO_UUVREQ) || (m_CSBKO == CSBKO_UUANSRSP)) {
if (ovcm)
m_data[2U] |= 0x04U;
else
m_data[2U] &= 0xFBU;
}
}
void CDMRCSBK::clearOVCM()
{
if (getOVCM())
m_data[2U] ^= 0x04U;
}
bool CDMRCSBK::getGI() const
{
return m_GI;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020,2021,2022 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,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
@ -28,7 +28,6 @@ enum CSBKO {
CSBKO_CTCSBK = 0x07,
CSBKO_CALL_ALERT = 0x1F,
CSBKO_CALL_ALERT_ACK = 0x20,
CSBKO_RADIO_CHECK = 0x24,
CSBKO_NACKRSP = 0x26,
CSBKO_BSDWNACT = 0x38,
CSBKO_PRECCSBK = 0x3D
@ -51,6 +50,7 @@ public:
// Set/Get the OVCM bit in the supported CSBKs
bool getOVCM() const;
void setOVCM(bool ovcm);
void clearOVCM();
// For BS Dwn Act
unsigned int getBSId() const;
@ -76,7 +76,6 @@ private:
unsigned int m_dstId;
bool m_dataContent;
unsigned char m_CBF;
bool m_OVCM;
};
#endif

View file

@ -38,13 +38,6 @@ m_lookup(lookup)
// Load black and white lists to DMRAccessControl
CDMRAccessControl::init(blacklist, whitelist, slot1TGWhitelist, slot2TGWhitelist, selfOnly, prefixes, id);
//Print whitelisted IDs
LogMessage("Allowed radio ids: ");
for (unsigned int i: whitelist) {
std::string id_name = std::to_string(i);
LogMessage(id_name.c_str());
}
CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi, jitter, ovcm);
}
@ -70,17 +63,15 @@ bool CDMRControl::processWakeup(const unsigned char* data)
return false;
unsigned int srcId = csbk.getSrcId();
std::string srcId_name = std::to_string(srcId);
LogMessage("Incoming uplink from radio id: %s", srcId_name.c_str());
std::string src = m_lookup->find(srcId);
bool ret = CDMRAccessControl::validateSrcId(srcId);
if (!ret) {
LogMessage("Blocked downlink activation from %s (%s)", src.c_str(), srcId_name.c_str());
LogMessage("Invalid Downlink Activate received from %s", src.c_str());
return false;
}
LogMessage("Downlink request received from %s (%s)", src.c_str(), srcId_name.c_str());
LogMessage("Downlink Activate received from %s", src.c_str());
return true;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2019,2021,2022 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2019,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
@ -193,8 +193,12 @@ void CDMRLC::setOVCM(bool ovcm)
{
if (ovcm)
m_options |= 0x04U;
else
m_options &= 0xFBU;
}
void CDMRLC::clearOVCM()
{
if (getOVCM())
m_options ^= 0x04U;
}
unsigned int CDMRLC::getSrcId() const

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2019,2021,2022 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2019,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
@ -41,6 +41,7 @@ public:
bool getOVCM() const;
void setOVCM(bool ovcm);
void clearOVCM();
unsigned char getFID() const;
void setFID(unsigned char fid);

View file

@ -92,7 +92,7 @@ void CDMRLookup::stop()
void CDMRLookup::findWithName(unsigned int id, class CUserDBentry *entry)
{
if (id == 0xFFFFFFFU) {
if (id == 0xFFFFFFU) {
entry->clear();
entry->set(keyCALLSIGN, "ALL");
return;
@ -115,7 +115,7 @@ std::string CDMRLookup::find(unsigned int id)
{
std::string callsign;
if (id == 0xFFFFFFFU)
if (id == 0xFFFFFFU)
return std::string("ALL");
class CUserDBentry entry;

View file

@ -235,13 +235,14 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
return false;
}
if (m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON)
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
lc->setOVCM(m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON);
m_rfLC = lc;
if (m_ovcm == DMR_OVCM_FORCE_OFF) {
lc->clearOVCM();
m_rfLC = lc;
}
// The standby LC data
m_rfEmbeddedLC.setLC(*m_rfLC);
m_rfEmbeddedData[0U].setLC(*m_rfLC);
@ -445,10 +446,10 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
return false;
// set the OVCM bit for the supported csbk
if (m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON)
csbk.setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
csbk.setOVCM(false);
csbk.setOVCM(m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON);
if (m_ovcm == DMR_OVCM_FORCE_OFF)
csbk.clearOVCM();
bool gi = csbk.getGI();
unsigned int srcId = csbk.getSrcId();
@ -507,9 +508,6 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
case CSBKO_CALL_ALERT_ACK:
LogMessage("DMR Slot %u, received RF Call Alert Ack CSBK from %s to %s%s", m_slotNo, src.c_str(), gi ? "TG " : "", dst.c_str());
break;
case CSBKO_RADIO_CHECK:
LogMessage("DMR Slot %u, received RF Radio Check %s CSBK from %s to %s%s", m_slotNo, /* TBD */ 1 ? "Req" : "Ack", src.c_str(), gi ? "TG " : "", dst.c_str());
break;
default:
LogWarning("DMR Slot %u, unhandled RF CSBK type - 0x%02X", m_slotNo, csbko);
break;
@ -812,13 +810,14 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
return false;
}
if (m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON)
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
lc->setOVCM(m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON);
m_rfLC = lc;
if (m_ovcm == DMR_OVCM_FORCE_OFF) {
lc->clearOVCM();
m_rfLC = lc;
}
// The standby LC data
m_rfEmbeddedLC.setLC(*m_rfLC);
m_rfEmbeddedData[0U].setLC(*m_rfLC);
@ -1072,13 +1071,14 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
dmrData.getSrcId(), dmrData.getFLCO() == FLCO_GROUP ? "TG" : "", dmrData.getDstId(),
srcId, flco == FLCO_GROUP ? "TG" : "", dstId);
if (m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON)
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
lc->setOVCM(m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON);
m_netLC = lc;
if (m_ovcm == DMR_OVCM_FORCE_OFF) {
lc->clearOVCM();
m_netLC = lc;
}
// The standby LC data
m_netEmbeddedLC.setLC(*m_netLC);
m_netEmbeddedData[0U].setLC(*m_netLC);
@ -1151,13 +1151,14 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
unsigned int dstId = lc->getDstId();
unsigned int srcId = lc->getSrcId();
if (m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON)
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
lc->setOVCM(m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON);
m_netLC = lc;
if (m_ovcm == DMR_OVCM_FORCE_OFF) {
lc->clearOVCM();
m_netLC = lc;
}
m_lastFrameValid = false;
m_netTimeoutTimer.start();
@ -1342,13 +1343,14 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
unsigned int dstId = lc->getDstId();
unsigned int srcId = lc->getSrcId();
if (m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON)
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
lc->setOVCM(m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON);
m_netLC = lc;
if (m_ovcm == DMR_OVCM_FORCE_OFF) {
lc->clearOVCM();
m_netLC = lc;
}
// The standby LC data
m_netEmbeddedLC.setLC(*m_netLC);
m_netEmbeddedData[0U].setLC(*m_netLC);
@ -1618,10 +1620,10 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
return;
// set the OVCM bit for the supported csbk
if (m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON)
csbk.setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
csbk.setOVCM(false);
csbk.setOVCM(m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON);
if (m_ovcm == DMR_OVCM_FORCE_OFF)
csbk.clearOVCM();
bool gi = csbk.getGI();
unsigned int srcId = csbk.getSrcId();
@ -1693,9 +1695,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
case CSBKO_CALL_ALERT_ACK:
LogMessage("DMR Slot %u, received network Call Alert Ack CSBK from %s to %s%s", m_slotNo, src.c_str(), gi ? "TG " : "", dst.c_str());
break;
case CSBKO_RADIO_CHECK:
LogMessage("DMR Slot %u, received network Radio Check %s CSBK from %s to %s%s", m_slotNo, /* TBD */ 1 ? "Req" : "Ack", src.c_str(), gi ? "TG " : "", dst.c_str());
break;
default:
LogWarning("DMR Slot %u, unhandled network CSBK type - 0x%02X", m_slotNo, csbko);
break;

View file

@ -0,0 +1,32 @@
# DMRplus - Startup Options
## Introduction
This file is to give an overview over the Options-parameter in MMDVM.ini [DMR Network]-section.
## Example
You can pull some conection-info at startup to the DMRplus-Network to define the behavior of TS1 and TS2 in DMR-mode.
An example of such a line would be following:
Options=StartRef=4013;RelinkTime=15;UserLink=1;TS1_1=262;TS1_2=1;TS1_3=20;TS1_4=110;TS1_5=270;
If an option is set, it overwrites the setting preset at the master, if an option is empty, it unsets a predefined setting from
the master. If an option is not set, the default from the master would be taken over.
## What the parameters are about?
Here is a quick explaination about the options to be set:
* StartRef: This is the default reflector in TS2, in example: Refl. 4013
* RelinkTime: This is the time to fall back to the default-reflector if linked to another one and no local traffic is done,
not yet implemented, would come next
* UserLink: This defines, if users are allowed to link to another reflector (other than defined as startreflector)
* 1 = allow
* 0 = disallow
* TS1_1: This is the first of 5 talkgroups that could be set static, in example: TG262
* TS1_2: This is the second of 5 talkgroups that could be set static, in example: TG1
* TS1_3: This is the third of 5 talkgroups that could be set static, in example: TG20
* TS1_4: This is the fourth of 5 talkgroups that could be set static, in example: TG110
* TS1_5: This is the fifth of 5 talkgroups that could be set static, in example: TG270
---
Info created by DG9VH 2016-11-11

1315
DStarControl.cpp Normal file

File diff suppressed because it is too large Load diff

150
DStarControl.h Normal file
View file

@ -0,0 +1,150 @@
/*
* Copyright (C) 2015-2019 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(DStarControl_H)
#define DStarControl_H
#include "RSSIInterpolator.h"
#include "DStarNetwork.h"
#include "DStarSlowData.h"
#include "DStarDefines.h"
#include "DStarHeader.h"
#include "RingBuffer.h"
#include "StopWatch.h"
#include "AMBEFEC.h"
#include "Display.h"
#include "Defines.h"
#include "Timer.h"
#include "Modem.h"
#include <string>
#include <vector>
class CDStarControl {
public:
CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool ackReply, unsigned int ackTime, DSTAR_ACK_MESSAGE ackMessage, bool errorReply, const std::vector<std::string>& blackList, const std::vector<std::string>& whiteList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper);
~CDStarControl();
bool writeModem(unsigned char* data, unsigned int len);
unsigned int readModem(unsigned char* data);
void clock();
bool isBusy() const;
void enable(bool enabled);
private:
unsigned char* m_callsign;
unsigned char* m_gateway;
bool m_selfOnly;
bool m_ackReply;
DSTAR_ACK_MESSAGE m_ackMessage;
bool m_errorReply;
bool m_remoteGateway;
std::vector<std::string> m_blackList;
std::vector<std::string> m_whiteList;
CDStarNetwork* m_network;
CDisplay* m_display;
bool m_duplex;
CRingBuffer<unsigned char> m_queue;
CDStarHeader m_rfHeader;
CDStarHeader m_netHeader;
RPT_RF_STATE m_rfState;
RPT_NET_STATE m_netState;
bool m_net;
CDStarSlowData m_slowData;
unsigned char m_rfN;
unsigned char m_netN;
CTimer m_networkWatchdog;
CTimer m_rfTimeoutTimer;
CTimer m_netTimeoutTimer;
CTimer m_packetTimer;
CTimer m_ackTimer;
CTimer m_errTimer;
CStopWatch m_interval;
CStopWatch m_elapsed;
unsigned int m_rfFrames;
unsigned int m_netFrames;
unsigned int m_netLost;
CAMBEFEC m_fec;
unsigned int m_rfBits;
unsigned int m_netBits;
unsigned int m_rfErrs;
unsigned int m_netErrs;
unsigned char* m_lastFrame;
bool m_lastFrameValid;
CRSSIInterpolator* m_rssiMapper;
unsigned char m_rssi;
unsigned char m_maxRSSI;
unsigned char m_minRSSI;
unsigned int m_aveRSSI;
unsigned int m_rssiCount;
bool m_enabled;
FILE* m_fp;
unsigned char* m_rfVoiceSyncData;
unsigned int m_rfVoiceSyncDataLen;
unsigned char* m_netVoiceSyncData;
unsigned int m_netVoiceSyncDataLen;
bool m_rfNextFrameIsFastData;
bool m_netNextFrameIsFastData;
unsigned int m_rfSkipDTMFBlankingFrames;
unsigned int m_netSkipDTMFBlankingFrames;
unsigned int maybeFixupVoiceFrame(
unsigned char* data,
unsigned int len,
unsigned int offset,
const char* log_prefix,
unsigned char n,
bool blank_dtmf,
unsigned char* voice_sync_data,
unsigned int& voice_sync_data_len,
bool& next_frame_is_fast_data,
unsigned int& skip_dtmf_blanking_frames
);
void writeNetwork();
void writeQueueHeaderRF(const unsigned char* data);
void writeQueueDataRF(const unsigned char* data);
void writeQueueEOTRF();
void writeQueueHeaderNet(const unsigned char* data);
void writeQueueDataNet(const unsigned char* data);
void writeQueueEOTNet();
void writeNetworkHeaderRF(const unsigned char* data);
void writeNetworkDataRF(const unsigned char* data, unsigned int errors, bool end);
void writeEndRF();
void writeEndNet();
bool openFile();
bool writeFile(const unsigned char* data, unsigned int length);
void closeFile();
bool insertSilence(const unsigned char* data, unsigned char seqNo);
void insertSilence(unsigned int count);
void blankDTMF(unsigned char* data) const;
void sendAck();
void sendError();
};
#endif

95
DStarDefines.h Normal file
View file

@ -0,0 +1,95 @@
/*
* Copyright (C) 2015,2016,2018,2019,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(DStarDefines_H)
#define DStarDefines_H
#include "Defines.h"
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
const unsigned int DSTAR_FRAME_LENGTH_BYTES = 12U;
const unsigned char DSTAR_END_PATTERN_BYTES[] = { TAG_EOT, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A };
const unsigned int DSTAR_END_PATTERN_LENGTH_BYTES = 6U;
const unsigned char DSTAR_NULL_AMBE_DATA_BYTES[] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8 };
// DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED is DSTAR_NULL_AMBE_DATA_BYTES XORed with DSTAR_SCRAMBLER_BYTES.
const unsigned char DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED[] = { 0xEEU, 0xC2U, 0xA1U, 0xC8U, 0x42U, 0x6EU, 0x52U, 0x51U, 0xC3U };
const unsigned char DSTAR_NULL_SLOW_SYNC_BYTES[] = { 0x55, 0x2D, 0x16 };
// Note that these are already scrambled, 0x66 0x66 0x66 otherwise
const unsigned char DSTAR_NULL_SLOW_DATA_BYTES[] = { 0x16, 0x29, 0xF5 };
const unsigned char DSTAR_NULL_FRAME_SYNC_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16 };
const unsigned char DSTAR_NULL_FRAME_DATA_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x16, 0x29, 0xF5 };
const unsigned int DSTAR_VOICE_FRAME_LENGTH_BYTES = 9U;
const unsigned int DSTAR_DATA_FRAME_LENGTH_BYTES = 3U;
const unsigned int DSTAR_LONG_CALLSIGN_LENGTH = 8U;
const unsigned int DSTAR_SHORT_CALLSIGN_LENGTH = 4U;
const unsigned char DSTAR_SLOW_DATA_TYPE_MASK = 0xF0U;
const unsigned char DSTAR_SLOW_DATA_TYPE_GPSDATA = 0x30U;
const unsigned char DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
const unsigned char DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA01 = 0x80U;
const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA16 = 0x90U;
const unsigned char DSTAR_SLOW_DATA_TYPE_SQUELCH = 0xC0U;
const unsigned char DSTAR_SLOW_DATA_LENGTH_MASK = 0x0FU;
// Data Frames are always scrambled using the first three bytes of
// DSTAR_SCRAMBLER_BYTES, and Voice Frames are scrambled with all nine
// bytes when Fast Data is in use
const unsigned char DSTAR_SCRAMBLER_BYTES[] = { 0x70U, 0x4FU, 0x93U, 0x40U, 0x64U, 0x74U, 0x6DU, 0x30U, 0x2BU };
const unsigned char DSTAR_DATA_MASK = 0x80U;
const unsigned char DSTAR_REPEATER_MASK = 0x40U;
const unsigned char DSTAR_INTERRUPTED_MASK = 0x20U;
const unsigned char DSTAR_CONTROL_SIGNAL_MASK = 0x10U;
const unsigned char DSTAR_URGENT_MASK = 0x08U;
const unsigned char DSTAR_REPEATER_CONTROL = 0x07U;
const unsigned char DSTAR_AUTO_REPLY = 0x06U;
const unsigned char DSTAR_RESEND_REQUESTED = 0x04U;
const unsigned char DSTAR_ACK_FLAG = 0x03U;
const unsigned char DSTAR_NO_RESPONSE = 0x02U;
const unsigned char DSTAR_RELAY_UNAVAILABLE = 0x01U;
const unsigned char DSTAR_SYNC_BYTES[] = {0x55U, 0x2DU, 0x16U};
const unsigned char DSTAR_DTMF_MASK[] = { 0x82U, 0x08U, 0x20U, 0x82U, 0x00U, 0x00U, 0x82U, 0x00U, 0x00U };
const unsigned char DSTAR_DTMF_SIG[] = { 0x82U, 0x08U, 0x20U, 0x82U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U };
const unsigned int DSTAR_FRAME_TIME = 20U;
enum LINK_STATUS {
LS_NONE,
LS_PENDING_IRCDDB,
LS_LINKING_LOOPBACK,
LS_LINKING_DEXTRA,
LS_LINKING_DPLUS,
LS_LINKING_DCS,
LS_LINKING_CCS,
LS_LINKED_LOOPBACK,
LS_LINKED_DEXTRA,
LS_LINKED_DPLUS,
LS_LINKED_DCS,
LS_LINKED_CCS
};
#endif

165
DStarHeader.cpp Normal file
View file

@ -0,0 +1,165 @@
/*
* Copyright (C) 2016 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 "DStarDefines.h"
#include "DStarHeader.h"
#include "CRC.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CDStarHeader::CDStarHeader(const unsigned char* header) :
m_header(NULL)
{
assert(header != NULL);
m_header = new unsigned char[DSTAR_HEADER_LENGTH_BYTES];
::memcpy(m_header, header, DSTAR_HEADER_LENGTH_BYTES);
}
CDStarHeader::CDStarHeader() :
m_header(NULL)
{
m_header = new unsigned char[DSTAR_HEADER_LENGTH_BYTES];
::memset(m_header, ' ', DSTAR_HEADER_LENGTH_BYTES);
m_header[0U] = 0x00U;
m_header[1U] = 0x00U;
m_header[2U] = 0x00U;
}
CDStarHeader::~CDStarHeader()
{
delete[] m_header;
}
CDStarHeader& CDStarHeader::operator=(const CDStarHeader& header)
{
if (&header != this)
::memcpy(m_header, header.m_header, DSTAR_HEADER_LENGTH_BYTES);
return *this;
}
bool CDStarHeader::isRepeater() const
{
return (m_header[0U] & DSTAR_REPEATER_MASK) == DSTAR_REPEATER_MASK;
}
void CDStarHeader::setRepeater(bool on)
{
if (on)
m_header[0U] |= DSTAR_REPEATER_MASK;
else
m_header[0U] &= ~DSTAR_REPEATER_MASK;
}
bool CDStarHeader::isDataPacket() const
{
return (m_header[0U] & DSTAR_DATA_MASK) == DSTAR_DATA_MASK;
}
void CDStarHeader::setUnavailable(bool on)
{
if (on)
m_header[0U] |= DSTAR_RELAY_UNAVAILABLE;
else
m_header[0U] &= ~DSTAR_RELAY_UNAVAILABLE;
}
void CDStarHeader::getMyCall1(unsigned char* call1) const
{
assert(call1 != NULL);
::memcpy(call1, m_header + 27U, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::getMyCall2(unsigned char* call2) const
{
assert(call2 != NULL);
::memcpy(call2, m_header + 35U, DSTAR_SHORT_CALLSIGN_LENGTH);
}
void CDStarHeader::setMyCall1(const unsigned char* call1)
{
assert(call1 != NULL);
::memcpy(m_header + 27U, call1, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::setMyCall2(const unsigned char* call2)
{
assert(call2 != NULL);
::memcpy(m_header + 35U, call2, DSTAR_SHORT_CALLSIGN_LENGTH);
}
void CDStarHeader::getRPTCall1(unsigned char* call1) const
{
assert(call1 != NULL);
::memcpy(call1, m_header + 11U, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::getRPTCall2(unsigned char* call2) const
{
assert(call2 != NULL);
::memcpy(call2, m_header + 3U, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::setRPTCall1(const unsigned char* call1)
{
assert(call1 != NULL);
::memcpy(m_header + 11U, call1, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::setRPTCall2(const unsigned char* call2)
{
assert(call2 != NULL);
::memcpy(m_header + 3U, call2, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::getYourCall(unsigned char* call) const
{
assert(call != NULL);
::memcpy(call, m_header + 19U, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::setYourCall(const unsigned char* call)
{
assert(call != NULL);
::memcpy(m_header + 19U, call, DSTAR_LONG_CALLSIGN_LENGTH);
}
void CDStarHeader::get(unsigned char* header) const
{
assert(header != NULL);
::memcpy(header, m_header, DSTAR_HEADER_LENGTH_BYTES);
CCRC::addCCITT161(header, DSTAR_HEADER_LENGTH_BYTES);
}

58
DStarHeader.h Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2016 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 DStarHeader_H
#define DStarHeader_H
class CDStarHeader {
public:
CDStarHeader(const unsigned char* header);
CDStarHeader();
~CDStarHeader();
bool isRepeater() const;
void setRepeater(bool on);
bool isDataPacket() const;
void setUnavailable(bool on);
void getMyCall1(unsigned char* call1) const;
void getMyCall2(unsigned char* call2) const;
void setMyCall1(const unsigned char* call1);
void setMyCall2(const unsigned char* call2);
void getRPTCall1(unsigned char* call1) const;
void getRPTCall2(unsigned char* call2) const;
void setRPTCall1(const unsigned char* call1);
void setRPTCall2(const unsigned char* call2);
void getYourCall(unsigned char* call) const;
void setYourCall(const unsigned char* call);
void get(unsigned char* header) const;
CDStarHeader& operator=(const CDStarHeader& header);
private:
unsigned char* m_header;
};
#endif

346
DStarNetwork.cpp Normal file
View file

@ -0,0 +1,346 @@
/*
* Copyright (C) 2009-2014,2016,2019,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 "DStarDefines.h"
#include "DStarNetwork.h"
#include "StopWatch.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>
const unsigned int BUFFER_LENGTH = 100U;
CDStarNetwork::CDStarNetwork(const std::string& gatewayAddress, unsigned short gatewayPort, const std::string& localAddress, unsigned short localPort, bool duplex, const char* version, bool debug) :
m_socket(localAddress, localPort),
m_addr(),
m_addrLen(0U),
m_duplex(duplex),
m_version(version),
m_debug(debug),
m_enabled(false),
m_outId(0U),
m_outSeq(0U),
m_inId(0U),
m_buffer(1000U, "D-Star Network"),
m_pollTimer(1000U, 60U),
m_linkStatus(LS_NONE),
m_linkReflector(NULL),
m_random()
{
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0)
m_addrLen = 0U;
m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
std::random_device rd;
std::mt19937 mt(rd());
m_random = mt;
}
CDStarNetwork::~CDStarNetwork()
{
delete[] m_linkReflector;
}
bool CDStarNetwork::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of the ircDDB Gateway");
return false;
}
LogMessage("Opening D-Star network connection");
m_pollTimer.start();
return m_socket.open(m_addr);
}
bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length, bool busy)
{
assert(header != NULL);
unsigned char buffer[50U];
buffer[0] = 'D';
buffer[1] = 'S';
buffer[2] = 'R';
buffer[3] = 'P';
buffer[4] = busy ? 0x22U : 0x20U;
// Create a random id for this transmission
std::uniform_int_distribution<uint16_t> dist(0x0001, 0xfffe);
m_outId = dist(m_random);
buffer[5] = m_outId / 256U; // Unique session id
buffer[6] = m_outId % 256U;
buffer[7] = 0U;
::memcpy(buffer + 8U, header, length);
m_outSeq = 0U;
if (m_debug)
CUtils::dump(1U, "D-Star Network Header Sent", buffer, 49U);
for (unsigned int i = 0U; i < 2U; i++) {
bool ret = m_socket.write(buffer, 49U, m_addr, m_addrLen);
if (!ret)
return false;
}
return true;
}
bool CDStarNetwork::writeData(const unsigned char* data, unsigned int length, unsigned int errors, bool end, bool busy)
{
assert(data != NULL);
unsigned char buffer[30U];
buffer[0] = 'D';
buffer[1] = 'S';
buffer[2] = 'R';
buffer[3] = 'P';
buffer[4] = busy ? 0x23U : 0x21U;
buffer[5] = m_outId / 256U; // Unique session id
buffer[6] = m_outId % 256U;
// If this is a data sync, reset the sequence to zero
if (data[9] == 0x55 && data[10] == 0x2D && data[11] == 0x16)
m_outSeq = 0U;
buffer[7] = m_outSeq;
if (end)
buffer[7] |= 0x40U; // End of data marker
buffer[8] = errors;
m_outSeq++;
if (m_outSeq > 0x14U)
m_outSeq = 0U;
::memcpy(buffer + 9U, data, length);
if (m_debug)
CUtils::dump(1U, "D-Star Network Data Sent", buffer, length + 9U);
return m_socket.write(buffer, length + 9U, m_addr, m_addrLen);
}
bool CDStarNetwork::writePoll(const char* text)
{
assert(text != NULL);
unsigned char buffer[40U];
buffer[0] = 'D';
buffer[1] = 'S';
buffer[2] = 'R';
buffer[3] = 'P';
buffer[4] = 0x0A; // Poll with text
unsigned int length = ::strlen(text);
// Include the nul at the end also
::memcpy(buffer + 5U, text, length + 1U);
// if (m_debug)
// CUtils::dump(1U, "D-Star Network Poll Sent", buffer, 6U + length);
return m_socket.write(buffer, 6U + length, m_addr, m_addrLen);
}
void CDStarNetwork::clock(unsigned int ms)
{
m_pollTimer.clock(ms);
if (m_pollTimer.hasExpired()) {
char text[60U];
#if defined(_WIN32) || defined(_WIN64)
if (m_duplex)
::sprintf(text, "win_mmdvm-%s", m_version);
else
::sprintf(text, "win_mmdvm-dvmega-%s", m_version);
#else
if (m_duplex)
::sprintf(text, "linux_mmdvm-%s", m_version);
else
::sprintf(text, "linux_mmdvm-dvmega-%s", m_version);
#endif
writePoll(text);
m_pollTimer.start();
}
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage address;
unsigned int addrLen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrLen);
if (length <= 0)
return;
if (!CUDPSocket::match(m_addr, address)) {
LogMessage("D-Star, packet received from an invalid source");
return;
}
// Invalid packet type?
if (::memcmp(buffer, "DSRP", 4U) != 0)
return;
switch (buffer[4]) {
case 0x00U: // NETWORK_TEXT;
if (m_debug)
CUtils::dump(1U, "D-Star Network Status Received", buffer, length);
m_linkStatus = LINK_STATUS(buffer[25U]);
::memcpy(m_linkReflector, buffer + 26U, DSTAR_LONG_CALLSIGN_LENGTH);
LogMessage("D-Star link status set to \"%20.20s\"", buffer + 5U);
return;
case 0x01U: // NETWORK_TEMPTEXT;
case 0x04U: // NETWORK_STATUS1..5
case 0x24U: // NETWORK_DD_DATA
return;
case 0x20U: // NETWORK_HEADER
if (m_inId == 0U && m_enabled) {
if (m_debug)
CUtils::dump(1U, "D-Star Network Header Received", buffer, length);
m_inId = buffer[5] * 256U + buffer[6];
unsigned char c = length - 7U;
m_buffer.addData(&c, 1U);
c = TAG_HEADER;
m_buffer.addData(&c, 1U);
m_buffer.addData(buffer + 8U, length - 8U);
}
break;
case 0x21U: // NETWORK_DATA
if (m_enabled) {
if (m_debug)
CUtils::dump(1U, "D-Star Network Data Received", buffer, length);
uint16_t id = buffer[5] * 256U + buffer[6];
// Check that the stream id matches the valid header, reject otherwise
if (id == m_inId && m_enabled) {
unsigned char ctrl[3U];
ctrl[0U] = length - 7U;
// Is this the last packet in the stream?
if ((buffer[7] & 0x40) == 0x40) {
m_inId = 0U;
ctrl[1U] = TAG_EOT;
} else {
ctrl[1U] = TAG_DATA;
}
ctrl[2U] = buffer[7] & 0x3FU;
m_buffer.addData(ctrl, 3U);
m_buffer.addData(buffer + 9U, length - 9U);
}
}
break;
default:
CUtils::dump("Unknown D-Star packet from the Gateway", buffer, length);
break;
}
}
unsigned int CDStarNetwork::read(unsigned char* data, unsigned int length)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return 0U;
unsigned char c = 0U;
m_buffer.getData(&c, 1U);
assert(c <= 100U);
assert(c <= length);
unsigned char buffer[100U];
m_buffer.getData(buffer, c);
switch (buffer[0U]) {
case TAG_HEADER:
case TAG_DATA:
case TAG_EOT:
::memcpy(data, buffer, c);
return c;
default:
return 0U;
}
}
void CDStarNetwork::reset()
{
m_inId = 0U;
}
bool CDStarNetwork::isConnected() const
{
return (m_addrLen != 0);
}
void CDStarNetwork::close()
{
m_socket.close();
LogMessage("Closing D-Star network connection");
}
void CDStarNetwork::enable(bool enabled)
{
if (enabled && !m_enabled)
reset();
else if (!enabled && m_enabled)
m_buffer.clear();
m_enabled = enabled;
}
void CDStarNetwork::getStatus(LINK_STATUS& status, unsigned char* reflector)
{
assert(reflector != NULL);
status = m_linkStatus;
::memcpy(reflector, m_linkReflector, DSTAR_LONG_CALLSIGN_LENGTH);
}

75
DStarNetwork.h Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2009-2014,2016,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.
*/
#ifndef DStarNetwork_H
#define DStarNetwork_H
#include "DStarDefines.h"
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
#include <random>
class CDStarNetwork {
public:
CDStarNetwork(const std::string& gatewayAddress, unsigned short gatewayPort, const std::string& localAddress, unsigned short localPort, bool duplex, const char* version, bool debug);
~CDStarNetwork();
bool open();
void enable(bool enabled);
bool writeHeader(const unsigned char* header, unsigned int length, bool busy);
bool writeData(const unsigned char* data, unsigned int length, unsigned int errors, bool end, bool busy);
void getStatus(LINK_STATUS& status, unsigned char* reflector);
unsigned int read(unsigned char* data, unsigned int length);
void reset();
bool isConnected() const;
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
sockaddr_storage m_addr;
unsigned int m_addrLen;
bool m_duplex;
const char* m_version;
bool m_debug;
bool m_enabled;
uint16_t m_outId;
uint8_t m_outSeq;
uint16_t m_inId;
CRingBuffer<unsigned char> m_buffer;
CTimer m_pollTimer;
LINK_STATUS m_linkStatus;
unsigned char* m_linkReflector;
std::mt19937 m_random;
bool writePoll(const char* text);
};
#endif

158
DStarSlowData.cpp Normal file
View file

@ -0,0 +1,158 @@
/*
* Copyright (C) 2016 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 "DStarSlowData.h"
#include "DStarDefines.h"
#include "CRC.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CDStarSlowData::CDStarSlowData() :
m_header(NULL),
m_ptr(0U),
m_buffer(NULL),
m_text(NULL),
m_textPtr(0U),
m_state(SDD_FIRST)
{
m_header = new unsigned char[50U]; // DSTAR_HEADER_LENGTH_BYTES
m_buffer = new unsigned char[DSTAR_DATA_FRAME_LENGTH_BYTES * 2U];
m_text = new unsigned char[24U];
}
CDStarSlowData::~CDStarSlowData()
{
delete[] m_header;
delete[] m_buffer;
delete[] m_text;
}
CDStarHeader* CDStarSlowData::add(const unsigned char* data)
{
assert(data != NULL);
switch (m_state) {
case SDD_FIRST:
m_buffer[0U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U];
m_buffer[1U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U];
m_buffer[2U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U];
m_state = SDD_SECOND;
return NULL;
case SDD_SECOND:
m_buffer[3U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U];
m_buffer[4U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U];
m_buffer[5U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U];
m_state = SDD_FIRST;
break;
}
if ((m_buffer[0U] & DSTAR_SLOW_DATA_TYPE_MASK) != DSTAR_SLOW_DATA_TYPE_HEADER)
return NULL;
if (m_ptr >= 45U)
return NULL;
::memcpy(m_header + m_ptr, m_buffer + 1U, 5U);
m_ptr += 5U;
// Clean up the data
m_header[0U] &= (DSTAR_INTERRUPTED_MASK | DSTAR_URGENT_MASK | DSTAR_REPEATER_MASK);
m_header[1U] = 0x00U;
m_header[2U] = 0x00U;
for (unsigned int i = 3U; i < 39U; i++)
m_header[i] &= 0x7FU;
// Check the CRC
bool ret = CCRC::checkCCITT161(m_header, DSTAR_HEADER_LENGTH_BYTES);
if (!ret) {
if (m_ptr == 45U)
LogMessage("D-Star, invalid slow data header");
return NULL;
}
return new CDStarHeader(m_header);
}
void CDStarSlowData::start()
{
::memset(m_header, 0x00U, DSTAR_HEADER_LENGTH_BYTES);
m_ptr = 0U;
m_state = SDD_FIRST;
}
void CDStarSlowData::reset()
{
m_ptr = 0U;
m_state = SDD_FIRST;
}
void CDStarSlowData::setText(const char* text)
{
assert(text != NULL);
m_text[0U] = DSTAR_SLOW_DATA_TYPE_TEXT | 0U;
m_text[1U] = text[0U];
m_text[2U] = text[1U];
m_text[3U] = text[2U];
m_text[4U] = text[3U];
m_text[5U] = text[4U];
m_text[6U] = DSTAR_SLOW_DATA_TYPE_TEXT | 1U;
m_text[7U] = text[5U];
m_text[8U] = text[6U];
m_text[9U] = text[7U];
m_text[10U] = text[8U];
m_text[11U] = text[9U];
m_text[12U] = DSTAR_SLOW_DATA_TYPE_TEXT | 2U;
m_text[13U] = text[10U];
m_text[14U] = text[11U];
m_text[15U] = text[12U];
m_text[16U] = text[13U];
m_text[17U] = text[14U];
m_text[18U] = DSTAR_SLOW_DATA_TYPE_TEXT | 3U;
m_text[19U] = text[15U];
m_text[20U] = text[16U];
m_text[21U] = text[17U];
m_text[22U] = text[18U];
m_text[23U] = text[19U];
m_textPtr = 0U;
}
void CDStarSlowData::get(unsigned char* data)
{
assert(data != NULL);
if (m_textPtr < 24U) {
data[0U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[0U];
data[1U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[1U];
data[2U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[2U];
} else {
data[0U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[0U];
data[1U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[1U];
data[2U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[2U];
}
}

52
DStarSlowData.h Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2016 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 DStarSlowData_H
#define DStarSlowData_H
#include "DStarHeader.h"
class CDStarSlowData {
public:
CDStarSlowData();
~CDStarSlowData();
CDStarHeader* add(const unsigned char* data);
void start();
void reset();
void setText(const char* text);
void get(unsigned char* data);
private:
unsigned char* m_header;
unsigned int m_ptr;
unsigned char* m_buffer;
unsigned char* m_text;
unsigned int m_textPtr;
enum SDD_STATE {
SDD_FIRST,
SDD_SECOND
};
SDD_STATE m_state;
};
#endif

View file

@ -20,7 +20,15 @@
#define Defines_H
const unsigned char MODE_IDLE = 0U;
const unsigned char MODE_DSTAR = 1U;
const unsigned char MODE_DMR = 2U;
const unsigned char MODE_YSF = 3U;
const unsigned char MODE_P25 = 4U;
const unsigned char MODE_NXDN = 5U;
const unsigned char MODE_POCSAG = 6U;
const unsigned char MODE_M17 = 7U;
const unsigned char MODE_FM = 10U;
const unsigned char MODE_CW = 98U;
const unsigned char MODE_LOCKOUT = 99U;
@ -80,4 +88,10 @@ enum DMR_OVCM_TYPES {
DMR_OVCM_FORCE_OFF
};
enum DSTAR_ACK_MESSAGE {
DSTAR_ACK_BER,
DSTAR_ACK_RSSI,
DSTAR_ACK_SMETER
};
#endif

View file

@ -99,6 +99,53 @@ void CDisplay::setQuit()
setQuitInt();
}
void CDisplay::setFM()
{
m_timer1.stop();
m_timer2.stop();
m_mode1 = MODE_FM;
m_mode2 = MODE_FM;
setFMInt();
}
void CDisplay::writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{
assert(my1 != NULL);
assert(my2 != NULL);
assert(your != NULL);
assert(type != NULL);
assert(reflector != NULL);
m_timer1.start();
m_mode1 = MODE_IDLE;
writeDStarInt(my1, my2, your, type, reflector);
}
void CDisplay::writeDStarRSSI(unsigned char rssi)
{
if (rssi != 0U)
writeDStarRSSIInt(rssi);
}
void CDisplay::writeDStarBER(float ber)
{
writeDStarBERInt(ber);
}
void CDisplay::clearDStar()
{
if (m_timer1.hasExpired()) {
clearDStarInt();
m_timer1.stop();
m_mode1 = MODE_IDLE;
} else {
m_mode1 = MODE_DSTAR;
}
}
void CDisplay::writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
{
assert(type != NULL);
@ -174,6 +221,171 @@ void CDisplay::clearDMR(unsigned int slotNo)
}
}
void CDisplay::writeFusion(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin)
{
assert(source != NULL);
assert(dest != NULL);
assert(type != NULL);
assert(origin != NULL);
m_timer1.start();
m_mode1 = MODE_IDLE;
writeFusionInt(source, dest, dgid, type, origin);
}
void CDisplay::writeFusionRSSI(unsigned char rssi)
{
if (rssi != 0U)
writeFusionRSSIInt(rssi);
}
void CDisplay::writeFusionBER(float ber)
{
writeFusionBERInt(ber);
}
void CDisplay::clearFusion()
{
if (m_timer1.hasExpired()) {
clearFusionInt();
m_timer1.stop();
m_mode1 = MODE_IDLE;
} else {
m_mode1 = MODE_YSF;
}
}
void CDisplay::writeP25(const char* source, bool group, unsigned int dest, const char* type)
{
assert(source != NULL);
assert(type != NULL);
m_timer1.start();
m_mode1 = MODE_IDLE;
writeP25Int(source, group, dest, type);
}
void CDisplay::writeP25RSSI(unsigned char rssi)
{
if (rssi != 0U)
writeP25RSSIInt(rssi);
}
void CDisplay::writeP25BER(float ber)
{
writeP25BERInt(ber);
}
void CDisplay::clearP25()
{
if (m_timer1.hasExpired()) {
clearP25Int();
m_timer1.stop();
m_mode1 = MODE_IDLE;
} else {
m_mode1 = MODE_P25;
}
}
void CDisplay::writeNXDN(const char* source, bool group, unsigned int dest, const char* type)
{
assert(source != NULL);
assert(type != NULL);
m_timer1.start();
m_mode1 = MODE_IDLE;
writeNXDNInt(source, group, dest, type);
}
void CDisplay::writeNXDN(const class CUserDBentry& source, bool group, unsigned int dest, const char* type)
{
assert(type != NULL);
m_timer1.start();
m_mode1 = MODE_IDLE;
if (writeNXDNIntEx(source, group, dest, type))
writeNXDNInt(source.get(keyCALLSIGN).c_str(), group, dest, type);
}
void CDisplay::writeNXDNRSSI(unsigned char rssi)
{
if (rssi != 0U)
writeNXDNRSSIInt(rssi);
}
void CDisplay::writeNXDNBER(float ber)
{
writeNXDNBERInt(ber);
}
void CDisplay::clearNXDN()
{
if (m_timer1.hasExpired()) {
clearNXDNInt();
m_timer1.stop();
m_mode1 = MODE_IDLE;
} else {
m_mode1 = MODE_NXDN;
}
}
void CDisplay::writeM17(const char* source, const char* dest, const char* type)
{
assert(source != NULL);
assert(dest != NULL);
assert(type != NULL);
m_timer1.start();
m_mode1 = MODE_IDLE;
writeM17Int(source, dest, type);
}
void CDisplay::writeM17RSSI(unsigned char rssi)
{
if (rssi != 0U)
writeM17RSSIInt(rssi);
}
void CDisplay::writeM17BER(float ber)
{
writeM17BERInt(ber);
}
void CDisplay::clearM17()
{
if (m_timer1.hasExpired()) {
clearM17Int();
m_timer1.stop();
m_mode1 = MODE_IDLE;
} else {
m_mode1 = MODE_M17;
}
}
void CDisplay::writePOCSAG(uint32_t ric, const std::string& message)
{
m_timer1.start();
m_mode1 = MODE_POCSAG;
writePOCSAGInt(ric, message);
}
void CDisplay::clearPOCSAG()
{
if (m_timer1.hasExpired()) {
clearPOCSAGInt();
m_timer1.stop();
m_mode1 = MODE_IDLE;
} else {
m_mode1 = MODE_POCSAG;
}
}
void CDisplay::writeCW()
{
m_timer1.start();
@ -187,11 +399,41 @@ void CDisplay::clock(unsigned int ms)
m_timer1.clock(ms);
if (m_timer1.isRunning() && m_timer1.hasExpired()) {
switch (m_mode1) {
case MODE_DSTAR:
clearDStarInt();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_DMR:
clearDMRInt(1U);
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_YSF:
clearFusionInt();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_P25:
clearP25Int();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_NXDN:
clearNXDNInt();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_M17:
clearM17Int();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_POCSAG:
clearPOCSAGInt();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_CW:
clearCWInt();
m_mode1 = MODE_IDLE;
@ -219,6 +461,14 @@ void CDisplay::clockInt(unsigned int ms)
{
}
void CDisplay::writeDStarRSSIInt(unsigned char rssi)
{
}
void CDisplay::writeDStarBERInt(float ber)
{
}
int CDisplay::writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type)
{
/*
@ -245,6 +495,44 @@ void CDisplay::writeDMRBERInt(unsigned int slotNo, float ber)
{
}
void CDisplay::writeFusionRSSIInt(unsigned char rssi)
{
}
void CDisplay::writeFusionBERInt(float ber)
{
}
void CDisplay::writeP25RSSIInt(unsigned char rssi)
{
}
void CDisplay::writeP25BERInt(float ber)
{
}
void CDisplay::writeNXDNRSSIInt(unsigned char rssi)
{
}
void CDisplay::writeNXDNBERInt(float ber)
{
}
void CDisplay::writeM17RSSIInt(unsigned char rssi)
{
}
void CDisplay::writeM17BERInt(float ber)
{
}
int CDisplay::writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type)
{
/* return value definition is same as writeDMRIntEx() */
return -1; // not supported
}
/* Factory method extracted from MMDVMHost.cpp - BG5HHP */
CDisplay* CDisplay::createDisplay(const CConf& conf, CModem* modem)

View file

@ -44,6 +44,11 @@ public:
void setQuit();
void setFM();
void writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
void writeDStarRSSI(unsigned char rssi);
void writeDStarBER(float ber);
void clearDStar();
void writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
void writeDMR(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type);
void writeDMRRSSI(unsigned int slotNo, unsigned char rssi);
@ -51,6 +56,30 @@ public:
void writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
void clearDMR(unsigned int slotNo);
void writeFusion(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin);
void writeFusionRSSI(unsigned char rssi);
void writeFusionBER(float ber);
void clearFusion();
void writeP25(const char* source, bool group, unsigned int dest, const char* type);
void writeP25RSSI(unsigned char rssi);
void writeP25BER(float ber);
void clearP25();
void writeNXDN(const char* source, bool group, unsigned int dest, const char* type);
void writeNXDN(const class CUserDBentry& source, bool group, unsigned int dest, const char* type);
void writeNXDNRSSI(unsigned char rssi);
void writeNXDNBER(float ber);
void clearNXDN();
void writeM17(const char* source, const char* dest, const char* type);
void writeM17RSSI(unsigned char rssi);
void writeM17BER(float ber);
void clearM17();
void writePOCSAG(uint32_t ric, const std::string& message);
void clearPOCSAG();
void writeCW();
virtual void close() = 0;
@ -64,6 +93,12 @@ protected:
virtual void setLockoutInt() = 0;
virtual void setErrorInt(const char* text) = 0;
virtual void setQuitInt() = 0;
virtual void setFMInt() = 0;
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0;
virtual void writeDStarRSSIInt(unsigned char rssi);
virtual void writeDStarBERInt(float ber);
virtual void clearDStarInt() = 0;
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) = 0;
virtual int writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type);
@ -72,6 +107,30 @@ protected:
virtual void writeDMRBERInt(unsigned int slotNo, float ber);
virtual void clearDMRInt(unsigned int slotNo) = 0;
virtual void writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin) = 0;
virtual void writeFusionRSSIInt(unsigned char rssi);
virtual void writeFusionBERInt(float ber);
virtual void clearFusionInt() = 0;
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type) = 0;
virtual void writeP25RSSIInt(unsigned char rssi);
virtual void writeP25BERInt(float ber);
virtual void clearP25Int() = 0;
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type) = 0;
virtual int writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type);
virtual void writeNXDNRSSIInt(unsigned char rssi);
virtual void writeNXDNBERInt(float ber);
virtual void clearNXDNInt() = 0;
virtual void writeM17Int(const char* source, const char* dest, const char* type) = 0;
virtual void writeM17RSSIInt(unsigned char rssi);
virtual void writeM17BERInt(float ber);
virtual void clearM17Int() = 0;
virtual void writePOCSAGInt(uint32_t ric, const std::string& message) = 0;
virtual void clearPOCSAGInt() = 0;
virtual void writeCWInt() = 0;
virtual void clearCWInt() = 0;

19
Dockerfile Normal file
View file

@ -0,0 +1,19 @@
FROM alpine
RUN apk add --update --no-cache \
cmake \
make \
g++ \
git \
&& rm -rf /var/cache/apk/*
ADD ./ /MMDVMHost
WORKDIR /MMDVMHost
RUN make \
&& cp MMDVMHost /usr/local/bin
VOLUME /MMDVMHost
WORKDIR /MMDVMHost
CMD ["MMDVMHost", "/MMDVMHost/MMDVM.ini"]

192
FMControl.cpp Normal file
View file

@ -0,0 +1,192 @@
/*
* Copyright (C) 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 "FMControl.h"
#include <string>
#if defined(DUMP_RF_AUDIO)
#include <cstdio>
#endif
#define SWAP_BYTES_16(a) (((a >> 8) & 0x00FFU) | ((a << 8) & 0xFF00U))
const float DEEMPHASIS_GAIN_DB = 8.0F; // Audio gain adjustment
const float PREEMPHASIS_GAIN_DB = 0.0F; // Audio gain adjustment
const float FILTER_GAIN_DB = 2.0F; // Audio gain adjustment
const unsigned int FM_MASK = 0x00000FFFU;
CFMControl::CFMControl(CFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn) :
m_network(network),
m_txAudioGain(txAudioGain),
m_rxAudioGain(rxAudioGain),
m_preEmphasisOn(preEmphasisOn),
m_deEmphasisOn(deEmphasisOn),
m_enabled(false),
m_incomingRFAudio(1600U, "Incoming RF FM Audio"),
m_preEmphasis(NULL),
m_deEmphasis(NULL),
m_filterStage1(NULL),
m_filterStage2(NULL),
m_filterStage3(NULL)
{
assert(txAudioGain > 0.0F);
assert(rxAudioGain > 0.0F);
m_preEmphasis = new CIIRDirectForm1Filter(8.315375384336983F, -7.03334621603483F,0.0F,1.0F, 0.282029168302153F,0.0F, PREEMPHASIS_GAIN_DB);
m_deEmphasis = new CIIRDirectForm1Filter(0.07708787090460224F, 0.07708787090460224F,0.0F, 1.0F, -0.8458242581907955F,0.0F, DEEMPHASIS_GAIN_DB);
// Chebyshev type 1 0.2dB cheby type 1 3rd order 300-2700Hz fs=8000
m_filterStage1 = new CIIRDirectForm1Filter(0.29495028f, 0.0f, -0.29495028f, 1.0f, -0.61384624f, -0.057158668f, FILTER_GAIN_DB);
m_filterStage2 = new CIIRDirectForm1Filter(1.0f, 2.0f, 1.0f, 1.0f, 0.9946123f, 0.6050482f, FILTER_GAIN_DB);
m_filterStage3 = new CIIRDirectForm1Filter(1.0f, -2.0f, 1.0f, 1.0f, -1.8414584f, 0.8804949f, FILTER_GAIN_DB);
}
CFMControl::~CFMControl()
{
delete m_preEmphasis;
delete m_deEmphasis;
delete m_filterStage1;
delete m_filterStage2;
delete m_filterStage3;
}
bool CFMControl::writeModem(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
if (m_network == NULL)
return true;
if (data[0U] == TAG_HEADER)
return true;
if (data[0U] == TAG_EOT)
return m_network->writeEnd();
if (data[0U] != TAG_DATA)
return false;
m_incomingRFAudio.addData(data + 1U, length - 1U);
unsigned int bufferLength = m_incomingRFAudio.dataSize();
if (bufferLength > 240U) // 160 samples 12-bit
bufferLength = 240U; // 160 samples 12-bit
if (bufferLength >= 3U) {
bufferLength = bufferLength - bufferLength % 3U; // Round down to nearest multiple of 3
unsigned char bufferData[240U]; // 160 samples 12-bit
m_incomingRFAudio.getData(bufferData, bufferLength);
unsigned int pack = 0U;
unsigned char* packPointer = (unsigned char*)&pack;
float out[160U]; // 160 samples 12-bit
unsigned int nOut = 0U;
short unpackedSamples[2U];
for (unsigned int i = 0U; i < bufferLength; i += 3U) {
// Extract unsigned 12 bit unsigned sample pairs packed into 3 bytes to 16 bit signed
packPointer[0U] = bufferData[i + 0U];
packPointer[1U] = bufferData[i + 1U];
packPointer[2U] = bufferData[i + 2U];
unpackedSamples[1U] = short(int(pack & FM_MASK) - 2048);
unpackedSamples[0U] = short(int(pack >> 12 & FM_MASK) - 2048); //
// Process unpacked sample pair
for (unsigned char j = 0U; j < 2U; j++) {
// Convert to float (-1.0 to +1.0)
float sampleFloat = (float(unpackedSamples[j]) * m_rxAudioGain) / 2048.0F;
// De-emphasise and remove CTCSS
if (m_deEmphasisOn)
sampleFloat = m_deEmphasis->filter(sampleFloat);
out[nOut++] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(sampleFloat)));
}
}
#if defined(DUMP_RF_AUDIO)
FILE * audiofile = fopen("./audiodump.bin", "ab");
if (audiofile != NULL) {
fwrite(out, sizeof(float), nOut, audiofile);
fclose(audiofile);
}
#endif
return m_network->writeData(out, nOut);
}
return true;
}
unsigned int CFMControl::readModem(unsigned char* data, unsigned int space)
{
assert(data != NULL);
assert(space > 0U);
if (m_network == NULL)
return 0U;
if (space > 240U) // 160 samples 12-bit
space = 240U; // 160 samples 12-bit
float netData[160U]; // Modem can handle up to 160 samples at a time
unsigned int length = m_network->read(netData, 160U); // 160 samples 12-bit
if (length == 0U)
return 0U;
unsigned int pack = 0U;
unsigned char* packPointer = (unsigned char*)&pack;
unsigned int nData = 0U;
for (unsigned int i = 0; i < length; i++) {
float sampleFloat = netData[i] * m_txAudioGain;
// Pre-emphasis
if (m_preEmphasisOn)
sampleFloat = m_preEmphasis->filter(sampleFloat);
// Convert float to 12-bit samples (0 to 4095)
unsigned int sample12bit = (unsigned int)((sampleFloat + 1.0F) * 2048.0F + 0.5F);
// Pack 2 samples into 3 bytes
if ((i & 1U) == 0) {
pack = 0U;
pack = sample12bit << 12;
} else {
pack |= sample12bit;
data[nData++] = packPointer[0U];
data[nData++] = packPointer[1U];
data[nData++] = packPointer[2U];
}
}
return nData;
}
void CFMControl::clock(unsigned int ms)
{
// May not be needed
}
void CFMControl::enable(bool enabled)
{
// May not be needed
}

59
FMControl.h Normal file
View file

@ -0,0 +1,59 @@
/*
* Copyright (C) 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(FMControl_H)
#define FMControl_H
#include "FMNetwork.h"
#include "Defines.h"
#include "IIRDirectForm1Filter.h"
// Uncomment this to dump audio to a raw audio file
// The file will be written in same folder as executable
// Toplay the file : ffplay -autoexit -f u16be -ar 8000 audiodump.bin
// #define DUMP_RF_AUDIO
class CFMControl {
public:
CFMControl(CFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn);
~CFMControl();
bool writeModem(const unsigned char* data, unsigned int length);
unsigned int readModem(unsigned char* data, unsigned int space);
void clock(unsigned int ms);
void enable(bool enabled);
private:
CFMNetwork* m_network;
float m_txAudioGain;
float m_rxAudioGain;
bool m_preEmphasisOn;
bool m_deEmphasisOn;
bool m_enabled;
CRingBuffer<unsigned char> m_incomingRFAudio;
CIIRDirectForm1Filter* m_preEmphasis;
CIIRDirectForm1Filter* m_deEmphasis;
CIIRDirectForm1Filter* m_filterStage1;
CIIRDirectForm1Filter* m_filterStage2;
CIIRDirectForm1Filter* m_filterStage3;
};
#endif

398
FMNetwork.cpp Normal file
View file

@ -0,0 +1,398 @@
/*
* Copyright (C) 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 "FMNetwork.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 1500U;
CFMNetwork::CFMNetwork(const std::string& callsign, const std::string& protocol, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug) :
m_callsign(callsign),
m_protocol(FMNP_USRP),
m_socket(localAddress, localPort),
m_addr(),
m_addrLen(0U),
m_debug(debug),
m_enabled(false),
m_buffer(2000U, "FM Network"),
m_seqNo(0U)
{
assert(!callsign.empty());
assert(gatewayPort > 0U);
assert(!gatewayAddress.empty());
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0)
m_addrLen = 0U;
// Remove any trailing letters in the callsign
size_t pos = callsign.find_first_of(' ');
if (pos != std::string::npos)
m_callsign = callsign.substr(0U, pos);
// if (protocol == "USRP")
// m_protocol = FMNP_USRP;
}
CFMNetwork::~CFMNetwork()
{
}
bool CFMNetwork::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of the FM Gateway");
return false;
}
LogMessage("Opening FM network connection");
return m_socket.open(m_addr);
}
bool CFMNetwork::writeData(float* data, unsigned int nSamples)
{
assert(data != NULL);
assert(nSamples > 0U);
if (m_seqNo == 0U) {
bool ret = writeStart();
if (!ret)
return false;
}
unsigned char buffer[500U];
::memset(buffer, 0x00U, 500U);
unsigned int length = 0U;
if (m_protocol == FMNP_USRP) {
buffer[length++] = 'U';
buffer[length++] = 'S';
buffer[length++] = 'R';
buffer[length++] = 'P';
// Sequence number
buffer[length++] = (m_seqNo >> 24) & 0xFFU;
buffer[length++] = (m_seqNo >> 16) & 0xFFU;
buffer[length++] = (m_seqNo >> 8) & 0xFFU;
buffer[length++] = (m_seqNo >> 0) & 0xFFU;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// PTT on
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x01U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// Type, 0 for audio
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
}
for (unsigned int i = 0U; i < nSamples; i++) {
short val = short(data[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE
buffer[length++] = (val >> 0) & 0xFFU;
buffer[length++] = (val >> 8) & 0xFFU;
}
if (m_debug)
CUtils::dump(1U, "FM Network Data Sent", buffer, length);
m_seqNo++;
return m_socket.write(buffer, length, m_addr, m_addrLen);
}
bool CFMNetwork::writeEnd()
{
unsigned char buffer[500U];
::memset(buffer, 0x00U, 500U);
unsigned int length = 0U;
if (m_protocol == FMNP_USRP) {
buffer[length++] = 'U';
buffer[length++] = 'S';
buffer[length++] = 'R';
buffer[length++] = 'P';
// Sequence number
buffer[length++] = (m_seqNo >> 24) & 0xFFU;
buffer[length++] = (m_seqNo >> 16) & 0xFFU;
buffer[length++] = (m_seqNo >> 8) & 0xFFU;
buffer[length++] = (m_seqNo >> 0) & 0xFFU;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// PTT off
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// Type, 0 for audio
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
length += 320U;
}
m_seqNo = 0U;
if (length > 0U) {
if (m_debug)
CUtils::dump(1U, "FM Network Data Sent", buffer, length);
return m_socket.write(buffer, length, m_addr, m_addrLen);
} else {
return true;
}
}
void CFMNetwork::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage addr;
unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, addr, addrlen);
if (length <= 0)
return;
// Check if the data is for us
if (!CUDPSocket::match(addr, m_addr)) {
LogMessage("FM packet received from an invalid source");
return;
}
if (!m_enabled)
return;
if (m_debug)
CUtils::dump(1U, "FM Network Data Received", buffer, length);
if (m_protocol == FMNP_USRP) {
// Invalid packet type?
if (::memcmp(buffer, "USRP", 4U) != 0)
return;
if (length < 32)
return;
// The type is a big-endian 4-byte integer
unsigned int type = (buffer[20U] << 24) +
(buffer[21U] << 16) +
(buffer[22U] << 8) +
(buffer[23U] << 0);
if (type == 0U)
m_buffer.addData(buffer + 32U, length - 32U);
}
}
unsigned int CFMNetwork::read(float* data, unsigned int nSamples)
{
assert(data != NULL);
assert(nSamples > 0U);
unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned short);
if (bytes == 0U)
return 0U;
if (bytes < nSamples)
nSamples = bytes;
unsigned char buffer[1500U];
m_buffer.getData(buffer, nSamples * sizeof(unsigned short));
for (unsigned int i = 0U; i < nSamples; i++) {
short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8);
data[i] = float(val) / 65536.0F;
}
return nSamples;
}
void CFMNetwork::reset()
{
m_buffer.clear();
}
void CFMNetwork::close()
{
m_socket.close();
LogMessage("Closing FM network connection");
}
void CFMNetwork::enable(bool enabled)
{
if (enabled && !m_enabled)
reset();
else if (!enabled && m_enabled)
reset();
m_enabled = enabled;
}
bool CFMNetwork::writeStart()
{
unsigned char buffer[500U];
::memset(buffer, 0x00U, 500U);
unsigned int length = 0U;
if (m_protocol == FMNP_USRP) {
buffer[length++] = 'U';
buffer[length++] = 'S';
buffer[length++] = 'R';
buffer[length++] = 'P';
// Sequence number
buffer[length++] = (m_seqNo >> 24) & 0xFFU;
buffer[length++] = (m_seqNo >> 16) & 0xFFU;
buffer[length++] = (m_seqNo >> 8) & 0xFFU;
buffer[length++] = (m_seqNo >> 0) & 0xFFU;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// PTT off
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// Type, 2 for metadata
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x02U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// TLV TAG for Metadata
buffer[length++] = 0x08U;
// TLV Length
buffer[length++] = 3U + 4U + 3U + 1U + 1U + m_callsign.size() + 1U;
// DMR Id
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// Rpt Id
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// Talk Group
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
buffer[length++] = 0x00U;
// Time Slot
buffer[length++] = 0x00U;
// Color Code
buffer[length++] = 0x00U;
// Callsign
for (std::string::const_iterator it = m_callsign.cbegin(); it != m_callsign.cend(); ++it)
buffer[length++] = *it;
// End of Metadata
buffer[length++] = 0x00U;
length = 70U;
}
if (length > 0U) {
if (m_debug)
CUtils::dump(1U, "FM Network Data Sent", buffer, length);
return m_socket.write(buffer, length, m_addr, m_addrLen);
} else {
return true;
}
}

67
FMNetwork.h Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (C) 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.
*/
#ifndef FMNetwork_H
#define FMNetwork_H
#include "RingBuffer.h"
#include "UDPSocket.h"
#include <cstdint>
#include <string>
enum FM_NETWORK_PROTOCOL {
FMNP_USRP
};
class CFMNetwork {
public:
CFMNetwork(const std::string& callsign, const std::string& protocol, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug);
~CFMNetwork();
bool open();
void enable(bool enabled);
bool writeData(float* data, unsigned int nSamples);
bool writeEnd();
unsigned int read(float* data, unsigned int nSamples);
void reset();
void close();
void clock(unsigned int ms);
private:
std::string m_callsign;
FM_NETWORK_PROTOCOL m_protocol;
CUDPSocket m_socket;
sockaddr_storage m_addr;
unsigned int m_addrLen;
bool m_debug;
bool m_enabled;
CRingBuffer<unsigned char> m_buffer;
unsigned int m_seqNo;
bool writeStart();
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
*
* 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
@ -41,7 +41,6 @@ const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms
const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms
const unsigned int M17_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms
CHD44780::CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector<unsigned int>& pins, unsigned int i2cAddress, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex) :
CDisplay(),
@ -212,12 +211,12 @@ void CHD44780::adafruitLCDSetup()
::pinMode(AF_RW, OUTPUT);
::digitalWrite(AF_RW, LOW);
m_rb = AF_RS;
m_strb = AF_E;
m_d0 = AF_D0;
m_d1 = AF_D1;
m_d2 = AF_D2;
m_d3 = AF_D3;
m_rb = AF_RS;
m_strb = AF_E;
m_d0 = AF_D0;
m_d1 = AF_D1;
m_d2 = AF_D2;
m_d3 = AF_D3;
}
void CHD44780::adafruitLCDColour(ADAFRUIT_COLOUR colour)
@ -276,12 +275,12 @@ void CHD44780::pcf8574LCDSetup()
::pcf8574Setup(AF_BASE, m_i2cAddress);
// Turn on backlight
::pinMode(AF_BL, OUTPUT);
::digitalWrite(AF_BL, 1);
::pinMode (AF_BL, OUTPUT);
::digitalWrite (AF_BL, 1);
// Set LCD to write mode.
::pinMode(AF_RW, OUTPUT);
::digitalWrite(AF_RW, 0);
::pinMode (AF_RW, OUTPUT);
::digitalWrite (AF_RW, 0);
m_rb = AF_RS;
m_strb = AF_E;
@ -298,7 +297,7 @@ void CHD44780::setIdleInt()
::lcdClear(m_fd);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_WHITE);
adafruitLCDColour(AC_WHITE);
#endif
if (m_pwm) {
@ -328,7 +327,7 @@ void CHD44780::setErrorInt(const char* text)
assert(text != NULL);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_RED);
adafruitLCDColour(AC_RED);
#endif
m_clockDisplayTimer.stop(); // Stop the clock display
@ -406,7 +405,7 @@ void CHD44780::setFMInt()
::lcdClear(m_fd);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_WHITE);
adafruitLCDColour(AC_WHITE);
#endif
if (m_pwm) {
@ -440,7 +439,7 @@ void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your,
assert(reflector != NULL);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_RED);
adafruitLCDColour(AC_RED);
#endif
m_clockDisplayTimer.stop(); // Stop the clock display
@ -464,10 +463,11 @@ void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your,
::lcdPrintf(m_fd, " %.8s/%.4s", my1, my2);
::lcdPosition(m_fd, m_cols - 1, (m_rows / 2) - 1);
if (strcmp(type, "R") == 0)
if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2);
else
} else {
::lcdPutchar(m_fd, 3);
}
::sprintf(m_buffer1, "%.8s", your);
@ -493,19 +493,19 @@ void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your,
::lcdPrintf(m_fd, " %.*s", m_cols, m_buffer1);
m_dmr = false;
m_rssiCount1 = 0U;
m_rssiCount1 = 0U;
}
void CHD44780::writeDStarRSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
void CHD44780::writeDStarRSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "-%3udBm", rssi);
}
m_rssiCount1++;
if (m_rssiCount1 >= DSTAR_RSSI_COUNT)
m_rssiCount1 = 0U;
}
m_rssiCount1++;
if (m_rssiCount1 >= DSTAR_RSSI_COUNT)
m_rssiCount1 = 0U;
}
void CHD44780::clearDStarInt()
@ -599,20 +599,21 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2) - 1);
::lcdPuts(m_fd, " ");
if (group)
if (group) {
::lcdPutchar(m_fd, 5);
else
} else {
::lcdPutchar(m_fd, 4);
}
if (strcmp(type, "R") == 0)
if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2);
else
} else {
::lcdPutchar(m_fd, 3);
}
} else {
::lcdPosition(m_fd, 0, (m_rows / 2));
::lcdPuts(m_fd, "2 ");
if (m_cols > 16)
if (m_cols > 16 )
::sprintf(m_buffer2, "%s > %s%s%s", src.c_str(), group ? "TG" : "", dst.c_str(), DEADSPACE);
else
::sprintf(m_buffer2, "%s>%s%s", src.c_str(), dst.c_str(), DEADSPACE);
@ -621,15 +622,17 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2));
::lcdPuts(m_fd, " ");
if (group)
if (group) {
::lcdPutchar(m_fd, 5);
else
} else {
::lcdPutchar(m_fd, 4);
}
if (strcmp(type, "R") == 0)
if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2);
else
} else {
::lcdPutchar(m_fd, 3);
}
}
} else {
if (m_rows > 2U) {
@ -644,10 +647,11 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2);
::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2) - 1);
if (strcmp(type, "R") == 0)
if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2);
else
} else {
::lcdPutchar(m_fd, 3);
}
::lcdPosition(m_fd, 0, (m_rows / 2));
::lcdPutchar(m_fd, 1);
@ -655,38 +659,38 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2);
::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2));
if (group)
if (group) {
::lcdPutchar(m_fd, 5);
else
} else {
::lcdPutchar(m_fd, 4);
}
}
m_dmr = true;
m_rssiCount1 = 0U;
m_rssiCount2 = 0U;
m_rssiCount2 = 0U;
}
void CHD44780::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
{
void CHD44780::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
{
if (m_rows > 2) {
if (slotNo == 1U) {
if (m_rssiCount1 == 0U) {
if (slotNo == 1U) {
if (m_rssiCount1 == 0U) {
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "-%3udBm", rssi);
}
}
m_rssiCount1++;
if (m_rssiCount1 >= DMR_RSSI_COUNT)
m_rssiCount1 = 0U;
} else {
if (m_rssiCount2 == 0U) {
m_rssiCount1++;
if (m_rssiCount1 >= DMR_RSSI_COUNT)
m_rssiCount1 = 0U;
} else {
if (m_rssiCount2 == 0U) {
::lcdPosition(m_fd, (m_cols / 2), 3);
::lcdPrintf(m_fd, "-%3udBm", rssi);
}
}
m_rssiCount2++;
if (m_rssiCount2 >= DMR_RSSI_COUNT)
m_rssiCount2 = 0U;
m_rssiCount2++;
if (m_rssiCount2 >= DMR_RSSI_COUNT)
m_rssiCount2 = 0U;
}
}
}
@ -718,6 +722,7 @@ void CHD44780::clearDMRInt(unsigned int slotNo)
}
}
} else {
if (m_rows > 2U) {
::lcdPosition(m_fd, 0, (m_rows / 2) - 2);
::sprintf(m_buffer1, "%s", DEADSPACE);
@ -740,7 +745,7 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned cha
assert(origin != NULL);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_RED);
adafruitLCDColour(AC_RED);
#endif
m_clockDisplayTimer.stop(); // Stop the clock display
@ -757,10 +762,12 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned cha
::lcdPuts(m_fd, "System Fusion");
if (m_rows == 2U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -769,6 +776,7 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned cha
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 20U) {
char m_buffer1[20U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -777,6 +785,7 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned cha
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 2 && m_cols == 40U) {
char m_buffer1[40U];
::sprintf(m_buffer1, "%.10s > DG-ID %u", source, dgid);
::lcdPosition(m_fd, 0, 1);
@ -787,16 +796,16 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned cha
m_rssiCount1 = 0U;
}
void CHD44780::writeFusionRSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
void CHD44780::writeFusionRSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "-%3udBm", rssi);
}
m_rssiCount1++;
if (m_rssiCount1 >= YSF_RSSI_COUNT)
m_rssiCount1 = 0U;
}
m_rssiCount1++;
if (m_rssiCount1 >= YSF_RSSI_COUNT)
m_rssiCount1 = 0U;
}
void CHD44780::clearFusionInt()
@ -839,7 +848,7 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
assert(type != NULL);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_RED);
adafruitLCDColour(AC_RED);
#endif
m_clockDisplayTimer.stop(); // Stop the clock display
@ -856,10 +865,12 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
::lcdPuts(m_fd, "P25");
if (m_rows == 2U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -868,6 +879,7 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 20U) {
char m_buffer1[20U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -876,6 +888,7 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 2 && m_cols == 40U) {
char m_buffer1[40U];
::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest);
::lcdPosition(m_fd, 0, 1);
@ -883,19 +896,19 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
}
m_dmr = false;
m_rssiCount1 = 0U;
m_rssiCount1 = 0U;
}
void CHD44780::writeP25RSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
void CHD44780::writeP25RSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "-%3udBm", rssi);
}
m_rssiCount1++;
if (m_rssiCount1 >= P25_RSSI_COUNT)
m_rssiCount1 = 0U;
}
m_rssiCount1++;
if (m_rssiCount1 >= P25_RSSI_COUNT)
m_rssiCount1 = 0U;
}
void CHD44780::clearP25Int()
@ -939,7 +952,7 @@ void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, c
assert(type != NULL);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_RED);
adafruitLCDColour(AC_RED);
#endif
m_clockDisplayTimer.stop(); // Stop the clock display
@ -956,10 +969,12 @@ void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, c
::lcdPuts(m_fd, "NXDN");
if (m_rows == 2U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -968,6 +983,7 @@ void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, c
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 20U) {
char m_buffer1[20U];
::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -976,25 +992,27 @@ void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, c
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 2 && m_cols == 40U) {
char m_buffer1[40U];
::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
}
m_dmr = false;
m_rssiCount1 = 0U;
m_rssiCount1 = 0U;
}
void CHD44780::writeNXDNRSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
void CHD44780::writeNXDNRSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "-%3udBm", rssi);
}
m_rssiCount1++;
if (m_rssiCount1 >= NXDN_RSSI_COUNT)
m_rssiCount1 = 0U;
}
m_rssiCount1++;
if (m_rssiCount1 >= NXDN_RSSI_COUNT)
m_rssiCount1 = 0U;
}
void CHD44780::clearNXDNInt()
@ -1032,115 +1050,16 @@ void CHD44780::clearNXDNInt()
}
}
void CHD44780::writeM17Int(const char* source, const char* dest, const char* type)
{
assert(source != NULL);
assert(dest != NULL);
assert(type != NULL);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_RED);
#endif
m_clockDisplayTimer.stop(); // Stop the clock display
::lcdClear(m_fd);
if (m_pwm) {
if (m_pwmPin != 1U)
::softPwmWrite(m_pwmPin, m_pwmBright);
else
::pwmWrite(m_pwmPin, (m_pwmBright / 100) * 1024);
}
::lcdPosition(m_fd, 0, 0);
::lcdPuts(m_fd, "M17");
::sprintf(m_buffer1, "%.9s", source);
::sprintf(m_buffer2, "%.9s", dest);
if (m_rows == 2U && m_cols == 16U) {
::lcdPosition(m_fd, 5, 0);
::lcdPrintf(m_fd, "%.*s", m_cols - 5, m_buffer1);
::lcdPosition(m_fd, 5, 1);
::lcdPrintf(m_fd, "%.*s", m_cols - 5, m_buffer2);
} else if (m_rows == 4U && m_cols == 16U) {
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer2);
} else if (m_rows == 4U && m_cols == 20U) {
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 2 && m_cols == 40U) {
::sprintf(m_buffer1, "%.9s > %.9s", source, dest);
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
}
m_dmr = false;
m_rssiCount1 = 0U;
}
void CHD44780::writeM17RSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U && m_rows > 2) {
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "-%3udBm", rssi);
}
m_rssiCount1++;
if (m_rssiCount1 >= M17_RSSI_COUNT)
m_rssiCount1 = 0U;
}
void CHD44780::clearM17Int()
{
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_PURPLE);
#endif
m_clockDisplayTimer.stop(); // Stop the clock display
if (m_rows == 2U && m_cols == 16U) {
::lcdPosition(m_fd, 5, 0);
::lcdPrintf(m_fd, "%.*s", m_cols - 5, LISTENING);
::lcdPosition(m_fd, 5, 1);
::lcdPrintf(m_fd, "%.*s", m_cols - 5, " ");
} else if (m_rows == 4U && m_cols == 16U) {
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING);
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
} else if (m_rows == 4U && m_cols == 20U) {
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING);
::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
::lcdPosition(m_fd, 0, 3);
::lcdPrintf(m_fd, "%.*s", m_cols, " ");
} else if (m_rows == 2 && m_cols == 40U) {
::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, LISTENING);
}
}
void CHD44780::writePOCSAGInt(uint32_t ric, const std::string& message)
{
::lcdPosition(m_fd, m_cols - 5, m_rows - 1);
::lcdPuts(m_fd, "POCSG"); // Shortened "POCSAG TX" to 5 characters because it wraps around onto the next line (or on 16x2 displays the 1st line).
::lcdPuts(m_fd, "POCSAG TX");
}
void CHD44780::clearPOCSAGInt()
{
::lcdPosition(m_fd, m_cols - 5, m_rows - 1);
::lcdPuts(m_fd, " Idle"); // Reverted back to 5 character implementation.
::lcdPuts(m_fd, " Idle");
}
void CHD44780::writeCWInt()
@ -1161,30 +1080,31 @@ void CHD44780::clockInt(unsigned int ms)
// Idle clock display
if (m_displayClock && m_clockDisplayTimer.isRunning() && m_clockDisplayTimer.hasExpired()) {
time_t currentTime;
struct tm *Time;
::time(&currentTime);
time_t currentTime;
struct tm *Time;
time(&currentTime);
if (m_utc)
Time = ::gmtime(&currentTime);
else
Time = ::localtime(&currentTime);
if (m_utc) {
Time = gmtime(&currentTime);
} else {
Time = localtime(&currentTime);
}
setlocale(LC_TIME,"");
::strftime(m_buffer1, 128, "%X", Time); // Time
::strftime(m_buffer2, 128, "%x", Time); // Date
setlocale(LC_TIME,"");
strftime(m_buffer1, 128, "%X", Time); // Time
strftime(m_buffer2, 128, "%x", Time); // Date
if (m_cols == 16U && m_rows == 2U) {
::lcdPosition(m_fd, m_cols - 10, 1);
::lcdPrintf(m_fd, "%s%.*s", strlen(m_buffer1) > 8 ? "" : " ", 10, m_buffer1);
} else {
::lcdPosition(m_fd, (m_cols - (strlen(m_buffer1) == 8 ? 8 : 10)) / 2, m_rows == 2 ? 1 : 2);
::lcdPrintf(m_fd, "%.*s", strlen(m_buffer1) == 8 ? 8 : 10, m_buffer1);
::lcdPosition(m_fd, (m_cols - strlen(m_buffer2)) / 2, m_rows == 2 ? 0 : 1);
::lcdPrintf(m_fd, "%s", m_buffer2);
}
if (m_cols == 16U && m_rows == 2U) {
::lcdPosition(m_fd, m_cols - 10, 1);
::lcdPrintf(m_fd, "%s%.*s", strlen(m_buffer1) > 8 ? "" : " ", 10, m_buffer1);
} else {
::lcdPosition(m_fd, (m_cols - (strlen(m_buffer1) == 8 ? 8 : 10)) / 2, m_rows == 2 ? 1 : 2);
::lcdPrintf(m_fd, "%.*s", strlen(m_buffer1) == 8 ? 8 : 10, m_buffer1);
::lcdPosition(m_fd, (m_cols - strlen(m_buffer2)) / 2, m_rows == 2 ? 0 : 1);
::lcdPrintf(m_fd, "%s", m_buffer2);
}
m_clockDisplayTimer.start();
m_clockDisplayTimer.start();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
*
* 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
@ -89,51 +89,47 @@ enum ADAFRUIT_COLOUR {
class CHD44780 : public CDisplay
{
public:
CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector<unsigned int>& pins, unsigned int i2cAddress, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex);
virtual ~CHD44780();
CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector<unsigned int>& pins, unsigned int i2cAddress, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex);
virtual ~CHD44780();
virtual bool open();
virtual bool open();
virtual void close();
virtual void close();
protected:
virtual void setIdleInt();
virtual void setErrorInt(const char* text);
virtual void setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void setIdleInt();
virtual void setErrorInt(const char* text);
virtual void setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi);
virtual void clearDStarInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi);
virtual void clearDStarInt();
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void clearDMRInt(unsigned int slotNo);
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void clearDMRInt(unsigned int slotNo);
virtual void writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin);
virtual void writeFusionRSSIInt(unsigned char rssi);
virtual void clearFusionInt();
virtual void writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin);
virtual void writeFusionRSSIInt(unsigned char rssi);
virtual void clearFusionInt();
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
virtual void writeP25RSSIInt(unsigned char rssi);
virtual void clearP25Int();
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
virtual void writeP25RSSIInt(unsigned char rssi);
virtual void clearP25Int();
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
virtual void writeNXDNRSSIInt(unsigned char rssi);
virtual void clearNXDNInt();
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
virtual void writeNXDNRSSIInt(unsigned char rssi);
virtual void clearNXDNInt();
virtual void writeM17Int(const char* source, const char* dest, const char* type);
virtual void writeM17RSSIInt(unsigned char rssi);
virtual void clearM17Int();
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);
virtual void clearPOCSAGInt();
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);
virtual void clearPOCSAGInt();
virtual void writeCWInt();
virtual void clearCWInt();
virtual void writeCWInt();
virtual void clearCWInt();
virtual void clockInt(unsigned int ms);
virtual void clockInt(unsigned int ms);
private:
unsigned int m_rows;
@ -166,12 +162,12 @@ private:
*/
#ifdef ADAFRUIT_DISPLAY
void adafruitLCDSetup();
void adafruitLCDColour(ADAFRUIT_COLOUR colour);
void adafruitLCDSetup();
void adafruitLCDColour(ADAFRUIT_COLOUR colour);
#endif
#ifdef PCF8574_DISPLAY
void pcf8574LCDSetup();
void pcf8574LCDSetup();
#endif
};

View file

@ -161,7 +161,7 @@ void Log(unsigned int level, const char* fmt, ...)
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000LL);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03ld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000L);
#endif
va_list vl;

84
M17CRC.cpp Normal file
View file

@ -0,0 +1,84 @@
/*
* Copyright (C) 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 "M17CRC.h"
#include <cstdio>
#include <cassert>
const uint16_t CRC16_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x64D4U, 0x8F8BU, 0xD6BEU, 0x7BC2U, 0x22F7U, 0xC9A8U,
0x909DU, 0x4623U, 0x1F16U, 0xF449U, 0xAD7CU, 0xF784U, 0xAEB1U, 0x45EEU, 0x1CDBU, 0xCA65U, 0x9350U,
0x780FU, 0x213AU, 0x8C46U, 0xD573U, 0x3E2CU, 0x6719U, 0xB1A7U, 0xE892U, 0x03CDU, 0x5AF8U, 0xB63DU,
0xEF08U, 0x0457U, 0x5D62U, 0x8BDCU, 0xD2E9U, 0x39B6U, 0x6083U, 0xCDFFU, 0x94CAU, 0x7F95U, 0x26A0U,
0xF01EU, 0xA92BU, 0x4274U, 0x1B41U, 0x41B9U, 0x188CU, 0xF3D3U, 0xAAE6U, 0x7C58U, 0x256DU, 0xCE32U,
0x9707U, 0x3A7BU, 0x634EU, 0x8811U, 0xD124U, 0x079AU, 0x5EAFU, 0xB5F0U, 0xECC5U, 0x354FU, 0x6C7AU,
0x8725U, 0xDE10U, 0x08AEU, 0x519BU, 0xBAC4U, 0xE3F1U, 0x4E8DU, 0x17B8U, 0xFCE7U, 0xA5D2U, 0x736CU,
0x2A59U, 0xC106U, 0x9833U, 0xC2CBU, 0x9BFEU, 0x70A1U, 0x2994U, 0xFF2AU, 0xA61FU, 0x4D40U, 0x1475U,
0xB909U, 0xE03CU, 0x0B63U, 0x5256U, 0x84E8U, 0xDDDDU, 0x3682U, 0x6FB7U, 0x8372U, 0xDA47U, 0x3118U,
0x682DU, 0xBE93U, 0xE7A6U, 0x0CF9U, 0x55CCU, 0xF8B0U, 0xA185U, 0x4ADAU, 0x13EFU, 0xC551U, 0x9C64U,
0x773BU, 0x2E0EU, 0x74F6U, 0x2DC3U, 0xC69CU, 0x9FA9U, 0x4917U, 0x1022U, 0xFB7DU, 0xA248U, 0x0F34U,
0x5601U, 0xBD5EU, 0xE46BU, 0x32D5U, 0x6BE0U, 0x80BFU, 0xD98AU, 0x6A9EU, 0x33ABU, 0xD8F4U, 0x81C1U,
0x577FU, 0x0E4AU, 0xE515U, 0xBC20U, 0x115CU, 0x4869U, 0xA336U, 0xFA03U, 0x2CBDU, 0x7588U, 0x9ED7U,
0xC7E2U, 0x9D1AU, 0xC42FU, 0x2F70U, 0x7645U, 0xA0FBU, 0xF9CEU, 0x1291U, 0x4BA4U, 0xE6D8U, 0xBFEDU,
0x54B2U, 0x0D87U, 0xDB39U, 0x820CU, 0x6953U, 0x3066U, 0xDCA3U, 0x8596U, 0x6EC9U, 0x37FCU, 0xE142U,
0xB877U, 0x5328U, 0x0A1DU, 0xA761U, 0xFE54U, 0x150BU, 0x4C3EU, 0x9A80U, 0xC3B5U, 0x28EAU, 0x71DFU,
0x2B27U, 0x7212U, 0x994DU, 0xC078U, 0x16C6U, 0x4FF3U, 0xA4ACU, 0xFD99U, 0x50E5U, 0x09D0U, 0xE28FU,
0xBBBAU, 0x6D04U, 0x3431U, 0xDF6EU, 0x865BU, 0x5FD1U, 0x06E4U, 0xEDBBU, 0xB48EU, 0x6230U, 0x3B05U,
0xD05AU, 0x896FU, 0x2413U, 0x7D26U, 0x9679U, 0xCF4CU, 0x19F2U, 0x40C7U, 0xAB98U, 0xF2ADU, 0xA855U,
0xF160U, 0x1A3FU, 0x430AU, 0x95B4U, 0xCC81U, 0x27DEU, 0x7EEBU, 0xD397U, 0x8AA2U, 0x61FDU, 0x38C8U,
0xEE76U, 0xB743U, 0x5C1CU, 0x0529U, 0xE9ECU, 0xB0D9U, 0x5B86U, 0x02B3U, 0xD40DU, 0x8D38U, 0x6667U,
0x3F52U, 0x922EU, 0xCB1BU, 0x2044U, 0x7971U, 0xAFCFU, 0xF6FAU, 0x1DA5U, 0x4490U, 0x1E68U, 0x475DU,
0xAC02U, 0xF537U, 0x2389U, 0x7ABCU, 0x91E3U, 0xC8D6U, 0x65AAU, 0x3C9FU, 0xD7C0U, 0x8EF5U, 0x584BU,
0x017EU, 0xEA21U, 0xB314U};
bool CM17CRC::checkCRC16(const unsigned char* in, unsigned int nBytes)
{
assert(in != NULL);
assert(nBytes > 2U);
uint16_t crc = createCRC16(in, nBytes - 2U);
uint8_t temp[2U];
temp[0U] = (crc >> 8) & 0xFFU;
temp[1U] = (crc >> 0) & 0xFFU;
return temp[0U] == in[nBytes - 2U] && temp[1U] == in[nBytes - 1U];
}
void CM17CRC::encodeCRC16(unsigned char* in, unsigned int nBytes)
{
assert(in != NULL);
assert(nBytes > 2U);
uint16_t crc = createCRC16(in, nBytes - 2U);
in[nBytes - 2U] = (crc >> 8) & 0xFFU;
in[nBytes - 1U] = (crc >> 0) & 0xFFU;
}
uint16_t CM17CRC::createCRC16(const unsigned char* in, unsigned int nBytes)
{
assert(in != NULL);
uint16_t crc = 0xFFFFU;
for (unsigned int i = 0U; i < nBytes; i++)
crc = (crc << 8) ^ CRC16_TABLE[((crc >> 8) ^ uint16_t(in[i])) & 0x00FFU];
return crc;
}

34
M17CRC.h Normal file
View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 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(M17CRC_H)
#define M17CRC_H
#include <cstdint>
class CM17CRC
{
public:
static bool checkCRC16(const unsigned char* in, unsigned int nBytes);
static void encodeCRC16(unsigned char* in, unsigned int nBytes);
private:
static uint16_t createCRC16(const unsigned char* in, unsigned int nBytes);
};
#endif

821
M17Control.cpp Normal file
View file

@ -0,0 +1,821 @@
/*
* Copyright (C) 2020,2021 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; version 2 of the License.
*
* 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.
*/
#include "M17Control.h"
#include "M17Convolution.h"
#include "M17Utils.h"
#include "M17CRC.h"
#include "Golay24128.h"
#include "Utils.h"
#include "Sync.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <ctime>
const unsigned int INTERLEAVER[] = {
0U, 137U, 90U, 227U, 180U, 317U, 270U, 39U, 360U, 129U, 82U, 219U, 172U, 309U, 262U, 31U, 352U, 121U, 74U, 211U, 164U,
301U, 254U, 23U, 344U, 113U, 66U, 203U, 156U, 293U, 246U, 15U, 336U, 105U, 58U, 195U, 148U, 285U, 238U, 7U, 328U, 97U,
50U, 187U, 140U, 277U, 230U, 367U, 320U, 89U, 42U, 179U, 132U, 269U, 222U, 359U, 312U, 81U, 34U, 171U, 124U, 261U, 214U,
351U, 304U, 73U, 26U, 163U, 116U, 253U, 206U, 343U, 296U, 65U, 18U, 155U, 108U, 245U, 198U, 335U, 288U, 57U, 10U, 147U,
100U, 237U, 190U, 327U, 280U, 49U, 2U, 139U, 92U, 229U, 182U, 319U, 272U, 41U, 362U, 131U, 84U, 221U, 174U, 311U, 264U,
33U, 354U, 123U, 76U, 213U, 166U, 303U, 256U, 25U, 346U, 115U, 68U, 205U, 158U, 295U, 248U, 17U, 338U, 107U, 60U, 197U,
150U, 287U, 240U, 9U, 330U, 99U, 52U, 189U, 142U, 279U, 232U, 1U, 322U, 91U, 44U, 181U, 134U, 271U, 224U, 361U, 314U, 83U,
36U, 173U, 126U, 263U, 216U, 353U, 306U, 75U, 28U, 165U, 118U, 255U, 208U, 345U, 298U, 67U, 20U, 157U, 110U, 247U, 200U,
337U, 290U, 59U, 12U, 149U, 102U, 239U, 192U, 329U, 282U, 51U, 4U, 141U, 94U, 231U, 184U, 321U, 274U, 43U, 364U, 133U, 86U,
223U, 176U, 313U, 266U, 35U, 356U, 125U, 78U, 215U, 168U, 305U, 258U, 27U, 348U, 117U, 70U, 207U, 160U, 297U, 250U, 19U,
340U, 109U, 62U, 199U, 152U, 289U, 242U, 11U, 332U, 101U, 54U, 191U, 144U, 281U, 234U, 3U, 324U, 93U, 46U, 183U, 136U, 273U,
226U, 363U, 316U, 85U, 38U, 175U, 128U, 265U, 218U, 355U, 308U, 77U, 30U, 167U, 120U, 257U, 210U, 347U, 300U, 69U, 22U,
159U, 112U, 249U, 202U, 339U, 292U, 61U, 14U, 151U, 104U, 241U, 194U, 331U, 284U, 53U, 6U, 143U, 96U, 233U, 186U, 323U,
276U, 45U, 366U, 135U, 88U, 225U, 178U, 315U, 268U, 37U, 358U, 127U, 80U, 217U, 170U, 307U, 260U, 29U, 350U, 119U, 72U,
209U, 162U, 299U, 252U, 21U, 342U, 111U, 64U, 201U, 154U, 291U, 244U, 13U, 334U, 103U, 56U, 193U, 146U, 283U, 236U, 5U,
326U, 95U, 48U, 185U, 138U, 275U, 228U, 365U, 318U, 87U, 40U, 177U, 130U, 267U, 220U, 357U, 310U, 79U, 32U, 169U, 122U,
259U, 212U, 349U, 302U, 71U, 24U, 161U, 114U, 251U, 204U, 341U, 294U, 63U, 16U, 153U, 106U, 243U, 196U, 333U, 286U, 55U,
8U, 145U, 98U, 235U, 188U, 325U, 278U, 47U};
const unsigned char SCRAMBLER[] = {
0x00U, 0x00U, 0xD6U, 0xB5U, 0xE2U, 0x30U, 0x82U, 0xFFU, 0x84U, 0x62U, 0xBAU, 0x4EU, 0x96U, 0x90U, 0xD8U, 0x98U, 0xDDU,
0x5DU, 0x0CU, 0xC8U, 0x52U, 0x43U, 0x91U, 0x1DU, 0xF8U, 0x6EU, 0x68U, 0x2FU, 0x35U, 0xDAU, 0x14U, 0xEAU, 0xCDU, 0x76U,
0x19U, 0x8DU, 0xD5U, 0x80U, 0xD1U, 0x33U, 0x87U, 0x13U, 0x57U, 0x18U, 0x2DU, 0x29U, 0x78U, 0xC3U};
// #define DUMP_M17
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])
CM17Control::CM17Control(const std::string& callsign, unsigned int can, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) :
m_callsign(callsign),
m_can(can),
m_selfOnly(selfOnly),
m_allowEncryption(allowEncryption),
m_network(network),
m_display(display),
m_duplex(duplex),
m_queue(5000U, "M17 Control"),
m_rfState(RS_RF_LISTENING),
m_netState(RS_NET_IDLE),
m_rfTimeoutTimer(1000U, timeout),
m_netTimeoutTimer(1000U, timeout),
m_networkWatchdog(1000U, 0U, 1500U),
m_elapsed(),
m_rfFrames(0U),
m_netFrames(0U),
m_rfErrs(0U),
m_rfBits(1U),
m_rfLSF(),
m_rfLSFn(0U),
m_netLSF(),
m_netLSFn(0U),
m_rssiMapper(rssiMapper),
m_rssi(0U),
m_maxRSSI(0U),
m_minRSSI(0U),
m_aveRSSI(0U),
m_rssiCount(0U),
m_enabled(true),
m_fp(NULL)
{
assert(display != NULL);
assert(rssiMapper != NULL);
}
CM17Control::~CM17Control()
{
}
bool CM17Control::writeModem(unsigned char* data, unsigned int len)
{
assert(data != NULL);
if (!m_enabled)
return false;
unsigned char type = data[0U];
if (type == TAG_LOST && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA_AUDIO)) {
std::string source = m_rfLSF.getSource();
std::string dest = m_rfLSF.getDest();
if (m_rssi != 0U)
LogMessage("M17, transmission lost from %s to %s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
LogMessage("M17, transmission lost from %s to %s, %.1f seconds, BER: %.1f%%", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits));
writeEndRF();
return false;
}
if (type == TAG_LOST && m_rfState == RS_RF_DATA) {
writeEndRF();
return false;
}
if (type == TAG_LOST && m_rfState == RS_RF_REJECTED) {
writeEndRF();
return false;
}
if (type == TAG_LOST) {
m_rfState = RS_RF_LISTENING;
return false;
}
// Have we got RSSI bytes on the end?
if (len == (M17_FRAME_LENGTH_BYTES + 4U)) {
uint16_t raw = 0U;
raw |= (data[50U] << 8) & 0xFF00U;
raw |= (data[51U] << 0) & 0x00FFU;
// Convert the raw RSSI to dBm
int rssi = m_rssiMapper->interpolate(raw);
if (rssi != 0)
LogDebug("M17, raw RSSI: %u, reported RSSI: %d dBm", raw, rssi);
// RSSI is always reported as positive
m_rssi = (rssi >= 0) ? rssi : -rssi;
if (m_rssi > m_minRSSI)
m_minRSSI = m_rssi;
if (m_rssi < m_maxRSSI)
m_maxRSSI = m_rssi;
m_aveRSSI += m_rssi;
m_rssiCount++;
}
unsigned char temp[M17_FRAME_LENGTH_BYTES];
decorrelator(data + 2U, temp);
interleaver(temp, data + 2U);
if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_HEADER) {
m_rfLSF.reset();
CM17Convolution conv;
unsigned char frame[M17_LSF_LENGTH_BYTES];
unsigned int ber = conv.decodeLinkSetup(data + 2U + M17_SYNC_LENGTH_BYTES, frame);
bool valid = CM17CRC::checkCRC16(frame, M17_LSF_LENGTH_BYTES);
if (valid) {
m_rfLSF.setLinkSetup(frame);
bool ret = processRFHeader(false);
if (!ret) {
m_rfLSF.reset();
return false;
}
LogDebug("M17, link setup frame: errs: %u/368 (%.1f%%)", ber, float(ber) / 3.68F);
m_rfFrames = 0U;
m_rfErrs = ber;
m_rfBits = 368U;
m_rfTimeoutTimer.start();
m_minRSSI = m_rssi;
m_maxRSSI = m_rssi;
m_aveRSSI = m_rssi;
m_rssiCount = 1U;
m_rfLSFn = 0U;
#if defined(DUMP_M17)
openFile();
#endif
return true;
} else {
m_rfState = RS_RF_LATE_ENTRY;
return false;
}
}
if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_DATA) {
m_rfState = RS_RF_LATE_ENTRY;
m_rfLSF.reset();
}
if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA) {
unsigned int lich1, lich2, lich3, lich4;
bool valid1 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 0U, lich1);
bool valid2 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 3U, lich2);
bool valid3 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 6U, lich3);
bool valid4 = CGolay24128::decode24128(data + 2U + M17_SYNC_LENGTH_BYTES + 9U, lich4);
if (!valid1 || !valid2 || !valid3 || !valid4)
return false;
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich);
m_rfLSFn = (lich4 >> 5) & 0x07U;
m_rfLSF.setFragment(lich, m_rfLSFn);
bool valid = m_rfLSF.isValid();
if (valid) {
bool ret = processRFHeader(true);
if (!ret) {
m_rfLSF.reset();
return false;
}
m_rfFrames = 0U;
m_rfErrs = 0U;
m_rfBits = 1U;
m_rfTimeoutTimer.start();
m_minRSSI = m_rssi;
m_maxRSSI = m_rssi;
m_aveRSSI = m_rssi;
m_rssiCount = 1U;
#if defined(DUMP_M17)
openFile();
#endif
// Fall through
} else {
return false;
}
}
if ((m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA_AUDIO) && data[0U] == TAG_DATA) {
#if defined(DUMP_M17)
writeFile(data + 2U);
#endif
CM17Convolution conv;
unsigned char frame[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES];
unsigned int errors = conv.decodeData(data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES, frame);
uint16_t fn = (frame[0U] << 8) + (frame[1U] << 0);
LogDebug("M17, audio: FN: %u, errs: %u/272 (%.1f%%)", fn, errors, float(errors) / 2.72F);
m_rfBits += 272U;
m_rfErrs += errors;
float ber = float(m_rfErrs) / float(m_rfBits);
m_display->writeM17BER(ber);
if (m_duplex) {
unsigned char rfData[2U + M17_FRAME_LENGTH_BYTES];
rfData[0U] = TAG_DATA;
rfData[1U] = 0x00U;
// Generate the sync
CSync::addM17StreamSync(rfData + 2U);
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
m_rfLSF.getFragment(lich, m_rfLSFn);
// Add the fragment number
lich[5U] = (m_rfLSFn & 0x07U) << 5;
unsigned int frag1, frag2, frag3, frag4;
CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4);
// Add Golay to the LICH fragment here
unsigned int lich1 = CGolay24128::encode24128(frag1);
unsigned int lich2 = CGolay24128::encode24128(frag2);
unsigned int lich3 = CGolay24128::encode24128(frag3);
unsigned int lich4 = CGolay24128::encode24128(frag4);
CM17Utils::combineFragmentLICHFEC(lich1, lich2, lich3, lich4, rfData + 2U + M17_SYNC_LENGTH_BYTES);
// Add the Convolution FEC
conv.encodeData(frame, rfData + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES);
unsigned char temp[M17_FRAME_LENGTH_BYTES];
interleaver(rfData + 2U, temp);
decorrelator(temp, rfData + 2U);
writeQueueRF(rfData);
}
if (m_network != NULL && m_rfTimeoutTimer.isRunning() && !m_rfTimeoutTimer.hasExpired()) {
unsigned char netData[M17_LSF_LENGTH_BYTES + M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES];
m_rfLSF.getNetwork(netData + 0U);
// Copy the FN and payload from the frame
::memcpy(netData + M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES, frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES);
// Remove any erronous EOF from the FN
netData[M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES + 0U] &= 0x7FU;
// The CRC is added in the networking code
m_network->write(netData);
}
m_rfFrames++;
m_rfLSFn++;
if (m_rfLSFn >= 6U)
m_rfLSFn = 0U;
return true;
}
if ((m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA_AUDIO) && data[0U] == TAG_EOT) {
#if defined(DUMP_M17)
writeFile(data + 2U);
#endif
if (m_duplex) {
unsigned char rfData[M17_FRAME_LENGTH_BYTES + 2U];
rfData[0U] = TAG_EOT;
rfData[1U] = 0x00U;
// Generate the sync
for (unsigned int i = 0U; i < M17_FRAME_LENGTH_BYTES; i += M17_SYNC_LENGTH_BYTES)
CSync::addM17EOTSync(rfData + 2U + i);
writeQueueRF(rfData);
}
if (m_network != NULL && m_rfTimeoutTimer.isRunning() && !m_rfTimeoutTimer.hasExpired()) {
unsigned char netData[M17_LSF_LENGTH_BYTES + M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES];
m_rfLSF.getNetwork(netData + 0U);
// Add a EOF FN and silence for the EOF frame
netData[M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES + 0U] = 0x80U;
netData[M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES + 1U] = 0x00U;
if (m_rfState == RS_RF_AUDIO) {
::memcpy(netData + M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES + M17_FN_LENGTH_BYTES + 0U, M17_3200_SILENCE, 8U);
::memcpy(netData + M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES + M17_FN_LENGTH_BYTES + 8U, M17_3200_SILENCE, 8U);
} else {
::memcpy(netData + M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES + M17_FN_LENGTH_BYTES + 0U, M17_1600_SILENCE, 8U);
::memset(netData + M17_LSF_LENGTH_BYTES - M17_CRC_LENGTH_BYTES + M17_FN_LENGTH_BYTES + 8U, 0x00U, 8U);
}
// The CRC is added in the networking code
m_network->write(netData);
}
std::string source = m_rfLSF.getSource();
std::string dest = m_rfLSF.getDest();
if (m_rssi != 0U)
LogMessage("M17, received RF end of transmission from %s to %s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
LogMessage("M17, received RF end of transmission from %s to %s, %.1f seconds, BER: %.1f%%", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits));
writeEndRF();
return true;
}
return false;
}
unsigned int CM17Control::readModem(unsigned char* data)
{
assert(data != NULL);
if (m_queue.isEmpty())
return 0U;
unsigned char len = 0U;
m_queue.getData(&len, 1U);
m_queue.getData(data, len);
return len;
}
void CM17Control::writeEndRF()
{
m_rfState = RS_RF_LISTENING;
m_rfTimeoutTimer.stop();
m_rfLSF.reset();
if (m_netState == RS_NET_IDLE) {
m_display->clearM17();
if (m_network != NULL)
m_network->reset();
}
#if defined(DUMP_M17)
closeFile();
#endif
}
void CM17Control::writeEndNet()
{
m_netState = RS_NET_IDLE;
m_netTimeoutTimer.stop();
m_networkWatchdog.stop();
m_netLSF.reset();
m_display->clearM17();
if (m_network != NULL)
m_network->reset();
}
void CM17Control::writeNetwork()
{
unsigned char netData[100U];
bool exists = m_network->read(netData);
if (!exists)
return;
if (!m_enabled)
return;
if (m_rfState != RS_RF_LISTENING && m_rfState != RS_RF_LATE_ENTRY && m_netState == RS_NET_IDLE) {
m_network->reset();
return;
}
m_networkWatchdog.start();
m_netLSF.setNetwork(netData);
m_netLSF.setCAN(m_can);
if (!m_allowEncryption) {
unsigned char type = m_netLSF.getEncryptionType();
if (type != M17_ENCRYPTION_TYPE_NONE) {
m_network->reset();
return;
}
}
if (m_netState == RS_NET_IDLE) {
std::string source = m_netLSF.getSource();
std::string dest = m_netLSF.getDest();
unsigned char dataType = m_netLSF.getDataType();
switch (dataType) {
case M17_DATA_TYPE_DATA:
LogMessage("M17, received network data transmission from %s to %s", source.c_str(), dest.c_str());
m_netState = RS_NET_DATA;
break;
case M17_DATA_TYPE_VOICE:
LogMessage("M17, received network voice transmission from %s to %s", source.c_str(), dest.c_str());
m_netState = RS_NET_AUDIO;
break;
case M17_DATA_TYPE_VOICE_DATA:
LogMessage("M17, received network voice + data transmission from %s to %s", source.c_str(), dest.c_str());
m_netState = RS_NET_DATA_AUDIO;
break;
default:
m_network->reset();
return;
}
m_display->writeM17(source.c_str(), dest.c_str(), "N");
m_netTimeoutTimer.start();
m_elapsed.start();
m_netFrames = 0U;
m_netLSFn = 0U;
// Create a dummy start message
unsigned char start[M17_FRAME_LENGTH_BYTES + 2U];
start[0U] = TAG_HEADER;
start[1U] = 0x00U;
// Generate the sync
CSync::addM17LinkSetupSync(start + 2U);
unsigned char setup[M17_LSF_LENGTH_BYTES];
m_netLSF.getLinkSetup(setup);
// Add the convolution FEC
CM17Convolution conv;
conv.encodeLinkSetup(setup, start + 2U + M17_SYNC_LENGTH_BYTES);
unsigned char temp[M17_FRAME_LENGTH_BYTES];
interleaver(start + 2U, temp);
decorrelator(temp, start + 2U);
writeQueueNet(start);
}
if (m_netState == RS_NET_AUDIO || m_netState == RS_NET_DATA_AUDIO) {
unsigned char data[M17_FRAME_LENGTH_BYTES + 2U];
data[0U] = TAG_DATA;
data[1U] = 0x00U;
// Generate the sync
CSync::addM17StreamSync(data + 2U);
m_netFrames++;
// Add the fragment LICH
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
m_netLSF.getFragment(lich, m_netLSFn);
// Add the fragment number
lich[5U] = (m_netLSFn & 0x07U) << 5;
unsigned int frag1, frag2, frag3, frag4;
CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4);
// Add Golay to the LICH fragment here
unsigned int lich1 = CGolay24128::encode24128(frag1);
unsigned int lich2 = CGolay24128::encode24128(frag2);
unsigned int lich3 = CGolay24128::encode24128(frag3);
unsigned int lich4 = CGolay24128::encode24128(frag4);
CM17Utils::combineFragmentLICHFEC(lich1, lich2, lich3, lich4, data + 2U + M17_SYNC_LENGTH_BYTES);
// Add the FN and the data/audio
unsigned char payload[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES];
// Copy the FN minus the EOF marker
payload[0U] = netData[28U] & 0x7FU;
payload[1U] = netData[29U];
::memcpy(payload + 2U, netData + 30U, M17_PAYLOAD_LENGTH_BYTES);
// Add the Convolution FEC
CM17Convolution conv;
conv.encodeData(payload, data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES);
unsigned char temp[M17_FRAME_LENGTH_BYTES];
interleaver(data + 2U, temp);
decorrelator(temp, data + 2U);
writeQueueNet(data);
m_netLSFn++;
if (m_netLSFn >= 6U)
m_netLSFn = 0U;
// EOT handling
uint16_t fn = (netData[28U] << 8) + (netData[29U] << 0);
if ((fn & 0x8000U) == 0x8000U) {
std::string source = m_netLSF.getSource();
std::string dest = m_netLSF.getDest();
LogMessage("M17, received network end of transmission from %s to %s, %.1f seconds", source.c_str(), dest.c_str(), float(m_netFrames) / 25.0F);
unsigned char data[M17_FRAME_LENGTH_BYTES + 2U];
data[0U] = TAG_EOT;
data[1U] = 0x00U;
// Generate the sync
for (unsigned int i = 0U; i < M17_FRAME_LENGTH_BYTES; i += M17_SYNC_LENGTH_BYTES)
CSync::addM17EOTSync(data + 2U + i);
writeQueueNet(data);
writeEndNet();
}
}
}
bool CM17Control::processRFHeader(bool lateEntry)
{
unsigned char packetStream = m_rfLSF.getPacketStream();
if (packetStream == M17_PACKET_TYPE)
return false;
unsigned char can = m_rfLSF.getCAN();
if (can != m_can)
return false;
std::string source = m_rfLSF.getSource();
std::string dest = m_rfLSF.getDest();
if (!m_allowEncryption) {
unsigned char type = m_rfLSF.getEncryptionType();
if (type != M17_ENCRYPTION_TYPE_NONE) {
LogMessage("M17, access attempt with encryption from %s to %s", source.c_str(), dest.c_str());
m_rfState = RS_RF_REJECTED;
return true;
}
}
if (m_selfOnly) {
bool ret = checkCallsign(source);
if (!ret) {
LogMessage("M17, invalid access attempt from %s to %s", source.c_str(), dest.c_str());
m_rfState = RS_RF_REJECTED;
return true;
}
}
unsigned char dataType = m_rfLSF.getDataType();
switch (dataType) {
case M17_DATA_TYPE_DATA:
LogMessage("M17, received RF%sdata transmission from %s to %s", lateEntry ? " late entry " : " ", source.c_str(), dest.c_str());
m_rfState = RS_RF_DATA;
break;
case M17_DATA_TYPE_VOICE:
LogMessage("M17, received RF%svoice transmission from %s to %s", lateEntry ? " late entry " : " ", source.c_str(), dest.c_str());
m_rfState = RS_RF_AUDIO;
break;
case M17_DATA_TYPE_VOICE_DATA:
LogMessage("M17, received RF%svoice + data transmission from %s to %s", lateEntry ? " late entry " : " ", source.c_str(), dest.c_str());
m_rfState = RS_RF_DATA_AUDIO;
break;
default:
return false;
}
m_display->writeM17(source.c_str(), dest.c_str(), "R");
if (m_duplex) {
unsigned char data[M17_FRAME_LENGTH_BYTES + 2U];
// Create a Link Setup frame
data[0U] = TAG_HEADER;
data[1U] = 0x00U;
// Generate the sync
CSync::addM17LinkSetupSync(data + 2U);
unsigned char setup[M17_LSF_LENGTH_BYTES];
m_rfLSF.getLinkSetup(setup);
// Add the convolution FEC
CM17Convolution conv;
conv.encodeLinkSetup(setup, data + 2U + M17_SYNC_LENGTH_BYTES);
unsigned char temp[M17_FRAME_LENGTH_BYTES];
interleaver(data + 2U, temp);
decorrelator(temp, data + 2U);
writeQueueRF(data);
}
return true;
}
void CM17Control::clock(unsigned int ms)
{
if (m_network != NULL)
writeNetwork();
m_rfTimeoutTimer.clock(ms);
m_netTimeoutTimer.clock(ms);
if (m_netState == RS_NET_AUDIO || m_netState == RS_NET_DATA_AUDIO) {
m_networkWatchdog.clock(ms);
if (m_networkWatchdog.hasExpired()) {
LogMessage("M17, network watchdog has expired, %.1f seconds", float(m_netFrames) / 25.0F);
writeEndNet();
}
}
}
void CM17Control::writeQueueRF(const unsigned char *data)
{
assert(data != NULL);
if (m_netState != RS_NET_IDLE)
return;
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
return;
const unsigned char len = M17_FRAME_LENGTH_BYTES + 2U;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("M17, overflow in the M17 RF queue");
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
void CM17Control::writeQueueNet(const unsigned char *data)
{
assert(data != NULL);
if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired())
return;
const unsigned char len = M17_FRAME_LENGTH_BYTES + 2U;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("M17, overflow in the M17 RF queue");
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
void CM17Control::interleaver(const unsigned char* in, unsigned char* out) const
{
assert(in != NULL);
assert(out != NULL);
for (unsigned int i = 0U; i < (M17_FRAME_LENGTH_BITS - M17_SYNC_LENGTH_BITS); i++) {
unsigned int n1 = i + M17_SYNC_LENGTH_BITS;
bool b = READ_BIT(in, n1) != 0U;
unsigned int n2 = INTERLEAVER[i] + M17_SYNC_LENGTH_BITS;
WRITE_BIT(out, n2, b);
}
}
void CM17Control::decorrelator(const unsigned char* in, unsigned char* out) const
{
assert(in != NULL);
assert(out != NULL);
for (unsigned int i = M17_SYNC_LENGTH_BYTES; i < M17_FRAME_LENGTH_BYTES; i++) {
out[i] = in[i] ^ SCRAMBLER[i];
}
}
bool CM17Control::checkCallsign(const std::string& callsign) const
{
size_t len = m_callsign.size();
return m_callsign.compare(0U, len, callsign, 0U, len) == 0;
}
bool CM17Control::openFile()
{
if (m_fp != NULL)
return true;
time_t t;
::time(&t);
struct tm* tm = ::localtime(&t);
char name[100U];
::sprintf(name, "M17_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
m_fp = ::fopen(name, "wb");
if (m_fp == NULL)
return false;
::fwrite("M17", 1U, 3U, m_fp);
return true;
}
bool CM17Control::writeFile(const unsigned char* data)
{
if (m_fp == NULL)
return false;
::fwrite(data, 1U, M17_FRAME_LENGTH_BYTES, m_fp);
return true;
}
void CM17Control::closeFile()
{
if (m_fp != NULL) {
::fclose(m_fp);
m_fp = NULL;
}
}
bool CM17Control::isBusy() const
{
return m_rfState != RS_RF_LISTENING || m_netState != RS_NET_IDLE;
}
void CM17Control::enable(bool enabled)
{
if (!enabled && m_enabled) {
m_queue.clear();
// Reset the RF section
m_rfState = RS_RF_LISTENING;
m_rfTimeoutTimer.stop();
// Reset the networking section
m_netState = RS_NET_IDLE;
m_netTimeoutTimer.stop();
m_networkWatchdog.stop();
}
m_enabled = enabled;
}

103
M17Control.h Normal file
View file

@ -0,0 +1,103 @@
/*
* Copyright (C) 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(M17Control_H)
#define M17Control_H
#include "RSSIInterpolator.h"
#include "M17Network.h"
#include "M17Defines.h"
#include "RingBuffer.h"
#include "StopWatch.h"
#include "Display.h"
#include "Defines.h"
#include "M17LSF.h"
#include "Timer.h"
#include "Modem.h"
#include <string>
class CM17Control {
public:
CM17Control(const std::string& callsign, unsigned int can, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper);
~CM17Control();
bool writeModem(unsigned char* data, unsigned int len);
unsigned int readModem(unsigned char* data);
void clock(unsigned int ms);
bool isBusy() const;
void enable(bool enabled);
private:
std::string m_callsign;
unsigned int m_can;
bool m_selfOnly;
bool m_allowEncryption;
CM17Network* m_network;
CDisplay* m_display;
bool m_duplex;
CRingBuffer<unsigned char> m_queue;
RPT_RF_STATE m_rfState;
RPT_NET_STATE m_netState;
CTimer m_rfTimeoutTimer;
CTimer m_netTimeoutTimer;
CTimer m_networkWatchdog;
CStopWatch m_elapsed;
unsigned int m_rfFrames;
unsigned int m_netFrames;
unsigned int m_rfErrs;
unsigned int m_rfBits;
CM17LSF m_rfLSF;
unsigned int m_rfLSFn;
CM17LSF m_netLSF;
unsigned int m_netLSFn;
CRSSIInterpolator* m_rssiMapper;
unsigned char m_rssi;
unsigned char m_maxRSSI;
unsigned char m_minRSSI;
unsigned int m_aveRSSI;
unsigned int m_rssiCount;
bool m_enabled;
FILE* m_fp;
bool processRFHeader(bool lateEntry);
void writeQueueRF(const unsigned char* data);
void writeQueueNet(const unsigned char* data);
void writeNetwork();
void interleaver(const unsigned char* in, unsigned char* out) const;
void decorrelator(const unsigned char* in, unsigned char* out) const;
bool checkCallsign(const std::string& source) const;
void writeEndRF();
void writeEndNet();
bool openFile();
bool writeFile(const unsigned char* data);
void closeFile();
};
#endif

283
M17Convolution.cpp Normal file
View file

@ -0,0 +1,283 @@
/*
* Copyright (C) 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 "M17Convolution.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>
const unsigned int PUNCTURE_LIST_LINK_SETUP_COUNT = 60U;
const unsigned int PUNCTURE_LIST_LINK_SETUP[] = {
2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U, 46U, 50U, 54U, 58U, 63U, 67U, 71U, 75U, 79U, 83U,
87U, 91U, 95U, 99U, 103U, 107U, 111U, 115U, 119U, 124U, 128U, 132U, 136U, 140U, 144U, 148U, 152U, 156U, 160U, 164U, 168U,
172U, 176U, 180U, 185U, 189U, 193U, 197U, 201U, 205U, 209U, 213U, 217U, 221U, 225U, 229U, 233U, 237U, 241U, 246U, 250U, 254U,
258U, 262U, 266U, 270U, 274U, 278U, 282U, 286U, 290U, 294U, 298U, 302U, 307U, 311U, 315U, 319U, 323U, 327U, 331U, 335U, 339U,
343U, 347U, 351U, 355U, 359U, 363U, 368U, 372U, 376U, 380U, 384U, 388U, 392U, 396U, 400U, 404U, 408U, 412U, 416U, 420U, 424U,
429U, 433U, 437U, 441U, 445U, 449U, 453U, 457U, 461U, 465U, 469U, 473U, 477U, 481U, 485U};
const unsigned int PUNCTURE_LIST_DATA_COUNT = 12U;
const unsigned int PUNCTURE_LIST_DATA[] = {
11U, 23U, 35U, 47U, 59U, 71U, 83U, 95U, 107U, 119U, 131U, 143U, 155U, 167U, 179U, 191U, 203U, 215U, 227U, 239U, 251U,
263U, 275U, 287U};
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
const uint8_t BRANCH_TABLE1[] = {0U, 0U, 0U, 0U, 2U, 2U, 2U, 2U};
const uint8_t BRANCH_TABLE2[] = {0U, 2U, 2U, 0U, 0U, 2U, 2U, 0U};
const unsigned int NUM_OF_STATES_D2 = 8U;
const unsigned int NUM_OF_STATES = 16U;
const uint32_t M = 4U;
const unsigned int K = 5U;
CM17Convolution::CM17Convolution() :
m_metrics1(NULL),
m_metrics2(NULL),
m_oldMetrics(NULL),
m_newMetrics(NULL),
m_decisions(NULL),
m_dp(NULL)
{
m_metrics1 = new uint16_t[20U];
m_metrics2 = new uint16_t[20U];
m_decisions = new uint64_t[300U];
}
CM17Convolution::~CM17Convolution()
{
delete[] m_metrics1;
delete[] m_metrics2;
delete[] m_decisions;
}
void CM17Convolution::encodeLinkSetup(const unsigned char* in, unsigned char* out) const
{
assert(in != NULL);
assert(out != NULL);
unsigned char temp1[31U];
::memset(temp1, 0x00U, 31U);
::memcpy(temp1, in, 30U);
unsigned char temp2[61U];
encode(temp1, temp2, 244U);
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 488U; i++) {
if (i != PUNCTURE_LIST_LINK_SETUP[index]) {
bool b = READ_BIT1(temp2, i);
WRITE_BIT1(out, n, b);
n++;
} else {
index++;
}
}
}
void CM17Convolution::encodeData(const unsigned char* in, unsigned char* out) const
{
assert(in != NULL);
assert(out != NULL);
unsigned char temp1[19U];
::memset(temp1, 0x00U, 19U);
::memcpy(temp1, in, 18U);
unsigned char temp2[37U];
encode(temp1, temp2, 148U);
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 296U; i++) {
if (i != PUNCTURE_LIST_DATA[index]) {
bool b = READ_BIT1(temp2, i);
WRITE_BIT1(out, n, b);
n++;
} else {
index++;
}
}
}
unsigned int CM17Convolution::decodeLinkSetup(const unsigned char* in, unsigned char* out)
{
assert(in != NULL);
assert(out != NULL);
uint8_t temp[500U];
::memset(temp, 0x00U, 500U);
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 368U; i++) {
if (n == PUNCTURE_LIST_LINK_SETUP[index]) {
temp[n++] = 1U;
index++;
}
bool b = READ_BIT1(in, i);
temp[n++] = b ? 2U : 0U;
}
start();
n = 0U;
for (unsigned int i = 0U; i < 244U; i++) {
uint8_t s0 = temp[n++];
uint8_t s1 = temp[n++];
decode(s0, s1);
}
return chainback(out, 240U) - PUNCTURE_LIST_LINK_SETUP_COUNT;
}
unsigned int CM17Convolution::decodeData(const unsigned char* in, unsigned char* out)
{
assert(in != NULL);
assert(out != NULL);
uint8_t temp[300U];
::memset(temp, 0x00U, 300U);
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 272U; i++) {
if (n == PUNCTURE_LIST_DATA[index]) {
temp[n++] = 1U;
index++;
}
bool b = READ_BIT1(in, i);
temp[n++] = b ? 2U : 0U;
}
start();
n = 0U;
for (unsigned int i = 0U; i < 148U; i++) {
uint8_t s0 = temp[n++];
uint8_t s1 = temp[n++];
decode(s0, s1);
}
return chainback(out, 144U) - PUNCTURE_LIST_DATA_COUNT;
}
void CM17Convolution::start()
{
::memset(m_metrics1, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
::memset(m_metrics2, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
m_oldMetrics = m_metrics1;
m_newMetrics = m_metrics2;
m_dp = m_decisions;
}
void CM17Convolution::decode(uint8_t s0, uint8_t s1)
{
*m_dp = 0U;
for (uint8_t i = 0U; i < NUM_OF_STATES_D2; i++) {
uint8_t j = i * 2U;
uint16_t metric = std::abs(BRANCH_TABLE1[i] - s0) + std::abs(BRANCH_TABLE2[i] - s1);
uint16_t m0 = m_oldMetrics[i] + metric;
uint16_t m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + (M - metric);
uint8_t decision0 = (m0 >= m1) ? 1U : 0U;
m_newMetrics[j + 0U] = decision0 != 0U ? m1 : m0;
m0 = m_oldMetrics[i] + (M - metric);
m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + metric;
uint8_t decision1 = (m0 >= m1) ? 1U : 0U;
m_newMetrics[j + 1U] = decision1 != 0U ? m1 : m0;
*m_dp |= (uint64_t(decision1) << (j + 1U)) | (uint64_t(decision0) << (j + 0U));
}
++m_dp;
assert((m_dp - m_decisions) <= 300);
uint16_t* tmp = m_oldMetrics;
m_oldMetrics = m_newMetrics;
m_newMetrics = tmp;
}
unsigned int CM17Convolution::chainback(unsigned char* out, unsigned int nBits)
{
assert(out != NULL);
uint32_t state = 0U;
while (nBits-- > 0) {
--m_dp;
uint32_t i = state >> (9 - K);
uint8_t bit = uint8_t(*m_dp >> i) & 1;
state = (bit << 7) | (state >> 1);
WRITE_BIT1(out, nBits, bit != 0U);
}
unsigned int minCost = m_oldMetrics[0];
for (unsigned int i = 0U; i < NUM_OF_STATES; i++) {
if (m_oldMetrics[i] < minCost)
minCost = m_oldMetrics[i];
}
return minCost / (M >> 1);
}
void CM17Convolution::encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const
{
assert(in != NULL);
assert(out != NULL);
assert(nBits > 0U);
uint8_t d1 = 0U, d2 = 0U, d3 = 0U, d4 = 0U;
uint32_t k = 0U;
for (unsigned int i = 0U; i < nBits; i++) {
uint8_t d = READ_BIT1(in, i) ? 1U : 0U;
uint8_t g1 = (d + d3 + d4) & 1;
uint8_t g2 = (d + d1 + d2 + d4) & 1;
d4 = d3;
d3 = d2;
d2 = d1;
d1 = d;
WRITE_BIT1(out, k, g1 != 0U);
k++;
WRITE_BIT1(out, k, g2 != 0U);
k++;
}
}

51
M17Convolution.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 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(M17Convolution_H)
#define M17Convolution_H
#include <cstdint>
class CM17Convolution {
public:
CM17Convolution();
~CM17Convolution();
unsigned int decodeLinkSetup(const unsigned char* in, unsigned char* out);
unsigned int decodeData(const unsigned char* in, unsigned char* out);
void encodeLinkSetup(const unsigned char* in, unsigned char* out) const;
void encodeData(const unsigned char* in, unsigned char* out) const;
private:
uint16_t* m_metrics1;
uint16_t* m_metrics2;
uint16_t* m_oldMetrics;
uint16_t* m_newMetrics;
uint64_t* m_decisions;
uint64_t* m_dp;
void start();
void decode(uint8_t s0, uint8_t s1);
unsigned int chainback(unsigned char* out, unsigned int nBits);
void encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const;
};
#endif

79
M17Defines.h Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 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(M17DEFINES_H)
#define M17DEFINES_H
const unsigned int M17_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int M17_FRAME_LENGTH_BITS = 384U;
const unsigned int M17_FRAME_LENGTH_BYTES = M17_FRAME_LENGTH_BITS / 8U;
const unsigned char M17_LINK_SETUP_SYNC_BYTES[] = {0x55U, 0xF7U};
const unsigned char M17_STREAM_SYNC_BYTES[] = {0xFFU, 0x5DU};
const unsigned char M17_EOT_SYNC_BYTES[] = {0x55U, 0x5DU};
const unsigned int M17_SYNC_LENGTH_BITS = 16U;
const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U;
const unsigned int M17_LSF_LENGTH_BITS = 240U;
const unsigned int M17_LSF_LENGTH_BYTES = M17_LSF_LENGTH_BITS / 8U;
const unsigned int M17_LSF_FRAGMENT_LENGTH_BITS = M17_LSF_LENGTH_BITS / 6U;
const unsigned int M17_LSF_FRAGMENT_LENGTH_BYTES = M17_LSF_FRAGMENT_LENGTH_BITS / 8U;
const unsigned int M17_LICH_FRAGMENT_LENGTH_BITS = M17_LSF_FRAGMENT_LENGTH_BITS + 8U;
const unsigned int M17_LICH_FRAGMENT_LENGTH_BYTES = M17_LICH_FRAGMENT_LENGTH_BITS / 8U;
const unsigned int M17_LSF_FRAGMENT_FEC_LENGTH_BITS = M17_LSF_FRAGMENT_LENGTH_BITS * 2U;
const unsigned int M17_LSF_FRAGMENT_FEC_LENGTH_BYTES = M17_LSF_FRAGMENT_FEC_LENGTH_BITS / 8U;
const unsigned int M17_LICH_FRAGMENT_FEC_LENGTH_BITS = M17_LICH_FRAGMENT_LENGTH_BITS * 2U;
const unsigned int M17_LICH_FRAGMENT_FEC_LENGTH_BYTES = M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 8U;
const unsigned int M17_PAYLOAD_LENGTH_BITS = 128U;
const unsigned int M17_PAYLOAD_LENGTH_BYTES = M17_PAYLOAD_LENGTH_BITS / 8U;
const unsigned char M17_NULL_NONCE[] = {0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
const unsigned int M17_META_LENGTH_BITS = 112U;
const unsigned int M17_META_LENGTH_BYTES = M17_META_LENGTH_BITS / 8U;
const unsigned int M17_FN_LENGTH_BITS = 16U;
const unsigned int M17_FN_LENGTH_BYTES = M17_FN_LENGTH_BITS / 8U;
const unsigned int M17_CRC_LENGTH_BITS = 16U;
const unsigned int M17_CRC_LENGTH_BYTES = M17_CRC_LENGTH_BITS / 8U;
const unsigned char M17_3200_SILENCE[] = {0x01U, 0x00U, 0x09U, 0x43U, 0x9CU, 0xE4U, 0x21U, 0x08U};
const unsigned char M17_1600_SILENCE[] = {0x0CU, 0x41U, 0x09U, 0x03U, 0x0CU, 0x41U, 0x09U, 0x03U};
const unsigned char M17_PACKET_TYPE = 0U;
const unsigned char M17_STREAM_TYPE = 1U;
const unsigned char M17_DATA_TYPE_DATA = 0x01U;
const unsigned char M17_DATA_TYPE_VOICE = 0x02U;
const unsigned char M17_DATA_TYPE_VOICE_DATA = 0x03U;
const unsigned char M17_ENCRYPTION_TYPE_NONE = 0x00U;
const unsigned char M17_ENCRYPTION_TYPE_AES = 0x01U;
const unsigned char M17_ENCRYPTION_TYPE_SCRAMBLE = 0x02U;
const unsigned char M17_ENCRYPTION_SUB_TYPE_TEXT = 0x00U;
const unsigned char M17_ENCRYPTION_SUB_TYPE_GPS = 0x01U;
#endif

199
M17LSF.cpp Normal file
View file

@ -0,0 +1,199 @@
/*
* Copyright (C) 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 "M17LSF.h"
#include "M17Utils.h"
#include "M17Defines.h"
#include "M17CRC.h"
#include <cassert>
#include <cstring>
CM17LSF::CM17LSF() :
m_lsf(NULL),
m_valid(false)
{
m_lsf = new unsigned char[M17_LSF_LENGTH_BYTES];
}
CM17LSF::~CM17LSF()
{
delete[] m_lsf;
}
void CM17LSF::getNetwork(unsigned char* data) const
{
assert(data != NULL);
::memcpy(data, m_lsf, M17_LSF_LENGTH_BYTES);
}
void CM17LSF::setNetwork(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_lsf, data, M17_LSF_LENGTH_BYTES);
m_valid = true;
}
std::string CM17LSF::getSource() const
{
std::string callsign;
CM17Utils::decodeCallsign(m_lsf + 6U, callsign);
return callsign;
}
void CM17LSF::setSource(const std::string& callsign)
{
CM17Utils::encodeCallsign(callsign, m_lsf + 6U);
}
std::string CM17LSF::getDest() const
{
std::string callsign;
CM17Utils::decodeCallsign(m_lsf + 0U, callsign);
return callsign;
}
void CM17LSF::setDest(const std::string& callsign)
{
CM17Utils::encodeCallsign(callsign, m_lsf + 0U);
}
unsigned char CM17LSF::getPacketStream() const
{
return m_lsf[13U] & 0x01U;
}
void CM17LSF::setPacketStream(unsigned char ps)
{
m_lsf[13U] &= 0xF7U;
m_lsf[13U] |= ps & 0x01U;
}
unsigned char CM17LSF::getDataType() const
{
return (m_lsf[13U] >> 1) & 0x03U;
}
void CM17LSF::setDataType(unsigned char type)
{
m_lsf[13U] &= 0xF9U;
m_lsf[13U] |= (type << 1) & 0x06U;
}
unsigned char CM17LSF::getEncryptionType() const
{
return (m_lsf[13U] >> 3) & 0x03U;
}
void CM17LSF::setEncryptionType(unsigned char type)
{
m_lsf[13U] &= 0xE7U;
m_lsf[13U] |= (type << 3) & 0x18U;
}
unsigned char CM17LSF::getEncryptionSubType() const
{
return (m_lsf[13U] >> 5) & 0x03U;
}
void CM17LSF::setEncryptionSubType(unsigned char type)
{
m_lsf[13U] &= 0x9FU;
m_lsf[13U] |= (type << 5) & 0x60U;
}
unsigned char CM17LSF::getCAN() const
{
return ((m_lsf[12U] << 1) & 0x0EU) | ((m_lsf[13U] >> 7) & 0x01U);
}
void CM17LSF::setCAN(unsigned char can)
{
m_lsf[13U] &= 0x7FU;
m_lsf[13U] |= (can << 7) & 0x80U;
m_lsf[12U] &= 0xF8U;
m_lsf[12U] |= (can >> 1) & 0x07U;
}
void CM17LSF::getMeta(unsigned char* data) const
{
assert(data != NULL);
::memcpy(data, m_lsf + 14U, M17_META_LENGTH_BYTES);
}
void CM17LSF::setMeta(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_lsf + 14U, data, M17_META_LENGTH_BYTES);
}
void CM17LSF::reset()
{
::memset(m_lsf, 0x00U, M17_LSF_LENGTH_BYTES);
m_valid = false;
}
bool CM17LSF::isValid() const
{
return m_valid;
}
void CM17LSF::getLinkSetup(unsigned char* data) const
{
assert(data != NULL);
::memcpy(data, m_lsf, M17_LSF_LENGTH_BYTES);
CM17CRC::encodeCRC16(data, M17_LSF_LENGTH_BYTES);
}
void CM17LSF::setLinkSetup(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_lsf, data, M17_LSF_LENGTH_BYTES);
m_valid = CM17CRC::checkCRC16(m_lsf, M17_LSF_LENGTH_BYTES);
}
void CM17LSF::getFragment(unsigned char* data, unsigned int n) const
{
assert(data != NULL);
CM17CRC::encodeCRC16(m_lsf, M17_LSF_LENGTH_BYTES);
::memcpy(data, m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), M17_LSF_FRAGMENT_LENGTH_BYTES);
}
void CM17LSF::setFragment(const unsigned char* data, unsigned int n)
{
assert(data != NULL);
::memcpy(m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), data, M17_LSF_FRAGMENT_LENGTH_BYTES);
m_valid = CM17CRC::checkCRC16(m_lsf, M17_LSF_LENGTH_BYTES);
}

70
M17LSF.h Normal file
View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 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(M17LSF_H)
#define M17LSF_H
#include <string>
class CM17LSF {
public:
CM17LSF();
~CM17LSF();
void getNetwork(unsigned char* data) const;
void setNetwork(const unsigned char* data);
std::string getSource() const;
void setSource(const std::string& callsign);
std::string getDest() const;
void setDest(const std::string& callsign);
unsigned char getPacketStream() const;
void setPacketStream(unsigned char ps);
unsigned char getDataType() const;
void setDataType(unsigned char type);
unsigned char getEncryptionType() const;
void setEncryptionType(unsigned char type);
unsigned char getEncryptionSubType() const;
void setEncryptionSubType(unsigned char type);
unsigned char getCAN() const;
void setCAN(unsigned char can);
void getMeta(unsigned char* data) const;
void setMeta(const unsigned char* data);
void reset();
bool isValid() const;
void getLinkSetup(unsigned char* data) const;
void setLinkSetup(const unsigned char* data);
void getFragment(unsigned char* data, unsigned int n) const;
void setFragment(const unsigned char* data, unsigned int n);
private:
unsigned char* m_lsf;
bool m_valid;
};
#endif

210
M17Network.cpp Normal file
View file

@ -0,0 +1,210 @@
/*
* Copyright (C) 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 "M17Network.h"
#include "M17Defines.h"
#include "M17Utils.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
CM17Network::CM17Network(const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug) :
m_socket(localAddress, localPort),
m_addr(),
m_addrLen(0U),
m_debug(debug),
m_enabled(false),
m_outId(0U),
m_inId(0U),
m_buffer(1000U, "M17 Network"),
m_random(),
m_timer(1000U, 5U)
{
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) {
m_addrLen = 0U;
return;
}
std::random_device rd;
std::mt19937 mt(rd());
m_random = mt;
}
CM17Network::~CM17Network()
{
}
bool CM17Network::open()
{
if (m_addrLen == 0U) {
LogError("M17, unable to resolve the gateway address");
return false;
}
LogMessage("Opening M17 network connection");
bool ret = m_socket.open(m_addr);
if (ret) {
m_timer.start();
return true;
} else {
return false;
}
}
bool CM17Network::write(const unsigned char* data)
{
if (m_addrLen == 0U)
return false;
assert(data != NULL);
unsigned char buffer[100U];
buffer[0U] = 'M';
buffer[1U] = '1';
buffer[2U] = '7';
buffer[3U] = ' ';
// Create a random id for this transmission if needed
if (m_outId == 0U) {
std::uniform_int_distribution<uint16_t> dist(0x0001, 0xFFFE);
m_outId = dist(m_random);
}
buffer[4U] = m_outId / 256U; // Unique session id
buffer[5U] = m_outId % 256U;
::memcpy(buffer + 6U, data, 46U);
// Dummy CRC
buffer[52U] = 0x00U;
buffer[53U] = 0x00U;
if (m_debug)
CUtils::dump(1U, "M17 data transmitted", buffer, 54U);
return m_socket.write(buffer, 54U, m_addr, m_addrLen);
}
void CM17Network::clock(unsigned int ms)
{
m_timer.clock(ms);
if (m_timer.isRunning() && m_timer.hasExpired()) {
sendPing();
m_timer.start();
}
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage address;
unsigned int addrLen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrLen);
if (length <= 0)
return;
if (!CUDPSocket::match(m_addr, address)) {
LogMessage("M17, packet received from an invalid source");
return;
}
if (m_debug)
CUtils::dump(1U, "M17 Network Data Received", buffer, length);
if (!m_enabled)
return;
if (::memcmp(buffer + 0U, "PING", 4U) == 0)
return;
if (::memcmp(buffer + 0U, "M17 ", 4U) != 0) {
CUtils::dump(2U, "M17, received unknown packet", buffer, length);
return;
}
uint16_t id = (buffer[4U] << 8) + (buffer[5U] << 0);
if (m_inId == 0U) {
m_inId = id;
} else {
if (id != m_inId)
return;
}
unsigned char c = length - 6U;
m_buffer.addData(&c, 1U);
m_buffer.addData(buffer + 6U, length - 6U);
}
bool CM17Network::read(unsigned char* data)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return false;
unsigned char c = 0U;
m_buffer.getData(&c, 1U);
m_buffer.getData(data, c);
return true;
}
void CM17Network::close()
{
m_socket.close();
LogMessage("Closing M17 network connection");
}
void CM17Network::reset()
{
m_outId = 0U;
m_inId = 0U;
}
void CM17Network::enable(bool enabled)
{
if (!enabled && m_enabled)
m_buffer.clear();
m_enabled = enabled;
}
void CM17Network::sendPing()
{
unsigned char buffer[5U];
buffer[0U] = 'P';
buffer[1U] = 'I';
buffer[2U] = 'N';
buffer[3U] = 'G';
if (m_debug)
CUtils::dump(1U, "M17 data transmitted", buffer, 4U);
m_socket.write(buffer, 4U, m_addr, m_addrLen);
}

64
M17Network.h Normal file
View file

@ -0,0 +1,64 @@
/*
* Copyright (C) 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.
*/
#ifndef M17Network_H
#define M17Network_H
#include "M17Defines.h"
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <random>
#include <cstdint>
class CM17Network {
public:
CM17Network(const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug);
~CM17Network();
bool open();
void enable(bool enabled);
bool write(const unsigned char* data);
bool read(unsigned char* data);
void reset();
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
sockaddr_storage m_addr;
unsigned int m_addrLen;
bool m_debug;
bool m_enabled;
uint16_t m_outId;
uint16_t m_inId;
CRingBuffer<unsigned char> m_buffer;
std::mt19937 m_random;
CTimer m_timer;
void sendPing();
};
#endif

226
M17Utils.cpp Normal file
View file

@ -0,0 +1,226 @@
/*
* Copyright (C) 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 "M17Utils.h"
#include "M17Defines.h"
#include <cassert>
const std::string M17_CHARS = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
void CM17Utils::encodeCallsign(const std::string& callsign, unsigned char* encoded)
{
assert(encoded != NULL);
if (callsign == "ALL" || callsign == "ALL ") {
encoded[0U] = 0xFFU;
encoded[1U] = 0xFFU;
encoded[2U] = 0xFFU;
encoded[3U] = 0xFFU;
encoded[4U] = 0xFFU;
encoded[5U] = 0xFFU;
return;
}
unsigned int len = callsign.size();
if (len > 9U)
len = 9U;
uint64_t enc = 0ULL;
for (int i = len - 1; i >= 0; i--) {
size_t pos = M17_CHARS.find(callsign[i]);
if (pos == std::string::npos)
pos = 0ULL;
enc *= 40ULL;
enc += pos;
}
encoded[0U] = (enc >> 40) & 0xFFU;
encoded[1U] = (enc >> 32) & 0xFFU;
encoded[2U] = (enc >> 24) & 0xFFU;
encoded[3U] = (enc >> 16) & 0xFFU;
encoded[4U] = (enc >> 8) & 0xFFU;
encoded[5U] = (enc >> 0) & 0xFFU;
}
void CM17Utils::decodeCallsign(const unsigned char* encoded, std::string& callsign)
{
assert(encoded != NULL);
callsign.clear();
if (encoded[0U] == 0xFFU && encoded[1U] == 0xFFU && encoded[2U] == 0xFFU &&
encoded[3U] == 0xFFU && encoded[4U] == 0xFFU && encoded[5U] == 0xFFU) {
callsign = "ALL";
return;
}
uint64_t enc =
(uint64_t(encoded[0U]) << 40) +
(uint64_t(encoded[1U]) << 32) +
(uint64_t(encoded[2U]) << 24) +
(uint64_t(encoded[3U]) << 16) +
(uint64_t(encoded[4U]) << 8) +
(uint64_t(encoded[5U]) << 0);
if (enc >= 262144000000000ULL) // 40^9
return;
while (enc > 0ULL) {
callsign += " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."[enc % 40ULL];
enc /= 40ULL;
}
}
void CM17Utils::splitFragmentLICH(const unsigned char* data, unsigned int& frag1, unsigned int& frag2, unsigned int& frag3, unsigned int& frag4)
{
assert(data != NULL);
frag1 = frag2 = frag3 = frag4 = 0x00U;
unsigned int offset = 0U;
unsigned int MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag1 |= MASK;
}
MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag2 |= MASK;
}
MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag3 |= MASK;
}
MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag4 |= MASK;
}
}
void CM17Utils::splitFragmentLICHFEC(const unsigned char* data, unsigned int& frag1, unsigned int& frag2, unsigned int& frag3, unsigned int& frag4)
{
assert(data != NULL);
frag1 = frag2 = frag3 = frag4 = 0x00U;
unsigned int offset = 0U;
unsigned int MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag1 |= MASK;
}
MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag2 |= MASK;
}
MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag3 |= MASK;
}
MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = READ_BIT1(data, offset) != 0x00U;
if (b)
frag4 |= MASK;
}
}
void CM17Utils::combineFragmentLICH(unsigned int frag1, unsigned int frag2, unsigned int frag3, unsigned int frag4, unsigned char* data)
{
assert(data != NULL);
unsigned int offset = 0U;
unsigned int MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag1 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag2 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag3 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
MASK = 0x800U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag4 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
}
void CM17Utils::combineFragmentLICHFEC(unsigned int frag1, unsigned int frag2, unsigned int frag3, unsigned int frag4, unsigned char* data)
{
assert(data != NULL);
unsigned int offset = 0U;
unsigned int MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag1 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag2 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag3 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
MASK = 0x800000U;
for (unsigned int i = 0U; i < (M17_LICH_FRAGMENT_FEC_LENGTH_BITS / 4U); i++, offset++, MASK >>= 1) {
bool b = (frag4 & MASK) == MASK;
WRITE_BIT1(data, offset, b);
}
}

41
M17Utils.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 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.
*/
#if !defined(M17Utils_H)
#define M17Utils_H
#include <string>
class CM17Utils {
public:
CM17Utils();
~CM17Utils();
static void encodeCallsign(const std::string& callsign, unsigned char* encoded);
static void decodeCallsign(const unsigned char* encoded, std::string& callsign);
static void splitFragmentLICH(const unsigned char* data, unsigned int& frag1, unsigned int& frag2, unsigned int& frag3, unsigned int& frag4);
static void splitFragmentLICHFEC(const unsigned char* data, unsigned int& frag1, unsigned int& frag2, unsigned int& frag3, unsigned int& frag4);
static void combineFragmentLICH(unsigned int frag1, unsigned int frag2, unsigned int frag3, unsigned int frag4, unsigned char* data);
static void combineFragmentLICHFEC(unsigned int frag1, unsigned int frag2, unsigned int frag3, unsigned int frag4, unsigned char* data);
private:
};
#endif

207
MMDVM.ini
View file

@ -1,6 +1,6 @@
[General]
Callsign=MUTRPT
Id=1337
Callsign=G9BF
Id=123456
Timeout=180
Duplex=1
# ModeHang=10
@ -13,6 +13,13 @@ Daemon=0
RXFrequency=435000000
TXFrequency=435000000
Power=1
# The following lines are only needed if a direct connection to a DMR master is being used
Latitude=0.0
Longitude=0.0
Height=0
Location=Nowhere
Description=Multi-Mode Repeater
URL=www.google.co.uk
[Log]
# Logging levels, 0=No logging
@ -31,6 +38,10 @@ Time=10
File=DMRIds.dat
Time=24
[NXDN Id Lookup]
File=NXDN.csv
Time=24
[Modem]
# Valid values are "null", "uart", "udp", and (on Linux) "i2c"
Protocol=uart
@ -60,7 +71,16 @@ TXLevel=50
RXDCOffset=0
TXDCOffset=0
RFLevel=100
DMRTXLevel=50
# CWIdTXLevel=50
# D-StarTXLevel=50
# DMRTXLevel=50
# YSFTXLevel=50
# P25TXLevel=50
# NXDNTXLevel=50
# M17TXLevel=50
# POCSAGTXLevel=50
# FMTXLevel=50
# AX25TXLevel=50
RSSIMappingFile=RSSI.dat
UseCOSAsLockout=0
Trace=0
@ -73,12 +93,24 @@ RemotePort=40094
LocalPort=40095
# SendFrameType=0
[D-Star]
Enable=1
Module=C
SelfOnly=0
AckReply=1
AckTime=750
AckMessage=0
ErrorReply=1
RemoteGateway=0
# ModeHang=10
WhiteList=
[DMR]
Enable=1
Beacons=0
BeaconInterval=60
BeaconDuration=3
ColorCode=7
ColorCode=1
SelfOnly=0
EmbeddedLCOnly=0
DumpTAData=1
@ -91,11 +123,110 @@ TXHang=4
# OVCM Values, 0=off, 1=rx_on, 2=tx_on, 3=both_on, 4=force off
# OVCM=0
[System Fusion]
Enable=1
LowDeviation=0
SelfOnly=0
TXHang=4
RemoteGateway=0
# ModeHang=10
[P25]
Enable=1
NAC=293
SelfOnly=0
OverrideUIDCheck=0
RemoteGateway=0
TXHang=5
# ModeHang=10
[NXDN]
Enable=1
RAN=1
SelfOnly=0
RemoteGateway=0
TXHang=5
# ModeHang=10
[M17]
Enable=1
CAN=0
SelfOnly=0
TXHang=5
# ModeHang=10
[POCSAG]
Enable=1
Frequency=439987500
[FM]
Enable=1
# Callsign=G4KLX
CallsignSpeed=20
CallsignFrequency=1000
CallsignTime=10
CallsignHoldoff=0
CallsignHighLevel=50
CallsignLowLevel=20
CallsignAtStart=1
CallsignAtEnd=1
CallsignAtLatch=0
RFAck=K
ExtAck=N
AckSpeed=20
AckFrequency=1750
AckMinTime=4
AckDelay=1000
AckLevel=50
# Timeout=180
TimeoutLevel=80
CTCSSFrequency=88.4
CTCSSThreshold=30
# CTCSSHighThreshold=30
# CTCSSLowThreshold=20
CTCSSLevel=20
KerchunkTime=0
HangTime=7
# AccessMode values are:
# 0 - Carrier access with COS
# 1 - CTCSS only access without COS
# 2 - CTCSS only access with COS
# 3 - CTCSS only access with COS to start, then carrier access with COS
AccessMode=1
# LinkMode=1 to remove almost all of the logic control
LinkMode=0
COSInvert=0
NoiseSquelch=0
SquelchThreshold=30
# SquelchHighThreshold=30
# SquelchLowThreshold=20
RFAudioBoost=1
MaxDevLevel=90
ExtAudioBoost=1
# ModeHang=10
[AX.25]
Enable=1
TXDelay=300
RXTwist=6
SlotTime=30
PPersist=128
Trace=1
[D-Star Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=20011
GatewayAddress=127.0.0.1
GatewayPort=20010
# ModeHang=3
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=Direct
Type=Gateway
LocalAddress=127.0.0.1
LocalPort=62032
RemoteAddress=127.0.0.1
@ -108,6 +239,72 @@ Slot2=1
# ModeHang=3
Debug=0
[System Fusion Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=3200
GatewayAddress=127.0.0.1
GatewayPort=4200
# ModeHang=3
Debug=0
[P25 Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=32010
GatewayAddress=127.0.0.1
GatewayPort=42020
# ModeHang=3
Debug=0
[NXDN Network]
Enable=1
Protocol=Icom
LocalAddress=127.0.0.1
LocalPort=14021
GatewayAddress=127.0.0.1
GatewayPort=14020
# ModeHang=3
Debug=0
[M17 Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=17011
GatewayAddress=127.0.0.1
GatewayPort=17010
# ModeHang=3
Debug=0
[POCSAG Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=3800
GatewayAddress=127.0.0.1
GatewayPort=4800
# ModeHang=3
Debug=0
[FM Network]
Enable=1
# Protocol=USRP
LocalAddress=127.0.0.1
LocalPort=3810
GatewayAddress=127.0.0.1
GatewayPort=4810
PreEmphasis=1
DeEmphasis=1
TXAudioGain=1.0
RXAudioGain=1.0
# ModeHang=3
Debug=0
[AX.25 Network]
Enable=1
Port=/dev/ttyp7
Speed=9600
Debug=0
[TFT Serial]
# Port=modem
Port=/dev/ttyAMA0

File diff suppressed because it is too large Load diff

View file

@ -20,27 +20,27 @@
#define MMDVMHOST_H
#include "RemoteControl.h"
//#include "POCSAGNetwork.h"
//#include "POCSAGControl.h"
//#include "DStarNetwork.h"
//#include "AX25Network.h"
//#include "NXDNNetwork.h"
//#include "DStarControl.h"
//#include "AX25Control.h"
#include "POCSAGNetwork.h"
#include "POCSAGControl.h"
#include "DStarNetwork.h"
#include "AX25Network.h"
#include "NXDNNetwork.h"
#include "DStarControl.h"
#include "AX25Control.h"
#include "DMRControl.h"
//#include "YSFControl.h"
//#include "P25Control.h"
//#include "NXDNControl.h"
//#include "M17Control.h"
//#include "NXDNLookup.h"
//#include "YSFNetwork.h"
//#include "P25Network.h"
#include "YSFControl.h"
#include "P25Control.h"
#include "NXDNControl.h"
#include "M17Control.h"
#include "NXDNLookup.h"
#include "YSFNetwork.h"
#include "P25Network.h"
#include "DMRNetwork.h"
//#include "M17Network.h"
//#include "FMNetwork.h"
#include "M17Network.h"
#include "FMNetwork.h"
#include "DMRLookup.h"
//#include "FMControl.h"
//#include "Display.h"
#include "FMControl.h"
#include "Display.h"
#include "Timer.h"
#include "Modem.h"
#include "Conf.h"
@ -57,15 +57,28 @@ public:
int run();
void buildNetworkStatusString(std::string &str);
void buildNetworkHostsString(std::string &str);
private:
CConf m_conf;
CModem* m_modem;
CDStarControl* m_dstar;
CDMRControl* m_dmr;
CYSFControl* m_ysf;
CP25Control* m_p25;
CNXDNControl* m_nxdn;
CM17Control* m_m17;
CPOCSAGControl* m_pocsag;
CFMControl* m_fm;
CAX25Control* m_ax25;
CDStarNetwork* m_dstarNetwork;
IDMRNetwork* m_dmrNetwork;
CYSFNetwork* m_ysfNetwork;
CP25Network* m_p25Network;
INXDNNetwork* m_nxdnNetwork;
CM17Network* m_m17Network;
CPOCSAGNetwork* m_pocsagNetwork;
CFMNetwork* m_fmNetwork;
CAX25Network* m_ax25Network;
CDisplay* m_display;
unsigned char m_mode;
unsigned int m_dstarRFModeHang;
@ -99,6 +112,7 @@ private:
bool m_ax25Enabled;
unsigned int m_cwIdTime;
CDMRLookup* m_dmrLookup;
CNXDNLookup* m_nxdnLookup;
std::string m_callsign;
unsigned int m_id;
std::string m_cwCallsign;

41
MMDVMHost.sln Normal file
View file

@ -0,0 +1,41 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.271
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMDVMHost", "MMDVMHost.vcxproj", "{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RemoteCommand", "RemoteCommand.vcxproj", "{5A61AB93-58BB-413A-BBD9-A26284CB37AE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x64.ActiveCfg = Debug|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x64.Build.0 = Debug|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x86.ActiveCfg = Debug|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x86.Build.0 = Debug|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x64.ActiveCfg = Release|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x64.Build.0 = Release|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.ActiveCfg = Release|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.Build.0 = Release|Win32
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x64.ActiveCfg = Debug|x64
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x64.Build.0 = Debug|x64
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x86.ActiveCfg = Debug|Win32
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x86.Build.0 = Debug|Win32
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x64.ActiveCfg = Release|x64
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x64.Build.0 = Release|x64
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x86.ActiveCfg = Release|Win32
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4FE84D69-7345-440E-8E0A-0CC1C84477F8}
EndGlobalSection
EndGlobal

376
MMDVMHost.vcxproj Normal file
View file

@ -0,0 +1,376 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>MMDVMHost</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_LOG_H;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_LOG_H;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>"$(ProjectDir)prebuild.cmd" $(ProjectDir)</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>prebuild.cmd generates GitVersion.h from git refs heads master</Message>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_LOG_H;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_LOG_H;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AMBEFEC.h" />
<ClInclude Include="AX25Control.h" />
<ClInclude Include="AX25Defines.h" />
<ClInclude Include="AX25Network.h" />
<ClInclude Include="BCH.h" />
<ClInclude Include="BPTC19696.h" />
<ClInclude Include="CASTInfo.h" />
<ClInclude Include="Conf.h" />
<ClInclude Include="CRC.h" />
<ClInclude Include="Defines.h" />
<ClInclude Include="Display.h" />
<ClInclude Include="DMRAccessControl.h" />
<ClInclude Include="DMRControl.h" />
<ClInclude Include="DMRCSBK.h" />
<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" />
<ClInclude Include="DMRSlot.h" />
<ClInclude Include="DMRSlotType.h" />
<ClInclude Include="DMRTA.h" />
<ClInclude Include="DMRTrellis.h" />
<ClInclude Include="DStarControl.h" />
<ClInclude Include="DStarDefines.h" />
<ClInclude Include="DStarHeader.h" />
<ClInclude Include="DStarNetwork.h" />
<ClInclude Include="DStarSlowData.h" />
<ClInclude Include="FMControl.h" />
<ClInclude Include="FMNetwork.h" />
<ClInclude Include="Golay2087.h" />
<ClInclude Include="Golay24128.h" />
<ClInclude Include="Hamming.h" />
<ClInclude Include="DMRLookup.h" />
<ClInclude Include="IIRDirectForm1Filter.h" />
<ClInclude Include="LCDproc.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="M17Control.h" />
<ClInclude Include="M17Convolution.h" />
<ClInclude Include="M17CRC.h" />
<ClInclude Include="M17Defines.h" />
<ClInclude Include="M17LSF.h" />
<ClInclude Include="M17Network.h" />
<ClInclude Include="M17Utils.h" />
<ClInclude Include="MMDVMHost.h" />
<ClInclude Include="ModemPort.h" />
<ClInclude Include="ModemSerialPort.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="NetworkInfo.h" />
<ClInclude Include="Nextion.h" />
<ClInclude Include="NullController.h" />
<ClInclude Include="NullDisplay.h" />
<ClInclude Include="NXDNAudio.h" />
<ClInclude Include="NXDNControl.h" />
<ClInclude Include="NXDNConvolution.h" />
<ClInclude Include="NXDNCRC.h" />
<ClInclude Include="NXDNDefines.h" />
<ClInclude Include="NXDNFACCH1.h" />
<ClInclude Include="NXDNIcomNetwork.h" />
<ClInclude Include="NXDNKenwoodNetwork.h" />
<ClInclude Include="NXDNLayer3.h" />
<ClInclude Include="NXDNLICH.h" />
<ClInclude Include="NXDNLookup.h" />
<ClInclude Include="NXDNNetwork.h" />
<ClInclude Include="NXDNUDCH.h" />
<ClInclude Include="P25Audio.h" />
<ClInclude Include="P25Control.h" />
<ClInclude Include="P25Defines.h" />
<ClInclude Include="P25Data.h" />
<ClInclude Include="P25LowSpeedData.h" />
<ClInclude Include="P25Network.h" />
<ClInclude Include="P25NID.h" />
<ClInclude Include="P25Trellis.h" />
<ClInclude Include="P25Utils.h" />
<ClInclude Include="POCSAGControl.h" />
<ClInclude Include="POCSAGDefines.h" />
<ClInclude Include="POCSAGNetwork.h" />
<ClInclude Include="PseudoTTYController.h" />
<ClInclude Include="QR1676.h" />
<ClInclude Include="RemoteControl.h" />
<ClInclude Include="RingBuffer.h" />
<ClInclude Include="RS129.h" />
<ClInclude Include="RS241213.h" />
<ClInclude Include="RSSIInterpolator.h" />
<ClInclude Include="NXDNSACCH.h" />
<ClInclude Include="UARTController.h" />
<ClInclude Include="Modem.h" />
<ClInclude Include="SerialPort.h" />
<ClInclude Include="SHA256.h" />
<ClInclude Include="SMeter.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Sync.h" />
<ClInclude Include="TFTSurenoo.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="UDPController.h" />
<ClInclude Include="UDPSocket.h" />
<ClInclude Include="UserDB.h" />
<ClInclude Include="UserDBentry.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="Version.h" />
<ClInclude Include="YSFControl.h" />
<ClInclude Include="YSFConvolution.h" />
<ClInclude Include="YSFDefines.h" />
<ClInclude Include="YSFFICH.h" />
<ClInclude Include="YSFNetwork.h" />
<ClInclude Include="YSFPayload.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AMBEFEC.cpp" />
<ClCompile Include="AX25Control.cpp" />
<ClCompile Include="AX25Network.cpp" />
<ClCompile Include="BCH.cpp" />
<ClCompile Include="BPTC19696.cpp" />
<ClCompile Include="CASTInfo.cpp" />
<ClCompile Include="Conf.cpp" />
<ClCompile Include="CRC.cpp" />
<ClCompile Include="Display.cpp" />
<ClCompile Include="DMRAccessControl.cpp" />
<ClCompile Include="DMRControl.cpp" />
<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" />
<ClCompile Include="DMRShortLC.cpp" />
<ClCompile Include="DMRSlot.cpp" />
<ClCompile Include="DMRSlotType.cpp" />
<ClCompile Include="DMRTA.cpp" />
<ClCompile Include="DMRTrellis.cpp" />
<ClCompile Include="DStarControl.cpp" />
<ClCompile Include="DStarHeader.cpp" />
<ClCompile Include="DStarNetwork.cpp" />
<ClCompile Include="DStarSlowData.cpp" />
<ClCompile Include="FMControl.cpp" />
<ClCompile Include="FMNetwork.cpp" />
<ClCompile Include="Golay2087.cpp" />
<ClCompile Include="Golay24128.cpp" />
<ClCompile Include="Hamming.cpp" />
<ClCompile Include="IIRDirectForm1Filter.cpp" />
<ClCompile Include="LCDproc.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="M17Control.cpp" />
<ClCompile Include="M17Convolution.cpp" />
<ClCompile Include="M17CRC.cpp" />
<ClCompile Include="M17LSF.cpp" />
<ClCompile Include="M17Network.cpp" />
<ClCompile Include="M17Utils.cpp" />
<ClCompile Include="MMDVMHost.cpp" />
<ClCompile Include="ModemPort.cpp" />
<ClCompile Include="ModemSerialPort.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="NetworkInfo.cpp" />
<ClCompile Include="Nextion.cpp" />
<ClCompile Include="NullController.cpp" />
<ClCompile Include="NullDisplay.cpp" />
<ClCompile Include="NXDNAudio.cpp" />
<ClCompile Include="NXDNControl.cpp" />
<ClCompile Include="NXDNConvolution.cpp" />
<ClCompile Include="NXDNCRC.cpp" />
<ClCompile Include="NXDNFACCH1.cpp" />
<ClCompile Include="NXDNIcomNetwork.cpp" />
<ClCompile Include="NXDNKenwoodNetwork.cpp" />
<ClCompile Include="NXDNLayer3.cpp" />
<ClCompile Include="NXDNLICH.cpp" />
<ClCompile Include="NXDNLookup.cpp" />
<ClCompile Include="NXDNNetwork.cpp" />
<ClCompile Include="NXDNSACCH.cpp" />
<ClCompile Include="NXDNUDCH.cpp" />
<ClCompile Include="P25Audio.cpp" />
<ClCompile Include="P25Control.cpp" />
<ClCompile Include="P25Data.cpp" />
<ClCompile Include="P25LowSpeedData.cpp" />
<ClCompile Include="P25Network.cpp" />
<ClCompile Include="P25NID.cpp" />
<ClCompile Include="P25Trellis.cpp" />
<ClCompile Include="P25Utils.cpp" />
<ClCompile Include="POCSAGControl.cpp" />
<ClCompile Include="POCSAGNetwork.cpp" />
<ClCompile Include="PseudoTTYController.cpp" />
<ClCompile Include="QR1676.cpp" />
<ClCompile Include="RemoteControl.cpp" />
<ClCompile Include="RS129.cpp" />
<ClCompile Include="RS241213.cpp" />
<ClCompile Include="RSSIInterpolator.cpp" />
<ClCompile Include="UARTController.cpp" />
<ClCompile Include="Modem.cpp" />
<ClCompile Include="SerialPort.cpp" />
<ClCompile Include="SHA256.cpp" />
<ClCompile Include="SMeter.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Sync.cpp" />
<ClCompile Include="TFTSurenoo.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPController.cpp" />
<ClCompile Include="UDPSocket.cpp" />
<ClCompile Include="UserDB.cpp" />
<ClCompile Include="UserDBentry.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="YSFNetwork.cpp" />
<ClCompile Include="YSFPayload.cpp" />
<ClCompile Include="YSFControl.cpp" />
<ClCompile Include="YSFConvolution.cpp" />
<ClCompile Include="YSFFICH.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

662
MMDVMHost.vcxproj.filters Normal file
View file

@ -0,0 +1,662 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="BPTC19696.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Conf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CRC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Display.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRData.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRDefines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRSlot.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DStarDefines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Golay2087.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Golay24128.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Hamming.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Log.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MMDVMHost.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NullDisplay.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="QR1676.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RemoteControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RingBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RS129.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StopWatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UDPSocket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFDefines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AMBEFEC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DStarNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRDataHeader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DStarHeader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DStarSlowData.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DStarControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFConvolution.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFFICH.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRCSBK.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Sync.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMREMB.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMREmbeddedData.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRFullLC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRLC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRShortLC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRSlotType.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFPayload.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Nextion.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRLookup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Thread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRTrellis.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRAccessControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Control.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25NID.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Audio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Data.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25LowSpeedData.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BCH.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RS241213.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SerialPort.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ModemSerialPort.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Mutex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LCDproc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RSSIInterpolator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NetworkInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Trellis.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNDefines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNLICH.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNConvolution.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNCRC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNLookup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNSACCH.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNFACCH1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNUDCH.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNLayer3.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNAudio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="POCSAGNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="POCSAGControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="POCSAGDefines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRTA.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CASTInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TFTSurenoo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UserDB.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UserDBentry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AX25Control.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AX25Network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNIcomNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNKenwoodNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Control.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17LSF.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17CRC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Convolution.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AX25Defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FMNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FMControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IIRDirectForm1Filter.h">
<Filter>Header Files</Filter>
</ClInclude>
<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>
<ClInclude Include="UARTController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UDPController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NullController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Modem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ModemPort.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SMeter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Conf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CRC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Display.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRSlot.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Golay2087.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Golay24128.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Hamming.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MMDVMHost.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NullDisplay.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="QR1676.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RemoteControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RS129.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StopWatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UDPSocket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AMBEFEC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DStarNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRDataHeader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DStarHeader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DStarSlowData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DStarControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="YSFConvolution.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="YSFFICH.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRCSBK.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Sync.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMREMB.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMREmbeddedData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRFullLC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRLC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRShortLC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRSlotType.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="YSFControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="YSFPayload.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Nextion.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRLookup.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="YSFNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRTrellis.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRAccessControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Control.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25NID.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Audio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Data.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25LowSpeedData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BCH.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RS241213.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SerialPort.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ModemSerialPort.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Mutex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LCDproc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RSSIInterpolator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NetworkInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Trellis.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNLICH.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNConvolution.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNCRC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNLookup.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNSACCH.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNFACCH1.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNUDCH.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNLayer3.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNAudio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="POCSAGNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="POCSAGControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRTA.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CASTInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TFTSurenoo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UserDB.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UserDBentry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AX25Control.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AX25Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNIcomNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNKenwoodNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17Control.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17CRC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17LSF.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17Convolution.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FMNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FMControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IIRDirectForm1Filter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<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>
<ClCompile Include="UARTController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UDPController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NullController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Modem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ModemPort.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SMeter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -7,13 +7,15 @@ LIBS = -lpthread -lutil
LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
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 \
DMRAccessControl.o DMRTA.o DMRTrellis.o Golay2087.o Golay24128.o\
Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o \
Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \
RemoteControl.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o \
Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.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 \
Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \
NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o \
Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -7,13 +7,15 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil
LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \
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 \
DMRAccessControl.o DMRTA.o DMRTrellis.o Golay2087.o Golay24128.o\
Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o \
Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \
RemoteControl.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o \
Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.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 \
Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \
NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o \
Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

69
Makefile.Pi.Adafruit Normal file
View file

@ -0,0 +1,69 @@
# This makefile is for use with the Raspberry Pi when using an HD44780 compatible display. The wiringpi library is needed.
# Support for the Adafruit i2c 16 x 2 RGB LCD Pi Plate
CC = cc
CXX = c++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include
LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil
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 \
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 Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \
NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \
NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \
POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \
TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \
YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand
MMDVMHost: GitVersion.h $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
RemoteCommand: Log.o RemoteCommand.o UDPSocket.o
$(CXX) Log.o RemoteCommand.o UDPSocket.o $(CFLAGS) $(LIBS) -o RemoteCommand
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
.PHONY install:
install: all
install -m 755 MMDVMHost /usr/local/bin/
install -m 755 RemoteCommand /usr/local/bin/
.PHONY install-service:
install-service: install /etc/MMDVM.ini
@useradd --user-group -M --system mmdvm --shell /bin/false || true
@usermod --groups dialout --append mmdvm || true
@mkdir /var/log/mmdvm || true
@chown mmdvm:mmdvm /var/log/mmdvm
@cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/
@systemctl enable mmdvmhost.service
/etc/MMDVM.ini:
@cp -n MMDVM.ini /etc/MMDVM.ini
@sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini
@sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini
@chown mmdvm:mmdvm /etc/MMDVM.ini
.PHONY uninstall-service:
uninstall-service:
@systemctl stop mmdvmhost.service || true
@systemctl disable mmdvmhost.service || true
@rm -f /usr/local/bin/MMDVMHost || true
@rm -f /lib/systemd/system/mmdvmhost.service || true
clean:
$(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifneq ("$(wildcard .git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
else
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
endif

68
Makefile.Pi.HD44780 Normal file
View file

@ -0,0 +1,68 @@
# This makefile is for use with the Raspberry Pi when using an HD44780 compatible display. The wiringpi library is needed.
CC = cc
CXX = c++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DHD44780 -I/usr/local/include
LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil
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 \
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 Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \
NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \
NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \
POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \
TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \
YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand
MMDVMHost: GitVersion.h $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
RemoteCommand: Log.o RemoteCommand.o UDPSocket.o
$(CXX) Log.o RemoteCommand.o UDPSocket.o $(CFLAGS) $(LIBS) -o RemoteCommand
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
.PHONY install:
install: all
install -m 755 MMDVMHost /usr/local/bin/
install -m 755 RemoteCommand /usr/local/bin/
.PHONY install-service:
install-service: install /etc/MMDVM.ini
@useradd --user-group -M --system mmdvm --shell /bin/false || true
@usermod --groups dialout --append mmdvm || true
@mkdir /var/log/mmdvm || true
@chown mmdvm:mmdvm /var/log/mmdvm
@cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/
@systemctl enable mmdvmhost.service
/etc/MMDVM.ini:
@cp -n MMDVM.ini /etc/MMDVM.ini
@sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini
@sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini
@chown mmdvm:mmdvm /etc/MMDVM.ini
.PHONY uninstall-service:
uninstall-service:
@systemctl stop mmdvmhost.service || true
@systemctl disable mmdvmhost.service || true
@rm -f /usr/local/bin/MMDVMHost || true
@rm -f /lib/systemd/system/mmdvmhost.service || true
clean:
$(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifneq ("$(wildcard .git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
else
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
endif

72
Makefile.Pi.OLED Normal file
View file

@ -0,0 +1,72 @@
# This makefile is for use with the Raspberry Pi when using an OLED display. The wiringpi library is not needed.
CC = cc
CXX = c++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DOLED -I/usr/local/include
LIBS = -lArduiPi_OLED -lpthread -lutil
# If you use NetBSD, add following CFLAGS
#CFLAGS += -L/usr/local/lib -Wl,-rpath=/usr/local/lib
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 \
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 \
Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \
NXDNUDCH.o OLED.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \
POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \
TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand
MMDVMHost: GitVersion.h $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
RemoteCommand: Log.o RemoteCommand.o UDPSocket.o
$(CXX) Log.o RemoteCommand.o UDPSocket.o $(CFLAGS) $(LIBS) -o RemoteCommand
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
.PHONY install:
install: all
install -m 755 MMDVMHost /usr/local/bin/
install -m 755 RemoteCommand /usr/local/bin/
.PHONY install-service:
install-service: install /etc/MMDVM.ini
@useradd --user-group -M --system mmdvm --shell /bin/false || true
@usermod --groups dialout --append mmdvm || true
@mkdir /var/log/mmdvm || true
@chown mmdvm:mmdvm /var/log/mmdvm
@cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/
@systemctl enable mmdvmhost.service
/etc/MMDVM.ini:
@cp -n MMDVM.ini /etc/MMDVM.ini
@sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini
@sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini
@chown mmdvm:mmdvm /etc/MMDVM.ini
.PHONY uninstall-service:
uninstall-service:
@systemctl stop mmdvmhost.service || true
@systemctl disable mmdvmhost.service || true
@rm -f /usr/local/bin/MMDVMHost || true
@rm -f /lib/systemd/system/mmdvmhost.service || true
clean:
$(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifneq ("$(wildcard .git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
else
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
endif

69
Makefile.Pi.PCF8574 Normal file
View file

@ -0,0 +1,69 @@
# This makefile is for use with the Raspberry Pi when using an HD44780 compatible display. The wiringpi library is needed.
# Support for the HD44780 connected via a PCF8574 8-bit GPIO expander IC
CC = cc
CXX = c++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include
LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil
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 \
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 Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \
NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \
NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \
POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \
TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \
YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand
MMDVMHost: GitVersion.h $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
RemoteCommand: Log.o RemoteCommand.o UDPSocket.o
$(CXX) Log.o RemoteCommand.o UDPSocket.o $(CFLAGS) $(LIBS) -o RemoteCommand
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
.PHONY install:
install: all
install -m 755 MMDVMHost /usr/local/bin/
install -m 755 RemoteCommand /usr/local/bin/
.PHONY install-service:
install-service: install /etc/MMDVM.ini
@useradd --user-group -M --system mmdvm --shell /bin/false || true
@usermod --groups dialout --append mmdvm || true
@mkdir /var/log/mmdvm || true
@chown mmdvm:mmdvm /var/log/mmdvm
@cp ./linux/systemd/mmdvmhost.service /lib/systemd/system/
@systemctl enable mmdvmhost.service
/etc/MMDVM.ini:
@cp -n MMDVM.ini /etc/MMDVM.ini
@sed -i 's/FilePath=./FilePath=\/var\/log\/mmdvm\//' /etc/MMDVM.ini
@sed -i 's/Daemon=0/Daemon=1/' /etc/MMDVM.ini
@chown mmdvm:mmdvm /etc/MMDVM.ini
.PHONY uninstall-service:
uninstall-service:
@systemctl stop mmdvmhost.service || true
@systemctl disable mmdvmhost.service || true
@rm -f /usr/local/bin/MMDVMHost || true
@rm -f /lib/systemd/system/mmdvmhost.service || true
clean:
$(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifneq ("$(wildcard .git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
else
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
endif

1609
Modem.cpp

File diff suppressed because it is too large Load diff

103
Modem.h
View file

@ -46,9 +46,9 @@ public:
~CModem();
void setPort(IModemPort* port);
void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel);
void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency);
void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool m17Enabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled);
void setLevels(float rxLevel, float cwIdTXLevel, float dmrTXLevel);
void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float m17TXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel);
void setDMRParams(unsigned int colorCode);
void setYSFParams(bool loDev, unsigned int txHang);
void setP25Params(unsigned int txHang);
@ -104,9 +104,24 @@ public:
bool hasError() const;
bool writeConfig();
bool writeDStarData(const unsigned char* data, unsigned int length);
bool writeDMRData1(const unsigned char* data, unsigned int length);
bool writeDMRData2(const unsigned char* data, unsigned int length);
bool writeYSFData(const unsigned char* data, unsigned int length);
bool writeP25Data(const unsigned char* data, unsigned int length);
bool writeNXDNData(const unsigned char* data, unsigned int length);
bool writeM17Data(const unsigned char* data, unsigned int length);
bool writePOCSAGData(const unsigned char* data, unsigned int length);
bool writeFMData(const unsigned char* data, unsigned int length);
bool writeAX25Data(const unsigned char* data, unsigned int length);
bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
bool writeYSFInfo(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin);
bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type);
bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type);
bool writeM17Info(const char* source, const char* dest, const char* type);
bool writePOCSAGInfo(unsigned int ric, const std::string& message);
bool writeIPInfo(const std::string& address);
bool writeDMRStart(bool tx);
@ -133,6 +148,11 @@ public:
private:
unsigned int m_protocolVersion;
unsigned int m_dmrColorCode;
bool m_ysfLoDev;
unsigned int m_ysfTXHang;
unsigned int m_p25TXHang;
unsigned int m_nxdnTXHang;
unsigned int m_m17TXHang;
bool m_duplex;
bool m_rxInvert;
bool m_txInvert;
@ -141,15 +161,31 @@ private:
unsigned int m_dmrDelay;
float m_rxLevel;
float m_cwIdTXLevel;
float m_dstarTXLevel;
float m_dmrTXLevel;
float m_ysfTXLevel;
float m_p25TXLevel;
float m_nxdnTXLevel;
float m_m17TXLevel;
float m_pocsagTXLevel;
float m_fmTXLevel;
float m_ax25TXLevel;
float m_rfLevel;
bool m_useCOSAsLockout;
bool m_trace;
bool m_debug;
unsigned int m_rxFrequency;
unsigned int m_txFrequency;
unsigned int m_pocsagFrequency;
bool m_dstarEnabled;
bool m_dmrEnabled;
bool m_ysfEnabled;
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_m17Enabled;
bool m_pocsagEnabled;
bool m_fmEnabled;
bool m_ax25Enabled;
int m_rxDCOffset;
int m_txDCOffset;
IModemPort* m_port;
@ -158,10 +194,25 @@ private:
unsigned int m_offset;
SERIAL_STATE m_state;
unsigned char m_type;
CRingBuffer<unsigned char> m_rxDStarData;
CRingBuffer<unsigned char> m_txDStarData;
CRingBuffer<unsigned char> m_rxDMRData1;
CRingBuffer<unsigned char> m_rxDMRData2;
CRingBuffer<unsigned char> m_txDMRData1;
CRingBuffer<unsigned char> m_txDMRData2;
CRingBuffer<unsigned char> m_rxYSFData;
CRingBuffer<unsigned char> m_txYSFData;
CRingBuffer<unsigned char> m_rxP25Data;
CRingBuffer<unsigned char> m_txP25Data;
CRingBuffer<unsigned char> m_rxNXDNData;
CRingBuffer<unsigned char> m_txNXDNData;
CRingBuffer<unsigned char> m_rxM17Data;
CRingBuffer<unsigned char> m_txM17Data;
CRingBuffer<unsigned char> m_txPOCSAGData;
CRingBuffer<unsigned char> m_rxFMData;
CRingBuffer<unsigned char> m_txFMData;
CRingBuffer<unsigned char> m_rxAX25Data;
CRingBuffer<unsigned char> m_txAX25Data;
CRingBuffer<unsigned char> m_rxSerialData;
CRingBuffer<unsigned char> m_txSerialData;
CRingBuffer<unsigned char> m_rxTransparentData;
@ -170,14 +221,62 @@ private:
CTimer m_statusTimer;
CTimer m_inactivityTimer;
CTimer m_playoutTimer;
unsigned int m_dstarSpace;
unsigned int m_dmrSpace1;
unsigned int m_dmrSpace2;
unsigned int m_ysfSpace;
unsigned int m_p25Space;
unsigned int m_nxdnSpace;
unsigned int m_m17Space;
unsigned int m_pocsagSpace;
unsigned int m_fmSpace;
unsigned int m_ax25Space;
bool m_tx;
bool m_cd;
bool m_lockout;
bool m_error;
unsigned char m_mode;
HW_TYPE m_hwType;
int m_ax25RXTwist;
unsigned int m_ax25TXDelay;
unsigned int m_ax25SlotTime;
unsigned int m_ax25PPersist;
std::string m_fmCallsign;
unsigned int m_fmCallsignSpeed;
unsigned int m_fmCallsignFrequency;
unsigned int m_fmCallsignTime;
unsigned int m_fmCallsignHoldoff;
float m_fmCallsignHighLevel;
float m_fmCallsignLowLevel;
bool m_fmCallsignAtStart;
bool m_fmCallsignAtEnd;
bool m_fmCallsignAtLatch;
std::string m_fmRfAck;
std::string m_fmExtAck;
unsigned int m_fmAckSpeed;
unsigned int m_fmAckFrequency;
unsigned int m_fmAckMinTime;
unsigned int m_fmAckDelay;
float m_fmAckLevel;
unsigned int m_fmTimeout;
float m_fmTimeoutLevel;
float m_fmCtcssFrequency;
unsigned int m_fmCtcssHighThreshold;
unsigned int m_fmCtcssLowThreshold;
float m_fmCtcssLevel;
unsigned int m_fmKerchunkTime;
unsigned int m_fmHangTime;
unsigned int m_fmAccessMode;
bool m_fmLinkMode;
bool m_fmCOSInvert;
bool m_fmNoiseSquelch;
unsigned int m_fmSquelchHighThreshold;
unsigned int m_fmSquelchLowThreshold;
unsigned int m_fmRFAudioBoost;
unsigned int m_fmExtAudioBoost;
float m_fmMaxDevLevel;
bool m_fmExtEnable;
unsigned char m_capabilities1;
unsigned char m_capabilities2;

2339
NXDN.csv Normal file

File diff suppressed because it is too large Load diff

577
NXDNAudio.cpp Normal file
View file

@ -0,0 +1,577 @@
/*
* 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 "NXDNAudio.h"
#include "Golay24128.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 PRNG_TABLE[] = {
0x42CC47U, 0x19D6FEU, 0x304729U, 0x6B2CD0U, 0x60BF47U, 0x39650EU, 0x7354F1U, 0xEACF60U, 0x819C9FU, 0xDE25CEU,
0xD7B745U, 0x8CC8B8U, 0x8D592BU, 0xF71257U, 0xBCA084U, 0xA5B329U, 0xEE6AFAU, 0xF7D9A7U, 0xBCC21CU, 0x4712D9U,
0x4F2922U, 0x14FA37U, 0x5D43ECU, 0x564115U, 0x299A92U, 0x20A9EBU, 0x7B707DU, 0x3BE3A4U, 0x20D95BU, 0x6B085AU,
0x5233A5U, 0x99A474U, 0xC0EDCBU, 0xCB5F12U, 0x918455U, 0xF897ECU, 0xE32E3BU, 0xAA7CC2U, 0xB1E7C9U, 0xFC561DU,
0xA70DE6U, 0x8DBE73U, 0xD4F608U, 0x57658DU, 0x0E5E56U, 0x458DABU, 0x7E15B8U, 0x376645U, 0x2DFD86U, 0x64EC3BU,
0x3F1F60U, 0x3481B4U, 0x4DA00FU, 0x067BCEU, 0x1B68B1U, 0xD19328U, 0xCA03FFU, 0xA31856U, 0xF8EB81U, 0xF9F2F8U,
0xA26067U, 0xA91BB6U, 0xF19A59U, 0x9A6148U, 0x8372B6U, 0xC8E86FU, 0x9399DCU, 0x1A0291U, 0x619142U, 0x6DE9FFU,
0x367A2CU, 0x7D2511U, 0x6484DAU, 0x2F1F0FU, 0x1E6DB4U, 0x55F6E1U, 0x0EA70AU, 0x061C96U, 0xDD0E45U, 0xB4D738U,
0xAF64ABU, 0xE47F42U, 0xFDBE9DU, 0xB684ACU, 0xFE5773U, 0xC1E4A2U, 0x8AFD0DU, 0x932ED4U, 0xD814E3U, 0x81853AU,
0x225EECU, 0x7A6945U, 0x31A112U, 0x2AB2EBU, 0x630974U, 0x785AB5U, 0x11E3CEU, 0x4A715BU, 0x402AA0U, 0x199B7DU,
0x16C05EU, 0x6F5283U, 0xA4FB10U, 0xBFA8ECU, 0xF633B7U, 0xEC4012U, 0xADD8C9U, 0xD6EB1CU, 0xDD3027U, 0x84A1FAU,
0xCF9E19U, 0xD64C80U, 0xBC4557U, 0xA7B62EU, 0x6E2DA1U, 0x311F50U, 0x38C68EU, 0x63D5BFU, 0x486E60U, 0x10BFE1U,
0x5BAD1EU, 0x4A4647U, 0x0157F0U, 0x7ACC29U, 0x73BEEAU, 0x2825D7U, 0xA0940CU, 0xFBCFF9U, 0xB05C62U, 0x892426U,
0xC6B3DDU, 0xDF3840U, 0x9449B3U, 0xCED3BEU, 0xE7804DU, 0xBC3B90U, 0xF5AA0BU, 0xE6D17EU, 0x2D43B5U, 0x345A04U,
0x5EA9DBU, 0x07A202U, 0x0C7134U, 0x45C9FDU, 0x5EDA0AU, 0x310193U, 0x6830C4U, 0x62AA3DU, 0x3B59B2U, 0xB04043U,
0xEB975CU, 0x82BCADU, 0x912E62U, 0xD8F7FBU, 0x82C489U, 0x895F54U, 0xF00FE7U, 0xFBBC2AU, 0xA2E771U, 0xE956C4U,
0xF6CD1FU, 0x3F8FEAU, 0x0534E1U, 0x4C653CU, 0x17FE8FU, 0x1C4C52U, 0x4515A1U, 0x2E86A9U, 0x3FBD56U, 0x756C87U,
0x6ED218U, 0x279179U, 0x7C0AA6U, 0xD53B17U, 0x8EE0C8U, 0x85F291U, 0xD94B36U, 0x9298EFU, 0xAB8318U, 0xE07301U,
0xBB68DFU, 0xB2CB7CU, 0xE910A5U, 0xE101D2U, 0x92BB4BU, 0x59E8B4U, 0x407175U, 0x0B026AU, 0x12989BU, 0x792944U,
0x2376EDU, 0x2EF5BAU, 0x758663U, 0x7C1ED5U, 0x078D0CU, 0x4EF6ABU, 0x5567F2U, 0x9F7C29U, 0xC68E9CU, 0xC51747U,
0xBC6422U, 0xB7EFB9U, 0xECFD44U, 0xA50497U, 0xAF178AU, 0xD68C69U, 0xD97DB5U, 0x82670EU, 0xCBB45BU, 0x508D90U,
0x190A25U, 0x63F0FEU, 0x68E3C7U, 0x317A10U, 0x3A09D9U, 0x6B926EU, 0x004237U, 0x1B79C8U, 0x53EA59U, 0x48B3B7U,
0x811166U, 0xDE4A79U, 0xF5F988U, 0xAC6057U, 0xE733FEU, 0xFF89ADU, 0xB49830U, 0x8F4BC3U, 0xC6F00EU, 0x9DA135U,
0x942FE0U, 0xC71C3BU, 0x4DC78FU, 0x3476C4U, 0x7F6C39U, 0x66BFAAU, 0x298657U, 0x725504U, 0x5B4E89U, 0x01FE72U,
0x0835A3U, 0x53269CU, 0x189D4DU, 0x01CDC2U, 0xEA763BU, 0xF3A56DU, 0xB0BCD4U, 0xE80F13U, 0xE355CAU, 0x98C47DU,
0x91AB24U, 0xCE38DBU, 0x87A35AU, 0x9CD3A5U, 0xD648F4U, 0xAF7B6FU, 0x24A292U, 0x7D3011U, 0x764B6DU, 0x2DDABEU,
0x44D123U, 0x5E22D8U, 0x1FB09DU, 0x04A926U, 0x4F5AF3U, 0x064128U, 0x3DB105U, 0x70AAD6U, 0xAA392FU, 0xA1C4B8U,
0xF8C7C0U, 0xD35D0FU, 0x8A2E9EU, 0xC1B761U, 0xDA44F0U, 0x925E8FU, 0x89CF4EU, 0xE8B4D1U, 0xB32728U, 0xB8FE7FU,
0x61DCC6U, 0x2A4701U, 0x1614D8U, 0x5DADE2U, 0x46BE37U, 0x0F44DCU, 0x54D549U, 0x5D8E32U, 0x263DAFU, 0x2C237CU,
0x75E291U, 0xBE5982U, 0xA74A7FU, 0xC493A4U, 0xDFA131U, 0x967A5AU, 0xCCCB8EU, 0xC1D835U, 0x9A02ECU, 0xF331BBU,
0xE8B812U, 0xA3EBC5U, 0xBA507CU, 0x7080ABU, 0x099BC2U, 0x02285DU, 0x59718CU, 0x50C273U, 0x0B1862U, 0x4A1F8CU,
0x70A655U, 0x3BF5C2U, 0x666FBBU, 0x6DDE68U, 0x3485C5U, 0x9F161EU, 0xC46F4BU, 0x8CFDF0U, 0x97C625U, 0xDE058EU,
0xC59CD3U, 0xAEAE20U, 0xF775BCU, 0xFC647FU, 0xBD9F02U, 0xE70C91U, 0xCC1468U, 0x11E7B7U, 0x1AFC36U, 0x435B49U,
0x080398U, 0x139027U, 0x7B63FEU, 0x607AF9U, 0x29E900U, 0x7293D6U, 0x79026FU, 0x00D930U, 0x0BEAF1U, 0xD3614EU,
0x90119FU, 0x8B8AE4U, 0xC61969U, 0xBD609AU, 0xB4F247U, 0xEFA954U, 0xE518A9U, 0xBC0362U, 0xD7D0D6U, 0xCE7E8DU,
0x856F18U, 0x1C94E3U, 0x578726U, 0x0D5F1DU, 0x24ECC0U, 0x7FF713U, 0x3E26AAU, 0x251D6DU, 0x6A8F14U, 0x53648BU,
0x19757AU, 0x40AEB4U, 0xCB9CA5U, 0x90055AU, 0x9956C3U, 0xE2ED34U, 0xAB3C7DU, 0xB126EAU, 0xFA9513U, 0xA3D2C8U,
0x886BFDU, 0xD9F836U, 0xD2A2E3U, 0x8D1359U, 0x454804U, 0x5EDBF7U, 0x37637AU, 0x2C3089U, 0x67ABD4U, 0x3E8847U,
0x3551BAU, 0x4D6331U, 0x46B8C4U, 0x1D299FU, 0x54120EU, 0x5FC0E1U, 0x86D93BU, 0xE56A0EU, 0xFBB1D5U, 0xB2B600U,
0xA94EABU, 0xE05DF6U, 0x9BE605U, 0x90B798U, 0xC92C6BU, 0xC3DE66U, 0x9AC7BDU, 0xD15448U, 0x6A3FD3U, 0x23ADA3U,
0x78346CU, 0x7147F5U, 0x2BDC02U, 0x0EAD5BU, 0x553FFCU, 0x1EA425U, 0x07D5F2U, 0x4C4ECBU, 0x554C14U, 0x3EB3F5U,
0xE4A26AU, 0xED799BU, 0xB6CA85U, 0xFFD25CU, 0xC421BFU, 0x8F3A22U, 0x96AB51U, 0xDC518CU, 0x895217U, 0x8289F2U,
0xF9B8A9U, 0xF0231CU, 0x2BF1C7U, 0x62C80AU, 0x781B39U, 0x1320E5U, 0x4AB156U, 0x41EB8FU, 0x1848E0U, 0x13D771U,
0x4886AEU, 0x203C5FU, 0x3B6F40U, 0x76F6A1U, 0xE5457EU, 0xAE1EE7U, 0xD7AC10U, 0xDCB549U, 0x8476EFU, 0x8FC536U,
0xD49DE9U, 0x9D0ED8U, 0xA63513U, 0xEFE4A6U, 0xB4DF7DU, 0x3E0D00U, 0x779693U, 0x4CA75EU, 0x0568ADU, 0x527BB0U,
0x59C34BU, 0x00109FU, 0x0A0B14U, 0x73FA61U, 0x38E0BAU, 0x23530FU, 0x6A88D4U, 0xB199DDU, 0x98322AU, 0xC260F3U,
0xCBF944U, 0x908A0DU, 0xDB11F2U, 0xC28163U, 0xADFABDU, 0xBC694CU, 0xF65243U, 0xAD83BAU, 0xA40D6DU, 0x5F7EF4U,
0x16E787U, 0x0DF44AU, 0x460EF1U, 0x5E1F24U, 0x15CC3FU, 0x6C77CAU, 0x676401U, 0x3C9CBDU, 0x359FEEU, 0x6A0413U,
0x02F590U, 0x91EE4DU, 0xDA3C3EU, 0xC305A3U, 0x889658U, 0xF14D99U, 0xFA7F86U, 0xA1E677U, 0xE981E8U, 0xF21A10U,
0xBB4BD7U, 0x80F1CEU, 0xCB6239U, 0x123BE0U, 0x1D885FU, 0x45921EU, 0x6641E1U, 0x3DE870U, 0x74BBAFU, 0x6F00C6U,
0x261055U, 0x7DCBA8U, 0x57787AU, 0x0E2167U, 0x05B28CU, 0xCC8819U, 0x975BE2U, 0xBC52B7U, 0xE5E52CU, 0xEB37C9U,
0xB20E12U, 0xF9DD2FU, 0xE8C6FCU, 0x837701U, 0xD8AD82U, 0xD1BE5AU, 0x0B0525U, 0x0244B4U, 0x79FE5BU, 0x322DCAU,
0x2B3495U, 0x60876CU, 0x79DCFBU, 0x334C12U, 0x4C7745U, 0x45A4DCU, 0x1E3F23U, 0x175FF2U, 0xC4C0D8U, 0xAFF30DU,
0xB72AF6U, 0xFCB96BU, 0xA5C338U, 0xAE5295U, 0xF54946U, 0xDCBABBU, 0x87A1A8U, 0xCF2165U, 0xD4DA9EU, 0x9FC90BU,
0x223070U, 0x6922A4U, 0x30B92FU, 0x3348D6U, 0x695B01U, 0x20C038U, 0x1BB2EFU, 0x523B06U, 0x49EC99U, 0x02D7C8U,
0x5B4777U, 0x713CA6U, 0xA8AF49U, 0xA3B650U, 0xF84586U, 0xB5DF7FU, 0xAE8CF8U, 0xC72581U, 0x9D3652U, 0x9EEDCFU,
0xC75D34U, 0xCC0671U, 0xB5B5CAU, 0xFEAC1FU, 0x677EA4U, 0x2DC5F9U, 0x26D63AU, 0x7F1F86U, 0x142855U, 0x0DF2A8U,
0x42E3B3U, 0x195872U, 0x108B8DU, 0x6AB31CU, 0x632063U, 0x307BAAU, 0xFBC83DU, 0xE201C4U, 0xA91393U, 0x90A82AU,
0xDAF9E4U, 0x816A55U, 0x88D00AU, 0xD383DBU, 0xFA3A64U, 0xA569A5U, 0xEEE2DEU, 0x76D243U, 0x3D0D90U, 0x649E6DU,
0x47E76EU, 0x1C7491U, 0x156E49U, 0x4E9DDEU, 0x0604B7U, 0x3D3720U, 0x76FDD9U, 0x6FEC06U, 0x2417B7U, 0xFD04F8U,
0xF29D29U, 0x886F92U, 0xC1744FU, 0xDAC73CU, 0x939EB1U, 0x880C63U, 0xEBE79EU, 0xB2F285U, 0xB86970U, 0xE11ABBU,
0xEA822EU, 0x311155U, 0x586AC0U, 0x43F92BU, 0x0A81F6U, 0x5412C5U, 0x5D111CU, 0x26E8CBU, 0x2D7B63U, 0x74213CU,
0x3F90CDU, 0x2E8B52U, 0x645883U, 0xDFE36CU, 0x96F375U, 0xDD0882U, 0xC40B1BU, 0x8FD6CCU, 0xB464A5U, 0xFC7F3EU,
0xA7AECBU, 0xAA9511U, 0xF10634U, 0xBA5CEFU, 0x83ED32U, 0x483681U, 0x5015DCU, 0x138D3FU, 0x48DEA2U, 0x616571U,
0x3AF40CU, 0x33AF97U, 0x681D72U, 0x2246E9U, 0x3BD7B9U, 0x506C46U, 0x0D2FDFU, 0x869338U, 0xDDC061U, 0xD45BD6U,
0xAF6A0FU, 0xE7B8C0U, 0xFC2371U, 0xBF102EU, 0xA6C9DFU, 0xEDDA40U, 0x943089U, 0x9FA1BFU, 0x459A66U, 0x0C4995U,
0x175108U, 0x7AE243U, 0x6139B6U, 0x2A2A2DU, 0x73D3D8U, 0x79C183U, 0x204A26U, 0x0B3FFDU, 0x5AA420U, 0x111613U,
0x8A4FDFU, 0xC3DC2CU, 0xF9A7B5U, 0xB034EAU, 0xEBAC5BU, 0xE0CF94U, 0xBD5465U, 0xF605FAU, 0xCFBEA3U, 0x85AC54U,
0x9E55DDU, 0xD7C62AU, 0x0CDD73U, 0x252FCDU, 0x76361CU, 0x7DF5D3U, 0x3546E2U, 0x6E5B39U, 0x67A98CU, 0x1CB247U,
0x57231AU, 0x4AD8A9U, 0x01CA74U, 0x191187U, 0xF2208AU, 0xA9AB50U, 0xA0F8A5U, 0xFB403EU, 0xF2D34BU, 0xA9A880U,
0xCB393DU, 0xD262EEU, 0x99D0B7U, 0xC04B00U, 0xCB1AC9U, 0xB0B176U, 0x39E3A7U, 0x677EF8U, 0x2ECD58U, 0x359687U,
0x7E277EU, 0x473D69U, 0x0CEEB0U, 0x55D557U, 0x5F04CEU, 0x0C8EBDU, 0x25BD60U, 0x7E64DBU, 0xB7771EU, 0xACCC05U,
0xE51CF0U, 0xBF2F2AU, 0x90F497U, 0xC9E7D4U, 0xC25F09U, 0x9B9CBAU, 0xD08767U, 0xEB320CU, 0xA36999U, 0x38FB42U,
0x7180B3U, 0x22112CU, 0x29AA45U, 0x50F9D2U, 0x1B610AU, 0x0202FDU, 0x4899E4U, 0x57080BU, 0x3E72DAU, 0x65E165U,
0x6CFA34U, 0xB70BEBU, 0xBC104AU, 0xE4E295U, 0x8F7BECU, 0x96787FU, 0xD583B2U, 0x9E9740U, 0x870C5DU, 0xECFFA6U,
0xF4E433U, 0xBF35F8U, 0xE00F8DU, 0x699C16U, 0x3265EBU, 0x1B6638U, 0x40F515U, 0x0A8DC6U, 0x131E1BU, 0x5845A0U,
0x21F670U, 0x2A6E1FU, 0x791D8EU, 0x708651U, 0x2AD7E8U, 0xE37CAFU, 0xD8EE56U, 0x97B3C1U, 0x8E0018U, 0xC51B6FU,
0x9CC9E6U, 0xB67019U, 0xEF23C8U, 0xE498F2U, 0xBF9927U, 0xF643ECU, 0xCD7051U, 0x04E902U, 0x563AFFU, 0x5D006CU,
0x04D3A1U, 0x0FCA9AU, 0x72794FU, 0x39A2B4U, 0x228231U, 0x6A19EAU, 0x714E96U, 0x18F705U, 0x4324FCU, 0xC83E3BU,
0x918D02U, 0xDADCD5U, 0xC2470CU, 0xA135B3U, 0xBABCF2U, 0xF30F4DU, 0xA8549EU, 0xA1C543U, 0xDEFF78U, 0xD42CBCU,
0x0DB747U, 0x46C6D2U, 0x5F5C89U, 0x144F60U, 0x6FA6F7U, 0x66350EU, 0x2C0A59U, 0x35DAE0U, 0x7EC12FU, 0x0D32FEU,
0x0429C1U, 0x5FB911U, 0xD642AEU, 0x895167U, 0xC3D8B0U, 0xFAAB89U, 0xB1315AU, 0xA8C0A7U, 0xE3DB24U, 0xB84879U,
0x913382U, 0xCBA317U, 0x82F8FCU, 0x994BA9U, 0x50C213U, 0x4390CEU, 0x282F5DU, 0x713E30U, 0x7FCDE3U, 0x26565EU,
0x2D0485U, 0x56BDD4U, 0x1FAE7BU, 0x0475AAU, 0x4DD555U, 0x17CE4CU, 0x9C1D9BU, 0xE52473U, 0xEEF7E4U, 0xB7CD1DU,
0xF45E42U, 0xEF87E3U, 0x87B43CU, 0x986FADU, 0xD16FD2U, 0x8AD403U, 0x8103A8U, 0xD83A75U, 0x33A826U, 0x2BF39BU,
0x604049U, 0x7B99A4U, 0x328ABFU, 0x49306AU, 0x407191U, 0x1BEA04U, 0x19D96FU, 0x4001F2U, 0x0FB201U, 0x36E9DCU,
0xFD7ADFU, 0xE64326U, 0xAF91F9U, 0xF51249U, 0xDC2B16U, 0x87F8D7U, 0xCCE668U, 0xC517B1U, 0x9E8C46U, 0x97BF5FU,
0xED6498U, 0xA67461U, 0x378FF6U, 0x788C8FU, 0x611514U, 0x0AE6F1U, 0x53FC2BU, 0x596F3EU, 0x0216C5U, 0x4B8508U,
0x507FBBU, 0x396EE6U, 0x22F535U, 0xE99688U, 0xB10F43U, 0xBA1D36U, 0xC3E2ADU, 0xC07178U, 0x9B28C3U, 0xD69A8BU,
0xCD817CU, 0x8570E5U, 0xFEEB12U, 0xF5E8CBU, 0xAC10C4U, 0x270335U, 0x7ED8EAU, 0x156B5BU, 0x0E7A14U, 0x46A0C5U,
0x5D937AU, 0x144AA3U, 0x4F79D5U, 0x6CF35CU, 0x31228FU, 0x7A1932U, 0x628E69U, 0xA9D59CU, 0x926517U, 0xDBBEE2U,
0x80ADB9U, 0x891424U, 0xD246D7U, 0xD8ED1AU, 0xA17C28U, 0xEA27F5U, 0xF3942EU, 0xB8CE8FU, 0xAB5FD0U, 0x466461U,
0x1CB7BEU, 0x152F6FU, 0x4E1CC0U, 0x05D799U, 0x1CE66EU, 0x773DF7U, 0x7EAB00U, 0x249048U, 0x6D41D7U, 0x765A26U,
0x1DA9F9U, 0x8431C8U, 0xCF0203U, 0x96C1DEU, 0x90D86DU, 0xCB6A30U, 0xA23193U, 0xB9A24EU, 0xF05B95U, 0xEB48A0U,
0xA0D27AU, 0xD8A39FU, 0xD33804U, 0x0A9B79U, 0x01C3AAU, 0x5A5437U, 0x132FD4U, 0x28BC0DU, 0x60253AU, 0x3F57E3U,
0x3CCC7CU, 0x65DD9DU, 0x4E26C2U, 0x172572U, 0xDCDDADU, 0xC64E64U, 0x8F5553U, 0x94A68AU, 0xFDBE7DU, 0xA66DE4U,
0xADD68BU, 0xF4C75AU, 0xFE0CC1U, 0x873E34U, 0xC8A72FU, 0xDBD0C2U, 0x124B10U, 0x49998DU, 0x40A8FEU, 0x3A3323U,
0x316088U, 0x68D95DU, 0x235B06U, 0x3A00B3U, 0x51B178U, 0x4AEA89U, 0x025816U, 0x59C36FU, 0xD092B8U, 0x8B2930U,
0xE43AC7U, 0xF5E2DEU, 0xBEC121U, 0xA71AF0U, 0xED8B7FU, 0x94B40EU, 0x9F66D1U, 0xD45D68U, 0xCD8CBFU, 0x8617F6U,
0x5F2545U, 0x75FC98U, 0x2EFF62U, 0x674467U, 0x7C959CU, 0x318F09U, 0x0A7CD2U, 0x4967AFU, 0x11D62CU, 0x1A8CD1U,
0x431F02U, 0x48A69DU, 0xB3E5ECU, 0xFA7623U, 0xE10E9AU, 0xA99948U, 0xB20215U, 0xD971A6U, 0x80E86BU, 0x8BDA90U,
0xD60185U, 0x9D907EU, 0x8FFBFBU, 0xE66920U, 0x7D705DU, 0x3483CEU, 0x6F9833U, 0x646BF1U, 0x1DF3E8U, 0x17E017U,
0x4E1BC6U, 0x050A79U, 0x1E8038U, 0x5773E7U, 0x2C685EU, 0xA1BD89U, 0xFB86B0U, 0xF01477U, 0xA16D8EU, 0xCAFE19U,
0xD365C1U, 0x9815AEU, 0x839E3FU, 0xCBCDC4U, 0x907611U, 0xB9E70AU, 0xE2BDE7U, 0x2B0E34U, 0x301789U, 0x7BE4DAU,
0x477707U, 0x0C2FACU, 0x558C79U, 0x5E9743U, 0x0D4496U, 0x04786DU, 0x7FABE0U, 0x3730B3U, 0x3C014AU, 0xE7DADDU,
0xEEE834U, 0x956163U, 0xDCB2FAU, 0xC78905U, 0x8D5BD4U, 0xD0427BU, 0xDBF12BU, 0xA22AB4U, 0xA93B4DU, 0xFA819AU,
0xB3D2B3U, 0x287B64U, 0x40289DU, 0x5BB206U, 0x100153U, 0x495CB8U, 0x42CF2DU, 0x3BF4D6U, 0x70248BU, 0x6ABF19U,
0x23CCF4U, 0x3C4527U, 0x75761AU, 0x8EACC1U, 0x853F44U, 0xD44EBFU, 0xDED5EEU, 0x87C751U, 0xEC3E80U, 0xF72D6FU,
0xBEB676U, 0xE557A1U, 0xEC4D59U, 0xB6BECEU, 0x9DA527U, 0x443078U, 0x0BCAE9U, 0x12D916U, 0x594087U, 0x6033E8U,
0x22A831U, 0x7948A2U, 0x70535FU, 0x2BC01CU, 0x62BBA1U, 0x592A7BU, 0x92308EU, 0x8AC395U, 0xC15A50U, 0x9809ABU,
0xB3B336U, 0xECB245U, 0xE54998U, 0xBEDA1BU, 0xF681E6U, 0xED35F5U, 0x8E2E0CU, 0x87FDD3U, 0x5CC453U, 0x1556ACU,
0x0E85FDU, 0x64AC42U, 0x3D7F8BU, 0x36447CU, 0x6FD665U, 0x640FB2U, 0x3B3C4BU, 0x52A7C4U, 0x48F7B5U, 0x014C2EU,
0x9A9FFBU, 0xD19601U, 0xA0250CU, 0xAB7FFFU, 0xF2C822U, 0xB8D1B1U, 0xA302CCU, 0xEAB907U, 0xD1E9B2U, 0x987269U,
0xC3411CU, 0xCC8897U, 0x141A42U, 0x3F61B8U, 0x66F2A1U, 0x2DCB56U, 0x3618DFU, 0x778208U, 0x2CB3F1U, 0x0468EEU,
0x5F7B1FU, 0x5693D0U, 0x0D8041U, 0x461B3EU, 0xFFECE7U, 0xB4FD50U, 0xA94798U, 0xE314CFU, 0xB88D76U, 0xB17EADU,
0xCA7508U, 0xC3E553U, 0x989EA6U, 0xDB0D3DU, 0xC396E8U, 0xA8E683U, 0x717D1EU, 0x7A0EEDU, 0x219730U, 0x288422U,
0x736ECFU, 0x1BFF14U, 0x04A4A1U, 0x4F177AU, 0x56092BU, 0x1DD884U, 0x64635DU, 0xEF70EAU, 0xA589B3U, 0xF49B54U,
0xFF50CDU, 0xA66312U, 0x8DFA62U, 0xD628FDU, 0x9F131CU, 0x8582C3U, 0xCCF9DAU, 0xF36A29U, 0xB8B2F4U, 0x618157U,
0x6A020AU, 0x335999U, 0x79E864U, 0x4272BFU, 0x03259AU, 0x189C40U, 0x51CFB5U, 0x0A752EU, 0x216463U, 0x79BF90U,
0x721C0DU, 0xAB47FEU, 0xE4D727U, 0xFDEC28U, 0x963FD9U, 0x8DA646U, 0xC594B7U, 0x9E4FE8U, 0x977E60U, 0xECA597U,
0xAF264EU, 0xB61C79U, 0xFDCDA0U, 0x65D64FU, 0x2E61DCU, 0x553881U, 0x5CAA72U, 0x0351FBU, 0x0A400CU, 0x51FB55U,
0x3BB9CAU, 0x22223AU, 0x6993B5U, 0x30C8C4U, 0x3B5B1BU, 0xE02B82U, 0xC1B075U, 0x9B23BCU, 0xD25A8BU, 0xC9C852U,
0x82A3A9U, 0xBB303CU, 0xF42977U, 0xADDA82U, 0xA64418U, 0xFC55E5U, 0xB5AEE6U, 0x0EBD3BU, 0x4765C8U, 0x4CD655U,
0x17DD2EU, 0x562EEBU, 0x6C3770U, 0x25A585U, 0x3E5EDEU, 0x754F6FU, 0x2C94A1U, 0x23A758U, 0x5A3F4FU, 0xD07C96U,
0x8BC761U, 0xC254E8U, 0xD92C97U, 0xB0BF06U, 0xEBE0D9U, 0xE25138U, 0xB8CAA7U, 0xBB98DEU, 0xE22109U, 0x896291U,
0x10F172U, 0x5BCB2FU, 0x401A94U, 0x0CA141U, 0x77B2BAU, 0x7E6BBFU, 0x255964U, 0x6E82D9U, 0x77130AU, 0x3C3877U,
0x04EAF4U, 0x4FD129U, 0x9C40DBU, 0x959BC6U, 0xCEAC2DU, 0xE774FCU, 0xBC6763U, 0xF6DC12U, 0xEB8DCDU, 0xA00664U,
0xF9F4B3U, 0xD2EF4AU, 0x895E5DU, 0x800584U, 0x5A972BU, 0x132EFBU, 0x287D84U, 0x63E615U, 0x7297CEU, 0x391D23U,
0x608E30U, 0x6AF5CDU, 0x11641EU, 0x5C5E93U, 0x4789E0U, 0x0E903DU, 0x956386U, 0xFEF053U, 0xB6E879U, 0xAD0BACU,
0xE41077U, 0xFF83CAU, 0xB47A99U, 0xCD6870U, 0xCE93E7U, 0x96823EU, 0x9D1941U, 0xC4EBD0U, 0x2BF23FU, 0x3031EEU,
0x790A71U, 0x229909U, 0x2AC1CEU, 0x717677U, 0x5AEDA0U, 0x039C99U, 0x480646U, 0x515587U, 0x1AEC3CU, 0x296F69U,
0xE13492U, 0xBA8607U, 0xB39FCCU, 0xEC4CB1U, 0xA77723U, 0x9EA7DEU, 0xD51C0DU, 0xCD0F00U, 0x86D4FBU, 0xDDF56EU,
0xF46F95U, 0x2FBCD4U, 0x268D6BU, 0x7D52B2U, 0x374165U, 0x26F9DCU, 0x4D2A9BU, 0x141163U, 0x1FD2FCU, 0x40CA2DU,
0x497952U, 0x3322D3U, 0x7AB32CU, 0xE108F5U, 0xAA5AE2U, 0xB3E31BU, 0xF8B098U, 0x812B65U, 0x8B8936U, 0xD0D08AU,
0xD94341U, 0x8A7894U, 0xE3A9AFU, 0xF8377AU, 0xB74481U, 0x6FDD0CU, 0x64EE5FU, 0x3D35A2U, 0x163731U, 0x5F8ECCU,
0x045DC7U, 0x0F4616U, 0x57B6E8U, 0x7CAD79U, 0x253E86U, 0x6EC7CFU, 0x7DD478U, 0xB426A1U, 0xCF2D76U, 0xC3BC5FU,
0x984780U, 0x935571U, 0xCACCEEU, 0x81BBBFU, 0xB82054U, 0xF371C0U, 0xE9CB3BU, 0xA05826U, 0xFB33F5U, 0x52A218U,
0x09B88BU, 0x424BF6U, 0x53D22DU, 0x198198U, 0x043A53U, 0x6F2A06U, 0x34F1BDU, 0x3DC260U, 0x664982U, 0x6FB81BU,
0x15A24CU, 0xDE71F5U, 0xC7482AU, 0x8CDFCBU, 0x9505D4U, 0xDE3405U, 0xA5EFFAU, 0xA4FC63U, 0xFE5704U, 0xB387DDU,
0xA8BC6AU, 0xC32FB2U, 0x5A7EE5U, 0x11C44CU, 0x489797U, 0x420E62U, 0x19BD79U, 0x30E6BCU, 0x6B6407U, 0x225DDAU,
0x398EA9U, 0x703534U, 0x0A64F7U, 0x09FA0AU, 0xD4C910U, 0xDF10E5U, 0x86833EU, 0xCDB99BU, 0xE67A40U, 0xBE631BU,
0xB590AEU, 0xEC8B75U, 0xA73BD0U, 0x9CE08BU, 0xD5F35EU, 0x8E0AE5U, 0x061828U, 0x5D835AU, 0x5660C7U, 0x277914U,
0x68CAE9U, 0x7190E2U, 0x3A0113U, 0x20FECCU, 0x49ED7DU, 0x127522U, 0x1B06ABU, 0x40855CU, 0x8B9E85U, 0x926FB2U,
0xF8F56AU, 0xE186A5U, 0xAA1F14U, 0xF10CCBU, 0xF0F7BAU, 0x8F6735U, 0x867CECU, 0xDC9F1FU, 0x978402U, 0x8E54F1U,
0x45EF3CU, 0x7CFC8FU, 0x3705D2U, 0x6C1248U, 0x64C8BDU, 0x3FF976U, 0x566243U, 0x4DA198U, 0x069B45U, 0x1F0AF6U,
0x5851BBU, 0x00E248U, 0xAB3BD1U, 0xF2090EU, 0xF9926FU, 0xA2C3F1U, 0xEB7800U, 0xD07B9FU, 0x98A1E6U, 0xC31021U,
0xC84BB8U, 0x91D84FU, 0x9AEC96U, 0x6337A9U, 0x288468U, 0x369FB3U, 0x774E06U, 0x6C645DU, 0x05B7A9U, 0x4E2E22U,
0x551DFFU, 0x1CC78CU, 0x47D611U, 0x4F2DF2U, 0x343E6FU, 0xBF8514U, 0xE655C1U, 0xAD5E5AU, 0xB4EDBFU, 0xDFB4E4U,
0xC1265DU, 0x80DD8BU, 0xDBC852U, 0xD25375U, 0x8920ACU, 0xA2BA53U, 0xFB0BC2U, 0x31401DU, 0x28D33CU, 0x63AAE3U,
0x18381AU, 0x11238DU, 0x4AD2E4U, 0x434933U, 0x195BABU, 0x56A058U, 0x6FB105U, 0x2C5AAEU, 0x35C97BU, 0xFED9A0U,
0xA52295U, 0x8D314EU, 0xD6ECA3U, 0x9F5E30U, 0x84456DU, 0xCFB6DEU, 0xD6AF03U, 0xBD2CE9U, 0xE556FCU, 0xEEC707U,
0xB71CD6U, 0x382F59U, 0x43B720U, 0x02E4F7U, 0x195F4EU, 0x51CC99U, 0x0AA550U, 0x013767U, 0x786CBEU, 0x73DD01U,
0x2AC6D1U, 0x61159EU, 0x7BA92FU, 0x92BAF4U, 0x896109U, 0xC0521AU, 0x9F9AF7U, 0x942924U, 0xC532B9U, 0xEFE3C2U,
0xA6D807U, 0xFD0ABCU, 0xF69369U, 0xAFA033U, 0x44738EU, 0x5D694DU, 0x17C8F0U, 0x0C93A3U, 0x45207AU, 0x1EF9C5U,
0x37EB04U, 0x6850FBU, 0x6305EAU, 0x3B9E15U, 0x782DC4U, 0x41774BU, 0x8AF633U, 0xD18DE4U, 0xD81E5DU, 0x83A69AU,
0x8AF583U, 0xF06E7CU, 0xBB5FADU, 0xA28416U, 0xE99653U, 0xF06D88U, 0x9FEC35U, 0xC4F7E6U, 0x4C059AU, 0x1F1C19U,
0x56EFC4U, 0x4D743FU, 0x24612AU, 0x3F9BD1U, 0x748814U, 0x2C13AFU, 0x27F276U, 0x5EE861U, 0x553B88U, 0x0E0A5FU,
0xC791E6U, 0xD8E2B0U, 0x907A69U, 0xABE9C6U, 0xE09217U, 0xB10168U, 0xBA48F9U, 0xE3FA26U, 0x8861CFU, 0x9230D8U,
0xDB8B21U, 0xC099B2U, 0x09644FU, 0x52F704U, 0x79AC90U, 0x201F6BU, 0x2E17BEU, 0x77C495U, 0x3CFF48U, 0x172E9BU,
0x4E9426U, 0x0D8775U, 0x145E98U, 0x5E6D03U, 0xC5F6D6U, 0xAC242DU, 0xF70D3CU, 0xFEDED2U, 0xA5C543U, 0xAE74BCU,
0xD62EE5U, 0x9D9D72U, 0x80029BU, 0xCB534CU, 0x90E175U, 0x19BAAAU, 0x6A3B6BU, 0x6280D4U, 0x39D385U, 0x724B7AU,
0x6B78E2U, 0x00A321U, 0x19101CU, 0x5248CFU, 0x0ADB30U, 0x01F0A9U, 0x5A21CEU, 0xB73A17U, 0xACC880U, 0xE55179U,
0xFE42A6U, 0xB4B987U, 0xC5AF58U, 0xCE1688U, 0x97C533U, 0x9CCE76U, 0xC73F8DU, 0x8E2510U, 0xB4B6C3U, 0x7D4FFEU,
0x665C3DU, 0x2DC7C0U, 0x70B55BU, 0x5B2C2EU, 0x025FF5U, 0x49D470U, 0x53448AU, 0x1A3FD7U, 0x09AC64U, 0x60BDBDU,
0x3B467AU, 0xB0D043U, 0xE98B9CU, 0xE33A2DU, 0x9A21E2U, 0xD1C3B3U, 0xCA5A0CU, 0x8709DDU, 0xDCB222U, 0xF5A3AAU,
0xBF79DDU, 0xA44A04U, 0xEDD193U, 0x3E006AU, 0x373B21U, 0x4CF994U, 0x47C04FU, 0x1F53DAU, 0x5488A1U, 0x4DB86CU,
0x2623DFU, 0x7D7402U, 0x70CF50U, 0x2B9EFDU, 0x232426U, 0xF8A7D3U, 0x91FEC8U, 0x8A4D39U, 0xC117F6U, 0xD0866FU,
0x9B3D18U, 0xE36EC1U, 0xE8F576U, 0xB3C5BFU, 0xBA1629U, 0xE1BD50U, 0xA8EC8FU, 0x17763EU, 0x5D45F1U, 0x049CA0U,
0x0F8F1FU, 0x5630C6U, 0x7DE225U, 0x26FB38U, 0x6F08CBU, 0x7D0316U, 0x34B28DU, 0x2F68E9U, 0xC47B72U, 0x9DC287U,
0x96915CU, 0xCF0B41U, 0x85F8A2U, 0xBAE17FU, 0xF372CCU, 0xE81991U, 0xA1894AU, 0xFAF2EBU, 0xF16134U, 0x89F845U,
0x0A8ADBU, 0x53153AU, 0x1806E5U, 0x03FF7CU, 0x6A7C0BU, 0x312692U, 0x399775U, 0x628CACU, 0x6D7FB3U, 0x34EE42U,
0x5FF49DU, 0x56073CU, 0x8D1C67U, 0x87CDBBU, 0xDEE708U, 0xB574D5U, 0xA4ADB6U, 0xEF9E2BU, 0xF605D0U, 0xBD7545U,
0xE6EE0EU, 0xCE39FBU, 0x950260U, 0xD8929DU, 0x43D9CEU, 0x086A47U, 0x31B3B1U, 0x7AA068U, 0x221ADFU, 0x294B86U,
0x72F049U, 0x73E3F8U, 0x083927U, 0x418856U, 0x5AC3C9U, 0x105020U, 0xC969B7U, 0xE2BBEEU, 0xBF2019U, 0xB41181U,
0xEFCA6AU, 0xA6FD3FU, 0xBC27A4U, 0xD53651U, 0xCE9D9AU, 0x854EA7U, 0xDC5E74U, 0xDFE5A9U, 0x26B61AU, 0x6C0D57U,
0x77DCECU, 0x3EC639U, 0x2575C3U, 0x682CD6U, 0x13AF1DU, 0x1855ECU, 0x404473U, 0x4BDF8AU, 0x12ACDDU, 0xF93754U,
0xE207A3U, 0xABD87AU, 0xF04B45U, 0xF03284U, 0xABB05BU, 0x80ABEBU, 0xD95AB4U, 0x92C10DU, 0x8FD2CEU, 0xC42833U,
0xEC3920U, 0x37C2FDU, 0x7C5106U, 0x654883U, 0x2EAAF8U, 0x37B12DU, 0x5C20B6U, 0x065B42U, 0x07C909U, 0x5C12B4U,
0x152367U, 0x2EB4FAU, 0x65CF19U, 0xFC5F40U, 0xB294FFU, 0xEBA72EU, 0xE03ED1U, 0x9B6CD0U, 0x92D70FU, 0xC944F6U,
0x801D60U, 0x9AAE19U, 0xF1F4DEU, 0xA85547U, 0xAB4EB8U, 0x729DE9U, 0x792456U, 0x223697U, 0x4BED0CU, 0x55DE71U,
0x1C03A2U, 0x07910FU, 0x4CAADCU, 0x356BA0U, 0x3E5033U, 0x67C3EEU, 0x2D9B05U, 0xB62810U, 0xFFF3EBU, 0xC4E03EU,
0x8558A5U, 0xDE0B48U, 0xD5905BU, 0x8D71A2U, 0xA26A75U, 0xFBD8ECU, 0xB08982U, 0xAB1253U, 0xE2A1ECU, 0x79FB3FU,
0x116E52U, 0x4A15C9U, 0x43861CU, 0x188FE7U, 0x537DF2U, 0x62E619U, 0x29D7C0U, 0x310C57U, 0x7A1F2EU, 0x25E5B8U,
0xAC7451U, 0xC76F86U, 0xDE9C9FU, 0x959460U, 0xCF27B1U, 0xC6FC1EU, 0xBDEDCFU, 0xF416B0U, 0xEF0429U, 0xA49FEEU,
0xBDEA17U, 0xFF7104U, 0x06A3F8U, 0x0D8A63U, 0x5219A6U, 0x5B62DDU, 0x00F348U, 0x6969B3U, 0x731A6EU, 0x38816DU,
0x61D090U, 0x6A6343U, 0x33F9FEU, 0x18B8A5U, 0xC30340U, 0x8B10DAU, 0x98E80BU, 0xD1FB74U, 0xEA20F5U, 0xA5930AU,
0xFC8E93U, 0xF75CC4U, 0xAF673DU, 0xA4E6BAU, 0xDF3D43U, 0x960F9CU, 0x0DD68DU, 0x44E572U, 0x1F7EB2U, 0x35AD09U,
0x6C9554U, 0x6746A7U, 0x365D3AU, 0x7DFCF9U, 0x64A6C4U, 0x0B351FU, 0x118CEAU, 0x58DF61U, 0x836434U, 0x8A36CFU,
0xF1AB5BU, 0xBA18A0U, 0xA343EDU, 0xE8C27EU, 0xF0F887U, 0xBB2B50U, 0xC03A69U, 0xC9C1A6U, 0x9A5317U, 0x9368C8U,
0x5CB919U, 0x26A226U, 0x2F01EFU, 0x74D919U, 0x3DCA80U, 0x2631D7U, 0x6D223EU, 0x54BAA1U, 0x1E4950U, 0x47520BU,
0x4CA79EU, 0x97BC75U, 0xBE3EA8U, 0xED479BU, 0xA4D446U, 0xBA4FF5U, 0xF13C39U, 0xE8A46AU, 0x83D7D7U, 0xDA4C0CU,
0xD1DDF9U, 0x8AA7F2U, 0xC22427U, 0x793DDCU, 0x30CE45U, 0x2B5522U, 0x6007FBU, 0x39BE6CU, 0x32AD95U, 0x42560BU,
0x4D426AU, 0x16D1B5U, 0x5F3A04U, 0x442BDBU, 0x2DF082U, 0xF6C225U, 0xFE59FCU, 0xA5880FU, 0xAEB312U, 0xF761C9U,
0x9C582CU, 0x85CBB7U, 0xCE00C3U, 0xD43118U, 0x9DAB9DU, 0xEAF866U, 0xE3437BU, 0x381288U, 0x738955U, 0x6A3BF6U,
0x2066ABU, 0x19D570U, 0x52DEC1U, 0x090E1EU, 0x00B5FFU, 0x5BE6E1U, 0x727D38U, 0x284CCFU, 0x639656U, 0xFA8531U,
0xBD3CA8U, 0xD4EF77U, 0xCFC586U, 0x841489U, 0x9C0F78U, 0xD7BCA7U, 0x8E671EU, 0xA5774DU, 0xFE8481U, 0xF79F32U,
0xAC0AEFU, 0x65F09CU, 0x5FF301U, 0x144ACAU, 0x0D193FU, 0x468224U, 0x13F0D1U, 0x18694AU, 0x63FA87U, 0x2B81F4U,
0x30106DU, 0x790A9BU, 0xE2E952U, 0x8970CDU, 0xD003BCU, 0xDB9963U, 0x838AD2U, 0x88731DU, 0xD1E064U, 0xBAFFF3U,
0xA10F2AU, 0xEC049DU, 0xBFD7D4U, 0xB7EE2BU, 0x4C7CBBU, 0x478760U, 0x1E9415U, 0x554D9EU, 0x4C7E6BU, 0x07E4B0U,
0x3D35ADU, 0x741E4EU, 0x2F8D93U, 0x26FC20U, 0x7D667DU, 0x16B586U, 0x8B8E02U, 0xC91FD9U, 0xD0456CU, 0x9BF237U,
0xC0EBCEU, 0xE92849U, 0xB29390U, 0xBBC3E7U, 0xE1787EU, 0xAA6B81U, 0x93B040U, 0xD8005FU, 0x411BAEU, 0x0AC870U,
0x51F1D1U, 0x5D328EU, 0x362837U, 0x6799E0U, 0x6C4239U, 0x37711AU, 0x3EABC7U, 0x45BA3CU, 0x0D01A9U, 0x16D6F2U,
0xDDCF17U, 0xC46D8CU, 0x8F3670U, 0xF6A723U, 0xFD5CBCU, 0xA74F5DU, 0xEAF582U, 0xF1A43BU, 0x903768U, 0x8B0CC5U,
0xC0DC16U, 0x9957CBU, 0x1324F0U, 0x4ABD25U, 0x61AECEU, 0x38545AU, 0x73C701U, 0x68FEF4U, 0x212D6FU, 0x5B3382U,
0x52C2D1U, 0x09494CU, 0x065ABFU, 0xDFA126U, 0x9CB149U, 0xA56A98U, 0xEE5927U, 0xF4C0F6U, 0xBD33B8U, 0xE62901U,
0xCFB8D6U, 0x94D32FU, 0x9F40B8U, 0xC69AF1U, 0x8CAB0EU, 0x15309FU, 0x7E6360U, 0x21DA31U, 0x2848BAU, 0x733747U,
0x72A6D4U, 0x08EDA8U, 0x435F7BU, 0x5A4CD6U, 0x119505U, 0x082658U, 0x433DE3U, 0xB8ED26U, 0xB0D6DDU, 0xEB05C8U,
0xA2BC13U, 0xA9BEEAU, 0xD6656DU, 0xDF5614U, 0x848F82U, 0xC41C5BU, 0xDF26A4U, 0x94F7A5U, 0xADCC5AU, 0x665B8BU,
0x3F1234U, 0x34A0EDU, 0x6E7BAAU, 0x076813U, 0x1CD1C4U, 0x55833DU, 0x4E1836U, 0x03A9E2U, 0x58F219U, 0x72418CU,
0x2B09F7U, 0xA89A72U, 0xF1A1A9U, 0xBA7254U, 0x81EA47U, 0xC899BAU, 0xD20279U, 0x9B13C4U, 0xC0E09FU, 0xCB7E4BU,
0xB25FF0U, 0xF98431U, 0xE4974EU, 0x2E6CD7U, 0x35FC00U, 0x5CE7A9U, 0x07147EU, 0x060D07U, 0x5D9F98U, 0x56E449U,
0x0E65A6U, 0x659EB7U, 0x7C8D49U, 0x371790U, 0x6C6623U, 0xE5FD6EU, 0x9E6EBDU, 0x921600U, 0xC985D3U, 0x82DAEEU,
0x9B7B25U, 0xD0E0F0U, 0xE1924BU, 0xAA091EU, 0xF158F5U, 0xF9E369U, 0x22F1BAU, 0x4B28C7U, 0x509B54U, 0x1B80BDU,
0x024162U, 0x497B53U, 0x01A88CU, 0x3E1B5DU, 0x7502F2U, 0x6CD12BU, 0x27EB1CU, 0x7E7AC5U, 0xDDA113U, 0x8596BAU,
0xCE5EEDU, 0xD54D14U, 0x9CF68BU, 0x87A54AU, 0xEE1C31U, 0xB58EA4U, 0xBFD55FU, 0xE66482U, 0xE93FA1U, 0x90AD7CU,
0x5B04EFU, 0x405713U, 0x09CC48U, 0x13BFEDU, 0x522736U, 0x2914E3U, 0x22CFD8U, 0x7B5E05U, 0x3061E6U, 0x29B37FU,
0x43BAA8U, 0x5849D1U, 0x91D25EU, 0xCEE0AFU, 0xC73971U, 0x9C2A40U, 0xB7919FU, 0xEF401EU, 0xA452E1U, 0xB5B9B8U,
0xFEA80FU, 0x8533D6U, 0x8C4115U, 0xD7DA28U, 0x5F6BF3U, 0x043006U, 0x4FA39DU, 0x76DBD9U, 0x394C22U, 0x20C7BFU,
0x6BB64CU, 0x312C41U, 0x187FB2U, 0x43C46FU, 0x0A55F4U, 0x192E81U, 0xD2BC4AU, 0xCBA5FBU, 0xA15624U, 0xF85DFDU,
0xF38ECBU, 0xBA3602U, 0xA125F5U, 0xCEFE6CU, 0x97CF3BU, 0x9D55C2U, 0xC4A64DU, 0x4FBFBCU, 0x1468A3U, 0x7D4352U,
0x6ED19DU, 0x270804U, 0x7D3B76U, 0x76A0ABU, 0x0FF018U, 0x0443D5U, 0x5D188EU, 0x16A93BU, 0x0932E0U, 0xC07015U,
0xFACB1EU, 0xB39AC3U, 0xE80170U, 0xE3B3ADU, 0xBAEA5EU, 0xD17956U, 0xC042A9U, 0x8A9378U, 0x912DE7U, 0xD86E86U,
0x83F559U, 0x2AC4E8U, 0x711F37U, 0x7A0D6EU, 0x26B4C9U, 0x6D6710U, 0x547CE7U, 0x1F8CFEU, 0x449720U, 0x4D3483U,
0x16EF5AU, 0x1EFE2DU, 0x6D44B4U, 0xA6174BU, 0xBF8E8AU, 0xF4FD95U, 0xED6764U, 0x86D6BBU, 0xDC8912U, 0xD10A45U,
0x8A799CU, 0x83E12AU, 0xF872F3U, 0xB10954U, 0xAA980DU, 0x6083D6U, 0x397163U, 0x3AE8B8U, 0x439BDDU, 0x481046U,
0x1302BBU, 0x5AFB68U, 0x50E875U, 0x297396U, 0x26824AU, 0x7D98F1U, 0x344BA4U, 0xAF726FU, 0xE6F5DAU, 0x9C0F01U,
0x971C38U, 0xCE85EFU, 0xC5F626U, 0x946D91U, 0xFFBDC8U, 0xE48637U, 0xAC15A6U, 0xB74C48U, 0x7EEE99U, 0x21B586U,
0x0A0677U, 0x539FA8U, 0x18CC01U, 0x007652U, 0x4B67CFU, 0x70B43CU, 0x390FF1U, 0x625ECAU, 0x6BD01FU, 0x38E3C4U,
0xB23870U, 0xCB893BU, 0x8093C6U, 0x994055U, 0xD679A8U, 0x8DAAFBU, 0xA4B176U, 0xFE018DU, 0xF7CA5CU, 0xACD963U,
0xE762B2U, 0xFE323DU, 0x1589C4U, 0x0C5A92U, 0x4F432BU, 0x17F0ECU, 0x1CAA35U, 0x673B82U, 0x6E54DBU, 0x31C724U,
0x785CA5U, 0x632C5AU, 0x29B70BU, 0x508490U, 0xDB5D6DU, 0x82CFEEU, 0x89B492U, 0xD22541U, 0xBB2EDCU, 0xA1DD27U,
0xE04F62U, 0xFB56D9U, 0xB0A50CU, 0xF9BED7U, 0xC24EFAU, 0x8F5529U, 0x55C6D0U, 0x5E3B47U, 0x07383FU, 0x2CA2F0U,
0x75D161U, 0x3E489EU, 0x25BB0FU, 0x6DA170U, 0x7630B1U, 0x174B2EU, 0x4CD8D7U, 0x470180U, 0x9E2339U, 0xD5B8FEU,
0xE9EB27U, 0xA2521DU, 0xB941C8U, 0xF0BB23U, 0xAB2AB6U, 0xA271CDU, 0xD9C250U, 0xD3DC83U, 0x8A1D6EU, 0x41A67DU,
0x58B580U, 0x3B6C5BU, 0x205ECEU, 0x6985A5U, 0x333471U, 0x3E27CAU, 0x65FD13U, 0x0CCE44U, 0x1747EDU, 0x5C143AU,
0x45AF83U, 0x8F7F54U, 0xF6643DU, 0xFDD7A2U, 0xA68E73U, 0xAF3D8CU, 0xF4E79DU, 0xB5E073U, 0x8F59AAU, 0xC40A3DU,
0x999044U, 0x922197U, 0xCB7A3AU, 0x60E9E1U, 0x3B90B4U, 0x73020FU, 0x6839DAU, 0x21FA71U, 0x3A632CU, 0x5151DFU,
0x088A43U, 0x039B80U, 0x4260FDU, 0x18F36EU, 0x33EB97U, 0xEE1848U, 0xE503C9U, 0xBCA4B6U, 0xF7FC67U, 0xEC6FD8U,
0x849C01U, 0x9F8506U, 0xD616FFU, 0x8D6C29U, 0x86FD90U, 0xFF26CFU, 0xF4150EU, 0x2C9EB1U, 0x6FEE60U, 0x74751BU,
0x39E696U, 0x429F65U, 0x4B0DB8U, 0x1056ABU, 0x1AE756U, 0x43FC9DU, 0x282F29U, 0x318172U, 0x7A90E7U, 0xE36B1CU,
0xA878D9U, 0xF2A0E2U, 0xDB133FU, 0x8008ECU, 0xC1D955U, 0xDAE292U, 0x9570EBU, 0xAC9B74U, 0xE68A85U, 0xBF514BU,
0x34635AU, 0x6FFAA5U, 0x66A93CU, 0x1D12CBU, 0x54C382U, 0x4ED915U, 0x056AECU, 0x5C2D37U, 0x779402U, 0x2607C9U,
0x2D5D1CU, 0x72ECA6U, 0xBAB7FBU, 0xA12408U, 0xC89C85U, 0xD3CF76U, 0x98542BU, 0xC177B8U, 0xCAAE45U, 0xB29CCEU,
0xB9473BU, 0xE2D660U, 0xABEDF1U, 0xA03F1EU, 0x7926C4U, 0x1A95F1U, 0x044E2AU, 0x4D49FFU, 0x56B154U, 0x1FA209U,
0x6419FAU, 0x6F4867U, 0x36D394U, 0x3C2199U, 0x653842U, 0x2EABB7U, 0x95C02CU, 0xDC525CU, 0x87CB93U, 0x8EB80AU,
0xD423FDU, 0xF152A4U, 0xAAC003U, 0xE15BDAU, 0xF82A0DU, 0xB3B134U, 0xAAB3EBU, 0xC14C0AU, 0x1B5D95U, 0x128664U,
0x49357AU, 0x002DA3U, 0x3BDE40U, 0x70C5DDU, 0x6954AEU, 0x23AE73U, 0x76ADE8U, 0x7D760DU, 0x064756U, 0x0FDCE3U,
0xD40E38U, 0x9D37F5U, 0x87E4C6U, 0xECDF1AU, 0xB54EA9U, 0xBE1470U, 0xE7B71FU, 0xEC288EU, 0xB77951U, 0xDFC3A0U,
0xC490BFU, 0x89095EU, 0x1ABA81U, 0x51E118U, 0x2853EFU, 0x234AB6U, 0x7B8910U, 0x703AC9U, 0x2B6216U, 0x62F127U,
0x59CAECU, 0x101B59U, 0x4B2082U, 0xC1F2FFU, 0x88696CU, 0xB358A1U, 0xFA9752U, 0xAD844FU, 0xA63CB4U, 0xFFEF60U,
0xF5F4EBU, 0x8C059EU, 0xC71F45U, 0xDCACF0U, 0x95772BU, 0x4E6622U, 0x67CDD5U, 0x3D9F0CU, 0x3406BBU, 0x6F75F2U,
0x24EE0DU, 0x3D7E9CU, 0x520542U, 0x4396B3U, 0x09ADBCU, 0x527C45U, 0x5BF292U, 0xA0810BU, 0xE91878U, 0xF20BB5U,
0xB9F10EU, 0xA1E0DBU, 0xEA33C0U, 0x938835U, 0x989BFEU, 0xC36342U, 0xCA6011U, 0x95FBECU, 0xFD0A6FU, 0x6E11B2U,
0x25C3C1U, 0x3CFA5CU, 0x7769A7U, 0x0EB266U, 0x058079U, 0x5E1988U, 0x167E17U, 0x0DE5EFU, 0x44B428U, 0x7F0E31U,
0x349DC6U, 0xEDC41FU, 0xE277A0U, 0xBA6DE1U, 0x99BE1EU, 0xC2178FU, 0x8B4450U, 0x90FF39U, 0xD9EFAAU, 0x823457U,
0xA88785U, 0xF1DE98U, 0xFA4D73U, 0x3377E6U, 0x68A41DU, 0x43AD48U, 0x1A1AD3U, 0x14C836U, 0x4DF1EDU, 0x0622D0U,
0x173903U, 0x7C88FEU, 0x27527DU, 0x2E41A5U, 0xF4FADAU, 0xFDBB4BU, 0x8601A4U, 0xCDD235U, 0xD4CB6AU, 0x9F7893U,
0x862304U, 0xCCB3EDU, 0xB388BAU, 0xBA5B23U, 0xE1C0DCU, 0xE8A00DU, 0x3B3F27U, 0x500CF2U, 0x48D509U, 0x034694U,
0x5A3CC7U, 0x51AD6AU, 0x0AB6B9U, 0x234544U, 0x785E57U, 0x30DE9AU, 0x2B2561U, 0x6036F4U, 0xDDCF8FU, 0x96DD5BU,
0xCF46D0U, 0xCCB729U, 0x96A4FEU, 0xDF3FC7U, 0xE44D10U, 0xADC4F9U, 0xB61366U, 0xFD2837U, 0xA4B888U, 0x8EC359U,
0x5750B6U, 0x5C49AFU, 0x07BA79U, 0x4A2080U, 0x517307U, 0x38DA7EU, 0x62C9ADU, 0x611230U, 0x38A2CBU, 0x33F98EU,
0x4A4A35U, 0x0153E0U, 0x98815BU, 0xD23A06U, 0xD929C5U, 0x80E079U, 0xEBD7AAU, 0xF20D57U, 0xBD1C4CU, 0xE6A78DU,
0xEF7472U, 0x954CE3U, 0x9CDF9CU, 0xCF8455U, 0x0437C2U, 0x1DFE3BU, 0x56EC6CU, 0x6F57D5U, 0x25061BU, 0x7E95AAU,
0x772FF5U, 0x2C7C24U, 0x05C59BU, 0x5A965AU, 0x111D21U, 0x892DBCU, 0xC2F26FU, 0x9B6192U, 0xB81891U, 0xE38B6EU,
0xEA91B6U, 0xB16221U, 0xF9FB48U, 0xC2C8DFU, 0x890226U, 0x9013F9U, 0xDBE848U, 0x02FB07U, 0x0D62D6U, 0x77906DU,
0x3E8BB0U, 0x2538C3U, 0x6C614EU, 0x77F39CU, 0x141861U, 0x4D0D7AU, 0x47968FU, 0x1EE544U, 0x157DD1U, 0xCEEEAAU,
0xA7953FU, 0xBC06D4U, 0xF57E09U, 0xABED3AU, 0xA2EEE3U, 0xD91734U, 0xD2849CU, 0x8BDEC3U, 0xC06F32U, 0xD174ADU,
0x9BA77CU, 0x201C93U, 0x690C8AU, 0x22F77DU, 0x3BF4E4U, 0x702933U, 0x4B9B5AU, 0x0380C1U, 0x585134U, 0x556AEEU,
0x0EF9CBU, 0x45A310U, 0x7C12CDU, 0xB7C97EU, 0xAFEA23U, 0xEC72C0U, 0xB7215DU, 0x9E9A8EU, 0xC50BF3U, 0xCC5068U,
0x97E28DU, 0xDDB916U, 0xC42846U, 0xAF93B9U, 0xF2D020U, 0x796CC7U, 0x223F9EU, 0x2BA429U, 0x5095F0U, 0x18473FU,
0x03DC8EU, 0x40EFD1U, 0x593620U, 0x1225BFU, 0x6BCF76U, 0x605E40U, 0xBA6599U, 0xF3B66AU, 0xE8AEF7U, 0x851DBCU,
0x9EC649U, 0xD5D5D2U, 0x8C2C27U, 0x863E7CU, 0xDFB5D9U, 0xF4C002U, 0xA55BDFU, 0xEEE9ECU, 0x75B020U, 0x3C23D3U,
0x06584AU, 0x4FCB15U, 0x1453A4U, 0x1F306BU, 0x42AB9AU, 0x09FA05U, 0x30415CU, 0x7A53ABU, 0x61AA22U, 0x2839D5U,
0xF3228CU, 0xDAD032U, 0x89C9E3U, 0x820A2CU, 0xCAB91DU, 0x91A4C6U, 0x985673U, 0xE34DB8U, 0xA8DCE5U, 0xB52756U,
0xFE358BU, 0xE6EE78U, 0x0DDF75U, 0x5654AFU, 0x5F075AU, 0x04BFC1U, 0x0D2CB4U, 0x56577FU, 0x34C6C2U, 0x2D9D11U,
0x662F48U, 0x3FB4FFU, 0x34E536U, 0x4F4E89U, 0xC61C58U, 0x988107U, 0xD132A7U, 0xCA6978U, 0x81D881U, 0xB8C296U,
0xF3114FU, 0xAA2AA8U, 0xA0FB31U, 0xF37142U, 0xDA429FU, 0x819B24U, 0x4888E1U, 0x5333FAU, 0x1AE30FU, 0x40D0D5U,
0x6F0B68U, 0x36182BU, 0x3DA0F6U, 0x646345U, 0x2F7898U, 0x14CDF3U, 0x5C9666U, 0xC704BDU, 0x8E7F4CU, 0xDDEED3U,
0xD655BAU, 0xAF062DU, 0xE49EF5U, 0xFDFD02U, 0xB7661BU, 0xA8F7F4U, 0xC18D25U, 0x9A1E9AU, 0x9305CBU, 0x48F414U,
0x43EFB5U, 0x1B1D6AU, 0x708413U, 0x698780U, 0x2A7C4DU, 0x6168BFU, 0x78F3A2U, 0x130059U, 0x0B1BCCU, 0x40CA07U,
0x1FF072U, 0x9663E9U, 0xCD9A14U, 0xE499C7U, 0xBF0AEAU, 0xF57239U, 0xECE1E4U, 0xA7BA5FU, 0xDE098FU, 0xD591E0U,
0x86E271U, 0x8F79AEU, 0xD52817U, 0x1C8350U, 0x2711A9U, 0x684C3EU, 0x71FFE7U, 0x3AE490U, 0x633619U, 0x498FE6U,
0x10DC37U, 0x1B670DU, 0x4066D8U, 0x09BC13U, 0x328FAEU, 0xFB16FDU, 0xA9C500U, 0xA2FF93U, 0xFB2C5EU, 0xF03565U,
0x8D86B0U, 0xC65D4BU, 0xDD7DCEU, 0x95E615U, 0x8EB169U, 0xE708FAU, 0xBCDB03U, 0x37C1C4U, 0x6E72FDU, 0x25232AU,
0x3DB8F3U, 0x5ECA4CU, 0x45430DU, 0x0CF0B2U, 0x57AB61U, 0x5E3ABCU, 0x210087U, 0x2BD343U, 0xF248B8U, 0xB9392DU,
0xA0A376U, 0xEBB09FU, 0x905908U, 0x99CAF1U, 0xD3F5A6U, 0xCA251FU, 0x813ED0U, 0xF2CD01U, 0xFBD63EU, 0xA046EEU,
0x29BD51U, 0x76AE98U, 0x3C274FU, 0x055476U, 0x4ECEA5U, 0x573F58U, 0x1C24DBU, 0x47B786U, 0x6ECC7DU, 0x345CE8U,
0x7D0703U, 0x66B456U, 0xAF3DECU, 0xBC6F31U, 0xD7D0A2U, 0x8EC1CFU, 0x80321CU, 0xD9A9A1U, 0xD2FB7AU, 0xA9422BU,
0xE05184U, 0xFB8A55U, 0xB22AAAU, 0xE831B3U, 0x63E264U, 0x1ADB8CU, 0x11081BU, 0x4832E2U, 0x0BA1BDU, 0x10781CU,
0x784BC3U, 0x679052U, 0x2E902DU, 0x752BFCU, 0x7EFC57U, 0x27C58AU, 0xCC57D9U, 0xD40C64U, 0x9FBFB6U, 0x84665BU,
0xCD7540U, 0xB6CF95U, 0xBF8E6EU, 0xE415FBU, 0xE62690U, 0xBFFE0DU, 0xF04DFEU, 0xC91623U, 0x028520U, 0x19BCD9U,
0x506E06U, 0x0AEDB6U, 0x23D4E9U, 0x780728U, 0x331997U, 0x3AE84EU, 0x6173B9U, 0x6840A0U, 0x129B67U, 0x598B9EU,
0xC87009U, 0x877370U, 0x9EEAEBU, 0xF5190EU, 0xAC03D4U, 0xA690C1U, 0xFDE93AU, 0xB47AF7U, 0xAF8044U, 0xC69119U,
0xDD0ACAU, 0x166977U, 0x4EF0BCU, 0x45E2C9U, 0x3C1D52U, 0x3F8E87U, 0x64D73CU, 0x296574U, 0x327E83U, 0x7A8F1AU,
0x0114EDU, 0x0A1734U, 0x53EF3BU, 0xD8FCCAU, 0x812715U, 0xEA94A4U, 0xF185EBU, 0xB95F3AU, 0xA26C85U, 0xEBB55CU,
0xB0862AU, 0x930CA3U, 0xCEDD70U, 0x85E6CDU, 0x9D7196U, 0x562A63U, 0x6D9AE8U, 0x24411DU, 0x7F5246U, 0x76EBDBU,
0x2DB928U, 0x2712E5U, 0x5E83D7U, 0x15D80AU, 0x0C6BD1U, 0x473170U, 0x54A02FU, 0xB99B9EU, 0xE34841U, 0xEAD090U,
0xB1E33FU, 0xFA2866U, 0xE31991U, 0x88C208U, 0x8154FFU, 0xDB6FB7U, 0x92BE28U, 0x89A5D9U, 0xE25606U, 0x7BCE37U,
0x30FDFCU, 0x693E21U, 0x6F2792U, 0x3495CFU, 0x5DCE6CU, 0x465DB1U, 0x0FA46AU, 0x14B75FU, 0x5F2D85U, 0x275C60U,
0x2CC7FBU, 0xF56486U, 0xFE3C55U, 0xA5ABC8U, 0xECD02BU, 0xD743F2U, 0x9FDAC5U, 0xC0A81CU, 0xC33383U, 0x9A2262U,
0xB1D93DU, 0xE8DA8DU, 0x232252U, 0x39B19BU, 0x70AAACU, 0x6B5975U, 0x024182U, 0x59921BU, 0x522974U, 0x0B38A5U,
0x01F33EU, 0x78C1CBU, 0x3758D0U, 0x242F3DU, 0xEDB4EFU, 0xB66672U, 0xBF5701U, 0xC5CCDCU, 0xCE9F77U, 0x9726A2U,
0xDCA4F9U, 0xC5FF4CU, 0xAE4E87U, 0xB51576U, 0xFDA7E9U, 0xA63C90U, 0x2F6D47U, 0x74D6CFU, 0x1BC538U, 0x0A1D21U,
0x413EDEU, 0x58E50FU, 0x127480U, 0x6B4BF1U, 0x60992EU, 0x2BA297U, 0x327340U, 0x79E809U, 0xA0DABAU, 0x8A0367U,
0xD1009DU, 0x98BB98U, 0x836A63U, 0xCE70F6U, 0xF5832DU, 0xB69850U, 0xEE29D3U, 0xE5732EU, 0xBCE0FDU, 0xB75962U,
0x4C1A13U, 0x0589DCU, 0x1EF165U, 0x5666B7U, 0x4DFDEAU, 0x268E59U, 0x7F1794U, 0x74256FU, 0x29FE7AU, 0x626F81U,
0x700404U, 0x1996DFU, 0x828FA2U, 0xCB7C31U, 0x9067CCU, 0x9B940EU, 0xE20C17U, 0xE81FE8U, 0xB1E439U, 0xFAF586U,
0xE17FC7U, 0xA88C18U, 0xD397A1U, 0x5E4276U, 0x04794FU, 0x0FEB88U, 0x5E9271U, 0x3501E6U, 0x2C9A3EU, 0x67EA51U,
0x7C61C0U, 0x34323BU, 0x6F89EEU, 0x4618F5U, 0x1D4218U, 0xD4F1CBU, 0xCFE876U, 0x841B25U, 0xB888F8U, 0xF3D053U,
0xAA7386U, 0xA168BCU, 0xF2BB69U, 0xFB8792U, 0x80541FU, 0xC8CF4CU, 0xC3FEB5U, 0x182522U, 0x1117CBU, 0x6A9E9CU,
0x234D05U, 0x3876FAU, 0x72A42BU, 0x2FBD84U, 0x240ED4U, 0x5DD54BU, 0x56C4B2U, 0x057E65U, 0x4C2D4CU, 0xD7849BU,
0xBFD762U, 0xA44DF9U, 0xEFFEACU, 0xB6A347U, 0xBD30D2U, 0xC40B29U, 0x8FDB74U, 0x9540E6U, 0xDC330BU, 0xC3BAD8U,
0x8A89E5U, 0x71533EU, 0x7AC0BBU, 0x2BB140U, 0x212A11U, 0x7838AEU, 0x13C17FU, 0x08D290U, 0x414989U, 0x1AA85EU,
0x13B2A6U, 0x494131U, 0x625AD8U, 0xBBCF87U, 0xF43516U, 0xED26E9U, 0xA6BF78U, 0x9FCC17U, 0xDD57CEU, 0x86B75DU,
0x8FACA0U, 0xD43FE3U, 0x9D445EU, 0xA6D584U, 0x6DCF71U, 0x753C6AU, 0x3EA5AFU, 0x67F654U, 0x4C4CC9U, 0x134DBAU,
0x1AB667U, 0x4125E4U, 0x097E19U, 0x12CA0AU, 0x71D1F3U, 0x78022CU, 0xA33BACU, 0xEAA953U, 0xF17A02U, 0x9B53BDU,
0xC28074U, 0xC9BB83U, 0x90299AU, 0x9BF04DU, 0xC4C3B4U, 0xAD583BU, 0xB7084AU, 0xFEB3D1U, 0x656004U, 0x2E69FEU,
0x5FDAF3U, 0x548000U, 0x0D37DDU, 0x472E4EU, 0x5CFD33U, 0x1546F8U, 0x2E164DU, 0x678D96U, 0x3CBEE3U, 0x337768U,
0xEBE5BDU, 0xC09E47U, 0x990D5EU, 0xD234A9U, 0xC9E720U, 0x887DF7U, 0xD34C0EU, 0xFB9711U, 0xA084E0U, 0xA96C2FU,
0xF27FBEU, 0xB9E4C1U, 0x001318U, 0x4B02AFU, 0x56B867U, 0x1CEB30U, 0x477289U, 0x4E8152U, 0x358AF7U, 0x3C1AACU,
0x676159U, 0x24F2C2U, 0x3C6917U, 0x57197CU, 0x8E82E1U, 0x85F112U, 0xDE68CFU, 0xD77BDDU, 0x8C9130U, 0xE400EBU,
0xFB5B5EU, 0xB0E885U, 0xA9F6D4U, 0xE2277BU, 0x9B9CA2U, 0x108F15U, 0x5A764CU, 0x0B64ABU, 0x00AF32U, 0x599CEDU,
0x72059DU, 0x29D702U, 0x60ECE3U, 0x7A7D3CU, 0x330625U, 0x0C95D6U, 0x474D0BU, 0x9E7EA8U, 0x95FDF5U, 0xCCA666U,
0x86179BU, 0xBD8D40U, 0xFCDA65U, 0xE763BFU, 0xAE304AU, 0xF58AD1U, 0xDE9B9CU, 0x86406FU, 0x8DE3F2U, 0x54B801U,
0x1B28D8U, 0x0213D7U, 0x69C026U, 0x7259B9U, 0x3A6B48U, 0x61B017U, 0x68819FU, 0x135A68U, 0x50D9B1U, 0x49E386U,
0x02325FU, 0x9A29B0U, 0xD19E23U, 0xAAC77EU, 0xA3558DU, 0xFCAE04U, 0xF5BFF3U, 0xAE04AAU, 0xC44635U, 0xDDDDC5U,
0x966C4AU, 0xCF373BU, 0xC4A4E4U, 0x1FD47DU, 0x3E4F8AU, 0x64DC43U, 0x2DA574U, 0x3637ADU, 0x7D5C56U, 0x44CFC3U,
0x0BD688U, 0x52257DU, 0x59BBE7U, 0x03AA1AU, 0x4A5119U, 0xF142C4U, 0xB89A37U, 0xB329AAU, 0xE822D1U, 0xA9D114U,
0x93C88FU, 0xDA5A7AU, 0xC1A121U, 0x8AB090U, 0xD36B5EU, 0xDC58A7U, 0xA5C0B0U, 0x2F8369U, 0x74389EU, 0x3DAB17U,
0x26D368U, 0x4F40F9U, 0x141F26U, 0x1DAEC7U, 0x473558U, 0x446721U, 0x1DDEF6U, 0x769D6EU, 0xEF0E8DU, 0xA434D0U,
0xBFE56BU, 0xF35EBEU, 0x884D45U, 0x819440U, 0xDAA69BU, 0x917D26U, 0x88ECF5U, 0xC3C788U, 0xFB150BU, 0xB02ED6U,
0x63BF24U, 0x6A6439U, 0x3153D2U, 0x188B03U, 0x43989CU, 0x0923EDU, 0x147232U, 0x5FF99BU, 0x060B4CU, 0x2D10B5U,
0x76A1A2U, 0x7FFA7BU, 0xA568D4U, 0xECD104U, 0xD7827BU, 0x9C19EAU, 0x8D6831U, 0xC6E2DCU, 0x9F71CFU, 0x950A32U,
0xEE9BE1U, 0xA3A16CU, 0xB8761FU, 0xF16FC2U, 0x6A9C79U, 0x010FACU, 0x491786U, 0x52F453U, 0x1BEF88U, 0x007C35U,
0x4B8566U, 0x32978FU, 0x316C18U, 0x697DC1U, 0x62E6BEU, 0x3B142FU, 0xD40DC0U, 0xCFCE11U, 0x86F58EU, 0xDD66F6U,
0xD53E31U, 0x8E8988U, 0xA5125FU, 0xFC6366U, 0xB7F9B9U, 0xAEAA78U, 0xE513C3U, 0xD69096U, 0x1ECB6DU, 0x4579F8U,
0x4C6033U, 0x13B34EU, 0x5888DCU, 0x615821U, 0x2AE3F2U, 0x32F0FFU, 0x792B04U, 0x220A91U, 0x0B906AU, 0xD0432BU,
0xD97294U, 0x82AD4DU, 0xC8BE9AU, 0xD90623U, 0xB2D564U, 0xEBEE9CU, 0xE02D03U, 0xBF35D2U, 0xB686ADU, 0xCCDD2CU,
0x854CD3U, 0x1EF70AU, 0x55A51DU, 0x4C1CE4U, 0x074F67U, 0x7ED49AU, 0x7476C9U, 0x2F2F75U, 0x26BCBEU, 0x75876BU,
0x1C5650U, 0x07C885U, 0x48BB7EU, 0x9022F3U, 0x9B11A0U, 0xC2CA5DU, 0xE9C8CEU, 0xA07133U, 0xFBA238U, 0xF0B9E9U,
0xA84917U, 0x835286U, 0xDAC179U, 0x913830U, 0x822B87U, 0x4BD95EU, 0x30D289U, 0x3C43A0U, 0x67B87FU, 0x6CAA8EU,
0x353311U, 0x7E4440U, 0x47DFABU, 0x0C8E3FU, 0x1634C4U, 0x5FA7D9U, 0x04CC0AU, 0xAD5DE7U, 0xF64774U, 0xBDB409U,
0xAC2DD2U, 0xE67E67U, 0xFBC5ACU, 0x90D5F9U, 0xCB0E42U, 0xC23D9FU, 0x99B67DU, 0x9047E4U, 0xEA5DB3U, 0x218E0AU,
0x38B7D5U, 0x732034U, 0x6AFA2BU, 0x21CBFAU, 0x5A1005U, 0x5B039CU, 0x01A8FBU, 0x4C7822U, 0x574395U, 0x3CD04DU,
0xA5811AU, 0xEE3BB3U, 0xB76868U, 0xBDF19DU, 0xE64286U, 0xCF1943U, 0x949BF8U, 0xDDA225U, 0xC67156U, 0x8FCACBU,
0xF59B08U, 0xF605F5U, 0x2B36EFU, 0x20EF1AU, 0x797CC1U, 0x324664U, 0x1985BFU, 0x419CE4U, 0x4A6F51U, 0x13748AU,
0x58C42FU, 0x631F74U, 0x2A0CA1U, 0x71F51AU, 0xF9E7D7U, 0xA27CA5U, 0xA99F38U, 0xD886EBU, 0x973516U, 0x8E6F1DU,
0xC5FEECU, 0xDF0133U, 0xB61282U, 0xED8ADDU, 0xE4F954U, 0xBF7AA3U, 0x74617AU, 0x6D904DU, 0x070A95U, 0x1E795AU,
0x55E0EBU, 0x0EF334U, 0x0F0845U, 0x7098CAU, 0x798313U, 0x2360E0U, 0x687BFDU, 0x71AB0EU, 0xBA10C3U, 0x830370U,
0xC8FA2DU, 0x93EDB7U, 0x9B3742U, 0xC00689U, 0xA99DBCU, 0xB25E67U, 0xF964BAU, 0xE0F509U, 0xA7AE44U, 0xFF1DB7U,
0x54C42EU, 0x0DF6F1U, 0x066D90U, 0x5D3C0EU, 0x1487FFU, 0x2F8460U, 0x675E19U, 0x3CEFDEU, 0x37B447U, 0x6E27B0U,
0x651369U, 0x9CC856U, 0xD77B97U, 0xC9604CU, 0x88B1F9U, 0x939BA2U, 0xFA4856U, 0xB1D1DDU, 0xAAE200U, 0xE33873U,
0xB829EEU, 0xB0D20DU, 0xCBC190U, 0x407AEBU, 0x19AA3EU, 0x52A1A5U, 0x4B1240U, 0x204B1BU, 0x3ED9A2U, 0x7F2274U,
0x2437ADU, 0x2DAC8AU, 0x76DF53U, 0x5D45ACU, 0x04F43DU, 0xCEBFE2U, 0xD72CC3U, 0x9C551CU, 0xE7C7E5U, 0xEEDC72U,
0xB52D1BU, 0xBCB6CCU, 0xE6A454U, 0xA95FA7U, 0x904EFAU, 0xD3A551U, 0xCA3684U, 0x01265FU, 0x5ADD6AU, 0x72CEB1U,
0x29135CU, 0x60A1CFU, 0x7BBA92U, 0x304921U, 0x2950FCU, 0x42D316U, 0x1AA903U, 0x1138F8U, 0x48E329U, 0xC7D0A6U,
0xBC48DFU, 0xFD1B08U, 0xE6A0B1U, 0xAE3366U, 0xF55AAFU, 0xFEC898U, 0x879341U, 0x8C22FEU, 0xD5392EU, 0x9EEA61U,
0x8456D0U, 0x6D450BU, 0x769EF6U, 0x3FADE5U, 0x606508U, 0x6BD6DBU, 0x3ACD46U, 0x101C3DU, 0x5927F8U, 0x02F543U,
0x096C96U, 0x505FCCU, 0xBB8C71U, 0xA296B2U, 0xE8370FU, 0xF36C5CU, 0xBADF85U, 0xE1063AU, 0xC814FBU, 0x97AF04U,
0x9CFA15U, 0xC461EAU, 0x87D23BU, 0xBE88B4U, 0x7509CCU, 0x2E721BU, 0x27E1A2U, 0x7C5965U, 0x750A7CU, 0x0F9183U,
0x44A052U, 0x5D7BE9U, 0x1669ACU, 0x0F9277U, 0x6013CAU, 0x3B0819U, 0xB3FA65U, 0xE0E3E6U, 0xA9103BU, 0xB28BC0U,
0xDB9ED5U, 0xC0642EU, 0x8B77EBU, 0xD3EC50U, 0xD80D89U, 0xA1179EU, 0xAAC477U, 0xF1F5A0U, 0x386E19U, 0x271D4FU,
0x6F8596U, 0x541639U, 0x1F6DE8U, 0x4EFE97U, 0x45B706U, 0x1C05D9U, 0x779E30U, 0x6DCF27U, 0x2474DEU, 0x3F664DU,
0xF69BB0U, 0xAD08FBU, 0x86536FU, 0xDFE094U, 0xD1E841U, 0x883B6AU, 0xC300B7U, 0xE8D164U, 0xB16BD9U, 0xF2788AU,
0xEBA167U, 0xA192FCU, 0x3A0929U, 0x53DBD2U, 0x08F2C3U, 0x01212DU, 0x5A3ABCU, 0x518B43U, 0x29D11AU, 0x62628DU,
0x7FFD64U, 0x34ACB3U, 0x6F1E8AU, 0xE64555U, 0x95C494U, 0x9D7F2BU, 0xC62C7AU, 0x8DB485U, 0x94871DU, 0xFF5CDEU,
0xE6EFE3U, 0xADB730U, 0xF524CFU, 0xFE0F56U, 0xA5DE31U, 0x48C5E8U, 0x53377FU, 0x1AAE86U, 0x01BD59U, 0x4B4678U,
0x3A50A7U, 0x31E977U, 0x683ACCU, 0x633189U, 0x38C072U, 0x71DAEFU, 0x4B493CU, 0x82B001U, 0x99A3C2U, 0xD2383FU,
0x8F4AA4U, 0xA4D3D1U, 0xFDA00AU, 0xB62B8FU, 0xACBB75U, 0xE5C028U, 0xF6539BU, 0x9F4242U, 0xC4B985U, 0x4F2FBCU,
0x167463U, 0x1CC5D2U, 0x65DE1DU, 0x2E3C4CU, 0x35A5F3U, 0x78F622U, 0x234DDDU, 0x0A5C55U, 0x408622U, 0x5BB5FBU,
0x122E6CU, 0xC1FF95U, 0xC8C4DEU, 0xB3066BU, 0xB83FB0U, 0xE0AC25U, 0xAB775EU, 0xB24793U, 0xD9DC20U, 0x828BFDU,
0x8F30AFU, 0xD46102U, 0xDCDBD9U, 0x07582CU, 0x6E0137U, 0x75B2C6U, 0x3EE809U, 0x2F7990U, 0x64C2E7U, 0x1C913EU,
0x170A89U, 0x4C3A40U, 0x45E9D6U, 0x1E42AFU, 0x571370U, 0xE889C1U, 0xA2BA0EU, 0xFB635FU, 0xF070E0U, 0xA9CF39U,
0x821DDAU, 0xD904C7U, 0x90F734U, 0x82FCE9U, 0xCB4D72U, 0xD09716U, 0x3B848DU, 0x623D78U, 0x696EA3U, 0x30F4BEU,
0x7A075DU, 0x451E80U, 0x0C8D33U, 0x17E66EU, 0x5E76B5U, 0x050D14U, 0x0E9ECBU, 0x7607BAU, 0xF57524U, 0xACEAC5U,
0xE7F91AU, 0xFC0083U, 0x9583F4U, 0xCED96DU, 0xC6688AU, 0x9D7353U, 0x92804CU, 0xCB11BDU, 0xA00B62U, 0xA9F8C3U,
0x72E398U, 0x783244U, 0x2118F7U, 0x4A8B2AU, 0x5B5249U, 0x1061D4U, 0x09FA2FU, 0x428ABAU, 0x1911F1U, 0x31C604U,
0x6AFD9FU, 0x276D62U, 0xBC2631U, 0xF795B8U, 0xCE4C4EU, 0x855F97U, 0xDDE520U, 0xD6B479U, 0x8D0FB6U, 0x8C1C07U,
0xF7C6D8U, 0xBE77A9U, 0xA53C36U, 0xEFAFDFU, 0x369648U, 0x1D4411U, 0x40DFE6U, 0x4BEE7EU, 0x103595U, 0x5902C0U,
0x43D85BU, 0x2AC9AEU, 0x316265U, 0x7AB158U, 0x23A18BU, 0x201A56U, 0xD949E5U, 0x93F2A8U, 0x882313U, 0xC139C6U,
0xDA8A3CU, 0x97D329U, 0xEC50E2U, 0xE7AA13U, 0xBFBB8CU, 0xB42075U, 0xED5322U, 0x06C8ABU, 0x1DF85CU, 0x542785U,
0x0FB4BAU, 0x0FCD7BU, 0x544FA4U, 0x7F5414U, 0x26A54BU, 0x6D3EF2U, 0x702D31U, 0x3BD7CCU, 0x13C6DFU, 0xC83D02U,
0x83AEF9U, 0x9AB77CU, 0xD15507U, 0xC84ED2U, 0xA3DF49U, 0xF9A4BDU, 0xF836F6U, 0xA3ED4BU, 0xEADC98U, 0xD14B05U,
0x9A30E6U, 0x03A0BFU, 0x4D6B00U, 0x1458D1U, 0x1FC12EU, 0x64932FU, 0x6D28F0U, 0x36BB09U, 0x7FE29FU, 0x6551E6U,
0x0E0B21U, 0x57AAB8U, 0x54B147U, 0x8D6216U, 0x86DBA9U, 0xDDC968U, 0xB412F3U, 0xAA218EU, 0xE3FC5DU, 0xF86EF0U,
0xB35523U, 0xCA945FU, 0xC1AFCCU, 0x983C11U, 0xD264FAU, 0x49D7EFU, 0x000C14U, 0x3B1FC1U, 0x7AA75AU, 0x21F4B7U,
0x2A6FA4U, 0x728E5DU, 0x5D958AU, 0x042713U, 0x4F767DU, 0x54EDACU, 0x1D5E13U, 0x8604C0U, 0xEE91ADU, 0xB5EA36U,
0xBC79E3U, 0xE77018U, 0xAC820DU, 0x9D19E6U, 0xD6283FU, 0xCEF3A8U, 0x85E0D1U, 0xDA1A47U, 0x538BAEU, 0x389079U,
0x216360U, 0x6A6B9FU, 0x30D84EU, 0x3903E1U, 0x421230U, 0x0BE94FU, 0x10FBD6U, 0x5B6011U, 0x4215E8U, 0x008EFBU,
0xF95C07U, 0xF2759CU, 0xADE659U, 0xA49D22U, 0xFF0CB7U, 0x96964CU, 0x8CE591U, 0xC77E92U, 0x9E2F6FU, 0x959CBCU,
0xCC0601U, 0xE7475AU, 0x3CFCBFU, 0x74EF25U, 0x6717F4U, 0x2E048BU, 0x15DF0AU, 0x5A6CF5U, 0x03716CU, 0x08A33BU,
0x5098C2U, 0x5B1945U, 0x20C2BCU, 0x69F063U, 0xF22972U, 0xBB1A8DU, 0xE0814DU, 0xCA52F6U, 0x936AABU, 0x98B958U,
0xC9A2C5U, 0x820306U, 0x9B593BU, 0xF4CAE0U, 0xEE7315U, 0xA7209EU, 0x7C9BCBU, 0x75C930U, 0x0E54A4U, 0x45E75FU,
0x5CBC12U, 0x173D81U, 0x0F0778U, 0x44D4AFU, 0x3FC596U, 0x363E59U, 0x65ACE8U, 0x6C9737U, 0xA346E6U, 0xD95DD9U,
0xD0FE10U, 0x8B26E6U, 0xC2357FU, 0xD9CE28U, 0x92DDC1U, 0xAB455EU, 0xE1B6AFU, 0xB8ADF4U, 0xB35861U, 0x68438AU,
0x41C157U, 0x12B864U, 0x5B2BB9U, 0x45B00AU, 0x0EC3C6U, 0x175B95U, 0x7C2828U, 0x25B3F3U, 0x2E2206U, 0x75580DU,
0x3DDBD8U, 0x86C223U, 0xCF31BAU, 0xD4AADDU, 0x9FF804U, 0xC64193U, 0xCD526AU, 0xBDA9F4U, 0xB2BD95U, 0xE92E4AU,
0xA0C5FBU, 0xBBD424U, 0xD20F7DU, 0x093DDAU, 0x01A603U, 0x5A77F0U, 0x514CEDU, 0x089E36U, 0x63A7D3U, 0x7A3448U,
0x31FF3CU, 0x2BCEE7U, 0x625462U, 0x150799U, 0x1CBC84U, 0xC7ED77U, 0x8C76AAU, 0x95C409U, 0xDF9954U, 0xE62A8FU,
0xAD213EU, 0xF6F1E1U, 0xFF4A00U, 0xA4191EU, 0x8D82C7U, 0xD7B330U, 0x9C69A9U, 0x057ACEU, 0x42C357U, 0x2B1088U,
0x303A79U, 0x7BEB76U, 0x63F087U, 0x284358U, 0x7198E1U, 0x5A88B2U, 0x017B7EU, 0x0860CDU, 0x53F510U, 0x9A0F63U,
0xA00CFEU, 0xEBB535U, 0xF2E6C0U, 0xB97DDBU, 0xEC0F2EU, 0xE796B5U, 0x9C0578U, 0xD47E0BU, 0xCFEF92U, 0x86F564U,
0x1D16ADU, 0x768F32U, 0x2FFC43U, 0x24669CU, 0x7C752DU, 0x778CE2U, 0x2E1F9BU, 0x45000CU, 0x5EF0D5U, 0x13FB62U,
0x40282BU, 0x4811D4U, 0xB38344U, 0xB8789FU, 0xE16BEAU, 0xAAB261U, 0xB38194U, 0xF81B4FU, 0xC2CA52U, 0x8BE1B1U,
0xD0726CU, 0xD903DFU, 0x829982U, 0xE94A79U, 0x7471FDU, 0x36E026U, 0x2FBA93U, 0x640DC8U, 0x3F1431U, 0x16D7B6U,
0x4D6C6FU, 0x443C18U, 0x1E8781U, 0x55947EU, 0x6C4FBFU, 0x27FFA0U, 0xBEE451U, 0xF5378FU, 0xAE0E2EU, 0xA2CD71U,
0xC9D7C8U, 0x98661FU, 0x93BDC6U, 0xC88EE5U, 0xC15438U, 0xBA45C3U, 0xF2FE56U, 0xE9290DU, 0x2230E8U, 0x3B9273U,
0x70C98FU, 0x0958DCU, 0x02A343U, 0x58B0A2U, 0x150A7DU, 0x0E5BC4U, 0x6FC897U, 0x74F33AU, 0x3F23E9U, 0x66A834U,
0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U,
0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U };
const unsigned int A_TABLE[] = { 0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U,
48U, 52U, 56U, 60U, 64U, 68U, 1U, 5U, 9U, 13U, 17U, 21U };
const unsigned int B_TABLE[] = { 25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U,
2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U };
const unsigned int C_TABLE[] = { 46U, 50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U,
23U, 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U };
CNXDNAudio::CNXDNAudio()
{
}
CNXDNAudio::~CNXDNAudio()
{
}
void CNXDNAudio::decode(const unsigned char* in, unsigned char* out) const
{
assert(in != NULL);
assert(out != NULL);
decode(in + 0U, out, 0U);
decode(in + 9U, out, 49U);
}
void CNXDNAudio::encode(const unsigned char* in, unsigned char* out) const
{
assert(in != NULL);
assert(out != NULL);
encode(in, out + 0U, 0U);
encode(in, out + 9U, 49U);
}
void CNXDNAudio::decode(const unsigned char* in, unsigned char* out, unsigned int offset) const
{
assert(in != NULL);
assert(out != NULL);
unsigned int a = 0U;
unsigned int MASK = 0x800000U;
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
unsigned int aPos = A_TABLE[i];
if (READ_BIT(in, aPos))
a |= MASK;
}
unsigned int b = 0U;
MASK = 0x400000U;
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
unsigned int bPos = B_TABLE[i];
if (READ_BIT(in, bPos))
b |= MASK;
}
unsigned int c = 0U;
MASK = 0x1000000U;
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
unsigned int cPos = C_TABLE[i];
if (READ_BIT(in, cPos))
c |= MASK;
}
a >>= 12;
// The PRNG
b ^= (PRNG_TABLE[a] >> 1);
b >>= 11;
MASK = 0x000800U;
for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) {
unsigned int aPos = i + offset + 0U;
unsigned int bPos = i + offset + 12U;
WRITE_BIT(out, aPos, a & MASK);
WRITE_BIT(out, bPos, b & MASK);
}
MASK = 0x1000000U;
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
unsigned int cPos = i + offset + 24U;
WRITE_BIT(out, cPos, c & MASK);
}
}
void CNXDNAudio::encode(const unsigned char* in, unsigned char* out, unsigned int offset) const
{
assert(in != NULL);
assert(out != NULL);
unsigned int aOrig = 0U;
unsigned int bOrig = 0U;
unsigned int cOrig = 0U;
unsigned int MASK = 0x000800U;
for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) {
unsigned int n1 = i + offset + 0U;
unsigned int n2 = i + offset + 12U;
if (READ_BIT(in, n1))
aOrig |= MASK;
if (READ_BIT(in, n2))
bOrig |= MASK;
}
MASK = 0x1000000U;
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
unsigned int n = i + offset + 24U;
if (READ_BIT(in, n))
cOrig |= MASK;
}
unsigned int a = CGolay24128::encode24128(aOrig);
// The PRNG
unsigned int p = PRNG_TABLE[aOrig] >> 1;
unsigned int b = CGolay24128::encode23127(bOrig) >> 1;
b ^= p;
MASK = 0x800000U;
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
unsigned int aPos = A_TABLE[i];
WRITE_BIT(out, aPos, a & MASK);
}
MASK = 0x400000U;
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
unsigned int bPos = B_TABLE[i];
WRITE_BIT(out, bPos, b & MASK);
}
MASK = 0x1000000U;
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
unsigned int cPos = C_TABLE[i];
WRITE_BIT(out, cPos, cOrig & MASK);
}
}

37
NXDNAudio.h Normal file
View file

@ -0,0 +1,37 @@
/*
* 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(NXDNAudio_H)
#define NXDNAudio_H
class CNXDNAudio {
public:
CNXDNAudio();
~CNXDNAudio();
void encode(const unsigned char* in, unsigned char* out) const;
void decode(const unsigned char* in, unsigned char* out) const;
private:
void encode(const unsigned char* in, unsigned char* out, unsigned int offset) const;
void decode(const unsigned char* in, unsigned char* out, unsigned int offset) const;
};
#endif

185
NXDNCRC.cpp Normal file
View 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
NXDNCRC.h Normal file
View 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

1139
NXDNControl.cpp Normal file

File diff suppressed because it is too large Load diff

105
NXDNControl.h Normal file
View file

@ -0,0 +1,105 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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(NXDNControl_H)
#define NXDNControl_H
#include "RSSIInterpolator.h"
#include "NXDNNetwork.h"
#include "NXDNDefines.h"
#include "NXDNLayer3.h"
#include "NXDNLookup.h"
#include "RingBuffer.h"
#include "StopWatch.h"
#include "NXDNLICH.h"
#include "Display.h"
#include "Defines.h"
#include "Timer.h"
#include "Modem.h"
#include <string>
class CNXDNControl {
public:
CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper);
~CNXDNControl();
bool writeModem(unsigned char* data, unsigned int len);
unsigned int readModem(unsigned char* data);
void clock(unsigned int ms);
bool isBusy() const;
void enable(bool enabled);
private:
unsigned int m_ran;
unsigned int m_id;
bool m_selfOnly;
INXDNNetwork* m_network;
CDisplay* m_display;
bool m_duplex;
bool m_remoteGateway;
CNXDNLookup* m_lookup;
CRingBuffer<unsigned char> m_queue;
RPT_RF_STATE m_rfState;
RPT_NET_STATE m_netState;
CTimer m_rfTimeoutTimer;
CTimer m_netTimeoutTimer;
CTimer m_packetTimer;
CTimer m_networkWatchdog;
CStopWatch m_elapsed;
unsigned int m_rfFrames;
unsigned int m_netFrames;
unsigned int m_rfErrs;
unsigned int m_rfBits;
CNXDNLICH m_rfLastLICH;
CNXDNLayer3 m_rfLayer3;
CNXDNLayer3 m_netLayer3;
unsigned char m_rfMask;
unsigned char m_netMask;
CRSSIInterpolator* m_rssiMapper;
unsigned char m_rssi;
unsigned char m_maxRSSI;
unsigned char m_minRSSI;
unsigned int m_aveRSSI;
unsigned int m_rssiCount;
bool m_enabled;
FILE* m_fp;
bool processVoice(unsigned char usc, unsigned char option, unsigned char *data);
bool processData(unsigned char option, unsigned char *data);
void writeQueueRF(const unsigned char* data);
void writeQueueNet(const unsigned char* data);
void writeNetwork(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type);
void writeNetwork();
void scrambler(unsigned char* data) const;
void writeEndRF();
void writeEndNet();
bool openFile();
bool writeFile(const unsigned char* data);
void closeFile();
};
#endif

151
NXDNConvolution.cpp Normal file
View file

@ -0,0 +1,151 @@
/*
* Copyright (C) 2009-2016,2018,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNConvolution.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
const uint8_t BRANCH_TABLE1[] = {0U, 0U, 0U, 0U, 2U, 2U, 2U, 2U};
const uint8_t BRANCH_TABLE2[] = {0U, 2U, 2U, 0U, 0U, 2U, 2U, 0U};
const unsigned int NUM_OF_STATES_D2 = 8U;
const unsigned int NUM_OF_STATES = 16U;
const uint32_t M = 4U;
const unsigned int K = 5U;
CNXDNConvolution::CNXDNConvolution() :
m_metrics1(NULL),
m_metrics2(NULL),
m_oldMetrics(NULL),
m_newMetrics(NULL),
m_decisions(NULL),
m_dp(NULL)
{
m_metrics1 = new uint16_t[20U];
m_metrics2 = new uint16_t[20U];
m_decisions = new uint64_t[300U];
}
CNXDNConvolution::~CNXDNConvolution()
{
delete[] m_metrics1;
delete[] m_metrics2;
delete[] m_decisions;
}
void CNXDNConvolution::start()
{
::memset(m_metrics1, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
::memset(m_metrics2, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
m_oldMetrics = m_metrics1;
m_newMetrics = m_metrics2;
m_dp = m_decisions;
}
void CNXDNConvolution::decode(uint8_t s0, uint8_t s1)
{
*m_dp = 0U;
for (uint8_t i = 0U; i < NUM_OF_STATES_D2; i++) {
uint8_t j = i * 2U;
uint16_t metric = std::abs(BRANCH_TABLE1[i] - s0) + std::abs(BRANCH_TABLE2[i] - s1);
uint16_t m0 = m_oldMetrics[i] + metric;
uint16_t m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + (M - metric);
uint8_t decision0 = (m0 >= m1) ? 1U : 0U;
m_newMetrics[j + 0U] = decision0 != 0U ? m1 : m0;
m0 = m_oldMetrics[i] + (M - metric);
m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + metric;
uint8_t decision1 = (m0 >= m1) ? 1U : 0U;
m_newMetrics[j + 1U] = decision1 != 0U ? m1 : m0;
*m_dp |= (uint64_t(decision1) << (j + 1U)) | (uint64_t(decision0) << (j + 0U));
}
++m_dp;
assert((m_dp - m_decisions) <= 300);
uint16_t* tmp = m_oldMetrics;
m_oldMetrics = m_newMetrics;
m_newMetrics = tmp;
}
unsigned int CNXDNConvolution::chainback(unsigned char* out, unsigned int nBits)
{
assert(out != NULL);
uint32_t state = 0U;
while (nBits-- > 0) {
--m_dp;
uint32_t i = state >> (9 - K);
uint8_t bit = uint8_t(*m_dp >> i) & 1;
state = (bit << 7) | (state >> 1);
WRITE_BIT1(out, nBits, bit != 0U);
}
unsigned int minCost = m_oldMetrics[0];
for (unsigned int i = 0U; i < NUM_OF_STATES; i++) {
if (m_oldMetrics[i] < minCost)
minCost = m_oldMetrics[i];
}
return minCost / (M >> 1);
}
void CNXDNConvolution::encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const
{
assert(in != NULL);
assert(out != NULL);
assert(nBits > 0U);
uint8_t d1 = 0U, d2 = 0U, d3 = 0U, d4 = 0U;
uint32_t k = 0U;
for (unsigned int i = 0U; i < nBits; i++) {
uint8_t d = READ_BIT1(in, i) ? 1U : 0U;
uint8_t g1 = (d + d3 + d4) & 1;
uint8_t g2 = (d + d1 + d2 + d4) & 1;
d4 = d3;
d3 = d2;
d2 = d1;
d1 = d;
WRITE_BIT1(out, k, g1 != 0U);
k++;
WRITE_BIT1(out, k, g2 != 0U);
k++;
}
}

46
NXDNConvolution.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2015,2016,2018,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NXDNConvolution_H)
#define NXDNConvolution_H
#include <cstdint>
class CNXDNConvolution {
public:
CNXDNConvolution();
~CNXDNConvolution();
void start();
void decode(uint8_t s0, uint8_t s1);
unsigned int chainback(unsigned char* out, unsigned int nBits);
void encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const;
private:
uint16_t* m_metrics1;
uint16_t* m_metrics2;
uint16_t* m_oldMetrics;
uint16_t* m_newMetrics;
uint64_t* m_decisions;
uint64_t* m_dp;
};
#endif

102
NXDNDefines.h Normal file
View file

@ -0,0 +1,102 @@
/*
* Copyright (C) 2016,2017,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(NXDNDEFINES_H)
#define NXDNDEFINES_H
const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int NXDN_FRAME_LENGTH_BITS = 384U;
const unsigned int NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U;
const unsigned int NXDN_FRAME_LENGTH_SYMBOLS = NXDN_FRAME_LENGTH_BITS / 2U;
const unsigned int NXDN_FSW_LENGTH_BITS = 20U;
const unsigned int NXDN_FSW_LENGTH_SYMBOLS = NXDN_FSW_LENGTH_BITS / 2U;
const unsigned int NXDN_FSW_LENGTH_SAMPLES = NXDN_FSW_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
const unsigned char NXDN_FSW_BYTES[] = {0xCDU, 0xF5U, 0x90U};
const unsigned char NXDN_FSW_BYTES_MASK[] = {0xFFU, 0xFFU, 0xF0U};
const unsigned int NXDN_FSW_BYTES_LENGTH = 3U;
const unsigned int NXDN_LICH_LENGTH_BITS = 16U;
const unsigned int NXDN_SACCH_LENGTH_BITS = 60U;
const unsigned int NXDN_FACCH1_LENGTH_BITS = 144U;
const unsigned int NXDN_FACCH2_LENGTH_BITS = 348U;
const unsigned int NXDN_FSW_LICH_SACCH_LENGTH_BITS = NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS;
const unsigned int NXDN_FSW_LICH_SACCH_LENGTH_BYTES = NXDN_FSW_LICH_SACCH_LENGTH_BITS / 8U;
const unsigned char NXDN_LICH_RFCT_RCCH = 0U;
const unsigned char NXDN_LICH_RFCT_RTCH = 1U;
const unsigned char NXDN_LICH_RFCT_RDCH = 2U;
const unsigned char NXDN_LICH_RFCT_RTCH_C = 3U;
const unsigned char NXDN_LICH_USC_SACCH_NS = 0U;
const unsigned char NXDN_LICH_USC_UDCH = 1U;
const unsigned char NXDN_LICH_USC_SACCH_SS = 2U;
const unsigned char NXDN_LICH_USC_SACCH_SS_IDLE = 3U;
const unsigned char NXDN_LICH_STEAL_NONE = 3U;
const unsigned char NXDN_LICH_STEAL_FACCH1_2 = 2U;
const unsigned char NXDN_LICH_STEAL_FACCH1_1 = 1U;
const unsigned char NXDN_LICH_STEAL_FACCH = 0U;
const unsigned char NXDN_LICH_DIRECTION_INBOUND = 0U;
const unsigned char NXDN_LICH_DIRECTION_OUTBOUND = 1U;
const unsigned char NXDN_SR_SINGLE = 0U;
const unsigned char NXDN_SR_4_4 = 0U;
const unsigned char NXDN_SR_3_4 = 1U;
const unsigned char NXDN_SR_2_4 = 2U;
const unsigned char NXDN_SR_1_4 = 3U;
const unsigned char NXDN_MESSAGE_TYPE_VCALL = 0x01U;
const unsigned char NXDN_MESSAGE_TYPE_VCALL_IV = 0x03U;
const unsigned char NXDN_MESSAGE_TYPE_DCALL_HDR = 0x09U;
const unsigned char NXDN_MESSAGE_TYPE_DCALL_DATA = 0x0BU;
const unsigned char NXDN_MESSAGE_TYPE_DCALL_ACK = 0x0CU;
const unsigned char NXDN_MESSAGE_TYPE_TX_REL = 0x08U;
const unsigned char NXDN_MESSAGE_TYPE_HEAD_DLY = 0x0FU;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_REQ_HDR = 0x38U;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_REQ_DATA = 0x39U;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_RESP = 0x3BU;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_IV = 0x3AU;
const unsigned char NXDN_MESSAGE_TYPE_STAT_INQ_REQ = 0x30U;
const unsigned char NXDN_MESSAGE_TYPE_STAT_INQ_RESP = 0x31U;
const unsigned char NXDN_MESSAGE_TYPE_STAT_REQ = 0x32U;
const unsigned char NXDN_MESSAGE_TYPE_STAT_RESP = 0x33U;
const unsigned char NXDN_MESSAGE_TYPE_REM_CON_REQ = 0x34U;
const unsigned char NXDN_MESSAGE_TYPE_REM_CON_RESP = 0x35U;
const unsigned char NXDN_MESSAGE_TYPE_IDLE = 0x10U;
const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_REQ = 0x28U;
const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_RESP = 0x29U;
const unsigned char NXDN_MESSAGE_TYPE_PROP_FORM = 0x3FU;
const unsigned char NXDN_VOICE_CALL_OPTION_HALF_DUPLEX = 0x00U;
const unsigned char NXDN_VOICE_CALL_OPTION_DUPLEX = 0x10U;
const unsigned char NXDN_DATA_CALL_OPTION_HALF_DUPLEX = 0x00U;
const unsigned char NXDN_DATA_CALL_OPTION_DUPLEX = 0x10U;
const unsigned char NXDN_DATA_CALL_OPTION_4800 = 0x00U;
const unsigned char NXDN_DATA_CALL_OPTION_9600 = 0x02U;
const unsigned char SACCH_IDLE[] = { NXDN_MESSAGE_TYPE_IDLE, 0x00U, 0x00U };
#endif

188
NXDNFACCH1.cpp Normal file
View file

@ -0,0 +1,188 @@
/*
* 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 "NXDNFACCH1.h"
#include "NXDNConvolution.h"
#include "NXDNDefines.h"
#include "NXDNCRC.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int INTERLEAVE_TABLE[] = {
0U, 9U, 18U, 27U, 36U, 45U, 54U, 63U, 72U, 81U, 90U, 99U, 108U, 117U, 126U, 135U,
1U, 10U, 19U, 28U, 37U, 46U, 55U, 64U, 73U, 82U, 91U, 100U, 109U, 118U, 127U, 136U,
2U, 11U, 20U, 29U, 38U, 47U, 56U, 65U, 74U, 83U, 92U, 101U, 110U, 119U, 128U, 137U,
3U, 12U, 21U, 30U, 39U, 48U, 57U, 66U, 75U, 84U, 93U, 102U, 111U, 120U, 129U, 138U,
4U, 13U, 22U, 31U, 40U, 49U, 58U, 67U, 76U, 85U, 94U, 103U, 112U, 121U, 130U, 139U,
5U, 14U, 23U, 32U, 41U, 50U, 59U, 68U, 77U, 86U, 95U, 104U, 113U, 122U, 131U, 140U,
6U, 15U, 24U, 33U, 42U, 51U, 60U, 69U, 78U, 87U, 96U, 105U, 114U, 123U, 132U, 141U,
7U, 16U, 25U, 34U, 43U, 52U, 61U, 70U, 79U, 88U, 97U, 106U, 115U, 124U, 133U, 142U,
8U, 17U, 26U, 35U, 44U, 53U, 62U, 71U, 80U, 89U, 98U, 107U, 116U, 125U, 134U, 143U };
const unsigned int PUNCTURE_LIST[] = { 1U, 5U, 9U, 13U, 17U, 21U, 25U, 29U, 33U, 37U,
41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, 73U, 77U,
81U, 85U, 89U, 93U, 97U, 101U, 105U, 109U, 113U, 117U,
121U, 125U, 129U, 133U, 137U, 141U, 145U, 149U, 153U, 157U,
161U, 165U, 169U, 173U, 177U, 181U, 185U, 189U };
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CNXDNFACCH1::CNXDNFACCH1(const CNXDNFACCH1& facch1) :
m_data(NULL)
{
m_data = new unsigned char[10U + 2U];
::memcpy(m_data, facch1.m_data, 10U + 2U);
}
CNXDNFACCH1::CNXDNFACCH1() :
m_data(NULL)
{
m_data = new unsigned char[10U + 2U];
}
CNXDNFACCH1::~CNXDNFACCH1()
{
delete[] m_data;
}
bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset)
{
assert(data != NULL);
unsigned char temp1[18U];
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + offset;
bool b = READ_BIT1(data, n);
WRITE_BIT1(temp1, i, b);
}
uint8_t temp2[210U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
if (n == PUNCTURE_LIST[index]) {
temp2[n++] = 1U;
index++;
}
bool b = READ_BIT1(temp1, i);
temp2[n++] = b ? 2U : 0U;
}
for (unsigned int i = 0U; i < 8U; i++) {
temp2[n++] = 0U;
}
CNXDNConvolution conv;
conv.start();
n = 0U;
for (unsigned int i = 0U; i < 100U; i++) {
uint8_t s0 = temp2[n++];
uint8_t s1 = temp2[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, 96U);
return CNXDNCRC::checkCRC12(m_data, 80U);
}
void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const
{
assert(data != NULL);
unsigned char temp1[12U];
::memset(temp1, 0x00U, 12U);
::memcpy(temp1, m_data, 10U);
CNXDNCRC::encodeCRC12(temp1, 80U);
unsigned char temp2[24U];
CNXDNConvolution conv;
conv.encode(temp1, temp2, 96U);
unsigned char temp3[18U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 192U; i++) {
if (i != PUNCTURE_LIST[index]) {
bool b = READ_BIT1(temp2, i);
WRITE_BIT1(temp3, n, b);
n++;
} else {
index++;
}
}
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + offset;
bool b = READ_BIT1(temp3, i);
WRITE_BIT1(data, n, b);
}
}
void CNXDNFACCH1::getData(unsigned char* data) const
{
assert(data != NULL);
::memcpy(data, m_data, 10U);
}
void CNXDNFACCH1::getRaw(unsigned char* data) const
{
assert(data != NULL);
::memset(data, 0x00U, 12U);
::memcpy(data, m_data, 10U);
CNXDNCRC::encodeCRC12(data, 80U);
}
void CNXDNFACCH1::setData(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_data, data, 10U);
}
void CNXDNFACCH1::setRaw(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_data, data, 12U);
}
CNXDNFACCH1& CNXDNFACCH1::operator=(const CNXDNFACCH1& facch1)
{
if (&facch1 != this)
::memcpy(m_data, facch1.m_data, 10U + 2U);
return *this;
}

44
NXDNFACCH1.h Normal file
View file

@ -0,0 +1,44 @@
/*
* 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(NXDNFACCH1_H)
#define NXDNFACCH1_H
class CNXDNFACCH1 {
public:
CNXDNFACCH1(const CNXDNFACCH1& facch);
CNXDNFACCH1();
~CNXDNFACCH1();
bool decode(const unsigned char* data, unsigned int offset);
void encode(unsigned char* data, unsigned int offset) const;
void getData(unsigned char* data) const;
void getRaw(unsigned char* data) const;
void setData(const unsigned char* data);
void setRaw(const unsigned char* data);
CNXDNFACCH1& operator=(const CNXDNFACCH1& facch);
private:
unsigned char* m_data;
};
#endif

176
NXDNIcomNetwork.cpp Normal file
View file

@ -0,0 +1,176 @@
/*
* 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 "NXDNIcomNetwork.h"
#include "NXDNDefines.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
CNXDNIcomNetwork::CNXDNIcomNetwork(const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug) :
m_socket(localAddress, localPort),
m_addr(),
m_addrLen(0U),
m_debug(debug),
m_enabled(false),
m_buffer(1000U, "NXDN Network")
{
assert(gatewayPort > 0U);
assert(!gatewayAddress.empty());
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0)
m_addrLen = 0U;
}
CNXDNIcomNetwork::~CNXDNIcomNetwork()
{
}
bool CNXDNIcomNetwork::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of the NXDN Gateway");
return false;
}
LogMessage("Opening NXDN network connection");
return m_socket.open(m_addr);
}
bool CNXDNIcomNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type)
{
assert(data != NULL);
unsigned char buffer[110U];
::memset(buffer, 0x00U, 110U);
buffer[0U] = 'I';
buffer[1U] = 'C';
buffer[2U] = 'O';
buffer[3U] = 'M';
buffer[4U] = 0x01U;
buffer[5U] = 0x01U;
buffer[6U] = 0x08U;
buffer[7U] = 0xE0U;
switch (type) {
case NNMT_VOICE_HEADER:
case NNMT_VOICE_TRAILER:
buffer[37U] = 0x23U;
buffer[38U] = 0x1CU;
buffer[39U] = 0x21U;
break;
case NNMT_VOICE_BODY:
buffer[37U] = 0x23U;
buffer[38U] = 0x10U;
buffer[39U] = 0x21U;
break;
case NNMT_DATA_HEADER:
case NNMT_DATA_BODY:
case NNMT_DATA_TRAILER:
buffer[37U] = 0x23U;
buffer[38U] = 0x02U;
buffer[39U] = 0x18U;
break;
default:
return false;
}
::memcpy(buffer + 40U, data, 33U);
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U);
return m_socket.write(buffer, 102U, m_addr, m_addrLen);
}
void CNXDNIcomNetwork::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage address;
unsigned int addrLen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrLen);
if (length <= 0)
return;
if (!CUDPSocket::match(m_addr, address)) {
LogMessage("NXDN, packet received from an invalid source");
return;
}
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Received", buffer, length);
// Invalid packet type?
if (::memcmp(buffer, "ICOM", 4U) != 0)
return;
if (length != 102)
return;
if (!m_enabled)
return;
m_buffer.addData(buffer + 40U, 33U);
}
bool CNXDNIcomNetwork::read(unsigned char* data)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return false;
m_buffer.getData(data, 33U);
return true;
}
void CNXDNIcomNetwork::reset()
{
}
bool CNXDNIcomNetwork::isConnected() const
{
return (m_addrLen != 0);
}
void CNXDNIcomNetwork::close()
{
m_socket.close();
LogMessage("Closing NXDN network connection");
}
void CNXDNIcomNetwork::enable(bool enabled)
{
if (enabled && !m_enabled)
reset();
else if (!enabled && m_enabled)
m_buffer.clear();
m_enabled = enabled;
}

61
NXDNIcomNetwork.h Normal file
View file

@ -0,0 +1,61 @@
/*
* 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 NXDNIcomNetwork_H
#define NXDNIcomNetwork_H
#include "NXDNNetwork.h"
#include "NXDNDefines.h"
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CNXDNIcomNetwork : public INXDNNetwork {
public:
CNXDNIcomNetwork(const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug);
virtual ~CNXDNIcomNetwork();
virtual bool open();
virtual void enable(bool enabled);
virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type);
virtual bool read(unsigned char* data);
virtual void reset();
virtual bool isConnected() const;
virtual void close();
virtual void clock(unsigned int ms);
private:
CUDPSocket m_socket;
sockaddr_storage m_addr;
unsigned int m_addrLen;
bool m_debug;
bool m_enabled;
CRingBuffer<unsigned char> m_buffer;
};
#endif

1187
NXDNKenwoodNetwork.cpp Normal file

File diff suppressed because it is too large Load diff

102
NXDNKenwoodNetwork.h Normal file
View file

@ -0,0 +1,102 @@
/*
* 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 NXDNKenwoodNetwork_H
#define NXDNKenwoodNetwork_H
#include "NXDNNetwork.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
#include <random>
class CNXDNKenwoodNetwork : public INXDNNetwork {
public:
CNXDNKenwoodNetwork(const std::string& localAddress, unsigned short localPort, const std::string& gwyAddress, unsigned short gwyPort, bool debug);
virtual ~CNXDNKenwoodNetwork();
virtual bool open();
virtual void enable(bool enabled);
virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type);
virtual bool read(unsigned char* data);
virtual void reset();
virtual bool isConnected() const;
virtual void close();
virtual void clock(unsigned int ms);
private:
CUDPSocket m_rtpSocket;
CUDPSocket m_rtcpSocket;
sockaddr_storage m_rtcpAddr;
sockaddr_storage m_rtpAddr;
unsigned int m_rtcpAddrLen;
unsigned int m_rtpAddrLen;
bool m_enabled;
bool m_headerSeen;
bool m_seen1;
bool m_seen2;
bool m_seen3;
bool m_seen4;
unsigned char* m_sacch;
uint8_t m_sessionId;
uint16_t m_seqNo;
unsigned int m_ssrc;
bool m_debug;
uint32_t m_startSecs;
uint32_t m_startUSecs;
CTimer m_rtcpTimer;
CTimer m_hangTimer;
unsigned char m_hangType;
unsigned short m_hangSrc;
unsigned short m_hangDst;
std::mt19937 m_random;
bool processIcomVoiceHeader(const unsigned char* data);
bool processIcomVoiceData(const unsigned char* data);
bool processIcomDataHeader(const unsigned char* data);
bool processIcomDataData(const unsigned char* data);
bool processIcomDataTrailer(const unsigned char* data);
bool processKenwoodVoiceHeader(unsigned char* data);
bool processKenwoodVoiceData(unsigned char* data);
bool processKenwoodVoiceLateEntry(unsigned char* data);
bool processKenwoodData(unsigned char* data);
bool writeRTPVoiceHeader(const unsigned char* data);
bool writeRTPVoiceData(const unsigned char* data);
bool writeRTPVoiceTrailer(const unsigned char* data);
bool writeRTPDataHeader(const unsigned char* data);
bool writeRTPDataData(const unsigned char* data);
bool writeRTPDataTrailer(const unsigned char* data);
bool writeRTCPStart();
bool writeRTCPPing();
bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst);
bool writeRTCPHang();
unsigned int readRTP(unsigned char* data);
unsigned int readRTCP(unsigned char* data);
unsigned long getTimeStamp() const;
};
#endif

162
NXDNLICH.cpp Normal file
View file

@ -0,0 +1,162 @@
/*
* 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 "NXDNDefines.h"
#include "NXDNLICH.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CNXDNLICH::CNXDNLICH(const CNXDNLICH& lich) :
m_lich(NULL)
{
m_lich = new unsigned char[1U];
m_lich[0U] = lich.m_lich[0U];
}
CNXDNLICH::CNXDNLICH() :
m_lich(NULL)
{
m_lich = new unsigned char[1U];
}
CNXDNLICH::~CNXDNLICH()
{
delete[] m_lich;
}
bool CNXDNLICH::decode(const unsigned char* bytes)
{
assert(bytes != NULL);
unsigned int offset = NXDN_FSW_LENGTH_BITS;
for (unsigned int i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++, offset += 2U) {
bool b = READ_BIT1(bytes, offset);
WRITE_BIT1(m_lich, i, b);
}
bool newParity = getParity();
bool origParity = (m_lich[0U] & 0x01U) == 0x01U;
return origParity == newParity;
}
void CNXDNLICH::encode(unsigned char* bytes)
{
assert(bytes != NULL);
bool parity = getParity();
if (parity)
m_lich[0U] |= 0x01U;
else
m_lich[0U] &= 0xFEU;
unsigned int offset = NXDN_FSW_LENGTH_BITS;
for (unsigned int i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++) {
bool b = READ_BIT1(m_lich, i);
WRITE_BIT1(bytes, offset, b);
offset++;
WRITE_BIT1(bytes, offset, true);
offset++;
}
}
unsigned char CNXDNLICH::getRFCT() const
{
return (m_lich[0U] >> 6) & 0x03U;
}
unsigned char CNXDNLICH::getFCT() const
{
return (m_lich[0U] >> 4) & 0x03U;
}
unsigned char CNXDNLICH::getOption() const
{
return (m_lich[0U] >> 2) & 0x03U;
}
unsigned char CNXDNLICH::getDirection() const
{
return (m_lich[0U] >> 1) & 0x01U;
}
unsigned char CNXDNLICH::getRaw() const
{
bool parity = getParity();
if (parity)
m_lich[0U] |= 0x01U;
else
m_lich[0U] &= 0xFEU;
return m_lich[0U];
}
void CNXDNLICH::setRFCT(unsigned char rfct)
{
m_lich[0U] &= 0x3FU;
m_lich[0U] |= (rfct << 6) & 0xC0U;
}
void CNXDNLICH::setFCT(unsigned char usc)
{
m_lich[0U] &= 0xCFU;
m_lich[0U] |= (usc << 4) & 0x30U;
}
void CNXDNLICH::setOption(unsigned char option)
{
m_lich[0U] &= 0xF3U;
m_lich[0U] |= (option << 2) & 0x0CU;
}
void CNXDNLICH::setDirection(unsigned char direction)
{
m_lich[0U] &= 0xFDU;
m_lich[0U] |= (direction << 1) & 0x02U;
}
void CNXDNLICH::setRaw(unsigned char lich)
{
m_lich[0U] = lich;
}
CNXDNLICH& CNXDNLICH::operator=(const CNXDNLICH& lich)
{
if (&lich != this)
m_lich[0U] = lich.m_lich[0U];
return *this;
}
bool CNXDNLICH::getParity() const
{
switch (m_lich[0U] & 0xF0U) {
case 0x80U:
case 0xB0U:
return true;
default:
return false;
}
}

52
NXDNLICH.h Normal file
View file

@ -0,0 +1,52 @@
/*
* 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(NXDNLICH_H)
#define NXDNLICH_H
class CNXDNLICH {
public:
CNXDNLICH(const CNXDNLICH& lich);
CNXDNLICH();
~CNXDNLICH();
bool decode(const unsigned char* bytes);
void encode(unsigned char* bytes);
unsigned char getRFCT() const;
unsigned char getFCT() const;
unsigned char getOption() const;
unsigned char getDirection() const;
unsigned char getRaw() const;
void setRFCT(unsigned char rfct);
void setFCT(unsigned char usc);
void setOption(unsigned char option);
void setDirection(unsigned char direction);
void setRaw(unsigned char lich);
CNXDNLICH& operator=(const CNXDNLICH& lich);
private:
unsigned char* m_lich;
bool getParity() const;
};
#endif

117
NXDNLayer3.cpp Normal file
View file

@ -0,0 +1,117 @@
/*
* 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 "NXDNDefines.h"
#include "NXDNLayer3.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CNXDNLayer3::CNXDNLayer3(const CNXDNLayer3& layer3) :
m_data(NULL)
{
m_data = new unsigned char[22U];
::memcpy(m_data, layer3.m_data, 22U);
}
CNXDNLayer3::CNXDNLayer3() :
m_data(NULL)
{
m_data = new unsigned char[22U];
::memset(m_data, 0x00U, 22U);
}
CNXDNLayer3::~CNXDNLayer3()
{
delete[] m_data;
}
void CNXDNLayer3::decode(const unsigned char* bytes, unsigned int length, unsigned int offset)
{
assert(bytes != NULL);
for (unsigned int i = 0U; i < length; i++, offset++) {
bool b = READ_BIT1(bytes, i);
WRITE_BIT1(m_data, offset, b);
}
}
void CNXDNLayer3::encode(unsigned char* bytes, unsigned int length, unsigned int offset)
{
assert(bytes != NULL);
for (unsigned int i = 0U; i < length; i++, offset++) {
bool b = READ_BIT1(m_data, offset);
WRITE_BIT1(bytes, i, b);
}
}
unsigned char CNXDNLayer3::getMessageType() const
{
return m_data[0U] & 0x3FU;
}
unsigned short CNXDNLayer3::getSourceUnitId() const
{
return (m_data[3U] << 8) | m_data[4U];
}
unsigned short CNXDNLayer3::getDestinationGroupId() const
{
return (m_data[5U] << 8) | m_data[6U];
}
bool CNXDNLayer3::getIsGroup() const
{
return (m_data[2U] & 0x80U) != 0x80U;
}
unsigned char CNXDNLayer3::getDataBlocks() const
{
return (m_data[8U] & 0x0FU) + 1U;
}
void CNXDNLayer3::getData(unsigned char* data) const
{
::memcpy(data, m_data, 22U);
}
void CNXDNLayer3::setData(const unsigned char* data, unsigned int length)
{
::memset(m_data, 0x00U, 22U);
::memcpy(m_data, data, length);
}
void CNXDNLayer3::reset()
{
::memset(m_data, 0x00U, 22U);
}
CNXDNLayer3& CNXDNLayer3::operator=(const CNXDNLayer3& layer3)
{
if (&layer3 != this)
::memcpy(m_data, layer3.m_data, 22U);
return *this;
}

49
NXDNLayer3.h Normal file
View file

@ -0,0 +1,49 @@
/*
* 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(NXDNLayer3_H)
#define NXDNLayer3_H
class CNXDNLayer3 {
public:
CNXDNLayer3(const CNXDNLayer3& layer3);
CNXDNLayer3();
~CNXDNLayer3();
void decode(const unsigned char* bytes, unsigned int length, unsigned int offset = 0U);
void encode(unsigned char* bytes, unsigned int length, unsigned int offset = 0U);
unsigned char getMessageType() const;
unsigned short getSourceUnitId() const;
unsigned short getDestinationGroupId() const;
bool getIsGroup() const;
unsigned char getDataBlocks() const;
void setData(const unsigned char* data, unsigned int length);
void getData(unsigned char* data) const;
void reset();
CNXDNLayer3& operator=(const CNXDNLayer3& layer3);
private:
unsigned char* m_data;
};
#endif

136
NXDNLookup.cpp Normal file
View file

@ -0,0 +1,136 @@
/*
* Copyright (C) 2016,2017,2018,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNLookup.h"
#include "Timer.h"
#include "Log.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
CNXDNLookup::CNXDNLookup(const std::string& filename, unsigned int reloadTime) :
CThread(),
m_filename(filename),
m_reloadTime(reloadTime),
m_table(),
m_stop(false),
m_reload(false)
{
}
CNXDNLookup::~CNXDNLookup()
{
}
bool CNXDNLookup::read()
{
bool ret = m_table.load(m_filename);
if (m_reloadTime > 0U)
run();
return ret;
}
void CNXDNLookup::reload()
{
if (m_reloadTime == 0U)
m_table.load(m_filename);
else
m_reload = true;
}
void CNXDNLookup::entry()
{
LogInfo("Started the NXDN Id lookup reload thread");
CTimer timer(1U, 3600U * m_reloadTime);
timer.start();
while (!m_stop) {
sleep(1000U);
timer.clock();
if (timer.hasExpired() || m_reload) {
m_table.load(m_filename);
timer.start();
m_reload = false;
}
}
LogInfo("Stopped the NXDN Id lookup reload thread");
}
void CNXDNLookup::stop()
{
if (m_reloadTime == 0U) {
delete this;
return;
}
m_stop = true;
wait();
}
void CNXDNLookup::findWithName(unsigned int id, class CUserDBentry *entry)
{
if (id == 0xFFFFU) {
entry->clear();
entry->set(keyCALLSIGN, "ALL");
return;
}
if (m_table.lookup(id, entry)) {
LogDebug("FindWithName =%s %s", entry->get(keyCALLSIGN).c_str(), entry->get(keyFIRST_NAME).c_str());
} else {
entry->clear();
char text[10U];
::snprintf(text, sizeof(text), "%u", id);
entry->set(keyCALLSIGN, text);
}
return;
}
std::string CNXDNLookup::find(unsigned int id)
{
std::string callsign;
if (id == 0xFFFFU)
return std::string("ALL");
class CUserDBentry entry;
if (m_table.lookup(id, &entry)) {
callsign = entry.get(keyCALLSIGN);
} else {
char text[10U];
::snprintf(text, sizeof(text), "%u", id);
callsign = std::string(text);
}
return callsign;
}
bool CNXDNLookup::exists(unsigned int id)
{
return m_table.lookup(id, NULL);
}

53
NXDNLookup.h Normal file
View file

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NXDNLookup_H
#define NXDNLookup_H
#include "Thread.h"
#include "UserDB.h"
#include <string>
class CNXDNLookup : public CThread {
public:
CNXDNLookup(const std::string& filename, unsigned int reloadTime);
virtual ~CNXDNLookup();
bool read();
void reload();
virtual void entry();
std::string find(unsigned int id);
void findWithName(unsigned int id, class CUserDBentry *entry);
bool exists(unsigned int id);
void stop();
private:
std::string m_filename;
unsigned int m_reloadTime;
class CUserDB m_table;
bool m_stop;
bool m_reload;
};
#endif

23
NXDNNetwork.cpp Normal file
View file

@ -0,0 +1,23 @@
/*
* Copyright (C) 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 "NXDNNetwork.h"
INXDNNetwork::~INXDNNetwork()
{
}

58
NXDNNetwork.h Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 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 NXDNNetwork_H
#define NXDNNetwork_H
#include "NXDNDefines.h"
#include <cstdint>
enum NXDN_NETWORK_MESSAGE_TYPE {
NNMT_VOICE_HEADER,
NNMT_VOICE_BODY,
NNMT_VOICE_TRAILER,
NNMT_DATA_HEADER,
NNMT_DATA_BODY,
NNMT_DATA_TRAILER
};
class INXDNNetwork {
public:
virtual ~INXDNNetwork() = 0;
virtual bool open() = 0;
virtual void enable(bool enabled) = 0;
virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) = 0;
virtual bool read(unsigned char* data) = 0;
virtual void reset() = 0;
virtual bool isConnected() const = 0;
virtual void close() = 0;
virtual void clock(unsigned int ms) = 0;
private:
};
#endif

214
NXDNSACCH.cpp Normal file
View file

@ -0,0 +1,214 @@
/*
* 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 "NXDNSACCH.h"
#include "NXDNConvolution.h"
#include "NXDNDefines.h"
#include "NXDNCRC.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int INTERLEAVE_TABLE[] = {
0U, 5U, 10U, 15U, 20U, 25U, 30U, 35U, 40U, 45U, 50U, 55U,
1U, 6U, 11U, 16U, 21U, 26U, 31U, 36U, 41U, 46U, 51U, 56U,
2U, 7U, 12U, 17U, 22U, 27U, 32U, 37U, 42U, 47U, 52U, 57U,
3U, 8U, 13U, 18U, 23U, 28U, 33U, 38U, 43U, 48U, 53U, 58U,
4U, 9U, 14U, 19U, 24U, 29U, 34U, 39U, 44U, 49U, 54U, 59U
};
const unsigned int PUNCTURE_LIST[] = { 5U, 11U, 17U, 23U, 29U, 35U, 41U, 47U, 53U, 59U, 65U, 71U };
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CNXDNSACCH::CNXDNSACCH(const CNXDNSACCH& sacch) :
m_data(NULL)
{
m_data = new unsigned char[5U];
::memcpy(m_data, sacch.m_data, 5U);
}
CNXDNSACCH::CNXDNSACCH() :
m_data(NULL)
{
m_data = new unsigned char[5U];
}
CNXDNSACCH::~CNXDNSACCH()
{
delete[] m_data;
}
bool CNXDNSACCH::decode(const unsigned char* data)
{
assert(data != NULL);
unsigned char temp1[8U];
for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
bool b = READ_BIT1(data, n);
WRITE_BIT1(temp1, i, b);
}
uint8_t temp2[90U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) {
if (n == PUNCTURE_LIST[index]) {
temp2[n++] = 1U;
index++;
}
bool b = READ_BIT1(temp1, i);
temp2[n++] = b ? 2U : 0U;
}
for (unsigned int i = 0U; i < 8U; i++) {
temp2[n++] = 0U;
}
CNXDNConvolution conv;
conv.start();
n = 0U;
for (unsigned int i = 0U; i < 40U; i++) {
uint8_t s0 = temp2[n++];
uint8_t s1 = temp2[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, 36U);
return CNXDNCRC::checkCRC6(m_data, 26U);
}
void CNXDNSACCH::encode(unsigned char* data) const
{
assert(data != NULL);
unsigned char temp1[5U];
::memset(temp1, 0x00U, 5U);
for (unsigned int i = 0U; i < 26U; i++) {
bool b = READ_BIT1(m_data, i);
WRITE_BIT1(temp1, i, b);
}
CNXDNCRC::encodeCRC6(temp1, 26U);
unsigned char temp2[9U];
CNXDNConvolution conv;
conv.encode(temp1, temp2, 36U);
unsigned char temp3[8U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 72U; i++) {
if (i != PUNCTURE_LIST[index]) {
bool b = READ_BIT1(temp2, i);
WRITE_BIT1(temp3, n, b);
n++;
} else {
index++;
}
}
for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
bool b = READ_BIT1(temp3, i);
WRITE_BIT1(data, n, b);
}
}
unsigned char CNXDNSACCH::getRAN() const
{
return m_data[0U] & 0x3FU;
}
unsigned char CNXDNSACCH::getStructure() const
{
return (m_data[0U] >> 6) & 0x03U;
}
void CNXDNSACCH::getData(unsigned char* data) const
{
assert(data != NULL);
unsigned int offset = 8U;
for (unsigned int i = 0U; i < 18U; i++, offset++) {
bool b = READ_BIT1(m_data, offset);
WRITE_BIT1(data, i, b);
}
}
void CNXDNSACCH::getRaw(unsigned char* data) const
{
assert(data != NULL);
::memcpy(data, m_data, 4U);
CNXDNCRC::encodeCRC6(data, 26U);
}
void CNXDNSACCH::setRAN(unsigned char ran)
{
m_data[0U] &= 0xC0U;
m_data[0U] |= ran;
}
void CNXDNSACCH::setStructure(unsigned char structure)
{
m_data[0U] &= 0x3FU;
m_data[0U] |= (structure << 6) & 0xC0U;
}
void CNXDNSACCH::setData(const unsigned char* data)
{
assert(data != NULL);
unsigned int offset = 8U;
for (unsigned int i = 0U; i < 18U; i++, offset++) {
bool b = READ_BIT1(data, i);
WRITE_BIT1(m_data, offset, b);
}
}
void CNXDNSACCH::setRaw(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_data, data, 4U);
}
CNXDNSACCH& CNXDNSACCH::operator=(const CNXDNSACCH& sacch)
{
if (&sacch != this)
::memcpy(m_data, sacch.m_data, 5U);
return *this;
}

50
NXDNSACCH.h Normal file
View file

@ -0,0 +1,50 @@
/*
* 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(NXDNSACCH_H)
#define NXDNSACCH_H
class CNXDNSACCH {
public:
CNXDNSACCH(const CNXDNSACCH& sacch);
CNXDNSACCH();
~CNXDNSACCH();
bool decode(const unsigned char* data);
void encode(unsigned char* data) const;
unsigned char getRAN() const;
unsigned char getStructure() const;
void getData(unsigned char* data) const;
void getRaw(unsigned char* data) const;
void setRAN(unsigned char ran);
void setStructure(unsigned char structure);
void setData(const unsigned char* data);
void setRaw(const unsigned char* data);
CNXDNSACCH& operator=(const CNXDNSACCH& sacch);
private:
unsigned char* m_data;
};
#endif

217
NXDNUDCH.cpp Normal file
View file

@ -0,0 +1,217 @@
/*
* 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 "NXDNUDCH.h"
#include "NXDNConvolution.h"
#include "NXDNDefines.h"
#include "NXDNCRC.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int INTERLEAVE_TABLE[] = {
0U, 29U, 58U, 87U, 116U, 145U, 174U, 203U, 232U, 261U, 290U, 319U,
1U, 30U, 59U, 88U, 117U, 146U, 175U, 204U, 233U, 262U, 291U, 320U,
2U, 31U, 60U, 89U, 118U, 147U, 176U, 205U, 234U, 263U, 292U, 321U,
3U, 32U, 61U, 90U, 119U, 148U, 177U, 206U, 235U, 264U, 293U, 322U,
4U, 33U, 62U, 91U, 120U, 149U, 178U, 207U, 236U, 265U, 294U, 323U,
5U, 34U, 63U, 92U, 121U, 150U, 179U, 208U, 237U, 266U, 295U, 324U,
6U, 35U, 64U, 93U, 122U, 151U, 180U, 209U, 238U, 267U, 296U, 325U,
7U, 36U, 65U, 94U, 123U, 152U, 181U, 210U, 239U, 268U, 297U, 326U,
8U, 37U, 66U, 95U, 124U, 153U, 182U, 211U, 240U, 269U, 298U, 327U,
9U, 38U, 67U, 96U, 125U, 154U, 183U, 212U, 241U, 270U, 299U, 328U,
10U, 39U, 68U, 97U, 126U, 155U, 184U, 213U, 242U, 271U, 300U, 329U,
11U, 40U, 69U, 98U, 127U, 156U, 185U, 214U, 243U, 272U, 301U, 330U,
12U, 41U, 70U, 99U, 128U, 157U, 186U, 215U, 244U, 273U, 302U, 331U,
13U, 42U, 71U, 100U, 129U, 158U, 187U, 216U, 245U, 274U, 303U, 332U,
14U, 43U, 72U, 101U, 130U, 159U, 188U, 217U, 246U, 275U, 304U, 333U,
15U, 44U, 73U, 102U, 131U, 160U, 189U, 218U, 247U, 276U, 305U, 334U,
16U, 45U, 74U, 103U, 132U, 161U, 190U, 219U, 248U, 277U, 306U, 335U,
17U, 46U, 75U, 104U, 133U, 162U, 191U, 220U, 249U, 278U, 307U, 336U,
18U, 47U, 76U, 105U, 134U, 163U, 192U, 221U, 250U, 279U, 308U, 337U,
19U, 48U, 77U, 106U, 135U, 164U, 193U, 222U, 251U, 280U, 309U, 338U,
20U, 49U, 78U, 107U, 136U, 165U, 194U, 223U, 252U, 281U, 310U, 339U,
21U, 50U, 79U, 108U, 137U, 166U, 195U, 224U, 253U, 282U, 311U, 340U,
22U, 51U, 80U, 109U, 138U, 167U, 196U, 225U, 254U, 283U, 312U, 341U,
23U, 52U, 81U, 110U, 139U, 168U, 197U, 226U, 255U, 284U, 313U, 342U,
24U, 53U, 82U, 111U, 140U, 169U, 198U, 227U, 256U, 285U, 314U, 343U,
25U, 54U, 83U, 112U, 141U, 170U, 199U, 228U, 257U, 286U, 315U, 344U,
26U, 55U, 84U, 113U, 142U, 171U, 200U, 229U, 258U, 287U, 316U, 345U,
27U, 56U, 85U, 114U, 143U, 172U, 201U, 230U, 259U, 288U, 317U, 346U,
28U, 57U, 86U, 115U, 144U, 173U, 202U, 231U, 260U, 289U, 318U, 347U };
const unsigned int PUNCTURE_LIST[] = { 3U, 11U, 17U, 25U, 31U, 39U, 45U, 53U, 59U, 67U,
73U, 81U, 87U, 95U, 101U, 109U, 115U, 123U, 129U, 137U,
143U, 151U, 157U, 165U, 171U, 179U, 185U, 193U, 199U, 207U,
213U, 221U, 227U, 235U, 241U, 249U, 255U, 263U, 269U, 277U,
283U, 291U, 297U, 305U, 311U, 319U, 325U, 333U, 339U, 347U,
353U, 361U, 367U, 375U, 381U, 389U, 395U, 403U };
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CNXDNUDCH::CNXDNUDCH(const CNXDNUDCH& udch) :
m_data(NULL)
{
m_data = new unsigned char[23U + 3U];
::memcpy(m_data, udch.m_data, 23U + 3U);
}
CNXDNUDCH::CNXDNUDCH() :
m_data(NULL)
{
m_data = new unsigned char[23U + 3U];
}
CNXDNUDCH::~CNXDNUDCH()
{
delete[] m_data;
}
bool CNXDNUDCH::decode(const unsigned char* data)
{
assert(data != NULL);
unsigned char temp1[44U];
for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
bool b = READ_BIT1(data, n);
WRITE_BIT1(temp1, i, b);
}
uint8_t temp2[420U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) {
if (n == PUNCTURE_LIST[index]) {
temp2[n++] = 1U;
index++;
}
bool b = READ_BIT1(temp1, i);
temp2[n++] = b ? 2U : 0U;
}
for (unsigned int i = 0U; i < 8U; i++) {
temp2[n++] = 0U;
}
CNXDNConvolution conv;
conv.start();
n = 0U;
for (unsigned int i = 0U; i < 207U; i++) {
uint8_t s0 = temp2[n++];
uint8_t s1 = temp2[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, 203U);
return CNXDNCRC::checkCRC15(m_data, 184U);
}
void CNXDNUDCH::encode(unsigned char* data) const
{
assert(data != NULL);
unsigned char temp1[25U];
::memset(temp1, 0x00U, 25U);
::memcpy(temp1, m_data, 23U);
CNXDNCRC::encodeCRC15(temp1, 184U);
unsigned char temp2[51U];
CNXDNConvolution conv;
conv.encode(temp1, temp2, 203U);
unsigned char temp3[44U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 406U; i++) {
if (i != PUNCTURE_LIST[index]) {
bool b = READ_BIT1(temp2, i);
WRITE_BIT1(temp3, n, b);
n++;
} else {
index++;
}
}
for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
bool b = READ_BIT1(temp3, i);
WRITE_BIT1(data, n, b);
}
}
unsigned char CNXDNUDCH::getRAN() const
{
return m_data[0U] & 0x3FU;
}
void CNXDNUDCH::getData(unsigned char* data) const
{
assert(data != NULL);
::memcpy(data, m_data + 1U, 22U);
}
void CNXDNUDCH::getRaw(unsigned char* data) const
{
assert(data != NULL);
::memset(data, 0x00U, 25U);
::memcpy(data, m_data, 23U);
}
void CNXDNUDCH::setRAN(unsigned char ran)
{
m_data[0U] = ran;
}
void CNXDNUDCH::setData(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_data + 1U, data, 22U);
}
void CNXDNUDCH::setRaw(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_data, data, 25U);
}
CNXDNUDCH& CNXDNUDCH::operator=(const CNXDNUDCH& udch)
{
if (&udch != this)
::memcpy(m_data, udch.m_data, 23U + 2U);
return *this;
}

48
NXDNUDCH.h Normal file
View file

@ -0,0 +1,48 @@
/*
* 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(NXDNUDCH_H)
#define NXDNUDCH_H
class CNXDNUDCH {
public:
CNXDNUDCH(const CNXDNUDCH& udch);
CNXDNUDCH();
~CNXDNUDCH();
bool decode(const unsigned char* data);
void encode(unsigned char* data) const;
unsigned char getRAN() const;
void getData(unsigned char* data) const;
void getRaw(unsigned char* data) const;
void setRAN(unsigned char ran);
void setData(const unsigned char* data);
void setRaw(const unsigned char* data);
CNXDNUDCH& operator=(const CNXDNUDCH& udch);
private:
unsigned char* m_data;
};
#endif

View file

@ -26,8 +26,18 @@
#include <ctime>
#include <clocale>
const unsigned int DSTAR_RSSI_COUNT = 3U; // 3 * 420ms = 1260ms
const unsigned int DSTAR_BER_COUNT = 63U; // 63 * 20ms = 1260ms
const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms
const unsigned int DMR_BER_COUNT = 24U; // 24 * 60ms = 1440ms
const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
const unsigned int YSF_BER_COUNT = 13U; // 13 * 100ms = 1300ms
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
const unsigned int P25_BER_COUNT = 7U; // 7 * 180ms = 1260ms
const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms
const unsigned int NXDN_BER_COUNT = 28U; // 28 * 40ms = 1120ms
const unsigned int M17_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms
const unsigned int M17_BER_COUNT = 28U; // 28 * 40ms = 1120ms
#define LAYOUT_COMPAT_MASK (7 << 0) // compatibility for old setting
#define LAYOUT_TA_ENABLE (1 << 4) // enable Talker Alias (TA) display
@ -252,6 +262,107 @@ void CNextion::setQuitInt()
m_mode = MODE_QUIT;
}
void CNextion::setFMInt()
{
sendCommand("page MMDVM");
sendCommandAction(1U);
char command[20];
if (m_brightness > 0) {
::sprintf(command, "dim=%u", m_brightness);
sendCommand(command);
}
sendCommand("t0.txt=\"FM\"");
sendCommandAction(15U);
m_clockDisplayTimer.stop();
m_mode = MODE_FM;
}
void CNextion::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{
assert(my1 != NULL);
assert(my2 != NULL);
assert(your != NULL);
assert(type != NULL);
assert(reflector != NULL);
if (m_mode != MODE_DSTAR) {
sendCommand("page DStar");
sendCommandAction(2U);
}
char text[50U];
if (m_brightness>0) {
::sprintf(text, "dim=%u", m_brightness);
sendCommand(text);
}
::sprintf(text, "t0.txt=\"%s %.8s/%4.4s\"", type, my1, my2);
sendCommand(text);
sendCommandAction(42U);
::sprintf(text, "t1.txt=\"%.8s\"", your);
sendCommand(text);
sendCommandAction(45U);
if (::strcmp(reflector, " ") != 0) {
::sprintf(text, "t2.txt=\"via %.8s\"", reflector);
sendCommand(text);
sendCommandAction(46U);
}
m_clockDisplayTimer.stop();
m_mode = MODE_DSTAR;
m_rssiAccum1 = 0U;
m_berAccum1 = 0.0F;
m_rssiCount1 = 0U;
m_berCount1 = 0U;
}
void CNextion::writeDStarRSSIInt(unsigned char rssi)
{
m_rssiAccum1 += rssi;
m_rssiCount1++;
if (m_rssiCount1 == DSTAR_RSSI_COUNT) {
char text[25U];
::sprintf(text, "t3.txt=\"-%udBm\"", m_rssiAccum1 / DSTAR_RSSI_COUNT);
sendCommand(text);
sendCommandAction(47U);
m_rssiAccum1 = 0U;
m_rssiCount1 = 0U;
}
}
void CNextion::writeDStarBERInt(float ber)
{
m_berAccum1 += ber;
m_berCount1++;
if (m_berCount1 == DSTAR_BER_COUNT) {
char text[25U];
::sprintf(text, "t4.txt=\"%.1f%%\"", m_berAccum1 / float(DSTAR_BER_COUNT));
sendCommand(text);
sendCommandAction(48U);
m_berAccum1 = 0.0F;
m_berCount1 = 0U;
}
}
void CNextion::clearDStarInt()
{
sendCommand("t0.txt=\"Listening\"");
sendCommandAction(41U);
sendCommand("t1.txt=\"\"");
sendCommand("t2.txt=\"\"");
sendCommand("t3.txt=\"\"");
sendCommand("t4.txt=\"\"");
}
void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
{
assert(type != NULL);
@ -487,6 +598,338 @@ void CNextion::clearDMRInt(unsigned int slotNo)
}
}
void CNextion::writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin)
{
assert(source != NULL);
assert(dest != NULL);
assert(type != NULL);
assert(origin != NULL);
if (m_mode != MODE_YSF) {
sendCommand("page YSF");
sendCommandAction(4U);
}
char text[30U];
if (m_brightness>0) {
::sprintf(text, "dim=%u", m_brightness);
sendCommand(text);
}
::sprintf(text, "t0.txt=\"%s %.10s\"", type, source);
sendCommand(text);
sendCommandAction(82U);
::sprintf(text, "t1.txt=\"DG-ID %u\"", dgid);
sendCommand(text);
sendCommandAction(83U);
if (::strcmp(origin, " ") != 0) {
::sprintf(text, "t2.txt=\"at %.10s\"", origin);
sendCommand(text);
sendCommandAction(84U);
}
m_clockDisplayTimer.stop();
m_mode = MODE_YSF;
m_rssiAccum1 = 0U;
m_berAccum1 = 0.0F;
m_rssiCount1 = 0U;
m_berCount1 = 0U;
}
void CNextion::writeFusionRSSIInt(unsigned char rssi)
{
m_rssiAccum1 += rssi;
m_rssiCount1++;
if (m_rssiCount1 == YSF_RSSI_COUNT) {
char text[25U];
::sprintf(text, "t3.txt=\"-%udBm\"", m_rssiAccum1 / YSF_RSSI_COUNT);
sendCommand(text);
sendCommandAction(85U);
m_rssiAccum1 = 0U;
m_rssiCount1 = 0U;
}
}
void CNextion::writeFusionBERInt(float ber)
{
m_berAccum1 += ber;
m_berCount1++;
if (m_berCount1 == YSF_BER_COUNT) {
char text[25U];
::sprintf(text, "t4.txt=\"%.1f%%\"", m_berAccum1 / float(YSF_BER_COUNT));
sendCommand(text);
sendCommandAction(86U);
m_berAccum1 = 0.0F;
m_berCount1 = 0U;
}
}
void CNextion::clearFusionInt()
{
sendCommand("t0.txt=\"Listening\"");
sendCommandAction(81U);
sendCommand("t1.txt=\"\"");
sendCommand("t2.txt=\"\"");
sendCommand("t3.txt=\"\"");
sendCommand("t4.txt=\"\"");
}
void CNextion::writeP25Int(const char* source, bool group, unsigned int dest, const char* type)
{
assert(source != NULL);
assert(type != NULL);
if (m_mode != MODE_P25) {
sendCommand("page P25");
sendCommandAction(5U);
}
char text[30U];
if (m_brightness>0) {
::sprintf(text, "dim=%u", m_brightness);
sendCommand(text);
}
::sprintf(text, "t0.txt=\"%s %.10s\"", type, source);
sendCommand(text);
sendCommandAction(102U);
::sprintf(text, "t1.txt=\"%s%u\"", group ? "TG" : "", dest);
sendCommand(text);
sendCommandAction(103U);
m_clockDisplayTimer.stop();
m_mode = MODE_P25;
m_rssiAccum1 = 0U;
m_berAccum1 = 0.0F;
m_rssiCount1 = 0U;
m_berCount1 = 0U;
}
void CNextion::writeP25RSSIInt(unsigned char rssi)
{
m_rssiAccum1 += rssi;
m_rssiCount1++;
if (m_rssiCount1 == P25_RSSI_COUNT) {
char text[25U];
::sprintf(text, "t2.txt=\"-%udBm\"", m_rssiAccum1 / P25_RSSI_COUNT);
sendCommand(text);
sendCommandAction(104U);
m_rssiAccum1 = 0U;
m_rssiCount1 = 0U;
}
}
void CNextion::writeP25BERInt(float ber)
{
m_berAccum1 += ber;
m_berCount1++;
if (m_berCount1 == P25_BER_COUNT) {
char text[25U];
::sprintf(text, "t3.txt=\"%.1f%%\"", m_berAccum1 / float(P25_BER_COUNT));
sendCommand(text);
sendCommandAction(105U);
m_berAccum1 = 0.0F;
m_berCount1 = 0U;
}
}
void CNextion::clearP25Int()
{
sendCommand("t0.txt=\"Listening\"");
sendCommandAction(101U);
sendCommand("t1.txt=\"\"");
sendCommand("t2.txt=\"\"");
sendCommand("t3.txt=\"\"");
}
void CNextion::writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type)
{
assert(source != NULL);
assert(type != NULL);
if (m_mode != MODE_NXDN) {
sendCommand("page NXDN");
sendCommandAction(6U);
}
char text[30U];
if (m_brightness>0) {
::sprintf(text, "dim=%u", m_brightness);
sendCommand(text);
}
::sprintf(text, "t0.txt=\"%s %.10s\"", type, source);
sendCommand(text);
sendCommandAction(122U);
::sprintf(text, "t1.txt=\"%s%u\"", group ? "TG" : "", dest);
sendCommand(text);
sendCommandAction(123U);
m_clockDisplayTimer.stop();
m_mode = MODE_NXDN;
m_rssiAccum1 = 0U;
m_berAccum1 = 0.0F;
m_rssiCount1 = 0U;
m_berCount1 = 0U;
}
void CNextion::writeNXDNRSSIInt(unsigned char rssi)
{
m_rssiAccum1 += rssi;
m_rssiCount1++;
if (m_rssiCount1 == NXDN_RSSI_COUNT) {
char text[25U];
::sprintf(text, "t2.txt=\"-%udBm\"", m_rssiAccum1 / NXDN_RSSI_COUNT);
sendCommand(text);
sendCommandAction(124U);
m_rssiAccum1 = 0U;
m_rssiCount1 = 0U;
}
}
void CNextion::writeNXDNBERInt(float ber)
{
m_berAccum1 += ber;
m_berCount1++;
if (m_berCount1 == NXDN_BER_COUNT) {
char text[25U];
::sprintf(text, "t3.txt=\"%.1f%%\"", m_berAccum1 / float(NXDN_BER_COUNT));
sendCommand(text);
sendCommandAction(125U);
m_berAccum1 = 0.0F;
m_berCount1 = 0U;
}
}
void CNextion::clearNXDNInt()
{
sendCommand("t0.txt=\"Listening\"");
sendCommandAction(121U);
sendCommand("t1.txt=\"\"");
sendCommand("t2.txt=\"\"");
sendCommand("t3.txt=\"\"");
}
void CNextion::writeM17Int(const char* source, const char* dest, const char* type)
{
assert(source != NULL);
assert(dest != NULL);
assert(type != NULL);
if (m_mode != MODE_M17) {
sendCommand("page M17");
sendCommandAction(6U);
}
char text[30U];
if (m_brightness > 0) {
::sprintf(text, "dim=%u", m_brightness);
sendCommand(text);
}
::sprintf(text, "t0.txt=\"%s %.10s\"", type, source);
sendCommand(text);
sendCommandAction(122U);
::sprintf(text, "t1.txt=\"%s\"", dest);
sendCommand(text);
sendCommandAction(123U);
m_clockDisplayTimer.stop();
m_mode = MODE_M17;
m_rssiAccum1 = 0U;
m_berAccum1 = 0.0F;
m_rssiCount1 = 0U;
m_berCount1 = 0U;
}
void CNextion::writeM17RSSIInt(unsigned char rssi)
{
m_rssiAccum1 += rssi;
m_rssiCount1++;
if (m_rssiCount1 == M17_RSSI_COUNT) {
char text[25U];
::sprintf(text, "t2.txt=\"-%udBm\"", m_rssiAccum1 / M17_RSSI_COUNT);
sendCommand(text);
sendCommandAction(124U);
m_rssiAccum1 = 0U;
m_rssiCount1 = 0U;
}
}
void CNextion::writeM17BERInt(float ber)
{
m_berAccum1 += ber;
m_berCount1++;
if (m_berCount1 == M17_BER_COUNT) {
char text[25U];
::sprintf(text, "t3.txt=\"%.1f%%\"", m_berAccum1 / float(M17_BER_COUNT));
sendCommand(text);
sendCommandAction(125U);
m_berAccum1 = 0.0F;
m_berCount1 = 0U;
}
}
void CNextion::clearM17Int()
{
sendCommand("t0.txt=\"Listening\"");
sendCommandAction(121U);
sendCommand("t1.txt=\"\"");
sendCommand("t2.txt=\"\"");
sendCommand("t3.txt=\"\"");
}
void CNextion::writePOCSAGInt(uint32_t ric, const std::string& message)
{
if (m_mode != MODE_POCSAG) {
sendCommand("page POCSAG");
sendCommandAction(7U);
}
char text[200U];
if (m_brightness>0) {
::sprintf(text, "dim=%u", m_brightness);
sendCommand(text);
}
::sprintf(text, "t0.txt=\"RIC: %u\"", ric);
sendCommand(text);
sendCommandAction(132U);
::sprintf(text, "t1.txt=\"%s\"", message.c_str());
sendCommand(text);
sendCommandAction(133U);
m_clockDisplayTimer.stop();
m_mode = MODE_POCSAG;
}
void CNextion::clearPOCSAGInt()
{
sendCommand("t0.txt=\"Waiting\"");
sendCommandAction(134U);
sendCommand("t1.txt=\"\"");
}
void CNextion::writeCWInt()
{
sendCommand("t1.txt=\"Sending CW Ident\"");

View file

@ -41,6 +41,12 @@ protected:
virtual void setErrorInt(const char* text);
virtual void setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi);
virtual void writeDStarBERInt(float ber);
virtual void clearDStarInt();
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
@ -49,6 +55,29 @@ protected:
virtual void writeDMRBERInt(unsigned int slotNo, float ber);
virtual void clearDMRInt(unsigned int slotNo);
virtual void writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin);
virtual void writeFusionRSSIInt(unsigned char rssi);
virtual void writeFusionBERInt(float ber);
virtual void clearFusionInt();
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
virtual void writeP25RSSIInt(unsigned char rssi);
virtual void writeP25BERInt(float ber);
virtual void clearP25Int();
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
virtual void writeNXDNRSSIInt(unsigned char rssi);
virtual void writeNXDNBERInt(float ber);
virtual void clearNXDNInt();
virtual void writeM17Int(const char* source, const char* dest, const char* type);
virtual void writeM17RSSIInt(unsigned char rssi);
virtual void writeM17BERInt(float ber);
virtual void clearM17Int();
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);
virtual void clearPOCSAGInt();
virtual void writeCWInt();
virtual void clearCWInt();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more