Merge pull request #565 from jg1uaa/ipv6

add IPv6 support
This commit is contained in:
Jonathan Naylor 2020-06-12 12:53:36 +01:00 committed by GitHub
commit 19c8c6515c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 1560 additions and 340 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -76,6 +76,10 @@ void CCASTInfo::setQuitInt()
{ {
} }
void CCASTInfo::setFMInt()
{
}
void CCASTInfo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CCASTInfo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
if (m_modem != NULL) if (m_modem != NULL)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -40,6 +40,7 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt(); virtual void clearDStarInt();

311
Conf.cpp
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -44,6 +44,7 @@ enum SECTION {
SECTION_P25, SECTION_P25,
SECTION_NXDN, SECTION_NXDN,
SECTION_POCSAG, SECTION_POCSAG,
SECTION_FM,
SECTION_DSTAR_NETWORK, SECTION_DSTAR_NETWORK,
SECTION_DMR_NETWORK, SECTION_DMR_NETWORK,
SECTION_FUSION_NETWORK, SECTION_FUSION_NETWORK,
@ -109,6 +110,7 @@ m_modemYSFTXLevel(50.0F),
m_modemP25TXLevel(50.0F), m_modemP25TXLevel(50.0F),
m_modemNXDNTXLevel(50.0F), m_modemNXDNTXLevel(50.0F),
m_modemPOCSAGTXLevel(50.0F), m_modemPOCSAGTXLevel(50.0F),
m_modemFMTXLevel(50.0F),
m_modemRSSIMappingFile(), m_modemRSSIMappingFile(),
m_modemTrace(false), m_modemTrace(false),
m_modemDebug(false), m_modemDebug(false),
@ -161,15 +163,48 @@ m_p25NAC(0x293U),
m_p25SelfOnly(false), m_p25SelfOnly(false),
m_p25OverrideUID(false), m_p25OverrideUID(false),
m_p25RemoteGateway(false), m_p25RemoteGateway(false),
m_p25TXHang(5U),
m_p25ModeHang(10U), m_p25ModeHang(10U),
m_nxdnEnabled(false), m_nxdnEnabled(false),
m_nxdnId(0U), m_nxdnId(0U),
m_nxdnRAN(1U), m_nxdnRAN(1U),
m_nxdnSelfOnly(false), m_nxdnSelfOnly(false),
m_nxdnRemoteGateway(false), m_nxdnRemoteGateway(false),
m_nxdnTXHang(5U),
m_nxdnModeHang(10U), m_nxdnModeHang(10U),
m_pocsagEnabled(false), m_pocsagEnabled(false),
m_pocsagFrequency(0U), m_pocsagFrequency(0U),
m_fmEnabled(false),
m_fmCallsign(),
m_fmCallsignSpeed(20U),
m_fmCallsignFrequency(1000U),
m_fmCallsignTime(10U),
m_fmCallsignHoldoff(1U),
m_fmCallsignHighLevel(35.0F),
m_fmCallsignLowLevel(15.0F),
m_fmCallsignAtStart(true),
m_fmCallsignAtEnd(true),
m_fmCallsignAtLatch(true),
m_fmRFAck("K"),
m_fmExtAck("N"),
m_fmAckSpeed(20U),
m_fmAckFrequency(1750U),
m_fmAckMinTime(5U),
m_fmAckDelay(1000U),
m_fmAckLevel(80.0F),
m_fmTimeout(180U),
m_fmTimeoutLevel(80.0F),
m_fmCTCSSFrequency(88.6F),
m_fmCTCSSHighThreshold(30U),
m_fmCTCSSLowThreshold(20U),
m_fmCTCSSLevel(2.0F),
m_fmKerchunkTime(0U),
m_fmHangTime(7U),
m_fmUseCOS(true),
m_fmCOSInvert(false),
m_fmRFAudioBoost(1U),
m_fmMaxDevLevel(90.0F),
m_fmExtAudioBoost(1U),
m_dstarNetworkEnabled(false), m_dstarNetworkEnabled(false),
m_dstarGatewayAddress(), m_dstarGatewayAddress(),
m_dstarGatewayPort(0U), m_dstarGatewayPort(0U),
@ -244,12 +279,14 @@ m_lcdprocPort(0U),
m_lcdprocLocalPort(0U), m_lcdprocLocalPort(0U),
m_lcdprocDisplayClock(false), m_lcdprocDisplayClock(false),
m_lcdprocUTC(false), m_lcdprocUTC(false),
m_lcdprocDimOnIdle(false),
m_lockFileEnabled(false), m_lockFileEnabled(false),
m_lockFileName(), m_lockFileName(),
m_mobileGPSEnabled(false), m_mobileGPSEnabled(false),
m_mobileGPSAddress(), m_mobileGPSAddress(),
m_mobileGPSPort(0U), m_mobileGPSPort(0U),
m_remoteControlEnabled(false), m_remoteControlEnabled(false),
m_remoteControlAddress("127.0.0.1"),
m_remoteControlPort(0U) m_remoteControlPort(0U)
{ {
} }
@ -304,6 +341,8 @@ bool CConf::read()
section = SECTION_NXDN; section = SECTION_NXDN;
else if (::strncmp(buffer, "[POCSAG]", 8U) == 0) else if (::strncmp(buffer, "[POCSAG]", 8U) == 0)
section = SECTION_POCSAG; section = SECTION_POCSAG;
else if (::strncmp(buffer, "[FM]", 4U) == 0)
section = SECTION_FM;
else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0) else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0)
section = SECTION_DSTAR_NETWORK; section = SECTION_DSTAR_NETWORK;
else if (::strncmp(buffer, "[DMR Network]", 13U) == 0) else if (::strncmp(buffer, "[DMR Network]", 13U) == 0)
@ -358,11 +397,11 @@ bool CConf::read()
// Convert the callsign to upper case // Convert the callsign to upper case
for (unsigned int i = 0U; value[i] != 0; i++) for (unsigned int i = 0U; value[i] != 0; i++)
value[i] = ::toupper(value[i]); value[i] = ::toupper(value[i]);
m_cwIdCallsign = m_callsign = value; m_fmCallsign = m_cwIdCallsign = m_callsign = value;
} else if (::strcmp(key, "Id") == 0) } else if (::strcmp(key, "Id") == 0)
m_id = m_p25Id = m_dmrId = (unsigned int)::atoi(value); m_id = m_p25Id = m_dmrId = (unsigned int)::atoi(value);
else if (::strcmp(key, "Timeout") == 0) else if (::strcmp(key, "Timeout") == 0)
m_timeout = (unsigned int)::atoi(value); m_fmTimeout = m_timeout = (unsigned int)::atoi(value);
else if (::strcmp(key, "Duplex") == 0) else if (::strcmp(key, "Duplex") == 0)
m_duplex = ::atoi(value) == 1; m_duplex = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0) else if (::strcmp(key, "ModeHang") == 0)
@ -455,7 +494,7 @@ bool CConf::read()
else if (::strcmp(key, "RXLevel") == 0) else if (::strcmp(key, "RXLevel") == 0)
m_modemRXLevel = float(::atof(value)); m_modemRXLevel = float(::atof(value));
else if (::strcmp(key, "TXLevel") == 0) else if (::strcmp(key, "TXLevel") == 0)
m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value));
else if (::strcmp(key, "CWIdTXLevel") == 0) else if (::strcmp(key, "CWIdTXLevel") == 0)
m_modemCWIdTXLevel = float(::atof(value)); m_modemCWIdTXLevel = float(::atof(value));
else if (::strcmp(key, "D-StarTXLevel") == 0) else if (::strcmp(key, "D-StarTXLevel") == 0)
@ -470,6 +509,8 @@ bool CConf::read()
m_modemNXDNTXLevel = float(::atof(value)); m_modemNXDNTXLevel = float(::atof(value));
else if (::strcmp(key, "POCSAGTXLevel") == 0) else if (::strcmp(key, "POCSAGTXLevel") == 0)
m_modemPOCSAGTXLevel = float(::atof(value)); m_modemPOCSAGTXLevel = float(::atof(value));
else if (::strcmp(key, "FMTXLevel") == 0)
m_modemFMTXLevel = float(::atof(value));
else if (::strcmp(key, "RSSIMappingFile") == 0) else if (::strcmp(key, "RSSIMappingFile") == 0)
m_modemRSSIMappingFile = value; m_modemRSSIMappingFile = value;
else if (::strcmp(key, "Trace") == 0) else if (::strcmp(key, "Trace") == 0)
@ -636,6 +677,8 @@ bool CConf::read()
m_p25SelfOnly = ::atoi(value) == 1; m_p25SelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "RemoteGateway") == 0) else if (::strcmp(key, "RemoteGateway") == 0)
m_p25RemoteGateway = ::atoi(value) == 1; m_p25RemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "TXHang") == 0)
m_p25TXHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0) else if (::strcmp(key, "ModeHang") == 0)
m_p25ModeHang = (unsigned int)::atoi(value); m_p25ModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_NXDN) { } else if (section == SECTION_NXDN) {
@ -649,13 +692,90 @@ bool CConf::read()
m_nxdnSelfOnly = ::atoi(value) == 1; m_nxdnSelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "RemoteGateway") == 0) else if (::strcmp(key, "RemoteGateway") == 0)
m_nxdnRemoteGateway = ::atoi(value) == 1; m_nxdnRemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "TXHang") == 0)
m_nxdnTXHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0) else if (::strcmp(key, "ModeHang") == 0)
m_nxdnModeHang = (unsigned int)::atoi(value); m_nxdnModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_POCSAG) { } else if (section == SECTION_POCSAG) {
if (::strcmp(key, "Enable") == 0)
m_pocsagEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Frequency") == 0)
m_pocsagFrequency = (unsigned int)::atoi(value);
}
else if (section == SECTION_FM) {
if (::strcmp(key, "Enable") == 0) if (::strcmp(key, "Enable") == 0)
m_pocsagEnabled = ::atoi(value) == 1; m_fmEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Frequency") == 0) else if (::strcmp(key, "Callsign") == 0) {
m_pocsagFrequency = (unsigned int)::atoi(value); // Convert the callsign to upper case
for (unsigned int i = 0U; value[i] != 0; i++)
value[i] = ::toupper(value[i]);
m_fmCallsign = value;
} else if (::strcmp(key, "CallsignSpeed") == 0)
m_fmCallsignSpeed = (unsigned int)::atoi(value);
else if (::strcmp(key, "CallsignFrequency") == 0)
m_fmCallsignFrequency = (unsigned int)::atoi(value);
else if (::strcmp(key, "CallsignTime") == 0)
m_fmCallsignTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "CallsignHoldoff") == 0)
m_fmCallsignHoldoff = (unsigned int)::atoi(value);
else if (::strcmp(key, "CallsignHighLevel") == 0)
m_fmCallsignHighLevel = float(::atof(value));
else if (::strcmp(key, "CallsignLowLevel") == 0)
m_fmCallsignLowLevel = float(::atof(value));
else if (::strcmp(key, "CallsignAtStart") == 0)
m_fmCallsignAtStart = ::atoi(value) == 1;
else if (::strcmp(key, "CallsignAtEnd") == 0)
m_fmCallsignAtEnd = ::atoi(value) == 1;
else if (::strcmp(key, "CallsignAtLatch") == 0)
m_fmCallsignAtLatch = ::atoi(value) == 1;
else if (::strcmp(key, "RFAck") == 0) {
// Convert the ack to upper case
for (unsigned int i = 0U; value[i] != 0; i++)
value[i] = ::toupper(value[i]);
m_fmRFAck = value;
} else if (::strcmp(key, "ExtAck") == 0) {
// Convert the ack to upper case
for (unsigned int i = 0U; value[i] != 0; i++)
value[i] = ::toupper(value[i]);
m_fmExtAck = value;
} else if (::strcmp(key, "AckSpeed") == 0)
m_fmAckSpeed = (unsigned int)::atoi(value);
else if (::strcmp(key, "AckFrequency") == 0)
m_fmAckFrequency = (unsigned int)::atoi(value);
else if (::strcmp(key, "AckMinTime") == 0)
m_fmAckMinTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "AckDelay") == 0)
m_fmAckDelay = (unsigned int)::atoi(value);
else if (::strcmp(key, "AckLevel") == 0)
m_fmAckLevel = float(::atof(value));
else if (::strcmp(key, "Timeout") == 0)
m_fmTimeout = (unsigned int)::atoi(value);
else if (::strcmp(key, "TimeoutLevel") == 0)
m_fmTimeoutLevel = float(::atof(value));
else if (::strcmp(key, "CTCSSFrequency") == 0)
m_fmCTCSSFrequency = float(::atof(value));
else if (::strcmp(key, "CTCSSThreshold") == 0)
m_fmCTCSSHighThreshold = m_fmCTCSSLowThreshold = (unsigned int)::atoi(value);
else if (::strcmp(key, "CTCSSHighThreshold") == 0)
m_fmCTCSSHighThreshold = (unsigned int)::atoi(value);
else if (::strcmp(key, "CTCSSLowThreshold") == 0)
m_fmCTCSSLowThreshold = (unsigned int)::atoi(value);
else if (::strcmp(key, "CTCSSLevel") == 0)
m_fmCTCSSLevel = float(::atof(value));
else if (::strcmp(key, "KerchunkTime") == 0)
m_fmKerchunkTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "HangTime") == 0)
m_fmHangTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "UseCOS") == 0)
m_fmUseCOS = ::atoi(value) == 1;
else if (::strcmp(key, "COSInvert") == 0)
m_fmCOSInvert = ::atoi(value) == 1;
else if (::strcmp(key, "RFAudioBoost") == 0)
m_fmRFAudioBoost = (unsigned int)::atoi(value);
else if (::strcmp(key, "MaxDevLevel") == 0)
m_fmMaxDevLevel = float(::atof(value));
else if (::strcmp(key, "ExtAudioBoost") == 0)
m_fmExtAudioBoost = (unsigned int)::atoi(value);
} else if (section == SECTION_DSTAR_NETWORK) { } else if (section == SECTION_DSTAR_NETWORK) {
if (::strcmp(key, "Enable") == 0) if (::strcmp(key, "Enable") == 0)
m_dstarNetworkEnabled = ::atoi(value) == 1; m_dstarNetworkEnabled = ::atoi(value) == 1;
@ -838,6 +958,8 @@ bool CConf::read()
} else if (section == SECTION_REMOTE_CONTROL) { } else if (section == SECTION_REMOTE_CONTROL) {
if (::strcmp(key, "Enable") == 0) if (::strcmp(key, "Enable") == 0)
m_remoteControlEnabled = ::atoi(value) == 1; m_remoteControlEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
m_remoteControlAddress = value;
else if (::strcmp(key, "Port") == 0) else if (::strcmp(key, "Port") == 0)
m_remoteControlPort = (unsigned int)::atoi(value); m_remoteControlPort = (unsigned int)::atoi(value);
} }
@ -1083,6 +1205,11 @@ float CConf::getModemPOCSAGTXLevel() const
return m_modemPOCSAGTXLevel; return m_modemPOCSAGTXLevel;
} }
float CConf::getModemFMTXLevel() const
{
return m_modemFMTXLevel;
}
std::string CConf::getModemRSSIMappingFile () const std::string CConf::getModemRSSIMappingFile () const
{ {
return m_modemRSSIMappingFile; return m_modemRSSIMappingFile;
@ -1343,6 +1470,11 @@ bool CConf::getP25RemoteGateway() const
return m_p25RemoteGateway; return m_p25RemoteGateway;
} }
unsigned int CConf::getP25TXHang() const
{
return m_p25TXHang;
}
unsigned int CConf::getP25ModeHang() const unsigned int CConf::getP25ModeHang() const
{ {
return m_p25ModeHang; return m_p25ModeHang;
@ -1373,6 +1505,11 @@ bool CConf::getNXDNRemoteGateway() const
return m_nxdnRemoteGateway; return m_nxdnRemoteGateway;
} }
unsigned int CConf::getNXDNTXHang() const
{
return m_nxdnTXHang;
}
unsigned int CConf::getNXDNModeHang() const unsigned int CConf::getNXDNModeHang() const
{ {
return m_nxdnModeHang; return m_nxdnModeHang;
@ -1388,6 +1525,161 @@ unsigned int CConf::getPOCSAGFrequency() const
return m_pocsagFrequency; return m_pocsagFrequency;
} }
bool CConf::getFMEnabled() const
{
return m_fmEnabled;
}
std::string CConf::getFMCallsign() const
{
return m_fmCallsign;
}
unsigned int CConf::getFMCallsignSpeed() const
{
return m_fmCallsignSpeed;
}
unsigned int CConf::getFMCallsignFrequency() const
{
return m_fmCallsignFrequency;
}
unsigned int CConf::getFMCallsignTime() const
{
return m_fmCallsignTime;
}
unsigned int CConf::getFMCallsignHoldoff() const
{
return m_fmCallsignHoldoff;
}
float CConf::getFMCallsignHighLevel() const
{
return m_fmCallsignHighLevel;
}
float CConf::getFMCallsignLowLevel() const
{
return m_fmCallsignLowLevel;
}
bool CConf::getFMCallsignAtStart() const
{
return m_fmCallsignAtStart;
}
bool CConf::getFMCallsignAtEnd() const
{
return m_fmCallsignAtEnd;
}
bool CConf::getFMCallsignAtLatch() const
{
return m_fmCallsignAtLatch;
}
std::string CConf::getFMRFAck() const
{
return m_fmRFAck;
}
std::string CConf::getFMExtAck() const
{
return m_fmExtAck;
}
unsigned int CConf::getFMAckSpeed() const
{
return m_fmAckSpeed;
}
unsigned int CConf::getFMAckFrequency() const
{
return m_fmAckFrequency;
}
unsigned int CConf::getFMAckMinTime() const
{
return m_fmAckMinTime;
}
unsigned int CConf::getFMAckDelay() const
{
return m_fmAckDelay;
}
float CConf::getFMAckLevel() const
{
return m_fmAckLevel;
}
unsigned int CConf::getFMTimeout() const
{
return m_fmTimeout;
}
float CConf::getFMTimeoutLevel() const
{
return m_fmTimeoutLevel;
}
float CConf::getFMCTCSSFrequency() const
{
return m_fmCTCSSFrequency;
}
unsigned int CConf::getFMCTCSSHighThreshold() const
{
return m_fmCTCSSHighThreshold;
}
unsigned int CConf::getFMCTCSSLowThreshold() const
{
return m_fmCTCSSLowThreshold;
}
float CConf::getFMCTCSSLevel() const
{
return m_fmCTCSSLevel;
}
unsigned int CConf::getFMKerchunkTime() const
{
return m_fmKerchunkTime;
}
unsigned int CConf::getFMHangTime() const
{
return m_fmHangTime;
}
bool CConf::getFMUseCOS() const
{
return m_fmUseCOS;
}
bool CConf::getFMCOSInvert() const
{
return m_fmCOSInvert;
}
unsigned int CConf::getFMRFAudioBoost() const
{
return m_fmRFAudioBoost;
}
float CConf::getFMMaxDevLevel() const
{
return m_fmMaxDevLevel;
}
unsigned int CConf::getFMExtAudioBoost() const
{
return m_fmExtAudioBoost;
}
bool CConf::getDStarNetworkEnabled() const bool CConf::getDStarNetworkEnabled() const
{ {
return m_dstarNetworkEnabled; return m_dstarNetworkEnabled;
@ -1794,6 +2086,11 @@ bool CConf::getRemoteControlEnabled() const
return m_remoteControlEnabled; return m_remoteControlEnabled;
} }
std::string CConf::getRemoteControlAddress() const
{
return m_remoteControlAddress;
}
unsigned int CConf::getRemoteControlPort() const unsigned int CConf::getRemoteControlPort() const
{ {
return m_remoteControlPort; return m_remoteControlPort;

75
Conf.h
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -90,6 +90,7 @@ public:
float getModemP25TXLevel() const; float getModemP25TXLevel() const;
float getModemNXDNTXLevel() const; float getModemNXDNTXLevel() const;
float getModemPOCSAGTXLevel() const; float getModemPOCSAGTXLevel() const;
float getModemFMTXLevel() const;
std::string getModemRSSIMappingFile() const; std::string getModemRSSIMappingFile() const;
bool getModemTrace() const; bool getModemTrace() const;
bool getModemDebug() const; bool getModemDebug() const;
@ -154,6 +155,7 @@ public:
bool getP25SelfOnly() const; bool getP25SelfOnly() const;
bool getP25OverrideUID() const; bool getP25OverrideUID() const;
bool getP25RemoteGateway() const; bool getP25RemoteGateway() const;
unsigned int getP25TXHang() const;
unsigned int getP25ModeHang() const; unsigned int getP25ModeHang() const;
// The NXDN section // The NXDN section
@ -162,12 +164,46 @@ public:
unsigned int getNXDNRAN() const; unsigned int getNXDNRAN() const;
bool getNXDNSelfOnly() const; bool getNXDNSelfOnly() const;
bool getNXDNRemoteGateway() const; bool getNXDNRemoteGateway() const;
unsigned int getNXDNTXHang() const;
unsigned int getNXDNModeHang() const; unsigned int getNXDNModeHang() const;
// The POCSAG section // The POCSAG section
bool getPOCSAGEnabled() const; bool getPOCSAGEnabled() const;
unsigned int getPOCSAGFrequency() const; unsigned int getPOCSAGFrequency() const;
// The FM Section
bool getFMEnabled() const;
std::string getFMCallsign() const;
unsigned int getFMCallsignSpeed() const;
unsigned int getFMCallsignFrequency() const;
unsigned int getFMCallsignTime() const;
unsigned int getFMCallsignHoldoff() const;
float getFMCallsignHighLevel() const;
float getFMCallsignLowLevel() const;
bool getFMCallsignAtStart() const;
bool getFMCallsignAtEnd() const;
bool getFMCallsignAtLatch() const;
std::string getFMRFAck() const;
std::string getFMExtAck() const;
unsigned int getFMAckSpeed() const;
unsigned int getFMAckFrequency() const;
unsigned int getFMAckMinTime() const;
unsigned int getFMAckDelay() const;
float getFMAckLevel() const;
unsigned int getFMTimeout() const;
float getFMTimeoutLevel() const;
float getFMCTCSSFrequency() const;
unsigned int getFMCTCSSHighThreshold() const;
unsigned int getFMCTCSSLowThreshold() const;
float getFMCTCSSLevel() const;
unsigned int getFMKerchunkTime() const;
unsigned int getFMHangTime() const;
bool getFMUseCOS() const;
bool getFMCOSInvert() const;
unsigned int getFMRFAudioBoost() const;
float getFMMaxDevLevel() const;
unsigned int getFMExtAudioBoost() const;
// The D-Star Network section // The D-Star Network section
bool getDStarNetworkEnabled() const; bool getDStarNetworkEnabled() const;
std::string getDStarGatewayAddress() const; std::string getDStarGatewayAddress() const;
@ -276,6 +312,7 @@ public:
// The Remote Control section // The Remote Control section
bool getRemoteControlEnabled() const; bool getRemoteControlEnabled() const;
std::string getRemoteControlAddress() const;
unsigned int getRemoteControlPort() const; unsigned int getRemoteControlPort() const;
private: private:
@ -333,6 +370,7 @@ private:
float m_modemP25TXLevel; float m_modemP25TXLevel;
float m_modemNXDNTXLevel; float m_modemNXDNTXLevel;
float m_modemPOCSAGTXLevel; float m_modemPOCSAGTXLevel;
float m_modemFMTXLevel;
std::string m_modemRSSIMappingFile; std::string m_modemRSSIMappingFile;
bool m_modemTrace; bool m_modemTrace;
bool m_modemDebug; bool m_modemDebug;
@ -391,6 +429,7 @@ private:
bool m_p25SelfOnly; bool m_p25SelfOnly;
bool m_p25OverrideUID; bool m_p25OverrideUID;
bool m_p25RemoteGateway; bool m_p25RemoteGateway;
unsigned int m_p25TXHang;
unsigned int m_p25ModeHang; unsigned int m_p25ModeHang;
bool m_nxdnEnabled; bool m_nxdnEnabled;
@ -398,11 +437,44 @@ private:
unsigned int m_nxdnRAN; unsigned int m_nxdnRAN;
bool m_nxdnSelfOnly; bool m_nxdnSelfOnly;
bool m_nxdnRemoteGateway; bool m_nxdnRemoteGateway;
unsigned int m_nxdnTXHang;
unsigned int m_nxdnModeHang; unsigned int m_nxdnModeHang;
bool m_pocsagEnabled; bool m_pocsagEnabled;
unsigned int m_pocsagFrequency; unsigned int m_pocsagFrequency;
bool m_fmEnabled;
std::string m_fmCallsign;
unsigned int m_fmCallsignSpeed;
unsigned int m_fmCallsignFrequency;
unsigned int m_fmCallsignTime;
unsigned int m_fmCallsignHoldoff;
float m_fmCallsignHighLevel;
float m_fmCallsignLowLevel;
bool m_fmCallsignAtStart;
bool m_fmCallsignAtEnd;
bool m_fmCallsignAtLatch;
std::string m_fmRFAck;
std::string m_fmExtAck;
unsigned int m_fmAckSpeed;
unsigned int m_fmAckFrequency;
unsigned int m_fmAckMinTime;
unsigned int m_fmAckDelay;
float m_fmAckLevel;
unsigned int m_fmTimeout;
float m_fmTimeoutLevel;
float m_fmCTCSSFrequency;
unsigned int m_fmCTCSSHighThreshold;
unsigned int m_fmCTCSSLowThreshold;
float m_fmCTCSSLevel;
unsigned int m_fmKerchunkTime;
unsigned int m_fmHangTime;
bool m_fmUseCOS;
bool m_fmCOSInvert;
unsigned int m_fmRFAudioBoost;
float m_fmMaxDevLevel;
unsigned int m_fmExtAudioBoost;
bool m_dstarNetworkEnabled; bool m_dstarNetworkEnabled;
std::string m_dstarGatewayAddress; std::string m_dstarGatewayAddress;
unsigned int m_dstarGatewayPort; unsigned int m_dstarGatewayPort;
@ -497,6 +569,7 @@ private:
unsigned int m_mobileGPSPort; unsigned int m_mobileGPSPort;
bool m_remoteControlEnabled; bool m_remoteControlEnabled;
std::string m_remoteControlAddress;
unsigned int m_remoteControlPort; unsigned int m_remoteControlPort;
}; };

