Compare commits

..

2 commits

Author SHA1 Message Date
Jonathan Naylor
d0c3d1ecfb More rollback to original jitter buffer processing. 2019-11-04 13:48:13 +00:00
Jonathan Naylor
1e7f99127f Add the DMR jitter buffer back in. 2019-11-03 22:17:51 +00:00
223 changed files with 27947 additions and 45233 deletions

1
.gitignore vendored
View file

@ -17,4 +17,3 @@ RemoteCommand
.vs .vs
*.ambe *.ambe
GitVersion.h 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"
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010,2014,2016,2018,2021 by Jonathan Naylor G4KLX * Copyright (C) 2010,2014,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2016 Mathias Weyland, HB9FRV * Copyright (C) 2016 Mathias Weyland, HB9FRV
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -20,7 +20,6 @@
#include "Golay24128.h" #include "Golay24128.h"
#include "Hamming.h" #include "Hamming.h"
#include "AMBEFEC.h" #include "AMBEFEC.h"
#include "Utils.h"
#include <cstdio> #include <cstdio>
#include <cassert> #include <cassert>
@ -796,31 +795,34 @@ unsigned int CAMBEFEC::regenerateDStar(unsigned int& a, unsigned int& b) const
unsigned int orig_a = a; unsigned int orig_a = a;
unsigned int orig_b = b; unsigned int orig_b = b;
unsigned int data; unsigned int data = CGolay24128::decode24128(a);
bool valid1 = CGolay24128::decode24128(a, data);
if (!valid1) a = CGolay24128::encode24128(data);
return 10U;
// The PRNG // The PRNG
unsigned int p = PRNG_TABLE[data]; unsigned int p = PRNG_TABLE[data];
b ^= p; b ^= p;
unsigned int datb; unsigned int datb = CGolay24128::decode24128(b);
bool valid2 = CGolay24128::decode24128(b, datb);
if (!valid2)
return 10U;
a = CGolay24128::encode24128(data);
b = CGolay24128::encode24128(datb); b = CGolay24128::encode24128(datb);
b ^= p; b ^= p;
unsigned int errsA = 0U, errsB = 0U;
unsigned int v = a ^ orig_a; unsigned int v = a ^ orig_a;
unsigned int errsA = CUtils::countBits(v); while (v != 0U) {
v &= v - 1U;
errsA++;
}
v = b ^ orig_b; v = b ^ orig_b;
unsigned int errsB = CUtils::countBits(v); while (v != 0U) {
v &= v - 1U;
errsB++;
}
return errsA + errsB; return errsA + errsB;
} }
@ -830,14 +832,7 @@ unsigned int CAMBEFEC::regenerateDMR(unsigned int& a, unsigned int& b, unsigned
unsigned int orig_a = a; unsigned int orig_a = a;
unsigned int orig_b = b; unsigned int orig_b = b;
unsigned int data; unsigned int data = CGolay24128::decode24128(a);
bool valid = CGolay24128::decode24128(a, data);
if (!valid) {
a = 0xF00292U;
b = 0x0E0B20U;
c = 0x000000U;
return 10U; // An invalid A block gives an error count of 10
}
a = CGolay24128::encode24128(data); a = CGolay24128::encode24128(data);
@ -852,11 +847,19 @@ unsigned int CAMBEFEC::regenerateDMR(unsigned int& a, unsigned int& b, unsigned
b ^= p; b ^= p;
unsigned int errsA = 0U, errsB = 0U;
unsigned int v = a ^ orig_a; unsigned int v = a ^ orig_a;
unsigned int errsA = CUtils::countBits(v); while (v != 0U) {
v &= v - 1U;
errsA++;
}
v = b ^ orig_b; v = b ^ orig_b;
unsigned int errsB = CUtils::countBits(v); while (v != 0U) {
v &= v - 1U;
errsB++;
}
if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) { if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) {
a = 0xF00292U; a = 0xF00292U;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -76,6 +76,16 @@ void CCASTInfo::setQuitInt()
{ {
} }
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) void CCASTInfo::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
{ {
if (m_modem != NULL) if (m_modem != NULL)
@ -86,6 +96,46 @@ void CCASTInfo::clearDMRInt(unsigned int slotNo)
{ {
} }
void CCASTInfo::writeFusionInt(const char* source, const char* dest, const char* type, const char* origin)
{
if (m_modem != NULL)
m_modem->writeYSFInfo(source, dest, 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::writePOCSAGInt(uint32_t ric, const std::string& message)
{
if (m_modem != NULL)
m_modem->writePOCSAGInfo(ric, message);
}
void CCASTInfo::clearPOCSAGInt()
{
}
void CCASTInfo::writeCWInt() void CCASTInfo::writeCWInt()
{ {
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -25,7 +25,6 @@
#include "NetworkInfo.h" #include "NetworkInfo.h"
#include "Modem.h" #include "Modem.h"
class CCASTInfo : public CDisplay class CCASTInfo : public CDisplay
{ {
public: public:
@ -42,9 +41,24 @@ protected:
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
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 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 clearDMRInt(unsigned int slotNo);
virtual void writeFusionInt(const char* source, const char* dest, 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 writePOCSAGInt(uint32_t ric, const std::string& message);
virtual void clearPOCSAGInt();
virtual void writeCWInt(); virtual void writeCWInt();
virtual void clearCWInt(); virtual void clearCWInt();

919
Conf.cpp

File diff suppressed because it is too large Load diff

262
Conf.h
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -54,7 +54,6 @@ public:
unsigned int getLogFileLevel() const; unsigned int getLogFileLevel() const;
std::string getLogFilePath() const; std::string getLogFilePath() const;
std::string getLogFileRoot() const; std::string getLogFileRoot() const;
bool getLogFileRotate() const;
// The CW ID section // The CW ID section
bool getCWIdEnabled() const; bool getCWIdEnabled() const;
@ -65,16 +64,14 @@ public:
std::string getDMRIdLookupFile() const; std::string getDMRIdLookupFile() const;
unsigned int getDMRIdLookupTime() const; unsigned int getDMRIdLookupTime() const;
// The NXDN Id section
std::string getNXDNIdLookupFile() const;
unsigned int getNXDNIdLookupTime() const;
// The Modem section // The Modem section
std::string getModemPort() const;
std::string getModemProtocol() const; std::string getModemProtocol() const;
std::string getModemUARTPort() const; unsigned int getModemAddress() const;
unsigned int getModemUARTSpeed() const;
std::string getModemI2CPort() const;
unsigned int getModemI2CAddress() const;
std::string getModemModemAddress() const;
unsigned short getModemModemPort() const;
std::string getModemLocalAddress() const;
unsigned short getModemLocalPort() const;
bool getModemRXInvert() const; bool getModemRXInvert() const;
bool getModemTXInvert() const; bool getModemTXInvert() const;
bool getModemPTTInvert() const; bool getModemPTTInvert() const;
@ -92,25 +89,37 @@ public:
float getModemYSFTXLevel() const; float getModemYSFTXLevel() const;
float getModemP25TXLevel() const; float getModemP25TXLevel() const;
float getModemNXDNTXLevel() const; float getModemNXDNTXLevel() const;
float getModemM17TXLevel() const;
float getModemPOCSAGTXLevel() const; float getModemPOCSAGTXLevel() const;
float getModemFMTXLevel() const;
float getModemAX25TXLevel() const;
std::string getModemRSSIMappingFile() const; std::string getModemRSSIMappingFile() const;
bool getModemUseCOSAsLockout() const;
bool getModemTrace() const; bool getModemTrace() const;
bool getModemDebug() const; bool getModemDebug() const;
// The Transparent Data section // The Transparent Data section
bool getTransparentEnabled() const; bool getTransparentEnabled() const;
std::string getTransparentRemoteAddress() const; std::string getTransparentRemoteAddress() const;
unsigned short getTransparentRemotePort() const; unsigned int getTransparentRemotePort() const;
unsigned short getTransparentLocalPort() const; unsigned int getTransparentLocalPort() const;
unsigned int getTransparentSendFrameType() const; unsigned int getTransparentSendFrameType() const;
// The UMP section
bool getUMPEnabled() const;
std::string getUMPPort() const;
// The D-Star section
bool getDStarEnabled() const;
std::string getDStarModule() const;
bool getDStarSelfOnly() const;
std::vector<std::string> getDStarBlackList() const;
bool getDStarAckReply() const;
unsigned int getDStarAckTime() const;
bool getDStarAckMessage() const;
bool getDStarErrorReply() const;
bool getDStarRemoteGateway() const;
unsigned int getDStarModeHang() const;
// The DMR section // The DMR section
bool getDMREnabled() const; bool getDMREnabled() const;
DMR_BEACONS getDMRBeacons() const; bool getDMRBeacons() const;
unsigned int getDMRBeaconInterval() const; unsigned int getDMRBeaconInterval() const;
unsigned int getDMRBeaconDuration() const; unsigned int getDMRBeaconDuration() const;
unsigned int getDMRId() const; unsigned int getDMRId() const;
@ -126,15 +135,52 @@ public:
unsigned int getDMRCallHang() const; unsigned int getDMRCallHang() const;
unsigned int getDMRTXHang() const; unsigned int getDMRTXHang() const;
unsigned int getDMRModeHang() const; unsigned int getDMRModeHang() const;
DMR_OVCM_TYPES getDMROVCM() const; bool getDMROVCM() const;
// The System Fusion section
bool getFusionEnabled() const;
bool getFusionLowDeviation() const;
bool getFusionRemoteGateway() const;
bool getFusionSelfOnly() const;
unsigned int getFusionTXHang() const;
bool getFusionDGIdEnabled() const;
unsigned char getFusionDGId() 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 getP25ModeHang() const;
// The NXDN section
bool getNXDNEnabled() const;
unsigned int getNXDNId() const;
unsigned int getNXDNRAN() const;
bool getNXDNSelfOnly() const;
bool getNXDNRemoteGateway() const;
unsigned int getNXDNModeHang() const;
// The POCSAG section
bool getPOCSAGEnabled() const;
unsigned int getPOCSAGFrequency() const;
// The D-Star Network section
bool getDStarNetworkEnabled() const;
std::string getDStarGatewayAddress() const;
unsigned int getDStarGatewayPort() const;
unsigned int getDStarLocalPort() const;
unsigned int getDStarNetworkModeHang() const;
bool getDStarNetworkDebug() const;
// The DMR Network section // The DMR Network section
bool getDMRNetworkEnabled() const; bool getDMRNetworkEnabled() const;
std::string getDMRNetworkType() const; std::string getDMRNetworkAddress() const;
std::string getDMRNetworkRemoteAddress() const; unsigned int getDMRNetworkPort() const;
unsigned short getDMRNetworkRemotePort() const; unsigned int getDMRNetworkLocal() const;
std::string getDMRNetworkLocalAddress() const;
unsigned short getDMRNetworkLocalPort() const;
std::string getDMRNetworkPassword() const; std::string getDMRNetworkPassword() const;
std::string getDMRNetworkOptions() const; std::string getDMRNetworkOptions() const;
bool getDMRNetworkDebug() const; bool getDMRNetworkDebug() const;
@ -143,6 +189,41 @@ public:
bool getDMRNetworkSlot2() const; bool getDMRNetworkSlot2() const;
unsigned int getDMRNetworkModeHang() const; unsigned int getDMRNetworkModeHang() const;
// The System Fusion Network section
bool getFusionNetworkEnabled() const;
std::string getFusionNetworkMyAddress() const;
unsigned int getFusionNetworkMyPort() const;
std::string getFusionNetworkGatewayAddress() const;
unsigned int getFusionNetworkGatewayPort() const;
unsigned int getFusionNetworkModeHang() const;
bool getFusionNetworkDebug() const;
// The P25 Network section
bool getP25NetworkEnabled() const;
std::string getP25GatewayAddress() const;
unsigned int getP25GatewayPort() const;
unsigned int getP25LocalPort() const;
unsigned int getP25NetworkModeHang() const;
bool getP25NetworkDebug() const;
// The NXDN Network section
bool getNXDNNetworkEnabled() const;
std::string getNXDNGatewayAddress() const;
unsigned int getNXDNGatewayPort() const;
std::string getNXDNLocalAddress() const;
unsigned int getNXDNLocalPort() const;
unsigned int getNXDNNetworkModeHang() const;
bool getNXDNNetworkDebug() const;
// The POCSAG Network section
bool getPOCSAGNetworkEnabled() const;
std::string getPOCSAGGatewayAddress() const;
unsigned int getPOCSAGGatewayPort() const;
std::string getPOCSAGLocalAddress() const;
unsigned int getPOCSAGLocalPort() const;
unsigned int getPOCSAGNetworkModeHang() const;
bool getPOCSAGNetworkDebug() const;
// The TFTSERIAL section // The TFTSERIAL section
std::string getTFTSerialPort() const; std::string getTFTSerialPort() const;
unsigned int getTFTSerialBrightness() const; unsigned int getTFTSerialBrightness() const;
@ -178,8 +259,8 @@ public:
// The LCDproc section // The LCDproc section
std::string getLCDprocAddress() const; std::string getLCDprocAddress() const;
unsigned short getLCDprocPort() const; unsigned int getLCDprocPort() const;
unsigned short getLCDprocLocalPort() const; unsigned int getLCDprocLocalPort() const;
bool getLCDprocDisplayClock() const; bool getLCDprocDisplayClock() const;
bool getLCDprocUTC() const; bool getLCDprocUTC() const;
bool getLCDprocDimOnIdle() const; bool getLCDprocDimOnIdle() const;
@ -188,10 +269,14 @@ public:
bool getLockFileEnabled() const; bool getLockFileEnabled() const;
std::string getLockFileName() const; std::string getLockFileName() const;
// The Mobile GPS section
bool getMobileGPSEnabled() const;
std::string getMobileGPSAddress() const;
unsigned int getMobileGPSPort() const;
// The Remote Control section // The Remote Control section
bool getRemoteControlEnabled() const; bool getRemoteControlEnabled() const;
std::string getRemoteControlAddress() const; unsigned int getRemoteControlPort() const;
unsigned short getRemoteControlPort() const;
private: private:
std::string m_file; std::string m_file;
@ -216,7 +301,6 @@ private:
unsigned int m_logFileLevel; unsigned int m_logFileLevel;
std::string m_logFilePath; std::string m_logFilePath;
std::string m_logFileRoot; std::string m_logFileRoot;
bool m_logFileRotate;
bool m_cwIdEnabled; bool m_cwIdEnabled;
unsigned int m_cwIdTime; unsigned int m_cwIdTime;
@ -228,15 +312,9 @@ private:
std::string m_nxdnIdLookupFile; std::string m_nxdnIdLookupFile;
unsigned int m_nxdnIdLookupTime; unsigned int m_nxdnIdLookupTime;
std::string m_modemPort;
std::string m_modemProtocol; std::string m_modemProtocol;
std::string m_modemUARTPort; unsigned int m_modemAddress;
unsigned int m_modemUARTSpeed;
std::string m_modemI2CPort;
unsigned int m_modemI2CAddress;
std::string m_modemModemAddress;
unsigned short m_modemModemPort;
std::string m_modemLocalAddress;
unsigned short m_modemLocalPort;
bool m_modemRXInvert; bool m_modemRXInvert;
bool m_modemTXInvert; bool m_modemTXInvert;
bool m_modemPTTInvert; bool m_modemPTTInvert;
@ -249,20 +327,38 @@ private:
float m_modemRFLevel; float m_modemRFLevel;
float m_modemRXLevel; float m_modemRXLevel;
float m_modemCWIdTXLevel; float m_modemCWIdTXLevel;
float m_modemDStarTXLevel;
float m_modemDMRTXLevel; float m_modemDMRTXLevel;
float m_modemYSFTXLevel;
float m_modemP25TXLevel;
float m_modemNXDNTXLevel;
float m_modemPOCSAGTXLevel;
std::string m_modemRSSIMappingFile; std::string m_modemRSSIMappingFile;
bool m_modemUseCOSAsLockout;
bool m_modemTrace; bool m_modemTrace;
bool m_modemDebug; bool m_modemDebug;
bool m_transparentEnabled; bool m_transparentEnabled;
std::string m_transparentRemoteAddress; std::string m_transparentRemoteAddress;
unsigned short m_transparentRemotePort; unsigned int m_transparentRemotePort;
unsigned short m_transparentLocalPort; unsigned int m_transparentLocalPort;
unsigned int m_transparentSendFrameType; unsigned int m_transparentSendFrameType;
bool m_umpEnabled;
std::string m_umpPort;
bool m_dstarEnabled;
std::string m_dstarModule;
bool m_dstarSelfOnly;
std::vector<std::string> m_dstarBlackList;
bool m_dstarAckReply;
unsigned int m_dstarAckTime;
bool m_dstarAckMessage;
bool m_dstarErrorReply;
bool m_dstarRemoteGateway;
unsigned int m_dstarModeHang;
bool m_dmrEnabled; bool m_dmrEnabled;
DMR_BEACONS m_dmrBeacons; bool m_dmrBeacons;
unsigned int m_dmrBeaconInterval; unsigned int m_dmrBeaconInterval;
unsigned int m_dmrBeaconDuration; unsigned int m_dmrBeaconDuration;
unsigned int m_dmrId; unsigned int m_dmrId;
@ -278,14 +374,46 @@ private:
unsigned int m_dmrCallHang; unsigned int m_dmrCallHang;
unsigned int m_dmrTXHang; unsigned int m_dmrTXHang;
unsigned int m_dmrModeHang; unsigned int m_dmrModeHang;
DMR_OVCM_TYPES m_dmrOVCM; bool m_dmrOVCM;
bool m_fusionEnabled;
bool m_fusionLowDeviation;
bool m_fusionRemoteGateway;
bool m_fusionSelfOnly;
unsigned int m_fusionTXHang;
bool m_fusionDGIdEnabled;
unsigned char m_fusionDGId;
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_p25ModeHang;
bool m_nxdnEnabled;
unsigned int m_nxdnId;
unsigned int m_nxdnRAN;
bool m_nxdnSelfOnly;
bool m_nxdnRemoteGateway;
unsigned int m_nxdnModeHang;
bool m_pocsagEnabled;
unsigned int m_pocsagFrequency;
bool m_dstarNetworkEnabled;
std::string m_dstarGatewayAddress;
unsigned int m_dstarGatewayPort;
unsigned int m_dstarLocalPort;
unsigned int m_dstarNetworkModeHang;
bool m_dstarNetworkDebug;
bool m_dmrNetworkEnabled; bool m_dmrNetworkEnabled;
std::string m_dmrNetworkType; std::string m_dmrNetworkAddress;
std::string m_dmrNetworkRemoteAddress; unsigned int m_dmrNetworkPort;
unsigned short m_dmrNetworkRemotePort; unsigned int m_dmrNetworkLocal;
std::string m_dmrNetworkLocalAddress;
unsigned short m_dmrNetworkLocalPort;
std::string m_dmrNetworkPassword; std::string m_dmrNetworkPassword;
std::string m_dmrNetworkOptions; std::string m_dmrNetworkOptions;
bool m_dmrNetworkDebug; bool m_dmrNetworkDebug;
@ -294,6 +422,37 @@ private:
bool m_dmrNetworkSlot2; bool m_dmrNetworkSlot2;
unsigned int m_dmrNetworkModeHang; unsigned int m_dmrNetworkModeHang;
bool m_fusionNetworkEnabled;
std::string m_fusionNetworkMyAddress;
unsigned int m_fusionNetworkMyPort;
std::string m_fusionNetworkGatewayAddress;
unsigned int m_fusionNetworkGatewayPort;
unsigned int m_fusionNetworkModeHang;
bool m_fusionNetworkDebug;
bool m_p25NetworkEnabled;
std::string m_p25GatewayAddress;
unsigned int m_p25GatewayPort;
unsigned int m_p25LocalPort;
unsigned int m_p25NetworkModeHang;
bool m_p25NetworkDebug;
bool m_nxdnNetworkEnabled;
std::string m_nxdnGatewayAddress;
unsigned int m_nxdnGatewayPort;
std::string m_nxdnLocalAddress;
unsigned int m_nxdnLocalPort;
unsigned int m_nxdnNetworkModeHang;
bool m_nxdnNetworkDebug;
bool m_pocsagNetworkEnabled;
std::string m_pocsagGatewayAddress;
unsigned int m_pocsagGatewayPort;
std::string m_pocsagLocalAddress;
unsigned int m_pocsagLocalPort;
unsigned int m_pocsagNetworkModeHang;
bool m_pocsagNetworkDebug;
std::string m_tftSerialPort; std::string m_tftSerialPort;
unsigned int m_tftSerialBrightness; unsigned int m_tftSerialBrightness;
@ -324,8 +483,8 @@ private:
bool m_oledLogoScreensaver; bool m_oledLogoScreensaver;
std::string m_lcdprocAddress; std::string m_lcdprocAddress;
unsigned short m_lcdprocPort; unsigned int m_lcdprocPort;
unsigned short m_lcdprocLocalPort; unsigned int m_lcdprocLocalPort;
bool m_lcdprocDisplayClock; bool m_lcdprocDisplayClock;
bool m_lcdprocUTC; bool m_lcdprocUTC;
bool m_lcdprocDimOnIdle; bool m_lcdprocDimOnIdle;
@ -333,9 +492,12 @@ private:
bool m_lockFileEnabled; bool m_lockFileEnabled;
std::string m_lockFileName; std::string m_lockFileName;
bool m_mobileGPSEnabled;
std::string m_mobileGPSAddress;
unsigned int m_mobileGPSPort;
bool m_remoteControlEnabled; bool m_remoteControlEnabled;
std::string m_remoteControlAddress; unsigned int m_remoteControlPort;
unsigned short m_remoteControlPort;
}; };
#endif #endif

View file

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

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2020,2021,2022 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2019 by Patrick Maier DK5MP
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -34,8 +33,7 @@ m_bsId(0U),
m_srcId(0U), m_srcId(0U),
m_dstId(0U), m_dstId(0U),
m_dataContent(false), m_dataContent(false),
m_CBF(0U), m_CBF(0U)
m_OVCM(false)
{ {
m_data = new unsigned char[12U]; m_data = new unsigned char[12U];
} }
@ -82,7 +80,6 @@ bool CDMRCSBK::put(const unsigned char* bytes)
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false; m_dataContent = false;
m_CBF = 0U; m_CBF = 0U;
m_OVCM = (m_data[2U] & 0x04U) == 0x04U;
CUtils::dump(1U, "Unit to Unit Service Request CSBK", m_data, 12U); CUtils::dump(1U, "Unit to Unit Service Request CSBK", m_data, 12U);
break; break;
@ -92,7 +89,6 @@ bool CDMRCSBK::put(const unsigned char* bytes)
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U]; m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false; m_dataContent = false;
m_CBF = 0U; m_CBF = 0U;
m_OVCM = (m_data[2U] & 0x04U) == 0x04U;
CUtils::dump(1U, "Unit to Unit Service Answer Response CSBK", m_data, 12U); CUtils::dump(1U, "Unit to Unit Service Answer Response CSBK", m_data, 12U);
break; break;
@ -114,39 +110,6 @@ bool CDMRCSBK::put(const unsigned char* bytes)
CUtils::dump(1U, "Negative Acknowledge Response CSBK", m_data, 12U); CUtils::dump(1U, "Negative Acknowledge Response CSBK", m_data, 12U);
break; break;
case CSBKO_CALL_ALERT:
m_GI = false;
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];
m_dataContent = false;
m_CBF = 0U;
CUtils::dump(1U, "Call Alert CSBK", m_data, 12U);
break;
case CSBKO_CALL_ALERT_ACK:
m_GI = false;
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];
m_dataContent = false;
m_CBF = 0U;
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: default:
m_GI = false; m_GI = false;
m_srcId = 0U; m_srcId = 0U;
@ -186,23 +149,6 @@ unsigned char CDMRCSBK::getFID() const
return m_FID; return m_FID;
} }
bool CDMRCSBK::getOVCM() const
{
return m_OVCM;
}
void CDMRCSBK::setOVCM(bool ovcm)
{
if (m_CSBKO == CSBKO_UUVREQ || m_CSBKO == CSBKO_UUANSRSP) {
m_OVCM = ovcm;
if (ovcm)
m_data[2U] |= 0x04U;
else
m_data[2U] &= 0xFBU;
}
}
bool CDMRCSBK::getGI() const bool CDMRCSBK::getGI() const
{ {
return m_GI; return m_GI;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2020,2021,2022 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -26,9 +26,6 @@ enum CSBKO {
CSBKO_UUVREQ = 0x04, CSBKO_UUVREQ = 0x04,
CSBKO_UUANSRSP = 0x05, CSBKO_UUANSRSP = 0x05,
CSBKO_CTCSBK = 0x07, CSBKO_CTCSBK = 0x07,
CSBKO_CALL_ALERT = 0x1F,
CSBKO_CALL_ALERT_ACK = 0x20,
CSBKO_RADIO_CHECK = 0x24,
CSBKO_NACKRSP = 0x26, CSBKO_NACKRSP = 0x26,
CSBKO_BSDWNACT = 0x38, CSBKO_BSDWNACT = 0x38,
CSBKO_PRECCSBK = 0x3D CSBKO_PRECCSBK = 0x3D
@ -48,10 +45,6 @@ public:
CSBKO getCSBKO() const; CSBKO getCSBKO() const;
unsigned char getFID() const; unsigned char getFID() const;
// Set/Get the OVCM bit in the supported CSBKs
bool getOVCM() const;
void setOVCM(bool ovcm);
// For BS Dwn Act // For BS Dwn Act
unsigned int getBSId() const; unsigned int getBSId() const;
@ -76,7 +69,6 @@ private:
unsigned int m_dstId; unsigned int m_dstId;
bool m_dataContent; bool m_dataContent;
unsigned char m_CBF; unsigned char m_CBF;
bool m_OVCM;
}; };
#endif #endif

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2021 Jonathan Naylor, G4KLX * Copyright (C) 2015-2019 Jonathan Naylor, G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,7 +21,7 @@
#include <cassert> #include <cassert>
#include <algorithm> #include <algorithm>
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, bool ovcm) :
m_colorCode(colorCode), m_colorCode(colorCode),
m_modem(modem), m_modem(modem),
m_network(network), m_network(network),
@ -38,14 +38,7 @@ m_lookup(lookup)
// Load black and white lists to DMRAccessControl // Load black and white lists to DMRAccessControl
CDMRAccessControl::init(blacklist, whitelist, slot1TGWhitelist, slot2TGWhitelist, selfOnly, prefixes, id); CDMRAccessControl::init(blacklist, whitelist, slot1TGWhitelist, slot2TGWhitelist, selfOnly, prefixes, id);
//Print whitelisted IDs CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi, ovcm);
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);
} }
CDMRControl::~CDMRControl() CDMRControl::~CDMRControl()
@ -70,17 +63,15 @@ bool CDMRControl::processWakeup(const unsigned char* data)
return false; return false;
unsigned int srcId = csbk.getSrcId(); 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); std::string src = m_lookup->find(srcId);
bool ret = CDMRAccessControl::validateSrcId(srcId); bool ret = CDMRAccessControl::validateSrcId(srcId);
if (!ret) { 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; 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; return true;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@
class CDMRControl { class CDMRControl {
public: public:
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, bool ovcm);
~CDMRControl(); ~CDMRControl();
bool processWakeup(const unsigned char* data); bool processWakeup(const unsigned char* data);
@ -51,7 +51,7 @@ public:
private: private:
unsigned int m_colorCode; unsigned int m_colorCode;
CModem* m_modem; CModem* m_modem;
IDMRNetwork* m_network; CDMRNetwork* m_network;
CDMRSlot m_slot1; CDMRSlot m_slot1;
CDMRSlot m_slot2; CDMRSlot m_slot2;
CDMRLookup* m_lookup; CDMRLookup* m_lookup;

View file

@ -29,6 +29,7 @@ m_dstId(data.m_dstId),
m_flco(data.m_flco), m_flco(data.m_flco),
m_dataType(data.m_dataType), m_dataType(data.m_dataType),
m_seqNo(data.m_seqNo), m_seqNo(data.m_seqNo),
m_missing(data.m_missing),
m_n(data.m_n), m_n(data.m_n),
m_ber(data.m_ber), m_ber(data.m_ber),
m_rssi(data.m_rssi) m_rssi(data.m_rssi)
@ -45,6 +46,7 @@ m_dstId(0U),
m_flco(FLCO_GROUP), m_flco(FLCO_GROUP),
m_dataType(0U), m_dataType(0U),
m_seqNo(0U), m_seqNo(0U),
m_missing(false),
m_n(0U), m_n(0U),
m_ber(0U), m_ber(0U),
m_rssi(0U) m_rssi(0U)
@ -68,6 +70,7 @@ CDMRData& CDMRData::operator=(const CDMRData& data)
m_flco = data.m_flco; m_flco = data.m_flco;
m_dataType = data.m_dataType; m_dataType = data.m_dataType;
m_seqNo = data.m_seqNo; m_seqNo = data.m_seqNo;
m_missing = data.m_missing;
m_n = data.m_n; m_n = data.m_n;
m_ber = data.m_ber; m_ber = data.m_ber;
m_rssi = data.m_rssi; m_rssi = data.m_rssi;
@ -138,6 +141,16 @@ void CDMRData::setSeqNo(unsigned char seqNo)
m_seqNo = seqNo; m_seqNo = seqNo;
} }
bool CDMRData::isMissing() const
{
return m_missing;
}
void CDMRData::setMissing(bool missing)
{
m_missing = missing;
}
unsigned char CDMRData::getN() const unsigned char CDMRData::getN() const
{ {
return m_n; return m_n;

View file

@ -45,6 +45,9 @@ public:
unsigned char getDataType() const; unsigned char getDataType() const;
void setDataType(unsigned char dataType); void setDataType(unsigned char dataType);
bool isMissing() const;
void setMissing(bool missing);
unsigned char getBER() const; unsigned char getBER() const;
void setBER(unsigned char ber); void setBER(unsigned char ber);
@ -62,6 +65,7 @@ private:
FLCO m_flco; FLCO m_flco;
unsigned char m_dataType; unsigned char m_dataType;
unsigned char m_seqNo; unsigned char m_seqNo;
bool m_missing;
unsigned char m_n; unsigned char m_n;
unsigned char m_ber; unsigned char m_ber;
unsigned char m_rssi; unsigned char m_rssi;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2021 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,644 +0,0 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "DMRDirectNetwork.h"
#include "SHA256.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
const unsigned int BUFFER_LENGTH = 500U;
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
CDMRDirectNetwork::CDMRDirectNetwork(const std::string& address, unsigned short port, const std::string& localAddress, unsigned short localPort, unsigned int id, const std::string& password, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) :
m_address(address),
m_port(port),
m_addr(),
m_addrLen(0U),
m_id(NULL),
m_password(password),
m_duplex(duplex),
m_version(version),
m_debug(debug),
m_socket(localAddress, localPort),
m_enabled(false),
m_slot1(slot1),
m_slot2(slot2),
m_hwType(hwType),
m_status(WAITING_CONNECT),
m_retryTimer(1000U, 10U),
m_timeoutTimer(1000U, 60U),
m_buffer(NULL),
m_streamId(NULL),
m_salt(NULL),
m_rxData(1000U, "DMR Network"),
m_options(),
m_random(),
m_callsign(),
m_rxFrequency(0U),
m_txFrequency(0U),
m_power(0U),
m_colorCode(0U),
m_latitude(0.0F),
m_longitude(0.0F),
m_height(0),
m_location(),
m_description(),
m_url(),
m_beacon(false)
{
assert(!address.empty());
assert(port > 0U);
assert(id > 1000U);
assert(!password.empty());
m_buffer = new unsigned char[BUFFER_LENGTH];
m_salt = new unsigned char[sizeof(uint32_t)];
m_id = new uint8_t[4U];
m_streamId = new uint32_t[2U];
m_id[0U] = id >> 24;
m_id[1U] = id >> 16;
m_id[2U] = id >> 8;
m_id[3U] = id >> 0;
std::random_device rd;
std::mt19937 mt(rd());
m_random = mt;
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
m_streamId[0U] = dist(m_random);
m_streamId[1U] = dist(m_random);
}
CDMRDirectNetwork::~CDMRDirectNetwork()
{
delete[] m_streamId;
delete[] m_buffer;
delete[] m_salt;
delete[] m_id;
}
void CDMRDirectNetwork::setOptions(const std::string& options)
{
m_options = options;
}
void CDMRDirectNetwork::setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url)
{
m_callsign = callsign;
m_rxFrequency = rxFrequency;
m_txFrequency = txFrequency;
m_power = power;
m_colorCode = colorCode;
m_latitude = latitude;
m_longitude = longitude;
m_height = height;
m_location = location;
m_description = description;
m_url = url;
}
bool CDMRDirectNetwork::open()
{
if (CUDPSocket::lookup(m_address, m_port, m_addr, m_addrLen) != 0) {
LogError("DMR, Could not lookup the address of the DMR Network");
return false;
}
LogMessage("Opening DMR Network");
m_status = WAITING_CONNECT;
m_timeoutTimer.stop();
m_retryTimer.start();
return true;
}
void CDMRDirectNetwork::enable(bool enabled)
{
if (!enabled && m_enabled)
m_rxData.clear();
m_enabled = enabled;
}
bool CDMRDirectNetwork::read(CDMRData& data)
{
if (m_status != RUNNING)
return false;
if (m_rxData.isEmpty())
return false;
unsigned char length = 0U;
m_rxData.getData(&length, 1U);
m_rxData.getData(m_buffer, length);
// Is this a data packet?
if (::memcmp(m_buffer, "DMRD", 4U) != 0)
return false;
unsigned char seqNo = m_buffer[4U];
unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0);
unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0);
unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U;
// DMO mode slot disabling
if (slotNo == 1U && !m_duplex)
return false;
// Individual slot disabling
if (slotNo == 1U && !m_slot1)
return false;
if (slotNo == 2U && !m_slot2)
return false;
FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP;
data.setSeqNo(seqNo);
data.setSlotNo(slotNo);
data.setSrcId(srcId);
data.setDstId(dstId);
data.setFLCO(flco);
bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U;
bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U;
if (dataSync) {
unsigned char dataType = m_buffer[15U] & 0x0FU;
data.setData(m_buffer + 20U);
data.setDataType(dataType);
data.setN(0U);
} else if (voiceSync) {
data.setData(m_buffer + 20U);
data.setDataType(DT_VOICE_SYNC);
data.setN(0U);
} else {
unsigned char n = m_buffer[15U] & 0x0FU;
data.setData(m_buffer + 20U);
data.setDataType(DT_VOICE);
data.setN(n);
}
return true;
}
bool CDMRDirectNetwork::write(const CDMRData& data)
{
if (m_status != RUNNING)
return false;
unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH];
::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH);
buffer[0U] = 'D';
buffer[1U] = 'M';
buffer[2U] = 'R';
buffer[3U] = 'D';
unsigned int srcId = data.getSrcId();
buffer[5U] = srcId >> 16;
buffer[6U] = srcId >> 8;
buffer[7U] = srcId >> 0;
unsigned int dstId = data.getDstId();
buffer[8U] = dstId >> 16;
buffer[9U] = dstId >> 8;
buffer[10U] = dstId >> 0;
::memcpy(buffer + 11U, m_id, 4U);
unsigned int slotNo = data.getSlotNo();
// Individual slot disabling
if (slotNo == 1U && !m_slot1)
return false;
if (slotNo == 2U && !m_slot2)
return false;
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
FLCO flco = data.getFLCO();
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
unsigned int slotIndex = slotNo - 1U;
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
unsigned char dataType = data.getDataType();
if (dataType == DT_VOICE_SYNC) {
buffer[15U] |= 0x10U;
} else if (dataType == DT_VOICE) {
buffer[15U] |= data.getN();
} else {
if (dataType == DT_VOICE_LC_HEADER)
m_streamId[slotIndex] = dist(m_random);
if (dataType == DT_CSBK || dataType == DT_DATA_HEADER)
m_streamId[slotIndex] = dist(m_random);
buffer[15U] |= (0x20U | dataType);
}
buffer[4U] = data.getSeqNo();
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
data.getData(buffer + 20U);
buffer[53U] = data.getBER();
buffer[54U] = data.getRSSI();
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
return true;
}
bool CDMRDirectNetwork::writeRadioPosition(unsigned int id, const unsigned char* data)
{
if (m_status != RUNNING)
return false;
unsigned char buffer[20U];
::memcpy(buffer + 0U, "DMRG", 4U);
buffer[4U] = id >> 16;
buffer[5U] = id >> 8;
buffer[6U] = id >> 0;
::memcpy(buffer + 7U, data + 2U, 7U);
return write(buffer, 14U);
}
bool CDMRDirectNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
{
if (m_status != RUNNING)
return false;
unsigned char buffer[20U];
::memcpy(buffer + 0U, "DMRA", 4U);
buffer[4U] = id >> 16;
buffer[5U] = id >> 8;
buffer[6U] = id >> 0;
buffer[7U] = type;
::memcpy(buffer + 8U, data + 2U, 7U);
return write(buffer, 15U);
}
bool CDMRDirectNetwork::isConnected() const
{
return (m_status == RUNNING);
}
void CDMRDirectNetwork::close(bool sayGoodbye)
{
LogMessage("Closing DMR Network");
if (sayGoodbye && (m_status == RUNNING)) {
unsigned char buffer[9U];
::memcpy(buffer + 0U, "RPTCL", 5U);
::memcpy(buffer + 5U, m_id, 4U);
write(buffer, 9U);
}
m_socket.close();
m_retryTimer.stop();
m_timeoutTimer.stop();
}
void CDMRDirectNetwork::clock(unsigned int ms)
{
m_retryTimer.clock(ms);
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
switch (m_status) {
case WAITING_CONNECT:
if (m_socket.open(m_addr.ss_family)) {
if (writeLogin()) {
m_status = WAITING_LOGIN;
}
}
break;
case WAITING_LOGIN:
writeLogin();
break;
case WAITING_AUTHORISATION:
writeAuthorisation();
break;
case WAITING_OPTIONS:
writeOptions();
break;
case WAITING_CONFIG:
writeConfig();
break;
case RUNNING:
writePing();
break;
default:
break;
}
m_retryTimer.start();
}
sockaddr_storage address;
unsigned int addrlen;
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen);
if (length < 0) {
LogError("DMR, Socket has failed, retrying connection to the master");
close(false);
open();
return;
}
if (length > 0) {
if (!CUDPSocket::match(m_addr, address)) {
LogMessage("DMR, packet received from an invalid source");
return;
}
if (m_debug)
CUtils::dump(1U, "DMR, Network Received", m_buffer, length);
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
if (m_enabled) {
unsigned char len = length;
m_rxData.addData(&len, 1U);
m_rxData.addData(m_buffer, len);
}
} else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) {
if (m_status == RUNNING) {
LogWarning("DMR, Login to the master has failed, retrying login ...");
m_status = WAITING_LOGIN;
m_timeoutTimer.start();
m_retryTimer.start();
} else {
/* Once the modem death spiral has been prevented in Modem.cpp
the Network sometimes times out and reaches here.
We want it to reconnect so... */
LogError("DMR, Login to the master has failed, retrying network ...");
close(false);
open();
return;
}
} else if (::memcmp(m_buffer, "RPTACK", 6U) == 0) {
switch (m_status) {
case WAITING_LOGIN:
LogDebug("DMR, Sending authorisation");
::memcpy(m_salt, m_buffer + 6U, sizeof(uint32_t));
writeAuthorisation();
m_status = WAITING_AUTHORISATION;
m_timeoutTimer.start();
m_retryTimer.start();
break;
case WAITING_AUTHORISATION:
LogDebug("DMR, Sending configuration");
writeConfig();
m_status = WAITING_CONFIG;
m_timeoutTimer.start();
m_retryTimer.start();
break;
case WAITING_CONFIG:
if (m_options.empty()) {
LogMessage("DMR, Logged into the master successfully");
m_status = RUNNING;
} else {
LogDebug("DMR, Sending options");
writeOptions();
m_status = WAITING_OPTIONS;
}
m_timeoutTimer.start();
m_retryTimer.start();
break;
case WAITING_OPTIONS:
LogMessage("DMR, Logged into the master successfully");
m_status = RUNNING;
m_timeoutTimer.start();
m_retryTimer.start();
break;
default:
break;
}
} else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) {
LogError("DMR, Master is closing down");
close(false);
open();
} else if (::memcmp(m_buffer, "MSTPONG", 7U) == 0) {
m_timeoutTimer.start();
} else if (::memcmp(m_buffer, "RPTSBKN", 7U) == 0) {
m_beacon = true;
} else {
CUtils::dump("DMR, Unknown packet from the master", m_buffer, length);
}
}
m_timeoutTimer.clock(ms);
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
LogError("DMR, Connection to the master has timed out, retrying connection");
close(false);
open();
}
}
bool CDMRDirectNetwork::writeLogin()
{
unsigned char buffer[8U];
::memcpy(buffer + 0U, "RPTL", 4U);
::memcpy(buffer + 4U, m_id, 4U);
return write(buffer, 8U);
}
bool CDMRDirectNetwork::writeAuthorisation()
{
size_t size = m_password.size();
unsigned char* in = new unsigned char[size + sizeof(uint32_t)];
::memcpy(in, m_salt, sizeof(uint32_t));
for (size_t i = 0U; i < size; i++)
in[i + sizeof(uint32_t)] = m_password.at(i);
unsigned char out[40U];
::memcpy(out + 0U, "RPTK", 4U);
::memcpy(out + 4U, m_id, 4U);
CSHA256 sha256;
sha256.buffer(in, (unsigned int)(size + sizeof(uint32_t)), out + 8U);
delete[] in;
return write(out, 40U);
}
bool CDMRDirectNetwork::writeOptions()
{
char buffer[300U];
::memcpy(buffer + 0U, "RPTO", 4U);
::memcpy(buffer + 4U, m_id, 4U);
::strcpy(buffer + 8U, m_options.c_str());
return write((unsigned char*)buffer, (unsigned int)m_options.length() + 8U);
}
bool CDMRDirectNetwork::writeConfig()
{
const char* software;
char slots = '0';
if (m_duplex) {
if (m_slot1 && m_slot2)
slots = '3';
else if (m_slot1 && !m_slot2)
slots = '1';
else if (!m_slot1 && m_slot2)
slots = '2';
switch (m_hwType) {
case HWT_MMDVM:
software = "MMDVM";
break;
case HWT_MMDVM_HS:
software = "MMDVM_MMDVM_HS";
break;
case HWT_MMDVM_HS_DUAL_HAT:
software = "MMDVM_MMDVM_HS_Dual_Hat";
break;
case HWT_NANO_HOTSPOT:
software = "MMDVM_Nano_hotSPOT";
break;
default:
software = "MMDVM_Unknown";
break;
}
} else {
slots = '4';
switch (m_hwType) {
case HWT_MMDVM:
software = "MMDVM_DMO";
break;
case HWT_DVMEGA:
software = "MMDVM_DVMega";
break;
case HWT_MMDVM_ZUMSPOT:
software = "MMDVM_ZUMspot";
break;
case HWT_MMDVM_HS_HAT:
software = "MMDVM_MMDVM_HS_Hat";
break;
case HWT_MMDVM_HS_DUAL_HAT:
software = "MMDVM_MMDVM_HS_Dual_Hat";
break;
case HWT_NANO_HOTSPOT:
software = "MMDVM_Nano_hotSPOT";
break;
case HWT_NANO_DV:
software = "MMDVM_Nano_DV";
break;
case HWT_D2RG_MMDVM_HS:
software = "MMDVM_D2RG_MMDVM_HS";
break;
case HWT_MMDVM_HS:
software = "MMDVM_MMDVM_HS";
break;
default:
software = "MMDVM_Unknown";
break;
}
}
char buffer[400U];
::memcpy(buffer + 0U, "RPTC", 4U);
::memcpy(buffer + 4U, m_id, 4U);
char latitude[20U];
::sprintf(latitude, "%08f", m_latitude);
char longitude[20U];
::sprintf(longitude, "%09f", m_longitude);
unsigned int power = m_power;
if (power > 99U)
power = 99U;
int height = m_height;
if (height > 999)
height = 999;
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%8.8s%9.9s%03d%-20.20s%-19.19s%c%-124.124s%-40.40s%-40.40s", m_callsign.c_str(),
m_rxFrequency, m_txFrequency, power, m_colorCode, latitude, longitude, height, m_location.c_str(),
m_description.c_str(), slots, m_url.c_str(), m_version, software);
return write((unsigned char*)buffer, 302U);
}
bool CDMRDirectNetwork::writePing()
{
unsigned char buffer[11U];
::memcpy(buffer + 0U, "RPTPING", 7U);
::memcpy(buffer + 7U, m_id, 4U);
return write(buffer, 11U);
}
bool CDMRDirectNetwork::wantsBeacon()
{
bool beacon = m_beacon;
m_beacon = false;
return beacon;
}
bool CDMRDirectNetwork::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
if (m_debug)
CUtils::dump(1U, "DMR Network Transmitted", data, length);
bool ret = m_socket.write(data, length, m_addr, m_addrLen);
if (!ret) {
LogError("DMR, Socket has failed when writing data to the master, retrying connection");
close(false);
open();
return false;
}
return true;
}

