nitial commit of POCSAG files.

This commit is contained in:
Jonathan Naylor 2018-06-07 18:46:03 +01:00
parent 86630e230e
commit 2a0364a6d4
23 changed files with 808 additions and 108 deletions

View File

@ -43,11 +43,13 @@ enum SECTION {
SECTION_FUSION,
SECTION_P25,
SECTION_NXDN,
SECTION_POCSAG,
SECTION_DSTAR_NETWORK,
SECTION_DMR_NETWORK,
SECTION_FUSION_NETWORK,
SECTION_P25_NETWORK,
SECTION_NXDN_NETWORK,
SECTION_POCSAG_NETWORK,
SECTION_TFTSERIAL,
SECTION_HD44780,
SECTION_NEXTION,
@ -102,6 +104,7 @@ m_modemDMRTXLevel(50.0F),
m_modemYSFTXLevel(50.0F),
m_modemP25TXLevel(50.0F),
m_modemNXDNTXLevel(50.0F),
m_modemPOCSAGTXLevel(50.0F),
m_modemRSSIMappingFile(),
m_modemTrace(false),
m_modemDebug(false),
@ -158,6 +161,7 @@ m_nxdnRAN(1U),
m_nxdnSelfOnly(false),
m_nxdnRemoteGateway(false),
m_nxdnModeHang(10U),
m_pocsagEnabled(false),
m_dstarNetworkEnabled(false),
m_dstarGatewayAddress(),
m_dstarGatewayPort(0U),
@ -195,6 +199,13 @@ m_nxdnLocalAddress(),
m_nxdnLocalPort(0U),
m_nxdnNetworkModeHang(3U),
m_nxdnNetworkDebug(false),
m_pocsagNetworkEnabled(false),
m_pocsagGatewayAddress(),
m_pocsagGatewayPort(0U),
m_pocsagLocalAddress(),
m_pocsagLocalPort(0U),
m_pocsagNetworkModeHang(3U),
m_pocsagNetworkDebug(false),
m_tftSerialPort("/dev/ttyAMA0"),
m_tftSerialBrightness(50U),
m_hd44780Rows(2U),
@ -273,6 +284,8 @@ bool CConf::read()
section = SECTION_P25;
else if (::strncmp(buffer, "[NXDN]", 6U) == 0)
section = SECTION_NXDN;
else if (::strncmp(buffer, "[POCSAG]", 8U) == 0)
section = SECTION_POCSAG;
else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0)
section = SECTION_DSTAR_NETWORK;
else if (::strncmp(buffer, "[DMR Network]", 13U) == 0)
@ -283,6 +296,8 @@ bool CConf::read()
section = SECTION_P25_NETWORK;
else if (::strncmp(buffer, "[NXDN Network]", 14U) == 0)
section = SECTION_NXDN_NETWORK;
else if (::strncmp(buffer, "[POCSAG Network]", 16U) == 0)
section = SECTION_POCSAG_NETWORK;
else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0)
section = SECTION_TFTSERIAL;
else if (::strncmp(buffer, "[HD44780]", 9U) == 0)
@ -425,6 +440,8 @@ bool CConf::read()
m_modemP25TXLevel = float(::atof(value));
else if (::strcmp(key, "NXDNTXLevel") == 0)
m_modemNXDNTXLevel = float(::atof(value));
else if (::strcmp(key, "POCSAGTXLevel") == 0)
m_modemPOCSAGTXLevel = float(::atof(value));
else if (::strcmp(key, "RSSIMappingFile") == 0)
m_modemRSSIMappingFile = value;
else if (::strcmp(key, "Trace") == 0)
@ -586,6 +603,9 @@ bool CConf::read()
m_nxdnRemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
m_nxdnModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_POCSAG) {
if (::strcmp(key, "Enable") == 0)
m_pocsagEnabled = ::atoi(value) == 1;
} else if (section == SECTION_DSTAR_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_dstarNetworkEnabled = ::atoi(value) == 1;
@ -665,6 +685,21 @@ bool CConf::read()
m_nxdnNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_nxdnNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_POCSAG_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_pocsagNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "LocalAddress") == 0)
m_pocsagLocalAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_pocsagLocalPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "GatewayAddress") == 0)
m_pocsagGatewayAddress = value;
else if (::strcmp(key, "GatewayPort") == 0)
m_pocsagGatewayPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_pocsagNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_pocsagNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_TFTSERIAL) {
if (::strcmp(key, "Port") == 0)
m_tftSerialPort = value;
@ -960,6 +995,11 @@ float CConf::getModemNXDNTXLevel() const
return m_modemNXDNTXLevel;
}
float CConf::getModemPOCSAGTXLevel() const
{
return m_modemPOCSAGTXLevel;
}
std::string CConf::getModemRSSIMappingFile () const
{
return m_modemRSSIMappingFile;
@ -1240,6 +1280,11 @@ unsigned int CConf::getNXDNModeHang() const
return m_nxdnModeHang;
}
bool CConf::getPOCSAGEnabled() const
{
return m_pocsagEnabled;
}
bool CConf::getDStarNetworkEnabled() const
{
return m_dstarNetworkEnabled;
@ -1425,6 +1470,41 @@ bool CConf::getNXDNNetworkDebug() const
return m_nxdnNetworkDebug;
}
bool CConf::getPOCSAGNetworkEnabled() const
{
return m_pocsagNetworkEnabled;
}
std::string CConf::getPOCSAGGatewayAddress() const
{
return m_pocsagGatewayAddress;
}
unsigned int CConf::getPOCSAGGatewayPort() const
{
return m_pocsagGatewayPort;
}
std::string CConf::getPOCSAGLocalAddress() const
{
return m_pocsagLocalAddress;
}
unsigned int CConf::getPOCSAGLocalPort() const
{
return m_pocsagLocalPort;
}
unsigned int CConf::getPOCSAGNetworkModeHang() const
{
return m_pocsagNetworkModeHang;
}
bool CConf::getPOCSAGNetworkDebug() const
{
return m_pocsagNetworkDebug;
}
std::string CConf::getTFTSerialPort() const
{
return m_tftSerialPort;

24
Conf.h
View File

@ -87,6 +87,7 @@ public:
float getModemYSFTXLevel() const;
float getModemP25TXLevel() const;
float getModemNXDNTXLevel() const;
float getModemPOCSAGTXLevel() const;
std::string getModemRSSIMappingFile() const;
bool getModemTrace() const;
bool getModemDebug() const;
@ -158,6 +159,9 @@ public:
bool getNXDNRemoteGateway() const;
unsigned int getNXDNModeHang() const;
// The POCSAG section
bool getPOCSAGEnabled() const;
// The D-Star Network section
bool getDStarNetworkEnabled() const;
std::string getDStarGatewayAddress() const;
@ -205,6 +209,15 @@ public:
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
std::string getTFTSerialPort() const;
unsigned int getTFTSerialBrightness() const;
@ -295,6 +308,7 @@ private:
float m_modemYSFTXLevel;
float m_modemP25TXLevel;
float m_modemNXDNTXLevel;
float m_modemPOCSAGTXLevel;
std::string m_modemRSSIMappingFile;
bool m_modemTrace;
bool m_modemDebug;
@ -359,6 +373,8 @@ private:
bool m_nxdnRemoteGateway;
unsigned int m_nxdnModeHang;
bool m_pocsagEnabled;
bool m_dstarNetworkEnabled;
std::string m_dstarGatewayAddress;
unsigned int m_dstarGatewayPort;
@ -401,6 +417,14 @@ private:
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;
unsigned int m_tftSerialBrightness;

View File

@ -25,6 +25,7 @@ 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_LOCKOUT = 99U;
const unsigned char MODE_ERROR = 100U;

View File

@ -62,6 +62,7 @@ RFLevel=100
# YSFTXLevel=50
# P25TXLevel=50
# NXDNTXLevel=50
# POCSAGTXLevel=50
RSSIMappingFile=RSSI.dat
Trace=0
Debug=0
@ -127,6 +128,9 @@ SelfOnly=0
RemoteGateway=0
# ModeHang=10
[POCSAG]
Enable=1
[D-Star Network]
Enable=1
GatewayAddress=127.0.0.1
@ -174,6 +178,15 @@ 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
Debug=0
[TFT Serial]
# Port=modem
Port=/dev/ttyAMA0

View File

@ -30,6 +30,7 @@
#include "YSFControl.h"
#include "P25Control.h"
#include "NXDNControl.h"
#include "POCSAGControl.h"
#include "Nextion.h"
#include "LCDproc.h"
#include "Thread.h"
@ -134,6 +135,7 @@ m_dmrNetwork(NULL),
m_ysfNetwork(NULL),
m_p25Network(NULL),
m_nxdnNetwork(NULL),
m_pocsagNetwork(NULL),
m_display(NULL),
m_ump(NULL),
m_mode(MODE_IDLE),
@ -147,6 +149,7 @@ m_dmrNetModeHang(3U),
m_ysfNetModeHang(3U),
m_p25NetModeHang(3U),
m_nxdnNetModeHang(3U),
m_pocsagNetModeHang(3U),
m_modeTimer(1000U),
m_dmrTXTimer(1000U),
m_cwIdTimer(1000U),
@ -157,6 +160,7 @@ m_dmrEnabled(false),
m_ysfEnabled(false),
m_p25Enabled(false),
m_nxdnEnabled(false),
m_pocsagEnabled(false),
m_cwIdTime(0U),
m_dmrLookup(NULL),
m_nxdnLookup(NULL),
@ -308,6 +312,12 @@ int CMMDVMHost::run()
return 1;
}
if (m_pocsagEnabled && m_conf.getPOCSAGNetworkEnabled()) {
ret = createPOCSAGNetwork();
if (!ret)
return 1;
}
in_addr transparentAddress;
unsigned int transparentPort = 0U;
CUDPSocket* transparentSocket = NULL;
@ -545,6 +555,10 @@ int CMMDVMHost::run()
nxdn = new CNXDNControl(ran, id, selfOnly, m_nxdnNetwork, m_display, m_timeout, m_duplex, remoteGateway, m_nxdnLookup, rssi);
}
CPOCSAGControl* pocsag = NULL;
if (m_pocsagEnabled)
pocsag = new CPOCSAGControl(m_pocsagNetwork, m_display);
setMode(MODE_IDLE);
LogMessage("MMDVMHost-%s is running", VERSION);
@ -843,6 +857,25 @@ int CMMDVMHost::run()
}
}
if (pocsag != NULL) {
ret = m_modem->hasPOCSAGSpace();
if (ret) {
len = pocsag->readModem(data);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_pocsagNetModeHang);
setMode(MODE_POCSAG);
}
if (m_mode == MODE_POCSAG) {
m_modem->writePOCSAGData(data, len);
m_modeTimer.start();
} else if (m_mode != MODE_LOCKOUT) {
LogWarning("POCSAG data received when in mode %u", m_mode);
}
}
}
}
if (transparentSocket != NULL) {
in_addr address;
unsigned int port = 0U;
@ -869,6 +902,8 @@ int CMMDVMHost::run()
p25->clock(ms);
if (nxdn != NULL)
nxdn->clock(ms);
if (pocsag != NULL)
pocsag->clock(ms);
if (m_dstarNetwork != NULL)
m_dstarNetwork->clock(ms);
@ -880,6 +915,8 @@ int CMMDVMHost::run()
m_p25Network->clock(ms);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->clock(ms);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->clock(ms);
m_cwIdTimer.clock(ms);
if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) {
@ -965,6 +1002,11 @@ int CMMDVMHost::run()
delete m_nxdnNetwork;
}
if (m_pocsagNetwork != NULL) {
m_pocsagNetwork->close();
delete m_pocsagNetwork;
}
if (transparentSocket != NULL) {
transparentSocket->close();
delete transparentSocket;
@ -975,6 +1017,7 @@ int CMMDVMHost::run()
delete ysf;
delete p25;
delete nxdn;
delete pocsag;
return 0;
}
@ -994,6 +1037,7 @@ bool CMMDVMHost::createModem()
float ysfTXLevel = m_conf.getModemYSFTXLevel();
float p25TXLevel = m_conf.getModemP25TXLevel();
float nxdnTXLevel = m_conf.getModemNXDNTXLevel();
float pocsagTXLevel = m_conf.getModemPOCSAGTXLevel();
bool trace = m_conf.getModemTrace();
bool debug = m_conf.getModemDebug();
unsigned int colorCode = m_conf.getDMRColorCode();
@ -1026,12 +1070,13 @@ bool CMMDVMHost::createModem()
LogInfo(" YSF TX Level: %.1f%%", ysfTXLevel);
LogInfo(" P25 TX Level: %.1f%%", p25TXLevel);
LogInfo(" NXDN TX Level: %.1f%%", nxdnTXLevel);
LogInfo(" POCSAG TX Level: %.1f%%", pocsagTXLevel);
LogInfo(" RX Frequency: %uHz (%uHz)", rxFrequency, rxFrequency + rxOffset);
LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset);
m_modem = new CModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel);
m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel);
m_modem->setDMRParams(colorCode);
m_modem->setYSFParams(lowDeviation, txHang);
@ -1233,17 +1278,48 @@ bool CMMDVMHost::createNXDNNetwork()
return true;
}
bool CMMDVMHost::createPOCSAGNetwork()
{
std::string gatewayAddress = m_conf.getPOCSAGGatewayAddress();
unsigned int gatewayPort = m_conf.getPOCSAGGatewayPort();
std::string localAddress = m_conf.getPOCSAGLocalAddress();
unsigned int localPort = m_conf.getPOCSAGLocalPort();
m_pocsagNetModeHang = m_conf.getPOCSAGNetworkModeHang();
bool debug = m_conf.getPOCSAGNetworkDebug();
LogInfo("POCSAG Network Parameters");
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %u", gatewayPort);
LogInfo(" Local Address: %s", localAddress.c_str());
LogInfo(" Local Port: %u", localPort);
LogInfo(" Mode Hang: %us", m_pocsagNetModeHang);
m_pocsagNetwork = new CPOCSAGNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug);
bool ret = m_pocsagNetwork->open();
if (!ret) {
delete m_pocsagNetwork;
m_pocsagNetwork = NULL;
return false;
}
m_pocsagNetwork->enable(true);
return true;
}
void CMMDVMHost::readParams()
{
m_dstarEnabled = m_conf.getDStarEnabled();
m_dmrEnabled = m_conf.getDMREnabled();
m_ysfEnabled = m_conf.getFusionEnabled();
m_p25Enabled = m_conf.getP25Enabled();
m_nxdnEnabled = m_conf.getNXDNEnabled();
m_duplex = m_conf.getDuplex();
m_callsign = m_conf.getCallsign();
m_id = m_conf.getId();
m_timeout = m_conf.getTimeout();
m_dstarEnabled = m_conf.getDStarEnabled();
m_dmrEnabled = m_conf.getDMREnabled();
m_ysfEnabled = m_conf.getFusionEnabled();
m_p25Enabled = m_conf.getP25Enabled();
m_nxdnEnabled = m_conf.getNXDNEnabled();
m_pocsagEnabled = m_conf.getPOCSAGEnabled();
m_duplex = m_conf.getDuplex();
m_callsign = m_conf.getCallsign();
m_id = m_conf.getId();
m_timeout = m_conf.getTimeout();
LogInfo("General Parameters");
LogInfo(" Callsign: %s", m_callsign.c_str());
@ -1255,6 +1331,7 @@ void CMMDVMHost::readParams()
LogInfo(" YSF: %s", m_ysfEnabled ? "enabled" : "disabled");
LogInfo(" P25: %s", m_p25Enabled ? "enabled" : "disabled");
LogInfo(" NXDN: %s", m_nxdnEnabled ? "enabled" : "disabled");
LogInfo(" POCSAG: %s", m_pocsagEnabled ? "enabled" : "disabled");
}
void CMMDVMHost::createDisplay()
@ -1426,6 +1503,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
m_modem->setMode(MODE_DSTAR);
if (m_ump != NULL)
m_ump->setMode(MODE_DSTAR);
@ -1443,6 +1522,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
m_modem->setMode(MODE_DMR);
if (m_ump != NULL)
m_ump->setMode(MODE_DMR);
@ -1464,6 +1545,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
m_modem->setMode(MODE_YSF);
if (m_ump != NULL)
m_ump->setMode(MODE_YSF);
@ -1481,6 +1564,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_ysfNetwork->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
m_modem->setMode(MODE_P25);
if (m_ump != NULL)
m_ump->setMode(MODE_P25);
@ -1498,6 +1583,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_ysfNetwork->enable(false);
if (m_p25Network != NULL)
m_p25Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
m_modem->setMode(MODE_NXDN);
if (m_ump != NULL)
m_ump->setMode(MODE_NXDN);
@ -1506,6 +1593,25 @@ void CMMDVMHost::setMode(unsigned char mode)
m_cwIdTimer.stop();
break;
case MODE_POCSAG:
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(false);
if (m_dmrNetwork != NULL)
m_dmrNetwork->enable(false);
if (m_ysfNetwork != NULL)
m_ysfNetwork->enable(false);
if (m_p25Network != NULL)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
m_modem->setMode(MODE_POCSAG);
if (m_ump != NULL)
m_ump->setMode(MODE_POCSAG);
m_mode = MODE_POCSAG;
m_modeTimer.start();
m_cwIdTimer.stop();
break;
case MODE_LOCKOUT:
LogMessage("Mode set to Lockout");
if (m_dstarNetwork != NULL)
@ -1518,6 +1624,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false);
m_dmrTXTimer.stop();
@ -1543,6 +1651,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false);
m_dmrTXTimer.stop();
@ -1566,6 +1676,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(true);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(true);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(true);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false);
m_dmrTXTimer.stop();