View file

@ -36,6 +36,7 @@ const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType) : CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType) :
m_addressStr(address), m_addressStr(address),
m_address(), m_address(),
m_addrlen(),
m_port(port), m_port(port),
m_id(NULL), m_id(NULL),
m_password(password), m_password(password),
@ -73,7 +74,7 @@ m_beacon(false)
assert(id > 1000U); assert(id > 1000U);
assert(!password.empty()); assert(!password.empty());
m_address = CUDPSocket::lookup(address); CUDPSocket::lookup(m_addressStr, m_port, m_address, m_addrlen);
m_buffer = new unsigned char[BUFFER_LENGTH]; m_buffer = new unsigned char[BUFFER_LENGTH];
m_salt = new unsigned char[sizeof(uint32_t)]; m_salt = new unsigned char[sizeof(uint32_t)];
@ -124,8 +125,8 @@ bool CDMRNetwork::open()
{ {
LogMessage("DMR, Opening DMR Network"); LogMessage("DMR, Opening DMR Network");
if (m_address.s_addr == INADDR_NONE) if (CUDPSocket::isnone(m_address))
m_address = CUDPSocket::lookup(m_addressStr); CUDPSocket::lookup(m_addressStr, m_port, m_address, m_addrlen);
m_status = WAITING_CONNECT; m_status = WAITING_CONNECT;
m_timeoutTimer.stop(); m_timeoutTimer.stop();
@ -361,7 +362,7 @@ void CDMRNetwork::clock(unsigned int ms)
if (m_status == WAITING_CONNECT) { if (m_status == WAITING_CONNECT) {
m_retryTimer.clock(ms); m_retryTimer.clock(ms);
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
bool ret = m_socket.open(); bool ret = m_socket.open(m_address.ss_family);
if (ret) { if (ret) {
ret = writeLogin(); ret = writeLogin();
if (!ret) if (!ret)
@ -377,9 +378,9 @@ void CDMRNetwork::clock(unsigned int ms)
return; return;
} }
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port); int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen);
if (length < 0) { if (length < 0) {
LogError("DMR, Socket has failed, retrying connection to the master"); LogError("DMR, Socket has failed, retrying connection to the master");
close(); close();
@ -390,7 +391,7 @@ void CDMRNetwork::clock(unsigned int ms)
// if (m_debug && length > 0) // if (m_debug && length > 0)
// CUtils::dump(1U, "Network Received", m_buffer, length); // CUtils::dump(1U, "Network Received", m_buffer, length);
if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) { if (length > 0 && CUDPSocket::match(m_address, address)) {
if (::memcmp(m_buffer, "DMRD", 4U) == 0) { if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
if (m_enabled) { if (m_enabled) {
if (m_debug) if (m_debug)
@ -663,7 +664,7 @@ bool CDMRNetwork::write(const unsigned char* data, unsigned int length)
// if (m_debug) // if (m_debug)
// CUtils::dump(1U, "Network Transmitted", data, length); // CUtils::dump(1U, "Network Transmitted", data, length);
bool ret = m_socket.write(data, length, m_address, m_port); bool ret = m_socket.write(data, length, m_address, m_addrlen);
if (!ret) { if (!ret) {
LogError("DMR, Socket has failed when writing data to the master, retrying connection"); LogError("DMR, Socket has failed when writing data to the master, retrying connection");
m_socket.close(); m_socket.close();

View file

@ -60,7 +60,8 @@ public:
private: private:
std::string m_addressStr; std::string m_addressStr;
in_addr m_address; sockaddr_storage m_address;
unsigned int m_addrlen;
unsigned int m_port; unsigned int m_port;
uint8_t* m_id; uint8_t* m_id;
std::string m_password; std::string m_password;

View file

@ -33,7 +33,7 @@ const unsigned int BUFFER_LENGTH = 100U;
CDStarNetwork::CDStarNetwork(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool duplex, const char* version, bool debug) : CDStarNetwork::CDStarNetwork(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool duplex, const char* version, bool debug) :
m_socket(localPort), m_socket(localPort),
m_address(), m_address(),
m_port(gatewayPort), m_addrlen(),
m_duplex(duplex), m_duplex(duplex),
m_version(version), m_version(version),
m_debug(debug), m_debug(debug),
@ -46,7 +46,7 @@ m_pollTimer(1000U, 60U),
m_linkStatus(LS_NONE), m_linkStatus(LS_NONE),
m_linkReflector(NULL) m_linkReflector(NULL)
{ {
m_address = CUDPSocket::lookup(gatewayAddress); CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH]; m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
@ -63,12 +63,12 @@ bool CDStarNetwork::open()
{ {
LogMessage("Opening D-Star network connection"); LogMessage("Opening D-Star network connection");
if (m_address.s_addr == INADDR_NONE) if (CUDPSocket::isnone(m_address))
return false; return false;
m_pollTimer.start(); m_pollTimer.start();
return m_socket.open(); return m_socket.open(m_address.ss_family);
} }
bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length, bool busy) bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length, bool busy)
@ -100,7 +100,7 @@ bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length
CUtils::dump(1U, "D-Star Network Header Sent", buffer, 49U); CUtils::dump(1U, "D-Star Network Header Sent", buffer, 49U);
for (unsigned int i = 0U; i < 2U; i++) { for (unsigned int i = 0U; i < 2U; i++) {
bool ret = m_socket.write(buffer, 49U, m_address, m_port); bool ret = m_socket.write(buffer, 49U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
} }
@ -143,7 +143,7 @@ bool CDStarNetwork::writeData(const unsigned char* data, unsigned int length, un
if (m_debug) if (m_debug)
CUtils::dump(1U, "D-Star Network Data Sent", buffer, length + 9U); CUtils::dump(1U, "D-Star Network Data Sent", buffer, length + 9U);
return m_socket.write(buffer, length + 9U, m_address, m_port); return m_socket.write(buffer, length + 9U, m_address, m_addrlen);
} }
bool CDStarNetwork::writePoll(const char* text) bool CDStarNetwork::writePoll(const char* text)
@ -167,7 +167,7 @@ bool CDStarNetwork::writePoll(const char* text)
// if (m_debug) // if (m_debug)
// CUtils::dump(1U, "D-Star Network Poll Sent", buffer, 6U + length); // CUtils::dump(1U, "D-Star Network Poll Sent", buffer, 6U + length);
return m_socket.write(buffer, 6U + length, m_address, m_port); return m_socket.write(buffer, 6U + length, m_address, m_addrlen);
} }
void CDStarNetwork::clock(unsigned int ms) void CDStarNetwork::clock(unsigned int ms)
@ -192,18 +192,12 @@ void CDStarNetwork::clock(unsigned int ms)
unsigned char buffer[BUFFER_LENGTH]; unsigned char buffer[BUFFER_LENGTH];
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0) if (length <= 0 || !CUDPSocket::match(m_address, address))
return; return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || m_port != port) {
LogMessage("D-Star packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Invalid packet type? // Invalid packet type?
if (::memcmp(buffer, "DSRP", 4U) != 0) if (::memcmp(buffer, "DSRP", 4U) != 0)
return; return;

View file

@ -51,8 +51,8 @@ public:
private: private:
CUDPSocket m_socket; CUDPSocket m_socket;
in_addr m_address; sockaddr_storage m_address;
unsigned int m_port; unsigned int m_addrlen;
bool m_duplex; bool m_duplex;
const char* m_version; const char* m_version;
bool m_debug; bool m_debug;

View file

@ -26,6 +26,9 @@ const unsigned char MODE_YSF = 3U;
const unsigned char MODE_P25 = 4U; const unsigned char MODE_P25 = 4U;
const unsigned char MODE_NXDN = 5U; const unsigned char MODE_NXDN = 5U;
const unsigned char MODE_POCSAG = 6U; const unsigned char MODE_POCSAG = 6U;
const unsigned char MODE_FM = 10U;
const unsigned char MODE_CW = 98U; const unsigned char MODE_CW = 98U;
const unsigned char MODE_LOCKOUT = 99U; const unsigned char MODE_LOCKOUT = 99U;
const unsigned char MODE_ERROR = 100U; const unsigned char MODE_ERROR = 100U;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -101,6 +101,17 @@ void CDisplay::setQuit()
setQuitInt(); setQuitInt();
} }
void CDisplay::setFM()
{
m_timer1.stop();
m_timer2.stop();
m_mode1 = MODE_FM;
m_mode2 = MODE_FM;
setFMInt();
}
void CDisplay::writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CDisplay::writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);
@ -190,6 +201,7 @@ void CDisplay::writeDMRBER(unsigned int slotNo, float ber)
{ {
writeDMRBERInt(slotNo, ber); writeDMRBERInt(slotNo, ber);
} }
void CDisplay::clearDMR(unsigned int slotNo) void CDisplay::clearDMR(unsigned int slotNo)
{ {
if (slotNo == 1U) { if (slotNo == 1U) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -42,6 +42,7 @@ public:
void setLockout(); void setLockout();
void setError(const char* text); void setError(const char* text);
void setQuit(); void setQuit();
void setFM();
void writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); void writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
void writeDStarRSSI(unsigned char rssi); void writeDStarRSSI(unsigned char rssi);
@ -87,6 +88,7 @@ protected:
virtual void setLockoutInt() = 0; virtual void setLockoutInt() = 0;
virtual void setErrorInt(const char* text) = 0; virtual void setErrorInt(const char* text) = 0;
virtual void setQuitInt() = 0; virtual void setQuitInt() = 0;
virtual void setFMInt() = 0;
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0; virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0;
virtual void writeDStarRSSIInt(unsigned char rssi); virtual void writeDStarRSSIInt(unsigned char rssi);

View file

@ -399,6 +399,37 @@ void CHD44780::setQuitInt()
m_dmr = false; m_dmr = false;
} }
void CHD44780::setFMInt()
{
m_clockDisplayTimer.stop();
::lcdClear(m_fd);
#ifdef ADAFRUIT_DISPLAY
adafruitLCDColour(AC_WHITE);
#endif
if (m_pwm) {
if (m_pwmPin != 1U)
::softPwmWrite(m_pwmPin, m_pwmDim);
else
::pwmWrite(m_pwmPin, (m_pwmDim / 100) * 1024);
}
// Print callsign and ID at on top row for all screen sizes
::lcdPosition(m_fd, 0, 0);
::lcdPrintf(m_fd, "%-6s", m_callsign.c_str());
::lcdPosition(m_fd, m_cols - 7, 0);
::lcdPrintf(m_fd, "%7u", m_dmrid);
// Print MMDVM and Idle on bottom row for all screen sizes
::lcdPosition(m_fd, 0, m_rows - 1);
::lcdPuts(m_fd, "MMDVM");
::lcdPosition(m_fd, m_cols - 4, m_rows - 1);
::lcdPuts(m_fd, "FM"); // Gets overwritten by clock on 2 line screen
m_dmr = false;
}
void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX & Tony Corbett G0WFV * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -101,6 +101,7 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi); virtual void writeDStarRSSIInt(unsigned char rssi);

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2016,2017,2018 by Tony Corbett G0WFV * Copyright (C) 2016,2017,2018 by Tony Corbett G0WFV
* Copyright (C) 2018 by Jonathan Naylor G4KLX * Copyright (C) 2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -121,44 +121,53 @@ CLCDproc::~CLCDproc()
bool CLCDproc::open() bool CLCDproc::open()
{ {
const char *server; int err;
unsigned int port, localPort; unsigned int addrlen;
struct sockaddr_in serverAddress, clientAddress; std::string port, localPort;
struct hostent *h; struct sockaddr_storage serverAddress, clientAddress;
struct addrinfo hints, *res;
server = m_address.c_str(); port = std::to_string(m_port);
port = m_port; localPort = std::to_string(m_localPort);
localPort = m_localPort; memset(&hints, 0, sizeof(hints));
/* Lookup the hostname address */
hints.ai_flags = AI_NUMERICSERV;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(m_address.c_str(), port.c_str(), &hints, &res);
if (err) {
LogError("LCDproc, cannot lookup server");
return false;
}
memcpy(&serverAddress, res->ai_addr, addrlen = res->ai_addrlen);
freeaddrinfo(res);
/* Lookup the client address (random port - need to specify manual port from ini file) */
hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
hints.ai_family = serverAddress.ss_family;
err = getaddrinfo(NULL, localPort.c_str(), &hints, &res);
if (err) {
LogError("LCDproc, cannot lookup client");
return false;
}
memcpy(&clientAddress, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
/* Create TCP socket */ /* Create TCP socket */
m_socketfd = socket(AF_INET, SOCK_STREAM, 0); m_socketfd = socket(clientAddress.ss_family, SOCK_STREAM, 0);
if (m_socketfd == -1) { if (m_socketfd == -1) {
LogError("LCDproc, failed to create socket"); LogError("LCDproc, failed to create socket");
return false; return false;
} }
/* Sets client address (random port - need to specify manual port from ini file?) */
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
//clientAddress.sin_port = htons(0);
clientAddress.sin_port = htons(localPort);
/* Bind the address to the socket */ /* Bind the address to the socket */
if (bind(m_socketfd, (struct sockaddr *)&clientAddress, sizeof(clientAddress)) == -1) { if (bind(m_socketfd, (struct sockaddr *)&clientAddress, addrlen) == -1) {
LogError("LCDproc, error whilst binding address"); LogError("LCDproc, error whilst binding address");
return false; return false;
} }
/* Lookup the hostname address */ /* Connect to server */
h = gethostbyname(server); if (connect(m_socketfd, (struct sockaddr *)&serverAddress, addrlen) == -1) {
/* Sets server address */
serverAddress.sin_family = h->h_addrtype;
memcpy((char*)&serverAddress.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
serverAddress.sin_port = htons(port);
if (connect(m_socketfd, (struct sockaddr * )&serverAddress, sizeof(serverAddress))==-1) {
LogError("LCDproc, cannot connect to server"); LogError("LCDproc, cannot connect to server");
return false; return false;
} }
@ -241,6 +250,23 @@ void CLCDproc::setQuitInt()
m_dmr = false; m_dmr = false;
} }
void CLCDproc::setFMInt()
{
m_clockDisplayTimer.stop(); // Stop the clock display
if (m_screensDefined) {
socketPrintf(m_socketfd, "screen_set DStar -priority hidden");
socketPrintf(m_socketfd, "screen_set DMR -priority hidden");
socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
socketPrintf(m_socketfd, "widget_set Status Status %u %u FM", m_cols - 6, m_rows);
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
}
m_dmr = false;
}
void CLCDproc::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CLCDproc::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);
@ -294,7 +320,7 @@ void CLCDproc::clearDStarInt()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 Listening"); socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 8"); // Set LED4 color green socketPrintf(m_socketfd, "output 8"); // Set LED4 color green
@ -387,7 +413,7 @@ void CLCDproc::clearDMRInt(unsigned int slotNo)
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
} }
} else { } else {
socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 Listening"); socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
} }
@ -435,7 +461,7 @@ void CLCDproc::clearFusionInt()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 Listening"); socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 4"); // Set LED3 color green socketPrintf(m_socketfd, "output 4"); // Set LED3 color green
@ -480,7 +506,7 @@ void CLCDproc::clearP25Int()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 Listening"); socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 2"); // Set LED2 color green socketPrintf(m_socketfd, "output 2"); // Set LED2 color green
@ -525,7 +551,7 @@ void CLCDproc::clearNXDNInt()
{ {
m_clockDisplayTimer.stop(); // Stop the clock display m_clockDisplayTimer.stop(); // Stop the clock display
socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 Listening"); socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 16"); // Set LED5 color green socketPrintf(m_socketfd, "output 16"); // Set LED5 color green
@ -752,7 +778,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add DStar Line4 scroller"); socketPrintf(m_socketfd, "widget_add DStar Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 Listening"); socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\"");
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\"");
*/ */
@ -773,8 +799,8 @@ void CLCDproc::defineScreens()
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2); socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2);
socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1); socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1);
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 Listening"); socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 Listening"); socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 \"Listening\"");
*/ */
// The YSF Screen // The YSF Screen
@ -788,7 +814,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add YSF Line4 scroller"); socketPrintf(m_socketfd, "widget_add YSF Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 Listening"); socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \"");
socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \""); socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \"");
*/ */
@ -804,7 +830,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add P25 Line4 scroller"); socketPrintf(m_socketfd, "widget_add P25 Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 Listening"); socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \"");
socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \""); socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \"");
*/ */
@ -820,7 +846,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller"); socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller");
/* Do we need to pre-populate the values?? /* Do we need to pre-populate the values??
socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 Listening"); socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 \"Listening\"");
socketPrintf(m_socketfd, "widget_set NXDN Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set NXDN Line3 3 1 15 1 h 3 \" \"");
socketPrintf(m_socketfd, "widget_set NXDN Line4 4 2 15 2 h 3 \" \""); socketPrintf(m_socketfd, "widget_set NXDN Line4 4 2 15 2 h 3 \" \"");
*/ */

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2016,2017 by Tony Corbett G0WFV * Copyright (C) 2016,2017 by Tony Corbett G0WFV
* Copyright (C) 2018 by Jonathan Naylor G4KLX * Copyright (C) 2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -40,8 +40,8 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi); virtual void writeDStarRSSIInt(unsigned char rssi);
virtual void clearDStarInt(); virtual void clearDStarInt();