View file

@ -1,121 +0,0 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(DMRDirectNetwork_H)
#define DMRDirectNetwork_H
#include "DMRNetwork.h"
#include "UDPSocket.h"
#include "Timer.h"
#include "RingBuffer.h"
#include "DMRData.h"
#include <string>
#include <cstdint>
#include <random>
class CDMRDirectNetwork : public IDMRNetwork
{
public:
CDMRDirectNetwork(const std::string& remoteAddress, unsigned short remotePort, const std::string& localAddress, unsigned short localPort, unsigned int id, const std::string& password, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug);
virtual ~CDMRDirectNetwork();
virtual void setOptions(const std::string& options);
virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url);
virtual bool open();
virtual void enable(bool enabled);
virtual bool read(CDMRData& data);
virtual bool write(const CDMRData& data);
virtual bool writeRadioPosition(unsigned int id, const unsigned char* data);
virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
virtual bool wantsBeacon();
virtual void clock(unsigned int ms);
virtual bool isConnected() const;
virtual void close(bool sayGoodbye);
private:
std::string m_address;
unsigned short m_port;
sockaddr_storage m_addr;
unsigned int m_addrLen;
uint8_t* m_id;
std::string m_password;
bool m_duplex;
const char* m_version;
bool m_debug;
CUDPSocket m_socket;
bool m_enabled;
bool m_slot1;
bool m_slot2;
HW_TYPE m_hwType;
enum STATUS {
WAITING_CONNECT,
WAITING_LOGIN,
WAITING_AUTHORISATION,
WAITING_CONFIG,
WAITING_OPTIONS,
RUNNING
};
STATUS m_status;
CTimer m_retryTimer;
CTimer m_timeoutTimer;
unsigned char* m_buffer;
uint32_t* m_streamId;
unsigned char* m_salt;
CRingBuffer<unsigned char> m_rxData;
std::string m_options;
std::mt19937 m_random;
std::string m_callsign;
unsigned int m_rxFrequency;
unsigned int m_txFrequency;
unsigned int m_power;
unsigned int m_colorCode;
float m_latitude;
float m_longitude;
int m_height;
std::string m_location;
std::string m_description;
std::string m_url;
bool m_beacon;
bool writeLogin();
bool writeAuthorisation();
bool writeOptions();
bool writeConfig();
bool writePing();
bool write(const unsigned char* data, unsigned int length);
};
#endif

View file

@ -44,11 +44,11 @@ void CDMREMB::putData(const unsigned char* data)
DMREMB[1U] = (data[18U] << 4) & 0xF0U; DMREMB[1U] = (data[18U] << 4) & 0xF0U;
DMREMB[1U] |= (data[19U] >> 4) & 0x0FU; DMREMB[1U] |= (data[19U] >> 4) & 0x0FU;
unsigned char code = CQR1676::decode(DMREMB); CQR1676::decode(DMREMB);
m_colorCode = (code >> 4) & 0x0FU; m_colorCode = (DMREMB[0U] >> 4) & 0x0FU;
m_PI = (code & 0x08U) == 0x08U; m_PI = (DMREMB[0U] & 0x08U) == 0x08U;
m_LCSS = (code >> 1) & 0x03U; m_LCSS = (DMREMB[0U] >> 1) & 0x03U;
} }
void CDMREMB::getData(unsigned char* data) const void CDMREMB::getData(unsigned char* data) const

View file