View File

@ -19,6 +19,7 @@
#if !defined(MMDVMHOST_H)
#define MMDVMHOST_H
#include "POCSAGNetwork.h"
#include "DStarNetwork.h"
#include "NXDNNetwork.h"
#include "NXDNLookup.h"
@ -43,42 +44,45 @@ public:
int run();
private:
CConf m_conf;
CModem* m_modem;
CDStarNetwork* m_dstarNetwork;
CDMRNetwork* m_dmrNetwork;
CYSFNetwork* m_ysfNetwork;
CP25Network* m_p25Network;
CNXDNNetwork* m_nxdnNetwork;
CDisplay* m_display;
CUMP* m_ump;
unsigned char m_mode;
unsigned int m_dstarRFModeHang;
unsigned int m_dmrRFModeHang;
unsigned int m_ysfRFModeHang;
unsigned int m_p25RFModeHang;
unsigned int m_nxdnRFModeHang;
unsigned int m_dstarNetModeHang;
unsigned int m_dmrNetModeHang;
unsigned int m_ysfNetModeHang;
unsigned int m_p25NetModeHang;
unsigned int m_nxdnNetModeHang;
CTimer m_modeTimer;
CTimer m_dmrTXTimer;
CTimer m_cwIdTimer;
bool m_duplex;
unsigned int m_timeout;
bool m_dstarEnabled;
bool m_dmrEnabled;
bool m_ysfEnabled;
bool m_p25Enabled;
bool m_nxdnEnabled;
unsigned int m_cwIdTime;
CDMRLookup* m_dmrLookup;
CNXDNLookup* m_nxdnLookup;
std::string m_callsign;
unsigned int m_id;
std::string m_cwCallsign;
CConf m_conf;
CModem* m_modem;
CDStarNetwork* m_dstarNetwork;
CDMRNetwork* m_dmrNetwork;
CYSFNetwork* m_ysfNetwork;
CP25Network* m_p25Network;
CNXDNNetwork* m_nxdnNetwork;
CPOCSAGNetwork* m_pocsagNetwork;
CDisplay* m_display;
CUMP* m_ump;
unsigned char m_mode;
unsigned int m_dstarRFModeHang;
unsigned int m_dmrRFModeHang;
unsigned int m_ysfRFModeHang;
unsigned int m_p25RFModeHang;
unsigned int m_nxdnRFModeHang;
unsigned int m_dstarNetModeHang;
unsigned int m_dmrNetModeHang;
unsigned int m_ysfNetModeHang;
unsigned int m_p25NetModeHang;
unsigned int m_nxdnNetModeHang;
unsigned int m_pocsagNetModeHang;
CTimer m_modeTimer;
CTimer m_dmrTXTimer;
CTimer m_cwIdTimer;
bool m_duplex;
unsigned int m_timeout;
bool m_dstarEnabled;
bool m_dmrEnabled;
bool m_ysfEnabled;
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_pocsagEnabled;
unsigned int m_cwIdTime;
CDMRLookup* m_dmrLookup;
CNXDNLookup* m_nxdnLookup;
std::string m_callsign;
unsigned int m_id;
std::string m_cwCallsign;
void readParams();
bool createModem();
@ -87,6 +91,7 @@ private:
bool createYSFNetwork();
bool createP25Network();
bool createNXDNNetwork();
bool createPOCSAGNetwork();
void createDisplay();
void setMode(unsigned char mode);