20
Log.cpp
View file

@ -22,6 +22,7 @@
#include <Windows.h> #include <Windows.h>
#else #else
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h>
#endif #endif
#include <cstdio> #include <cstdio>
@ -36,6 +37,7 @@ static std::string m_filePath;
static std::string m_fileRoot; static std::string m_fileRoot;
static FILE* m_fpLog = NULL; static FILE* m_fpLog = NULL;
static bool m_daemon = false;
static unsigned int m_displayLevel = 2U; static unsigned int m_displayLevel = 2U;
@ -45,6 +47,8 @@ static char LEVELS[] = " DMIWEF";
static bool LogOpen() static bool LogOpen()
{ {
bool status = false;
if (m_fileLevel == 0U) if (m_fileLevel == 0U)
return true; return true;
@ -68,18 +72,28 @@ static bool LogOpen()
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); ::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif #endif
m_fpLog = ::fopen(filename, "a+t"); if ((m_fpLog = ::fopen(filename, "a+t")) != NULL)
{
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon)
dup2(fileno(m_fpLog), fileno(stderr));
#endif
}
m_tm = *tm; m_tm = *tm;
return m_fpLog != NULL; return status;
} }
bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel) bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel)
{ {
m_filePath = filePath; m_filePath = filePath;
m_fileRoot = fileRoot; m_fileRoot = fileRoot;
m_fileLevel = fileLevel; m_fileLevel = fileLevel;
m_displayLevel = displayLevel; m_displayLevel = displayLevel;
m_daemon = daemon;
return ::LogOpen(); return ::LogOpen();
} }

2
Log.h
View file

@ -30,7 +30,7 @@
extern void Log(unsigned int level, const char* fmt, ...); extern void Log(unsigned int level, const char* fmt, ...);
extern bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel); extern bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel);
extern void LogFinalise(); extern void LogFinalise();
#endif #endif

View file

@ -43,7 +43,7 @@ Time=24
[Modem] [Modem]
# Port=/dev/ttyACM0 # Port=/dev/ttyACM0
# Port=/dev/ttyAMA0 # Port=/dev/ttyAMA0
Port=\\.\COM3 Port=\\.\COM4
Protocol=uart Protocol=uart
# Address=0x22 # Address=0x22
TXInvert=1 TXInvert=1
@ -65,6 +65,7 @@ RFLevel=100
# P25TXLevel=50 # P25TXLevel=50
# NXDNTXLevel=50 # NXDNTXLevel=50
# POCSAGTXLevel=50 # POCSAGTXLevel=50
# FMTXLevel=50
RSSIMappingFile=RSSI.dat RSSIMappingFile=RSSI.dat
Trace=0 Trace=0
Debug=0 Debug=0
@ -125,6 +126,7 @@ NAC=293
SelfOnly=0 SelfOnly=0
OverrideUIDCheck=0 OverrideUIDCheck=0
RemoteGateway=0 RemoteGateway=0
TXHang=5
# ModeHang=10 # ModeHang=10
[NXDN] [NXDN]
@ -132,12 +134,47 @@ Enable=1
RAN=1 RAN=1
SelfOnly=0 SelfOnly=0
RemoteGateway=0 RemoteGateway=0
TXHang=5
# ModeHang=10 # ModeHang=10
[POCSAG] [POCSAG]
Enable=1 Enable=1
Frequency=439987500 Frequency=439987500
[FM]
Enable=1
# Callsign=G4KLX
CallsignSpeed=20
CallsignFrequency=1000
CallsignTime=10
CallsignHoldoff=0
CallsignHighLevel=50
CallsignLowLevel=20
CallsignAtStart=1
CallsignAtEnd=1
CallsignAtLatch=0
RFAck=K
ExtAck=N
AckSpeed=20
AckFrequency=1750
AckMinTime=4
AckDelay=1000
AckLevel=50
# Timeout=180
TimeoutLevel=80
CTCSSFrequency=88.4
CTCSSThreshold=30
# CTCSSHighThreshold=30
# CTCSSLowThreshold=20
CTCSSLevel=20
KerchunkTime=0
HangTime=7
UseCOS=1
COSInvert=0
RFAudioBoost=1
MaxDevLevel=90
ExtAudioBoost=1
[D-Star Network] [D-Star Network]
Enable=1 Enable=1
GatewayAddress=127.0.0.1 GatewayAddress=127.0.0.1
@ -257,4 +294,5 @@ Port=7834
[Remote Control] [Remote Control]
Enable=0 Enable=0
Address=127.0.0.1
Port=7642 Port=7642

View file