@ -1,450 +0,0 @@
/*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "DMRGatewayNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>
const unsigned int BUFFER_LENGTH = 500U;
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
CDMRGatewayNetwork::CDMRGatewayNetwork(const std::string& address, unsigned short port, const std::string& localAddress, unsigned short localPort, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) :
m_addressStr(address),
m_addr(),
m_addrLen(0U),
m_port(port),
m_id(NULL),
m_duplex(duplex),
m_version(version),
m_debug(debug),
m_socket(localAddress, localPort),
m_enabled(false),
m_slot1(slot1),
m_slot2(slot2),
m_hwType(hwType),
m_buffer(NULL),
m_streamId(NULL),
m_rxData(1000U, "DMR Network"),
m_beacon(false),
m_random(),
m_callsign(),
m_rxFrequency(0U),
m_txFrequency(0U),
m_power(0U),
m_colorCode(0U),
m_pingTimer(1000U, 10U)
{
assert(!address.empty());
assert(port > 0U);
assert(id > 1000U);
if (CUDPSocket::lookup(m_addressStr, m_port, m_addr, m_addrLen) != 0)
m_addrLen = 0U;
m_buffer = new unsigned char[BUFFER_LENGTH];
m_id = new uint8_t[4U];
m_streamId = new uint32_t[2U];
m_id[0U] = id >> 24;
m_id[1U] = id >> 16;
m_id[2U] = id >> 8;
m_id[3U] = id >> 0;
std::random_device rd;
std::mt19937 mt(rd());
m_random = mt;
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
m_streamId[0U] = dist(m_random);
m_streamId[1U] = dist(m_random);
}
CDMRGatewayNetwork::~CDMRGatewayNetwork()
{
delete[] m_buffer;
delete[] m_streamId;
delete[] m_id;
}
void CDMRGatewayNetwork::setConfig(const std::string & callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url)
{
m_callsign = callsign;
m_rxFrequency = rxFrequency;
m_txFrequency = txFrequency;
m_power = power;
m_colorCode = colorCode;
}
void CDMRGatewayNetwork::setOptions(const std::string& options)
{
}
bool CDMRGatewayNetwork::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of the DMR Network");
return false;
}
LogMessage("DMR, Opening DMR Network");
bool ret = m_socket.open(m_addr);
if (ret)
m_pingTimer.start();
return ret;
}
void CDMRGatewayNetwork::enable(bool enabled)
{
if (!enabled && m_enabled)
m_rxData.clear();
m_enabled = enabled;
}
bool CDMRGatewayNetwork::read(CDMRData& data)
{
if (m_rxData.isEmpty())
return false;
unsigned char length = 0U;
m_rxData.getData(&length, 1U);
m_rxData.getData(m_buffer, length);
// Is this a data packet?
if (::memcmp(m_buffer, "DMRD", 4U) != 0)
return false;
unsigned char seqNo = m_buffer[4U];
unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0);
unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0);
unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U;
// DMO mode slot disabling
if (slotNo == 1U && !m_duplex)
return false;
// Individual slot disabling
if (slotNo == 1U && !m_slot1)
return false;
if (slotNo == 2U && !m_slot2)
return false;
FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP;
data.setSeqNo(seqNo);
data.setSlotNo(slotNo);
data.setSrcId(srcId);
data.setDstId(dstId);
data.setFLCO(flco);
bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U;
bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U;
if (dataSync) {
unsigned char dataType = m_buffer[15U] & 0x0FU;
data.setData(m_buffer + 20U);
data.setDataType(dataType);
data.setN(0U);
} else if (voiceSync) {
data.setData(m_buffer + 20U);
data.setDataType(DT_VOICE_SYNC);
data.setN(0U);
} else {
unsigned char n = m_buffer[15U] & 0x0FU;
data.setData(m_buffer + 20U);
data.setDataType(DT_VOICE);
data.setN(n);
}
return true;
}
bool CDMRGatewayNetwork::write(const CDMRData& data)
{
unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH];
::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH);
buffer[0U] = 'D';
buffer[1U] = 'M';
buffer[2U] = 'R';
buffer[3U] = 'D';
unsigned int srcId = data.getSrcId();
buffer[5U] = srcId >> 16;
buffer[6U] = srcId >> 8;
buffer[7U] = srcId >> 0;
unsigned int dstId = data.getDstId();
buffer[8U] = dstId >> 16;
buffer[9U] = dstId >> 8;
buffer[10U] = dstId >> 0;
::memcpy(buffer + 11U, m_id, 4U);
unsigned int slotNo = data.getSlotNo();
// Individual slot disabling
if (slotNo == 1U && !m_slot1)
return false;
if (slotNo == 2U && !m_slot2)
return false;
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
FLCO flco = data.getFLCO();
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
unsigned int slotIndex = slotNo - 1U;
std::uniform_int_distribution<uint32_t> dist(0x00000001, 0xfffffffe);
unsigned char dataType = data.getDataType();
if (dataType == DT_VOICE_SYNC) {
buffer[15U] |= 0x10U;
} else if (dataType == DT_VOICE) {
buffer[15U] |= data.getN();
} else {
if (dataType == DT_VOICE_LC_HEADER)
m_streamId[slotIndex] = dist(m_random);
if (dataType == DT_CSBK || dataType == DT_DATA_HEADER)
m_streamId[slotIndex] = dist(m_random);
buffer[15U] |= (0x20U | dataType);
}
buffer[4U] = data.getSeqNo();
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
data.getData(buffer + 20U);
buffer[53U] = data.getBER();
buffer[54U] = data.getRSSI();
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
return true;
}
bool CDMRGatewayNetwork::writeRadioPosition(unsigned int id, const unsigned char* data)
{
unsigned char buffer[20U];
::memcpy(buffer + 0U, "DMRG", 4U);
buffer[4U] = id >> 16;
buffer[5U] = id >> 8;
buffer[6U] = id >> 0;
::memcpy(buffer + 7U, data + 2U, 7U);
return write(buffer, 14U);
}
bool CDMRGatewayNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
{
unsigned char buffer[20U];
::memcpy(buffer + 0U, "DMRA", 4U);
buffer[4U] = id >> 16;
buffer[5U] = id >> 8;
buffer[6U] = id >> 0;
buffer[7U] = type;
::memcpy(buffer + 8U, data + 2U, 7U);
return write(buffer, 15U);
}
bool CDMRGatewayNetwork::isConnected() const
{
return (m_addrLen != 0);
}
void CDMRGatewayNetwork::close(bool sayGoodbye)
{
LogMessage("DMR, Closing DMR Network");
m_socket.close();
}
void CDMRGatewayNetwork::clock(unsigned int ms)
{
m_pingTimer.clock(ms);
if (m_pingTimer.isRunning() && m_pingTimer.hasExpired()) {
writeConfig();
m_pingTimer.start();
}
sockaddr_storage address;
unsigned int addrLen;
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrLen);
if (length <= 0)
return;
if (!CUDPSocket::match(m_addr, address)) {
LogMessage("DMR, packet received from an invalid source");
return;
}
if (m_debug)
CUtils::dump(1U, "DMR Network Received", m_buffer, length);
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
if (m_enabled) {
unsigned char len = length;
m_rxData.addData(&len, 1U);
m_rxData.addData(m_buffer, len);
}
} else if (::memcmp(m_buffer, "DMRP", 4U) == 0) {
;
} else if (::memcmp(m_buffer, "DMRB", 4U) == 0) {
m_beacon = true;
} else {
CUtils::dump("DMR, unknown packet from the DMR Network", m_buffer, length);
}
}
bool CDMRGatewayNetwork::writeConfig()
{
const char* software;
char slots = '0';
if (m_duplex) {
if (m_slot1 && m_slot2)
slots = '3';
else if (m_slot1 && !m_slot2)
slots = '1';
else if (!m_slot1 && m_slot2)
slots = '2';
switch (m_hwType) {
case HWT_MMDVM:
software = "MMDVM";
break;
case HWT_MMDVM_HS:
software = "MMDVM_MMDVM_HS";
break;
case HWT_MMDVM_HS_DUAL_HAT:
software = "MMDVM_MMDVM_HS_Dual_Hat";
break;
case HWT_NANO_HOTSPOT:
software = "MMDVM_Nano_hotSPOT";
break;
default:
software = "MMDVM_Unknown";
break;
}
} else {
slots = '4';
switch (m_hwType) {
case HWT_MMDVM:
software = "MMDVM_DMO";
break;
case HWT_DVMEGA:
software = "MMDVM_DVMega";
break;
case HWT_MMDVM_ZUMSPOT:
software = "MMDVM_ZUMspot";
break;
case HWT_MMDVM_HS_HAT:
software = "MMDVM_MMDVM_HS_Hat";
break;
case HWT_MMDVM_HS_DUAL_HAT:
software = "MMDVM_MMDVM_HS_Dual_Hat";
break;
case HWT_NANO_HOTSPOT:
software = "MMDVM_Nano_hotSPOT";
break;
case HWT_NANO_DV:
software = "MMDVM_Nano_DV";
break;
case HWT_D2RG_MMDVM_HS:
software = "MMDVM_D2RG_MMDVM_HS";
break;
case HWT_MMDVM_HS:
software = "MMDVM_MMDVM_HS";
break;
case HWT_OPENGD77_HS:
software = "MMDVM_OpenGD77_HS";
break;
case HWT_SKYBRIDGE:
software = "MMDVM_SkyBridge";
break;
default:
software = "MMDVM_Unknown";
break;
}
}
unsigned int power = m_power;
if (power > 99U)
power = 99U;
char buffer[150U];
::memcpy(buffer + 0U, "DMRC", 4U);
::memcpy(buffer + 4U, m_id, 4U);
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%c%-40.40s%-40.40s",
m_callsign.c_str(), m_rxFrequency, m_txFrequency, power, m_colorCode, slots, m_version,
software);
return write((unsigned char*)buffer, 119U);
}
bool CDMRGatewayNetwork::wantsBeacon()
{
bool beacon = m_beacon;
m_beacon = false;
return beacon;
}
bool CDMRGatewayNetwork::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
if (m_debug)
CUtils::dump(1U, "DMR Network Transmitted", data, length);
bool ret = m_socket.write(data, length, m_addr, m_addrLen);
if (!ret) {
LogError("DMR, socket error when writing to the DMR Network");
return false;
}
return true;
}

View file

@ -1,94 +0,0 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(DMRGatewayNetwork_H)
#define DMRGatewayNetwork_H
#include "DMRNetwork.h"
#include "UDPSocket.h"
#include "Timer.h"
#include "RingBuffer.h"
#include "DMRData.h"
#include "Defines.h"
#include <string>
#include <cstdint>
#include <random>
class CDMRGatewayNetwork : public IDMRNetwork
{
public:
CDMRGatewayNetwork(const std::string& remoteAddress, unsigned short remotePort, const std::string& localAddress, unsigned short localPort, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug);
virtual ~CDMRGatewayNetwork();
virtual void setOptions(const std::string& options);
virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url);
virtual bool open();
virtual void enable(bool enabled);
virtual bool read(CDMRData& data);
virtual bool write(const CDMRData& data);
virtual bool writeRadioPosition(unsigned int id, const unsigned char* data);
virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
virtual bool wantsBeacon();
virtual void clock(unsigned int ms);
virtual bool isConnected() const;
virtual void close(bool sayGoodbye);
private:
std::string m_addressStr;
sockaddr_storage m_addr;
unsigned int m_addrLen;
unsigned short m_port;
uint8_t* m_id;
bool m_duplex;
const char* m_version;
bool m_debug;
CUDPSocket m_socket;
bool m_enabled;
bool m_slot1;
bool m_slot2;
HW_TYPE m_hwType;
unsigned char* m_buffer;
uint32_t* m_streamId;
CRingBuffer<unsigned char> m_rxData;
bool m_beacon;
std::mt19937 m_random;
std::string m_callsign;
unsigned int m_rxFrequency;
unsigned int m_txFrequency;
unsigned int m_power;
unsigned int m_colorCode;
CTimer m_pingTimer;
bool writeConfig();
bool write(const unsigned char* data, unsigned int length);
};
#endif

42048
DMRIds.dat

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2019,2021,2022 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2019 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2019,2021,2022 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2019 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -30,8 +30,8 @@ CThread(),
m_filename(filename), m_filename(filename),
m_reloadTime(reloadTime), m_reloadTime(reloadTime),
m_table(), m_table(),
m_stop(false), m_mutex(),
m_reload(false) m_stop(false)
{ {
} }
@ -41,7 +41,7 @@ CDMRLookup::~CDMRLookup()
bool CDMRLookup::read() bool CDMRLookup::read()
{ {
bool ret = m_table.load(m_filename); bool ret = load();
if (m_reloadTime > 0U) if (m_reloadTime > 0U)
run(); run();
@ -49,14 +49,6 @@ bool CDMRLookup::read()
return ret; return ret;
} }
void CDMRLookup::reload()
{
if (m_reloadTime == 0U)
m_table.load(m_filename);
else
m_reload = true;
}
void CDMRLookup::entry() void CDMRLookup::entry()
{ {
LogInfo("Started the DMR Id lookup reload thread"); LogInfo("Started the DMR Id lookup reload thread");
@ -68,10 +60,9 @@ void CDMRLookup::entry()
sleep(1000U); sleep(1000U);
timer.clock(); timer.clock();
if (timer.hasExpired() || m_reload) { if (timer.hasExpired()) {
m_table.load(m_filename); load();
timer.start(); timer.start();
m_reload = false;
} }
} }
@ -90,47 +81,118 @@ void CDMRLookup::stop()
wait(); wait();
} }
void CDMRLookup::findWithName(unsigned int id, class CUserDBentry *entry) std::string CDMRLookup::findWithName(unsigned int id)
{
if (id == 0xFFFFFFFU) {
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 CDMRLookup::find(unsigned int id)
{ {
std::string callsign; std::string callsign;
if (id == 0xFFFFFFFU) if (id == 0xFFFFFFU)
return std::string("ALL"); return std::string("ALL");
class CUserDBentry entry; m_mutex.lock();
if (m_table.lookup(id, &entry)) {
callsign = entry.get(keyCALLSIGN); try {
} else { callsign = m_table.at(id);
LogDebug("FindWithName =%s",callsign.c_str());
} catch (...) {
char text[10U]; char text[10U];
::snprintf(text, sizeof(text), "%u", id); ::sprintf(text, "%u", id);
callsign = std::string(text); callsign = std::string(text);
} }
m_mutex.unlock();
return callsign;
}
std::string CDMRLookup::find(unsigned int id)
{
std::string callsign;
std::string b;
if (id == 0xFFFFFFU)
return std::string("ALL");
m_mutex.lock();
try {
b = m_table.at(id);
size_t n = b.find(" ");
if (n > 0) {
callsign = b.substr(0,n);
} else {
LogDebug("b=%s",b.c_str());
callsign = b;
}
} catch (...) {
char text[10U];
::sprintf(text, "%u", id);
callsign = std::string(text);
}
m_mutex.unlock();
return callsign; return callsign;
} }
bool CDMRLookup::exists(unsigned int id) bool CDMRLookup::exists(unsigned int id)
{ {
return m_table.lookup(id, NULL); m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
}
bool CDMRLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogWarning("Cannot open the DMR Id lookup file - %s", m_filename.c_str());
return false;
}
m_mutex.lock();
// Remove the old entries
m_table.clear();
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, " \t\r\n");
char* p2 = ::strtok(NULL, " \r\n"); // tokenize to eol to capture name as well
if (p1 != NULL && p2 != NULL) {
unsigned int id = (unsigned int)::atoi(p1);
for (char* p = p2; *p != 0x00U; p++) {
if(*p == 0x09U)
*p = 0x20U;
else
*p = ::toupper(*p);
}
m_table[id] = std::string(p2);
}
}
m_mutex.unlock();
::fclose(fp);
size_t size = m_table.size();
if (size == 0U)
return false;
LogInfo("Loaded %u Ids to the DMR callsign lookup table", size);
return true;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,9 +20,10 @@
#define DMRLookup_H #define DMRLookup_H
#include "Thread.h" #include "Thread.h"
#include "UserDB.h" #include "Mutex.h"
#include <string> #include <string>
#include <unordered_map>
class CDMRLookup : public CThread { class CDMRLookup : public CThread {
public: public:
@ -31,12 +32,10 @@ public:
bool read(); bool read();
void reload();
virtual void entry(); virtual void entry();
std::string find(unsigned int id); std::string find(unsigned int id);
void findWithName(unsigned int id, class CUserDBentry *entry); std::string findWithName(unsigned int id);
bool exists(unsigned int id); bool exists(unsigned int id);
@ -45,9 +44,11 @@ public:
private: private:
std::string m_filename; std::string m_filename;
unsigned int m_reloadTime; unsigned int m_reloadTime;
class CUserDB m_table; std::unordered_map<unsigned int, std::string> m_table;
CMutex m_mutex;
bool m_stop; bool m_stop;
bool m_reload;
bool load();
}; };
#endif #endif

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -18,6 +18,697 @@
#include "DMRNetwork.h" #include "DMRNetwork.h"
IDMRNetwork::~IDMRNetwork() #include "StopWatch.h"
#include "SHA256.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>
const unsigned int BUFFER_LENGTH = 500U;
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, unsigned int jitter) :
m_addressStr(address),
m_address(),
m_port(port),
m_id(NULL),
m_password(password),
m_duplex(duplex),
m_version(version),
m_debug(debug),
m_socket(local),
m_enabled(false),
m_slot1(slot1),
m_slot2(slot2),
m_jitterBuffers(NULL),
m_hwType(hwType),
m_status(WAITING_CONNECT),
m_retryTimer(1000U, 10U),
m_timeoutTimer(1000U, 60U),
m_buffer(NULL),
m_salt(NULL),
m_streamId(NULL),
m_options(),
m_callsign(),
m_rxFrequency(0U),
m_txFrequency(0U),
m_power(0U),
m_colorCode(0U),
m_latitude(0.0F),
m_longitude(0.0F),
m_height(0),
m_location(),
m_description(),
m_url(),
m_beacon(false)
{ {
assert(!address.empty());
assert(port > 0U);
assert(id > 1000U);
assert(!password.empty());
assert(jitter > 0U);
m_address = CUDPSocket::lookup(address);
m_buffer = new unsigned char[BUFFER_LENGTH];
m_salt = new unsigned char[sizeof(uint32_t)];
m_id = new uint8_t[4U];
m_streamId = new uint32_t[2U];
m_jitterBuffers = new CJitterBuffer*[3U];
m_jitterBuffers[1U] = new CJitterBuffer("DMR Slot 1", 60U, DMR_SLOT_TIME, jitter, 256U, debug);
m_jitterBuffers[2U] = new CJitterBuffer("DMR Slot 2", 60U, DMR_SLOT_TIME, jitter, 256U, debug);
m_id[0U] = id >> 24;
m_id[1U] = id >> 16;
m_id[2U] = id >> 8;
m_id[3U] = id >> 0;
CStopWatch stopWatch;
::srand(stopWatch.start());
m_streamId[0U] = ::rand() + 1U;
m_streamId[1U] = ::rand() + 1U;
}
CDMRNetwork::~CDMRNetwork()
{
delete m_jitterBuffers[1U];
delete m_jitterBuffers[2U];
delete[] m_buffer;
delete[] m_salt;
delete[] m_streamId;
delete[] m_id;
delete[] m_jitterBuffers;
}
void CDMRNetwork::setOptions(const std::string& options)
{
m_options = options;
}
void CDMRNetwork::setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url)
{
m_callsign = callsign;
m_rxFrequency = rxFrequency;
m_txFrequency = txFrequency;
m_power = power;
m_colorCode = colorCode;
m_latitude = latitude;
m_longitude = longitude;
m_height = height;
m_location = location;
m_description = description;
m_url = url;
}
bool CDMRNetwork::open()
{
LogMessage("DMR, Opening DMR Network");
if (m_address.s_addr == INADDR_NONE)
m_address = CUDPSocket::lookup(m_addressStr);
m_status = WAITING_CONNECT;
m_timeoutTimer.stop();
m_retryTimer.start();
return true;
}
void CDMRNetwork::enable(bool enabled)
{
m_enabled = enabled;
}
bool CDMRNetwork::read(CDMRData& data)
{
if (m_status != RUNNING)
return false;
for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) {
unsigned int length = 0U;
B_STATUS status = BS_NO_DATA;
status = m_jitterBuffers[slotNo]->getData(m_buffer, length);
if (status != BS_NO_DATA) {
unsigned char seqNo = m_buffer[4U];
unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0);
unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0);
FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP;
data.setSeqNo(seqNo);
data.setSlotNo(slotNo);
data.setSrcId(srcId);
data.setDstId(dstId);
data.setFLCO(flco);
data.setMissing(status == BS_MISSING);
bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U;
bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U;
if (dataSync) {
unsigned char dataType = m_buffer[15U] & 0x0FU;
data.setData(m_buffer + 20U);
data.setDataType(dataType);
data.setN(0U);
} else if (voiceSync) {
data.setData(m_buffer + 20U);
data.setDataType(DT_VOICE_SYNC);
data.setN(0U);
} else {
unsigned char n = m_buffer[15U] & 0x0FU;
data.setData(m_buffer + 20U);
data.setDataType(DT_VOICE);
data.setN(n);
}
return true;
}
}
return false;
}
bool CDMRNetwork::write(const CDMRData& data)
{
if (m_status != RUNNING)
return false;
unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH];
::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH);
buffer[0U] = 'D';
buffer[1U] = 'M';
buffer[2U] = 'R';
buffer[3U] = 'D';
unsigned int srcId = data.getSrcId();
buffer[5U] = srcId >> 16;
buffer[6U] = srcId >> 8;
buffer[7U] = srcId >> 0;
unsigned int dstId = data.getDstId();
buffer[8U] = dstId >> 16;
buffer[9U] = dstId >> 8;
buffer[10U] = dstId >> 0;
::memcpy(buffer + 11U, m_id, 4U);
unsigned int slotNo = data.getSlotNo();
// Individual slot disabling
if (slotNo == 1U && !m_slot1)
return false;
if (slotNo == 2U && !m_slot2)
return false;
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
FLCO flco = data.getFLCO();
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
unsigned int slotIndex = slotNo - 1U;
unsigned int count = 1U;
unsigned char dataType = data.getDataType();
if (dataType == DT_VOICE_SYNC) {
buffer[15U] |= 0x10U;
} else if (dataType == DT_VOICE) {
buffer[15U] |= data.getN();
} else {
if (dataType == DT_VOICE_LC_HEADER)
count = 2U;
buffer[15U] |= (0x20U | dataType);
}
buffer[4U] = data.getSeqNo();
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
data.getData(buffer + 20U);
buffer[53U] = data.getBER();
buffer[54U] = data.getRSSI();
if (m_debug)
CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH);
for (unsigned int i = 0U; i < count; i++)
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
return true;
}
bool CDMRNetwork::writeRadioPosition(unsigned int id, const unsigned char* data)
{
if (m_status != RUNNING)
return false;
unsigned char buffer[20U];
::memcpy(buffer + 0U, "DMRG", 4U);
::memcpy(buffer + 4U, m_id, 4U);
buffer[8U] = id >> 16;
buffer[9U] = id >> 8;
buffer[10U] = id >> 0;
::memcpy(buffer + 11U, data + 2U, 7U);
return write(buffer, 18U);
}
bool CDMRNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
{
if (m_status != RUNNING)
return false;
unsigned char buffer[20U];
::memcpy(buffer + 0U, "DMRA", 4U);
::memcpy(buffer + 4U, m_id, 4U);
buffer[8U] = id >> 16;
buffer[9U] = id >> 8;
buffer[10U] = id >> 0;
buffer[11U] = type;
::memcpy(buffer + 12U, data + 2U, 7U);
return write(buffer, 19U);
}
bool CDMRNetwork::writeHomePosition(float latitude, float longitude)
{
m_latitude = latitude;
m_longitude = longitude;
if (m_status != RUNNING)
return false;
char buffer[50U];
::memcpy(buffer + 0U, "RPTG", 4U);
::memcpy(buffer + 4U, m_id, 4U);
::sprintf(buffer + 8U, "%08f%09f", latitude, longitude);
return write((unsigned char*)buffer, 25U);
}
void CDMRNetwork::close()
{
LogMessage("DMR, Closing DMR Network");
if (m_status == RUNNING) {
unsigned char buffer[9U];
::memcpy(buffer + 0U, "RPTCL", 5U);
::memcpy(buffer + 5U, m_id, 4U);
write(buffer, 9U);
}
m_socket.close();
m_retryTimer.stop();
m_timeoutTimer.stop();
}
void CDMRNetwork::clock(unsigned int ms)
{
m_jitterBuffers[1U]->clock(ms);
m_jitterBuffers[2U]->clock(ms);
if (m_status == WAITING_CONNECT) {
m_retryTimer.clock(ms);
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
bool ret = m_socket.open();
if (ret) {
ret = writeLogin();
if (!ret)
return;
m_status = WAITING_LOGIN;
m_timeoutTimer.start();
}
m_retryTimer.start();
}
return;
}
in_addr address;
unsigned int port;
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port);
if (length < 0) {
LogError("DMR, Socket has failed, retrying connection to the master");
close();
open();
return;
}
// if (m_debug && length > 0)
// CUtils::dump(1U, "Network Received", m_buffer, length);
if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) {
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
if (m_enabled) {
if (m_debug)
CUtils::dump(1U, "Network Received", m_buffer, length);
receiveData(m_buffer, length);
}
} else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) {
if (m_status == RUNNING) {
LogWarning("DMR, Login to the master has failed, retrying login ...");
m_status = WAITING_LOGIN;
m_timeoutTimer.start();
m_retryTimer.start();
} else {
/* Once the modem death spiral has been prevented in Modem.cpp
the Network sometimes times out and reaches here.
We want it to reconnect so... */
LogError("DMR, Login to the master has failed, retrying network ...");
close();
open();
return;
}
} else if (::memcmp(m_buffer, "RPTACK", 6U) == 0) {
switch (m_status) {
case WAITING_LOGIN:
LogDebug("DMR, Sending authorisation");
::memcpy(m_salt, m_buffer + 6U, sizeof(uint32_t));
writeAuthorisation();
m_status = WAITING_AUTHORISATION;
m_timeoutTimer.start();
m_retryTimer.start();
break;
case WAITING_AUTHORISATION:
LogDebug("DMR, Sending configuration");
writeConfig();
m_status = WAITING_CONFIG;
m_timeoutTimer.start();
m_retryTimer.start();
break;
case WAITING_CONFIG:
if (m_options.empty()) {
LogMessage("DMR, Logged into the master successfully");
m_status = RUNNING;
} else {
LogDebug("DMR, Sending options");
writeOptions();
m_status = WAITING_OPTIONS;
}
m_timeoutTimer.start();
m_retryTimer.start();
break;
case WAITING_OPTIONS:
LogMessage("DMR, Logged into the master successfully");
m_status = RUNNING;
m_timeoutTimer.start();
m_retryTimer.start();
break;
default:
break;
}
} else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) {
LogError("DMR, Master is closing down");
close();
open();
} else if (::memcmp(m_buffer, "MSTPONG", 7U) == 0) {
m_timeoutTimer.start();
} else if (::memcmp(m_buffer, "RPTSBKN", 7U) == 0) {
m_beacon = true;
} else {
CUtils::dump("Unknown packet from the master", m_buffer, length);
}
}
m_retryTimer.clock(ms);
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
switch (m_status) {
case WAITING_LOGIN:
writeLogin();
break;
case WAITING_AUTHORISATION:
writeAuthorisation();
break;
case WAITING_OPTIONS:
writeOptions();
break;
case WAITING_CONFIG:
writeConfig();
break;
case RUNNING:
writePing();
break;
default:
break;
}
m_retryTimer.start();
}
m_timeoutTimer.clock(ms);
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
LogError("DMR, Connection to the master has timed out, retrying connection");
close();
open();
}
}
void CDMRNetwork::reset(unsigned int slotNo)
{
assert(slotNo == 1U || slotNo == 2U);
if (slotNo == 1U) {
m_jitterBuffers[1U]->reset();
m_streamId[0U] = ::rand() + 1U;
} else {
m_jitterBuffers[2U]->reset();
m_streamId[1U] = ::rand() + 1U;
}
}
void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
unsigned int slotNo = (data[15U] & 0x80U) == 0x80U ? 2U : 1U;
// DMO mode slot disabling
if (slotNo == 1U && !m_duplex)
return;
// Individual slot disabling
if (slotNo == 1U && !m_slot1)
return;
if (slotNo == 2U && !m_slot2)
return;
unsigned char dataType = data[15U] & 0x3FU;
if (dataType == (0x20U | DT_CSBK) ||
dataType == (0x20U | DT_DATA_HEADER) ||
dataType == (0x20U | DT_RATE_1_DATA) ||
dataType == (0x20U | DT_RATE_34_DATA) ||
dataType == (0x20U | DT_RATE_12_DATA)) {
// Data & CSBK frames
m_jitterBuffers[slotNo]->appendData(data, length);
} else {
// Voice frames
unsigned char seqNo = data[4U];
m_jitterBuffers[slotNo]->addData(data, length, seqNo);
}
}
bool CDMRNetwork::writeLogin()
{
unsigned char buffer[8U];
::memcpy(buffer + 0U, "RPTL", 4U);
::memcpy(buffer + 4U, m_id, 4U);
return write(buffer, 8U);
}
bool CDMRNetwork::writeAuthorisation()
{
size_t size = m_password.size();
unsigned char* in = new unsigned char[size + sizeof(uint32_t)];
::memcpy(in, m_salt, sizeof(uint32_t));
for (size_t i = 0U; i < size; i++)
in[i + sizeof(uint32_t)] = m_password.at(i);
unsigned char out[40U];
::memcpy(out + 0U, "RPTK", 4U);
::memcpy(out + 4U, m_id, 4U);
CSHA256 sha256;
sha256.buffer(in, (unsigned int)(size + sizeof(uint32_t)), out + 8U);
delete[] in;
return write(out, 40U);
}
bool CDMRNetwork::writeOptions()
{
char buffer[300U];
::memcpy(buffer + 0U, "RPTO", 4U);
::memcpy(buffer + 4U, m_id, 4U);
::strcpy(buffer + 8U, m_options.c_str());
return write((unsigned char*)buffer, (unsigned int)m_options.length() + 8U);
}
bool CDMRNetwork::writeConfig()
{
const char* software;
char slots = '0';
if (m_duplex) {
if (m_slot1 && m_slot2)
slots = '3';
else if (m_slot1 && !m_slot2)
slots = '1';
else if (!m_slot1 && m_slot2)
slots = '2';
switch (m_hwType) {
case HWT_MMDVM:
software = "MMDVM";
break;
case HWT_MMDVM_HS:
software = "MMDVM_MMDVM_HS";
break;
case HWT_MMDVM_HS_DUAL_HAT:
software = "MMDVM_MMDVM_HS_Dual_Hat";
break;
case HWT_NANO_HOTSPOT:
software = "MMDVM_Nano_hotSPOT";
break;
default:
software = "MMDVM_Unknown";
break;
}
} else {
slots = '4';
switch (m_hwType) {
case HWT_MMDVM:
software = "MMDVM_DMO";
break;
case HWT_DVMEGA:
software = "MMDVM_DVMega";
break;
case HWT_MMDVM_ZUMSPOT:
software = "MMDVM_ZUMspot";
break;
case HWT_MMDVM_HS_HAT:
software = "MMDVM_MMDVM_HS_Hat";
break;
case HWT_MMDVM_HS_DUAL_HAT:
software = "MMDVM_MMDVM_HS_Dual_Hat";
break;
case HWT_NANO_HOTSPOT:
software = "MMDVM_Nano_hotSPOT";
break;
case HWT_NANO_DV:
software = "MMDVM_Nano_DV";
break;
case HWT_D2RG_MMDVM_HS:
software = "MMDVM_D2RG_MMDVM_HS";
break;
case HWT_MMDVM_HS:
software = "MMDVM_MMDVM_HS";
break;
default:
software = "MMDVM_Unknown";
break;
}
}
char buffer[400U];
::memcpy(buffer + 0U, "RPTC", 4U);
::memcpy(buffer + 4U, m_id, 4U);
char latitude[20U];
::sprintf(latitude, "%08f", m_latitude);
char longitude[20U];
::sprintf(longitude, "%09f", m_longitude);
unsigned int power = m_power;
if (power > 99U)
power = 99U;
int height = m_height;
if (height > 999)
height = 999;
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%8.8s%9.9s%03d%-20.20s%-19.19s%c%-124.124s%-40.40s%-40.40s", m_callsign.c_str(),
m_rxFrequency, m_txFrequency, power, m_colorCode, latitude, longitude, height, m_location.c_str(),
m_description.c_str(), slots, m_url.c_str(), m_version, software);
return write((unsigned char*)buffer, 302U);
}
bool CDMRNetwork::writePing()
{
unsigned char buffer[11U];
::memcpy(buffer + 0U, "RPTPING", 7U);
::memcpy(buffer + 7U, m_id, 4U);
return write(buffer, 11U);
}
bool CDMRNetwork::wantsBeacon()
{
bool beacon = m_beacon;
m_beacon = false;
return beacon;
}
bool CDMRNetwork::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
// if (m_debug)
// CUtils::dump(1U, "Network Transmitted", data, length);
bool ret = m_socket.write(data, length, m_address, m_port);
if (!ret) {
LogError("DMR, Socket has failed when writing data to the master, retrying connection");
m_socket.close();
open();
return false;
}
return true;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,40 +19,104 @@
#if !defined(DMRNetwork_H) #if !defined(DMRNetwork_H)
#define DMRNetwork_H #define DMRNetwork_H
#include "JitterBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include "DMRData.h" #include "DMRData.h"
#include "Defines.h"
#include <string> #include <string>
#include <cstdint>
class IDMRNetwork class CDMRNetwork
{ {
public: public:
virtual ~IDMRNetwork() = 0; CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, unsigned int jitter);
~CDMRNetwork();
virtual void setOptions(const std::string& options) = 0; void setOptions(const std::string& options);
virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url) = 0; void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url);
virtual bool open() = 0; bool open();
virtual void enable(bool enabled) = 0; void enable(bool enabled);
virtual bool read(CDMRData& data) = 0; bool read(CDMRData& data);
virtual bool write(const CDMRData& data) = 0; bool write(const CDMRData& data);
virtual bool writeRadioPosition(unsigned int id, const unsigned char* data) = 0; bool writeRadioPosition(unsigned int id, const unsigned char* data);
virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data) = 0; bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
virtual bool wantsBeacon() = 0; bool writeHomePosition(float latitude, float longitude);
virtual void clock(unsigned int ms) = 0; bool wantsBeacon();
virtual bool isConnected() const = 0; void clock(unsigned int ms);
virtual void close(bool sayGoodbye) = 0; void reset(unsigned int slotNo);
void close();
private: private:
std::string m_addressStr;
in_addr m_address;
unsigned int m_port;
uint8_t* m_id;
std::string m_password;
bool m_duplex;
const char* m_version;
bool m_debug;
CUDPSocket m_socket;
bool m_enabled;
bool m_slot1;
bool m_slot2;
CJitterBuffer** m_jitterBuffers;
HW_TYPE m_hwType;
enum STATUS {
WAITING_CONNECT,
WAITING_LOGIN,
WAITING_AUTHORISATION,
WAITING_CONFIG,
WAITING_OPTIONS,
RUNNING
};
STATUS m_status;
CTimer m_retryTimer;
CTimer m_timeoutTimer;
unsigned char* m_buffer;
unsigned char* m_salt;
uint32_t* m_streamId;
std::string m_options;
std::string m_callsign;
unsigned int m_rxFrequency;
unsigned int m_txFrequency;
unsigned int m_power;
unsigned int m_colorCode;
float m_latitude;
float m_longitude;
int m_height;
std::string m_location;
std::string m_description;
std::string m_url;
bool m_beacon;
bool writeLogin();
bool writeAuthorisation();
bool writeOptions();
bool writeConfig();
bool writePing();
bool write(const unsigned char* data, unsigned int length);
void receiveData(const unsigned char* data, unsigned int length);
}; };
#endif #endif

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2021 Jonathan Naylor, G4KLX * Copyright (C) 2015-2019 Jonathan Naylor, G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -38,18 +38,15 @@ bool CDMRSlot::m_embeddedLCOnly = false;
bool CDMRSlot::m_dumpTAData = true; bool CDMRSlot::m_dumpTAData = true;
CModem* CDMRSlot::m_modem = NULL; CModem* CDMRSlot::m_modem = NULL;
IDMRNetwork* CDMRSlot::m_network = NULL; CDMRNetwork* CDMRSlot::m_network = NULL;
CDisplay* CDMRSlot::m_display = NULL; CDisplay* CDMRSlot::m_display = NULL;
bool CDMRSlot::m_duplex = true; bool CDMRSlot::m_duplex = true;
CDMRLookup* CDMRSlot::m_lookup = NULL; CDMRLookup* CDMRSlot::m_lookup = NULL;
unsigned int CDMRSlot::m_hangCount = 3U * 17U; unsigned int CDMRSlot::m_hangCount = 3U * 17U;
DMR_OVCM_TYPES CDMRSlot::m_ovcm = DMR_OVCM_OFF; bool CDMRSlot::m_ovcm = true;
CRSSIInterpolator* CDMRSlot::m_rssiMapper = NULL; CRSSIInterpolator* CDMRSlot::m_rssiMapper = NULL;
unsigned int CDMRSlot::m_jitterTime = 360U;
unsigned int CDMRSlot::m_jitterSlots = 6U;
unsigned char* CDMRSlot::m_idle = NULL; unsigned char* CDMRSlot::m_idle = NULL;
FLCO CDMRSlot::m_flco1; FLCO CDMRSlot::m_flco1;
@ -96,7 +93,6 @@ m_netN(0U),
m_networkWatchdog(1000U, 0U, 1500U), m_networkWatchdog(1000U, 0U, 1500U),
m_rfTimeoutTimer(1000U, timeout), m_rfTimeoutTimer(1000U, timeout),
m_netTimeoutTimer(1000U, timeout), m_netTimeoutTimer(1000U, timeout),
m_packetTimer(1000U, 0U, 50U),
m_interval(), m_interval(),
m_elapsed(), m_elapsed(),
m_rfFrames(0U), m_rfFrames(0U),
@ -224,22 +220,16 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (!CDMRAccessControl::validateSrcId(srcId)) { if (!CDMRAccessControl::validateSrcId(srcId)) {
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
delete lc; delete lc;
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) { if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) {
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
delete lc; delete lc;
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
if (m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON) lc->setOVCM(m_ovcm);
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
m_rfLC = lc; m_rfLC = lc;
// The standby LC data // The standby LC data
@ -343,6 +333,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
data[0U] = TAG_EOT; data[0U] = TAG_EOT;
data[1U] = 0x00U; data[1U] = 0x00U;
writeNetworkRF(data, DT_TERMINATOR_WITH_LC);
writeNetworkRF(data, DT_TERMINATOR_WITH_LC); writeNetworkRF(data, DT_TERMINATOR_WITH_LC);
if (m_duplex) { if (m_duplex) {
@ -384,13 +375,11 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (!CDMRAccessControl::validateSrcId(srcId)) { if (!CDMRAccessControl::validateSrcId(srcId)) {
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) { if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
@ -444,12 +433,6 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (csbko == CSBKO_BSDWNACT) if (csbko == CSBKO_BSDWNACT)
return false; 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);
bool gi = csbk.getGI(); bool gi = csbk.getGI();
unsigned int srcId = csbk.getSrcId(); unsigned int srcId = csbk.getSrcId();
unsigned int dstId = csbk.getDstId(); unsigned int dstId = csbk.getDstId();
@ -457,13 +440,11 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (srcId != 0U || dstId != 0U) { if (srcId != 0U || dstId != 0U) {
if (!CDMRAccessControl::validateSrcId(srcId)) { if (!CDMRAccessControl::validateSrcId(srcId)) {
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) { if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
} }
@ -501,15 +482,6 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
case CSBKO_PRECCSBK: case CSBKO_PRECCSBK:
LogMessage("DMR Slot %u, received RF %s Preamble CSBK (%u to follow) from %s to %s%s", m_slotNo, csbk.getDataContent() ? "Data" : "CSBK", csbk.getCBF(), src.c_str(), gi ? "TG ": "", dst.c_str()); LogMessage("DMR Slot %u, received RF %s Preamble CSBK (%u to follow) from %s to %s%s", m_slotNo, csbk.getDataContent() ? "Data" : "CSBK", csbk.getCBF(), src.c_str(), gi ? "TG ": "", dst.c_str());
break; break;
case CSBKO_CALL_ALERT:
LogMessage("DMR Slot %u, received RF Call Alert CSBK from %s to %s%s", m_slotNo, src.c_str(), gi ? "TG " : "", dst.c_str());
break;
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: default:
LogWarning("DMR Slot %u, unhandled RF CSBK type - 0x%02X", m_slotNo, csbko); LogWarning("DMR Slot %u, unhandled RF CSBK type - 0x%02X", m_slotNo, csbko);
break; break;
@ -672,7 +644,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (!(m_rfTalkerId & TALKER_ID_HEADER)) { if (!(m_rfTalkerId & TALKER_ID_HEADER)) {
if (m_rfTalkerId == TALKER_ID_NONE) if (m_rfTalkerId == TALKER_ID_NONE)
m_rfTalkerAlias.reset(); m_rfTalkerAlias.reset();
m_rfTalkerAlias.add(0, data + 2U, 7U); m_rfTalkerAlias.add(0, data, 7U);
m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R"); m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R");
if (m_dumpTAData) { if (m_dumpTAData) {
@ -691,7 +663,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (!(m_rfTalkerId & TALKER_ID_BLOCK1)) { if (!(m_rfTalkerId & TALKER_ID_BLOCK1)) {
if (m_rfTalkerId == TALKER_ID_NONE) if (m_rfTalkerId == TALKER_ID_NONE)
m_rfTalkerAlias.reset(); m_rfTalkerAlias.reset();
m_rfTalkerAlias.add(1, data + 2U, 7U); m_rfTalkerAlias.add(1, data, 7U);
m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R"); m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R");
if (m_dumpTAData) { if (m_dumpTAData) {
@ -710,7 +682,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (!(m_rfTalkerId & TALKER_ID_BLOCK2)) { if (!(m_rfTalkerId & TALKER_ID_BLOCK2)) {
if (m_rfTalkerId == TALKER_ID_NONE) if (m_rfTalkerId == TALKER_ID_NONE)
m_rfTalkerAlias.reset(); m_rfTalkerAlias.reset();
m_rfTalkerAlias.add(2, data + 2U, 7U); m_rfTalkerAlias.add(2, data, 7U);
m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R"); m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R");
if (m_dumpTAData) { if (m_dumpTAData) {
@ -729,7 +701,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (!(m_rfTalkerId & TALKER_ID_BLOCK3)) { if (!(m_rfTalkerId & TALKER_ID_BLOCK3)) {
if (m_rfTalkerId == TALKER_ID_NONE) if (m_rfTalkerId == TALKER_ID_NONE)
m_rfTalkerAlias.reset(); m_rfTalkerAlias.reset();
m_rfTalkerAlias.add(3, data + 2U, 7U); m_rfTalkerAlias.add(3, data, 7U);
m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R"); m_display->writeDMRTA(m_slotNo, (unsigned char*)m_rfTalkerAlias.get(), "R");
if (m_dumpTAData) { if (m_dumpTAData) {
@ -801,22 +773,16 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (!CDMRAccessControl::validateSrcId(srcId)) { if (!CDMRAccessControl::validateSrcId(srcId)) {
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
delete lc; delete lc;
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) { if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) {
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
delete lc; delete lc;
m_rfState = RS_RF_LISTENING;
return false; return false;
} }
if (m_ovcm == DMR_OVCM_TX_ON || m_ovcm == DMR_OVCM_ON) lc->setOVCM(m_ovcm);
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
m_rfLC = lc; m_rfLC = lc;
// The standby LC data // The standby LC data
@ -966,6 +932,9 @@ void CDMRSlot::writeEndRF(bool writeEnd)
} }
} }
if (m_network != NULL)
m_network->reset(m_slotNo);
m_rfTimeoutTimer.stop(); m_rfTimeoutTimer.stop();
m_rfTimeout = false; m_rfTimeout = false;
@ -1016,9 +985,11 @@ void CDMRSlot::writeEndNet(bool writeEnd)
} }
} }
if (m_network != NULL)
m_network->reset(m_slotNo);
m_networkWatchdog.stop(); m_networkWatchdog.stop();
m_netTimeoutTimer.stop(); m_netTimeoutTimer.stop();
m_packetTimer.stop();
m_netTimeout = false; m_netTimeout = false;
m_netFrames = 0U; m_netFrames = 0U;
@ -1072,11 +1043,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
dmrData.getSrcId(), dmrData.getFLCO() == FLCO_GROUP ? "TG" : "", dmrData.getDstId(), dmrData.getSrcId(), dmrData.getFLCO() == FLCO_GROUP ? "TG" : "", dmrData.getDstId(),
srcId, flco == FLCO_GROUP ? "TG" : "", dstId); srcId, flco == FLCO_GROUP ? "TG" : "", dstId);
if (m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON) lc->setOVCM(m_ovcm);
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
m_netLC = lc; m_netLC = lc;
// The standby LC data // The standby LC data
@ -1118,9 +1085,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_modem->writeDMRAbort(m_slotNo); m_modem->writeDMRAbort(m_slotNo);
} }
for (unsigned int i = 0U; i < m_jitterSlots; i++)
writeQueueNet(m_idle);
if (m_duplex) { if (m_duplex) {
for (unsigned int i = 0U; i < NO_HEADERS_DUPLEX; i++) for (unsigned int i = 0U; i < NO_HEADERS_DUPLEX; i++)
writeQueueNet(data); writeQueueNet(data);
@ -1134,8 +1098,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
setShortLC(m_slotNo, dstId, flco, ACTIVITY_VOICE); setShortLC(m_slotNo, dstId, flco, ACTIVITY_VOICE);
std::string src = m_lookup->find(srcId); std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId); std::string dst = m_lookup->find(dstId);
class CUserDBentry cn; std::string cn = m_lookup->findWithName(srcId);
m_lookup->findWithName(srcId, &cn);
m_display->writeDMR(m_slotNo, cn, flco == FLCO_GROUP, dst, "N"); m_display->writeDMR(m_slotNo, cn, flco == FLCO_GROUP, dst, "N");
#if defined(DUMP_DMR) #if defined(DUMP_DMR)
@ -1151,11 +1114,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
unsigned int dstId = lc->getDstId(); unsigned int dstId = lc->getDstId();
unsigned int srcId = lc->getSrcId(); unsigned int srcId = lc->getSrcId();
if (m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON) lc->setOVCM(m_ovcm);
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
m_netLC = lc; m_netLC = lc;
m_lastFrameValid = false; m_lastFrameValid = false;
@ -1168,9 +1127,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_modem->writeDMRAbort(m_slotNo); m_modem->writeDMRAbort(m_slotNo);
} }
for (unsigned int i = 0U; i < m_jitterSlots; i++)
writeQueueNet(m_idle);
// Create a dummy start frame // Create a dummy start frame
unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U]; unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U];
@ -1206,12 +1162,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_netState = RS_NET_AUDIO; m_netState = RS_NET_AUDIO;
setShortLC(m_slotNo, dstId, m_netLC->getFLCO(), ACTIVITY_VOICE); setShortLC(m_slotNo, dstId, m_netLC->getFLCO(), ACTIVITY_VOICE);
std::string src = m_lookup->find(srcId); std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId); std::string dst = m_lookup->find(dstId);
class CUserDBentry cn;
m_lookup->findWithName(srcId, &cn);
m_display->writeDMR(m_slotNo, cn, m_netLC->getFLCO() == FLCO_GROUP, dst, "N"); m_display->writeDMR(m_slotNo, src, m_netLC->getFLCO() == FLCO_GROUP, dst, "N");
LogMessage("DMR Slot %u, received network late entry from %s to %s%s", m_slotNo, src.c_str(), m_netLC->getFLCO() == FLCO_GROUP ? "TG " : "", dst.c_str()); LogMessage("DMR Slot %u, received network late entry from %s to %s%s", m_slotNo, src.c_str(), m_netLC->getFLCO() == FLCO_GROUP ? "TG " : "", dst.c_str());
} }
@ -1342,11 +1297,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
unsigned int dstId = lc->getDstId(); unsigned int dstId = lc->getDstId();
unsigned int srcId = lc->getSrcId(); unsigned int srcId = lc->getSrcId();
if (m_ovcm == DMR_OVCM_RX_ON || m_ovcm == DMR_OVCM_ON) lc->setOVCM(m_ovcm);
lc->setOVCM(true);
else if (m_ovcm == DMR_OVCM_FORCE_OFF)
lc->setOVCM(false);
m_netLC = lc; m_netLC = lc;
// The standby LC data // The standby LC data
@ -1364,9 +1315,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_modem->writeDMRAbort(m_slotNo); m_modem->writeDMRAbort(m_slotNo);
} }
for (unsigned int i = 0U; i < m_jitterSlots; i++)
writeQueueNet(m_idle);
// Create a dummy start frame // Create a dummy start frame
unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U]; unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U];
@ -1409,10 +1357,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
std::string src = m_lookup->find(srcId); std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId); std::string dst = m_lookup->find(dstId);
class CUserDBentry cn;
m_lookup->findWithName(srcId, &cn);
m_display->writeDMR(m_slotNo, cn, m_netLC->getFLCO() == FLCO_GROUP, dst, "N"); m_display->writeDMR(m_slotNo, src, m_netLC->getFLCO() == FLCO_GROUP, dst, "N");
LogMessage("DMR Slot %u, received network late entry from %s to %s%s", m_slotNo, src.c_str(), m_netLC->getFLCO() == FLCO_GROUP ? "TG " : "", dst.c_str()); LogMessage("DMR Slot %u, received network late entry from %s to %s%s", m_slotNo, src.c_str(), m_netLC->getFLCO() == FLCO_GROUP ? "TG " : "", dst.c_str());
} }
@ -1447,7 +1393,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_netEmbeddedData[m_netEmbeddedWriteN].reset(); m_netEmbeddedData[m_netEmbeddedWriteN].reset();
m_packetTimer.start();
m_elapsed.start(); m_elapsed.start();
m_netFrames++; m_netFrames++;
@ -1594,7 +1539,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
writeQueueNet(data); writeQueueNet(data);
} }
m_packetTimer.start();
m_elapsed.start(); m_elapsed.start();
m_netFrames++; m_netFrames++;
@ -1617,12 +1561,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
if (csbko == CSBKO_BSDWNACT) if (csbko == CSBKO_BSDWNACT)
return; 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);
bool gi = csbk.getGI(); bool gi = csbk.getGI();
unsigned int srcId = csbk.getSrcId(); unsigned int srcId = csbk.getSrcId();
unsigned int dstId = csbk.getDstId(); unsigned int dstId = csbk.getDstId();
@ -1687,15 +1625,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
case CSBKO_PRECCSBK: case CSBKO_PRECCSBK:
LogMessage("DMR Slot %u, received network %s Preamble CSBK (%u to follow) from %s to %s%s", m_slotNo, csbk.getDataContent() ? "Data" : "CSBK", csbk.getCBF(), src.c_str(), gi ? "TG " : "", dst.c_str()); LogMessage("DMR Slot %u, received network %s Preamble CSBK (%u to follow) from %s to %s%s", m_slotNo, csbk.getDataContent() ? "Data" : "CSBK", csbk.getCBF(), src.c_str(), gi ? "TG " : "", dst.c_str());
break; break;
case CSBKO_CALL_ALERT:
LogMessage("DMR Slot %u, received network Call Alert CSBK from %s to %s%s", m_slotNo, src.c_str(), gi ? "TG " : "", dst.c_str());
break;
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: default:
LogWarning("DMR Slot %u, unhandled network CSBK type - 0x%02X", m_slotNo, csbko); LogWarning("DMR Slot %u, unhandled network CSBK type - 0x%02X", m_slotNo, csbko);
break; break;
@ -1848,21 +1777,6 @@ void CDMRSlot::clock()
} }
} }
} }
if (m_netState == RS_NET_AUDIO) {
m_packetTimer.clock(ms);
if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) {
unsigned int elapsed = m_elapsed.elapsed();
if (elapsed >= m_jitterTime) {
LogDebug("DMR Slot %u, lost audio for %ums filling in", m_slotNo, elapsed);
insertSilence(m_jitterSlots);
m_elapsed.start();
}
m_packetTimer.start();
}
}
} }
void CDMRSlot::writeQueueRF(const unsigned char *data) void CDMRSlot::writeQueueRF(const unsigned char *data)
@ -1936,7 +1850,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data)
m_queue.addData(data, len); m_queue.addData(data, len);
} }
void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, bool ovcm)
{ {
assert(modem != NULL); assert(modem != NULL);
assert(display != NULL); assert(display != NULL);
@ -1956,11 +1870,6 @@ void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData
m_rssiMapper = rssiMapper; m_rssiMapper = rssiMapper;
m_jitterTime = jitter;
float jitter_tmp = float(jitter) / 360.0F;
m_jitterSlots = (unsigned int) (std::ceil(jitter_tmp) * 6.0F);
m_idle = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U]; m_idle = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U];
::memcpy(m_idle, DMR_IDLE_DATA, DMR_FRAME_LENGTH_BYTES + 2U); ::memcpy(m_idle, DMR_IDLE_DATA, DMR_FRAME_LENGTH_BYTES + 2U);
@ -2216,7 +2125,6 @@ void CDMRSlot::enable(bool enabled)
m_networkWatchdog.stop(); m_networkWatchdog.stop();
m_netTimeoutTimer.stop(); m_netTimeoutTimer.stop();
m_packetTimer.stop();
m_netTimeout = false; m_netTimeout = false;
m_netFrames = 0U; m_netFrames = 0U;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -62,7 +62,7 @@ public:
void enable(bool enabled); void enable(bool enabled);
static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, bool ovcm);
private: private:
unsigned int m_slotNo; unsigned int m_slotNo;
@ -89,7 +89,6 @@ private:
CTimer m_networkWatchdog; CTimer m_networkWatchdog;
CTimer m_rfTimeoutTimer; CTimer m_rfTimeoutTimer;
CTimer m_netTimeoutTimer; CTimer m_netTimeoutTimer;
CTimer m_packetTimer;
CStopWatch m_interval; CStopWatch m_interval;
CStopWatch m_elapsed; CStopWatch m_elapsed;
unsigned int m_rfFrames; unsigned int m_rfFrames;
@ -118,18 +117,15 @@ private:
static bool m_dumpTAData; static bool m_dumpTAData;
static CModem* m_modem; static CModem* m_modem;
static IDMRNetwork* m_network; static CDMRNetwork* m_network;
static CDisplay* m_display; static CDisplay* m_display;
static bool m_duplex; static bool m_duplex;
static CDMRLookup* m_lookup; static CDMRLookup* m_lookup;
static unsigned int m_hangCount; static unsigned int m_hangCount;
static DMR_OVCM_TYPES m_ovcm; static bool m_ovcm;
static CRSSIInterpolator* m_rssiMapper; static CRSSIInterpolator* m_rssiMapper;
static unsigned int m_jitterTime;
static unsigned int m_jitterSlots;
static unsigned char* m_idle; static unsigned char* m_idle;
static FLCO m_flco1; static FLCO m_flco1;