View File

@ -212,6 +212,9 @@
<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="RingBuffer.h" />
<ClInclude Include="RS129.h" />
@ -294,6 +297,8 @@
<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="RS129.cpp" />
<ClCompile Include="RS241213.cpp" />

View File

@ -263,6 +263,15 @@
<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>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
@ -493,5 +502,11 @@
<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>
</ItemGroup>
</Project>

View File

@ -11,9 +11,9 @@ OBJECTS = \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \
NullDisplay.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 QR1676.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
NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o \
QR1676.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

View File

@ -11,9 +11,9 @@ OBJECTS = \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \
NullDisplay.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 QR1676.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
NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o \
QR1676.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

View File

@ -11,9 +11,9 @@ OBJECTS = \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \
Nextion.o NullDisplay.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 QR1676.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
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 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

View File

@ -11,9 +11,9 @@ OBJECTS = \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \
Nextion.o NullDisplay.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 QR1676.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
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 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

View File

@ -11,9 +11,9 @@ OBJECTS = \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \
Nextion.o NullDisplay.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 QR1676.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
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 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

View File

@ -11,9 +11,9 @@ OBJECTS = \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \
Nextion.o NullDisplay.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 QR1676.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
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 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

View File

@ -11,9 +11,9 @@ OBJECTS = \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \
NullDisplay.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 QR1676.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
NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o \
QR1676.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