@ -150,6 +150,7 @@ m_ysfEnabled(false),
m_p25Enabled(false), m_p25Enabled(false),
m_nxdnEnabled(false), m_nxdnEnabled(false),
m_pocsagEnabled(false), m_pocsagEnabled(false),
m_fmEnabled(false),
m_cwIdTime(0U), m_cwIdTime(0U),
m_dmrLookup(NULL), m_dmrLookup(NULL),
m_nxdnLookup(NULL), m_nxdnLookup(NULL),
@ -236,7 +237,11 @@ int CMMDVMHost::run()
#endif #endif
#endif #endif
ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel()); #if !defined(_WIN32) && !defined(_WIN64)
ret = ::LogInitialise(m_daemon, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel());
#else
ret = ::LogInitialise(false, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel());
#endif
if (!ret) { if (!ret) {
::fprintf(stderr, "MMDVMHost: unable to open the log file\n"); ::fprintf(stderr, "MMDVMHost: unable to open the log file\n");
return 1; return 1;
@ -246,7 +251,6 @@ int CMMDVMHost::run()
if (m_daemon) { if (m_daemon) {
::close(STDIN_FILENO); ::close(STDIN_FILENO);
::close(STDOUT_FILENO); ::close(STDOUT_FILENO);
::close(STDERR_FILENO);
} }
#endif #endif
@ -316,8 +320,8 @@ int CMMDVMHost::run()
return 1; return 1;
} }
in_addr transparentAddress; sockaddr_storage transparentAddress;
unsigned int transparentPort = 0U; unsigned int transparentAddrLen;
CUDPSocket* transparentSocket = NULL; CUDPSocket* transparentSocket = NULL;
unsigned int sendFrameType = 0U; unsigned int sendFrameType = 0U;
@ -333,11 +337,10 @@ int CMMDVMHost::run()
LogInfo(" Local Port: %u", localPort); LogInfo(" Local Port: %u", localPort);
LogInfo(" Send Frame Type: %u", sendFrameType); LogInfo(" Send Frame Type: %u", sendFrameType);
transparentAddress = CUDPSocket::lookup(remoteAddress); CUDPSocket::lookup(remoteAddress, remotePort, transparentAddress, transparentAddrLen);
transparentPort = remotePort;
transparentSocket = new CUDPSocket(localPort); transparentSocket = new CUDPSocket(localPort);
ret = transparentSocket->open(); ret = transparentSocket->open(transparentAddress.ss_family);
if (!ret) { if (!ret) {
LogWarning("Could not open the Transparent data socket, disabling"); LogWarning("Could not open the Transparent data socket, disabling");
delete transparentSocket; delete transparentSocket;
@ -546,12 +549,13 @@ int CMMDVMHost::run()
} }
if (m_p25Enabled) { if (m_p25Enabled) {
unsigned int id = m_conf.getP25Id(); unsigned int id = m_conf.getP25Id();
unsigned int nac = m_conf.getP25NAC(); unsigned int nac = m_conf.getP25NAC();
bool uidOverride = m_conf.getP25OverrideUID(); unsigned int txHang = m_conf.getP25TXHang();
bool selfOnly = m_conf.getP25SelfOnly(); bool uidOverride = m_conf.getP25OverrideUID();
bool remoteGateway = m_conf.getP25RemoteGateway(); bool selfOnly = m_conf.getP25SelfOnly();
m_p25RFModeHang = m_conf.getP25ModeHang(); bool remoteGateway = m_conf.getP25RemoteGateway();
m_p25RFModeHang = m_conf.getP25ModeHang();
LogInfo("P25 RF Parameters"); LogInfo("P25 RF Parameters");
LogInfo(" Id: %u", id); LogInfo(" Id: %u", id);
@ -559,6 +563,7 @@ int CMMDVMHost::run()
LogInfo(" UID Override: %s", uidOverride ? "yes" : "no"); LogInfo(" UID Override: %s", uidOverride ? "yes" : "no");
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no"); LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no"); LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
LogInfo(" TX Hang: %us", txHang);
LogInfo(" Mode Hang: %us", m_p25RFModeHang); LogInfo(" Mode Hang: %us", m_p25RFModeHang);
m_p25 = new CP25Control(nac, id, selfOnly, uidOverride, m_p25Network, m_display, m_timeout, m_duplex, m_dmrLookup, remoteGateway, rssi); m_p25 = new CP25Control(nac, id, selfOnly, uidOverride, m_p25Network, m_display, m_timeout, m_duplex, m_dmrLookup, remoteGateway, rssi);
@ -576,17 +581,19 @@ int CMMDVMHost::run()
m_nxdnLookup = new CNXDNLookup(lookupFile, reloadTime); m_nxdnLookup = new CNXDNLookup(lookupFile, reloadTime);
m_nxdnLookup->read(); m_nxdnLookup->read();
unsigned int id = m_conf.getNXDNId(); unsigned int id = m_conf.getNXDNId();
unsigned int ran = m_conf.getNXDNRAN(); unsigned int ran = m_conf.getNXDNRAN();
bool selfOnly = m_conf.getNXDNSelfOnly(); bool selfOnly = m_conf.getNXDNSelfOnly();
bool remoteGateway = m_conf.getNXDNRemoteGateway(); bool remoteGateway = m_conf.getNXDNRemoteGateway();
m_nxdnRFModeHang = m_conf.getNXDNModeHang(); unsigned int txHang = m_conf.getNXDNTXHang();
m_nxdnRFModeHang = m_conf.getNXDNModeHang();
LogInfo("NXDN RF Parameters"); LogInfo("NXDN RF Parameters");
LogInfo(" Id: %u", id); LogInfo(" Id: %u", id);
LogInfo(" RAN: %u", ran); LogInfo(" RAN: %u", ran);
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no"); LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no"); LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
LogInfo(" TX Hang: %us", txHang);
LogInfo(" Mode Hang: %us", m_nxdnRFModeHang); LogInfo(" Mode Hang: %us", m_nxdnRFModeHang);
m_nxdn = new CNXDNControl(ran, id, selfOnly, m_nxdnNetwork, m_display, m_timeout, m_duplex, remoteGateway, m_nxdnLookup, rssi); m_nxdn = new CNXDNControl(ran, id, selfOnly, m_nxdnNetwork, m_display, m_timeout, m_duplex, remoteGateway, m_nxdnLookup, rssi);
@ -602,17 +609,20 @@ int CMMDVMHost::run()
m_pocsag = new CPOCSAGControl(m_pocsagNetwork, m_display); m_pocsag = new CPOCSAGControl(m_pocsagNetwork, m_display);
pocsagTimer.start(); if (m_pocsagNetwork != NULL)
pocsagTimer.start();
} }
bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); bool remoteControlEnabled = m_conf.getRemoteControlEnabled();
if (remoteControlEnabled) { if (remoteControlEnabled) {
std::string address = m_conf.getRemoteControlAddress();
unsigned int port = m_conf.getRemoteControlPort(); unsigned int port = m_conf.getRemoteControlPort();
LogInfo("Remote Control Parameters"); LogInfo("Remote Control Parameters");
LogInfo(" Address: %s", address.c_str());
LogInfo(" Port: %u", port); LogInfo(" Port: %u", port);
m_remoteControl = new CRemoteControl(port); m_remoteControl = new CRemoteControl(address, port);
ret = m_remoteControl->open(); ret = m_remoteControl->open();
if (!ret) { if (!ret) {
@ -642,6 +652,12 @@ int CMMDVMHost::run()
else if (!error && m_mode == MODE_ERROR) else if (!error && m_mode == MODE_ERROR)
setMode(MODE_IDLE); setMode(MODE_IDLE);
unsigned char mode = m_modem->getMode();
if (mode == MODE_FM && m_mode != MODE_FM)
setMode(mode);
else if (mode != MODE_FM && m_mode == MODE_FM)
setMode(mode);
if (m_ump != NULL) { if (m_ump != NULL) {
bool tx = m_modem->hasTX(); bool tx = m_modem->hasTX();
m_ump->setTX(tx); m_ump->setTX(tx);
@ -793,7 +809,7 @@ int CMMDVMHost::run()
len = m_modem->readTransparentData(data); len = m_modem->readTransparentData(data);
if (transparentSocket != NULL && len > 0U) if (transparentSocket != NULL && len > 0U)
transparentSocket->write(data, len, transparentAddress, transparentPort); transparentSocket->write(data, len, transparentAddress, transparentAddrLen);
if (!m_fixedMode) { if (!m_fixedMode) {
if (m_modeTimer.isRunning() && m_modeTimer.hasExpired()) if (m_modeTimer.isRunning() && m_modeTimer.hasExpired())
@ -942,9 +958,9 @@ int CMMDVMHost::run()
} }
if (transparentSocket != NULL) { if (transparentSocket != NULL) {
in_addr address; sockaddr_storage address;
unsigned int port = 0U; unsigned int addrlen;
len = transparentSocket->read(data, 200U, address, port); len = transparentSocket->read(data, 200U, address, addrlen);
if (len > 0U) if (len > 0U)
m_modem->writeTransparentData(data, len); m_modem->writeTransparentData(data, len);
} }
@ -1149,11 +1165,14 @@ bool CMMDVMHost::createModem()
float p25TXLevel = m_conf.getModemP25TXLevel(); float p25TXLevel = m_conf.getModemP25TXLevel();
float nxdnTXLevel = m_conf.getModemNXDNTXLevel(); float nxdnTXLevel = m_conf.getModemNXDNTXLevel();
float pocsagTXLevel = m_conf.getModemPOCSAGTXLevel(); float pocsagTXLevel = m_conf.getModemPOCSAGTXLevel();
float fmTXLevel = m_conf.getModemFMTXLevel();
bool trace = m_conf.getModemTrace(); bool trace = m_conf.getModemTrace();
bool debug = m_conf.getModemDebug(); bool debug = m_conf.getModemDebug();
unsigned int colorCode = m_conf.getDMRColorCode(); unsigned int colorCode = m_conf.getDMRColorCode();
bool lowDeviation = m_conf.getFusionLowDeviation(); bool lowDeviation = m_conf.getFusionLowDeviation();
unsigned int txHang = m_conf.getFusionTXHang(); unsigned int ysfTXHang = m_conf.getFusionTXHang();
unsigned int p25TXHang = m_conf.getP25TXHang();
unsigned int nxdnTXHang = m_conf.getNXDNTXHang();
unsigned int rxFrequency = m_conf.getRXFrequency(); unsigned int rxFrequency = m_conf.getRXFrequency();
unsigned int txFrequency = m_conf.getTXFrequency(); unsigned int txFrequency = m_conf.getTXFrequency();
unsigned int pocsagFrequency = m_conf.getPOCSAGFrequency(); unsigned int pocsagFrequency = m_conf.getPOCSAGFrequency();
@ -1186,16 +1205,87 @@ bool CMMDVMHost::createModem()
LogInfo(" P25 TX Level: %.1f%%", p25TXLevel); LogInfo(" P25 TX Level: %.1f%%", p25TXLevel);
LogInfo(" NXDN TX Level: %.1f%%", nxdnTXLevel); LogInfo(" NXDN TX Level: %.1f%%", nxdnTXLevel);
LogInfo(" POCSAG TX Level: %.1f%%", pocsagTXLevel); LogInfo(" POCSAG TX Level: %.1f%%", pocsagTXLevel);
LogInfo(" RX Frequency: %uHz (%uHz)", rxFrequency, rxFrequency + rxOffset); LogInfo(" FM TX Level: %.1f%%", fmTXLevel);
LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset); LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset);
m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug);
m_modem->setSerialParams(protocol,address); m_modem->setSerialParams(protocol,address);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled); m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel); m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel);
m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency); m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency);
m_modem->setDMRParams(colorCode); m_modem->setDMRParams(colorCode);
m_modem->setYSFParams(lowDeviation, txHang); m_modem->setYSFParams(lowDeviation, ysfTXHang);
m_modem->setP25Params(p25TXHang);
m_modem->setNXDNParams(nxdnTXHang);
if (m_fmEnabled) {
std::string callsign = m_conf.getFMCallsign();
unsigned int callsignSpeed = m_conf.getFMCallsignSpeed();
unsigned int callsignFrequency = m_conf.getFMCallsignFrequency();
unsigned int callsignTime = m_conf.getFMCallsignTime();
unsigned int callsignHoldoff = m_conf.getFMCallsignHoldoff();
float callsignHighLevel = m_conf.getFMCallsignHighLevel();
float callsignLowLevel = m_conf.getFMCallsignLowLevel();
bool callsignAtStart = m_conf.getFMCallsignAtStart();
bool callsignAtEnd = m_conf.getFMCallsignAtEnd();
bool callsignAtLatch = m_conf.getFMCallsignAtLatch();
std::string rfAck = m_conf.getFMRFAck();
std::string extAck = m_conf.getFMExtAck();
unsigned int ackSpeed = m_conf.getFMAckSpeed();
unsigned int ackFrequency = m_conf.getFMAckFrequency();
unsigned int ackMinTime = m_conf.getFMAckMinTime();
unsigned int ackDelay = m_conf.getFMAckDelay();
float ackLevel = m_conf.getFMAckLevel();
unsigned int timeout = m_conf.getFMTimeout();
float timeoutLevel = m_conf.getFMTimeoutLevel();
float ctcssFrequency = m_conf.getFMCTCSSFrequency();
unsigned int ctcssHighThreshold = m_conf.getFMCTCSSHighThreshold();
unsigned int ctcssLowThreshold = m_conf.getFMCTCSSLowThreshold();
float ctcssLevel = m_conf.getFMCTCSSLevel();
unsigned int kerchunkTime = m_conf.getFMKerchunkTime();
unsigned int hangTime = m_conf.getFMHangTime();
bool useCOS = m_conf.getFMUseCOS();
bool cosInvert = m_conf.getFMCOSInvert();
unsigned int rfAudioBoost = m_conf.getFMRFAudioBoost();
float maxDevLevel = m_conf.getFMMaxDevLevel();
unsigned int extAudioBoost = m_conf.getFMExtAudioBoost();
LogInfo("FM Parameters");
LogInfo(" Callsign: %s", callsign.c_str());
LogInfo(" Callsign Speed: %uWPM", callsignSpeed);
LogInfo(" Callsign Frequency: %uHz", callsignFrequency);
LogInfo(" Callsign Time: %umins", callsignTime);
LogInfo(" Callsign Holdoff: 1/%u", callsignHoldoff);
LogInfo(" Callsign High Level: %.1f%%", callsignHighLevel);
LogInfo(" Callsign Low Level: %.1f%%", callsignLowLevel);
LogInfo(" Callsign At Start: %s", callsignAtStart ? "yes" : "no");
LogInfo(" Callsign At End: %s", callsignAtEnd ? "yes" : "no");
LogInfo(" Callsign At Latch: %s", callsignAtLatch ? "yes" : "no");
LogInfo(" RF Ack: %s", rfAck.c_str());
// LogInfo(" Ext. Ack: %s", extAck.c_str());
LogInfo(" Ack Speed: %uWPM", ackSpeed);
LogInfo(" Ack Frequency: %uHz", ackFrequency);
LogInfo(" Ack Min Time: %us", ackMinTime);
LogInfo(" Ack Delay: %ums", ackDelay);
LogInfo(" Ack Level: %.1f%%", ackLevel);
LogInfo(" Timeout: %us", timeout);
LogInfo(" Timeout Level: %.1f%%", timeoutLevel);
LogInfo(" CTCSS Frequency: %.1fHz", ctcssFrequency);
LogInfo(" CTCSS High Threshold: %u", ctcssHighThreshold);
LogInfo(" CTCSS Low Threshold: %u", ctcssLowThreshold);
LogInfo(" CTCSS Level: %.1f%%", ctcssLevel);
LogInfo(" Kerchunk Time: %us", kerchunkTime);
LogInfo(" Hang Time: %us", hangTime);
LogInfo(" Use COS: %s", useCOS ? "yes" : "no");
LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no");
LogInfo(" RF Audio Boost: x%u", rfAudioBoost);
LogInfo(" Max. Deviation Level: %.1f%%", maxDevLevel);
// LogInfo(" Ext. Audio Boost: x%u", extAudioBoost);
m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch);
m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel);
m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel);
}
bool ret = m_modem->open(); bool ret = m_modem->open();
if (!ret) { if (!ret) {
@ -1450,6 +1540,7 @@ void CMMDVMHost::readParams()
m_p25Enabled = m_conf.getP25Enabled(); m_p25Enabled = m_conf.getP25Enabled();
m_nxdnEnabled = m_conf.getNXDNEnabled(); m_nxdnEnabled = m_conf.getNXDNEnabled();
m_pocsagEnabled = m_conf.getPOCSAGEnabled(); m_pocsagEnabled = m_conf.getPOCSAGEnabled();
m_fmEnabled = m_conf.getFMEnabled();
m_duplex = m_conf.getDuplex(); m_duplex = m_conf.getDuplex();
m_callsign = m_conf.getCallsign(); m_callsign = m_conf.getCallsign();
m_id = m_conf.getId(); m_id = m_conf.getId();
@ -1466,6 +1557,7 @@ void CMMDVMHost::readParams()
LogInfo(" P25: %s", m_p25Enabled ? "enabled" : "disabled"); LogInfo(" P25: %s", m_p25Enabled ? "enabled" : "disabled");
LogInfo(" NXDN: %s", m_nxdnEnabled ? "enabled" : "disabled"); LogInfo(" NXDN: %s", m_nxdnEnabled ? "enabled" : "disabled");
LogInfo(" POCSAG: %s", m_pocsagEnabled ? "enabled" : "disabled"); LogInfo(" POCSAG: %s", m_pocsagEnabled ? "enabled" : "disabled");
LogInfo(" FM: %s", m_fmEnabled ? "enabled" : "disabled");
} }
void CMMDVMHost::setMode(unsigned char mode) void CMMDVMHost::setMode(unsigned char mode)
@ -1682,8 +1774,45 @@ void CMMDVMHost::setMode(unsigned char mode)
createLockFile("POCSAG"); createLockFile("POCSAG");
break; break;
case MODE_FM:
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);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
m_dmr->enable(false);
if (m_ysf != NULL)
m_ysf->enable(false);
if (m_p25 != NULL)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false);
m_dmrTXTimer.stop();
}
if (m_ump != NULL)
m_ump->setMode(MODE_FM);
m_display->setFM();
m_mode = MODE_FM;
m_modeTimer.stop();
m_cwIdTimer.stop();
createLockFile("FM");
break;
case MODE_LOCKOUT: case MODE_LOCKOUT:
LogMessage("Mode set to Lockout");
if (m_dstarNetwork != NULL) if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(false); m_dstarNetwork->enable(false);
if (m_dmrNetwork != NULL) if (m_dmrNetwork != NULL)
@ -1863,6 +1992,58 @@ void CMMDVMHost::remoteControl()
if (m_nxdn != NULL) if (m_nxdn != NULL)
processModeCommand(MODE_NXDN, m_nxdnRFModeHang); processModeCommand(MODE_NXDN, m_nxdnRFModeHang);
break; break;
case RCD_MODE_FM:
if (m_fmEnabled != false)
processModeCommand(MODE_FM, 0);
break;
case RCD_ENABLE_DSTAR:
if (m_dstar != NULL && m_dstarEnabled==false)
processEnableCommand(m_dstarEnabled, true);
break;
case RCD_ENABLE_DMR:
if (m_dmr != NULL && m_dmrEnabled==false)
processEnableCommand(m_dmrEnabled, true);
break;
case RCD_ENABLE_YSF:
if (m_ysf != NULL && m_ysfEnabled==false)
processEnableCommand(m_ysfEnabled, true);
break;
case RCD_ENABLE_P25:
if (m_p25 != NULL && m_p25Enabled==false)
processEnableCommand(m_p25Enabled, true);
break;
case RCD_ENABLE_NXDN:
if (m_nxdn != NULL && m_nxdnEnabled==false)
processEnableCommand(m_nxdnEnabled, true);
break;
case RCD_ENABLE_FM:
if (m_fmEnabled==false)
processEnableCommand(m_fmEnabled, true);
break;
case RCD_DISABLE_DSTAR:
if (m_dstar != NULL && m_dstarEnabled==true)
processEnableCommand(m_dstarEnabled, false);
break;
case RCD_DISABLE_DMR:
if (m_dmr != NULL && m_dmrEnabled==true)
processEnableCommand(m_dmrEnabled, false);
break;
case RCD_DISABLE_YSF:
if (m_ysf != NULL && m_ysfEnabled==true)
processEnableCommand(m_ysfEnabled, false);
break;
case RCD_DISABLE_P25:
if (m_p25 != NULL && m_p25Enabled==true)
processEnableCommand(m_p25Enabled, false);
break;
case RCD_DISABLE_NXDN:
if (m_nxdn != NULL && m_nxdnEnabled==true)
processEnableCommand(m_nxdnEnabled, false);
break;
case RCD_DISABLE_FM:
if (m_fmEnabled == true)
processEnableCommand(m_fmEnabled, false);
break;
case RCD_PAGE: case RCD_PAGE:
if (m_pocsag != NULL) { if (m_pocsag != NULL) {
unsigned int ric = m_remoteControl->getArgUInt(0U); unsigned int ric = m_remoteControl->getArgUInt(0U);
@ -1874,6 +2055,18 @@ void CMMDVMHost::remoteControl()
} }
m_pocsag->sendPage(ric, text); m_pocsag->sendPage(ric, text);
} }
case RCD_CW:
setMode(MODE_IDLE); // Force the modem to go idle so that we can send the CW text.
if (!m_modem->hasTX()){
std::string cwtext;
for (unsigned int i = 0U; i < m_remoteControl->getArgCount(); i++) {
if (i > 0U)
cwtext += " ";
cwtext += m_remoteControl->getArgString(i);
}
m_display->writeCW();
m_modem->sendCWId(cwtext);
}
default: default:
break; break;
} }
@ -1896,3 +2089,12 @@ void CMMDVMHost::processModeCommand(unsigned char mode, unsigned int timeout)
setMode(mode); setMode(mode);
} }
void CMMDVMHost::processEnableCommand(bool& mode, bool enabled)
{
LogDebug("Setting mode current=%s new=%s",mode ? "true" : "false",enabled ? "true" : "false");
mode=enabled;
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled);
if (!m_modem->writeConfig())
LogError("Cannot write Config to MMDVM");
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -93,6 +93,7 @@ private:
bool m_p25Enabled; bool m_p25Enabled;
bool m_nxdnEnabled; bool m_nxdnEnabled;
bool m_pocsagEnabled; bool m_pocsagEnabled;
bool m_fmEnabled;
unsigned int m_cwIdTime; unsigned int m_cwIdTime;
CDMRLookup* m_dmrLookup; CDMRLookup* m_dmrLookup;
CNXDNLookup* m_nxdnLookup; CNXDNLookup* m_nxdnLookup;
@ -116,6 +117,7 @@ private:
void remoteControl(); void remoteControl();
void processModeCommand(unsigned char mode, unsigned int timeout); void processModeCommand(unsigned char mode, unsigned int timeout);
void processEnableCommand(bool& mode, bool enabled);
void setMode(unsigned char mode); void setMode(unsigned char mode);