View file

@ -72,7 +72,7 @@ bool CDMRTA::decodeTA()
unsigned int TAformat = (talkerAlias[0] >> 6U) & 0x03U; unsigned int TAformat = (talkerAlias[0] >> 6U) & 0x03U;
unsigned int TAsize = (talkerAlias[0] >> 1U) & 0x1FU; unsigned int TAsize = (talkerAlias[0] >> 1U) & 0x1FU;
::strcpy(m_TA, "(could not decode)"); ::strncpy(m_TA, "(could not decode)", sizeof(m_TA));
switch (TAformat) { switch (TAformat) {
case 0U: // 7 bit case 0U: // 7 bit
@ -96,7 +96,7 @@ bool CDMRTA::decodeTA()
case 1U: // ISO 8 bit case 1U: // ISO 8 bit
case 2U: // UTF8 case 2U: // UTF8
::memcpy(m_TA, talkerAlias + 1U, sizeof(m_TA)); ::strncpy(m_TA, (char*)talkerAlias + 1U, sizeof(m_TA));
break; break;
case 3U: // UTF16 poor man's conversion case 3U: // UTF16 poor man's conversion
@ -117,9 +117,9 @@ bool CDMRTA::decodeTA()
if (TAlen > TAsize) { if (TAlen > TAsize) {
if (TAlen < 29U) if (TAlen < 29U)
strcat(m_TA, " ?"); strcat(m_TA," ?");
else else
strcpy(m_TA + 28U, " ?"); strcpy(m_TA + 28U," ?");
} }
return TAlen >= TAsize; return TAlen >= TAsize;

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

1266
DStarControl.cpp Normal file

File diff suppressed because it is too large Load diff

128
DStarControl.h Normal file
View file

@ -0,0 +1,128 @@
/*
* 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, bool ackMessage, bool errorReply, const std::vector<std::string>& blackList, 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;
bool m_ackMessage;
bool m_errorReply;
bool m_remoteGateway;
std::vector<std::string> m_blackList;
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;
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

92
DStarDefines.h Normal file
View file

@ -0,0 +1,92 @@
/*
* Copyright (C) 2015,2016,2018,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(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 };
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 char DSTAR_NULL_FRAME_DATA_SRAMBLED_BYTES[] = { 0xEEU, 0xC2U, 0xA1U, 0xC8U, 0x42U, 0x6EU, 0x52U, 0x51U, 0xC3U };
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_FAST_DATA1 = 0x80U;
const unsigned char DSTAR_SLOW_DATA_TYPE_FAST_DATA2 = 0x90U;
const unsigned char DSTAR_SLOW_DATA_TYPE_SQUELCH = 0xC0U;
const unsigned char DSTAR_SLOW_DATA_LENGTH_MASK = 0x0FU;
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

336
DStarNetwork.cpp Normal file
View file

@ -0,0 +1,336 @@
/*
* Copyright (C) 2009-2014,2016,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.
*/
#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 int gatewayPort, unsigned int localPort, bool duplex, const char* version, bool debug) :
m_socket(localPort),
m_address(),
m_port(gatewayPort),
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_address = CUDPSocket::lookup(gatewayAddress);
m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
CStopWatch stopWatch;
::srand(stopWatch.start());
}
CDStarNetwork::~CDStarNetwork()
{
delete[] m_linkReflector;
}
bool CDStarNetwork::open()
{
LogMessage("Opening D-Star network connection");
if (m_address.s_addr == INADDR_NONE)
return false;
m_pollTimer.start();
return m_socket.open();
}
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
m_outId = (::rand() % 65535U) + 1U;
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_address, m_port);
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_address, m_port);
}
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_address, m_port);
}
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];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || m_port != port) {
LogMessage("D-Star packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
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;
}
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);
}