110
Modem.cpp
View File

@ -21,6 +21,7 @@
#include "YSFDefines.h"
#include "P25Defines.h"
#include "NXDNDefines.h"
#include "POCSAGDefines.h"
#include "Thread.h"
#include "Modem.h"
#include "Utils.h"
@ -71,6 +72,8 @@ const unsigned char MMDVM_P25_LOST = 0x32U;
const unsigned char MMDVM_NXDN_DATA = 0x40U;
const unsigned char MMDVM_NXDN_LOST = 0x41U;
const unsigned char MMDVM_POCSAG_DATA = 0x50U;
const unsigned char MMDVM_ACK = 0x70U;
const unsigned char MMDVM_NAK = 0x7FU;
@ -107,6 +110,7 @@ m_dmrTXLevel(0U),
m_ysfTXLevel(0U),
m_p25TXLevel(0U),
m_nxdnTXLevel(0U),
m_pocsagTXLevel(0U),
m_trace(trace),
m_debug(debug),
m_rxFrequency(0U),
@ -116,6 +120,7 @@ m_dmrEnabled(false),
m_ysfEnabled(false),
m_p25Enabled(false),
m_nxdnEnabled(false),
m_pocsagEnabled(false),
m_rxDCOffset(0),
m_txDCOffset(0),
m_serial(port, SERIAL_115200, true),
@ -134,6 +139,7 @@ m_rxP25Data(1000U, "Modem RX P25"),
m_txP25Data(1000U, "Modem TX P25"),
m_rxNXDNData(1000U, "Modem RX NXDN"),
m_txNXDNData(1000U, "Modem TX NXDN"),
m_txPOCSAGData(1000U, "Modem TX POCSAG"),
m_rxTransparentData(1000U, "Modem RX Transparent"),
m_txTransparentData(1000U, "Modem TX Transparent"),
m_statusTimer(1000U, 0U, 250U),
@ -145,6 +151,7 @@ m_dmrSpace2(0U),
m_ysfSpace(0U),
m_p25Space(0U),
m_nxdnSpace(0U),
m_pocsagSpace(0U),
m_tx(false),
m_cd(false),
m_lockout(false),
@ -170,24 +177,26 @@ void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int tx
m_rfLevel = rfLevel;
}
void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled)
void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled)
{
m_dstarEnabled = dstarEnabled;
m_dmrEnabled = dmrEnabled;
m_ysfEnabled = ysfEnabled;
m_p25Enabled = p25Enabled;
m_nxdnEnabled = nxdnEnabled;
m_dstarEnabled = dstarEnabled;
m_dmrEnabled = dmrEnabled;
m_ysfEnabled = ysfEnabled;
m_p25Enabled = p25Enabled;
m_nxdnEnabled = nxdnEnabled;
m_pocsagEnabled = pocsagEnabled;
}
void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel)
void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel)
{
m_rxLevel = rxLevel;
m_cwIdTXLevel = cwIdTXLevel;
m_dstarTXLevel = dstarTXLevel;
m_dmrTXLevel = dmrTXLevel;
m_ysfTXLevel = ysfTXLevel;
m_p25TXLevel = p25TXLevel;
m_nxdnTXLevel = nxdnTXLevel;
m_rxLevel = rxLevel;
m_cwIdTXLevel = cwIdTXLevel;
m_dstarTXLevel = dstarTXLevel;
m_dmrTXLevel = dmrTXLevel;
m_ysfTXLevel = ysfTXLevel;
m_p25TXLevel = p25TXLevel;
m_nxdnTXLevel = nxdnTXLevel;
m_pocsagTXLevel = pocsagTXLevel;
}
void CModem::setDMRParams(unsigned int colorCode)
@ -498,15 +507,16 @@ void CModem::clock(unsigned int ms)
m_cd = (m_buffer[5U] & 0x40U) == 0x40U;
m_dstarSpace = m_buffer[6U];
m_dmrSpace1 = m_buffer[7U];
m_dmrSpace2 = m_buffer[8U];
m_ysfSpace = m_buffer[9U];
m_p25Space = m_buffer[10U];
m_nxdnSpace = m_buffer[11U];
m_dstarSpace = m_buffer[6U];
m_dmrSpace1 = m_buffer[7U];
m_dmrSpace2 = m_buffer[8U];
m_ysfSpace = m_buffer[9U];
m_p25Space = m_buffer[10U];
m_nxdnSpace = m_buffer[11U];
m_pocsagSpace = m_buffer[12U];
m_inactivityTimer.start();
// LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, int(m_lockout), int(m_cd));
// LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, int(m_lockout), int(m_cd));
}
break;
@ -676,6 +686,23 @@ void CModem::clock(unsigned int ms)
m_nxdnSpace--;
}
if (m_pocsagSpace > 1U && !m_txPOCSAGData.isEmpty()) {
unsigned char len = 0U;
m_txPOCSAGData.getData(&len, 1U);
m_txPOCSAGData.getData(m_buffer, len);
if (m_trace)
CUtils::dump(1U, "TX POCSAG Data", m_buffer, len);
int ret = m_serial.write(m_buffer, len);
if (ret != int(len))
LogWarning("Error when writing POCSAG data to the MMDVM");
m_playoutTimer.start();
m_pocsagSpace--;
}
if (!m_txTransparentData.isEmpty()) {
unsigned char len = 0U;
m_txTransparentData.getData(&len, 1U);
@ -995,6 +1022,33 @@ bool CModem::writeNXDNData(const unsigned char* data, unsigned int length)
return true;
}
bool CModem::hasPOCSAGSpace() const
{
unsigned int space = m_txPOCSAGData.freeSpace() / (POCSAG_FRAME_LENGTH_BYTES + 4U);
return space > 1U;
}
bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
unsigned char buffer[130U];
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = length + 2U;
buffer[2U] = MMDVM_POCSAG_DATA;
::memcpy(buffer + 3U, data, length);
unsigned char len = length + 3U; // XXX Check lengths
m_txPOCSAGData.addData(&len, 1U);
m_txPOCSAGData.addData(buffer, len);
return true;
}
bool CModem::writeTransparentData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
@ -1123,11 +1177,11 @@ bool CModem::readStatus()
bool CModem::setConfig()
{
unsigned char buffer[20U];
unsigned char buffer[30U];
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 20U;
buffer[1U] = 21U;
buffer[2U] = MMDVM_SET_CONFIG;
@ -1156,6 +1210,8 @@ bool CModem::setConfig()
buffer[4U] |= 0x08U;
if (m_nxdnEnabled)
buffer[4U] |= 0x10U;
if (m_pocsagEnabled)
buffer[4U] |= 0x20U;
buffer[5U] = m_txDelay / 10U; // In 10ms units
@ -1183,10 +1239,12 @@ bool CModem::setConfig()
buffer[19U] = (unsigned char)m_ysfTXHang;
// CUtils::dump(1U, "Written", buffer, 20U);
buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F);
int ret = m_serial.write(buffer, 20U);
if (ret != 20)
// CUtils::dump(1U, "Written", buffer, 21U);
int ret = m_serial.write(buffer, 21U);
if (ret != 21)
return false;
unsigned int count = 0U;