View file

@ -238,6 +238,8 @@
<ClInclude Include="Timer.h" /> <ClInclude Include="Timer.h" />
<ClInclude Include="UDPSocket.h" /> <ClInclude Include="UDPSocket.h" />
<ClInclude Include="UMP.h" /> <ClInclude Include="UMP.h" />
<ClInclude Include="UserDB.h" />
<ClInclude Include="UserDBentry.h" />
<ClInclude Include="Utils.h" /> <ClInclude Include="Utils.h" />
<ClInclude Include="Version.h" /> <ClInclude Include="Version.h" />
<ClInclude Include="YSFControl.h" /> <ClInclude Include="YSFControl.h" />
@ -327,6 +329,8 @@
<ClCompile Include="Timer.cpp" /> <ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPSocket.cpp" /> <ClCompile Include="UDPSocket.cpp" />
<ClCompile Include="UMP.cpp" /> <ClCompile Include="UMP.cpp" />
<ClCompile Include="UserDB.cpp" />
<ClCompile Include="UserDBentry.cpp" />
<ClCompile Include="Utils.cpp" /> <ClCompile Include="Utils.cpp" />
<ClCompile Include="YSFNetwork.cpp" /> <ClCompile Include="YSFNetwork.cpp" />
<ClCompile Include="YSFPayload.cpp" /> <ClCompile Include="YSFPayload.cpp" />

View file