71
DStarNetwork.h Normal file
View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2009-2014,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 DStarNetwork_H
#define DStarNetwork_H
#include "DStarDefines.h"
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CDStarNetwork {
public:
CDStarNetwork(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int 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();
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
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;
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

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,8 +20,12 @@
#define Defines_H #define Defines_H
const unsigned char MODE_IDLE = 0U; const unsigned char MODE_IDLE = 0U;
const unsigned char MODE_DSTAR = 1U;
const unsigned char MODE_DMR = 2U; 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_CW = 98U; const unsigned char MODE_CW = 98U;
const unsigned char MODE_LOCKOUT = 99U; const unsigned char MODE_LOCKOUT = 99U;
const unsigned char MODE_ERROR = 100U; const unsigned char MODE_ERROR = 100U;
@ -32,8 +36,6 @@ const unsigned char TAG_DATA = 0x01U;
const unsigned char TAG_LOST = 0x02U; const unsigned char TAG_LOST = 0x02U;
const unsigned char TAG_EOT = 0x03U; const unsigned char TAG_EOT = 0x03U;
const unsigned int DSTAR_MODEM_DATA_LEN = 220U;
enum HW_TYPE { enum HW_TYPE {
HWT_MMDVM, HWT_MMDVM,
HWT_DVMEGA, HWT_DVMEGA,
@ -44,8 +46,6 @@ enum HW_TYPE {
HWT_NANO_DV, HWT_NANO_DV,
HWT_D2RG_MMDVM_HS, HWT_D2RG_MMDVM_HS,
HWT_MMDVM_HS, HWT_MMDVM_HS,
HWT_OPENGD77_HS,
HWT_SKYBRIDGE,
HWT_UNKNOWN HWT_UNKNOWN
}; };
@ -53,7 +53,6 @@ enum RPT_RF_STATE {
RS_RF_LISTENING, RS_RF_LISTENING,
RS_RF_LATE_ENTRY, RS_RF_LATE_ENTRY,
RS_RF_AUDIO, RS_RF_AUDIO,
RS_RF_DATA_AUDIO,
RS_RF_DATA, RS_RF_DATA,
RS_RF_REJECTED, RS_RF_REJECTED,
RS_RF_INVALID RS_RF_INVALID
@ -62,22 +61,13 @@ enum RPT_RF_STATE {
enum RPT_NET_STATE { enum RPT_NET_STATE {
RS_NET_IDLE, RS_NET_IDLE,
RS_NET_AUDIO, RS_NET_AUDIO,
RS_NET_DATA_AUDIO,
RS_NET_DATA RS_NET_DATA
}; };
enum DMR_BEACONS { enum B_STATUS {
DMR_BEACONS_OFF, BS_NO_DATA,
DMR_BEACONS_NETWORK, BS_DATA,
DMR_BEACONS_TIMED BS_MISSING
};
enum DMR_OVCM_TYPES {
DMR_OVCM_OFF,
DMR_OVCM_RX_ON,
DMR_OVCM_TX_ON,
DMR_OVCM_ON,
DMR_OVCM_FORCE_OFF
}; };
#endif #endif

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -18,15 +18,16 @@
#include "Display.h" #include "Display.h"
#include "Defines.h" #include "Defines.h"
#include "UARTController.h" #include "SerialController.h"
#include "ModemSerialPort.h" #include "ModemSerialPort.h"
#include "NullDisplay.h" #include "NullDisplay.h"
#include "TFTSurenoo.h" #include "TFTSerial.h"
#include "LCDproc.h" #include "LCDproc.h"
#include "Nextion.h" #include "Nextion.h"
#include "CASTInfo.h" #include "CASTInfo.h"
#include "Conf.h" #include "Conf.h"
#include "Modem.h" #include "Modem.h"
#include "UMP.h"
#include "Log.h" #include "Log.h"
#if defined(HD44780) #if defined(HD44780)
@ -99,6 +100,42 @@ void CDisplay::setQuit()
setQuitInt(); setQuitInt();
} }
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) void CDisplay::writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
{ {
assert(type != NULL); assert(type != NULL);
@ -113,29 +150,6 @@ void CDisplay::writeDMR(unsigned int slotNo, const std::string& src, bool group,
writeDMRInt(slotNo, src, group, dst, type); writeDMRInt(slotNo, src, group, dst, type);
} }
void CDisplay::writeDMR(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type)
{
assert(type != NULL);
if (slotNo == 1U) {
m_timer1.start();
m_mode1 = MODE_IDLE;
} else {
m_timer2.start();
m_mode2 = MODE_IDLE;
}
if (int err = writeDMRIntEx(slotNo, src, group, dst, type)) {
std::string src_str = src.get(keyCALLSIGN);
if (err < 0 && !src.get(keyFIRST_NAME).empty()) {
// emulate the result of old CDMRLookup::findWithName()
// (it returned callsign and firstname)
src_str += " " + src.get(keyFIRST_NAME);
}
writeDMRInt(slotNo, src_str, group, dst, type);
}
}
void CDisplay::writeDMRRSSI(unsigned int slotNo, unsigned char rssi) void CDisplay::writeDMRRSSI(unsigned int slotNo, unsigned char rssi)
{ {
if (rssi != 0U) if (rssi != 0U)
@ -152,7 +166,6 @@ void CDisplay::writeDMRBER(unsigned int slotNo, float ber)
{ {
writeDMRBERInt(slotNo, ber); writeDMRBERInt(slotNo, ber);
} }
void CDisplay::clearDMR(unsigned int slotNo) void CDisplay::clearDMR(unsigned int slotNo)
{ {
if (slotNo == 1U) { if (slotNo == 1U) {
@ -174,6 +187,126 @@ void CDisplay::clearDMR(unsigned int slotNo)
} }
} }
void CDisplay::writeFusion(const char* source, const char* dest, 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, 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::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::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() void CDisplay::writeCW()
{ {
m_timer1.start(); m_timer1.start();
@ -187,11 +320,36 @@ void CDisplay::clock(unsigned int ms)
m_timer1.clock(ms); m_timer1.clock(ms);
if (m_timer1.isRunning() && m_timer1.hasExpired()) { if (m_timer1.isRunning() && m_timer1.hasExpired()) {
switch (m_mode1) { switch (m_mode1) {
case MODE_DSTAR:
clearDStarInt();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_DMR: case MODE_DMR:
clearDMRInt(1U); clearDMRInt(1U);
m_mode1 = MODE_IDLE; m_mode1 = MODE_IDLE;
m_timer1.stop(); m_timer1.stop();
break; 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_POCSAG:
clearPOCSAGInt();
m_mode1 = MODE_IDLE;
m_timer1.stop();
break;
case MODE_CW: case MODE_CW:
clearCWInt(); clearCWInt();
m_mode1 = MODE_IDLE; m_mode1 = MODE_IDLE;
@ -219,18 +377,12 @@ void CDisplay::clockInt(unsigned int ms)
{ {
} }
int CDisplay::writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type) void CDisplay::writeDStarRSSIInt(unsigned char rssi)
{
}
void CDisplay::writeDStarBERInt(float ber)
{ {
/*
* return value:
* < 0 error condition (i.e. not supported)
* -> call writeXXXXInt() to display
* = 0 no error, writeXXXXIntEx() displayed whole status
* = 1 no error, writeXXXXIntEx() displayed partial status
* -> call writeXXXXInt() to display remain part
* > 1 reserved for future use
*/
return -1; // not supported
} }
void CDisplay::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi) void CDisplay::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
@ -245,9 +397,32 @@ 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)
{
}
/* Factory method extracted from MMDVMHost.cpp - BG5HHP */ /* Factory method extracted from MMDVMHost.cpp - BG5HHP */
CDisplay* CDisplay::createDisplay(const CConf& conf, CModem* modem) CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem)
{ {
CDisplay *display = NULL; CDisplay *display = NULL;
@ -257,7 +432,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CModem* modem)
LogInfo("Display Parameters"); LogInfo("Display Parameters");
LogInfo(" Type: %s", type.c_str()); LogInfo(" Type: %s", type.c_str());
if (type == "TFT Surenoo") { if (type == "TFT Serial") {
std::string port = conf.getTFTSerialPort(); std::string port = conf.getTFTSerialPort();
unsigned int brightness = conf.getTFTSerialBrightness(); unsigned int brightness = conf.getTFTSerialBrightness();
@ -266,11 +441,11 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CModem* modem)
ISerialPort* serial = NULL; ISerialPort* serial = NULL;
if (port == "modem") if (port == "modem")
serial = new IModemSerialPort(modem); serial = new CModemSerialPort(modem);
else else
serial = new CUARTController(port, 115200U); serial = new CSerialController(port, SERIAL_9600);
display = new CTFTSurenoo(conf.getCallsign(), dmrid, serial, brightness, conf.getDuplex()); display = new CTFTSerial(conf.getCallsign(), dmrid, serial, brightness);
} else if (type == "Nextion") { } else if (type == "Nextion") {
std::string port = conf.getNextionPort(); std::string port = conf.getNextionPort();
unsigned int brightness = conf.getNextionBrightness(); unsigned int brightness = conf.getNextionBrightness();
@ -309,16 +484,23 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CModem* modem)
} }
if (port == "modem") { if (port == "modem") {
ISerialPort* serial = new IModemSerialPort(modem); ISerialPort* serial = new CModemSerialPort(modem);
display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF); display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation());
} else if (port == "ump") {
if (ump != NULL) {
display = new CNextion(conf.getCallsign(), dmrid, ump, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation());
} else { } else {
unsigned int baudrate = 9600U; LogInfo(" NullDisplay loaded");
if (screenLayout == 4U) display = new CNullDisplay;
baudrate = 115200U; }
} else {
SERIAL_SPEED baudrate = SERIAL_9600;
if (screenLayout==4U)
baudrate = SERIAL_115200;
LogInfo(" Display baudrate: %u ", baudrate); LogInfo(" Display baudrate: %u ",baudrate);
ISerialPort* serial = new CUARTController(port, baudrate); ISerialPort* serial = new CSerialController(port, baudrate);
display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF); display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation());
} }
} else if (type == "LCDproc") { } else if (type == "LCDproc") {
std::string address = conf.getLCDprocAddress(); std::string address = conf.getLCDprocAddress();
@ -389,7 +571,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CModem* modem)
bool rotate = conf.getOLEDRotate(); bool rotate = conf.getOLEDRotate();
bool logosaver = conf.getOLEDLogoScreensaver(); bool logosaver = conf.getOLEDLogoScreensaver();
display = new COLED(type, brightness, invert, scroll, rotate, logosaver, conf.getDuplex()); display = new COLED(type, brightness, invert, scroll, rotate, logosaver, conf.getDMRNetworkSlot1(), conf.getDMRNetworkSlot2());
#endif #endif
} else if (type == "CAST") { } else if (type == "CAST") {
display = new CCASTInfo(modem); display = new CCASTInfo(modem);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,8 +20,6 @@
#define DISPLAY_H #define DISPLAY_H
#include "Timer.h" #include "Timer.h"
#include "UserDBentry.h"
#include "Modem.h"
#include <string> #include <string>
@ -29,6 +27,7 @@
class CConf; class CConf;
class CModem; class CModem;
class CUMP;
class CDisplay class CDisplay
{ {
@ -42,22 +41,43 @@ public:
void setLockout(); void setLockout();
void setError(const char* text); void setError(const char* text);
void setQuit(); 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 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); void writeDMRRSSI(unsigned int slotNo, unsigned char rssi);
void writeDMRBER(unsigned int slotNo, float ber); void writeDMRBER(unsigned int slotNo, float ber);
void writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type); void writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
void clearDMR(unsigned int slotNo); void clearDMR(unsigned int slotNo);
void writeFusion(const char* source, const char* dest, 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 writeNXDNRSSI(unsigned char rssi);
void writeNXDNBER(float ber);
void clearNXDN();
void writePOCSAG(uint32_t ric, const std::string& message);
void clearPOCSAG();
void writeCW(); void writeCW();
virtual void close() = 0; virtual void close() = 0;
void clock(unsigned int ms); void clock(unsigned int ms);
static CDisplay* createDisplay(const CConf& conf, CModem* modem); static CDisplay* createDisplay(const CConf& conf, CUMP* ump, CModem* modem);
protected: protected:
virtual void setIdleInt() = 0; virtual void setIdleInt() = 0;
@ -65,13 +85,35 @@ protected:
virtual void setErrorInt(const char* text) = 0; virtual void setErrorInt(const char* text) = 0;
virtual void setQuitInt() = 0; virtual void setQuitInt() = 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 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);
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi); virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type); virtual void writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
virtual void writeDMRBERInt(unsigned int slotNo, float ber); virtual void writeDMRBERInt(unsigned int slotNo, float ber);
virtual void clearDMRInt(unsigned int slotNo) = 0; virtual void clearDMRInt(unsigned int slotNo) = 0;
virtual void writeFusionInt(const char* source, const char* dest, 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 void writeNXDNRSSIInt(unsigned char rssi);
virtual void writeNXDNBERInt(float ber);
virtual void clearNXDNInt() = 0;
virtual void writePOCSAGInt(uint32_t ric, const std::string& message) = 0;
virtual void clearPOCSAGInt() = 0;
virtual void writeCWInt() = 0; virtual void writeCWInt() = 0;
virtual void clearCWInt() = 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"]

View file

@ -1,10 +1,9 @@
/* /*
* Copyright (C) 2010,2016,2021 by Jonathan Naylor G4KLX * Copyright (C) 2010,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2002 by Robert H. Morelos-Zaragoza. All rights reserved. * Copyright (C) 2002 by Robert H. Morelos-Zaragoza. All rights reserved.
*/ */
#include "Golay24128.h" #include "Golay24128.h"
#include "Utils.h"
#include <cstdio> #include <cstdio>
#include <cassert> #include <cassert>
@ -1090,25 +1089,20 @@ unsigned int CGolay24128::decode23127(unsigned int code)
return code >> 11; return code >> 11;
} }
bool CGolay24128::decode24128(unsigned int in, unsigned int& out) unsigned int CGolay24128::decode24128(unsigned int code)
{ {
unsigned int syndrome = ::get_syndrome_23127(in >> 1); return decode23127(code >> 1);
unsigned int error_pattern = DECODING_TABLE_23127[syndrome] << 1;
out = in ^ error_pattern;
bool valid = (CUtils::countBits(syndrome) < 3U) || !(CUtils::countBits(out) & 1);
out >>= 12;
return valid;
} }
bool CGolay24128::decode24128(unsigned char* in, unsigned int& out) unsigned int CGolay24128::decode24128(unsigned char* bytes)
{ {
assert(in != NULL); assert(bytes != NULL);
unsigned int code = (in[0U] << 16) | (in[1U] << 8) | (in[2U] << 0); unsigned int code = bytes[0U];
code <<= 8;
code |= bytes[1U];
code <<= 8;
code |= bytes[2U];
return decode24128(code, out); return decode23127(code >> 1);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010,2016,2021 by Jonathan Naylor G4KLX * Copyright (C) 2010,2016 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -25,9 +25,8 @@ public:
static unsigned int encode24128(unsigned int data); static unsigned int encode24128(unsigned int data);
static unsigned int decode23127(unsigned int code); static unsigned int decode23127(unsigned int code);
static unsigned int decode24128(unsigned int code);
static bool decode24128(unsigned int in, unsigned int& out); static unsigned int decode24128(unsigned char* bytes);
static bool decode24128(unsigned char* in, unsigned int& out);
}; };
#endif #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 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -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 YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms 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) : 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(), CDisplay(),
@ -276,12 +275,12 @@ void CHD44780::pcf8574LCDSetup()
::pcf8574Setup(AF_BASE, m_i2cAddress); ::pcf8574Setup(AF_BASE, m_i2cAddress);
// Turn on backlight // Turn on backlight
::pinMode(AF_BL, OUTPUT); ::pinMode (AF_BL, OUTPUT);
::digitalWrite(AF_BL, 1); ::digitalWrite (AF_BL, 1);
// Set LCD to write mode. // Set LCD to write mode.
::pinMode(AF_RW, OUTPUT); ::pinMode (AF_RW, OUTPUT);
::digitalWrite(AF_RW, 0); ::digitalWrite (AF_RW, 0);
m_rb = AF_RS; m_rb = AF_RS;
m_strb = AF_E; m_strb = AF_E;
@ -400,37 +399,6 @@ void CHD44780::setQuitInt()
m_dmr = false; m_dmr = false;
} }
void CHD44780::setFMInt()
{
m_clockDisplayTimer.stop();
::lcdClear(m_fd);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_WHITE);
#endif
if (m_pwm) {
if (m_pwmPin != 1U)
::softPwmWrite(m_pwmPin, m_pwmDim);
else
::pwmWrite(m_pwmPin, (m_pwmDim / 100) * 1024);
}
// Print callsign and ID at on top row for all screen sizes
::lcdPosition(m_fd, 0, 0);
::lcdPrintf(m_fd, "%-6s", m_callsign.c_str());
::lcdPosition(m_fd, m_cols - 7, 0);
::lcdPrintf(m_fd, "%7u", m_dmrid);
// Print MMDVM and Idle on bottom row for all screen sizes
::lcdPosition(m_fd, 0, m_rows - 1);
::lcdPuts(m_fd, "MMDVM");
::lcdPosition(m_fd, m_cols - 4, m_rows - 1);
::lcdPuts(m_fd, "FM"); // Gets overwritten by clock on 2 line screen
m_dmr = false;
}
void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);
@ -464,10 +432,11 @@ void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your,
::lcdPrintf(m_fd, " %.8s/%.4s", my1, my2); ::lcdPrintf(m_fd, " %.8s/%.4s", my1, my2);
::lcdPosition(m_fd, m_cols - 1, (m_rows / 2) - 1); ::lcdPosition(m_fd, m_cols - 1, (m_rows / 2) - 1);
if (strcmp(type, "R") == 0) if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2); ::lcdPutchar(m_fd, 2);
else } else {
::lcdPutchar(m_fd, 3); ::lcdPutchar(m_fd, 3);
}
::sprintf(m_buffer1, "%.8s", your); ::sprintf(m_buffer1, "%.8s", your);
@ -599,20 +568,21 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2) - 1); ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2) - 1);
::lcdPuts(m_fd, " "); ::lcdPuts(m_fd, " ");
if (group) if (group) {
::lcdPutchar(m_fd, 5); ::lcdPutchar(m_fd, 5);
else } else {
::lcdPutchar(m_fd, 4); ::lcdPutchar(m_fd, 4);
}
if (strcmp(type, "R") == 0) if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2); ::lcdPutchar(m_fd, 2);
else } else {
::lcdPutchar(m_fd, 3); ::lcdPutchar(m_fd, 3);
}
} else { } else {
::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPosition(m_fd, 0, (m_rows / 2));
::lcdPuts(m_fd, "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); ::sprintf(m_buffer2, "%s > %s%s%s", src.c_str(), group ? "TG" : "", dst.c_str(), DEADSPACE);
else else
::sprintf(m_buffer2, "%s>%s%s", src.c_str(), dst.c_str(), DEADSPACE); ::sprintf(m_buffer2, "%s>%s%s", src.c_str(), dst.c_str(), DEADSPACE);
@ -621,16 +591,18 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2)); ::lcdPosition(m_fd, m_cols - 3U, (m_rows / 2));
::lcdPuts(m_fd, " "); ::lcdPuts(m_fd, " ");
if (group) if (group) {
::lcdPutchar(m_fd, 5); ::lcdPutchar(m_fd, 5);
else } else {
::lcdPutchar(m_fd, 4); ::lcdPutchar(m_fd, 4);
}
if (strcmp(type, "R") == 0) if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2); ::lcdPutchar(m_fd, 2);
else } else {
::lcdPutchar(m_fd, 3); ::lcdPutchar(m_fd, 3);
} }
}
} else { } else {
if (m_rows > 2U) { if (m_rows > 2U) {
::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::lcdPosition(m_fd, 0, (m_rows / 2) - 2);
@ -644,10 +616,11 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2); ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2);
::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2) - 1); ::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2) - 1);
if (strcmp(type, "R") == 0) if (strcmp(type, "R") == 0) {
::lcdPutchar(m_fd, 2); ::lcdPutchar(m_fd, 2);
else } else {
::lcdPutchar(m_fd, 3); ::lcdPutchar(m_fd, 3);
}
::lcdPosition(m_fd, 0, (m_rows / 2)); ::lcdPosition(m_fd, 0, (m_rows / 2));
::lcdPutchar(m_fd, 1); ::lcdPutchar(m_fd, 1);
@ -655,12 +628,12 @@ void CHD44780::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2); ::lcdPrintf(m_fd, "%.*s", m_cols - 4U, m_buffer2);
::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2)); ::lcdPosition(m_fd, m_cols - 1U, (m_rows / 2));
if (group) if (group) {
::lcdPutchar(m_fd, 5); ::lcdPutchar(m_fd, 5);
else } else {
::lcdPutchar(m_fd, 4); ::lcdPutchar(m_fd, 4);
} }
}
m_dmr = true; m_dmr = true;
m_rssiCount1 = 0U; m_rssiCount1 = 0U;
m_rssiCount2 = 0U; m_rssiCount2 = 0U;
@ -718,6 +691,7 @@ void CHD44780::clearDMRInt(unsigned int slotNo)
} }
} }
} else { } else {
if (m_rows > 2U) { if (m_rows > 2U) {
::lcdPosition(m_fd, 0, (m_rows / 2) - 2); ::lcdPosition(m_fd, 0, (m_rows / 2) - 2);
::sprintf(m_buffer1, "%s", DEADSPACE); ::sprintf(m_buffer1, "%s", DEADSPACE);
@ -732,7 +706,7 @@ void CHD44780::clearDMRInt(unsigned int slotNo)
} }
} }
void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin) void CHD44780::writeFusionInt(const char* source, const char* dest, const char* type, const char* origin)
{ {
assert(source != NULL); assert(source != NULL);
assert(dest != NULL); assert(dest != NULL);
@ -757,27 +731,31 @@ void CHD44780::writeFusionInt(const char* source, const char* dest, unsigned cha
::lcdPuts(m_fd, "System Fusion"); ::lcdPuts(m_fd, "System Fusion");
if (m_rows == 2U && m_cols == 16U) { if (m_rows == 2U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 16U) { } else if (m_rows == 4U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
::sprintf(m_buffer1, "DG-ID %u", dgid); ::sprintf(m_buffer1, "%.10s", dest);
::lcdPosition(m_fd, 0, 2); ::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 20U) { } else if (m_rows == 4U && m_cols == 20U) {
char m_buffer1[20U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
::sprintf(m_buffer1, "DG-ID %u", dgid); ::sprintf(m_buffer1, "%.10s", dest);
::lcdPosition(m_fd, 0, 2); ::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 2 && m_cols == 40U) { } else if (m_rows == 2 && m_cols == 40U) {
::sprintf(m_buffer1, "%.10s > DG-ID %u", source, dgid); char m_buffer1[40U];
::sprintf(m_buffer1, "%.10s > %.10s", source, dest);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -804,6 +782,7 @@ void CHD44780::clearFusionInt()
#ifdef ADAFRUIT_DISPLAY #ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_PURPLE); adafruitLCDColour(AC_PURPLE);
#endif #endif
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
if (m_rows == 2U && m_cols == 16U) { if (m_rows == 2U && m_cols == 16U) {
@ -856,10 +835,12 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
::lcdPuts(m_fd, "P25"); ::lcdPuts(m_fd, "P25");
if (m_rows == 2U && m_cols == 16U) { if (m_rows == 2U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 16U) { } else if (m_rows == 4U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -868,6 +849,7 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
::lcdPosition(m_fd, 0, 2); ::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 20U) { } else if (m_rows == 4U && m_cols == 20U) {
char m_buffer1[20U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -876,6 +858,7 @@ void CHD44780::writeP25Int(const char* source, bool group, unsigned int dest, co
::lcdPosition(m_fd, 0, 2); ::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 2 && m_cols == 40U) { } else if (m_rows == 2 && m_cols == 40U) {
char m_buffer1[40U];
::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest); ::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
@ -956,10 +939,12 @@ void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, c
::lcdPuts(m_fd, "NXDN"); ::lcdPuts(m_fd, "NXDN");
if (m_rows == 2U && m_cols == 16U) { if (m_rows == 2U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 16U) { } else if (m_rows == 4U && m_cols == 16U) {
char m_buffer1[16U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -968,6 +953,7 @@ void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, c
::lcdPosition(m_fd, 0, 2); ::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 4U && m_cols == 20U) { } else if (m_rows == 4U && m_cols == 20U) {
char m_buffer1[20U];
::sprintf(m_buffer1, "%.10s >", source); ::sprintf(m_buffer1, "%.10s >", source);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
@ -976,7 +962,9 @@ void CHD44780::writeNXDNInt(const char* source, bool group, unsigned int dest, c
::lcdPosition(m_fd, 0, 2); ::lcdPosition(m_fd, 0, 2);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} else if (m_rows == 2 && m_cols == 40U) { } else if (m_rows == 2 && m_cols == 40U) {
char m_buffer1[40U];
::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest); ::sprintf(m_buffer1, "%.10s > %s%u", source, group ? "TG" : "", dest);
::lcdPosition(m_fd, 0, 1); ::lcdPosition(m_fd, 0, 1);
::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1); ::lcdPrintf(m_fd, "%.*s", m_cols, m_buffer1);
} }
@ -1032,115 +1020,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) void CHD44780::writePOCSAGInt(uint32_t ric, const std::string& message)
{ {
::lcdPosition(m_fd, m_cols - 5, m_rows - 1); ::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() void CHD44780::clearPOCSAGInt()
{ {
::lcdPosition(m_fd, m_cols - 5, m_rows - 1); ::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() void CHD44780::writeCWInt()
@ -1163,16 +1052,17 @@ void CHD44780::clockInt(unsigned int ms)
if (m_displayClock && m_clockDisplayTimer.isRunning() && m_clockDisplayTimer.hasExpired()) { if (m_displayClock && m_clockDisplayTimer.isRunning() && m_clockDisplayTimer.hasExpired()) {
time_t currentTime; time_t currentTime;
struct tm *Time; struct tm *Time;
::time(&currentTime); time(&currentTime);
if (m_utc) if (m_utc) {
Time = ::gmtime(&currentTime); Time = gmtime(&currentTime);
else } else {
Time = ::localtime(&currentTime); Time = localtime(&currentTime);
}
setlocale(LC_TIME,""); setlocale(LC_TIME,"");
::strftime(m_buffer1, 128, "%X", Time); // Time strftime(m_buffer1, 128, "%X", Time); // Time
::strftime(m_buffer2, 128, "%x", Time); // Date strftime(m_buffer2, 128, "%x", Time); // Date
if (m_cols == 16U && m_rows == 2U) { if (m_cols == 16U && m_rows == 2U) {
::lcdPosition(m_fd, m_cols - 10, 1); ::lcdPosition(m_fd, m_cols - 10, 1);

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 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -101,7 +101,6 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); 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 writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi); virtual void writeDStarRSSIInt(unsigned char rssi);
@ -111,7 +110,7 @@ protected:
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi); virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void clearDMRInt(unsigned int slotNo); 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 writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
virtual void writeFusionRSSIInt(unsigned char rssi); virtual void writeFusionRSSIInt(unsigned char rssi);
virtual void clearFusionInt(); virtual void clearFusionInt();
@ -123,10 +122,6 @@ protected:
virtual void writeNXDNRSSIInt(unsigned char rssi); virtual void writeNXDNRSSIInt(unsigned char rssi);
virtual void clearNXDNInt(); 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 writePOCSAGInt(uint32_t ric, const std::string& message);
virtual void clearPOCSAGInt(); virtual void clearPOCSAGInt();

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2002-2004,2007-2011,2013,2014-2017 by Jonathan Naylor G4KLX
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -17,8 +17,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if defined(__linux__)
#include "I2CController.h" #include "I2CController.h"
#include "Log.h" #include "Log.h"
@ -26,18 +24,52 @@
#include <cassert> #include <cassert>
#include <sys/types.h> #include <sys/types.h>
#if defined(_WIN32) || defined(_WIN64)
#include <setupapi.h>
#include <winioctl.h>
CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) :
CSerialController(device, speed, assertRTS),
m_address(address)
{
}
CI2CController::~CI2CController()
{
}
bool CI2CController::open()
{
return CSerialController::open();
}
int CI2CController::read(unsigned char* buffer, unsigned int length)
{
return CSerialController::read(buffer, length);
}
int CI2CController::write(const unsigned char* buffer, unsigned int length)
{
return CSerialController::write(buffer, length);
}
#else
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <cerrno> #include <cerrno>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <termios.h> #include <termios.h>
#if defined(__linux__)
#include <linux/i2c-dev.h> #include <linux/i2c-dev.h>
#endif
CI2CController::CI2CController(const std::string& device, unsigned int address) : CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) :
m_device(device), CSerialController(device, speed, assertRTS),
m_address(address), m_address(address)
m_fd(-1)
{ {
} }
@ -49,6 +81,7 @@ bool CI2CController::open()
{ {
assert(m_fd == -1); assert(m_fd == -1);
#if defined(__linux__)
m_fd = ::open(m_device.c_str(), O_RDWR); m_fd = ::open(m_device.c_str(), O_RDWR);
if (m_fd < 0) { if (m_fd < 0) {
LogError("Cannot open device - %s", m_device.c_str()); LogError("Cannot open device - %s", m_device.c_str());
@ -56,16 +89,19 @@ bool CI2CController::open()
} }
if (::ioctl(m_fd, I2C_TENBIT, 0) < 0) { if (::ioctl(m_fd, I2C_TENBIT, 0) < 0) {
LogError("I2C: failed to set 7bitaddress"); LogError("CI2C: failed to set 7bitaddress");
::close(m_fd); ::close(m_fd);
return false; return false;
} }
if (::ioctl(m_fd, I2C_SLAVE, m_address) < 0) { if (::ioctl(m_fd, I2C_SLAVE, m_address) < 0) {
LogError("I2C: Failed to acquire bus access/talk to slave 0x%02X", m_address); LogError("CI2C: Failed to acquire bus access/talk to slave 0x%02X", m_address);
::close(m_fd); ::close(m_fd);
return false; return false;
} }
#else
#warning "I2C controller supports Linux only"
#endif
return true; return true;
} }
@ -81,6 +117,7 @@ int CI2CController::read(unsigned char* buffer, unsigned int length)
unsigned int offset = 0U; unsigned int offset = 0U;
while (offset < length) { while (offset < length) {
#if defined(__linux__)
ssize_t n = ::read(m_fd, buffer + offset, 1U); ssize_t n = ::read(m_fd, buffer + offset, 1U);
if (n < 0) { if (n < 0) {
if (errno != EAGAIN) { if (errno != EAGAIN) {
@ -91,6 +128,7 @@ int CI2CController::read(unsigned char* buffer, unsigned int length)
if (n > 0) if (n > 0)
offset += n; offset += n;
#endif
} }
return length; return length;
@ -106,7 +144,10 @@ int CI2CController::write(const unsigned char* buffer, unsigned int length)
unsigned int ptr = 0U; unsigned int ptr = 0U;
while (ptr < length) { while (ptr < length) {
ssize_t n = ::write(m_fd, buffer + ptr, 1U); ssize_t n = 0U;
#if defined(__linux__)
n = ::write(m_fd, buffer + ptr, 1U);
#endif
if (n < 0) { if (n < 0) {
if (errno != EAGAIN) { if (errno != EAGAIN) {
LogError("Error returned from write(), errno=%d", errno); LogError("Error returned from write(), errno=%d", errno);
@ -121,12 +162,4 @@ int CI2CController::write(const unsigned char* buffer, unsigned int length)
return length; return length;
} }
void CI2CController::close()
{
assert(m_fd != -1);
::close(m_fd);
m_fd = -1;
}
#endif #endif

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 by Jonathan Naylor G4KLX
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -20,16 +20,11 @@
#ifndef I2CController_H #ifndef I2CController_H
#define I2CController_H #define I2CController_H
#if defined(__linux__) #include "SerialController.h"
#include "ModemPort.h" class CI2CController : public CSerialController {
#include "SerialPort.h"
#include <string>
class CI2CController : public ISerialPort, public IModemPort {
public: public:
CI2CController(const std::string& device, unsigned int address = 0x22U); CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address = 0x22U, bool assertRTS = false);
virtual ~CI2CController(); virtual ~CI2CController();
virtual bool open(); virtual bool open();
@ -38,14 +33,8 @@ public:
virtual int write(const unsigned char* buffer, unsigned int length); virtual int write(const unsigned char* buffer, unsigned int length);
virtual void close();
private: private:
std::string m_device;
unsigned int m_address; unsigned int m_address;
int m_fd;
}; };
#endif #endif
#endif

View file

@ -1,60 +0,0 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck - F4FXL KC3FRA
*
* 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 "IIRDirectForm1Filter.h"
#include "math.h"
CIIRDirectForm1Filter::CIIRDirectForm1Filter(float b0, float b1, float b2, float , float a1, float a2, float addtionalGaindB) :
m_x2(0.0F),
m_y2(0.0F),
m_x1(0.0F),
m_y1(0.0F),
m_b0(b0),
m_b1(b1),
m_b2(b2),
m_a1(a1),
m_a2(a2),
m_additionalGainLin(0.0F)
{
m_additionalGainLin = ::powf(10.0F, addtionalGaindB / 20.0F);
}
float CIIRDirectForm1Filter::filter(float sample)
{
float output = m_b0 * sample
+ m_b1 * m_x1
+ m_b2 * m_x2
- m_a1 * m_y1
- m_a2 * m_y2;
m_x2 = m_x1;
m_y2 = m_y1;
m_x1 = sample;
m_y1 = output;
return output * m_additionalGainLin;
}
void CIIRDirectForm1Filter::reset()
{
m_x1 = 0.0f;
m_x2 = 0.0f;
m_y1 = 0.0f;
m_y2 = 0.0f;
}

9
ISSUES.txt Normal file
View file

@ -0,0 +1,9 @@
D-Star: On some radios, the header is not decoded correctly. It looks like frequency drift at the beginning of the transmission.
DMR: DMO mode doesn't wake up older radios like other radios do.
YSF: No known issues.
P25: Upgrade the filters, processing power in the Due permiting.
NXDN: No known issues.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

236
JitterBuffer.cpp Normal file
View file

@ -0,0 +1,236 @@
/*
* Copyright (C) 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.
*/
#include "JitterBuffer.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CJitterBuffer::CJitterBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber, bool debug) :
m_name(name),
m_blockSize(blockSize),
m_blockTime(blockTime),
m_topSequenceNumber(topSequenceNumber),
m_debug(debug),
m_blockCount(0U),
m_timer(1000U, 0U, jitterTime),
m_stopWatch(),
m_running(false),
m_buffer(NULL),
m_headSequenceNumber(0U),
m_appendSequenceNumber(0U),
m_lastData(NULL),
m_lastDataLength(0U)
{
assert(blockSize > 0U);
assert(blockTime > 0U);
assert(jitterTime > 0U);
assert(topSequenceNumber > 0U);
m_blockCount = topSequenceNumber / 2U;
m_buffer = new JitterEntry[m_blockCount];
for (unsigned int i = 0U; i < m_blockCount; i++)
m_buffer[i].m_data = new unsigned char[m_blockSize];
m_lastData = new unsigned char[m_blockSize];
reset();
}
CJitterBuffer::~CJitterBuffer()
{
for (unsigned int i = 0U; i < m_blockCount; i++)
delete[] m_buffer[i].m_data;
delete[] m_buffer;
delete[] m_lastData;
}
bool CJitterBuffer::addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber)
{
assert(data != NULL);
assert(length > 0U);
assert(length <= m_blockSize);
unsigned int headSequenceNumber = m_headSequenceNumber % m_topSequenceNumber;
unsigned int tailSequenceNumber = (m_headSequenceNumber + m_blockCount) % m_topSequenceNumber;
// Is the data out of sequence?
if (headSequenceNumber < tailSequenceNumber) {
if (sequenceNumber < headSequenceNumber || sequenceNumber >= tailSequenceNumber) {
LogDebug("%s, JitterBuffer: rejecting frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
} else {
if (sequenceNumber >= tailSequenceNumber && sequenceNumber < headSequenceNumber) {
LogDebug("%s, JitterBuffer: rejecting frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
}
unsigned int number;
if (sequenceNumber >= headSequenceNumber)
number = sequenceNumber - headSequenceNumber;
else
number = (sequenceNumber + m_blockCount) - headSequenceNumber;;
unsigned int index = (m_headSequenceNumber + number) % m_blockCount;
// Do we already have the data?
if (m_buffer[index].m_length > 0U) {
LogDebug("%s, JitterBuffer: rejecting duplicate frame with seqNo=%u, pos=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, index, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
if (m_debug)
LogDebug("%s, JitterBuffer: adding frame with seqNo=%u, pos=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, index, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
::memcpy(m_buffer[index].m_data, data, length);
m_buffer[index].m_length = length;
if (!m_timer.isRunning()) {
LogDebug("%s, JitterBuffer: starting the timer", m_name.c_str());
m_timer.start();
}
return true;
}
bool CJitterBuffer::appendData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
assert(length <= m_blockSize);
unsigned int headSequenceNumber = m_headSequenceNumber % m_topSequenceNumber;
unsigned int tailSequenceNumber = (m_headSequenceNumber + m_blockCount) % m_topSequenceNumber;
// Is the data out of sequence?
if (headSequenceNumber < tailSequenceNumber) {
if (m_appendSequenceNumber < headSequenceNumber || m_appendSequenceNumber >= tailSequenceNumber) {
LogDebug("%s, JitterBuffer: rejecting append frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), m_appendSequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
} else {
if (m_appendSequenceNumber >= tailSequenceNumber && m_appendSequenceNumber < headSequenceNumber) {
LogDebug("%s, JitterBuffer: rejecting append frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), m_appendSequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
}
unsigned int number;
if (m_appendSequenceNumber >= headSequenceNumber)
number = m_appendSequenceNumber - headSequenceNumber;
else
number = (m_appendSequenceNumber + m_blockCount) - headSequenceNumber;;
unsigned int index = (m_headSequenceNumber + number) % m_blockCount;
if (m_debug)
LogDebug("%s, JitterBuffer: appending frame with seqNo=%u, pos=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), m_appendSequenceNumber, index, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
::memcpy(m_buffer[index].m_data, data, length);
m_buffer[index].m_length = length;
if (!m_timer.isRunning()) {
LogDebug("%s, JitterBuffer: starting the timer from append", m_name.c_str());
m_timer.start();
}
m_appendSequenceNumber++;
return true;
}
B_STATUS CJitterBuffer::getData(unsigned char* data, unsigned int& length)
{
assert(data != NULL);
if (!m_running)
return BS_NO_DATA;
unsigned int sequenceNumber = m_stopWatch.elapsed() / m_blockTime + 2U;
if (m_headSequenceNumber > sequenceNumber)
return BS_NO_DATA;
unsigned int head = m_headSequenceNumber % m_blockCount;
m_headSequenceNumber++;
if (m_buffer[head].m_length > 0U) {
if (m_debug)
LogDebug("%s, JitterBuffer: returning data, elapsed=%ums, raw=%u, head=%u", m_name.c_str(), m_stopWatch.elapsed(), m_headSequenceNumber - 1U, head);
::memcpy(data, m_buffer[head].m_data, m_buffer[head].m_length);
length = m_buffer[head].m_length;
// Save this data in case no more data is available next time
::memcpy(m_lastData, m_buffer[head].m_data, m_buffer[head].m_length);
m_lastDataLength = m_buffer[head].m_length;
m_buffer[head].m_length = 0U;
return BS_DATA;
}
m_buffer[head].m_length = 0U;
LogDebug("%s, JitterBuffer: no data available, elapsed=%ums, raw=%u, head=%u", m_name.c_str(), m_stopWatch.elapsed(), m_headSequenceNumber - 1U, head);
// Return the last data frame if we have it
if (m_lastDataLength > 0U) {
LogDebug("%s, JitterBuffer: returning the last received frame", m_name.c_str());
::memcpy(data, m_lastData, m_lastDataLength);
length = m_lastDataLength;
return BS_MISSING;
}
return BS_NO_DATA;
}
void CJitterBuffer::reset()
{
for (unsigned int i = 0U; i < m_blockCount; i++)
m_buffer[i].m_length = 0U;
m_headSequenceNumber = 0U;
m_appendSequenceNumber = 0U;
m_lastDataLength = 0U;
m_timer.stop();
m_running = false;
}
void CJitterBuffer::clock(unsigned int ms)
{
m_timer.clock(ms);
if (m_timer.isRunning() && m_timer.hasExpired()) {
if (!m_running) {
m_stopWatch.start();
m_running = true;
}
}
}

68
JitterBuffer.h Normal file
View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 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(JITTERBUFFER_H)
#define JITTERBUFFER_H
#include "StopWatch.h"
#include "Defines.h"
#include "Timer.h"
#include <string>
class CJitterBuffer {
public:
CJitterBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber, bool debug);
~CJitterBuffer();
bool addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber);
bool appendData(const unsigned char* data, unsigned int length);
B_STATUS getData(unsigned char* data, unsigned int& length);
void reset();
void clock(unsigned int ms);
private:
std::string m_name;
unsigned int m_blockSize;
unsigned int m_blockTime;
unsigned int m_topSequenceNumber;
bool m_debug;
unsigned int m_blockCount;
CTimer m_timer;
CStopWatch m_stopWatch;
bool m_running;
struct JitterEntry
{
unsigned char* m_data;
unsigned int m_length;
};
JitterEntry* m_buffer;
unsigned int m_headSequenceNumber;
unsigned int m_appendSequenceNumber;
unsigned char* m_lastData;
unsigned int m_lastDataLength;
};
#endif

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2016,2017,2018 by Tony Corbett G0WFV * Copyright (C) 2016,2017,2018 by Tony Corbett G0WFV
* Copyright (C) 2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -72,7 +72,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdarg.h> #include <stdarg.h>
#else #else
#include <ws2tcpip.h> #include <winsock.h>
#endif #endif
#define BUFFER_MAX_LEN 128 #define BUFFER_MAX_LEN 128
@ -95,9 +95,8 @@ const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms
const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms
const unsigned int M17_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms
CLCDproc::CLCDproc(std::string address, unsigned int port, unsigned short localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle) : CLCDproc::CLCDproc(std::string address, unsigned int port, unsigned int localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle) :
CDisplay(), CDisplay(),
m_address(address), m_address(address),
m_port(port), m_port(port),
@ -122,53 +121,44 @@ CLCDproc::~CLCDproc()
bool CLCDproc::open() bool CLCDproc::open()
{ {
int err; const char *server;
unsigned int addrlen; unsigned int port, localPort;
std::string port, localPort; struct sockaddr_in serverAddress, clientAddress;
struct sockaddr_storage serverAddress, clientAddress; struct hostent *h;
struct addrinfo hints, *res;
port = std::to_string(m_port); server = m_address.c_str();
localPort = std::to_string(m_localPort); port = m_port;
memset(&hints, 0, sizeof(hints)); localPort = m_localPort;
/* Lookup the hostname address */
hints.ai_flags = AI_NUMERICSERV;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(m_address.c_str(), port.c_str(), &hints, &res);
if (err) {
LogError("LCDproc, cannot lookup server");
return false;
}
memcpy(&serverAddress, res->ai_addr, addrlen = res->ai_addrlen);
freeaddrinfo(res);
/* Lookup the client address (random port - need to specify manual port from ini file) */
hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
hints.ai_family = serverAddress.ss_family;
err = getaddrinfo(NULL, localPort.c_str(), &hints, &res);
if (err) {
LogError("LCDproc, cannot lookup client");
return false;
}
memcpy(&clientAddress, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
/* Create TCP socket */ /* Create TCP socket */
m_socketfd = socket(clientAddress.ss_family, SOCK_STREAM, 0); m_socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (m_socketfd == -1) { if (m_socketfd == -1) {
LogError("LCDproc, failed to create socket"); LogError("LCDproc, failed to create socket");
return false; return false;
} }
/* Sets client address (random port - need to specify manual port from ini file?) */
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
//clientAddress.sin_port = htons(0);
clientAddress.sin_port = htons(localPort);
/* Bind the address to the socket */ /* Bind the address to the socket */
if (bind(m_socketfd, (struct sockaddr *)&clientAddress, addrlen) == -1) { if (bind(m_socketfd, (struct sockaddr *)&clientAddress, sizeof(clientAddress)) == -1) {
LogError("LCDproc, error whilst binding address"); LogError("LCDproc, error whilst binding address");
return false; return false;
} }
/* Connect to server */ /* Lookup the hostname address */
if (connect(m_socketfd, (struct sockaddr *)&serverAddress, addrlen) == -1) { h = gethostbyname(server);
/* Sets server address */
serverAddress.sin_family = h->h_addrtype;
memcpy((char*)&serverAddress.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
serverAddress.sin_port = htons(port);
if (connect(m_socketfd, (struct sockaddr * )&serverAddress, sizeof(serverAddress))==-1) {
LogError("LCDproc, cannot connect to server"); LogError("LCDproc, cannot connect to server");
return false; return false;
} }
@ -189,7 +179,6 @@ void CLCDproc::setIdleInt()
socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
socketPrintf(m_socketfd, "screen_set M17 -priority hidden");
socketPrintf(m_socketfd, "widget_set Status Status %u %u Idle", m_cols - 3, m_rows); socketPrintf(m_socketfd, "widget_set Status Status %u %u Idle", m_cols - 3, m_rows);
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
} }
@ -209,7 +198,6 @@ void CLCDproc::setErrorInt(const char* text)
socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
socketPrintf(m_socketfd, "screen_set M17 -priority hidden");
socketPrintf(m_socketfd, "widget_set Status Status %u %u Error", m_cols - 4, m_rows); socketPrintf(m_socketfd, "widget_set Status Status %u %u Error", m_cols - 4, m_rows);
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
} }
@ -227,7 +215,6 @@ void CLCDproc::setLockoutInt()
socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
socketPrintf(m_socketfd, "screen_set M17 -priority hidden");
socketPrintf(m_socketfd, "widget_set Status Status %u %u Lockout", m_cols - 6, m_rows); socketPrintf(m_socketfd, "widget_set Status Status %u %u Lockout", m_cols - 6, m_rows);
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
} }
@ -247,7 +234,6 @@ void CLCDproc::setQuitInt()
socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
socketPrintf(m_socketfd, "screen_set M17 -priority hidden");
socketPrintf(m_socketfd, "widget_set Status Status %u %u Stopped", m_cols - 6, m_rows); socketPrintf(m_socketfd, "widget_set Status Status %u %u Stopped", m_cols - 6, m_rows);
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
} }
@ -255,24 +241,6 @@ void CLCDproc::setQuitInt()
m_dmr = false; m_dmr = false;
} }
void CLCDproc::setFMInt()
{
m_clockDisplayTimer.stop(); // Stop the clock display
if (m_screensDefined) {
socketPrintf(m_socketfd, "screen_set DStar -priority hidden");
socketPrintf(m_socketfd, "screen_set DMR -priority hidden");
socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
socketPrintf(m_socketfd, "screen_set M17 -priority hidden");
socketPrintf(m_socketfd, "widget_set Status Status %u %u FM", m_cols - 6, m_rows);
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
}
m_dmr = false;
}
void CLCDproc::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CLCDproc::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);
@ -326,7 +294,7 @@ void CLCDproc::clearDStarInt()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 Listening");
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 8"); // Set LED4 color green socketPrintf(m_socketfd, "output 8"); // Set LED4 color green
@ -419,7 +387,7 @@ void CLCDproc::clearDMRInt(unsigned int slotNo)
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
} }
} else { } else {
socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 Listening");
socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
} }
@ -428,7 +396,7 @@ void CLCDproc::clearDMRInt(unsigned int slotNo)
// LED 3 Green 4 Red 64 Yellow 68 // LED 3 Green 4 Red 64 Yellow 68
void CLCDproc::writeFusionInt(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin) void CLCDproc::writeFusionInt(const char* source, const char* dest, const char* type, const char* origin)
{ {
assert(source != NULL); assert(source != NULL);
assert(dest != NULL); assert(dest != NULL);
@ -441,10 +409,10 @@ void CLCDproc::writeFusionInt(const char* source, const char* dest, unsigned cha
socketPrintf(m_socketfd, "widget_set YSF Mode 1 1 \"System Fusion\""); socketPrintf(m_socketfd, "widget_set YSF Mode 1 1 \"System Fusion\"");
if (m_rows == 2U) { if (m_rows == 2U) {
socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s > DG-ID %u\"", source, dgid); socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s > %s%u\"", source, dest);
} else { } else {
socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s >\"", source); socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s >\"", source);
socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"DG-ID %u\"", dgid); socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"%s%u\"", dest);
socketPrintf(m_socketfd, "output 64"); // Set LED3 color red socketPrintf(m_socketfd, "output 64"); // Set LED3 color red
} }
@ -454,8 +422,9 @@ void CLCDproc::writeFusionInt(const char* source, const char* dest, unsigned cha
void CLCDproc::writeFusionRSSIInt(unsigned char rssi) void CLCDproc::writeFusionRSSIInt(unsigned char rssi)
{ {
if (m_rssiCount1 == 0U) if (m_rssiCount1 == 0U) {
socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi); socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
}
m_rssiCount1++; m_rssiCount1++;
if (m_rssiCount1 >= YSF_RSSI_COUNT) if (m_rssiCount1 >= YSF_RSSI_COUNT)
@ -466,7 +435,7 @@ void CLCDproc::clearFusionInt()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 Listening");
socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 4"); // Set LED3 color green socketPrintf(m_socketfd, "output 4"); // Set LED3 color green
@ -511,7 +480,7 @@ void CLCDproc::clearP25Int()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 Listening");
socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 2"); // Set LED2 color green socketPrintf(m_socketfd, "output 2"); // Set LED2 color green
@ -556,57 +525,12 @@ void CLCDproc::clearNXDNInt()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 Listening");
socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 16"); // Set LED5 color green socketPrintf(m_socketfd, "output 16"); // Set LED5 color green
} }
void CLCDproc::writeM17Int(const char* source, const char* dest, const char* type)
{
assert(source != NULL);
assert(dest != NULL);
assert(type != NULL);
m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "screen_set M17 -priority foreground");
socketPrintf(m_socketfd, "widget_set M17 Mode 1 1 M17");
if (m_rows == 2U) {
socketPrintf(m_socketfd, "widget_set M17 Line2 1 2 15 2 h 3 \"%.9s > %.9s\"", source, dest);
}
else {
socketPrintf(m_socketfd, "widget_set M17 Line2 1 2 15 2 h 3 \"%.9s >\"", source);
socketPrintf(m_socketfd, "widget_set M17 Line3 1 3 15 3 h 3 \"%.9ss\"", dest);
socketPrintf(m_socketfd, "output 255"); // Set LED5 color red
}
m_dmr = false;
m_rssiCount1 = 0U;
}
void CLCDproc::writeM17RSSIInt(unsigned char rssi)
{
if (m_rssiCount1 == 0U) {
socketPrintf(m_socketfd, "widget_set M17 Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
}
m_rssiCount1++;
if (m_rssiCount1 >= M17_RSSI_COUNT)
m_rssiCount1 = 0U;
}
void CLCDproc::clearM17Int()
{
m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set M17 Line2 1 2 15 2 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set M17 Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set M17 Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 16"); // Set LED5 color green
}
void CLCDproc::writePOCSAGInt(uint32_t ric, const std::string& message) void CLCDproc::writePOCSAGInt(uint32_t ric, const std::string& message)
{ {
} }
@ -828,7 +752,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add DStar Line4 scroller"); socketPrintf(m_socketfd, "widget_add DStar Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 Listening");
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\"");
*/ */
@ -849,8 +773,8 @@ void CLCDproc::defineScreens()
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2); socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2);
socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1); socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1);
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 Listening");
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 Listening");
*/ */
// The YSF Screen // The YSF Screen
@ -864,7 +788,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add YSF Line4 scroller"); socketPrintf(m_socketfd, "widget_add YSF Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 Listening");
socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \"");
socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \""); socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \"");
*/ */
@ -880,7 +804,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add P25 Line4 scroller"); socketPrintf(m_socketfd, "widget_add P25 Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 Listening");
socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \"");
socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \""); socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \"");
*/ */
@ -896,26 +820,10 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller"); socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 Listening");
socketPrintf(m_socketfd, "widget_set NXDN Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set NXDN Line3 3 1 15 1 h 3 \" \"");
socketPrintf(m_socketfd, "widget_set NXDN Line4 4 2 15 2 h 3 \" \""); socketPrintf(m_socketfd, "widget_set NXDN Line4 4 2 15 2 h 3 \" \"");
*/ */
// The M17 Screen
socketPrintf(m_socketfd, "screen_add M17");
socketPrintf(m_socketfd, "screen_set M17 -name M17 -heartbeat on -priority hidden -backlight on");
socketPrintf(m_socketfd, "widget_add M17 Mode string");
socketPrintf(m_socketfd, "widget_add M17 Line2 scroller");
socketPrintf(m_socketfd, "widget_add M17 Line3 scroller");
socketPrintf(m_socketfd, "widget_add M17 Line4 scroller");
/* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set M17 Line3 2 1 15 1 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set M17 Line3 3 1 15 1 h 3 \" \"");
socketPrintf(m_socketfd, "widget_set M17 Line4 4 2 15 2 h 3 \" \"");
*/
m_screensDefined = true; m_screensDefined = true;
} }

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2016,2017 by Tony Corbett G0WFV * Copyright (C) 2016,2017 by Tony Corbett G0WFV
* Copyright (C) 2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -28,7 +28,7 @@
class CLCDproc : public CDisplay class CLCDproc : public CDisplay
{ {
public: public:
CLCDproc(std::string address, unsigned int port, unsigned short localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle); CLCDproc(std::string address, unsigned int port, unsigned int localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle);
virtual ~CLCDproc(); virtual ~CLCDproc();
virtual bool open(); virtual bool open();
@ -40,7 +40,7 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); 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 writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi); virtual void writeDStarRSSIInt(unsigned char rssi);
@ -50,7 +50,7 @@ protected:
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi); virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void clearDMRInt(unsigned int slotNo); 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 writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
virtual void writeFusionRSSIInt(unsigned char rssi); virtual void writeFusionRSSIInt(unsigned char rssi);
virtual void clearFusionInt(); virtual void clearFusionInt();
@ -62,10 +62,6 @@ protected:
virtual void writeNXDNRSSIInt(unsigned char rssi); virtual void writeNXDNRSSIInt(unsigned char rssi);
virtual void clearNXDNInt(); 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 writePOCSAGInt(uint32_t ric, const std::string& message);
virtual void clearPOCSAGInt(); virtual void clearPOCSAGInt();
@ -77,7 +73,7 @@ protected:
private: private:
std::string m_address; std::string m_address;
unsigned int m_port; unsigned int m_port;
unsigned short m_localPort; unsigned int m_localPort;
std::string m_callsign; std::string m_callsign;
unsigned int m_dmrid; unsigned int m_dmrid;
bool m_displayClock; bool m_displayClock;