10
Modem.h
View File

@ -38,8 +38,8 @@ public:
~CModem();
void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel);
void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled);
void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel);
void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled);
void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel);
void setDMRParams(unsigned int colorCode);
void setYSFParams(bool loDev, unsigned int txHang);
@ -61,6 +61,7 @@ public:
bool hasYSFSpace() const;
bool hasP25Space() const;
bool hasNXDNSpace() const;
bool hasPOCSAGSpace() const;
bool hasTX() const;
bool hasCD() const;
@ -74,6 +75,7 @@ public:
bool writeYSFData(const unsigned char* data, unsigned int length);
bool writeP25Data(const unsigned char* data, unsigned int length);
bool writeNXDNData(const unsigned char* data, unsigned int length);
bool writePOCSAGData(const unsigned char* data, unsigned int length);
bool writeTransparentData(const unsigned char* data, unsigned int length);
bool writeDMRStart(bool tx);
@ -110,6 +112,7 @@ private:
float m_ysfTXLevel;
float m_p25TXLevel;
float m_nxdnTXLevel;
float m_pocsagTXLevel;
float m_rfLevel;
bool m_trace;
bool m_debug;
@ -120,6 +123,7 @@ private:
bool m_ysfEnabled;
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_pocsagEnabled;
int m_rxDCOffset;
int m_txDCOffset;
CSerialController m_serial;
@ -138,6 +142,7 @@ private:
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_txTransparentData;
CTimer m_statusTimer;
@ -149,6 +154,7 @@ private:
unsigned int m_ysfSpace;
unsigned int m_p25Space;
unsigned int m_nxdnSpace;
unsigned int m_pocsagSpace;
bool m_tx;
bool m_cd;
bool m_lockout;