@ -293,6 +293,12 @@
<ClInclude Include="TFTSurenoo.h"> <ClInclude Include="TFTSurenoo.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="UserDB.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UserDBentry.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="BPTC19696.cpp"> <ClCompile Include="BPTC19696.cpp">
@ -550,5 +556,11 @@
<ClCompile Include="TFTSurenoo.cpp"> <ClCompile Include="TFTSurenoo.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="UserDB.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UserDBentry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -26,7 +26,7 @@
CMobileGPS::CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network) : CMobileGPS::CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network) :
m_idTimer(1000U, 60U), m_idTimer(1000U, 60U),
m_address(), m_address(),
m_port(port), m_addrlen(),
m_socket(), m_socket(),
m_network(network) m_network(network)
{ {
@ -34,7 +34,7 @@ m_network(network)
assert(port > 0U); assert(port > 0U);
assert(network != NULL); assert(network != NULL);
m_address = CUDPSocket::lookup(address); CUDPSocket::lookup(address, port, m_address, m_addrlen);
} }
CMobileGPS::~CMobileGPS() CMobileGPS::~CMobileGPS()
@ -43,7 +43,7 @@ CMobileGPS::~CMobileGPS()
bool CMobileGPS::open() bool CMobileGPS::open()
{ {
bool ret = m_socket.open(); bool ret = m_socket.open(m_address.ss_family);
if (!ret) if (!ret)
return false; return false;
@ -71,16 +71,16 @@ void CMobileGPS::close()
bool CMobileGPS::pollGPS() bool CMobileGPS::pollGPS()
{ {
return m_socket.write((unsigned char*)"MMDVMHost", 9U, m_address, m_port); return m_socket.write((unsigned char*)"MMDVMHost", 9U, m_address, m_addrlen);
} }
void CMobileGPS::sendReport() void CMobileGPS::sendReport()
{ {
// Grab GPS data if it's available // Grab GPS data if it's available
unsigned char buffer[200U]; unsigned char buffer[200U];
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int ret = m_socket.read(buffer, 200U, address, port); int ret = m_socket.read(buffer, 200U, address, addrlen);
if (ret <= 0) if (ret <= 0)
return; return;

View file

@ -51,8 +51,8 @@ public:
private: private:
CTimer m_idTimer; CTimer m_idTimer;
in_addr m_address; sockaddr_storage m_address;
unsigned int m_port; unsigned int m_addrlen;
CUDPSocket m_socket; CUDPSocket m_socket;
CDMRNetwork* m_network; CDMRNetwork* m_network;

336
Modem.cpp
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011-2018 by Jonathan Naylor G4KLX * Copyright (C) 2011-2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -76,6 +76,10 @@ const unsigned char MMDVM_NXDN_LOST = 0x41U;
const unsigned char MMDVM_POCSAG_DATA = 0x50U; const unsigned char MMDVM_POCSAG_DATA = 0x50U;
const unsigned char MMDVM_FM_PARAMS1 = 0x60U;
const unsigned char MMDVM_FM_PARAMS2 = 0x61U;
const unsigned char MMDVM_FM_PARAMS3 = 0x62U;
const unsigned char MMDVM_ACK = 0x70U; const unsigned char MMDVM_ACK = 0x70U;
const unsigned char MMDVM_NAK = 0x7FU; const unsigned char MMDVM_NAK = 0x7FU;
@ -100,6 +104,8 @@ m_port(port),
m_dmrColorCode(0U), m_dmrColorCode(0U),
m_ysfLoDev(false), m_ysfLoDev(false),
m_ysfTXHang(4U), m_ysfTXHang(4U),
m_p25TXHang(5U),
m_nxdnTXHang(5U),
m_duplex(duplex), m_duplex(duplex),
m_rxInvert(rxInvert), m_rxInvert(rxInvert),
m_txInvert(txInvert), m_txInvert(txInvert),
@ -114,6 +120,7 @@ m_ysfTXLevel(0U),
m_p25TXLevel(0U), m_p25TXLevel(0U),
m_nxdnTXLevel(0U), m_nxdnTXLevel(0U),
m_pocsagTXLevel(0U), m_pocsagTXLevel(0U),
m_fmTXLevel(0U),
m_trace(trace), m_trace(trace),
m_debug(debug), m_debug(debug),
m_rxFrequency(0U), m_rxFrequency(0U),
@ -125,6 +132,7 @@ m_ysfEnabled(false),
m_p25Enabled(false), m_p25Enabled(false),
m_nxdnEnabled(false), m_nxdnEnabled(false),
m_pocsagEnabled(false), m_pocsagEnabled(false),
m_fmEnabled(false),
m_rxDCOffset(0), m_rxDCOffset(0),
m_txDCOffset(0), m_txDCOffset(0),
m_serial(NULL), m_serial(NULL),
@ -161,11 +169,40 @@ m_tx(false),
m_cd(false), m_cd(false),
m_lockout(false), m_lockout(false),
m_error(false), m_error(false),
m_hwType(HWT_UNKNOWN) m_mode(MODE_IDLE),
m_hwType(HWT_UNKNOWN),
m_fmCallsign(),
m_fmCallsignSpeed(20U),
m_fmCallsignFrequency(1000U),
m_fmCallsignTime(600U),
m_fmCallsignHoldoff(0U),
m_fmCallsignHighLevel(35.0F),
m_fmCallsignLowLevel(15.0F),
m_fmCallsignAtStart(true),
m_fmCallsignAtEnd(true),
m_fmCallsignAtLatch(true),
m_fmRfAck("K"),
m_fmAckSpeed(20U),
m_fmAckFrequency(1750U),
m_fmAckMinTime(4U),
m_fmAckDelay(1000U),
m_fmAckLevel(80.0F),
m_fmTimeout(120U),
m_fmTimeoutLevel(80.0F),
m_fmCtcssFrequency(88.4F),
m_fmCtcssHighThreshold(30U),
m_fmCtcssLowThreshold(20U),
m_fmCtcssLevel(10.0F),
m_fmKerchunkTime(0U),
m_fmHangTime(5U),
m_fmUseCOS(true),
m_fmCOSInvert(false),
m_fmRFAudioBoost(1U),
m_fmMaxDevLevel(90.0F)
{ {
assert(!port.empty());
m_buffer = new unsigned char[BUFFER_LENGTH]; m_buffer = new unsigned char[BUFFER_LENGTH];
assert(!port.empty());
} }
CModem::~CModem() CModem::~CModem()
@ -193,7 +230,7 @@ void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int tx
m_pocsagFrequency = pocsagFrequency + txOffset; m_pocsagFrequency = pocsagFrequency + txOffset;
} }
void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled) void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled)
{ {
m_dstarEnabled = dstarEnabled; m_dstarEnabled = dstarEnabled;
m_dmrEnabled = dmrEnabled; m_dmrEnabled = dmrEnabled;
@ -201,9 +238,10 @@ void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled,
m_p25Enabled = p25Enabled; m_p25Enabled = p25Enabled;
m_nxdnEnabled = nxdnEnabled; m_nxdnEnabled = nxdnEnabled;
m_pocsagEnabled = pocsagEnabled; m_pocsagEnabled = pocsagEnabled;
m_fmEnabled = fmEnabled;
} }
void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel) void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel)
{ {
m_rxLevel = rxLevel; m_rxLevel = rxLevel;
m_cwIdTXLevel = cwIdTXLevel; m_cwIdTXLevel = cwIdTXLevel;
@ -213,6 +251,7 @@ void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, flo
m_p25TXLevel = p25TXLevel; m_p25TXLevel = p25TXLevel;
m_nxdnTXLevel = nxdnTXLevel; m_nxdnTXLevel = nxdnTXLevel;
m_pocsagTXLevel = pocsagTXLevel; m_pocsagTXLevel = pocsagTXLevel;
m_fmTXLevel = fmTXLevel;
} }
void CModem::setDMRParams(unsigned int colorCode) void CModem::setDMRParams(unsigned int colorCode)
@ -228,6 +267,16 @@ void CModem::setYSFParams(bool loDev, unsigned int txHang)
m_ysfTXHang = txHang; m_ysfTXHang = txHang;
} }
void CModem::setP25Params(unsigned int txHang)
{
m_p25TXHang = txHang;
}
void CModem::setNXDNParams(unsigned int txHang)
{
m_nxdnTXHang = txHang;
}
void CModem::setTransparentDataParams(unsigned int sendFrameType) void CModem::setTransparentDataParams(unsigned int sendFrameType)
{ {
m_sendTransparentDataFrameType = sendFrameType; m_sendTransparentDataFrameType = sendFrameType;
@ -269,6 +318,32 @@ bool CModem::open()
return false; return false;
} }
if (m_fmEnabled && m_duplex) {
ret = setFMCallsignParams();
if (!ret) {
m_serial->close();
delete m_serial;
m_serial = NULL;
return false;
}
ret = setFMAckParams();
if (!ret) {
m_serial->close();
delete m_serial;
m_serial = NULL;
return false;
}
ret = setFMMiscParams();
if (!ret) {
m_serial->close();
delete m_serial;
m_serial = NULL;
return false;
}
}
m_statusTimer.start(); m_statusTimer.start();
m_error = false; m_error = false;
@ -518,6 +593,8 @@ void CModem::clock(unsigned int ms)
m_nxdnSpace = 0U; m_nxdnSpace = 0U;
m_pocsagSpace = 0U; m_pocsagSpace = 0U;
m_mode = m_buffer[4U];
m_tx = (m_buffer[5U] & 0x01U) == 0x01U; m_tx = (m_buffer[5U] & 0x01U) == 0x01U;
bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U; bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U;
@ -1429,6 +1506,11 @@ bool CModem::readStatus()
return m_serial->write(buffer, 3U) == 3; return m_serial->write(buffer, 3U) == 3;
} }
bool CModem::writeConfig()
{
return setConfig();
}
bool CModem::setConfig() bool CModem::setConfig()
{ {
assert(m_serial != NULL); assert(m_serial != NULL);
@ -1437,7 +1519,7 @@ bool CModem::setConfig()
buffer[0U] = MMDVM_FRAME_START; buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 21U; buffer[1U] = 24U;
buffer[2U] = MMDVM_SET_CONFIG; buffer[2U] = MMDVM_SET_CONFIG;
@ -1468,6 +1550,8 @@ bool CModem::setConfig()
buffer[4U] |= 0x10U; buffer[4U] |= 0x10U;
if (m_pocsagEnabled) if (m_pocsagEnabled)
buffer[4U] |= 0x20U; buffer[4U] |= 0x20U;
if (m_fmEnabled && m_duplex)
buffer[4U] |= 0x40U;
buffer[5U] = m_txDelay / 10U; // In 10ms units buffer[5U] = m_txDelay / 10U; // In 10ms units
@ -1497,10 +1581,16 @@ bool CModem::setConfig()
buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F); buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F);
// CUtils::dump(1U, "Written", buffer, 21U); buffer[21U] = (unsigned char)(m_fmTXLevel * 2.55F + 0.5F);
int ret = m_serial->write(buffer, 21U); buffer[22U] = (unsigned char)m_p25TXHang;
if (ret != 21)
buffer[23U] = (unsigned char)m_nxdnTXHang;
// CUtils::dump(1U, "Written", buffer, 24U);
int ret = m_serial->write(buffer, 24U);
if (ret != 24)
return false; return false;
unsigned int count = 0U; unsigned int count = 0U;
@ -1706,6 +1796,11 @@ HW_TYPE CModem::getHWType() const
return m_hwType; return m_hwType;
} }
unsigned char CModem::getMode() const
{
return m_mode;
}
bool CModem::setMode(unsigned char mode) bool CModem::setMode(unsigned char mode)
{ {
assert(m_serial != NULL); assert(m_serial != NULL);
@ -1811,6 +1906,227 @@ bool CModem::writeDMRShortLC(const unsigned char* lc)
return m_serial->write(buffer, 12U) == 12; return m_serial->write(buffer, 12U) == 12;
} }
void CModem::setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch)
{
m_fmCallsign = callsign;
m_fmCallsignSpeed = callsignSpeed;
m_fmCallsignFrequency = callsignFrequency;
m_fmCallsignTime = callsignTime;
m_fmCallsignHoldoff = callsignHoldoff;
m_fmCallsignHighLevel = callsignHighLevel;
m_fmCallsignLowLevel = callsignLowLevel;
m_fmCallsignAtStart = callsignAtStart;
m_fmCallsignAtEnd = callsignAtEnd;
m_fmCallsignAtLatch = callsignAtLatch;
}
void CModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel)
{
m_fmRfAck = rfAck;
m_fmAckSpeed = ackSpeed;
m_fmAckFrequency = ackFrequency;
m_fmAckMinTime = ackMinTime;
m_fmAckDelay = ackDelay;
m_fmAckLevel = ackLevel;
}
void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel)
{
m_fmTimeout = timeout;
m_fmTimeoutLevel = timeoutLevel;
m_fmCtcssFrequency = ctcssFrequency;
m_fmCtcssHighThreshold = ctcssHighThreshold;
m_fmCtcssLowThreshold = ctcssLowThreshold;
m_fmCtcssLevel = ctcssLevel;
m_fmKerchunkTime = kerchunkTime;
m_fmHangTime = hangTime;
m_fmUseCOS = useCOS;
m_fmCOSInvert = cosInvert;
m_fmRFAudioBoost = rfAudioBoost;
m_fmMaxDevLevel = maxDevLevel;
}
bool CModem::setFMCallsignParams()
{
assert(m_serial != NULL);
unsigned char buffer[80U];
unsigned char len = 10U + m_fmCallsign.size();
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = len;
buffer[2U] = MMDVM_FM_PARAMS1;
buffer[3U] = m_fmCallsignSpeed;
buffer[4U] = m_fmCallsignFrequency / 10U;
buffer[5U] = m_fmCallsignTime;
buffer[6U] = m_fmCallsignHoldoff;
buffer[7U] = (unsigned char)(m_fmCallsignHighLevel * 2.55F + 0.5F);
buffer[8U] = (unsigned char)(m_fmCallsignLowLevel * 2.55F + 0.5F);
buffer[9U] = 0x00U;
if (m_fmCallsignAtStart)
buffer[9U] |= 0x01U;
if (m_fmCallsignAtEnd)
buffer[9U] |= 0x02U;
if (m_fmCallsignAtLatch)
buffer[9U] |= 0x04U;
for (unsigned int i = 0U; i < m_fmCallsign.size(); i++)
buffer[10U + i] = m_fmCallsign.at(i);
// CUtils::dump(1U, "Written", buffer, len);
int ret = m_serial->write(buffer, len);
if (ret != len)
return false;
unsigned int count = 0U;
RESP_TYPE_MMDVM resp;
do {
CThread::sleep(10U);
resp = getResponse();
if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) {
count++;
if (count >= MAX_RESPONSES) {
LogError("The MMDVM is not responding to the SET_FM_PARAMS1 command");
return false;
}
}
} while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK);
// CUtils::dump(1U, "Response", m_buffer, m_length);
if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) {
LogError("Received a NAK to the SET_FM_PARAMS1 command from the modem");
return false;
}
return true;
}
bool CModem::setFMAckParams()
{
assert(m_serial != NULL);
unsigned char buffer[80U];
unsigned char len = 8U + m_fmRfAck.size();
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = len;
buffer[2U] = MMDVM_FM_PARAMS2;
buffer[3U] = m_fmAckSpeed;
buffer[4U] = m_fmAckFrequency / 10U;
buffer[5U] = m_fmAckMinTime;
buffer[6U] = m_fmAckDelay / 10U;
buffer[7U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F);
for (unsigned int i = 0U; i < m_fmRfAck.size(); i++)
buffer[8U + i] = m_fmRfAck.at(i);
// CUtils::dump(1U, "Written", buffer, len);
int ret = m_serial->write(buffer, len);
if (ret != len)
return false;
unsigned int count = 0U;
RESP_TYPE_MMDVM resp;
do {
CThread::sleep(10U);
resp = getResponse();
if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) {
count++;
if (count >= MAX_RESPONSES) {
LogError("The MMDVM is not responding to the SET_FM_PARAMS2 command");
return false;
}
}
} while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK);
// CUtils::dump(1U, "Response", m_buffer, m_length);
if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) {
LogError("Received a NAK to the SET_FM_PARAMS2 command from the modem");
return false;
}
return true;
}
bool CModem::setFMMiscParams()
{
assert(m_serial != NULL);
unsigned char buffer[20U];
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 15U;
buffer[2U] = MMDVM_FM_PARAMS3;
buffer[3U] = m_fmTimeout / 5U;
buffer[4U] = (unsigned char)(m_fmTimeoutLevel * 2.55F + 0.5F);
buffer[5U] = (unsigned char)m_fmCtcssFrequency;
buffer[6U] = m_fmCtcssHighThreshold;
buffer[7U] = m_fmCtcssLowThreshold;
buffer[8U] = (unsigned char)(m_fmCtcssLevel * 2.55F + 0.5F);
buffer[9U] = m_fmKerchunkTime;
buffer[10U] = m_fmHangTime;
buffer[11U] = 0x00U;
if (m_fmUseCOS)
buffer[11U] |= 0x01U;
if (m_fmCOSInvert)
buffer[11U] |= 0x02U;
buffer[12U] = m_fmRFAudioBoost;
buffer[13U] = (unsigned char)(m_fmMaxDevLevel * 2.55F + 0.5F);
buffer[14U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F);
// CUtils::dump(1U, "Written", buffer, 15U);
int ret = m_serial->write(buffer, 15U);
if (ret != 15)
return false;
unsigned int count = 0U;
RESP_TYPE_MMDVM resp;
do {
CThread::sleep(10U);
resp = getResponse();
if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) {
count++;
if (count >= MAX_RESPONSES) {
LogError("The MMDVM is not responding to the SET_FM_PARAMS3 command");
return false;
}
}
} while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK);
// CUtils::dump(1U, "Response", m_buffer, m_length);
if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) {
LogError("Received a NAK to the SET_FM_PARAMS3 command from the modem");
return false;
}
return true;
}
void CModem::printDebug() void CModem::printDebug()
{ {
if (m_buffer[2U] == MMDVM_DEBUG1) { if (m_buffer[2U] == MMDVM_DEBUG1) {

51
Modem.h
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011-2018 by Jonathan Naylor G4KLX * Copyright (C) 2011-2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -39,12 +39,18 @@ public:
virtual void setSerialParams(const std::string& protocol, unsigned int address); virtual void setSerialParams(const std::string& protocol, unsigned int address);
virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency);
virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled); virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled);
virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel); virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel);
virtual void setDMRParams(unsigned int colorCode); virtual void setDMRParams(unsigned int colorCode);
virtual void setYSFParams(bool loDev, unsigned int txHang); virtual void setYSFParams(bool loDev, unsigned int txHang);
virtual void setP25Params(unsigned int txHang);
virtual void setNXDNParams(unsigned int txHang);
virtual void setTransparentDataParams(unsigned int sendFrameType); virtual void setTransparentDataParams(unsigned int sendFrameType);
virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch);
virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel);
virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel);
virtual bool open(); virtual bool open();
virtual unsigned int readDStarData(unsigned char* data); virtual unsigned int readDStarData(unsigned char* data);
@ -71,6 +77,7 @@ public:
virtual bool hasLockout() const; virtual bool hasLockout() const;
virtual bool hasError() const; virtual bool hasError() const;
virtual bool writeConfig();
virtual bool writeDStarData(const unsigned char* data, unsigned int length); virtual bool writeDStarData(const unsigned char* data, unsigned int length);
virtual bool writeDMRData1(const unsigned char* data, unsigned int length); virtual bool writeDMRData1(const unsigned char* data, unsigned int length);
virtual bool writeDMRData2(const unsigned char* data, unsigned int length); virtual bool writeDMRData2(const unsigned char* data, unsigned int length);
@ -95,6 +102,7 @@ public:
virtual bool writeSerial(const unsigned char* data, unsigned int length); virtual bool writeSerial(const unsigned char* data, unsigned int length);
virtual unsigned char getMode() const;
virtual bool setMode(unsigned char mode); virtual bool setMode(unsigned char mode);
virtual bool sendCWId(const std::string& callsign); virtual bool sendCWId(const std::string& callsign);
@ -112,6 +120,8 @@ private:
unsigned int m_dmrColorCode; unsigned int m_dmrColorCode;
bool m_ysfLoDev; bool m_ysfLoDev;
unsigned int m_ysfTXHang; unsigned int m_ysfTXHang;
unsigned int m_p25TXHang;
unsigned int m_nxdnTXHang;
bool m_duplex; bool m_duplex;
bool m_rxInvert; bool m_rxInvert;
bool m_txInvert; bool m_txInvert;
@ -126,6 +136,7 @@ private:
float m_p25TXLevel; float m_p25TXLevel;
float m_nxdnTXLevel; float m_nxdnTXLevel;
float m_pocsagTXLevel; float m_pocsagTXLevel;
float m_fmTXLevel;
float m_rfLevel; float m_rfLevel;
bool m_trace; bool m_trace;
bool m_debug; bool m_debug;
@ -138,6 +149,7 @@ private:
bool m_p25Enabled; bool m_p25Enabled;
bool m_nxdnEnabled; bool m_nxdnEnabled;
bool m_pocsagEnabled; bool m_pocsagEnabled;
bool m_fmEnabled;
int m_rxDCOffset; int m_rxDCOffset;
int m_txDCOffset; int m_txDCOffset;
CSerialController* m_serial; CSerialController* m_serial;
@ -174,12 +186,45 @@ private:
bool m_cd; bool m_cd;
bool m_lockout; bool m_lockout;
bool m_error; bool m_error;
unsigned char m_mode;
HW_TYPE m_hwType; HW_TYPE m_hwType;
std::string m_fmCallsign;
unsigned int m_fmCallsignSpeed;
unsigned int m_fmCallsignFrequency;
unsigned int m_fmCallsignTime;
unsigned int m_fmCallsignHoldoff;
float m_fmCallsignHighLevel;
float m_fmCallsignLowLevel;
bool m_fmCallsignAtStart;
bool m_fmCallsignAtEnd;
bool m_fmCallsignAtLatch;
std::string m_fmRfAck;
unsigned int m_fmAckSpeed;
unsigned int m_fmAckFrequency;
unsigned int m_fmAckMinTime;
unsigned int m_fmAckDelay;
float m_fmAckLevel;
unsigned int m_fmTimeout;
float m_fmTimeoutLevel;
float m_fmCtcssFrequency;
unsigned int m_fmCtcssHighThreshold;
unsigned int m_fmCtcssLowThreshold;
float m_fmCtcssLevel;
unsigned int m_fmKerchunkTime;
unsigned int m_fmHangTime;
bool m_fmUseCOS;
bool m_fmCOSInvert;
unsigned int m_fmRFAudioBoost;
float m_fmMaxDevLevel;
bool readVersion(); bool readVersion();
bool readStatus(); bool readStatus();
bool setConfig(); bool setConfig();
bool setFrequency(); bool setFrequency();
bool setFMCallsignParams();
bool setFMAckParams();
bool setFMMiscParams();
void printDebug(); void printDebug();

View file

