diff --git a/Conf.cpp b/Conf.cpp
index 8f2837745..989ccfd9f 100644
--- a/Conf.cpp
+++ b/Conf.cpp
@@ -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;
diff --git a/Conf.h b/Conf.h
index f85c17b44..2ba0a1a8d 100644
--- a/Conf.h
+++ b/Conf.h
@@ -87,6 +87,7 @@ class CConf
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 @@ class CConf
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 @@ class CConf
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 @@ class CConf
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 @@ class CConf
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 @@ class CConf
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;
diff --git a/Defines.h b/Defines.h
index 1f47836ea..73e9e528f 100644
--- a/Defines.h
+++ b/Defines.h
@@ -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;
diff --git a/MMDVM.ini b/MMDVM.ini
index f9d93575a..4fee55064 100644
--- a/MMDVM.ini
+++ b/MMDVM.ini
@@ -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
diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp
index d3ef606fb..ff7cf00fa 100644
--- a/MMDVMHost.cpp
+++ b/MMDVMHost.cpp
@@ -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();
diff --git a/MMDVMHost.h b/MMDVMHost.h
index 787df3983..c19623ff0 100644
--- a/MMDVMHost.h
+++ b/MMDVMHost.h
@@ -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 @@ class CMMDVMHost
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 @@ class CMMDVMHost
bool createYSFNetwork();
bool createP25Network();
bool createNXDNNetwork();
+ bool createPOCSAGNetwork();
void createDisplay();
void setMode(unsigned char mode);
diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj
index e63859cc8..e967e9dfd 100644
--- a/MMDVMHost.vcxproj
+++ b/MMDVMHost.vcxproj
@@ -212,6 +212,9 @@
+
+
+
@@ -294,6 +297,8 @@
+
+
diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters
index c276fc7ef..20a3aad08 100644
--- a/MMDVMHost.vcxproj.filters
+++ b/MMDVMHost.vcxproj.filters
@@ -263,6 +263,15 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
@@ -493,5 +502,11 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
\ No newline at end of file
diff --git a/Makefile b/Makefile
index ae0175b52..8e0591570 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/Makefile.Pi b/Makefile.Pi
index 3ef95137a..0d8475b70 100644
--- a/Makefile.Pi
+++ b/Makefile.Pi
@@ -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
diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit
index ec8042702..27266def2 100644
--- a/Makefile.Pi.Adafruit
+++ b/Makefile.Pi.Adafruit
@@ -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
diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780
index e35f8d3bc..602ad3bb8 100644
--- a/Makefile.Pi.HD44780
+++ b/Makefile.Pi.HD44780
@@ -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
diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED
index 600e7db34..6ef3fd8e7 100644
--- a/Makefile.Pi.OLED
+++ b/Makefile.Pi.OLED
@@ -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
diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574
index 4fbc2a84c..0652e3476 100644
--- a/Makefile.Pi.PCF8574
+++ b/Makefile.Pi.PCF8574
@@ -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
diff --git a/Makefile.Solaris b/Makefile.Solaris
index 8f58787b8..a42b0445e 100644
--- a/Makefile.Solaris
+++ b/Makefile.Solaris
@@ -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
diff --git a/Modem.cpp b/Modem.cpp
index 037935bd5..8db90122c 100644
--- a/Modem.cpp
+++ b/Modem.cpp
@@ -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);
+
+ // CUtils::dump(1U, "Written", buffer, 21U);
- int ret = m_serial.write(buffer, 20U);
- if (ret != 20)
+ int ret = m_serial.write(buffer, 21U);
+ if (ret != 21)
return false;
unsigned int count = 0U;
diff --git a/Modem.h b/Modem.h
index 37ef76fc2..2e32cb16e 100644
--- a/Modem.h
+++ b/Modem.h
@@ -38,8 +38,8 @@ class CModem {
~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 @@ class CModem {
bool hasYSFSpace() const;
bool hasP25Space() const;
bool hasNXDNSpace() const;
+ bool hasPOCSAGSpace() const;
bool hasTX() const;
bool hasCD() const;
@@ -74,6 +75,7 @@ class CModem {
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 @@ class CModem {
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 @@ class CModem {
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 @@ class CModem {
CRingBuffer m_txP25Data;
CRingBuffer m_rxNXDNData;
CRingBuffer m_txNXDNData;
+ CRingBuffer m_txPOCSAGData;
CRingBuffer m_rxTransparentData;
CRingBuffer m_txTransparentData;
CTimer m_statusTimer;
@@ -149,6 +154,7 @@ class CModem {
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;
diff --git a/POCSAGControl.cpp b/POCSAGControl.cpp
new file mode 100644
index 000000000..216162339
--- /dev/null
+++ b/POCSAGControl.cpp
@@ -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
+#include
+#include
+#include
+
+// #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;
+ }
+}
diff --git a/POCSAGControl.h b/POCSAGControl.h
new file mode 100644
index 000000000..aa580ef6f
--- /dev/null
+++ b/POCSAGControl.h
@@ -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
+
+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 m_queue;
+ unsigned int m_frames;
+ FILE* m_fp;
+
+ void writeNetwork();
+
+ bool openFile();
+ bool writeFile(const unsigned char* data);
+ void closeFile();
+};
+
+#endif
diff --git a/POCSAGDefines.h b/POCSAGDefines.h
new file mode 100644
index 000000000..1919226da
--- /dev/null
+++ b/POCSAGDefines.h
@@ -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
+
+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
diff --git a/POCSAGNetwork.cpp b/POCSAGNetwork.cpp
new file mode 100644
index 000000000..5716a248a
--- /dev/null
+++ b/POCSAGNetwork.cpp
@@ -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
+#include
+#include
+
+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;
+}
diff --git a/POCSAGNetwork.h b/POCSAGNetwork.h
new file mode 100644
index 000000000..fe9520358
--- /dev/null
+++ b/POCSAGNetwork.h
@@ -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
+#include
+
+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 m_buffer;
+};
+
+#endif
diff --git a/UMP/UMP.ino b/UMP/UMP.ino
index d35d18f16..4cf98e301 100644
--- a/UMP/UMP.ino
+++ b/UMP/UMP.ino
@@ -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);