112
POCSAGControl.cpp Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2018 Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "POCSAGControl.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <ctime>
// #define DUMP_POCSAG
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])
CPOCSAGControl::CPOCSAGControl(CPOCSAGNetwork* network, CDisplay* display) :
m_network(network),
m_display(display),
m_queue(5000U, "POCSAG Control"),
m_fp(NULL)
{
assert(display != NULL);
}
CPOCSAGControl::~CPOCSAGControl()
{
}
unsigned int CPOCSAGControl::readModem(unsigned char* data)
{
assert(data != NULL);
if (m_queue.isEmpty())
return 0U;
unsigned char len = 0U;
m_queue.getData(&len, 1U);
m_queue.getData(data, len);
return len;
}
void CPOCSAGControl::writeNetwork()
{
unsigned char netData[40U];
unsigned int length = m_network->read(netData);
if (length == 0U)
return;
}
void CPOCSAGControl::clock(unsigned int ms)
{
if (m_network != NULL)
writeNetwork();
}
bool CPOCSAGControl::openFile()
{
if (m_fp != NULL)
return true;
time_t t;
::time(&t);
struct tm* tm = ::localtime(&t);
char name[100U];
::sprintf(name, "POCSAG_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
m_fp = ::fopen(name, "wb");
if (m_fp == NULL)
return false;
::fwrite("POCSAG", 1U, 3U, m_fp);
return true;
}
bool CPOCSAGControl::writeFile(const unsigned char* data)
{
if (m_fp == NULL)
return false;
::fwrite(data, 1U, POCSAG_FRAME_LENGTH_BYTES, m_fp);
return true;
}
void CPOCSAGControl::closeFile()
{
if (m_fp != NULL) {
::fclose(m_fp);
m_fp = NULL;
}
}

53
POCSAGControl.h Normal file
View File

@ -0,0 +1,53 @@
/*
* 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(POCSAGControl_H)
#define POCSAGControl_H
#include "POCSAGNetwork.h"
#include "POCSAGDefines.h"
#include "RingBuffer.h"
#include "Display.h"
#include "Defines.h"
#include <string>
class CPOCSAGControl {
public:
CPOCSAGControl(CPOCSAGNetwork* network, CDisplay* display);
~CPOCSAGControl();
unsigned int readModem(unsigned char* data);
void clock(unsigned int ms);
private:
CPOCSAGNetwork* m_network;
CDisplay* m_display;
CRingBuffer<unsigned char> m_queue;
unsigned int m_frames;
FILE* m_fp;
void writeNetwork();
bool openFile();
bool writeFile(const unsigned char* data);
void closeFile();
};
#endif

33
POCSAGDefines.h Normal file
View File

@ -0,0 +1,33 @@
/*
* 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(POCSAGDEFINES_H)
#define POCSAGDEFINES_H
#include <cstdint>
const unsigned int POCSAG_RADIO_SYMBOL_LENGTH = 20U; // At 24 kHz sample rate
const unsigned int POCSAG_FRAME_LENGTH_WORDS = 17U;
const unsigned int POCSAG_FRAME_LENGTH_BYTES = POCSAG_FRAME_LENGTH_WORDS * sizeof(uint32_t);
const uint32_t POCSAG_SYNC_WORD = 0x7CD215D8U;
const uint32_t POCSAG_IDLE_WORD = 0x7A89C197U;
#endif

122
POCSAGNetwork.cpp Normal file
View File

@ -0,0 +1,122 @@
/*
* 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 "POCSAGDefines.h"
#include "POCSAGNetwork.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
CPOCSAGNetwork::CPOCSAGNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) :
m_socket(myAddress, myPort),
m_address(),
m_port(gatewayPort),
m_debug(debug),
m_enabled(false),
m_buffer(1000U, "POCSAG Network")
{
m_address = CUDPSocket::lookup(gatewayAddress);
}
CPOCSAGNetwork::~CPOCSAGNetwork()
{
}
bool CPOCSAGNetwork::open()
{
LogMessage("Opening POCSAG network connection");
if (m_address.s_addr == INADDR_NONE)
return false;
return m_socket.open();
}
void CPOCSAGNetwork::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 || m_port != port) {
LogMessage("POCSAG 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, "POCSAG", 6U) != 0)
return;
if (!m_enabled)
return;
if (m_debug)
CUtils::dump(1U, "POCSAG Network Data Received", buffer, length);
unsigned char len = length - 6U;
m_buffer.addData(&len, 1U);
m_buffer.addData(buffer + 6U, length - 6U);
}
unsigned int CPOCSAGNetwork::read(unsigned char* data)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return 0U;
unsigned char len = 0U;
m_buffer.getData(&len, 1U);
m_buffer.getData(data, len);
return len;
}
void CPOCSAGNetwork::reset()
{
}
void CPOCSAGNetwork::close()
{
m_socket.close();
LogMessage("Closing POCSAG network connection");
}
void CPOCSAGNetwork::enable(bool enabled)
{
if (enabled && !m_enabled)
reset();
unsigned char c = enabled ? 0xFFU : 0x00U;
m_socket.write(&c, 1U, m_address, m_port);
m_enabled = enabled;
}

56
POCSAGNetwork.h Normal file
View File

@ -0,0 +1,56 @@
/*
* 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.
*/
#ifndef POCSAGNetwork_H
#define POCSAGNetwork_H
#include "POCSAGDefines.h"
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CPOCSAGNetwork {
public:
CPOCSAGNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug);
~CPOCSAGNetwork();
bool open();
void enable(bool enabled);
unsigned int 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

View File

@ -29,6 +29,7 @@
#define PIN_YSF 5
#define PIN_P25 6
#define PIN_NXDN 7
#define PIN_POCSAG 8
#define PIN_TX 10
#define PIN_CD 11
@ -64,17 +65,19 @@ void setup()
pinMode(PIN_YSF, OUTPUT);
pinMode(PIN_P25, OUTPUT);
pinMode(PIN_NXDN, OUTPUT);
pinMode(PIN_POCSAG, OUTPUT);
pinMode(PIN_TX, OUTPUT);
pinMode(PIN_CD, OUTPUT);
pinMode(PIN_LOCKOUT, INPUT);
digitalWrite(PIN_DSTAR, LOW);
digitalWrite(PIN_DMR, LOW);
digitalWrite(PIN_YSF, LOW);
digitalWrite(PIN_P25, LOW);
digitalWrite(PIN_NXDN, LOW);
digitalWrite(PIN_TX, LOW);
digitalWrite(PIN_CD, LOW);
digitalWrite(PIN_DSTAR, LOW);
digitalWrite(PIN_DMR, LOW);
digitalWrite(PIN_YSF, LOW);
digitalWrite(PIN_P25, LOW);
digitalWrite(PIN_NXDN, LOW);
digitalWrite(PIN_POCSAG, LOW);
digitalWrite(PIN_TX, LOW);
digitalWrite(PIN_CD, LOW);
}
#define UMP_FRAME_START 0xF0U
@ -95,6 +98,7 @@ void setup()
#define MODE_YSF 3U
#define MODE_P25 4U
#define MODE_NXDN 5U
#define MODE_POCSAG 6U
bool m_started = false;
uint32_t m_count = 0U;
@ -129,11 +133,12 @@ void loop()
m_started = true;
break;
case UMP_SET_MODE:
digitalWrite(PIN_DSTAR, m_buffer[3U] == MODE_DSTAR ? HIGH : LOW);
digitalWrite(PIN_DMR, m_buffer[3U] == MODE_DMR ? HIGH : LOW);
digitalWrite(PIN_YSF, m_buffer[3U] == MODE_YSF ? HIGH : LOW);
digitalWrite(PIN_P25, m_buffer[3U] == MODE_P25 ? HIGH : LOW);
digitalWrite(PIN_NXDN, m_buffer[3U] == MODE_NXDN ? HIGH : LOW);
digitalWrite(PIN_DSTAR, m_buffer[3U] == MODE_DSTAR ? HIGH : LOW);
digitalWrite(PIN_DMR, m_buffer[3U] == MODE_DMR ? HIGH : LOW);
digitalWrite(PIN_YSF, m_buffer[3U] == MODE_YSF ? HIGH : LOW);
digitalWrite(PIN_P25, m_buffer[3U] == MODE_P25 ? HIGH : LOW);
digitalWrite(PIN_NXDN, m_buffer[3U] == MODE_NXDN ? HIGH : LOW);
digitalWrite(PIN_POCSAG, m_buffer[3U] == MODE_POCSAG ? HIGH : LOW);
break;
case UMP_SET_TX:
digitalWrite(PIN_TX, m_buffer[3U] == 0x01U ? HIGH : LOW);