@ -31,7 +31,7 @@ const unsigned int BUFFER_LENGTH = 200U;
CNXDNNetwork::CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : CNXDNNetwork::CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) :
m_socket(localAddress, localPort), m_socket(localAddress, localPort),
m_address(), m_address(),
m_port(gatewayPort), m_addrlen(),
m_debug(debug), m_debug(debug),
m_enabled(false), m_enabled(false),
m_buffer(1000U, "NXDN Network") m_buffer(1000U, "NXDN Network")
@ -39,7 +39,7 @@ m_buffer(1000U, "NXDN Network")
assert(gatewayPort > 0U); assert(gatewayPort > 0U);
assert(!gatewayAddress.empty()); assert(!gatewayAddress.empty());
m_address = CUDPSocket::lookup(gatewayAddress); CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
} }
CNXDNNetwork::~CNXDNNetwork() CNXDNNetwork::~CNXDNNetwork()
@ -50,7 +50,7 @@ bool CNXDNNetwork::open()
{ {
LogMessage("Opening NXDN network connection"); LogMessage("Opening NXDN network connection");
if (m_address.s_addr == INADDR_NONE) if (CUDPSocket::isnone(m_address))
return false; return false;
return m_socket.open(); return m_socket.open();
@ -100,25 +100,19 @@ bool CNXDNNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE ty
if (m_debug) if (m_debug)
CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U); CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U);
return m_socket.write(buffer, 102U, m_address, m_port); return m_socket.write(buffer, 102U, m_address, m_addrlen);
} }
void CNXDNNetwork::clock(unsigned int ms) void CNXDNNetwork::clock(unsigned int ms)
{ {
unsigned char buffer[BUFFER_LENGTH]; unsigned char buffer[BUFFER_LENGTH];
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0) if (length <= 0 || !CUDPSocket::match(m_address, address))
return; return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || port != m_port) {
LogMessage("NXDN packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Invalid packet type? // Invalid packet type?
if (::memcmp(buffer, "ICOM", 4U) != 0) if (::memcmp(buffer, "ICOM", 4U) != 0)
return; return;

View file

@ -57,8 +57,8 @@ public:
private: private:
CUDPSocket m_socket; CUDPSocket m_socket;
in_addr m_address; sockaddr_storage m_address;
unsigned int m_port; unsigned int m_addrlen;
bool m_debug; bool m_debug;
bool m_enabled; bool m_enabled;
CRingBuffer<unsigned char> m_buffer; CRingBuffer<unsigned char> m_buffer;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -102,7 +102,6 @@ bool CNextion::open()
return true; return true;
} }
void CNextion::setIdleInt() void CNextion::setIdleInt()
{ {
// a few bits borrowed from Lieven De Samblanx ON7LDS, NextionDriver // a few bits borrowed from Lieven De Samblanx ON7LDS, NextionDriver
@ -240,6 +239,25 @@ void CNextion::setQuitInt()
m_mode = MODE_QUIT; m_mode = MODE_QUIT;
} }
void CNextion::setFMInt()
{
sendCommand("page MMDVM");
sendCommandAction(1U);
char command[20];
if (m_brightness > 0) {
::sprintf(command, "dim=%u", m_brightness);
sendCommand(command);
}
sendCommand("t0.txt=\"FM\"");
sendCommandAction(15U);
m_clockDisplayTimer.stop();
m_mode = MODE_FM;
}
void CNextion::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CNextion::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -41,6 +41,7 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi); virtual void writeDStarRSSIInt(unsigned char rssi);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -60,6 +60,10 @@ void CNullDisplay::setQuitInt()
{ {
} }
void CNullDisplay::setFMInt()
{
}
void CNullDisplay::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CNullDisplay::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
#if defined(RASPBERRY_PI) #if defined(RASPBERRY_PI)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -38,6 +38,7 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt(); virtual void clearDStarInt();

View file

@ -32,8 +32,8 @@ public:
virtual void setSerialParams(const std::string& protocol, unsigned int address){}; virtual void setSerialParams(const std::string& protocol, unsigned int address){};
virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency){}; virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency){};
virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled){}; virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled){};
virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel){}; virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel){};
virtual void setDMRParams(unsigned int colorCode){}; virtual void setDMRParams(unsigned int colorCode){};
virtual void setYSFParams(bool loDev, unsigned int txHang){}; virtual void setYSFParams(bool loDev, unsigned int txHang){};
virtual void setTransparentDataParams(unsigned int sendFrameType){}; virtual void setTransparentDataParams(unsigned int sendFrameType){};

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -306,6 +306,21 @@ void COLED::setQuitInt()
m_display.display(); m_display.display();
} }
void COLED::setFMInt()
{
m_mode = MODE_FM;
m_display.clearDisplay();
OLED_statusbar();
m_display.setCursor(0,30);
m_display.setTextSize(3);
m_display.print("FM");
m_display.setTextSize(1);
m_display.display();
}
void COLED::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void COLED::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
m_mode = MODE_DSTAR; m_mode = MODE_DSTAR;

3
OLED.h
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -50,6 +50,7 @@ public:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt(); virtual void clearDStarInt();

View file

@ -90,13 +90,13 @@ const unsigned int BUFFER_LENGTH = 100U;
CP25Network::CP25Network(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool debug) : CP25Network::CP25Network(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool debug) :
m_socket(localPort), m_socket(localPort),
m_address(), m_address(),
m_port(gatewayPort), m_addrlen(),
m_debug(debug), m_debug(debug),
m_enabled(false), m_enabled(false),
m_buffer(1000U, "P25 Network"), m_buffer(1000U, "P25 Network"),
m_audio() m_audio()
{ {
m_address = CUDPSocket::lookup(gatewayAddress); CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
} }
CP25Network::~CP25Network() CP25Network::~CP25Network()
@ -107,10 +107,10 @@ bool CP25Network::open()
{ {
LogMessage("Opening P25 network connection"); LogMessage("Opening P25 network connection");
if (m_address.s_addr == INADDR_NONE) if (CUDPSocket::isnone(m_address))
return false; return false;
return m_socket.open(); return m_socket.open(m_address.ss_family);
} }
bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, const CP25LowSpeedData& lsd, bool end) bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, const CP25LowSpeedData& lsd, bool end)
@ -126,7 +126,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 22U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 22U);
bool ret = m_socket.write(buffer, 22U, m_address, m_port); bool ret = m_socket.write(buffer, 22U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -137,7 +137,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 14U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 14U);
ret = m_socket.write(buffer, 14U, m_address, m_port); ret = m_socket.write(buffer, 14U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -150,7 +150,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -165,7 +165,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -180,7 +180,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -191,7 +191,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -202,7 +202,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -213,7 +213,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -226,7 +226,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 16U); CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 16U);
ret = m_socket.write(buffer, 16U, m_address, m_port); ret = m_socket.write(buffer, 16U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -234,7 +234,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network END Sent", REC80, 17U); CUtils::dump(1U, "P25 Network END Sent", REC80, 17U);
ret = m_socket.write(REC80, 17U, m_address, m_port); ret = m_socket.write(REC80, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
} }
@ -255,7 +255,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 22U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 22U);
bool ret = m_socket.write(buffer, 22U, m_address, m_port); bool ret = m_socket.write(buffer, 22U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -266,7 +266,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 14U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 14U);
ret = m_socket.write(buffer, 14U, m_address, m_port); ret = m_socket.write(buffer, 14U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -283,7 +283,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -297,7 +297,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -311,7 +311,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -326,7 +326,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -337,7 +337,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -348,7 +348,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U);
ret = m_socket.write(buffer, 17U, m_address, m_port); ret = m_socket.write(buffer, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -361,7 +361,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 16U); CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 16U);
ret = m_socket.write(buffer, 16U, m_address, m_port); ret = m_socket.write(buffer, 16U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
@ -369,7 +369,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug) if (m_debug)
CUtils::dump(1U, "P25 Network END Sent", REC80, 17U); CUtils::dump(1U, "P25 Network END Sent", REC80, 17U);
ret = m_socket.write(REC80, 17U, m_address, m_port); ret = m_socket.write(REC80, 17U, m_address, m_addrlen);
if (!ret) if (!ret)
return false; return false;
} }
@ -381,18 +381,12 @@ void CP25Network::clock(unsigned int ms)
{ {
unsigned char buffer[BUFFER_LENGTH]; unsigned char buffer[BUFFER_LENGTH];
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0) if (length <= 0 || !CUDPSocket::match(m_address, address))
return; return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || m_port != port) {
LogMessage("P25 packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
if (!m_enabled) if (!m_enabled)
return; return;

View file

@ -49,8 +49,8 @@ public:
private: private:
CUDPSocket m_socket; CUDPSocket m_socket;
in_addr m_address; sockaddr_storage m_address;
unsigned int m_port; unsigned int m_addrlen;
bool m_debug; bool m_debug;
bool m_enabled; bool m_enabled;
CRingBuffer<unsigned char> m_buffer; CRingBuffer<unsigned char> m_buffer;

View file

@ -31,12 +31,12 @@ const unsigned int BUFFER_LENGTH = 200U;
CPOCSAGNetwork::CPOCSAGNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : CPOCSAGNetwork::CPOCSAGNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) :
m_socket(myAddress, myPort), m_socket(myAddress, myPort),
m_address(), m_address(),
m_port(gatewayPort), m_addrlen(),
m_debug(debug), m_debug(debug),
m_enabled(false), m_enabled(false),
m_buffer(1000U, "POCSAG Network") m_buffer(1000U, "POCSAG Network")
{ {
m_address = CUDPSocket::lookup(gatewayAddress); CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
} }
CPOCSAGNetwork::~CPOCSAGNetwork() CPOCSAGNetwork::~CPOCSAGNetwork()
@ -47,7 +47,7 @@ bool CPOCSAGNetwork::open()
{ {
LogMessage("Opening POCSAG network connection"); LogMessage("Opening POCSAG network connection");
if (m_address.s_addr == INADDR_NONE) if (CUDPSocket::isnone(m_address))
return false; return false;
return m_socket.open(); return m_socket.open();
@ -57,18 +57,12 @@ void CPOCSAGNetwork::clock(unsigned int ms)
{ {
unsigned char buffer[BUFFER_LENGTH]; unsigned char buffer[BUFFER_LENGTH];
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0) if (length <= 0 || !CUDPSocket::match(m_address, address))
return; 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? // Invalid packet type?
if (::memcmp(buffer, "POCSAG", 6U) != 0) if (::memcmp(buffer, "POCSAG", 6U) != 0)
return; return;
@ -118,7 +112,7 @@ void CPOCSAGNetwork::enable(bool enabled)
unsigned char c = enabled ? 0x00U : 0xFFU; unsigned char c = enabled ? 0x00U : 0xFFU;
m_socket.write(&c, 1U, m_address, m_port); m_socket.write(&c, 1U, m_address, m_addrlen);
m_enabled = enabled; m_enabled = enabled;
} }

View file

@ -46,8 +46,8 @@ public:
private: private:
CUDPSocket m_socket; CUDPSocket m_socket;
in_addr m_address; sockaddr_storage m_address;
unsigned int m_port; unsigned int m_addrlen;
bool m_debug; bool m_debug;
bool m_enabled; bool m_enabled;
CRingBuffer<unsigned char> m_buffer; CRingBuffer<unsigned char> m_buffer;

View file

@ -1,8 +1,21 @@
These are the source files for building the MMDVMHost, the program that interfaces to the MMDVM or DVMega on the one side, and a suitable network on the other. It supports D-Star, DMR, P25 Phase 1, NXDN, System Fusion, and POCSAG paging on the MMDVM, and D-Star, DMR, and System Fusion on the DVMega. These are the source files for building the MMDVMHost, the program that
interfaces to the MMDVM or DVMega on the one side, and a suitable network on
the other. It supports D-Star, DMR, P25 Phase 1, NXDN, System Fusion,
POCSAG, and FM on the MMDVM, and D-Star, DMR, and System Fusion on the DVMega.
On the D-Star side the MMDVMHost interfaces with the ircDDB Gateway, on DMR it can connect to BrandMeister, DMR+, HB Link, XLX or [DMRGateway](https://github.com/g4klx/DMRGateway) (to connect to multiple DMR networks at once) on System Fusion it connects to the YSF Gateway to allow access to the FCS and YSF networks. On P25 it connects to the P25 Gateway. On NXDN it connects to the NXDN Gateway which provides access to the NXDN and NXCore talk groups. Finally it uses the DAPNET Gateway to access DAPNET to receive paging messages. On the D-Star side the MMDVMHost interfaces with the ircDDB Gateway, on DMR it
can connect to BrandMeister, DMR+, TGIF, HB Link, XLX or
[DMRGateway](https://github.com/g4klx/DMRGateway) (to connect to multiple DMR
networks at once) on System Fusion it connects to the YSF Gateway to allow
access to the FCS and YSF networks. On P25 it connects to the P25 Gateway. On
NXDN it connects to the NXDN Gateway which provides access to the NXDN and
NXCore talk groups. It uses the DAPNET Gateway to access DAPNET to receive
paging messages. Finally it uses the FM Gateway to interface to existing FM
networks.
It builds on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2017 on x86 and x64. It can optionally control various Displays. Currently these are: It builds on 32-bit and 64-bit Linux as well as on Windows using Visual Studio
2019 on x86 and x64. It can optionally control various Displays. Currently
these are:
- HD44780 (sizes 2x16, 2x40, 4x16, 4x20) - HD44780 (sizes 2x16, 2x40, 4x16, 4x20)
- Support for HD44780 via 4 bit GPIO connection (user selectable pins) - Support for HD44780 via 4 bit GPIO connection (user selectable pins)
@ -13,14 +26,23 @@ It builds on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2
- OLED 128x64 (SSD1306) - OLED 128x64 (SSD1306)
- LCDproc - LCDproc
The Nextion displays can connect to the UART on the Raspberry Pi, or via a USB to TTL serial converter like the FT-232RL. It may also be connected to the UART output of the MMDVM modem (Arduino Due, STM32, Teensy), or to the UART output on the UMP. The Nextion displays can connect to the UART on the Raspberry Pi, or via a USB
to TTL serial converter like the FT-232RL. It may also be connected to the UART
output of the MMDVM modem (Arduino Due, STM32, Teensy), or to the UART output
on the UMP.
The HD44780 displays are integrated with wiringPi for Raspberry Pi based platforms. The HD44780 displays are integrated with wiringPi for Raspberry Pi based
platforms.
The Hobbytronics TFT Display, which is a Pi-Hat, connects to the UART on the Raspbery Pi. The Hobbytronics TFT Display, which is a Pi-Hat, connects to the UART on the
Raspbery Pi.
The OLED display needs a extra library see OLED.md The OLED display needs an extra library see OLED.md
The LCDproc support enables the use of a multitude of other LCD screens. See the [supported devices](http://lcdproc.omnipotent.net/hardware.php3) page on the LCDproc website for more info. The LCDproc support enables the use of a multitude of other LCD screens. See
the [supported devices](http://lcdproc.omnipotent.net/hardware.php3) page on
the LCDproc website for more info.
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden. This software is licenced under the GPL v2 and is intended for amateur and
educational use only. Use of this software for commercial purposes is strictly
forbidden.

View file

@ -51,7 +51,7 @@ int main(int argc, char** argv)
CRemoteCommand::CRemoteCommand(unsigned int port) : CRemoteCommand::CRemoteCommand(unsigned int port) :
m_port(port) m_port(port)
{ {
::LogInitialise(".", "RemoteCommand", 2U, 2U); ::LogInitialise(false, ".", "RemoteCommand", 2U, 2U);
} }
CRemoteCommand::~CRemoteCommand() CRemoteCommand::~CRemoteCommand()
@ -61,15 +61,17 @@ CRemoteCommand::~CRemoteCommand()
int CRemoteCommand::send(const std::string& command) int CRemoteCommand::send(const std::string& command)
{ {
sockaddr_storage address;
unsigned int addrlen;
CUDPSocket::lookup("127.0.0.1", m_port, address, addrlen);
CUDPSocket socket(0U); CUDPSocket socket(0U);
bool ret = socket.open(); bool ret = socket.open(address.ss_family);
if (!ret) if (!ret)
return 1; return 1;
in_addr address = CUDPSocket::lookup("localhost"); ret = socket.write((unsigned char*)command.c_str(), command.length(), address, addrlen);
ret = socket.write((unsigned char*)command.c_str(), command.length(), address, m_port);
if (!ret) { if (!ret) {
socket.close(); socket.close();
return 1; return 1;

View file

@ -25,12 +25,15 @@
#include <cstring> #include <cstring>
const unsigned int SET_MODE_ARGS = 2U; const unsigned int SET_MODE_ARGS = 2U;
const unsigned int ENABLE_ARGS = 2U;
const unsigned int DISABLE_ARGS = 2U;
const unsigned int PAGE_ARGS = 3U; const unsigned int PAGE_ARGS = 3U;
const unsigned int CW_ARGS = 2U;
const unsigned int BUFFER_LENGTH = 100U; const unsigned int BUFFER_LENGTH = 100U;
CRemoteControl::CRemoteControl(unsigned int port) : CRemoteControl::CRemoteControl(const std::string address, unsigned int port) :
m_socket(port), m_socket(address, port),
m_command(RCD_NONE), m_command(RCD_NONE),
m_args() m_args()
{ {
@ -53,9 +56,9 @@ REMOTE_COMMAND CRemoteControl::getCommand()
char command[BUFFER_LENGTH]; char command[BUFFER_LENGTH];
char buffer[BUFFER_LENGTH]; char buffer[BUFFER_LENGTH];
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int ret = m_socket.read((unsigned char*)buffer, BUFFER_LENGTH, address, port); int ret = m_socket.read((unsigned char*)buffer, BUFFER_LENGTH, address, addrlen);
if (ret > 0) { if (ret > 0) {
buffer[ret] = '\0'; buffer[ret] = '\0';
@ -86,10 +89,39 @@ REMOTE_COMMAND CRemoteControl::getCommand()
m_command = RCD_MODE_P25; m_command = RCD_MODE_P25;
else if (m_args.at(1U) == "nxdn") else if (m_args.at(1U) == "nxdn")
m_command = RCD_MODE_NXDN; m_command = RCD_MODE_NXDN;
} else if (m_args.at(0U) == "enable" && m_args.size() >= ENABLE_ARGS) {
if (m_args.at(1U) == "dstar")
m_command = RCD_ENABLE_DSTAR;
else if (m_args.at(1U) == "dmr")
m_command = RCD_ENABLE_DMR;
else if (m_args.at(1U) == "ysf")
m_command = RCD_ENABLE_YSF;
else if (m_args.at(1U) == "p25")
m_command = RCD_ENABLE_P25;
else if (m_args.at(1U) == "nxdn")
m_command = RCD_ENABLE_NXDN;
else if (m_args.at(1U) == "fm")
m_command = RCD_ENABLE_FM;
} else if (m_args.at(0U) == "disable" && m_args.size() >= DISABLE_ARGS) {
if (m_args.at(1U) == "dstar")
m_command = RCD_DISABLE_DSTAR;
else if (m_args.at(1U) == "dmr")
m_command = RCD_DISABLE_DMR;
else if (m_args.at(1U) == "ysf")
m_command = RCD_DISABLE_YSF;
else if (m_args.at(1U) == "p25")
m_command = RCD_DISABLE_P25;
else if (m_args.at(1U) == "nxdn")
m_command = RCD_DISABLE_NXDN;
else if (m_args.at(1U) == "fm")
m_command = RCD_DISABLE_FM;
} else if (m_args.at(0U) == "page" && m_args.size() >= PAGE_ARGS) { } else if (m_args.at(0U) == "page" && m_args.size() >= PAGE_ARGS) {
// Page command is in the form of "page <ric> <message>" // Page command is in the form of "page <ric> <message>"
m_command = RCD_PAGE; m_command = RCD_PAGE;
} } else if (m_args.at(0U) == "cw" && m_args.size() >= CW_ARGS) {
// CW command is in the form of "cw <message>"
m_command = RCD_CW;
}
if (m_command == RCD_NONE) { if (m_command == RCD_NONE) {
m_args.clear(); m_args.clear();
@ -115,6 +147,8 @@ unsigned int CRemoteControl::getArgCount() const
return m_args.size() - SET_MODE_ARGS; return m_args.size() - SET_MODE_ARGS;
case RCD_PAGE: case RCD_PAGE:
return m_args.size() - 1U; return m_args.size() - 1U;
case RCD_CW:
return m_args.size() - 1U;
default: default:
return 0U; return 0U;
} }
@ -135,6 +169,9 @@ std::string CRemoteControl::getArgString(unsigned int n) const
case RCD_PAGE: case RCD_PAGE:
n += 1U; n += 1U;
break; break;
case RCD_CW:
n += 1U;
break;
default: default:
return ""; return "";
} }

View file

@ -33,12 +33,26 @@ enum REMOTE_COMMAND {
RCD_MODE_YSF, RCD_MODE_YSF,
RCD_MODE_P25, RCD_MODE_P25,
RCD_MODE_NXDN, RCD_MODE_NXDN,
RCD_PAGE RCD_MODE_FM,
RCD_ENABLE_DSTAR,
RCD_ENABLE_DMR,
RCD_ENABLE_YSF,
RCD_ENABLE_P25,
RCD_ENABLE_NXDN,
RCD_ENABLE_FM,
RCD_DISABLE_DSTAR,
RCD_DISABLE_DMR,
RCD_DISABLE_YSF,
RCD_DISABLE_P25,
RCD_DISABLE_NXDN,
RCD_DISABLE_FM,
RCD_PAGE,
RCD_CW
}; };
class CRemoteControl { class CRemoteControl {
public: public:
CRemoteControl(unsigned int port); CRemoteControl(const std::string address, unsigned int port);
~CRemoteControl(); ~CRemoteControl();
bool open(); bool open();

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -161,6 +161,22 @@ void CTFTSerial::setQuitInt()
m_mode = MODE_QUIT; m_mode = MODE_QUIT;
} }
void CTFTSerial::setFMInt()
{
// Clear the screen
clearScreen();
setFontSize(FONT_LARGE);
// Draw MMDVM logo
displayBitmap(0U, 0U, "MMDVM_sm.bmp");
gotoPosPixel(20U, 60U);
displayText("FM");
m_mode = MODE_FM;
}
void CTFTSerial::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CTFTSerial::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -40,6 +40,7 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt(); virtual void clearDStarInt();

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2019 by SASANO Takayoshi JG1UAA * Copyright (C) 2019 by SASANO Takayoshi JG1UAA
* Copyright (C) 2015,2016,2018,2019 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2018,2019,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -174,6 +174,14 @@ void CTFTSurenoo::setQuitInt()
m_mode = MODE_QUIT; m_mode = MODE_QUIT;
} }
void CTFTSurenoo::setFMInt()
{
setModeLine(STR_MMDVM);
setStatusLine(statusLineNo(1), "FM");
m_mode = MODE_FM;
}
void CTFTSurenoo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) void CTFTSurenoo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{ {
assert(my1 != NULL); assert(my1 != NULL);

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2019 by SASANO Takayoshi JG1UAA * Copyright (C) 2019 by SASANO Takayoshi JG1UAA
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -42,6 +42,7 @@ protected:
virtual void setErrorInt(const char* text); virtual void setErrorInt(const char* text);
virtual void setLockoutInt(); virtual void setLockoutInt();
virtual void setQuitInt(); virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt(); virtual void clearDStarInt();

View file

@ -60,49 +60,96 @@ CUDPSocket::~CUDPSocket()
#endif #endif
} }
in_addr CUDPSocket::lookup(const std::string& hostname) int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage &addr, unsigned int &address_length)
{ {
in_addr addr; struct addrinfo hints;
#if defined(_WIN32) || defined(_WIN64)
unsigned long address = ::inet_addr(hostname.c_str()); ::memset(&hints, 0, sizeof(hints));
if (address != INADDR_NONE && address != INADDR_ANY) {
addr.s_addr = address; return lookup(hostname, port, addr, address_length, hints);
return addr; }
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage &addr, unsigned int &address_length, struct addrinfo &hints)
{
int err;
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err) {
sockaddr_in *paddr = (sockaddr_in *)&addr;
::memset(paddr, 0, address_length = sizeof(sockaddr_in));
paddr->sin_family = AF_INET;
paddr->sin_port = htons(port);
paddr->sin_addr.s_addr = htonl(INADDR_NONE);
LogError("Cannot find address for host %s", hostname.c_str());
return err;
} }
struct hostent* hp = ::gethostbyname(hostname.c_str()); ::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); freeaddrinfo(res);
return addr; return 0;
}
bool CUDPSocket::match(const sockaddr_storage &addr1, const sockaddr_storage &addr2)
{
if (addr1.ss_family != addr2.ss_family)
return false;
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in *)&addr1;
in_2 = (struct sockaddr_in *)&addr2;
return ( (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) &&
(in_1->sin_port == in_2->sin_port) );
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6 *)&addr1;
in6_2 = (struct sockaddr_in6 *)&addr2;
return ( IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) &&
(in6_1->sin6_port == in6_2->sin6_port) );
default:
return false;
} }
}
LogError("Cannot find address for host %s", hostname.c_str()); bool CUDPSocket::isnone(const sockaddr_storage &addr)
{
struct sockaddr_in *in = (struct sockaddr_in *)&addr;
addr.s_addr = INADDR_NONE; return ( (addr.ss_family == AF_INET) &&
return addr; (in->sin_addr.s_addr == htonl(INADDR_NONE)) );
#else
in_addr_t address = ::inet_addr(hostname.c_str());
if (address != in_addr_t(-1)) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
LogError("Cannot find address for host %s", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
#endif
} }
bool CUDPSocket::open() bool CUDPSocket::open()
{ {
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); return open(AF_UNSPEC);
}
bool CUDPSocket::open(const unsigned int af)
{
int err;
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
/* to determine protocol family, call lookup() first. */
err = lookup(m_address, m_port, addr, addrlen, hints);
if (err) {
LogError("The local address is invalid - %s", m_address.c_str());
return false;
}
m_fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (m_fd < 0) { if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError()); LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
@ -113,24 +160,6 @@ bool CUDPSocket::open()
} }
if (m_port > 0U) { if (m_port > 0U) {
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(m_port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (!m_address.empty()) {
#if defined(_WIN32) || defined(_WIN64)
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#else
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#endif
if (addr.sin_addr.s_addr == INADDR_NONE) {
LogError("The local address is invalid - %s", m_address.c_str());
return false;
}
}
int reuse = 1; int reuse = 1;
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
@ -141,7 +170,7 @@ bool CUDPSocket::open()
return false; return false;
} }
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError()); LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else #else
@ -154,7 +183,7 @@ bool CUDPSocket::open()
return true; return true;
} }
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port) int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
{ {
assert(buffer != NULL); assert(buffer != NULL);
assert(length > 0U); assert(length > 0U);
@ -186,17 +215,16 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres
if (ret == 0) if (ret == 0)
return 0; return 0;
sockaddr_in addr;
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
int size = sizeof(sockaddr_in); int size = sizeof(sockaddr_storage);
#else #else
socklen_t size = sizeof(sockaddr_in); socklen_t size = sizeof(sockaddr_storage);
#endif #endif
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size); int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#else #else
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size); ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#endif #endif
if (len <= 0) { if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
@ -207,28 +235,19 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres
return -1; return -1;
} }
address = addr.sin_addr; address_length = size;
port = ntohs(addr.sin_port);
return len; return len;
} }
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port) bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
{ {
assert(buffer != NULL); assert(buffer != NULL);
assert(length > 0U); assert(length > 0U);
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr = address;
addr.sin_port = htons(port);
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length);
#else #else
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length);
#endif #endif
if (ret < 0) { if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)