74
Log.cpp
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,7 +22,6 @@
#include <Windows.h> #include <Windows.h>
#else #else
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h>
#endif #endif
#include <cstdio> #include <cstdio>
@ -35,10 +34,8 @@
static unsigned int m_fileLevel = 2U; static unsigned int m_fileLevel = 2U;
static std::string m_filePath; static std::string m_filePath;
static std::string m_fileRoot; static std::string m_fileRoot;
static bool m_fileRotate = true;
static FILE* m_fpLog = NULL; static FILE* m_fpLog = NULL;
static bool m_daemon = false;
static unsigned int m_displayLevel = 2U; static unsigned int m_displayLevel = 2U;
@ -46,10 +43,8 @@ static struct tm m_tm;
static char LEVELS[] = " DMIWEF"; static char LEVELS[] = " DMIWEF";
static bool logOpenRotate() static bool LogOpen()
{ {
bool status = false;
if (m_fileLevel == 0U) if (m_fileLevel == 0U)
return true; return true;
@ -66,76 +61,25 @@ static bool logOpenRotate()
::fclose(m_fpLog); ::fclose(m_fpLog);
} }
char filename[200U]; char filename[100U];
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); ::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#else #else
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); ::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif #endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) { m_fpLog = ::fopen(filename, "a+t");
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon)
dup2(fileno(m_fpLog), fileno(stderr));
#endif
}
m_tm = *tm; m_tm = *tm;
return status; return m_fpLog != NULL;
} }
static bool logOpenNoRotate() bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel)
{
bool status = false;
if (m_fileLevel == 0U)
return true;
if (m_fpLog != NULL)
return true;
char filename[200U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#else
::sprintf(filename, "%s/%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon)
dup2(fileno(m_fpLog), fileno(stderr));
#endif
}
return status;
}
bool LogOpen()
{
if (m_fileRotate)
return logOpenRotate();
else
return logOpenNoRotate();
}
bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate)
{ {
m_filePath = filePath; m_filePath = filePath;
m_fileRoot = fileRoot; m_fileRoot = fileRoot;
m_fileLevel = fileLevel; m_fileLevel = fileLevel;
m_displayLevel = displayLevel; m_displayLevel = displayLevel;
m_daemon = daemon;
m_fileRotate = rotate;
if (m_daemon)
m_displayLevel = 0U;
return ::LogOpen(); return ::LogOpen();
} }
@ -149,7 +93,7 @@ void Log(unsigned int level, const char* fmt, ...)
{ {
assert(fmt != NULL); assert(fmt != NULL);
char buffer[501U]; char buffer[300U];
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st; SYSTEMTIME st;
::GetSystemTime(&st); ::GetSystemTime(&st);
@ -161,13 +105,13 @@ void Log(unsigned int level, const char* fmt, ...)
struct tm* tm = ::gmtime(&now.tv_sec); 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.%03lu ", 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 / 1000U);
#endif #endif
va_list vl; va_list vl;
va_start(vl, fmt); va_start(vl, fmt);
::vsnprintf(buffer + ::strlen(buffer), 500, fmt, vl); ::vsprintf(buffer + ::strlen(buffer), fmt, vl);
va_end(vl); va_end(vl);

4
Log.h
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,7 +30,7 @@
extern void Log(unsigned int level, const char* fmt, ...); extern void Log(unsigned int level, const char* fmt, ...);
extern bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate); extern bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel);
extern void LogFinalise(); extern void LogFinalise();
#endif #endif

