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
* 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)
{
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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt();

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
* it under the terms of the GNU General Public License as published by
@ -44,6 +44,7 @@ enum SECTION {
SECTION_P25,
SECTION_NXDN,
SECTION_POCSAG,
SECTION_FM,
SECTION_DSTAR_NETWORK,
SECTION_DMR_NETWORK,
SECTION_FUSION_NETWORK,
@ -109,6 +110,7 @@ m_modemYSFTXLevel(50.0F),
m_modemP25TXLevel(50.0F),
m_modemNXDNTXLevel(50.0F),
m_modemPOCSAGTXLevel(50.0F),
m_modemFMTXLevel(50.0F),
m_modemRSSIMappingFile(),
m_modemTrace(false),
m_modemDebug(false),
@ -161,15 +163,48 @@ m_p25NAC(0x293U),
m_p25SelfOnly(false),
m_p25OverrideUID(false),
m_p25RemoteGateway(false),
m_p25TXHang(5U),
m_p25ModeHang(10U),
m_nxdnEnabled(false),
m_nxdnId(0U),
m_nxdnRAN(1U),
m_nxdnSelfOnly(false),
m_nxdnRemoteGateway(false),
m_nxdnTXHang(5U),
m_nxdnModeHang(10U),
m_pocsagEnabled(false),
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_dstarGatewayAddress(),
m_dstarGatewayPort(0U),
@ -244,12 +279,14 @@ m_lcdprocPort(0U),
m_lcdprocLocalPort(0U),
m_lcdprocDisplayClock(false),
m_lcdprocUTC(false),
m_lcdprocDimOnIdle(false),
m_lockFileEnabled(false),
m_lockFileName(),
m_mobileGPSEnabled(false),
m_mobileGPSAddress(),
m_mobileGPSPort(0U),
m_remoteControlEnabled(false),
m_remoteControlAddress("127.0.0.1"),
m_remoteControlPort(0U)
{
}
@ -304,6 +341,8 @@ bool CConf::read()
section = SECTION_NXDN;
else if (::strncmp(buffer, "[POCSAG]", 8U) == 0)
section = SECTION_POCSAG;
else if (::strncmp(buffer, "[FM]", 4U) == 0)
section = SECTION_FM;
else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0)
section = SECTION_DSTAR_NETWORK;
else if (::strncmp(buffer, "[DMR Network]", 13U) == 0)
@ -358,11 +397,11 @@ bool CConf::read()
// Convert the callsign to upper case
for (unsigned int i = 0U; value[i] != 0; i++)
value[i] = ::toupper(value[i]);
m_cwIdCallsign = m_callsign = value;
m_fmCallsign = m_cwIdCallsign = m_callsign = value;
} else if (::strcmp(key, "Id") == 0)
m_id = m_p25Id = m_dmrId = (unsigned int)::atoi(value);
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)
m_duplex = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
@ -455,7 +494,7 @@ bool CConf::read()
else if (::strcmp(key, "RXLevel") == 0)
m_modemRXLevel = float(::atof(value));
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)
m_modemCWIdTXLevel = float(::atof(value));
else if (::strcmp(key, "D-StarTXLevel") == 0)
@ -470,6 +509,8 @@ bool CConf::read()
m_modemNXDNTXLevel = float(::atof(value));
else if (::strcmp(key, "POCSAGTXLevel") == 0)
m_modemPOCSAGTXLevel = float(::atof(value));
else if (::strcmp(key, "FMTXLevel") == 0)
m_modemFMTXLevel = float(::atof(value));
else if (::strcmp(key, "RSSIMappingFile") == 0)
m_modemRSSIMappingFile = value;
else if (::strcmp(key, "Trace") == 0)
@ -636,6 +677,8 @@ bool CConf::read()
m_p25SelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "RemoteGateway") == 0)
m_p25RemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "TXHang") == 0)
m_p25TXHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_p25ModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_NXDN) {
@ -649,13 +692,90 @@ bool CConf::read()
m_nxdnSelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "RemoteGateway") == 0)
m_nxdnRemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "TXHang") == 0)
m_nxdnTXHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_nxdnModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_POCSAG) {
if (::strcmp(key, "Enable") == 0)
m_pocsagEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Frequency") == 0)
m_pocsagFrequency = (unsigned int)::atoi(value);
}
else if (section == SECTION_FM) {
if (::strcmp(key, "Enable") == 0)
m_pocsagEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Frequency") == 0)
m_pocsagFrequency = (unsigned int)::atoi(value);
m_fmEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Callsign") == 0) {
// 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) {
if (::strcmp(key, "Enable") == 0)
m_dstarNetworkEnabled = ::atoi(value) == 1;
@ -838,6 +958,8 @@ bool CConf::read()
} else if (section == SECTION_REMOTE_CONTROL) {
if (::strcmp(key, "Enable") == 0)
m_remoteControlEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
m_remoteControlAddress = value;
else if (::strcmp(key, "Port") == 0)
m_remoteControlPort = (unsigned int)::atoi(value);
}
@ -1083,6 +1205,11 @@ float CConf::getModemPOCSAGTXLevel() const
return m_modemPOCSAGTXLevel;
}
float CConf::getModemFMTXLevel() const
{
return m_modemFMTXLevel;
}
std::string CConf::getModemRSSIMappingFile () const
{
return m_modemRSSIMappingFile;
@ -1343,6 +1470,11 @@ bool CConf::getP25RemoteGateway() const
return m_p25RemoteGateway;
}
unsigned int CConf::getP25TXHang() const
{
return m_p25TXHang;
}
unsigned int CConf::getP25ModeHang() const
{
return m_p25ModeHang;
@ -1373,6 +1505,11 @@ bool CConf::getNXDNRemoteGateway() const
return m_nxdnRemoteGateway;
}
unsigned int CConf::getNXDNTXHang() const
{
return m_nxdnTXHang;
}
unsigned int CConf::getNXDNModeHang() const
{
return m_nxdnModeHang;
@ -1388,6 +1525,161 @@ unsigned int CConf::getPOCSAGFrequency() const
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
{
return m_dstarNetworkEnabled;
@ -1794,6 +2086,11 @@ bool CConf::getRemoteControlEnabled() const
return m_remoteControlEnabled;
}
std::string CConf::getRemoteControlAddress() const
{
return m_remoteControlAddress;
}
unsigned int CConf::getRemoteControlPort() const
{
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
* it under the terms of the GNU General Public License as published by
@ -90,6 +90,7 @@ public:
float getModemP25TXLevel() const;
float getModemNXDNTXLevel() const;
float getModemPOCSAGTXLevel() const;
float getModemFMTXLevel() const;
std::string getModemRSSIMappingFile() const;
bool getModemTrace() const;
bool getModemDebug() const;
@ -154,6 +155,7 @@ public:
bool getP25SelfOnly() const;
bool getP25OverrideUID() const;
bool getP25RemoteGateway() const;
unsigned int getP25TXHang() const;
unsigned int getP25ModeHang() const;
// The NXDN section
@ -162,12 +164,46 @@ public:
unsigned int getNXDNRAN() const;
bool getNXDNSelfOnly() const;
bool getNXDNRemoteGateway() const;
unsigned int getNXDNTXHang() const;
unsigned int getNXDNModeHang() const;
// The POCSAG section
bool getPOCSAGEnabled() 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
bool getDStarNetworkEnabled() const;
std::string getDStarGatewayAddress() const;
@ -276,6 +312,7 @@ public:
// The Remote Control section
bool getRemoteControlEnabled() const;
std::string getRemoteControlAddress() const;
unsigned int getRemoteControlPort() const;
private:
@ -333,6 +370,7 @@ private:
float m_modemP25TXLevel;
float m_modemNXDNTXLevel;
float m_modemPOCSAGTXLevel;
float m_modemFMTXLevel;
std::string m_modemRSSIMappingFile;
bool m_modemTrace;
bool m_modemDebug;
@ -391,6 +429,7 @@ private:
bool m_p25SelfOnly;
bool m_p25OverrideUID;
bool m_p25RemoteGateway;
unsigned int m_p25TXHang;
unsigned int m_p25ModeHang;
bool m_nxdnEnabled;
@ -398,11 +437,44 @@ private:
unsigned int m_nxdnRAN;
bool m_nxdnSelfOnly;
bool m_nxdnRemoteGateway;
unsigned int m_nxdnTXHang;
unsigned int m_nxdnModeHang;
bool m_pocsagEnabled;
unsigned int m_pocsagFrequency;
bool m_fmEnabled;
std::string m_fmCallsign;
unsigned int m_fmCallsignSpeed;
unsigned int m_fmCallsignFrequency;
unsigned int m_fmCallsignTime;
unsigned int m_fmCallsignHoldoff;
float m_fmCallsignHighLevel;
float m_fmCallsignLowLevel;
bool m_fmCallsignAtStart;
bool m_fmCallsignAtEnd;
bool m_fmCallsignAtLatch;
std::string m_fmRFAck;
std::string m_fmExtAck;
unsigned int m_fmAckSpeed;
unsigned int m_fmAckFrequency;
unsigned int m_fmAckMinTime;
unsigned int m_fmAckDelay;
float m_fmAckLevel;
unsigned int m_fmTimeout;
float m_fmTimeoutLevel;
float m_fmCTCSSFrequency;
unsigned int m_fmCTCSSHighThreshold;
unsigned int m_fmCTCSSLowThreshold;
float m_fmCTCSSLevel;
unsigned int m_fmKerchunkTime;
unsigned int m_fmHangTime;
bool m_fmUseCOS;
bool m_fmCOSInvert;
unsigned int m_fmRFAudioBoost;
float m_fmMaxDevLevel;
unsigned int m_fmExtAudioBoost;
bool m_dstarNetworkEnabled;
std::string m_dstarGatewayAddress;
unsigned int m_dstarGatewayPort;
@ -497,6 +569,7 @@ private:
unsigned int m_mobileGPSPort;
bool m_remoteControlEnabled;
std::string m_remoteControlAddress;
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) :
m_addressStr(address),
m_address(),
m_addrlen(),
m_port(port),
m_id(NULL),
m_password(password),
@ -73,7 +74,7 @@ m_beacon(false)
assert(id > 1000U);
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_salt = new unsigned char[sizeof(uint32_t)];
@ -124,8 +125,8 @@ bool CDMRNetwork::open()
{
LogMessage("DMR, Opening DMR Network");
if (m_address.s_addr == INADDR_NONE)
m_address = CUDPSocket::lookup(m_addressStr);
if (CUDPSocket::isnone(m_address))
CUDPSocket::lookup(m_addressStr, m_port, m_address, m_addrlen);
m_status = WAITING_CONNECT;
m_timeoutTimer.stop();
@ -361,7 +362,7 @@ void CDMRNetwork::clock(unsigned int ms)
if (m_status == WAITING_CONNECT) {
m_retryTimer.clock(ms);
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
bool ret = m_socket.open();
bool ret = m_socket.open(m_address.ss_family);
if (ret) {
ret = writeLogin();
if (!ret)
@ -377,9 +378,9 @@ void CDMRNetwork::clock(unsigned int ms)
return;
}
in_addr address;
unsigned int port;
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port);
sockaddr_storage address;
unsigned int addrlen;
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen);
if (length < 0) {
LogError("DMR, Socket has failed, retrying connection to the master");
close();
@ -390,7 +391,7 @@ void CDMRNetwork::clock(unsigned int ms)
// if (m_debug && length > 0)
// CUtils::dump(1U, "Network Received", m_buffer, length);
if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) {
if (length > 0 && CUDPSocket::match(m_address, address)) {
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
if (m_enabled) {
if (m_debug)
@ -663,7 +664,7 @@ bool CDMRNetwork::write(const unsigned char* data, unsigned int length)
// if (m_debug)
// 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) {
LogError("DMR, Socket has failed when writing data to the master, retrying connection");
m_socket.close();

View file

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

View file

@ -51,8 +51,8 @@ public:
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
sockaddr_storage m_address;
unsigned int m_addrlen;
bool m_duplex;
const char* m_version;
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_NXDN = 5U;
const unsigned char MODE_POCSAG = 6U;
const unsigned char MODE_FM = 10U;
const unsigned char MODE_CW = 98U;
const unsigned char MODE_LOCKOUT = 99U;
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
* it under the terms of the GNU General Public License as published by
@ -101,6 +101,17 @@ void CDisplay::setQuit()
setQuitInt();
}
void CDisplay::setFM()
{
m_timer1.stop();
m_timer2.stop();
m_mode1 = MODE_FM;
m_mode2 = MODE_FM;
setFMInt();
}
void CDisplay::writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{
assert(my1 != NULL);
@ -190,6 +201,7 @@ void CDisplay::writeDMRBER(unsigned int slotNo, float ber)
{
writeDMRBERInt(slotNo, ber);
}
void CDisplay::clearDMR(unsigned int slotNo)
{
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
* it under the terms of the GNU General Public License as published by
@ -42,6 +42,7 @@ public:
void setLockout();
void setError(const char* text);
void setQuit();
void setFM();
void writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
void writeDStarRSSI(unsigned char rssi);
@ -87,6 +88,7 @@ protected:
virtual void setLockoutInt() = 0;
virtual void setErrorInt(const char* text) = 0;
virtual void setQuitInt() = 0;
virtual void setFMInt() = 0;
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0;
virtual void writeDStarRSSIInt(unsigned char rssi);

View file

@ -399,6 +399,37 @@ void CHD44780::setQuitInt()
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)
{
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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi);

View file

@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -121,44 +121,53 @@ CLCDproc::~CLCDproc()
bool CLCDproc::open()
{
const char *server;
unsigned int port, localPort;
struct sockaddr_in serverAddress, clientAddress;
struct hostent *h;
int err;
unsigned int addrlen;
std::string port, localPort;
struct sockaddr_storage serverAddress, clientAddress;
struct addrinfo hints, *res;
server = m_address.c_str();
port = m_port;
localPort = m_localPort;
port = std::to_string(m_port);
localPort = std::to_string(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 */
m_socketfd = socket(AF_INET, SOCK_STREAM, 0);
m_socketfd = socket(clientAddress.ss_family, SOCK_STREAM, 0);
if (m_socketfd == -1) {
LogError("LCDproc, failed to create socket");
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 */
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");
return false;
}
/* Lookup the hostname address */
h = gethostbyname(server);
/* Sets server address */
serverAddress.sin_family = h->h_addrtype;
memcpy((char*)&serverAddress.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
serverAddress.sin_port = htons(port);
if (connect(m_socketfd, (struct sockaddr * )&serverAddress, sizeof(serverAddress))==-1) {
/* Connect to server */
if (connect(m_socketfd, (struct sockaddr *)&serverAddress, addrlen) == -1) {
LogError("LCDproc, cannot connect to server");
return false;
}
@ -241,6 +250,23 @@ void CLCDproc::setQuitInt()
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)
{
assert(my1 != NULL);
@ -294,7 +320,7 @@ void CLCDproc::clearDStarInt()
{
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 Line4 1 4 15 4 h 3 \"\"");
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, " ");
}
} 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 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
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 Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 4"); // Set LED3 color green
@ -480,7 +506,7 @@ void CLCDproc::clearP25Int()
{
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 Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 2"); // Set LED2 color green
@ -525,7 +551,7 @@ void CLCDproc::clearNXDNInt()
{
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 Line4 1 4 15 4 h 3 \"\"");
socketPrintf(m_socketfd, "output 16"); // Set LED5 color green
@ -752,7 +778,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add DStar Line4 scroller");
/* 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 Line4 1 4 15 4 h 3 \"\"");
*/
@ -773,8 +799,8 @@ void CLCDproc::defineScreens()
/* 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 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 Slot2 3 2 15 2 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\"");
*/
// The YSF Screen
@ -788,7 +814,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add YSF Line4 scroller");
/* 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 Line4 4 2 15 2 h 3 \" \"");
*/
@ -804,7 +830,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add P25 Line4 scroller");
/* 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 Line4 4 2 15 2 h 3 \" \"");
*/
@ -820,7 +846,7 @@ void CLCDproc::defineScreens()
socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller");
/* 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 Line4 4 2 15 2 h 3 \" \"");
*/

View file

@ -1,6 +1,6 @@
/*
* 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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi);
virtual void clearDStarInt();

20
Log.cpp
View file

@ -22,6 +22,7 @@
#include <Windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#include <cstdio>
@ -36,6 +37,7 @@ static std::string m_filePath;
static std::string m_fileRoot;
static FILE* m_fpLog = NULL;
static bool m_daemon = false;
static unsigned int m_displayLevel = 2U;
@ -45,6 +47,8 @@ static char LEVELS[] = " DMIWEF";
static bool LogOpen()
{
bool status = false;
if (m_fileLevel == 0U)
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);
#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;
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_fileRoot = fileRoot;
m_fileLevel = fileLevel;
m_displayLevel = displayLevel;
m_daemon = daemon;
return ::LogOpen();
}

2
Log.h
View file

@ -30,7 +30,7 @@
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();
#endif

View file

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

View file

@ -150,6 +150,7 @@ m_ysfEnabled(false),
m_p25Enabled(false),
m_nxdnEnabled(false),
m_pocsagEnabled(false),
m_fmEnabled(false),
m_cwIdTime(0U),
m_dmrLookup(NULL),
m_nxdnLookup(NULL),
@ -236,7 +237,11 @@ int CMMDVMHost::run()
#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) {
::fprintf(stderr, "MMDVMHost: unable to open the log file\n");
return 1;
@ -246,7 +251,6 @@ int CMMDVMHost::run()
if (m_daemon) {
::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
}
#endif
@ -316,8 +320,8 @@ int CMMDVMHost::run()
return 1;
}
in_addr transparentAddress;
unsigned int transparentPort = 0U;
sockaddr_storage transparentAddress;
unsigned int transparentAddrLen;
CUDPSocket* transparentSocket = NULL;
unsigned int sendFrameType = 0U;
@ -333,11 +337,10 @@ int CMMDVMHost::run()
LogInfo(" Local Port: %u", localPort);
LogInfo(" Send Frame Type: %u", sendFrameType);
transparentAddress = CUDPSocket::lookup(remoteAddress);
transparentPort = remotePort;
CUDPSocket::lookup(remoteAddress, remotePort, transparentAddress, transparentAddrLen);
transparentSocket = new CUDPSocket(localPort);
ret = transparentSocket->open();
ret = transparentSocket->open(transparentAddress.ss_family);
if (!ret) {
LogWarning("Could not open the Transparent data socket, disabling");
delete transparentSocket;
@ -546,12 +549,13 @@ int CMMDVMHost::run()
}
if (m_p25Enabled) {
unsigned int id = m_conf.getP25Id();
unsigned int nac = m_conf.getP25NAC();
bool uidOverride = m_conf.getP25OverrideUID();
bool selfOnly = m_conf.getP25SelfOnly();
bool remoteGateway = m_conf.getP25RemoteGateway();
m_p25RFModeHang = m_conf.getP25ModeHang();
unsigned int id = m_conf.getP25Id();
unsigned int nac = m_conf.getP25NAC();
unsigned int txHang = m_conf.getP25TXHang();
bool uidOverride = m_conf.getP25OverrideUID();
bool selfOnly = m_conf.getP25SelfOnly();
bool remoteGateway = m_conf.getP25RemoteGateway();
m_p25RFModeHang = m_conf.getP25ModeHang();
LogInfo("P25 RF Parameters");
LogInfo(" Id: %u", id);
@ -559,6 +563,7 @@ int CMMDVMHost::run()
LogInfo(" UID Override: %s", uidOverride ? "yes" : "no");
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
LogInfo(" TX Hang: %us", txHang);
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);
@ -576,17 +581,19 @@ int CMMDVMHost::run()
m_nxdnLookup = new CNXDNLookup(lookupFile, reloadTime);
m_nxdnLookup->read();
unsigned int id = m_conf.getNXDNId();
unsigned int ran = m_conf.getNXDNRAN();
bool selfOnly = m_conf.getNXDNSelfOnly();
bool remoteGateway = m_conf.getNXDNRemoteGateway();
m_nxdnRFModeHang = m_conf.getNXDNModeHang();
unsigned int id = m_conf.getNXDNId();
unsigned int ran = m_conf.getNXDNRAN();
bool selfOnly = m_conf.getNXDNSelfOnly();
bool remoteGateway = m_conf.getNXDNRemoteGateway();
unsigned int txHang = m_conf.getNXDNTXHang();
m_nxdnRFModeHang = m_conf.getNXDNModeHang();
LogInfo("NXDN RF Parameters");
LogInfo(" Id: %u", id);
LogInfo(" RAN: %u", ran);
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
LogInfo(" TX Hang: %us", txHang);
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);
@ -602,17 +609,20 @@ int CMMDVMHost::run()
m_pocsag = new CPOCSAGControl(m_pocsagNetwork, m_display);
pocsagTimer.start();
if (m_pocsagNetwork != NULL)
pocsagTimer.start();
}
bool remoteControlEnabled = m_conf.getRemoteControlEnabled();
if (remoteControlEnabled) {
std::string address = m_conf.getRemoteControlAddress();
unsigned int port = m_conf.getRemoteControlPort();
LogInfo("Remote Control Parameters");
LogInfo(" Address: %s", address.c_str());
LogInfo(" Port: %u", port);
m_remoteControl = new CRemoteControl(port);
m_remoteControl = new CRemoteControl(address, port);
ret = m_remoteControl->open();
if (!ret) {
@ -642,6 +652,12 @@ int CMMDVMHost::run()
else if (!error && m_mode == MODE_ERROR)
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) {
bool tx = m_modem->hasTX();
m_ump->setTX(tx);
@ -793,7 +809,7 @@ int CMMDVMHost::run()
len = m_modem->readTransparentData(data);
if (transparentSocket != NULL && len > 0U)
transparentSocket->write(data, len, transparentAddress, transparentPort);
transparentSocket->write(data, len, transparentAddress, transparentAddrLen);
if (!m_fixedMode) {
if (m_modeTimer.isRunning() && m_modeTimer.hasExpired())
@ -942,9 +958,9 @@ int CMMDVMHost::run()
}
if (transparentSocket != NULL) {
in_addr address;
unsigned int port = 0U;
len = transparentSocket->read(data, 200U, address, port);
sockaddr_storage address;
unsigned int addrlen;
len = transparentSocket->read(data, 200U, address, addrlen);
if (len > 0U)
m_modem->writeTransparentData(data, len);
}
@ -1149,11 +1165,14 @@ bool CMMDVMHost::createModem()
float p25TXLevel = m_conf.getModemP25TXLevel();
float nxdnTXLevel = m_conf.getModemNXDNTXLevel();
float pocsagTXLevel = m_conf.getModemPOCSAGTXLevel();
float fmTXLevel = m_conf.getModemFMTXLevel();
bool trace = m_conf.getModemTrace();
bool debug = m_conf.getModemDebug();
unsigned int colorCode = m_conf.getDMRColorCode();
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 txFrequency = m_conf.getTXFrequency();
unsigned int pocsagFrequency = m_conf.getPOCSAGFrequency();
@ -1186,16 +1205,87 @@ bool CMMDVMHost::createModem()
LogInfo(" P25 TX Level: %.1f%%", p25TXLevel);
LogInfo(" NXDN TX Level: %.1f%%", nxdnTXLevel);
LogInfo(" POCSAG TX Level: %.1f%%", pocsagTXLevel);
LogInfo(" RX Frequency: %uHz (%uHz)", rxFrequency, rxFrequency + rxOffset);
LogInfo(" FM TX Level: %.1f%%", fmTXLevel);
LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset);
m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug);
m_modem->setSerialParams(protocol,address);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel);
m_modem->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, fmTXLevel);
m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency);
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();
if (!ret) {
@ -1450,6 +1540,7 @@ void CMMDVMHost::readParams()
m_p25Enabled = m_conf.getP25Enabled();
m_nxdnEnabled = m_conf.getNXDNEnabled();
m_pocsagEnabled = m_conf.getPOCSAGEnabled();
m_fmEnabled = m_conf.getFMEnabled();
m_duplex = m_conf.getDuplex();
m_callsign = m_conf.getCallsign();
m_id = m_conf.getId();
@ -1466,6 +1557,7 @@ void CMMDVMHost::readParams()
LogInfo(" P25: %s", m_p25Enabled ? "enabled" : "disabled");
LogInfo(" NXDN: %s", m_nxdnEnabled ? "enabled" : "disabled");
LogInfo(" POCSAG: %s", m_pocsagEnabled ? "enabled" : "disabled");
LogInfo(" FM: %s", m_fmEnabled ? "enabled" : "disabled");
}
void CMMDVMHost::setMode(unsigned char mode)
@ -1682,8 +1774,45 @@ void CMMDVMHost::setMode(unsigned char mode)
createLockFile("POCSAG");
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:
LogMessage("Mode set to Lockout");
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(false);
if (m_dmrNetwork != NULL)
@ -1863,6 +1992,58 @@ void CMMDVMHost::remoteControl()
if (m_nxdn != NULL)
processModeCommand(MODE_NXDN, m_nxdnRFModeHang);
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:
if (m_pocsag != NULL) {
unsigned int ric = m_remoteControl->getArgUInt(0U);
@ -1874,6 +2055,18 @@ void CMMDVMHost::remoteControl()
}
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:
break;
}
@ -1896,3 +2089,12 @@ void CMMDVMHost::processModeCommand(unsigned char mode, unsigned int timeout)
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
* it under the terms of the GNU General Public License as published by
@ -93,6 +93,7 @@ private:
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_pocsagEnabled;
bool m_fmEnabled;
unsigned int m_cwIdTime;
CDMRLookup* m_dmrLookup;
CNXDNLookup* m_nxdnLookup;
@ -116,6 +117,7 @@ private:
void remoteControl();
void processModeCommand(unsigned char mode, unsigned int timeout);
void processEnableCommand(bool& mode, bool enabled);
void setMode(unsigned char mode);

View file

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

View file

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

View file

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

View file

@ -51,8 +51,8 @@ public:
private:
CTimer m_idTimer;
in_addr m_address;
unsigned int m_port;
sockaddr_storage m_address;
unsigned int m_addrlen;
CUDPSocket m_socket;
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
* 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_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_NAK = 0x7FU;
@ -100,6 +104,8 @@ m_port(port),
m_dmrColorCode(0U),
m_ysfLoDev(false),
m_ysfTXHang(4U),
m_p25TXHang(5U),
m_nxdnTXHang(5U),
m_duplex(duplex),
m_rxInvert(rxInvert),
m_txInvert(txInvert),
@ -114,6 +120,7 @@ m_ysfTXLevel(0U),
m_p25TXLevel(0U),
m_nxdnTXLevel(0U),
m_pocsagTXLevel(0U),
m_fmTXLevel(0U),
m_trace(trace),
m_debug(debug),
m_rxFrequency(0U),
@ -125,6 +132,7 @@ m_ysfEnabled(false),
m_p25Enabled(false),
m_nxdnEnabled(false),
m_pocsagEnabled(false),
m_fmEnabled(false),
m_rxDCOffset(0),
m_txDCOffset(0),
m_serial(NULL),
@ -161,11 +169,40 @@ m_tx(false),
m_cd(false),
m_lockout(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];
assert(!port.empty());
}
CModem::~CModem()
@ -193,7 +230,7 @@ void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int tx
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_dmrEnabled = dmrEnabled;
@ -201,9 +238,10 @@ void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled,
m_p25Enabled = p25Enabled;
m_nxdnEnabled = nxdnEnabled;
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_cwIdTXLevel = cwIdTXLevel;
@ -213,6 +251,7 @@ void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, flo
m_p25TXLevel = p25TXLevel;
m_nxdnTXLevel = nxdnTXLevel;
m_pocsagTXLevel = pocsagTXLevel;
m_fmTXLevel = fmTXLevel;
}
void CModem::setDMRParams(unsigned int colorCode)
@ -228,6 +267,16 @@ void CModem::setYSFParams(bool loDev, unsigned int 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)
{
m_sendTransparentDataFrameType = sendFrameType;
@ -269,6 +318,32 @@ bool CModem::open()
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_error = false;
@ -518,6 +593,8 @@ void CModem::clock(unsigned int ms)
m_nxdnSpace = 0U;
m_pocsagSpace = 0U;
m_mode = m_buffer[4U];
m_tx = (m_buffer[5U] & 0x01U) == 0x01U;
bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U;
@ -1429,6 +1506,11 @@ bool CModem::readStatus()
return m_serial->write(buffer, 3U) == 3;
}
bool CModem::writeConfig()
{
return setConfig();
}
bool CModem::setConfig()
{
assert(m_serial != NULL);
@ -1437,7 +1519,7 @@ bool CModem::setConfig()
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 21U;
buffer[1U] = 24U;
buffer[2U] = MMDVM_SET_CONFIG;
@ -1468,6 +1550,8 @@ bool CModem::setConfig()
buffer[4U] |= 0x10U;
if (m_pocsagEnabled)
buffer[4U] |= 0x20U;
if (m_fmEnabled && m_duplex)
buffer[4U] |= 0x40U;
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);
// CUtils::dump(1U, "Written", buffer, 21U);
buffer[21U] = (unsigned char)(m_fmTXLevel * 2.55F + 0.5F);
int ret = m_serial->write(buffer, 21U);
if (ret != 21)
buffer[22U] = (unsigned char)m_p25TXHang;
buffer[23U] = (unsigned char)m_nxdnTXHang;
// CUtils::dump(1U, "Written", buffer, 24U);
int ret = m_serial->write(buffer, 24U);
if (ret != 24)
return false;
unsigned int count = 0U;
@ -1706,6 +1796,11 @@ HW_TYPE CModem::getHWType() const
return m_hwType;
}
unsigned char CModem::getMode() const
{
return m_mode;
}
bool CModem::setMode(unsigned char mode)
{
assert(m_serial != NULL);
@ -1811,6 +1906,227 @@ bool CModem::writeDMRShortLC(const unsigned char* lc)
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()
{
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
* 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 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 setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel);
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, float fmTXLevel);
virtual void setDMRParams(unsigned int colorCode);
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 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 unsigned int readDStarData(unsigned char* data);
@ -71,6 +77,7 @@ public:
virtual bool hasLockout() const;
virtual bool hasError() const;
virtual bool writeConfig();
virtual bool writeDStarData(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);
@ -95,6 +102,7 @@ public:
virtual bool writeSerial(const unsigned char* data, unsigned int length);
virtual unsigned char getMode() const;
virtual bool setMode(unsigned char mode);
virtual bool sendCWId(const std::string& callsign);
@ -112,6 +120,8 @@ private:
unsigned int m_dmrColorCode;
bool m_ysfLoDev;
unsigned int m_ysfTXHang;
unsigned int m_p25TXHang;
unsigned int m_nxdnTXHang;
bool m_duplex;
bool m_rxInvert;
bool m_txInvert;
@ -126,6 +136,7 @@ private:
float m_p25TXLevel;
float m_nxdnTXLevel;
float m_pocsagTXLevel;
float m_fmTXLevel;
float m_rfLevel;
bool m_trace;
bool m_debug;
@ -138,6 +149,7 @@ private:
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_pocsagEnabled;
bool m_fmEnabled;
int m_rxDCOffset;
int m_txDCOffset;
CSerialController* m_serial;
@ -174,12 +186,45 @@ private:
bool m_cd;
bool m_lockout;
bool m_error;
unsigned char m_mode;
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 readStatus();
bool setConfig();
bool setFrequency();
bool setFMCallsignParams();
bool setFMAckParams();
bool setFMMiscParams();
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) :
m_socket(localAddress, localPort),
m_address(),
m_port(gatewayPort),
m_addrlen(),
m_debug(debug),
m_enabled(false),
m_buffer(1000U, "NXDN Network")
@ -39,7 +39,7 @@ m_buffer(1000U, "NXDN Network")
assert(gatewayPort > 0U);
assert(!gatewayAddress.empty());
m_address = CUDPSocket::lookup(gatewayAddress);
CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
}
CNXDNNetwork::~CNXDNNetwork()
@ -50,7 +50,7 @@ bool CNXDNNetwork::open()
{
LogMessage("Opening NXDN network connection");
if (m_address.s_addr == INADDR_NONE)
if (CUDPSocket::isnone(m_address))
return false;
return m_socket.open();
@ -100,25 +100,19 @@ bool CNXDNNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE ty
if (m_debug)
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)
{
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
sockaddr_storage address;
unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0 || !CUDPSocket::match(m_address, address))
return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || port != m_port) {
LogMessage("NXDN packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Invalid packet type?
if (::memcmp(buffer, "ICOM", 4U) != 0)
return;

View file

@ -57,8 +57,8 @@ public:
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
sockaddr_storage m_address;
unsigned int m_addrlen;
bool m_debug;
bool m_enabled;
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
* it under the terms of the GNU General Public License as published by
@ -102,7 +102,6 @@ bool CNextion::open()
return true;
}
void CNextion::setIdleInt()
{
// a few bits borrowed from Lieven De Samblanx ON7LDS, NextionDriver
@ -240,6 +239,25 @@ void CNextion::setQuitInt()
m_mode = MODE_QUIT;
}
void CNextion::setFMInt()
{
sendCommand("page MMDVM");
sendCommandAction(1U);
char command[20];
if (m_brightness > 0) {
::sprintf(command, "dim=%u", m_brightness);
sendCommand(command);
}
sendCommand("t0.txt=\"FM\"");
sendCommandAction(15U);
m_clockDisplayTimer.stop();
m_mode = MODE_FM;
}
void CNextion::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{
assert(my1 != NULL);

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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void writeDStarRSSIInt(unsigned char rssi);

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
* 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)
{
#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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt();

View file

@ -32,8 +32,8 @@ public:
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 setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled){};
virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel){};
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, float fmTXLevel){};
virtual void setDMRParams(unsigned int colorCode){};
virtual void setYSFParams(bool loDev, unsigned int txHang){};
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
* it under the terms of the GNU General Public License as published by
@ -306,6 +306,21 @@ void COLED::setQuitInt()
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)
{
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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt();

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) :
m_socket(localPort),
m_address(),
m_port(gatewayPort),
m_addrlen(),
m_debug(debug),
m_enabled(false),
m_buffer(1000U, "P25 Network"),
m_audio()
{
m_address = CUDPSocket::lookup(gatewayAddress);
CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
}
CP25Network::~CP25Network()
@ -107,10 +107,10 @@ bool CP25Network::open()
{
LogMessage("Opening P25 network connection");
if (m_address.s_addr == INADDR_NONE)
if (CUDPSocket::isnone(m_address))
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)
@ -126,7 +126,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -137,7 +137,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -150,7 +150,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -165,7 +165,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -180,7 +180,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -191,7 +191,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -202,7 +202,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -213,7 +213,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -226,7 +226,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
@ -234,7 +234,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control,
if (m_debug)
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)
return false;
}
@ -255,7 +255,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -266,7 +266,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -283,7 +283,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -297,7 +297,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -311,7 +311,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -326,7 +326,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -337,7 +337,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -348,7 +348,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -361,7 +361,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
@ -369,7 +369,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control,
if (m_debug)
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)
return false;
}
@ -381,18 +381,12 @@ void CP25Network::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
sockaddr_storage address;
unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0 || !CUDPSocket::match(m_address, address))
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)
return;

View file

@ -49,8 +49,8 @@ public:
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
sockaddr_storage m_address;
unsigned int m_addrlen;
bool m_debug;
bool m_enabled;
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) :
m_socket(myAddress, myPort),
m_address(),
m_port(gatewayPort),
m_addrlen(),
m_debug(debug),
m_enabled(false),
m_buffer(1000U, "POCSAG Network")
{
m_address = CUDPSocket::lookup(gatewayAddress);
CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen);
}
CPOCSAGNetwork::~CPOCSAGNetwork()
@ -47,7 +47,7 @@ bool CPOCSAGNetwork::open()
{
LogMessage("Opening POCSAG network connection");
if (m_address.s_addr == INADDR_NONE)
if (CUDPSocket::isnone(m_address))
return false;
return m_socket.open();
@ -57,18 +57,12 @@ void CPOCSAGNetwork::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
sockaddr_storage address;
unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0 || !CUDPSocket::match(m_address, address))
return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || m_port != port) {
LogMessage("POCSAG packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Invalid packet type?
if (::memcmp(buffer, "POCSAG", 6U) != 0)
return;
@ -118,7 +112,7 @@ void CPOCSAGNetwork::enable(bool enabled)
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;
}

View file

@ -46,8 +46,8 @@ public:
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
sockaddr_storage m_address;
unsigned int m_addrlen;
bool m_debug;
bool m_enabled;
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)
- 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)
- 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) :
m_port(port)
{
::LogInitialise(".", "RemoteCommand", 2U, 2U);
::LogInitialise(false, ".", "RemoteCommand", 2U, 2U);
}
CRemoteCommand::~CRemoteCommand()
@ -61,15 +61,17 @@ CRemoteCommand::~CRemoteCommand()
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);
bool ret = socket.open();
bool ret = socket.open(address.ss_family);
if (!ret)
return 1;
in_addr address = CUDPSocket::lookup("localhost");
ret = socket.write((unsigned char*)command.c_str(), command.length(), address, m_port);
ret = socket.write((unsigned char*)command.c_str(), command.length(), address, addrlen);
if (!ret) {
socket.close();
return 1;

View file

@ -25,12 +25,15 @@
#include <cstring>
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 CW_ARGS = 2U;
const unsigned int BUFFER_LENGTH = 100U;
CRemoteControl::CRemoteControl(unsigned int port) :
m_socket(port),
CRemoteControl::CRemoteControl(const std::string address, unsigned int port) :
m_socket(address, port),
m_command(RCD_NONE),
m_args()
{
@ -53,9 +56,9 @@ REMOTE_COMMAND CRemoteControl::getCommand()
char command[BUFFER_LENGTH];
char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int ret = m_socket.read((unsigned char*)buffer, BUFFER_LENGTH, address, port);
sockaddr_storage address;
unsigned int addrlen;
int ret = m_socket.read((unsigned char*)buffer, BUFFER_LENGTH, address, addrlen);
if (ret > 0) {
buffer[ret] = '\0';
@ -86,10 +89,39 @@ REMOTE_COMMAND CRemoteControl::getCommand()
m_command = RCD_MODE_P25;
else if (m_args.at(1U) == "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) {
// Page command is in the form of "page <ric> <message>"
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) {
m_args.clear();
@ -115,6 +147,8 @@ unsigned int CRemoteControl::getArgCount() const
return m_args.size() - SET_MODE_ARGS;
case RCD_PAGE:
return m_args.size() - 1U;
case RCD_CW:
return m_args.size() - 1U;
default:
return 0U;
}
@ -135,6 +169,9 @@ std::string CRemoteControl::getArgString(unsigned int n) const
case RCD_PAGE:
n += 1U;
break;
case RCD_CW:
n += 1U;
break;
default:
return "";
}

View file

@ -33,12 +33,26 @@ enum REMOTE_COMMAND {
RCD_MODE_YSF,
RCD_MODE_P25,
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 {
public:
CRemoteControl(unsigned int port);
CRemoteControl(const std::string address, unsigned int port);
~CRemoteControl();
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
* it under the terms of the GNU General Public License as published by
@ -161,6 +161,22 @@ void CTFTSerial::setQuitInt()
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)
{
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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt();

View file

@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -174,6 +174,14 @@ void CTFTSurenoo::setQuitInt()
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)
{
assert(my1 != NULL);

View file

@ -1,6 +1,6 @@
/*
* 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
* 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 setLockoutInt();
virtual void setQuitInt();
virtual void setFMInt();
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
virtual void clearDStarInt();

View file

@ -60,49 +60,96 @@ CUDPSocket::~CUDPSocket()
#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;
#if defined(_WIN32) || defined(_WIN64)
unsigned long address = ::inet_addr(hostname.c_str());
if (address != INADDR_NONE && address != INADDR_ANY) {
addr.s_addr = address;
return addr;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
return lookup(hostname, port, addr, address_length, hints);
}
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());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
freeaddrinfo(res);
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;
#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
return ( (addr.ss_family == AF_INET) &&
(in->sin_addr.s_addr == htonl(INADDR_NONE)) );
}
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 defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
@ -113,24 +160,6 @@ bool CUDPSocket::open()
}
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;
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
@ -141,7 +170,7 @@ bool CUDPSocket::open()
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)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
@ -154,7 +183,7 @@ bool CUDPSocket::open()
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(length > 0U);
@ -186,17 +215,16 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres
if (ret == 0)
return 0;
sockaddr_in addr;
#if defined(_WIN32) || defined(_WIN64)
int size = sizeof(sockaddr_in);
int size = sizeof(sockaddr_storage);
#else
socklen_t size = sizeof(sockaddr_in);
socklen_t size = sizeof(sockaddr_storage);
#endif
#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
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
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -207,28 +235,19 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres
return -1;
}
address = addr.sin_addr;
port = ntohs(addr.sin_port);
address_length = size;
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(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)
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
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
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)

View file

@ -31,7 +31,8 @@
#include <arpa/inet.h>
#include <errno.h>
#else
#include <winsock.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
class CUDPSocket {
@ -41,13 +42,17 @@ public:
~CUDPSocket();
bool open();
bool open(const unsigned int af);
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
bool write(const unsigned char* buffer, unsigned int length, const 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 sockaddr_storage& address, unsigned int address_length);
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:
std::string m_address;

View file

@ -42,7 +42,7 @@ bool CUserDB::lookup(unsigned int id, class CUserDBentry *entry)
if (entry != NULL)
*entry = m_table.at(id);
else
m_table.at(id);
(void)m_table.at(id);
rv = true;
} catch (...) {
@ -116,8 +116,8 @@ bool CUserDB::makeindex(char* buf, std::unordered_map<std::string, int>& index)
}
try {
index.at(keyRADIO_ID);
index.at(keyCALLSIGN);
(void)index.at(keyRADIO_ID);
(void)index.at(keyCALLSIGN);
return true;
} catch (...) {
return false;
@ -144,8 +144,8 @@ void CUserDB::parse(char* buf, std::unordered_map<std::string, int>& index)
}
try {
ptr.at(keyRADIO_ID);
ptr.at(keyCALLSIGN);
(void)ptr.at(keyRADIO_ID);
(void)ptr.at(keyCALLSIGN);
} catch (...) {
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
* it under the terms of the GNU General Public License as published by
@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20190131";
const char* VERSION = "20200608";
#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) :
m_socket(myAddress, myPort),
m_address(),
m_port(gatewayPort),
m_addrlen(),
m_callsign(),
m_debug(debug),
m_enabled(false),
@ -42,7 +42,7 @@ m_tag(NULL)
m_callsign = callsign;
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];
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
@ -57,7 +57,7 @@ bool CYSFNetwork::open()
{
LogMessage("Opening YSF network connection");
if (m_address.s_addr == INADDR_NONE)
if (CUDPSocket::isnone(m_address))
return false;
m_pollTimer.start();
@ -97,7 +97,7 @@ bool CYSFNetwork::write(const unsigned char* src, const unsigned char* dest, con
if (m_debug)
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()
@ -115,7 +115,7 @@ bool CYSFNetwork::writePoll()
if (m_debug)
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)
@ -128,18 +128,12 @@ void CYSFNetwork::clock(unsigned int ms)
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
sockaddr_storage address;
unsigned int addrlen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen);
if (length <= 0 || !CUDPSocket::match(m_address, address))
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
if (::memcmp(buffer, "YSFP", 4U) == 0)
return;

View file

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