View file

@ -31,7 +31,8 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#else #else
#include <winsock.h> #include <winsock2.h>
#include <ws2tcpip.h>
#endif #endif
class CUDPSocket { class CUDPSocket {
@ -41,13 +42,17 @@ public:
~CUDPSocket(); ~CUDPSocket();
bool open(); bool open();
bool open(const unsigned int af);
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port); int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port); bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
void close(); void close();
static in_addr lookup(const std::string& hostName); static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage &address, unsigned int &address_length);
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage &address, unsigned int &address_length, struct addrinfo &hints);
static bool match(const sockaddr_storage &addr1, const sockaddr_storage &addr2);
static bool isnone(const sockaddr_storage &addr);
private: private:
std::string m_address; std::string m_address;

View file

@ -42,7 +42,7 @@ bool CUserDB::lookup(unsigned int id, class CUserDBentry *entry)
if (entry != NULL) if (entry != NULL)
*entry = m_table.at(id); *entry = m_table.at(id);
else else
m_table.at(id); (void)m_table.at(id);
rv = true; rv = true;
} catch (...) { } catch (...) {
@ -116,8 +116,8 @@ bool CUserDB::makeindex(char* buf, std::unordered_map<std::string, int>& index)
} }
try { try {
index.at(keyRADIO_ID); (void)index.at(keyRADIO_ID);
index.at(keyCALLSIGN); (void)index.at(keyCALLSIGN);
return true; return true;
} catch (...) { } catch (...) {
return false; return false;
@ -144,8 +144,8 @@ void CUserDB::parse(char* buf, std::unordered_map<std::string, int>& index)
} }
try { try {
ptr.at(keyRADIO_ID); (void)ptr.at(keyRADIO_ID);
ptr.at(keyCALLSIGN); (void)ptr.at(keyCALLSIGN);
} catch (...) { } catch (...) {
return; return;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,6 +19,6 @@
#if !defined(VERSION_H) #if !defined(VERSION_H)
#define VERSION_H #define VERSION_H
const char* VERSION = "20190131"; const char* VERSION = "20200608";
#endif #endif

View file

@ -31,7 +31,7 @@ const unsigned int BUFFER_LENGTH = 200U;
CYSFNetwork::CYSFNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug) : CYSFNetwork::CYSFNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug) :
m_socket(myAddress, myPort), m_socket(myAddress, myPort),
m_address(), m_address(),
m_port(gatewayPort), m_addrlen(),
m_callsign(), m_callsign(),
m_debug(debug), m_debug(debug),
m_enabled(false), m_enabled(false),
@ -42,7 +42,7 @@ m_tag(NULL)
m_callsign = callsign; m_callsign = callsign;
m_callsign.resize(YSF_CALLSIGN_LENGTH, ' '); m_callsign.resize(YSF_CALLSIGN_LENGTH, ' ');
m_address = CUDPSocket::lookup(gatewayAddress); CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
m_tag = new unsigned char[YSF_CALLSIGN_LENGTH]; m_tag = new unsigned char[YSF_CALLSIGN_LENGTH];
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH); ::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
@ -57,7 +57,7 @@ bool CYSFNetwork::open()
{ {
LogMessage("Opening YSF network connection"); LogMessage("Opening YSF network connection");
if (m_address.s_addr == INADDR_NONE) if (CUDPSocket::isnone(m_address))
return false; return false;
m_pollTimer.start(); m_pollTimer.start();
@ -97,7 +97,7 @@ bool CYSFNetwork::write(const unsigned char* src, const unsigned char* dest, con
if (m_debug) if (m_debug)
CUtils::dump(1U, "YSF Network Data Sent", buffer, 155U); CUtils::dump(1U, "YSF Network Data Sent", buffer, 155U);
return m_socket.write(buffer, 155U, m_address, m_port); return m_socket.write(buffer, 155U, m_address, m_addrlen);
} }
bool CYSFNetwork::writePoll() bool CYSFNetwork::writePoll()
@ -115,7 +115,7 @@ bool CYSFNetwork::writePoll()
if (m_debug) if (m_debug)
CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U); CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U);
return m_socket.write(buffer, 14U, m_address, m_port); return m_socket.write(buffer, 14U, m_address, m_addrlen);
} }
void CYSFNetwork::clock(unsigned int ms) void CYSFNetwork::clock(unsigned int ms)
@ -128,18 +128,12 @@ void CYSFNetwork::clock(unsigned int ms)
unsigned char buffer[BUFFER_LENGTH]; unsigned char buffer[BUFFER_LENGTH];
in_addr address; sockaddr_storage address;
unsigned int port; unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0) if (length <= 0 || !CUDPSocket::match(m_address, address))
return; return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || m_port != port) {
LogMessage("YSF packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Ignore incoming polls // Ignore incoming polls
if (::memcmp(buffer, "YSFP", 4U) == 0) if (::memcmp(buffer, "YSFP", 4U) == 0)
return; return;

View file

@ -48,8 +48,8 @@ public:
private: private:
CUDPSocket m_socket; CUDPSocket m_socket;
in_addr m_address; sockaddr_storage m_address;
unsigned int m_port; unsigned int m_addrlen;
std::string m_callsign; std::string m_callsign;
bool m_debug; bool m_debug;
bool m_enabled; bool m_enabled;