157
MMDVM.ini
View file

@ -1,6 +1,6 @@
[General] [General]
Callsign=MUTRPT Callsign=G9BF
Id=1337 Id=123456
Timeout=180 Timeout=180
Duplex=1 Duplex=1
# ModeHang=10 # ModeHang=10
@ -13,6 +13,12 @@ Daemon=0
RXFrequency=435000000 RXFrequency=435000000
TXFrequency=435000000 TXFrequency=435000000
Power=1 Power=1
Latitude=0.0
Longitude=0.0
Height=0
Location=Nowhere
Description=Multi-Mode Repeater
URL=www.google.co.uk
[Log] [Log]
# Logging levels, 0=No logging # Logging levels, 0=No logging
@ -20,7 +26,6 @@ DisplayLevel=1
FileLevel=1 FileLevel=1
FilePath=. FilePath=.
FileRoot=MMDVM FileRoot=MMDVM
FileRotate=1
[CW Id] [CW Id]
Enable=1 Enable=1
@ -31,23 +36,16 @@ Time=10
File=DMRIds.dat File=DMRIds.dat
Time=24 Time=24
[Modem] [NXDN Id Lookup]
# Valid values are "null", "uart", "udp", and (on Linux) "i2c" File=NXDN.csv
Protocol=uart Time=24
# The port and speed used for a UART connection
# UARTPort=\\.\COM4
# UARTPort=/dev/ttyACM0
UARTPort=/dev/ttyAMA0
UARTSpeed=460800
# The port and address for an I2C connection
I2CPort=/dev/i2c
I2CAddress=0x22
# IP parameters for UDP connection
ModemAddress=192.168.2.100
ModemPort=3334
LocalAddress=192.168.2.1
LocalPort=3335
[Modem]
# Port=/dev/ttyACM0
# Port=/dev/ttyAMA0
Port=\\.\COM3
Protocol=uart
# Address=0x22
TXInvert=1 TXInvert=1
RXInvert=0 RXInvert=0
PTTInvert=0 PTTInvert=0
@ -60,9 +58,14 @@ TXLevel=50
RXDCOffset=0 RXDCOffset=0
TXDCOffset=0 TXDCOffset=0
RFLevel=100 RFLevel=100
DMRTXLevel=50 # CWIdTXLevel=50
# D-StarTXLevel=50
# DMRTXLevel=50
# YSFTXLevel=50
# P25TXLevel=50
# NXDNTXLevel=50
# POCSAGTXLevel=50
RSSIMappingFile=RSSI.dat RSSIMappingFile=RSSI.dat
UseCOSAsLockout=0
Trace=0 Trace=0
Debug=0 Debug=0
@ -73,12 +76,28 @@ RemotePort=40094
LocalPort=40095 LocalPort=40095
# SendFrameType=0 # SendFrameType=0
[UMP]
Enable=0
# Port=\\.\COM4
Port=/dev/ttyACM1
[D-Star]
Enable=1
Module=C
SelfOnly=0
AckReply=1
AckTime=750
AckMessage=0
ErrorReply=1
RemoteGateway=0
# ModeHang=10
[DMR] [DMR]
Enable=1 Enable=1
Beacons=0 Beacons=0
BeaconInterval=60 BeaconInterval=60
BeaconDuration=3 BeaconDuration=3
ColorCode=7 ColorCode=1
SelfOnly=0 SelfOnly=0
EmbeddedLCOnly=0 EmbeddedLCOnly=0
DumpTAData=1 DumpTAData=1
@ -88,23 +107,89 @@ DumpTAData=1
CallHang=3 CallHang=3
TXHang=4 TXHang=4
# ModeHang=10 # ModeHang=10
# OVCM Values, 0=off, 1=rx_on, 2=tx_on, 3=both_on, 4=force off OVCM=1
# OVCM=0
[System Fusion]
Enable=1
LowDeviation=0
SelfOnly=0
TXHang=4
#DGID=1
RemoteGateway=0
# ModeHang=10
[P25]
Enable=1
NAC=293
SelfOnly=0
OverrideUIDCheck=0
RemoteGateway=0
# ModeHang=10
[NXDN]
Enable=1
RAN=1
SelfOnly=0
RemoteGateway=0
# ModeHang=10
[POCSAG]
Enable=1
Frequency=439987500
[D-Star Network]
Enable=1
GatewayAddress=127.0.0.1
GatewayPort=20010
LocalPort=20011
# ModeHang=3
Debug=0
[DMR Network] [DMR Network]
Enable=1 Enable=1
# Type may be either 'Direct' or 'Gateway'. When Direct you must provide the Master's Address=44.131.4.1
# address as well as the Password, and for DMR+, Options also. Port=62031
Type=Direct
LocalAddress=127.0.0.1
LocalPort=62032
RemoteAddress=127.0.0.1
RemotePort=62031
# Password=P@ssw0rd1234
Jitter=360 Jitter=360
# Local=62032
Password=PASSWORD
# Options=
Slot1=1 Slot1=1
Slot2=1 Slot2=1
# Options= # 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
GatewayAddress=127.0.0.1
GatewayPort=42020
LocalPort=32010
# ModeHang=3
Debug=0
[NXDN Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=14021
GatewayAddress=127.0.0.1
GatewayPort=14020
# ModeHang=3
Debug=0
[POCSAG Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=3800
GatewayAddress=127.0.0.1
GatewayPort=4800
# ModeHang=3 # ModeHang=3
Debug=0 Debug=0
@ -164,7 +249,11 @@ UTC=0
Enable=0 Enable=0
File=/tmp/MMDVM_Active.lck File=/tmp/MMDVM_Active.lck
[Remote Control] [Mobile GPS]
Enable=0 Enable=0
Address=127.0.0.1 Address=127.0.0.1
Port=7834
[Remote Control]
Enable=0
Port=7642 Port=7642

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,34 +20,31 @@
#define MMDVMHOST_H #define MMDVMHOST_H
#include "RemoteControl.h" #include "RemoteControl.h"
//#include "POCSAGNetwork.h" #include "POCSAGNetwork.h"
//#include "POCSAGControl.h" #include "POCSAGControl.h"
//#include "DStarNetwork.h" #include "DStarNetwork.h"
//#include "AX25Network.h" #include "NXDNNetwork.h"
//#include "NXDNNetwork.h" #include "DStarControl.h"
//#include "DStarControl.h"
//#include "AX25Control.h"
#include "DMRControl.h" #include "DMRControl.h"
//#include "YSFControl.h" #include "YSFControl.h"
//#include "P25Control.h" #include "P25Control.h"
//#include "NXDNControl.h" #include "NXDNControl.h"
//#include "M17Control.h" #include "NXDNLookup.h"
//#include "NXDNLookup.h" #include "YSFNetwork.h"
//#include "YSFNetwork.h" #include "P25Network.h"
//#include "P25Network.h"
#include "DMRNetwork.h" #include "DMRNetwork.h"
//#include "M17Network.h"
//#include "FMNetwork.h"
#include "DMRLookup.h" #include "DMRLookup.h"
//#include "FMControl.h" #include "MobileGPS.h"
//#include "Display.h" #include "Display.h"
#include "Timer.h" #include "Timer.h"
#include "Modem.h" #include "Modem.h"
#include "Conf.h" #include "Conf.h"
#include "UMP.h"
#include <string> #include <string>
class CMMDVMHost class CMMDVMHost
{ {
public: public:
@ -56,33 +53,35 @@ public:
int run(); int run();
void buildNetworkStatusString(std::string &str);
void buildNetworkHostsString(std::string &str);
private: private:
CConf m_conf; CConf m_conf;
CModem* m_modem; CModem* m_modem;
CDStarControl* m_dstar;
CDMRControl* m_dmr; CDMRControl* m_dmr;
CYSFControl* m_ysf;
IDMRNetwork* m_dmrNetwork; CP25Control* m_p25;
CNXDNControl* m_nxdn;
CPOCSAGControl* m_pocsag;
CDStarNetwork* m_dstarNetwork;
CDMRNetwork* m_dmrNetwork;
CYSFNetwork* m_ysfNetwork;
CP25Network* m_p25Network;
CNXDNNetwork* m_nxdnNetwork;
CPOCSAGNetwork* m_pocsagNetwork;
CDisplay* m_display; CDisplay* m_display;
CUMP* m_ump;
unsigned char m_mode; unsigned char m_mode;
unsigned int m_dstarRFModeHang; unsigned int m_dstarRFModeHang;
unsigned int m_dmrRFModeHang; unsigned int m_dmrRFModeHang;
unsigned int m_ysfRFModeHang; unsigned int m_ysfRFModeHang;
unsigned int m_p25RFModeHang; unsigned int m_p25RFModeHang;
unsigned int m_nxdnRFModeHang; unsigned int m_nxdnRFModeHang;
unsigned int m_m17RFModeHang;
unsigned int m_fmRFModeHang;
unsigned int m_dstarNetModeHang; unsigned int m_dstarNetModeHang;
unsigned int m_dmrNetModeHang; unsigned int m_dmrNetModeHang;
unsigned int m_ysfNetModeHang; unsigned int m_ysfNetModeHang;
unsigned int m_p25NetModeHang; unsigned int m_p25NetModeHang;
unsigned int m_nxdnNetModeHang; unsigned int m_nxdnNetModeHang;
unsigned int m_m17NetModeHang;
unsigned int m_pocsagNetModeHang; unsigned int m_pocsagNetModeHang;
unsigned int m_fmNetModeHang;
CTimer m_modeTimer; CTimer m_modeTimer;
CTimer m_dmrTXTimer; CTimer m_dmrTXTimer;
CTimer m_cwIdTimer; CTimer m_cwIdTimer;
@ -93,17 +92,16 @@ private:
bool m_ysfEnabled; bool m_ysfEnabled;
bool m_p25Enabled; bool m_p25Enabled;
bool m_nxdnEnabled; bool m_nxdnEnabled;
bool m_m17Enabled;
bool m_pocsagEnabled; bool m_pocsagEnabled;
bool m_fmEnabled;
bool m_ax25Enabled;
unsigned int m_cwIdTime; unsigned int m_cwIdTime;
CDMRLookup* m_dmrLookup; CDMRLookup* m_dmrLookup;
CNXDNLookup* m_nxdnLookup;
std::string m_callsign; std::string m_callsign;
unsigned int m_id; unsigned int m_id;
std::string m_cwCallsign; std::string m_cwCallsign;
bool m_lockFileEnabled; bool m_lockFileEnabled;
std::string m_lockFileName; std::string m_lockFileName;
CMobileGPS* m_mobileGPS;
CRemoteControl* m_remoteControl; CRemoteControl* m_remoteControl;
bool m_fixedMode; bool m_fixedMode;
@ -114,14 +112,10 @@ private:
bool createYSFNetwork(); bool createYSFNetwork();
bool createP25Network(); bool createP25Network();
bool createNXDNNetwork(); bool createNXDNNetwork();
bool createM17Network();
bool createPOCSAGNetwork(); bool createPOCSAGNetwork();
bool createFMNetwork();
bool createAX25Network();
void remoteControl(); void remoteControl();
void processModeCommand(unsigned char mode, unsigned int timeout); void processModeCommand(unsigned char mode, unsigned int timeout);
void processEnableCommand(bool& mode, bool enabled);
void setMode(unsigned char mode); void setMode(unsigned char mode);

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

340
MMDVMHost.vcxproj Normal file
View file

@ -0,0 +1,340 @@
<?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.15063.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>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</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>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>_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>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>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="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="DMREMB.h" />
<ClInclude Include="DMREmbeddedData.h" />
<ClInclude Include="DMRFullLC.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="Golay2087.h" />
<ClInclude Include="Golay24128.h" />
<ClInclude Include="Hamming.h" />
<ClInclude Include="DMRLookup.h" />
<ClInclude Include="I2CController.h" />
<ClInclude Include="JitterBuffer.h" />
<ClInclude Include="LCDproc.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="MMDVMHost.h" />
<ClInclude Include="MobileGPS.h" />
<ClInclude Include="Modem.h" />
<ClInclude Include="ModemSerialPort.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="NetworkInfo.h" />
<ClInclude Include="Nextion.h" />
<ClInclude Include="NullDisplay.h" />
<ClInclude Include="NullModem.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="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="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="SerialController.h" />
<ClInclude Include="SerialPort.h" />
<ClInclude Include="SHA256.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Sync.h" />
<ClInclude Include="TFTSerial.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="UDPSocket.h" />
<ClInclude Include="UMP.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="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="DMREMB.cpp" />
<ClCompile Include="DMREmbeddedData.cpp" />
<ClCompile Include="DMRFullLC.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="Golay2087.cpp" />
<ClCompile Include="Golay24128.cpp" />
<ClCompile Include="Hamming.cpp" />
<ClCompile Include="I2CController.cpp" />
<ClCompile Include="JitterBuffer.cpp" />
<ClCompile Include="LCDproc.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="MMDVMHost.cpp" />
<ClCompile Include="MobileGPS.cpp" />
<ClCompile Include="Modem.cpp" />
<ClCompile Include="ModemSerialPort.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="NetworkInfo.cpp" />
<ClCompile Include="Nextion.cpp" />
<ClCompile Include="NullDisplay.cpp" />
<ClCompile Include="NullModem.cpp" />
<ClCompile Include="NXDNAudio.cpp" />
<ClCompile Include="NXDNControl.cpp" />
<ClCompile Include="NXDNConvolution.cpp" />
<ClCompile Include="NXDNCRC.cpp" />
<ClCompile Include="NXDNFACCH1.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="QR1676.cpp" />
<ClCompile Include="RemoteControl.cpp" />
<ClCompile Include="RS129.cpp" />
<ClCompile Include="RS241213.cpp" />
<ClCompile Include="RSSIInterpolator.cpp" />
<ClCompile Include="SerialController.cpp" />
<ClCompile Include="SerialPort.cpp" />
<ClCompile Include="SHA256.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Sync.cpp" />
<ClCompile Include="TFTSerial.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPSocket.cpp" />
<ClCompile Include="UMP.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>

554
MMDVMHost.vcxproj.filters Normal file
View file

@ -0,0 +1,554 @@
<?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="JitterBuffer.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="Modem.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="SerialController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SHA256.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StopWatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TFTSerial.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="UMP.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="I2CController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MobileGPS.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NullModem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRTA.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CASTInfo.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="JitterBuffer.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="Modem.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="SerialController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SHA256.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StopWatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TFTSerial.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="UMP.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="I2CController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MobileGPS.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NullModem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRTA.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CASTInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -2,18 +2,18 @@
CC = cc CC = cc
CXX = c++ CXX = c++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -I/usr/local/include CFLAGS = -g -O3 -Wall -std=c++0x -pthread
LIBS = -lpthread -lutil LIBS = -lpthread
LDFLAGS = -g -L/usr/local/lib LDFLAGS = -g
OBJECTS = \ 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 BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.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 \
DMRAccessControl.o DMRTA.o DMRTrellis.o Golay2087.o Golay24128.o\ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o \ NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o \
Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.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 \
RemoteControl.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o \ POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \
Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand all: MMDVMHost RemoteCommand
@ -26,33 +26,6 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o
%.o: %.cpp %.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $< $(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: clean:
$(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h

View file

@ -1,19 +1,19 @@
# This makefile is for use with the Raspberry Pi. The wiringpi library is needed. # This makefile is for use with the Raspberry Pi. The wiringpi library is needed.
CC = cc CC = gcc
CXX = c++ CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DRASPBERRY_PI -I/usr/local/include CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include
LIBS = -lwiringPi -lwiringPiDev -lpthread -lutil LIBS = -lwiringPi -lwiringPiDev -lpthread
LDFLAGS = -g -L/usr/local/lib LDFLAGS = -g -L/usr/local/lib
OBJECTS = \ 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 BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.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 \
DMRAccessControl.o DMRTA.o DMRTrellis.o Golay2087.o Golay24128.o\ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o \ NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \
Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \ NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.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 \ POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o \
Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand all: MMDVMHost RemoteCommand
@ -26,33 +26,6 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o
%.o: %.cpp %.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $< $(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: clean:
$(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h

39
Makefile.Pi.Adafruit Normal file
View file

@ -0,0 +1,39 @@
# 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 = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include
LIBS = -lwiringPi -lwiringPiDev -lpthread
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 DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.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 $@ $<
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

38
Makefile.Pi.HD44780 Normal file
View file

@ -0,0 +1,38 @@
# This makefile is for use with the Raspberry Pi when using an HD44780 compatible display. The wiringpi library is needed.
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -I/usr/local/include
LIBS = -lwiringPi -lwiringPiDev -lpthread
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 DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.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 $@ $<
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

38
Makefile.Pi.OLED Normal file
View file

@ -0,0 +1,38 @@
# This makefile is for use with the Raspberry Pi when using an OLED display. The wiringpi library is needed.
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include
LIBS = -lArduiPi_OLED -lwiringPi -lpthread
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 DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o JitterBuffer.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.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 $@ $<
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

39
Makefile.Pi.PCF8574 Normal file
View file

@ -0,0 +1,39 @@
# 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 = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include
LIBS = -lwiringPi -lwiringPiDev -lpthread
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 DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.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 $@ $<
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

38
Makefile.Solaris Normal file
View file

@ -0,0 +1,38 @@
# This makefile is for Solaris using gcc
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread
LIBS = -lpthread -lsocket
LDFLAGS = -g
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \
NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.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 POCSAGControl.o POCSAGNetwork.o \
QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o \
UMP.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 $@ $<
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

101
MobileGPS.cpp Normal file
View file

@ -0,0 +1,101 @@
/*
* 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 "MobileGPS.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cmath>
CMobileGPS::CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network) :
m_idTimer(1000U, 60U),
m_address(),
m_port(port),
m_socket(),
m_network(network)
{
assert(!address.empty());
assert(port > 0U);
assert(network != NULL);
m_address = CUDPSocket::lookup(address);
}
CMobileGPS::~CMobileGPS()
{
}
bool CMobileGPS::open()
{
bool ret = m_socket.open();
if (!ret)
return false;
m_idTimer.start();
return true;
}
void CMobileGPS::clock(unsigned int ms)
{
m_idTimer.clock(ms);
if (m_idTimer.hasExpired()) {
pollGPS();
m_idTimer.start();
}
sendReport();
}
void CMobileGPS::close()
{
m_socket.close();
}
bool CMobileGPS::pollGPS()
{
return m_socket.write((unsigned char*)"MMDVMHost", 9U, m_address, m_port);
}
void CMobileGPS::sendReport()
{
// Grab GPS data if it's available
unsigned char buffer[200U];
in_addr address;
unsigned int port;
int ret = m_socket.read(buffer, 200U, address, port);
if (ret <= 0)
return;
buffer[ret] = '\0';
// Parse the GPS data
char* pLatitude = ::strtok((char*)buffer, ",\n"); // Latitude
char* pLongitude = ::strtok(NULL, ",\n"); // Longitude
if (pLatitude == NULL || pLongitude == NULL)
return;
float latitude = float(::atof(pLatitude));
float longitude = float(::atof(pLongitude));
m_network->writeHomePosition(latitude, longitude);
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2020 by SASANO Takayoshi JG1UAA * Copyright (C) 2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,35 +16,48 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if !defined(USERDBENTRY_H) #ifndef MobileGPS_H
#define USERDBENTRY_H #define MobileGPS_H
#include "DMRNetwork.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <string> #include <string>
#include <unordered_map>
#include <vector>
#define keyRADIO_ID "RADIO_ID" #if !defined(_WIN32) && !defined(_WIN64)
#define keyCALLSIGN "CALLSIGN" #include <netdb.h>
#define keyFIRST_NAME "FIRST_NAME" #include <sys/time.h>
#define keyLAST_NAME "LAST_NAME" #include <sys/types.h>
#define keyCITY "CITY" #include <sys/socket.h>
#define keySTATE "STATE" #include <unistd.h>
#define keyCOUNTRY "COUNTRY" #include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <winsock.h>
#endif
class CUserDBentry { class CMobileGPS {
public: public:
CUserDBentry(); CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network);
~CUserDBentry(); ~CMobileGPS();
static const std::vector<std::string> keyList; bool open();
static bool isValidKey(const std::string key);
void set(const std::string key, const std::string value); void clock(unsigned int ms);
const std::string get(const std::string key) const;
void clear(void); void close();
private: private:
std::unordered_map<std::string, std::string> m_db; CTimer m_idTimer;
in_addr m_address;
unsigned int m_port;
CUDPSocket m_socket;
CDMRNetwork* m_network;
bool pollGPS();
void sendReport();
}; };
#endif #endif

1248
Modem.cpp

File diff suppressed because it is too large Load diff

184
Modem.h
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011-2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2011-2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,10 +16,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#ifndef Modem_H #ifndef MODEM_H
#define Modem_H #define MODEM_H
#include "ModemPort.h" #include "SerialController.h"
#include "RingBuffer.h" #include "RingBuffer.h"
#include "Defines.h" #include "Defines.h"
#include "Timer.h" #include "Timer.h"
@ -32,107 +32,86 @@ enum RESP_TYPE_MMDVM {
RTM_ERROR RTM_ERROR
}; };
enum SERIAL_STATE {
SS_START,
SS_LENGTH1,
SS_LENGTH2,
SS_TYPE,
SS_DATA
};
class CModem { class CModem {
public: public:
CModem(bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool useCOSAsLockout, bool trace, bool debug); CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug);
~CModem(); virtual ~CModem();
void setPort(IModemPort* port); virtual void setSerialParams(const std::string& protocol, unsigned int address);
void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel); virtual 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); virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled);
void setLevels(float rxLevel, float cwIdTXLevel, float dmrTXLevel); virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel);
void setDMRParams(unsigned int colorCode); virtual void setDMRParams(unsigned int colorCode);
void setYSFParams(bool loDev, unsigned int txHang); virtual void setYSFParams(bool loDev, unsigned int txHang);
void setP25Params(unsigned int txHang); virtual void setTransparentDataParams(unsigned int sendFrameType);
void setNXDNParams(unsigned int txHang);
void setM17Params(unsigned int txHang);
void setAX25Params(int rxTwist, unsigned int txDelay, unsigned int slotTime, unsigned int pPersist);
void setTransparentDataParams(unsigned int sendFrameType);
void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); virtual bool open();
void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel);
void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, unsigned int accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, unsigned int squelchHighThreshold, unsigned int squelchLowThreshold, unsigned int rfAudioBoost, float maxDevLevel);
void setFMExtParams(const std::string& ack, unsigned int audioBoost);
bool open(); virtual unsigned int readDStarData(unsigned char* data);
virtual unsigned int readDMRData1(unsigned char* data);
virtual unsigned int readDMRData2(unsigned char* data);
virtual unsigned int readYSFData(unsigned char* data);
virtual unsigned int readP25Data(unsigned char* data);
virtual unsigned int readNXDNData(unsigned char* data);
virtual unsigned int readTransparentData(unsigned char* data);
bool hasDStar() const; virtual unsigned int readSerial(unsigned char* data, unsigned int length);
bool hasDMR() const;
bool hasYSF() const;
bool hasP25() const;
bool hasNXDN() const;
bool hasM17() const;
bool hasPOCSAG() const;
bool hasFM() const;
bool hasAX25() const;
unsigned int getVersion() const; virtual bool hasDStarSpace() const;
virtual bool hasDMRSpace1() const;
virtual bool hasDMRSpace2() const;
virtual bool hasYSFSpace() const;
virtual bool hasP25Space() const;
virtual bool hasNXDNSpace() const;
virtual bool hasPOCSAGSpace() const;
unsigned int readDStarData(unsigned char* data); virtual bool hasTX() const;
unsigned int readDMRData1(unsigned char* data); virtual bool hasCD() const;
unsigned int readDMRData2(unsigned char* data);
unsigned int readYSFData(unsigned char* data);
unsigned int readP25Data(unsigned char* data);
unsigned int readNXDNData(unsigned char* data);
unsigned int readM17Data(unsigned char* data);
unsigned int readFMData(unsigned char* data);
unsigned int readAX25Data(unsigned char* data);
bool hasDStarSpace() const; virtual bool hasLockout() const;
bool hasDMRSpace1() const; virtual bool hasError() const;
bool hasDMRSpace2() const;
bool hasYSFSpace() const;
bool hasP25Space() const;
bool hasNXDNSpace() const;
bool hasM17Space() const;
bool hasPOCSAGSpace() const;
unsigned int getFMSpace() const;
bool hasAX25Space() const;
bool hasTX() const; virtual bool writeDStarData(const unsigned char* data, unsigned int length);
bool hasCD() const; virtual bool writeDMRData1(const unsigned char* data, unsigned int length);
virtual bool writeDMRData2(const unsigned char* data, unsigned int length);
virtual bool writeYSFData(const unsigned char* data, unsigned int length);
virtual bool writeP25Data(const unsigned char* data, unsigned int length);
virtual bool writeNXDNData(const unsigned char* data, unsigned int length);
virtual bool writePOCSAGData(const unsigned char* data, unsigned int length);
bool hasLockout() const; virtual bool writeTransparentData(const unsigned char* data, unsigned int length);
bool hasError() const;
bool writeConfig(); virtual bool writeDStarInfo(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
bool writeDMRData1(const unsigned char* data, unsigned int length); virtual bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
bool writeDMRData2(const unsigned char* data, unsigned int length); virtual bool writeYSFInfo(const char* source, const char* dest, const char* type, const char* origin);
bool writeDMRInfo(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type); virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type);
bool writeIPInfo(const std::string& address); virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type);
virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message);
virtual bool writeIPInfo(const std::string& address);
bool writeDMRStart(bool tx); virtual bool writeDMRStart(bool tx);
bool writeDMRShortLC(const unsigned char* lc); virtual bool writeDMRShortLC(const unsigned char* lc);
bool writeDMRAbort(unsigned int slotNo); virtual bool writeDMRAbort(unsigned int slotNo);
bool writeTransparentData(const unsigned char* data, unsigned int length); virtual bool writeSerial(const unsigned char* data, unsigned int length);
unsigned int readTransparentData(unsigned char* data);
bool writeSerial(const unsigned char* data, unsigned int length); virtual bool setMode(unsigned char mode);
unsigned int readSerial(unsigned char* data, unsigned int length);
unsigned char getMode() const; virtual bool sendCWId(const std::string& callsign);
bool setMode(unsigned char mode);
bool sendCWId(const std::string& callsign); virtual HW_TYPE getHWType() const;
HW_TYPE getHWType() const; virtual void clock(unsigned int ms);
void clock(unsigned int ms); virtual void close();
void close(); static CModem* createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug);
private: private:
unsigned int m_protocolVersion; std::string m_port;
unsigned int m_dmrColorCode; unsigned int m_dmrColorCode;
bool m_ysfLoDev;
unsigned int m_ysfTXHang;
bool m_duplex; bool m_duplex;
bool m_rxInvert; bool m_rxInvert;
bool m_txInvert; bool m_txInvert;
@ -141,55 +120,66 @@ private:
unsigned int m_dmrDelay; unsigned int m_dmrDelay;
float m_rxLevel; float m_rxLevel;
float m_cwIdTXLevel; float m_cwIdTXLevel;
float m_dstarTXLevel;
float m_dmrTXLevel; float m_dmrTXLevel;
float m_ysfTXLevel;
float m_p25TXLevel;
float m_nxdnTXLevel;
float m_pocsagTXLevel;
float m_rfLevel; float m_rfLevel;
bool m_useCOSAsLockout;
bool m_trace; bool m_trace;
bool m_debug; bool m_debug;
unsigned int m_rxFrequency; unsigned int m_rxFrequency;
unsigned int m_txFrequency; unsigned int m_txFrequency;
unsigned int m_pocsagFrequency;
bool m_dstarEnabled; bool m_dstarEnabled;
bool m_dmrEnabled; bool m_dmrEnabled;
bool m_ysfEnabled;
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_pocsagEnabled;
int m_rxDCOffset; int m_rxDCOffset;
int m_txDCOffset; int m_txDCOffset;
IModemPort* m_port; CSerialController* m_serial;
unsigned char* m_buffer; unsigned char* m_buffer;
unsigned int m_length; unsigned int m_length;
unsigned int m_offset; unsigned int m_offset;
SERIAL_STATE m_state; CRingBuffer<unsigned char> m_rxDStarData;
unsigned char m_type; CRingBuffer<unsigned char> m_txDStarData;
CRingBuffer<unsigned char> m_rxDMRData1; CRingBuffer<unsigned char> m_rxDMRData1;
CRingBuffer<unsigned char> m_rxDMRData2; CRingBuffer<unsigned char> m_rxDMRData2;
CRingBuffer<unsigned char> m_txDMRData1; CRingBuffer<unsigned char> m_txDMRData1;
CRingBuffer<unsigned char> m_txDMRData2; CRingBuffer<unsigned char> m_txDMRData2;
CRingBuffer<unsigned char> m_rxSerialData; CRingBuffer<unsigned char> m_rxYSFData;
CRingBuffer<unsigned char> m_txSerialData; 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_txPOCSAGData;
CRingBuffer<unsigned char> m_rxTransparentData; CRingBuffer<unsigned char> m_rxTransparentData;
CRingBuffer<unsigned char> m_txTransparentData; CRingBuffer<unsigned char> m_txTransparentData;
unsigned int m_sendTransparentDataFrameType; unsigned int m_sendTransparentDataFrameType;
CTimer m_statusTimer; CTimer m_statusTimer;
CTimer m_inactivityTimer; CTimer m_inactivityTimer;
CTimer m_playoutTimer; CTimer m_playoutTimer;
unsigned int m_dstarSpace;
unsigned int m_dmrSpace1; unsigned int m_dmrSpace1;
unsigned int m_dmrSpace2; unsigned int m_dmrSpace2;
unsigned int m_ysfSpace;
unsigned int m_p25Space;
unsigned int m_nxdnSpace;
unsigned int m_pocsagSpace;
bool m_tx; bool m_tx;
bool m_cd; bool m_cd;
bool m_lockout; bool m_lockout;
bool m_error; bool m_error;
unsigned char m_mode;
HW_TYPE m_hwType; HW_TYPE m_hwType;
unsigned char m_capabilities1;
unsigned char m_capabilities2;
bool readVersion(); bool readVersion();
bool readStatus(); bool readStatus();
bool setConfig1(); bool setConfig();
bool setConfig2();
bool setFrequency(); bool setFrequency();
bool setFMCallsignParams();
bool setFMAckParams();
bool setFMMiscParams();
bool setFMExtParams();
void printDebug(); void printDebug();

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,22 +21,22 @@
#include <cstdio> #include <cstdio>
#include <cassert> #include <cassert>
IModemSerialPort::IModemSerialPort(CModem* modem) : CModemSerialPort::CModemSerialPort(CModem* modem) :
m_modem(modem) m_modem(modem)
{ {
assert(modem != NULL); assert(modem != NULL);
} }
IModemSerialPort::~IModemSerialPort() CModemSerialPort::~CModemSerialPort()
{ {
} }
bool IModemSerialPort::open() bool CModemSerialPort::open()
{ {
return true; return true;
} }
int IModemSerialPort::write(const unsigned char* data, unsigned int length) int CModemSerialPort::write(const unsigned char* data, unsigned int length)
{ {
assert(data != NULL); assert(data != NULL);
assert(length > 0U); assert(length > 0U);
@ -46,7 +46,7 @@ int IModemSerialPort::write(const unsigned char* data, unsigned int length)
return ret ? int(length) : -1; return ret ? int(length) : -1;
} }
int IModemSerialPort::read(unsigned char* data, unsigned int length) int CModemSerialPort::read(unsigned char* data, unsigned int length)
{ {
assert(data != NULL); assert(data != NULL);
assert(length > 0U); assert(length > 0U);
@ -54,6 +54,6 @@ int IModemSerialPort::read(unsigned char* data, unsigned int length)
return m_modem->readSerial(data, length); return m_modem->readSerial(data, length);
} }
void IModemSerialPort::close() void CModemSerialPort::close()
{ {
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,10 +22,10 @@
#include "SerialPort.h" #include "SerialPort.h"
#include "Modem.h" #include "Modem.h"
class IModemSerialPort : public ISerialPort { class CModemSerialPort : public ISerialPort {
public: public:
IModemSerialPort(CModem* modem); CModemSerialPort(CModem* modem);
virtual ~IModemSerialPort(); virtual ~CModemSerialPort();
virtual bool open(); virtual bool open();

1628
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);
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2021 by Jonathan Naylor G4KLX * Copyright (C) 2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,8 +16,22 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "ModemPort.h" #if !defined(NXDNAudio_H)
#define NXDNAudio_H
IModemPort::~IModemPort() 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

1137
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-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(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, CNXDNNetwork* 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;
CNXDNNetwork* 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

142
NXDNConvolution.cpp Normal file
View file

@ -0,0 +1,142 @@
/*
* Copyright (C) 2009-2016,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 "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[16U];
m_metrics2 = new uint16_t[16U];
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;
}
void 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);
}
}
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++;
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2021 by Geoffrey Merck F4FXL / KC3FRA
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,21 +16,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "SMeter.h" #if !defined(NXDNConvolution_H)
#define NXDNConvolution_H
const unsigned int RSSI_S1 = 141U; #include <cstdint>
const unsigned int RSSI_S9 = 93U;
class CNXDNConvolution {
public:
CNXDNConvolution();
~CNXDNConvolution();
void start();
void decode(uint8_t s0, uint8_t s1);
void 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
void CSMeter::getSignal(unsigned int rssi, unsigned int& signal, unsigned int& plus)
{
if (rssi > RSSI_S1) {
signal = 0U;
plus = rssi - RSSI_S1;
} else if (rssi > RSSI_S9 && rssi <= RSSI_S1) {
signal = ((RSSI_S1 - rssi) / 6U) + 1U;
plus = (RSSI_S1 - rssi) % 6U;
} else {
signal = 9U;
plus = RSSI_S9 - rssi;
}
}

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

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;
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2020 by SASANO Takayoshi JG1UAA * Copyright (C) 2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,28 +16,37 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if !defined(USERDB_H) #if !defined(NXDNLICH_H)
#define USERDB_H #define NXDNLICH_H
#include "UserDBentry.h" class CNXDNLICH {
#include "Mutex.h"
class CUserDB {
public: public:
CUserDB(); CNXDNLICH(const CNXDNLICH& lich);
~CUserDB(); CNXDNLICH();
~CNXDNLICH();
bool lookup(unsigned int id, class CUserDBentry *entry); bool decode(const unsigned char* bytes);
bool load(std::string const& filename);
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: private:
bool makeindex(char* buf, std::unordered_map<std::string, int>& index); unsigned char* m_lich;
void parse(char* buf, std::unordered_map<std::string, int>& index);
void toupper_string(char* str);
char* tokenize(char* str, char** next);
std::unordered_map<unsigned int, class CUserDBentry> m_table; bool getParity() const;
CMutex m_mutex;
}; };
#endif #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

160
NXDNLookup.cpp Normal file
View file

@ -0,0 +1,160 @@
/*
* 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.
*/
#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_mutex(),
m_stop(false)
{
}
CNXDNLookup::~CNXDNLookup()
{
}
bool CNXDNLookup::read()
{
bool ret = load();
if (m_reloadTime > 0U)
run();
return ret;
}
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()) {
load();
timer.start();
}
}
LogInfo("Stopped the NXDN Id lookup reload thread");
}
void CNXDNLookup::stop()
{
if (m_reloadTime == 0U) {
delete this;
return;
}
m_stop = true;
wait();
}
std::string CNXDNLookup::find(unsigned int id)
{
std::string callsign;
if (id == 0xFFFFU)
return std::string("ALL");
m_mutex.lock();
try {
callsign = m_table.at(id);
} catch (...) {
char text[10U];
::sprintf(text, "%u", id);
callsign = std::string(text);
}
m_mutex.unlock();
return callsign;
}
bool CNXDNLookup::exists(unsigned int id)
{
m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
}
bool CNXDNLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogWarning("Cannot open the NXDN Id lookup file - %s", m_filename.c_str());
return false;
}
m_mutex.lock();
// Remove the old entries
m_table.clear();
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, ",\t\r\n");
char* p2 = ::strtok(NULL, ",\t\r\n");
if (p1 != NULL && p2 != NULL) {
unsigned int id = (unsigned int)::atoi(p1);
if (id > 0U) {
for (char* p = p2; *p != 0x00U; p++)
*p = ::toupper(*p);
m_table[id] = std::string(p2);
}
}
}
m_mutex.unlock();
::fclose(fp);
size_t size = m_table.size();
if (size == 0U)
return false;
LogInfo("Loaded %u Ids to the NXDN callsign lookup table", size);
return true;
}

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 "Mutex.h"
#include <string>
#include <unordered_map>
class CNXDNLookup : public CThread {
public:
CNXDNLookup(const std::string& filename, unsigned int reloadTime);
virtual ~CNXDNLookup();
bool read();
virtual void entry();
std::string find(unsigned int id);
bool exists(unsigned int id);
void stop();
private:
std::string m_filename;
unsigned int m_reloadTime;
std::unordered_map<unsigned int, std::string> m_table;
CMutex m_mutex;
bool m_stop;
bool load();
};
#endif

169
NXDNNetwork.cpp Normal file
View file

@ -0,0 +1,169 @@
/*
* Copyright (C) 2009-2014,2016,2018,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.
*/
#include "NXDNDefines.h"
#include "NXDNNetwork.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
CNXDNNetwork::CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) :
m_socket(localAddress, localPort),
m_address(),
m_port(gatewayPort),
m_debug(debug),
m_enabled(false),
m_buffer(1000U, "NXDN Network")
{
assert(gatewayPort > 0U);
assert(!gatewayAddress.empty());
m_address = CUDPSocket::lookup(gatewayAddress);
}
CNXDNNetwork::~CNXDNNetwork()
{
}
bool CNXDNNetwork::open()
{
LogMessage("Opening NXDN network connection");
if (m_address.s_addr == INADDR_NONE)
return false;
return m_socket.open();
}
bool CNXDNNetwork::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_address, m_port);
}
void CNXDNNetwork::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || port != m_port) {
LogMessage("NXDN packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Invalid packet type?
if (::memcmp(buffer, "ICOM", 4U) != 0)
return;
if (length != 102)
return;
if (!m_enabled)
return;
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Received", buffer, length);
m_buffer.addData(buffer + 40U, 33U);
}
bool CNXDNNetwork::read(unsigned char* data)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return false;
m_buffer.getData(data, 33U);
return true;
}
void CNXDNNetwork::reset()
{
}
void CNXDNNetwork::close()
{
m_socket.close();
LogMessage("Closing NXDN network connection");
}
void CNXDNNetwork::enable(bool enabled)
{
if (enabled && !m_enabled)
reset();
else if (!enabled && m_enabled)
m_buffer.clear();
m_enabled = enabled;
}

67
NXDNNetwork.h Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (C) 2009-2014,2016,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 NXDNNetwork_H
#define NXDNNetwork_H
#include "NXDNDefines.h"
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
enum NXDN_NETWORK_MESSAGE_TYPE {
NNMT_VOICE_HEADER,
NNMT_VOICE_BODY,
NNMT_VOICE_TRAILER,
NNMT_DATA_HEADER,
NNMT_DATA_BODY,
NNMT_DATA_TRAILER
};
class CNXDNNetwork {
public:
CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug);
~CNXDNNetwork();
bool open();
void enable(bool enabled);
bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type);
bool read(unsigned char* data);
void reset();
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
bool m_debug;
bool m_enabled;
CRingBuffer<unsigned char> m_buffer;
};
#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

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