Merge remote-tracking branch 'g4klx/master'

This commit is contained in:
Andy CA6JAU 2017-12-26 18:06:50 -03:00
commit bafa100e66
110 changed files with 20544 additions and 1430 deletions

290
Conf.cpp
View file

@ -55,10 +55,9 @@ enum SECTION {
CConf::CConf(const std::string& file) :
m_file(file),
m_callsign(),
m_id(0U),
m_timeout(120U),
m_duplex(true),
m_rfModeHang(10U),
m_netModeHang(3U),
m_display(),
m_daemon(false),
m_rxFrequency(0U),
@ -85,12 +84,16 @@ m_modemTXInvert(false),
m_modemPTTInvert(false),
m_modemTXDelay(100U),
m_modemDMRDelay(0U),
m_modemRXLevel(50U),
m_modemCWIdTXLevel(50U),
m_modemDStarTXLevel(50U),
m_modemDMRTXLevel(50U),
m_modemYSFTXLevel(50U),
m_modemP25TXLevel(50U),
m_modemTXOffset(0),
m_modemRXOffset(0),
m_modemRXDCOffset(0),
m_modemTXDCOffset(0),
m_modemRXLevel(50.0F),
m_modemCWIdTXLevel(50.0F),
m_modemDStarTXLevel(50.0F),
m_modemDMRTXLevel(50.0F),
m_modemYSFTXLevel(50.0F),
m_modemP25TXLevel(50.0F),
m_modemRSSIMappingFile(),
m_modemTrace(false),
m_modemDebug(false),
@ -100,7 +103,11 @@ m_dstarEnabled(false),
m_dstarModule("C"),
m_dstarSelfOnly(false),
m_dstarBlackList(),
m_dstarAckReply(true),
m_dstarAckTime(750U),
m_dstarErrorReply(true),
m_dstarRemoteGateway(false),
m_dstarModeHang(10U),
m_dmrEnabled(false),
m_dmrBeacons(false),
m_dmrId(0U),
@ -115,15 +122,26 @@ m_dmrSlot1TGWhiteList(),
m_dmrSlot2TGWhiteList(),
m_dmrCallHang(3U),
m_dmrTXHang(4U),
m_dmrModeHang(10U),
m_fusionEnabled(false),
m_fusionLowDeviation(false),
m_fusionRemoteGateway(false),
m_fusionSelfOnly(false),
m_fusionSQLEnabled(false),
m_fusionSQL(0U),
m_fusionModeHang(10U),
m_p25Enabled(false),
m_p25Id(0U),
m_p25NAC(0x293U),
m_p25SelfOnly(false),
m_p25OverrideUID(false),
m_p25RemoteGateway(false),
m_p25ModeHang(10U),
m_dstarNetworkEnabled(false),
m_dstarGatewayAddress(),
m_dstarGatewayPort(0U),
m_dstarLocalPort(0U),
m_dstarNetworkModeHang(3U),
m_dstarNetworkDebug(false),
m_dmrNetworkEnabled(false),
m_dmrNetworkAddress(),
@ -135,18 +153,20 @@ m_dmrNetworkDebug(false),
m_dmrNetworkJitter(300U),
m_dmrNetworkSlot1(true),
m_dmrNetworkSlot2(true),
m_dmrNetworkModeHang(3U),
m_fusionNetworkEnabled(false),
m_fusionNetworkMyAddress(),
m_fusionNetworkMyPort(0U),
m_fusionNetworkGwyAddress(),
m_fusionNetworkGwyPort(0U),
m_fusionNetworkGatewayAddress(),
m_fusionNetworkGatewayPort(0U),
m_fusionNetworkModeHang(3U),
m_fusionNetworkDebug(false),
m_p25NetworkEnabled(false),
m_p25GatewayAddress(),
m_p25GatewayPort(0U),
m_p25LocalPort(0U),
m_p25NetworkModeHang(3U),
m_p25NetworkDebug(false),
m_p25OverrideUID(false),
m_tftSerialPort("/dev/ttyAMA0"),
m_tftSerialBrightness(50U),
m_hd44780Rows(2U),
@ -164,9 +184,11 @@ m_nextionBrightness(50U),
m_nextionDisplayClock(false),
m_nextionUTC(false),
m_nextionIdleBrightness(20U),
m_nextionScreenLayout(0U),
m_oledType(3U),
m_oledBrightness(0U),
m_oledInvert(false),
m_oledScroll(false),
m_lcdprocAddress(),
m_lcdprocPort(0U),
m_lcdprocLocalPort(0U),
@ -255,16 +277,19 @@ bool CConf::read()
for (unsigned int i = 0U; value[i] != 0; i++)
value[i] = ::toupper(value[i]);
m_cwIdCallsign = m_callsign = value;
} else if (::strcmp(key, "Timeout") == 0)
} 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);
else if (::strcmp(key, "Duplex") == 0)
m_duplex = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
m_rfModeHang = m_netModeHang = (unsigned int)::atoi(value);
m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang =
m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "RFModeHang") == 0)
m_rfModeHang = (unsigned int)::atoi(value);
m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "NetModeHang") == 0)
m_netModeHang = (unsigned int)::atoi(value);
m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Display") == 0)
m_display = value;
else if (::strcmp(key, "Daemon") == 0)
@ -326,20 +351,28 @@ bool CConf::read()
m_modemTXDelay = (unsigned int)::atoi(value);
else if (::strcmp(key, "DMRDelay") == 0)
m_modemDMRDelay = (unsigned int)::atoi(value);
else if (::strcmp(key, "RXOffset") == 0)
m_modemRXOffset = ::atoi(value);
else if (::strcmp(key, "TXOffset") == 0)
m_modemTXOffset = ::atoi(value);
else if (::strcmp(key, "RXDCOffset") == 0)
m_modemRXDCOffset = ::atoi(value);
else if (::strcmp(key, "TXDCOffset") == 0)
m_modemTXDCOffset = ::atoi(value);
else if (::strcmp(key, "RXLevel") == 0)
m_modemRXLevel = (unsigned int)::atoi(value);
m_modemRXLevel = float(::atof(value));
else if (::strcmp(key, "TXLevel") == 0)
m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = (unsigned int)::atoi(value);
m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = float(::atof(value));
else if (::strcmp(key, "CWIdTXLevel") == 0)
m_modemCWIdTXLevel = (unsigned int)::atoi(value);
m_modemCWIdTXLevel = float(::atof(value));
else if (::strcmp(key, "D-StarTXLevel") == 0)
m_modemDStarTXLevel = (unsigned int)::atoi(value);
m_modemDStarTXLevel = float(::atof(value));
else if (::strcmp(key, "DMRTXLevel") == 0)
m_modemDMRTXLevel = (unsigned int)::atoi(value);
m_modemDMRTXLevel = float(::atof(value));
else if (::strcmp(key, "YSFTXLevel") == 0)
m_modemYSFTXLevel = (unsigned int)::atoi(value);
m_modemYSFTXLevel = float(::atof(value));
else if (::strcmp(key, "P25TXLevel") == 0)
m_modemP25TXLevel = (unsigned int)::atoi(value);
m_modemP25TXLevel = float(::atof(value));
else if (::strcmp(key, "RSSIMappingFile") == 0)
m_modemRSSIMappingFile = value;
else if (::strcmp(key, "Trace") == 0)
@ -373,8 +406,16 @@ bool CConf::read()
}
p = ::strtok(NULL, ",\r\n");
}
} else if (::strcmp(key, "ErrorReply") == 0)
} else if (::strcmp(key, "AckReply") == 0)
m_dstarAckReply = ::atoi(value) == 1;
else if (::strcmp(key, "AckTime") == 0)
m_dstarAckTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "ErrorReply") == 0)
m_dstarErrorReply = ::atoi(value) == 1;
else if (::strcmp(key, "RemoteGateway") == 0)
m_dstarRemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
m_dstarModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_DMR) {
if (::strcmp(key, "Enable") == 0)
m_dmrEnabled = ::atoi(value) == 1;
@ -434,20 +475,37 @@ bool CConf::read()
m_dmrTXHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "CallHang") == 0)
m_dmrCallHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_dmrModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_FUSION) {
if (::strcmp(key, "Enable") == 0)
m_fusionEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "LowDeviation") == 0)
m_fusionLowDeviation = ::atoi(value) == 1;
else if (::strcmp(key, "RemoteGateway") == 0)
else if (::strcmp(key, "DSQ") == 0) {
m_fusionSQLEnabled = true;
m_fusionSQL = (unsigned int)::atoi(value);
} else if (::strcmp(key, "RemoteGateway") == 0)
m_fusionRemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "SelfOnly") == 0)
m_fusionSelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
m_fusionModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_P25) {
if (::strcmp(key, "Enable") == 0)
m_p25Enabled = ::atoi(value) == 1;
else if (::strcmp(key, "Id") == 0)
m_p25Id = (unsigned int)::atoi(value);
else if (::strcmp(key, "NAC") == 0)
m_p25NAC = (unsigned int)::strtoul(value, NULL, 16);
else if (::strcmp(key, "OverrideUIDCheck") == 0)
m_p25OverrideUID = ::atoi(value) == 1;
else if (::strcmp(key, "SelfOnly") == 0)
m_p25SelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "RemoteGateway") == 0)
m_p25RemoteGateway = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
m_p25ModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_DSTAR_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_dstarNetworkEnabled = ::atoi(value) == 1;
@ -457,6 +515,8 @@ bool CConf::read()
m_dstarGatewayPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "LocalPort") == 0)
m_dstarLocalPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_dstarNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_dstarNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_DMR_NETWORK) {
@ -480,6 +540,8 @@ bool CConf::read()
m_dmrNetworkSlot1 = ::atoi(value) == 1;
else if (::strcmp(key, "Slot2") == 0)
m_dmrNetworkSlot2 = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
m_dmrNetworkModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_FUSION_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_fusionNetworkEnabled = ::atoi(value) == 1;
@ -487,10 +549,12 @@ bool CConf::read()
m_fusionNetworkMyAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_fusionNetworkMyPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "GwyAddress") == 0)
m_fusionNetworkGwyAddress = value;
else if (::strcmp(key, "GwyPort") == 0)
m_fusionNetworkGwyPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "GatewayAddress") == 0)
m_fusionNetworkGatewayAddress = value;
else if (::strcmp(key, "GatewayPort") == 0)
m_fusionNetworkGatewayPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_fusionNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_fusionNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_P25_NETWORK) {
@ -502,6 +566,8 @@ bool CConf::read()
m_p25GatewayPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "LocalPort") == 0)
m_p25LocalPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_p25NetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_p25NetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_TFTSERIAL) {
@ -547,6 +613,8 @@ bool CConf::read()
m_nextionUTC = ::atoi(value) == 1;
else if (::strcmp(key, "IdleBrightness") == 0)
m_nextionIdleBrightness = (unsigned int)::atoi(value);
else if (::strcmp(key, "ScreenLayout") == 0)
m_nextionScreenLayout = (unsigned int)::atoi(value);
} else if (section == SECTION_OLED) {
if (::strcmp(key, "Type") == 0)
m_oledType = (unsigned char)::atoi(value);
@ -554,6 +622,8 @@ bool CConf::read()
m_oledBrightness = (unsigned char)::atoi(value);
else if (::strcmp(key, "Invert") == 0)
m_oledInvert = ::atoi(value) == 1;
else if (::strcmp(key, "Scroll") == 0)
m_oledScroll = ::atoi(value) == 1;
} else if (section == SECTION_LCDPROC) {
if (::strcmp(key, "Address") == 0)
m_lcdprocAddress = value;
@ -580,6 +650,11 @@ std::string CConf::getCallsign() const
return m_callsign;
}
unsigned int CConf::getId() const
{
return m_id;
}
unsigned int CConf::getTimeout() const
{
return m_timeout;
@ -590,16 +665,6 @@ bool CConf::getDuplex() const
return m_duplex;
}
unsigned int CConf::getRFModeHang() const
{
return m_rfModeHang;
}
unsigned int CConf::getNetModeHang() const
{
return m_netModeHang;
}
std::string CConf::getDisplay() const
{
return m_display;
@ -610,12 +675,12 @@ bool CConf::getDaemon() const
return m_daemon;
}
unsigned int CConf::getRxFrequency() const
unsigned int CConf::getRXFrequency() const
{
return m_rxFrequency;
}
unsigned int CConf::getTxFrequency() const
unsigned int CConf::getTXFrequency() const
{
return m_txFrequency;
}
@ -730,32 +795,52 @@ unsigned int CConf::getModemDMRDelay() const
return m_modemDMRDelay;
}
unsigned int CConf::getModemRXLevel() const
int CConf::getModemRXOffset() const
{
return m_modemRXOffset;
}
int CConf::getModemTXOffset() const
{
return m_modemTXOffset;
}
int CConf::getModemRXDCOffset() const
{
return m_modemRXDCOffset;
}
int CConf::getModemTXDCOffset() const
{
return m_modemTXDCOffset;
}
float CConf::getModemRXLevel() const
{
return m_modemRXLevel;
}
unsigned int CConf::getModemCWIdTXLevel() const
float CConf::getModemCWIdTXLevel() const
{
return m_modemCWIdTXLevel;
}
unsigned int CConf::getModemDStarTXLevel() const
float CConf::getModemDStarTXLevel() const
{
return m_modemDStarTXLevel;
}
unsigned int CConf::getModemDMRTXLevel() const
float CConf::getModemDMRTXLevel() const
{
return m_modemDMRTXLevel;
}
unsigned int CConf::getModemYSFTXLevel() const
float CConf::getModemYSFTXLevel() const
{
return m_modemYSFTXLevel;
}
unsigned int CConf::getModemP25TXLevel() const
float CConf::getModemP25TXLevel() const
{
return m_modemP25TXLevel;
}
@ -805,11 +890,31 @@ std::vector<std::string> CConf::getDStarBlackList() const
return m_dstarBlackList;
}
bool CConf::getDStarAckReply() const
{
return m_dstarAckReply;
}
unsigned int CConf::getDStarAckTime() const
{
return m_dstarAckTime;
}
bool CConf::getDStarErrorReply() const
{
return m_dstarErrorReply;
}
bool CConf::getDStarRemoteGateway() const
{
return m_dstarRemoteGateway;
}
unsigned int CConf::getDStarModeHang() const
{
return m_dstarModeHang;
}
bool CConf::getDMREnabled() const
{
return m_dmrEnabled;
@ -880,6 +985,11 @@ unsigned int CConf::getDMRTXHang() const
return m_dmrTXHang;
}
unsigned int CConf::getDMRModeHang() const
{
return m_dmrModeHang;
}
bool CConf::getFusionEnabled() const
{
return m_fusionEnabled;
@ -895,16 +1005,61 @@ bool CConf::getFusionRemoteGateway() const
return m_fusionRemoteGateway;
}
bool CConf::getFusionSelfOnly() const
{
return m_fusionSelfOnly;
}
bool CConf::getFusionSQLEnabled() const
{
return m_fusionSQLEnabled;
}
unsigned char CConf::getFusionSQL() const
{
return m_fusionSQL;
}
unsigned int CConf::getFusionModeHang() const
{
return m_fusionModeHang;
}
bool CConf::getP25Enabled() const
{
return m_p25Enabled;
}
unsigned int CConf::getP25Id() const
{
return m_p25Id;
}
unsigned int CConf::getP25NAC() const
{
return m_p25NAC;
}
bool CConf::getP25OverrideUID() const
{
return m_p25OverrideUID;
}
bool CConf::getP25SelfOnly() const
{
return m_p25SelfOnly;
}
bool CConf::getP25RemoteGateway() const
{
return m_p25RemoteGateway;
}
unsigned int CConf::getP25ModeHang() const
{
return m_p25ModeHang;
}
bool CConf::getDStarNetworkEnabled() const
{
return m_dstarNetworkEnabled;
@ -925,6 +1080,11 @@ unsigned int CConf::getDStarLocalPort() const
return m_dstarLocalPort;
}
unsigned int CConf::getDStarNetworkModeHang() const
{
return m_dstarNetworkModeHang;
}
bool CConf::getDStarNetworkDebug() const
{
return m_dstarNetworkDebug;
@ -960,6 +1120,11 @@ std::string CConf::getDMRNetworkOptions() const
return m_dmrNetworkOptions;
}
unsigned int CConf::getDMRNetworkModeHang() const
{
return m_dmrNetworkModeHang;
}
bool CConf::getDMRNetworkDebug() const
{
return m_dmrNetworkDebug;
@ -995,14 +1160,19 @@ unsigned int CConf::getFusionNetworkMyPort() const
return m_fusionNetworkMyPort;
}
std::string CConf::getFusionNetworkGwyAddress() const
std::string CConf::getFusionNetworkGatewayAddress() const
{
return m_fusionNetworkGwyAddress;
return m_fusionNetworkGatewayAddress;
}
unsigned int CConf::getFusionNetworkGwyPort() const
unsigned int CConf::getFusionNetworkGatewayPort() const
{
return m_fusionNetworkGwyPort;
return m_fusionNetworkGatewayPort;
}
unsigned int CConf::getFusionNetworkModeHang() const
{
return m_fusionNetworkModeHang;
}
bool CConf::getFusionNetworkDebug() const
@ -1030,16 +1200,16 @@ unsigned int CConf::getP25LocalPort() const
return m_p25LocalPort;
}
unsigned int CConf::getP25NetworkModeHang() const
{
return m_p25NetworkModeHang;
}
bool CConf::getP25NetworkDebug() const
{
return m_p25NetworkDebug;
}
bool CConf::getP25OverrideUID() const
{
return m_p25OverrideUID;
}
std::string CConf::getTFTSerialPort() const
{
return m_tftSerialPort;
@ -1125,6 +1295,11 @@ unsigned int CConf::getNextionIdleBrightness() const
return m_nextionIdleBrightness;
}
unsigned int CConf::getNextionScreenLayout() const
{
return m_nextionScreenLayout;
}
unsigned char CConf::getOLEDType() const
{
return m_oledType;
@ -1140,6 +1315,11 @@ bool CConf::getOLEDInvert() const
return m_oledInvert;
}
bool CConf::getOLEDScroll() const
{
return m_oledScroll;
}
std::string CConf::getLCDprocAddress() const
{
return m_lcdprocAddress;

104
Conf.h
View file

@ -32,16 +32,15 @@ public:
// The General section
std::string getCallsign() const;
unsigned int getId() const;
unsigned int getTimeout() const;
bool getDuplex() const;
unsigned int getRFModeHang() const;
unsigned int getNetModeHang() const;
std::string getDisplay() const;
bool getDaemon() const;
// The Info section
unsigned int getRxFrequency() const;
unsigned int getTxFrequency() const;
unsigned int getRXFrequency() const;
unsigned int getTXFrequency() const;
unsigned int getPower() const;
float getLatitude() const;
float getLongitude() const;
@ -72,12 +71,16 @@ public:
bool getModemPTTInvert() const;
unsigned int getModemTXDelay() const;
unsigned int getModemDMRDelay() const;
unsigned int getModemRXLevel() const;
unsigned int getModemCWIdTXLevel() const;
unsigned int getModemDStarTXLevel() const;
unsigned int getModemDMRTXLevel() const;
unsigned int getModemYSFTXLevel() const;
unsigned int getModemP25TXLevel() const;
int getModemTXOffset() const;
int getModemRXOffset() const;
int getModemRXDCOffset() const;
int getModemTXDCOffset() const;
float getModemRXLevel() const;
float getModemCWIdTXLevel() const;
float getModemDStarTXLevel() const;
float getModemDMRTXLevel() const;
float getModemYSFTXLevel() const;
float getModemP25TXLevel() const;
std::string getModemRSSIMappingFile() const;
bool getModemTrace() const;
bool getModemDebug() const;
@ -91,7 +94,11 @@ public:
std::string getDStarModule() const;
bool getDStarSelfOnly() const;
std::vector<std::string> getDStarBlackList() const;
bool getDStarAckReply() const;
unsigned int getDStarAckTime() const;
bool getDStarErrorReply() const;
bool getDStarRemoteGateway() const;
unsigned int getDStarModeHang() const;
// The DMR section
bool getDMREnabled() const;
@ -108,21 +115,32 @@ public:
std::vector<unsigned int> getDMRSlot2TGWhiteList() const;
unsigned int getDMRCallHang() const;
unsigned int getDMRTXHang() const;
unsigned int getDMRModeHang() const;
// The System Fusion section
bool getFusionEnabled() const;
bool getFusionLowDeviation() const;
bool getFusionRemoteGateway() const;
bool getFusionEnabled() const;
bool getFusionLowDeviation() const;
bool getFusionRemoteGateway() const;
bool getFusionSelfOnly() const;
bool getFusionSQLEnabled() const;
unsigned char getFusionSQL() const;
unsigned int getFusionModeHang() const;
// The P25 section
bool getP25Enabled() const;
unsigned int getP25Id() const;
unsigned int getP25NAC() const;
bool getP25SelfOnly() const;
bool getP25OverrideUID() const;
bool getP25RemoteGateway() const;
unsigned int getP25ModeHang() const;
// The D-Star Network section
bool getDStarNetworkEnabled() const;
std::string getDStarGatewayAddress() const;
unsigned int getDStarGatewayPort() const;
unsigned int getDStarLocalPort() const;
unsigned int getDStarNetworkModeHang() const;
bool getDStarNetworkDebug() const;
// The DMR Network section
@ -136,13 +154,15 @@ public:
unsigned int getDMRNetworkJitter() const;
bool getDMRNetworkSlot1() const;
bool getDMRNetworkSlot2() const;
unsigned int getDMRNetworkModeHang() const;
// The System Fusion Network section
bool getFusionNetworkEnabled() const;
std::string getFusionNetworkMyAddress() const;
unsigned int getFusionNetworkMyPort() const;
std::string getFusionNetworkGwyAddress() const;
unsigned int getFusionNetworkGwyPort() const;
std::string getFusionNetworkGatewayAddress() const;
unsigned int getFusionNetworkGatewayPort() const;
unsigned int getFusionNetworkModeHang() const;
bool getFusionNetworkDebug() const;
// The P25 Network section
@ -150,8 +170,8 @@ public:
std::string getP25GatewayAddress() const;
unsigned int getP25GatewayPort() const;
unsigned int getP25LocalPort() const;
unsigned int getP25NetworkModeHang() const;
bool getP25NetworkDebug() const;
bool getP25OverrideUID() const;
// The TFTSERIAL section
std::string getTFTSerialPort() const;
@ -175,11 +195,13 @@ public:
bool getNextionDisplayClock() const;
bool getNextionUTC() const;
unsigned int getNextionIdleBrightness() const;
unsigned int getNextionScreenLayout() const;
// The OLED section
unsigned char getOLEDType() const;
unsigned char getOLEDBrightness() const;
bool getOLEDInvert() const;
bool getOLEDScroll() const;
// The LCDproc section
std::string getLCDprocAddress() const;
@ -192,10 +214,9 @@ public:
private:
std::string m_file;
std::string m_callsign;
unsigned int m_id;
unsigned int m_timeout;
bool m_duplex;
unsigned int m_rfModeHang;
unsigned int m_netModeHang;
std::string m_display;
bool m_daemon;
@ -227,12 +248,16 @@ private:
bool m_modemPTTInvert;
unsigned int m_modemTXDelay;
unsigned int m_modemDMRDelay;
unsigned int m_modemRXLevel;
unsigned int m_modemCWIdTXLevel;
unsigned int m_modemDStarTXLevel;
unsigned int m_modemDMRTXLevel;
unsigned int m_modemYSFTXLevel;
unsigned int m_modemP25TXLevel;
int m_modemTXOffset;
int m_modemRXOffset;
int m_modemRXDCOffset;
int m_modemTXDCOffset;
float m_modemRXLevel;
float m_modemCWIdTXLevel;
float m_modemDStarTXLevel;
float m_modemDMRTXLevel;
float m_modemYSFTXLevel;
float m_modemP25TXLevel;
std::string m_modemRSSIMappingFile;
bool m_modemTrace;
bool m_modemDebug;
@ -244,7 +269,11 @@ private:
std::string m_dstarModule;
bool m_dstarSelfOnly;
std::vector<std::string> m_dstarBlackList;
bool m_dstarAckReply;
unsigned int m_dstarAckTime;
bool m_dstarErrorReply;
bool m_dstarRemoteGateway;
unsigned int m_dstarModeHang;
bool m_dmrEnabled;
bool m_dmrBeacons;
@ -260,18 +289,29 @@ private:
std::vector<unsigned int> m_dmrSlot2TGWhiteList;
unsigned int m_dmrCallHang;
unsigned int m_dmrTXHang;
unsigned int m_dmrModeHang;
bool m_fusionEnabled;
bool m_fusionLowDeviation;
bool m_fusionRemoteGateway;
bool m_fusionEnabled;
bool m_fusionLowDeviation;
bool m_fusionRemoteGateway;
bool m_fusionSelfOnly;
bool m_fusionSQLEnabled;
unsigned char m_fusionSQL;
unsigned int m_fusionModeHang;
bool m_p25Enabled;
unsigned int m_p25Id;
unsigned int m_p25NAC;
bool m_p25SelfOnly;
bool m_p25OverrideUID;
bool m_p25RemoteGateway;
unsigned int m_p25ModeHang;
bool m_dstarNetworkEnabled;
std::string m_dstarGatewayAddress;
unsigned int m_dstarGatewayPort;
unsigned int m_dstarLocalPort;
unsigned int m_dstarNetworkModeHang;
bool m_dstarNetworkDebug;
bool m_dmrNetworkEnabled;
@ -284,20 +324,22 @@ private:
unsigned int m_dmrNetworkJitter;
bool m_dmrNetworkSlot1;
bool m_dmrNetworkSlot2;
unsigned int m_dmrNetworkModeHang;
bool m_fusionNetworkEnabled;
std::string m_fusionNetworkMyAddress;
unsigned int m_fusionNetworkMyPort;
std::string m_fusionNetworkGwyAddress;
unsigned int m_fusionNetworkGwyPort;
std::string m_fusionNetworkGatewayAddress;
unsigned int m_fusionNetworkGatewayPort;
unsigned int m_fusionNetworkModeHang;
bool m_fusionNetworkDebug;
bool m_p25NetworkEnabled;
std::string m_p25GatewayAddress;
unsigned int m_p25GatewayPort;
unsigned int m_p25LocalPort;
unsigned int m_p25NetworkModeHang;
bool m_p25NetworkDebug;
bool m_p25OverrideUID;
std::string m_tftSerialPort;
unsigned int m_tftSerialBrightness;
@ -318,10 +360,12 @@ private:
bool m_nextionDisplayClock;
bool m_nextionUTC;
unsigned int m_nextionIdleBrightness;
unsigned int m_nextionScreenLayout;
unsigned char m_oledType;
unsigned char m_oledBrightness;
bool m_oledInvert;
bool m_oledScroll;
std::string m_lcdprocAddress;
unsigned int m_lcdprocPort;

View file

@ -48,8 +48,14 @@ void CDMRAccessControl::init(const std::vector<unsigned int>& blacklist, const s
bool CDMRAccessControl::validateSrcId(unsigned int id)
{
if (m_selfOnly)
return id == m_id;
if (m_selfOnly) {
if (m_id > 99999999U) // Check that the Config DMR-ID is bigger than 8 digits
return id == m_id / 100U; // Does RF ID match Config ID / 100
else if (m_id > 9999999U) // Check that the Config DMR-ID is bigger than 7 digits
return id == m_id / 10U; // Does RF ID match Config ID / 10
else
return id == m_id;
}
if (std::find(m_blackList.begin(), m_blackList.end(), id) != m_blackList.end())
return false;

View file

@ -22,7 +22,6 @@
#include <algorithm>
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter) :
m_id(id),
m_colorCode(colorCode),
m_modem(modem),
m_network(network),
@ -64,25 +63,17 @@ bool CDMRControl::processWakeup(const unsigned char* data)
return false;
unsigned int srcId = csbk.getSrcId();
unsigned int bsId = csbk.getBSId();
std::string src = m_lookup->find(srcId);
bool ret = CDMRAccessControl::validateSrcId(srcId);
if (!ret) {
LogMessage("Invalid CSBK BS_Dwn_Act received from %s", src.c_str());
LogMessage("Invalid Downlink Activate received from %s", src.c_str());
return false;
}
if (bsId == 0xFFFFFFU) {
LogMessage("CSBK BS_Dwn_Act for ANY received from %s", src.c_str());
return true;
} else if (bsId == m_id) {
LogMessage("CSBK BS_Dwn_Act for %u received from %s", bsId, src.c_str());
return true;
}
LogMessage("Downlink Activate received from %s", src.c_str());
return false;
return true;
}
bool CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len)

View file

@ -45,7 +45,6 @@ public:
void clock();
private:
unsigned int m_id;
unsigned int m_colorCode;
CModem* m_modem;
CDMRNetwork* m_network;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2015,2016,2017 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
@ -29,6 +29,7 @@ m_dstId(data.m_dstId),
m_flco(data.m_flco),
m_dataType(data.m_dataType),
m_seqNo(data.m_seqNo),
m_missing(data.m_missing),
m_n(data.m_n),
m_ber(data.m_ber),
m_rssi(data.m_rssi)
@ -45,6 +46,7 @@ m_dstId(0U),
m_flco(FLCO_GROUP),
m_dataType(0U),
m_seqNo(0U),
m_missing(false),
m_n(0U),
m_ber(0U),
m_rssi(0U)
@ -68,6 +70,7 @@ CDMRData& CDMRData::operator=(const CDMRData& data)
m_flco = data.m_flco;
m_dataType = data.m_dataType;
m_seqNo = data.m_seqNo;
m_missing = data.m_missing;
m_n = data.m_n;
m_ber = data.m_ber;
m_rssi = data.m_rssi;
@ -138,6 +141,16 @@ void CDMRData::setSeqNo(unsigned char seqNo)
m_seqNo = seqNo;
}
bool CDMRData::isMissing() const
{
return m_missing;
}
void CDMRData::setMissing(bool missing)
{
m_missing = missing;
}
unsigned char CDMRData::getN() const
{
return m_n;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor, G4KLX
* Copyright (C) 2015,2016,2017 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
@ -45,11 +45,14 @@ public:
unsigned char getDataType() const;
void setDataType(unsigned char dataType);
bool isMissing() const;
void setMissing(bool missing);
unsigned char getBER() const;
void setBER(unsigned char ber);
unsigned char getRSSI() const;
void setRSSI(unsigned char ber);
void setRSSI(unsigned char rssi);
void setData(const unsigned char* buffer);
unsigned int getData(unsigned char* buffer) const;
@ -62,6 +65,7 @@ private:
FLCO m_flco;
unsigned char m_dataType;
unsigned char m_seqNo;
bool m_missing;
unsigned char m_n;
unsigned char m_ber;
unsigned char m_rssi;

18007
DMRIds.dat

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -103,6 +103,17 @@ std::string CDMRLookup::find(unsigned int id)
return callsign;
}
bool CDMRLookup::exists(unsigned int id)
{
m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
}
bool CDMRLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -36,6 +36,8 @@ public:
std::string find(unsigned int id);
bool exists(unsigned int id);
void stop();
private:

View file

@ -383,7 +383,7 @@ void CDMRNetwork::clock(unsigned int ms)
}
} else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) {
if (m_status == RUNNING) {
LogWarning("DMR, The master is restarting, logging back in");
LogWarning("DMR, Login to the master has failed, retrying login ...");
m_status = WAITING_LOGIN;
m_timeoutTimer.start();
m_retryTimer.start();
@ -391,7 +391,7 @@ void CDMRNetwork::clock(unsigned int ms)
/* Once the modem death spiral has been prevented in Modem.cpp
the Network sometimes times out and reaches here.
We want it to reconnect so... */
LogError("DMR, Login to the master has failed, retrying ...");
LogError("DMR, Login to the master has failed, retrying network ...");
close();
open();
return;
@ -543,6 +543,9 @@ bool CDMRNetwork::writeConfig()
case HWT_DVMEGA:
software = "MMDVM_DVMega";
break;
case HWT_MMDVM_HS:
software = "MMDVM_HS";
break;
default:
software = "MMDVM_Unknown";
break;

View file

@ -29,6 +29,7 @@
#include <cassert>
#include <ctime>
#include <algorithm>
#include <cstdint>
unsigned int CDMRSlot::m_colorCode = 0U;
@ -51,10 +52,10 @@ unsigned char* CDMRSlot::m_idle = NULL;
FLCO CDMRSlot::m_flco1;
unsigned char CDMRSlot::m_id1 = 0U;
bool CDMRSlot::m_voice1 = true;
ACTIVITY_TYPE CDMRSlot::m_activity1 = ACTIVITY_NONE;
FLCO CDMRSlot::m_flco2;
unsigned char CDMRSlot::m_id2 = 0U;
bool CDMRSlot::m_voice2 = true;
ACTIVITY_TYPE CDMRSlot::m_activity2 = ACTIVITY_NONE;
const unsigned char TALKER_ID_NONE = 0x00U;
const unsigned char TALKER_ID_HEADER = 0x01U;
@ -77,6 +78,7 @@ m_rfEmbeddedData(NULL),
m_rfEmbeddedReadN(0U),
m_rfEmbeddedWriteN(1U),
m_rfTalkerId(TALKER_ID_NONE),
m_rfTalkerAlias(NULL),
m_netEmbeddedLC(),
m_netEmbeddedData(NULL),
m_netEmbeddedReadN(0U),
@ -113,6 +115,7 @@ m_aveRSSI(0U),
m_rssiCount(0U),
m_fp(NULL)
{
m_rfTalkerAlias = new unsigned char[32U];
m_lastFrame = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U];
m_rfEmbeddedData = new CDMREmbeddedData[2U];
@ -126,6 +129,7 @@ CDMRSlot::~CDMRSlot()
delete[] m_rfEmbeddedData;
delete[] m_netEmbeddedData;
delete[] m_lastFrame;
delete[] m_rfTalkerAlias;
}
bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
@ -267,7 +271,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
std::string dst = m_lookup->find(dstId);
if (m_netState == RS_NET_IDLE) {
setShortLC(m_slotNo, dstId, flco, true);
setShortLC(m_slotNo, dstId, flco, ACTIVITY_VOICE);
m_display->writeDMR(m_slotNo, src, flco == FLCO_GROUP, dst, "R");
m_display->writeDMRRSSI(m_slotNo, m_rssi);
}
@ -332,6 +336,8 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
else
LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits));
m_display->writeDMRTA(m_slotNo, NULL, " ");
if (m_rfTimeout) {
writeEndRF();
return false;
@ -391,7 +397,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
std::string dst = m_lookup->find(dstId);
if (m_netState == RS_NET_IDLE) {
setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, false);
setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, ACTIVITY_DATA);
m_display->writeDMR(m_slotNo, src, gi, dst, "R");
m_display->writeDMRRSSI(m_slotNo, m_rssi);
}
@ -470,7 +476,14 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
break;
}
return true;
// If data preamble, signal its existence
if (m_netState == RS_NET_IDLE && csbko == CSBKO_PRECCSBK && csbk.getDataContent()) {
setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, ACTIVITY_DATA);
m_display->writeDMR(m_slotNo, src, gi, dst, "R");
m_display->writeDMRRSSI(m_slotNo, m_rssi);
}
return true;
} else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) {
if (m_rfState != RS_RF_DATA || m_rfFrames == 0U)
return false;
@ -599,6 +612,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded GPS Info", m_slotNo);
CUtils::dump(2U, text, data, 9U);
logGPSPosition(data);
}
if (m_network != NULL)
m_network->writePosition(m_rfLC->getSrcId(), data);
@ -609,6 +623,11 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
m_network->writeTalkerAlias(m_rfLC->getSrcId(), 0U, data);
if (!(m_rfTalkerId & TALKER_ID_HEADER)) {
if (m_rfTalkerId == TALKER_ID_NONE)
::memset(m_rfTalkerAlias, '\0', 32U);
::memcpy(m_rfTalkerAlias, data, 6U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "R");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Header", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -623,6 +642,11 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
m_network->writeTalkerAlias(m_rfLC->getSrcId(), 1U, data);
if (!(m_rfTalkerId & TALKER_ID_BLOCK1)) {
if (m_rfTalkerId == TALKER_ID_NONE)
::memset(m_rfTalkerAlias, '\0', 32U);
::memcpy(m_rfTalkerAlias + 6U, data, 7U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "R");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 1", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -637,6 +661,11 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
m_network->writeTalkerAlias(m_rfLC->getSrcId(), 2U, data);
if (!(m_rfTalkerId & TALKER_ID_BLOCK2)) {
if (m_rfTalkerId == TALKER_ID_NONE)
::memset(m_rfTalkerAlias, 0, 32U);
::memcpy(m_rfTalkerAlias + 6U + 7U, data, 7U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "R");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 2", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -651,6 +680,11 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
m_network->writeTalkerAlias(m_rfLC->getSrcId(), 3U, data);
if (!(m_rfTalkerId & TALKER_ID_BLOCK3)) {
if (m_rfTalkerId == TALKER_ID_NONE)
::memset(m_rfTalkerAlias, '\0', 32U);
::memcpy(m_rfTalkerAlias + 6U + 7U + 7U, data, 7U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "R");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 3", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -810,7 +844,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
std::string dst = m_lookup->find(dstId);
if (m_netState == RS_NET_IDLE) {
setShortLC(m_slotNo, dstId, flco, true);
setShortLC(m_slotNo, dstId, flco, ACTIVITY_VOICE);
m_display->writeDMR(m_slotNo, src, flco == FLCO_GROUP, dst, "R");
m_display->writeDMRRSSI(m_slotNo, m_rssi);
m_display->writeDMRBER(m_slotNo, float(errors) / 1.41F);
@ -1025,7 +1059,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_netState = RS_NET_AUDIO;
setShortLC(m_slotNo, dstId, flco, true);
setShortLC(m_slotNo, dstId, flco, ACTIVITY_VOICE);
std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId);
@ -1093,7 +1127,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_netState = RS_NET_AUDIO;
setShortLC(m_slotNo, dstId, m_netLC->getFLCO(), true);
setShortLC(m_slotNo, dstId, m_netLC->getFLCO(), ACTIVITY_VOICE);
std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId);
@ -1163,7 +1197,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
// We've received the voice header and terminator haven't we?
m_netFrames += 2U;
LogMessage("DMR Slot %u, received network end of voice transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", m_slotNo, float(m_netFrames) / 16.667F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits));
m_display->writeDMRTA(m_slotNo, NULL, " ");
writeEndNet();
} else if (dataType == DT_DATA_HEADER) {
if (m_netState == RS_NET_DATA)
@ -1205,7 +1239,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_netState = RS_NET_DATA;
setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, false);
setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, ACTIVITY_DATA);
std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId);
@ -1283,7 +1317,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_netState = RS_NET_AUDIO;
setShortLC(m_slotNo, dstId, m_netLC->getFLCO(), true);
setShortLC(m_slotNo, dstId, m_netLC->getFLCO(), ACTIVITY_VOICE);
std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId);
@ -1370,10 +1404,16 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded GPS Info", m_slotNo);
CUtils::dump(2U, text, data, 9U);
logGPSPosition(data);
}
break;
case FLCO_TALKER_ALIAS_HEADER:
if (!(m_netTalkerId & TALKER_ID_HEADER)) {
if (!m_netTalkerId)
::memset(m_rfTalkerAlias, '\0', 32U);
::memcpy(m_rfTalkerAlias, data + 2U, 7U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "N");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Header", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -1384,6 +1424,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
break;
case FLCO_TALKER_ALIAS_BLOCK1:
if (!(m_netTalkerId & TALKER_ID_BLOCK1)) {
if (!m_netTalkerId)
::memset(m_rfTalkerAlias, '\0', 32U);
::memcpy(m_rfTalkerAlias + 7U, data + 2U, 7U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "N");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 1", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -1394,6 +1439,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
break;
case FLCO_TALKER_ALIAS_BLOCK2:
if (!(m_netTalkerId & TALKER_ID_BLOCK2)) {
if (!m_netTalkerId)
::memset(m_rfTalkerAlias, '\0', 32U);
::memcpy(m_rfTalkerAlias + 7U + 7U, data + 2U, 7U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "N");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 2", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -1404,6 +1454,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
break;
case FLCO_TALKER_ALIAS_BLOCK3:
if (!(m_netTalkerId & TALKER_ID_BLOCK3)) {
if (!m_netTalkerId)
::memset(m_rfTalkerAlias, '\0', 32U);
::memcpy(m_rfTalkerAlias + 7U + 7U + 7U, data+2U, 7U);
m_display->writeDMRTA(m_slotNo, m_rfTalkerAlias, "N");
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, Embedded Talker Alias Block 3", m_slotNo);
CUtils::dump(2U, text, data, 9U);
@ -1523,7 +1578,13 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
LogWarning("DMR Slot %u, unhandled network CSBK type - 0x%02X", m_slotNo, csbko);
break;
}
} else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) {
// If data preamble, signal its existence
if (csbko == CSBKO_PRECCSBK && csbk.getDataContent()) {
setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, ACTIVITY_DATA);
m_display->writeDMR(m_slotNo, src, gi, dst, "N");
}
} else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) {
if (m_netState != RS_NET_DATA || m_netFrames == 0U)
return;
@ -1574,6 +1635,54 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
}
}
void CDMRSlot::logGPSPosition(const unsigned char* data)
{
unsigned int errorI = (data[2U] & 0x0E) >> 1U;
const char* error;
switch (errorI) {
case 0U:
error = "< 2m";
break;
case 1U:
error = "< 20m";
break;
case 2U:
error = "< 200m";
break;
case 3U:
error = "< 2km";
break;
case 4U:
error = "< 20km";
break;
case 5U:
error = "< 200km";
break;
case 6U:
error = "> 200km";
break;
default:
error = "not known";
break;
}
int32_t longitudeI = ((data[2U] & 0x01U) << 31) | (data[3U] << 23) | (data[4U] << 15) | (data[5U] << 7);
longitudeI >>= 7;
int32_t latitudeI = (data[6U] << 24) | (data[7U] << 16) | (data[8U] << 8);
latitudeI >>= 8;
float longitude = 360.0F / 33554432.0F; // 360/2^25 steps
float latitude = 180.0F / 16777216.0F; // 180/2^24 steps
longitude *= float(longitudeI);
latitude *= float(latitudeI);
LogMessage("GPS position [%f,%f] (Position error %s)", latitude, longitude, error);
}
void CDMRSlot::clock()
{
unsigned int ms = m_interval.elapsed();
@ -1737,15 +1846,15 @@ void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData
}
void CDMRSlot::setShortLC(unsigned int slotNo, unsigned int id, FLCO flco, bool voice)
void CDMRSlot::setShortLC(unsigned int slotNo, unsigned int id, FLCO flco, ACTIVITY_TYPE type)
{
assert(m_modem != NULL);
switch (slotNo) {
case 1U:
m_id1 = 0U;
m_flco1 = flco;
m_voice1 = voice;
m_id1 = 0U;
m_flco1 = flco;
m_activity1 = type;
if (id != 0U) {
unsigned char buffer[3U];
buffer[0U] = (id << 16) & 0xFFU;
@ -1755,9 +1864,9 @@ void CDMRSlot::setShortLC(unsigned int slotNo, unsigned int id, FLCO flco, bool
}
break;
case 2U:
m_id2 = 0U;
m_flco2 = flco;
m_voice2 = voice;
m_id2 = 0U;
m_flco2 = flco;
m_activity2 = type;
if (id != 0U) {
unsigned char buffer[3U];
buffer[0U] = (id << 16) & 0xFFU;
@ -1783,32 +1892,42 @@ void CDMRSlot::setShortLC(unsigned int slotNo, unsigned int id, FLCO flco, bool
if (m_id1 != 0U) {
lc[2U] = m_id1;
if (m_voice1) {
if (m_flco1 == FLCO_GROUP)
lc[1U] |= 0x80U;
else
lc[1U] |= 0x90U;
} else {
if (m_flco1 == FLCO_GROUP)
lc[1U] |= 0xB0U;
else
lc[1U] |= 0xA0U;
}
if (m_activity1 == ACTIVITY_VOICE && m_flco1 == FLCO_GROUP)
lc[1U] |= 0x08U;
else if (m_activity1 == ACTIVITY_VOICE && m_flco1 == FLCO_USER_USER)
lc[1U] |= 0x09U;
else if (m_activity1 == ACTIVITY_DATA && m_flco1 == FLCO_GROUP)
lc[1U] |= 0x0BU;
else if (m_activity1 == ACTIVITY_DATA && m_flco1 == FLCO_USER_USER)
lc[1U] |= 0x0AU;
else if (m_activity1 == ACTIVITY_CSBK && m_flco1 == FLCO_GROUP)
lc[1U] |= 0x02U;
else if (m_activity1 == ACTIVITY_CSBK && m_flco1 == FLCO_USER_USER)
lc[1U] |= 0x03U;
else if (m_activity1 == ACTIVITY_EMERG && m_flco1 == FLCO_GROUP)
lc[1U] |= 0x0CU;
else if (m_activity1 == ACTIVITY_EMERG && m_flco1 == FLCO_USER_USER)
lc[1U] |= 0x0DU;
}
if (m_id2 != 0U) {
lc[3U] = m_id2;
if (m_voice2) {
if (m_flco2 == FLCO_GROUP)
lc[1U] |= 0x08U;
else
lc[1U] |= 0x09U;
} else {
if (m_flco2 == FLCO_GROUP)
lc[1U] |= 0x0BU;
else
lc[1U] |= 0x0AU;
}
if (m_activity2 == ACTIVITY_VOICE && m_flco2 == FLCO_GROUP)
lc[1U] |= 0x80U;
else if (m_activity2 == ACTIVITY_VOICE && m_flco2 == FLCO_USER_USER)
lc[1U] |= 0x90U;
else if (m_activity2 == ACTIVITY_DATA && m_flco2 == FLCO_GROUP)
lc[1U] |= 0xB0U;
else if (m_activity2 == ACTIVITY_DATA && m_flco2 == FLCO_USER_USER)
lc[1U] |= 0xA0U;
else if (m_activity2 == ACTIVITY_CSBK && m_flco2 == FLCO_GROUP)
lc[1U] |= 0x20U;
else if (m_activity2 == ACTIVITY_CSBK && m_flco2 == FLCO_USER_USER)
lc[1U] |= 0x30U;
else if (m_activity2 == ACTIVITY_EMERG && m_flco2 == FLCO_GROUP)
lc[1U] |= 0xC0U;
else if (m_activity2 == ACTIVITY_EMERG && m_flco2 == FLCO_USER_USER)
lc[1U] |= 0xD0U;
}
lc[4U] = CCRC::crc8(lc, 4U);

View file

@ -36,6 +36,14 @@
#include <vector>
enum ACTIVITY_TYPE {
ACTIVITY_NONE,
ACTIVITY_VOICE,
ACTIVITY_DATA,
ACTIVITY_CSBK,
ACTIVITY_EMERG
};
class CDMRSlot {
public:
CDMRSlot(unsigned int slotNo, unsigned int timeout);
@ -61,6 +69,7 @@ private:
unsigned int m_rfEmbeddedReadN;
unsigned int m_rfEmbeddedWriteN;
unsigned char m_rfTalkerId;
unsigned char* m_rfTalkerAlias;
CDMREmbeddedData m_netEmbeddedLC;
CDMREmbeddedData* m_netEmbeddedData;
unsigned int m_netEmbeddedReadN;
@ -116,12 +125,14 @@ private:
static unsigned char* m_idle;
static FLCO m_flco1;
static FLCO m_flco1;
static unsigned char m_id1;
static bool m_voice1;
static ACTIVITY_TYPE m_activity1;
static FLCO m_flco2;
static unsigned char m_id2;
static bool m_voice2;
static ACTIVITY_TYPE m_activity2;
void logGPSPosition(const unsigned char* data);
void writeQueueRF(const unsigned char* data);
void writeQueueNet(const unsigned char* data);
@ -138,7 +149,7 @@ private:
bool insertSilence(const unsigned char* data, unsigned char seqNo);
void insertSilence(unsigned int count);
static void setShortLC(unsigned int slotNo, unsigned int id, FLCO flco = FLCO_GROUP, bool voice = true);
static void setShortLC(unsigned int slotNo, unsigned int id, FLCO flco = FLCO_GROUP, ACTIVITY_TYPE type = ACTIVITY_NONE);
};
#endif

View file

@ -36,11 +36,13 @@ bool CallsignCompare(const std::string& arg, const unsigned char* my)
// #define DUMP_DSTAR
CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool errorReply, const std::vector<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) :
CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool ackReply, unsigned int ackTime, bool errorReply, const std::vector<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper) :
m_callsign(NULL),
m_gateway(NULL),
m_selfOnly(selfOnly),
m_ackReply(ackReply),
m_errorReply(errorReply),
m_remoteGateway(remoteGateway),
m_blackList(blackList),
m_network(network),
m_display(display),
@ -58,8 +60,8 @@ m_networkWatchdog(1000U, 0U, 1500U),
m_rfTimeoutTimer(1000U, timeout),
m_netTimeoutTimer(1000U, timeout),
m_packetTimer(1000U, 0U, 300U),
m_ackTimer(1000U, 0U, 750U),
m_errTimer(1000U, 0U, 750U),
m_ackTimer(1000U, 0U, ackTime),
m_errTimer(1000U, 0U, ackTime),
m_interval(),
m_elapsed(),
m_rfFrames(0U),
@ -523,6 +525,7 @@ void CDStarControl::writeEndRF()
if (m_netState == RS_NET_IDLE) {
m_display->clearDStar();
m_ackTimer.start();
if (m_network != NULL)
@ -587,7 +590,6 @@ void CDStarControl::writeNetwork()
m_netTimeoutTimer.start();
m_packetTimer.start();
//m_elapsed.start(); // commented out and placed lower down due to delay introduced somewhere below here.
m_ackTimer.stop();
m_errTimer.stop();
@ -601,6 +603,13 @@ void CDStarControl::writeNetwork()
m_netBits = 1U;
m_netErrs = 0U;
if (m_remoteGateway) {
header.setRepeater(true);
header.setRPTCall1(m_callsign);
header.setRPTCall2(m_callsign);
header.get(data + 1U);
}
writeQueueHeaderNet(data);
#if defined(DUMP_DSTAR)
@ -1011,6 +1020,9 @@ void CDStarControl::sendAck()
{
m_rfTimeoutTimer.stop();
if (!m_ackReply)
return;
unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH];
m_rfHeader.getMyCall1(user);

View file

@ -37,7 +37,7 @@
class CDStarControl {
public:
CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool errorReply, const std::vector<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper);
CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool ackReply, unsigned int ackTime, bool errorReply, const std::vector<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper);
~CDStarControl();
bool writeModem(unsigned char* data, unsigned int len);
@ -50,7 +50,9 @@ private:
unsigned char* m_callsign;
unsigned char* m_gateway;
bool m_selfOnly;
bool m_ackReply;
bool m_errorReply;
bool m_remoteGateway;
std::vector<std::string> m_blackList;
CDStarNetwork* m_network;
CDisplay* m_display;

View file

@ -36,6 +36,7 @@ const unsigned char TAG_EOT = 0x03U;
enum HW_TYPE {
HWT_MMDVM,
HWT_DVMEGA,
HWT_MMDVM_HS,
HWT_UNKNOWN
};

View file

@ -18,14 +18,15 @@
#include "Display.h"
#include "Defines.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CDisplay::CDisplay() :
m_timer1(1000U, 3U),
m_timer2(1000U, 3U),
m_timer1(3000U, 3U),
m_timer2(3000U, 3U),
m_mode1(MODE_IDLE),
m_mode2(MODE_IDLE)
{
@ -117,7 +118,6 @@ void CDisplay::writeDMR(unsigned int slotNo, const std::string& src, bool group,
m_timer2.start();
m_mode2 = MODE_IDLE;
}
writeDMRInt(slotNo, src, group, dst, type);
}
@ -127,11 +127,55 @@ void CDisplay::writeDMRRSSI(unsigned int slotNo, unsigned char rssi)
writeDMRRSSIInt(slotNo, rssi);
}
void CDisplay::writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type)
{
char TA[32U];
unsigned char *b;
unsigned char c;
int j;
unsigned int i,t1,t2, TAsize, TAformat;
if (strcmp(type," ")==0) { writeDMRTAInt(slotNo, (unsigned char*)TA, type); return; }
TAformat=(talkerAlias[0]>>6U) & 0x03U;
TAsize = (talkerAlias[0]>>1U) & 0x1FU;
::strcpy(TA,"(could not decode)");
switch (TAformat) {
case 0U: // 7 bit
::memset (&TA,0,32U);
b=&talkerAlias[0];
t1=0; t2=0; c=0;
for (i=0;(i<32U)&&(t2<TAsize);i++) {
for (j=7U;j>=0;j--) {
c = (c<<1U) | (b[i] >> j);
if (++t1==7U) { if (i>0) {TA[t2++]=c & 0x7FU; } t1=0; c=0; }
}
}
break;
case 1U: // ISO 8 bit
case 2U: // UTF8
::strcpy(TA,(char*)talkerAlias+1U);
break;
case 3U: // UTF16 poor man's conversion
t2=0;
::memset (&TA,0,32U);
for(i=0;(i<15)&&(t2<TAsize);i++) {
if (talkerAlias[2U*i+1U]==0)
TA[t2++]=talkerAlias[2U*i+2U]; else TA[t2++]='?';
}
TA[TAsize]=0;
break;
}
LogMessage("DMR Talker Alias (Data Format %u, Received %u/%u char): '%s'", TAformat, ::strlen(TA), TAsize, TA);
if (::strlen(TA)>TAsize) { if (strlen(TA)<29U) strcat(TA," ?"); else strcpy(TA+28U," ?"); }
if (strlen((char*)TA)>=4U) writeDMRTAInt(slotNo, (unsigned char*)TA, type);
}
void CDisplay::writeDMRBER(unsigned int slotNo, float ber)
{
writeDMRBERInt(slotNo, ber);
}
void CDisplay::clearDMR(unsigned int slotNo)
{
if (slotNo == 1U) {
@ -293,6 +337,10 @@ void CDisplay::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
{
}
void CDisplay::writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type)
{
}
void CDisplay::writeDMRBERInt(unsigned int slotNo, float ber)
{
}

View file

@ -43,6 +43,7 @@ public:
void writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
void writeDMRRSSI(unsigned int slotNo, unsigned char rssi);
void writeDMRBER(unsigned int slotNo, float ber);
void writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
void clearDMR(unsigned int slotNo);
void writeFusion(const char* source, const char* dest, const char* type, const char* origin);
@ -74,6 +75,7 @@ protected:
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) = 0;
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
virtual void writeDMRBERInt(unsigned int slotNo, float ber);
virtual void clearDMRInt(unsigned int slotNo) = 0;

187
JitterBuffer.cpp Normal file
View file

@ -0,0 +1,187 @@
/*
* Copyright (C) 2017 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "JitterBuffer.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CJitterBuffer::CJitterBuffer(unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber, bool debug) :
m_blockSize(blockSize),
m_blockTime(blockTime),
m_topSequenceNumber(topSequenceNumber),
m_debug(debug),
m_blockCount(0U),
m_timer(1000U, 0U, jitterTime),
m_stopWatch(),
m_running(false),
m_buffer(NULL),
m_headSequenceNumber(0U),
m_lastData(NULL),
m_lastDataLength(0U)
{
assert(blockSize > 0U);
assert(blockTime > 0U);
assert(jitterTime > 0U);
assert(topSequenceNumber > 0U);
m_blockCount = (jitterTime / blockTime) * 2U + 1U;
m_buffer = new JitterEntry[m_blockCount];
for (unsigned int i = 0U; i < m_blockCount; i++)
m_buffer[i].m_data = new unsigned char[m_blockSize];
m_lastData = new unsigned char[m_blockSize];
reset();
}
CJitterBuffer::~CJitterBuffer()
{
for (unsigned int i = 0U; i < m_blockCount; i++)
delete[] m_buffer[i].m_data;
delete[] m_buffer;
delete[] m_lastData;
}
bool CJitterBuffer::addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber)
{
assert(data != NULL);
assert(length > 0U);
assert(length <= m_blockSize);
unsigned int headSequenceNumber = m_headSequenceNumber % m_topSequenceNumber;
unsigned int tailSequenceNumber = (m_headSequenceNumber + m_blockCount) % m_topSequenceNumber;
// Is the data out of sequence?
if (headSequenceNumber < tailSequenceNumber) {
if (sequenceNumber < headSequenceNumber || sequenceNumber >= tailSequenceNumber) {
if (m_debug)
LogDebug("JitterBuffer: rejecting frame with seqNo=%u, raw=%u, head=%u, tail=%u", sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
} else {
if (sequenceNumber >= tailSequenceNumber && sequenceNumber < headSequenceNumber) {
if (m_debug)
LogDebug("JitterBuffer: rejecting frame with seqNo=%u, raw=%u, head=%u, tail=%u", sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
}
unsigned int number;
if (sequenceNumber >= headSequenceNumber)
number = sequenceNumber - headSequenceNumber;
else
number = (sequenceNumber + m_blockCount) - headSequenceNumber;;
unsigned int index = (m_headSequenceNumber + number) % m_blockCount;
// Do we already have the data?
if (m_buffer[index].m_length > 0U) {
if (m_debug)
LogDebug("JitterBuffer: rejecting duplicate frame with seqNo=%u, raw=%u, head=%u, tail=%u", sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
return false;
}
LogDebug("JitterBuffer: adding frame with seqNo=%u, raw=%u, head=%u, tail=%u", sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber);
::memcpy(m_buffer[index].m_data, data, length);
m_buffer[index].m_length = length;
if (!m_timer.isRunning()) {
LogDebug("JitterBuffer: starting the timer");
m_timer.start();
}
return true;
}
JB_STATUS CJitterBuffer::getData(unsigned char* data, unsigned int& length)
{
assert(data != NULL);
if (!m_running)
return JBS_NO_DATA;
unsigned int sequenceNumber = m_stopWatch.elapsed() / m_blockTime + 3U;
if (m_headSequenceNumber > sequenceNumber)
return JBS_NO_DATA;
unsigned int head = m_headSequenceNumber % m_blockCount;
m_headSequenceNumber++;
if (m_buffer[head].m_length > 0U) {
LogDebug("JitterBuffer: returning data, elapsed=%ums, raw=%u, head=%u", m_stopWatch.elapsed(), m_headSequenceNumber - 1U, head);
::memcpy(data, m_buffer[head].m_data, m_buffer[head].m_length);
length = m_buffer[head].m_length;
// Save this data in case no more data is available next time
::memcpy(m_lastData, m_buffer[head].m_data, m_buffer[head].m_length);
m_lastDataLength = m_buffer[head].m_length;
m_buffer[head].m_length = 0U;
return JBS_DATA;
}
if (m_debug)
LogDebug("JitterBuffer: no data available, elapsed=%ums, raw=%u, head=%u", m_stopWatch.elapsed(), m_headSequenceNumber - 1U, head);
// Return the last data frame if we have it
if (m_lastDataLength > 0U) {
LogDebug("JitterBuffer: returning the last received frame");
::memcpy(data, m_lastData, m_lastDataLength);
length = m_lastDataLength;
return JBS_MISSING;
}
return JBS_NO_DATA;
}
void CJitterBuffer::reset()
{
for (unsigned int i = 0U; i < m_blockCount; i++)
m_buffer[i].m_length = 0U;
m_headSequenceNumber = 0U;
m_lastDataLength = 0U;
m_timer.stop();
m_running = false;
}
void CJitterBuffer::clock(unsigned int ms)
{
m_timer.clock(ms);
if (m_timer.isRunning() && m_timer.hasExpired()) {
if (!m_running) {
m_stopWatch.start();
m_running = true;
}
}
}

67
JitterBuffer.h Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (C) 2017 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(JITTERBUFFER_H)
#define JITTERBUFFER_H
#include "StopWatch.h"
#include "Timer.h"
enum JB_STATUS {
JBS_NO_DATA,
JBS_DATA,
JBS_MISSING
};
class CJitterBuffer {
public:
CJitterBuffer(unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber, bool debug);
~CJitterBuffer();
bool addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber);
JB_STATUS getData(unsigned char* data, unsigned int& length);
void reset();
void clock(unsigned int ms);
private:
unsigned int m_blockSize;
unsigned int m_blockTime;
unsigned int m_topSequenceNumber;
bool m_debug;
unsigned int m_blockCount;
CTimer m_timer;
CStopWatch m_stopWatch;
bool m_running;
struct JitterEntry
{
unsigned char* m_data;
unsigned int m_length;
};
JitterEntry* m_buffer;
unsigned int m_headSequenceNumber;
unsigned char* m_lastData;
unsigned int m_lastDataLength;
};
#endif

View file

@ -1,5 +1,6 @@
[General]
Callsign=G9BF
Id=123456
Timeout=180
Duplex=1
# ModeHang=10
@ -42,9 +43,13 @@ TXInvert=1
RXInvert=0
PTTInvert=0
TXDelay=100
RXOffset=0
TXOffset=0
DMRDelay=0
RXLevel=50
TXLevel=50
RXDCOffset=0
TXDCOffset=0
# CWIdTXLevel=50
# D-StarTXLevel=50
# DMRTXLevel=50
@ -63,12 +68,15 @@ Port=/dev/ttyACM1
Enable=1
Module=C
SelfOnly=0
AckReply=1
AckTime=750
ErrorReply=1
RemoteGateway=0
# ModeHang=10
[DMR]
Enable=1
Beacons=1
Id=123456
ColorCode=1
SelfOnly=0
EmbeddedLCOnly=0
@ -78,22 +86,30 @@ DumpTAData=1
# Slot2TGWhiteList=
CallHang=3
TXHang=4
# ModeHang=10
[System Fusion]
Enable=1
LowDeviation=0
SelfOnly=0
#DSQ=1
RemoteGateway=0
# ModeHang=10
[P25]
Enable=1
NAC=293
SelfOnly=0
OverrideUIDCheck=0
RemoteGateway=0
# ModeHang=10
[D-Star Network]
Enable=1
GatewayAddress=127.0.0.1
GatewayPort=20010
LocalPort=20011
# ModeHang=3
Debug=0
[DMR Network]
@ -101,19 +117,21 @@ Enable=1
Address=44.131.4.1
Port=62031
Jitter=300
# Local=3350
# Local=62032
Password=PASSWORD
# Options=
Slot1=1
Slot2=1
# ModeHang=3
Debug=0
[System Fusion Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=3200
GwyAddress=127.0.0.1
GwyPort=4200
GatewayAddress=127.0.0.1
GatewayPort=4200
# ModeHang=3
Debug=0
[P25 Network]
@ -121,6 +139,7 @@ Enable=1
GatewayAddress=127.0.0.1
GatewayPort=42020
LocalPort=32010
# ModeHang=3
Debug=0
[TFT Serial]
@ -154,12 +173,15 @@ Port=/dev/ttyAMA0
Brightness=50
DisplayClock=1
UTC=0
#Screen Layout: 0=G4KLX 2=ON7LDS
ScreenLayout=2
IdleBrightness=20
[OLED]
Type=3
Brightness=0
Invert=0
Scroll=1
[LCDproc]
Address=localhost

View file

@ -95,6 +95,7 @@ int main(int argc, char** argv)
}
#if !defined(_WIN32) && !defined(_WIN64)
::signal(SIGINT, sigHandler);
::signal(SIGTERM, sigHandler);
::signal(SIGHUP, sigHandler);
#endif
@ -109,11 +110,14 @@ int main(int argc, char** argv)
delete host;
if (m_signal == 2)
::LogInfo("MMDVMHost-%s exited on receipt of SIGINT", VERSION);
if (m_signal == 15)
::LogInfo("Caught SIGTERM, exiting");
::LogInfo("MMDVMHost-%s exited on receipt of SIGTERM", VERSION);
if (m_signal == 1)
::LogInfo("Caught SIGHUP, restarting");
::LogInfo("MMDVMHost-%s is restarting on receipt of SIGHUP", VERSION);
} while (m_signal == 1);
::LogFinalise();
@ -131,8 +135,14 @@ m_p25Network(NULL),
m_display(NULL),
m_ump(NULL),
m_mode(MODE_IDLE),
m_rfModeHang(10U),
m_netModeHang(3U),
m_dstarRFModeHang(10U),
m_dmrRFModeHang(10U),
m_ysfRFModeHang(10U),
m_p25RFModeHang(10U),
m_dstarNetModeHang(3U),
m_dmrNetModeHang(3U),
m_ysfNetModeHang(3U),
m_p25NetModeHang(3U),
m_modeTimer(1000U),
m_dmrTXTimer(1000U),
m_cwIdTimer(1000U),
@ -145,6 +155,7 @@ m_p25Enabled(false),
m_cwIdTime(0U),
m_lookup(NULL),
m_callsign(),
m_id(0U),
m_cwCallsign()
{
}
@ -331,20 +342,28 @@ int CMMDVMHost::run()
CDStarControl* dstar = NULL;
if (m_dstarEnabled) {
std::string module = m_conf.getDStarModule();
bool selfOnly = m_conf.getDStarSelfOnly();
std::string module = m_conf.getDStarModule();
bool selfOnly = m_conf.getDStarSelfOnly();
std::vector<std::string> blackList = m_conf.getDStarBlackList();
bool errorReply = m_conf.getDStarErrorReply();
bool ackReply = m_conf.getDStarAckReply();
unsigned int ackTime = m_conf.getDStarAckTime();
bool errorReply = m_conf.getDStarErrorReply();
bool remoteGateway = m_conf.getDStarRemoteGateway();
m_dstarRFModeHang = m_conf.getDStarModeHang();
LogInfo("D-Star Parameters");
LogInfo("D-Star RF Parameters");
LogInfo(" Module: %s", module.c_str());
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" Ack Reply: %s", ackReply ? "yes" : "no");
LogInfo(" Ack Time: %ums", ackTime);
LogInfo(" Error Reply: %s", errorReply ? "yes" : "no");
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
LogInfo(" Mode Hang: %us", m_dstarRFModeHang);
if (blackList.size() > 0U)
LogInfo(" Black List: %u", blackList.size());
dstar = new CDStarControl(m_callsign, module, selfOnly, errorReply, blackList, m_dstarNetwork, m_display, m_timeout, m_duplex, rssi);
dstar = new CDStarControl(m_callsign, module, selfOnly, ackReply, ackTime, errorReply, blackList, m_dstarNetwork, m_display, m_timeout, m_duplex, remoteGateway, rssi);
}
CDMRControl* dmr = NULL;
@ -362,16 +381,20 @@ int CMMDVMHost::run()
unsigned int callHang = m_conf.getDMRCallHang();
unsigned int txHang = m_conf.getDMRTXHang();
unsigned int jitter = m_conf.getDMRNetworkJitter();
m_dmrRFModeHang = m_conf.getDMRModeHang();
if (txHang > m_rfModeHang)
txHang = m_rfModeHang;
if (txHang > m_netModeHang)
txHang = m_netModeHang;
if (txHang > m_dmrRFModeHang)
txHang = m_dmrRFModeHang;
if (m_conf.getDMRNetworkEnabled()) {
if (txHang > m_dmrNetModeHang)
txHang = m_dmrNetModeHang;
}
if (callHang > txHang)
callHang = txHang;
LogInfo("DMR Parameters");
LogInfo("DMR RF Parameters");
LogInfo(" Id: %u", id);
LogInfo(" Color Code: %u", colorCode);
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
@ -390,6 +413,7 @@ int CMMDVMHost::run()
LogInfo(" Call Hang: %us", callHang);
LogInfo(" TX Hang: %us", txHang);
LogInfo(" Mode Hang: %us", m_dmrRFModeHang);
dmr = new CDMRControl(id, colorCode, callHang, selfOnly, embeddedLCOnly, dumpTAData, prefixes, blackList, whiteList, slot1TGWhiteList, slot2TGWhiteList, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, m_lookup, rssi, jitter);
@ -400,24 +424,42 @@ int CMMDVMHost::run()
if (m_ysfEnabled) {
bool lowDeviation = m_conf.getFusionLowDeviation();
bool remoteGateway = m_conf.getFusionRemoteGateway();
bool selfOnly = m_conf.getFusionSelfOnly();
bool sqlEnabled = m_conf.getFusionSQLEnabled();
unsigned char sql = m_conf.getFusionSQL();
m_ysfRFModeHang = m_conf.getFusionModeHang();
LogInfo("YSF Parameters");
LogInfo("YSF RF Parameters");
LogInfo(" Low Deviation: %s", lowDeviation ? "yes" : "no");
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" DSQ: %s", sqlEnabled ? "yes" : "no");
if (sqlEnabled)
LogInfo(" DSQ Value: %u", sql);
LogInfo(" Mode Hang: %us", m_ysfRFModeHang);
ysf = new CYSFControl(m_callsign, m_ysfNetwork, m_display, m_timeout, m_duplex, lowDeviation, remoteGateway, rssi);
ysf = new CYSFControl(m_callsign, selfOnly, m_ysfNetwork, m_display, m_timeout, m_duplex, lowDeviation, remoteGateway, rssi);
ysf->setSQL(sqlEnabled, sql);
}
CP25Control* p25 = NULL;
if (m_p25Enabled) {
unsigned int nac = m_conf.getP25NAC();
bool uidOverride = m_conf.getP25OverrideUID();
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();
LogInfo("P25 Parameters");
LogInfo("P25 RF Parameters");
LogInfo(" Id: %u", id);
LogInfo(" NAC: $%03X", nac);
LogInfo(" UID Override: %s", uidOverride ? "yes" : "no");
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no");
LogInfo(" Mode Hang: %us", m_p25RFModeHang);
p25 = new CP25Control(nac, uidOverride, m_p25Network, m_display, m_timeout, m_duplex, m_lookup, rssi);
p25 = new CP25Control(nac, id, selfOnly, uidOverride, m_p25Network, m_display, m_timeout, m_duplex, m_lookup, remoteGateway, rssi);
}
setMode(MODE_IDLE);
@ -456,7 +498,7 @@ int CMMDVMHost::run()
if (m_mode == MODE_IDLE) {
bool ret = dstar->writeModem(data, len);
if (ret) {
m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.setTimeout(m_dstarRFModeHang);
setMode(MODE_DSTAR);
}
} else if (m_mode == MODE_DSTAR) {
@ -473,12 +515,12 @@ int CMMDVMHost::run()
if (m_duplex) {
bool ret = dmr->processWakeup(data);
if (ret) {
m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.setTimeout(m_dmrRFModeHang);
setMode(MODE_DMR);
dmrBeaconTimer.stop();
}
} else {
m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.setTimeout(m_dmrRFModeHang);
setMode(MODE_DMR);
dmr->writeModemSlot1(data, len);
dmrBeaconTimer.stop();
@ -510,12 +552,12 @@ int CMMDVMHost::run()
if (m_duplex) {
bool ret = dmr->processWakeup(data);
if (ret) {
m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.setTimeout(m_dmrRFModeHang);
setMode(MODE_DMR);
dmrBeaconTimer.stop();
}
} else {
m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.setTimeout(m_dmrRFModeHang);
setMode(MODE_DMR);
dmr->writeModemSlot2(data, len);
dmrBeaconTimer.stop();
@ -546,7 +588,7 @@ int CMMDVMHost::run()
if (m_mode == MODE_IDLE) {
bool ret = ysf->writeModem(data, len);
if (ret) {
m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.setTimeout(m_ysfRFModeHang);
setMode(MODE_YSF);
}
} else if (m_mode == MODE_YSF) {
@ -562,7 +604,7 @@ int CMMDVMHost::run()
if (m_mode == MODE_IDLE) {
bool ret = p25->writeModem(data, len);
if (ret) {
m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.setTimeout(m_p25RFModeHang);
setMode(MODE_P25);
}
} else if (m_mode == MODE_P25) {
@ -582,7 +624,7 @@ int CMMDVMHost::run()
len = dstar->readModem(data);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang);
m_modeTimer.setTimeout(m_dstarNetModeHang);
setMode(MODE_DSTAR);
}
if (m_mode == MODE_DSTAR) {
@ -601,7 +643,7 @@ int CMMDVMHost::run()
len = dmr->readModemSlot1(data);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang);
m_modeTimer.setTimeout(m_dmrNetModeHang);
setMode(MODE_DMR);
}
if (m_mode == MODE_DMR) {
@ -623,7 +665,7 @@ int CMMDVMHost::run()
len = dmr->readModemSlot2(data);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang);
m_modeTimer.setTimeout(m_dmrNetModeHang);
setMode(MODE_DMR);
}
if (m_mode == MODE_DMR) {
@ -647,7 +689,7 @@ int CMMDVMHost::run()
len = ysf->readModem(data);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang);
m_modeTimer.setTimeout(m_ysfNetModeHang);
setMode(MODE_YSF);
}
if (m_mode == MODE_YSF) {
@ -666,14 +708,13 @@ int CMMDVMHost::run()
len = p25->readModem(data);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang);
m_modeTimer.setTimeout(m_p25NetModeHang);
setMode(MODE_P25);
}
if (m_mode == MODE_P25) {
m_modem->writeP25Data(data, len);
m_modeTimer.start();
}
else if (m_mode != MODE_LOCKOUT) {
} else if (m_mode != MODE_LOCKOUT) {
LogWarning("P25 data received when in mode %u", m_mode);
}
}
@ -745,8 +786,6 @@ int CMMDVMHost::run()
CThread::sleep(5U);
}
LogMessage("MMDVMHost-%s is exiting on receipt of SIGHUP1", VERSION);
setMode(MODE_IDLE);
m_modem->close();
@ -799,18 +838,22 @@ bool CMMDVMHost::createModem()
bool pttInvert = m_conf.getModemPTTInvert();
unsigned int txDelay = m_conf.getModemTXDelay();
unsigned int dmrDelay = m_conf.getModemDMRDelay();
unsigned int rxLevel = m_conf.getModemRXLevel();
unsigned int cwIdTXLevel = m_conf.getModemCWIdTXLevel();
unsigned int dstarTXLevel = m_conf.getModemDStarTXLevel();
unsigned int dmrTXLevel = m_conf.getModemDMRTXLevel();
unsigned int ysfTXLevel = m_conf.getModemYSFTXLevel();
unsigned int p25TXLevel = m_conf.getModemP25TXLevel();
float rxLevel = m_conf.getModemRXLevel();
float cwIdTXLevel = m_conf.getModemCWIdTXLevel();
float dstarTXLevel = m_conf.getModemDStarTXLevel();
float dmrTXLevel = m_conf.getModemDMRTXLevel();
float ysfTXLevel = m_conf.getModemYSFTXLevel();
float p25TXLevel = m_conf.getModemP25TXLevel();
bool trace = m_conf.getModemTrace();
bool debug = m_conf.getModemDebug();
unsigned int colorCode = m_conf.getDMRColorCode();
bool lowDeviation = m_conf.getFusionLowDeviation();
unsigned int rxFrequency = m_conf.getRxFrequency();
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRXFrequency();
unsigned int txFrequency = m_conf.getTXFrequency();
int rxOffset = m_conf.getModemRXOffset();
int txOffset = m_conf.getModemTXOffset();
int rxDCOffset = m_conf.getModemRXDCOffset();
int txDCOffset = m_conf.getModemTXDCOffset();
LogInfo("Modem Parameters");
LogInfo(" Port: %s", port.c_str());
@ -818,20 +861,24 @@ bool CMMDVMHost::createModem()
LogInfo(" TX Invert: %s", txInvert ? "yes" : "no");
LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no");
LogInfo(" TX Delay: %ums", txDelay);
LogInfo(" RX Offset: %dHz", rxOffset);
LogInfo(" TX Offset: %dHz", txOffset);
LogInfo(" RX DC Offset: %d", rxDCOffset);
LogInfo(" TX DC Offset: %d", txDCOffset);
LogInfo(" DMR Delay: %u (%.1fms)", dmrDelay, float(dmrDelay) * 0.0416666F);
LogInfo(" RX Level: %u%%", rxLevel);
LogInfo(" CW Id TX Level: %u%%", cwIdTXLevel);
LogInfo(" D-Star TX Level: %u%%", dstarTXLevel);
LogInfo(" DMR TX Level: %u%%", dmrTXLevel);
LogInfo(" YSF TX Level: %u%%", ysfTXLevel);
LogInfo(" P25 TX Level: %u%%", p25TXLevel);
LogInfo(" RX Frequency: %uHz", rxFrequency);
LogInfo(" TX Frequency: %uHz", txFrequency);
LogInfo(" RX Level: %.1f%%", rxLevel);
LogInfo(" CW Id TX Level: %.1f%%", cwIdTXLevel);
LogInfo(" D-Star TX Level: %.1f%%", dstarTXLevel);
LogInfo(" DMR TX Level: %.1f%%", dmrTXLevel);
LogInfo(" YSF TX Level: %.1f%%", ysfTXLevel);
LogInfo(" P25 TX Level: %.1f%%", p25TXLevel);
LogInfo(" RX Frequency: %uHz (%uHz)", rxFrequency, rxFrequency + rxOffset);
LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset);
m_modem = new CModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel);
m_modem->setRFParams(rxFrequency, txFrequency);
m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset);
m_modem->setDMRParams(colorCode);
m_modem->setYSFParams(lowDeviation);
@ -848,14 +895,16 @@ bool CMMDVMHost::createModem()
bool CMMDVMHost::createDStarNetwork()
{
std::string gatewayAddress = m_conf.getDStarGatewayAddress();
unsigned int gatewayPort = m_conf.getDStarGatewayPort();
unsigned int localPort = m_conf.getDStarLocalPort();
bool debug = m_conf.getDStarNetworkDebug();
unsigned int gatewayPort = m_conf.getDStarGatewayPort();
unsigned int localPort = m_conf.getDStarLocalPort();
bool debug = m_conf.getDStarNetworkDebug();
m_dstarNetModeHang = m_conf.getDStarNetworkModeHang();
LogInfo("D-Star Network Parameters");
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %u", gatewayPort);
LogInfo(" Local Port: %u", localPort);
LogInfo(" Mode Hang: %us", m_dstarNetModeHang);
m_dstarNetwork = new CDStarNetwork(gatewayAddress, gatewayPort, localPort, m_duplex, VERSION, debug);
@ -883,6 +932,7 @@ bool CMMDVMHost::createDMRNetwork()
bool slot1 = m_conf.getDMRNetworkSlot1();
bool slot2 = m_conf.getDMRNetworkSlot2();
HW_TYPE hwType = m_modem->getHWType();
m_dmrNetModeHang = m_conf.getDMRNetworkModeHang();
LogInfo("DMR Network Parameters");
LogInfo(" Address: %s", address.c_str());
@ -894,6 +944,7 @@ bool CMMDVMHost::createDMRNetwork()
LogInfo(" Jitter: %ums", jitter);
LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled");
LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled");
LogInfo(" Mode Hang: %us", m_dmrNetModeHang);
m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, hwType);
@ -903,8 +954,8 @@ bool CMMDVMHost::createDMRNetwork()
m_dmrNetwork->setOptions(options);
}
unsigned int rxFrequency = m_conf.getRxFrequency();
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRXFrequency();
unsigned int txFrequency = m_conf.getTXFrequency();
unsigned int power = m_conf.getPower();
unsigned int colorCode = m_conf.getDMRColorCode();
float latitude = m_conf.getLatitude();
@ -944,17 +995,19 @@ bool CMMDVMHost::createYSFNetwork()
{
std::string myAddress = m_conf.getFusionNetworkMyAddress();
unsigned int myPort = m_conf.getFusionNetworkMyPort();
std::string gwyAddress = m_conf.getFusionNetworkGwyAddress();
unsigned int gwyPort = m_conf.getFusionNetworkGwyPort();
std::string gatewayAddress = m_conf.getFusionNetworkGatewayAddress();
unsigned int gatewayPort = m_conf.getFusionNetworkGatewayPort();
m_ysfNetModeHang = m_conf.getFusionNetworkModeHang();
bool debug = m_conf.getFusionNetworkDebug();
LogInfo("System Fusion Network Parameters");
LogInfo(" Local Address: %s", myAddress.c_str());
LogInfo(" Local Port: %u", myPort);
LogInfo(" Gateway Address: %s", gwyAddress.c_str());
LogInfo(" Gateway Port: %u", gwyPort);
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %u", gatewayPort);
LogInfo(" Mode Hang: %us", m_ysfNetModeHang);
m_ysfNetwork = new CYSFNetwork(myAddress, myPort, gwyAddress, gwyPort, m_callsign, debug);
m_ysfNetwork = new CYSFNetwork(myAddress, myPort, gatewayAddress, gatewayPort, m_callsign, debug);
bool ret = m_ysfNetwork->open();
if (!ret) {
@ -973,12 +1026,14 @@ bool CMMDVMHost::createP25Network()
std::string gatewayAddress = m_conf.getP25GatewayAddress();
unsigned int gatewayPort = m_conf.getP25GatewayPort();
unsigned int localPort = m_conf.getP25LocalPort();
m_p25NetModeHang = m_conf.getP25NetworkModeHang();
bool debug = m_conf.getP25NetworkDebug();
LogInfo("P25 Network Parameters");
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %u", gatewayPort);
LogInfo(" Local Port: %u", localPort);
LogInfo(" Mode Hang: %us", m_p25NetModeHang);
m_p25Network = new CP25Network(gatewayAddress, gatewayPort, localPort, debug);
@ -1002,17 +1057,14 @@ void CMMDVMHost::readParams()
m_p25Enabled = m_conf.getP25Enabled();
m_duplex = m_conf.getDuplex();
m_callsign = m_conf.getCallsign();
m_id = m_conf.getId();
m_timeout = m_conf.getTimeout();
m_rfModeHang = m_conf.getRFModeHang();
m_netModeHang = m_conf.getNetModeHang();
LogInfo("General Parameters");
LogInfo(" Callsign: %s", m_callsign.c_str());
LogInfo(" Id: %u", m_id);
LogInfo(" Duplex: %s", m_duplex ? "yes" : "no");
LogInfo(" Timeout: %us", m_timeout);
LogInfo(" RF Mode Hang: %us", m_rfModeHang);
LogInfo(" Net Mode Hang: %us", m_netModeHang);
LogInfo(" D-Star: %s", m_dstarEnabled ? "enabled" : "disabled");
LogInfo(" DMR: %s", m_dmrEnabled ? "enabled" : "disabled");
LogInfo(" YSF: %s", m_ysfEnabled ? "enabled" : "disabled");
@ -1047,6 +1099,7 @@ void CMMDVMHost::createDisplay()
bool displayClock = m_conf.getNextionDisplayClock();
bool utc = m_conf.getNextionUTC();
unsigned int idleBrightness = m_conf.getNextionIdleBrightness();
unsigned int screenLayout = m_conf.getNextionScreenLayout();
LogInfo(" Port: %s", port.c_str());
LogInfo(" Brightness: %u", brightness);
@ -1055,15 +1108,27 @@ void CMMDVMHost::createDisplay()
LogInfo(" Display UTC: %s", utc ? "yes" : "no");
LogInfo(" Idle Brightness: %u", idleBrightness);
switch (screenLayout) {
case 0U:
LogInfo(" Screen Layout: G4KLX (Default)");
break;
case 2U:
LogInfo(" Screen Layout: ON7LDS");
break;
default:
LogInfo(" Screen Layout: %u (Unknown)", screenLayout);
break;
}
if (port == "modem") {
ISerialPort* serial = new CModemSerialPort(m_modem);
m_display = new CNextion(m_callsign, dmrid, serial, brightness, displayClock, utc, idleBrightness);
m_display = new CNextion(m_callsign, dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout);
} else if (port == "ump") {
if (m_ump != NULL)
m_display = new CNextion(m_callsign, dmrid, m_ump, brightness, displayClock, utc, idleBrightness);
m_display = new CNextion(m_callsign, dmrid, m_ump, brightness, displayClock, utc, idleBrightness, screenLayout);
} else {
ISerialPort* serial = new CSerialController(port, SERIAL_9600);
m_display = new CNextion(m_callsign, dmrid, serial, brightness, displayClock, utc, idleBrightness);
m_display = new CNextion(m_callsign, dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout);
}
} else if (type == "LCDproc") {
std::string address = m_conf.getLCDprocAddress();
@ -1131,7 +1196,8 @@ void CMMDVMHost::createDisplay()
unsigned char type = m_conf.getOLEDType();
unsigned char brightness = m_conf.getOLEDBrightness();
bool invert = m_conf.getOLEDInvert();
m_display = new COLED(type, brightness, invert);
bool scroll = m_conf.getOLEDScroll();
m_display = new COLED(type, brightness, invert, scroll);
#endif
} else {
m_display = new CNullDisplay;

View file

@ -50,8 +50,14 @@ private:
CDisplay* m_display;
CUMP* m_ump;
unsigned char m_mode;
unsigned int m_rfModeHang;
unsigned int m_netModeHang;
unsigned int m_dstarRFModeHang;
unsigned int m_dmrRFModeHang;
unsigned int m_ysfRFModeHang;
unsigned int m_p25RFModeHang;
unsigned int m_dstarNetModeHang;
unsigned int m_dmrNetModeHang;
unsigned int m_ysfNetModeHang;
unsigned int m_p25NetModeHang;
CTimer m_modeTimer;
CTimer m_dmrTXTimer;
CTimer m_cwIdTimer;
@ -64,6 +70,7 @@ private:
unsigned int m_cwIdTime;
CDMRLookup* m_lookup;
std::string m_callsign;
unsigned int m_id;
std::string m_cwCallsign;
void readParams();

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -22,32 +22,32 @@
<ProjectGuid>{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>MMDVMHost</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
@ -183,12 +183,14 @@
<ClInclude Include="Golay24128.h" />
<ClInclude Include="Hamming.h" />
<ClInclude Include="DMRLookup.h" />
<ClInclude Include="JitterBuffer.h" />
<ClInclude Include="LCDproc.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="MMDVMHost.h" />
<ClInclude Include="Modem.h" />
<ClInclude Include="ModemSerialPort.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="NetworkInfo.h" />
<ClInclude Include="Nextion.h" />
<ClInclude Include="NullDisplay.h" />
<ClInclude Include="P25Audio.h" />
@ -252,12 +254,14 @@
<ClCompile Include="Golay2087.cpp" />
<ClCompile Include="Golay24128.cpp" />
<ClCompile Include="Hamming.cpp" />
<ClCompile Include="JitterBuffer.cpp" />
<ClCompile Include="LCDproc.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="MMDVMHost.cpp" />
<ClCompile Include="Modem.cpp" />
<ClCompile Include="ModemSerialPort.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="NetworkInfo.cpp" />
<ClCompile Include="Nextion.cpp" />
<ClCompile Include="NullDisplay.cpp" />
<ClCompile Include="P25Audio.cpp" />

View file

@ -221,6 +221,12 @@
<ClInclude Include="RSSIInterpolator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NetworkInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JitterBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
@ -412,5 +418,11 @@
<ClCompile Include="RSSIInterpolator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NetworkInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JitterBuffer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -9,9 +9,9 @@ LDFLAGS = -g
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \
P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o P25Audio.o P25Control.o \
P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o \
Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \
P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o P25Audio.o P25Control.o \
P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o \
Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o \
TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o P25Audio.o \
P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \
P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o P25Audio.o \
P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \
P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Golay24128.o Hamming.o JitterBuffer.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o P25Audio.o \
P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \
P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o P25Audio.o \
P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -9,9 +9,9 @@ LDFLAGS = -g
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \
P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o P25Audio.o P25Control.o \
P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o \
Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -107,6 +107,8 @@ m_dstarEnabled(false),
m_dmrEnabled(false),
m_ysfEnabled(false),
m_p25Enabled(false),
m_rxDCOffset(0),
m_txDCOffset(0),
m_serial(port, SERIAL_115200, true),
m_buffer(NULL),
m_length(0U),
@ -145,10 +147,12 @@ CModem::~CModem()
delete[] m_buffer;
}
void CModem::setRFParams(unsigned int rxFrequency, unsigned int txFrequency)
void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset)
{
m_rxFrequency = rxFrequency;
m_txFrequency = txFrequency;
m_rxFrequency = rxFrequency + rxOffset;
m_txFrequency = txFrequency + txOffset;
m_txDCOffset = txDCOffset;
m_rxDCOffset = rxDCOffset;
}
void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled)
@ -159,7 +163,7 @@ void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled,
m_p25Enabled = p25Enabled;
}
void CModem::setLevels(unsigned int rxLevel, unsigned int cwIdTXLevel, unsigned int dstarTXLevel, unsigned int dmrTXLevel, unsigned int ysfTXLevel, unsigned int p25TXLevel)
void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel)
{
m_rxLevel = rxLevel;
m_cwIdTXLevel = cwIdTXLevel;
@ -902,6 +906,10 @@ bool CModem::readVersion()
if (ret != 3)
return false;
#if defined(__APPLE__)
m_serial.setNonblock(true);
#endif
for (unsigned int count = 0U; count < MAX_RESPONSES; count++) {
CThread::sleep(10U);
RESP_TYPE_MMDVM resp = getResponse();
@ -910,6 +918,8 @@ bool CModem::readVersion()
m_hwType = HWT_MMDVM;
else if (::memcmp(m_buffer + 4U, "DVMEGA", 6U) == 0)
m_hwType = HWT_DVMEGA;
else if (::memcmp(m_buffer + 4U, "ZUMspot", 7U) == 0)
m_hwType = HWT_MMDVM_HS;
LogInfo("MMDVM protocol version: %u, description: %.*s", m_buffer[3U], m_length - 4U, m_buffer + 4U);
return true;
@ -943,7 +953,7 @@ bool CModem::setConfig()
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 16U;
buffer[1U] = 18U;
buffer[2U] = MMDVM_SET_CONFIG;
@ -975,9 +985,9 @@ bool CModem::setConfig()
buffer[6U] = MODE_IDLE;
buffer[7U] = (m_rxLevel * 255U) / 100U;
buffer[7U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F);
buffer[8U] = (m_cwIdTXLevel * 255U) / 100U;
buffer[8U] = (unsigned char)(m_cwIdTXLevel * 2.55F + 0.5F);
buffer[9U] = m_dmrColorCode;
@ -985,15 +995,18 @@ bool CModem::setConfig()
buffer[11U] = 128U; // Was OscOffset
buffer[12U] = (m_dstarTXLevel * 255U) / 100U;
buffer[13U] = (m_dmrTXLevel * 255U) / 100U;
buffer[14U] = (m_ysfTXLevel * 255U) / 100U;
buffer[15U] = (m_p25TXLevel * 255U) / 100U;
buffer[12U] = (unsigned char)(m_dstarTXLevel * 2.55F + 0.5F);
buffer[13U] = (unsigned char)(m_dmrTXLevel * 2.55F + 0.5F);
buffer[14U] = (unsigned char)(m_ysfTXLevel * 2.55F + 0.5F);
buffer[15U] = (unsigned char)(m_p25TXLevel * 2.55F + 0.5F);
// CUtils::dump(1U, "Written", buffer, 16U);
buffer[16U] = (unsigned char)(m_txDCOffset + 128);
buffer[17U] = (unsigned char)(m_rxDCOffset + 128);
int ret = m_serial.write(buffer, 16U);
if (ret != 16)
// CUtils::dump(1U, "Written", buffer, 18U);
int ret = m_serial.write(buffer, 18U);
if (ret != 18)
return false;
unsigned int count = 0U;

18
Modem.h
View file

@ -37,9 +37,9 @@ public:
CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug);
~CModem();
void setRFParams(unsigned int rxFrequency, unsigned int txFrequency);
void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset);
void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled);
void setLevels(unsigned int rxLevel, unsigned int cwIdTXLevel, unsigned int dstarTXLevel, unsigned int dmrTXLevel, unsigned int ysfTXLevel, unsigned int p25Enabled);
void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25Enabled);
void setDMRParams(unsigned int colorCode);
void setYSFParams(bool loDev);
@ -97,12 +97,12 @@ private:
bool m_pttInvert;
unsigned int m_txDelay;
unsigned int m_dmrDelay;
unsigned int m_rxLevel;
unsigned int m_cwIdTXLevel;
unsigned int m_dstarTXLevel;
unsigned int m_dmrTXLevel;
unsigned int m_ysfTXLevel;
unsigned int m_p25TXLevel;
float m_rxLevel;
float m_cwIdTXLevel;
float m_dstarTXLevel;
float m_dmrTXLevel;
float m_ysfTXLevel;
float m_p25TXLevel;
bool m_trace;
bool m_debug;
unsigned int m_rxFrequency;
@ -111,6 +111,8 @@ private:
bool m_dmrEnabled;
bool m_ysfEnabled;
bool m_p25Enabled;
int m_rxDCOffset;
int m_txDCOffset;
CSerialController m_serial;
unsigned char* m_buffer;
unsigned int m_length;

222
NetworkInfo.cpp Normal file
View file

@ -0,0 +1,222 @@
/*
* Copyright (C) 2017 by Lieven De Samblanx ON7LDS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NetworkInfo.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <ctime>
#include <clocale>
#include <sys/types.h>
#if !defined(_WIN32) && !defined(_WIN64)
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#else
#include <ws2tcpip.h>
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")
#ifndef NO_ERROR
#define NO_ERROR 0
#endif
#ifndef ERROR_BUFFER_OVERFLOW
#define ERROR_BUFFER_OVERFLOW 111
#endif
#ifndef ERROR_INSUFFICIENT_BUFFER
#define ERROR_INSUFFICIENT_BUFFER 122
#endif
#endif
CNetworkInfo::CNetworkInfo()
{
}
CNetworkInfo::~CNetworkInfo()
{
}
void CNetworkInfo::getNetworkInterface(unsigned char* info)
{
LogInfo("Interfaces Info");
::strcpy((char*)info, "(address unknown)");
#if !defined(_WIN32) && !defined(_WIN64)
const unsigned int IFLISTSIZ = 25U;
FILE* fp = ::fopen("/proc/net/route" , "r");
if (fp == NULL) {
LogError("Unabled to open /proc/route");
return;
}
char* dflt = NULL;
char line[100U];
while (::fgets(line, 100U, fp)) {
char* p1 = strtok(line , " \t");
char* p2 = strtok(NULL , " \t");
if (p1 != NULL && p2 != NULL) {
if (::strcmp(p2, "00000000") == 0) {
dflt = p1;
break;
}
}
}
::fclose(fp);
if (dflt == NULL) {
LogError("Unable to find the default route");
return;
}
char interfacelist[IFLISTSIZ][50+INET6_ADDRSTRLEN];
for (unsigned int n = 0U; n < IFLISTSIZ; n++)
interfacelist[n][0] = 0;
struct ifaddrs* ifaddr;
if (::getifaddrs(&ifaddr) == -1) {
LogError("getifaddrs failure");
return;
}
unsigned int ifnr = 0U;
for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
int family = ifa->ifa_addr->sa_family;
if (family == AF_INET || family == AF_INET6) {
char host[NI_MAXHOST];
int s = ::getnameinfo(ifa->ifa_addr, family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0) {
LogError("getnameinfo() failed: %s\n", gai_strerror(s));
continue;
}
if (family == AF_INET) {
::sprintf(interfacelist[ifnr], "%s: %s", ifa->ifa_name, host);
LogInfo(" IPv4: %s", interfacelist[ifnr]);
} else {
::sprintf(interfacelist[ifnr], "%s: %s", ifa->ifa_name, host);
LogInfo(" IPv6: %s", interfacelist[ifnr]);
}
ifnr++;
}
}
::freeifaddrs(ifaddr);
LogInfo(" Default interface is : %s" , dflt);
for (unsigned int n = 0U; n < ifnr; n++) {
char* p = ::strchr(interfacelist[n], '%');
if (p != NULL)
*p = 0;
if (::strstr(interfacelist[n], dflt) != 0) {
::strcpy((char*)info, interfacelist[n]);
break;
}
}
LogInfo(" IP to show: %s", info);
#else
PMIB_IPFORWARDTABLE pIpForwardTable = (MIB_IPFORWARDTABLE *)::malloc(sizeof(MIB_IPFORWARDTABLE));
if (pIpForwardTable == NULL) {
LogError("Error allocating memory");
return;
}
DWORD dwSize = 0U;
if (::GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
::free(pIpForwardTable);
pIpForwardTable = (MIB_IPFORWARDTABLE *)::malloc(dwSize);
if (pIpForwardTable == NULL) {
LogError("Error allocating memory");
return;
}
}
DWORD ret = ::GetIpForwardTable(pIpForwardTable, &dwSize, 0);
if (ret != NO_ERROR) {
::free(pIpForwardTable);
LogError("GetIpForwardTable failed.");
return;
}
DWORD found = 999U;
for (DWORD i = 0U; i < pIpForwardTable->dwNumEntries; i++) {
if (pIpForwardTable->table[i].dwForwardDest == 0U) {
found = i;
break;
}
}
if (found == 999U) {
::free(pIpForwardTable);
LogError("Unable to find the default destination in the routing table.");
return;
}
DWORD ifnr = pIpForwardTable->table[found].dwForwardIfIndex;
::free(pIpForwardTable);
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)::malloc(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
LogError("Error allocating memory");
return;
}
ULONG buflen = sizeof(IP_ADAPTER_INFO);
if (::GetAdaptersInfo(pAdapterInfo, &buflen) == ERROR_BUFFER_OVERFLOW) {
::free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)::malloc(buflen);
if (pAdapterInfo == NULL) {
LogError("Error allocating memory");
return;
}
}
if (::GetAdaptersInfo(pAdapterInfo, &buflen) != NO_ERROR) {
::free(pAdapterInfo);
LogError("Call to GetAdaptersInfo failed.");
return;
}
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
while (pAdapter != NULL) {
LogInfo(" IP : %s", pAdapter->IpAddressList.IpAddress.String);
if (pAdapter->Index == ifnr)
::strcpy((char*)info, pAdapter->IpAddressList.IpAddress.String);
pAdapter = pAdapter->Next;
}
::free(pAdapterInfo);
LogInfo(" IP to show: %s", info);
#endif
}

32
NetworkInfo.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2017 by Lieven De Samblanx ON7LDS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NETWORKINFO_H)
#define NETWORKINFO_H
class CNetworkInfo {
public:
CNetworkInfo();
~CNetworkInfo();
void getNetworkInterface(unsigned char* info);
private:
};
#endif

View file

@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NetworkInfo.h"
#include "Nextion.h"
#include "Log.h"
@ -24,6 +25,7 @@
#include <cstring>
#include <ctime>
#include <clocale>
//#include <unistd.h>
const unsigned int DSTAR_RSSI_COUNT = 3U; // 3 * 420ms = 1260ms
const unsigned int DSTAR_BER_COUNT = 63U; // 63 * 20ms = 1260ms
@ -34,9 +36,10 @@ const unsigned int YSF_BER_COUNT = 13U; // 13 * 100ms = 1300ms
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
const unsigned int P25_BER_COUNT = 7U; // 7 * 180ms = 1260ms
CNextion::CNextion(const std::string& callsign, unsigned int dmrid, ISerialPort* serial, unsigned int brightness, bool displayClock, bool utc, unsigned int idleBrightness) :
CNextion::CNextion(const std::string& callsign, unsigned int dmrid, ISerialPort* serial, unsigned int brightness, bool displayClock, bool utc, unsigned int idleBrightness, unsigned int screenLayout) :
CDisplay(),
m_callsign(callsign),
m_ipaddress("(ip unknown)"),
m_dmrid(dmrid),
m_serial(serial),
m_brightness(brightness),
@ -44,6 +47,7 @@ m_mode(MODE_IDLE),
m_displayClock(displayClock),
m_utc(utc),
m_idleBrightness(idleBrightness),
m_screenLayout(screenLayout),
m_clockDisplayTimer(1000U, 0U, 400U),
m_rssiAccum1(0U),
m_rssiAccum2(0U),
@ -64,6 +68,9 @@ CNextion::~CNextion()
bool CNextion::open()
{
unsigned char info[100U];
CNetworkInfo* m_network;
bool ret = m_serial->open();
if (!ret) {
LogError("Cannot open the port for the Nextion display");
@ -71,6 +78,11 @@ bool CNextion::open()
return false;
}
info[0]=0;
m_network = new CNetworkInfo;
m_network->getNetworkInterface(info);
m_ipaddress = (char*)info;
sendCommand("bkcmd=0");
setIdle();
@ -78,19 +90,23 @@ bool CNextion::open()
return true;
}
void CNextion::setIdleInt()
{
sendCommand("page MMDVM");
char command[30];
char command[30U];
::sprintf(command, "dim=%u", m_idleBrightness);
sendCommand(command);
::sprintf(command, "t0.txt=\"%-6s / %u\"", m_callsign.c_str(), m_dmrid);
::sprintf(command, "t0.txt=\"%s/%u\"", m_callsign.c_str(), m_dmrid);
sendCommand(command);
sendCommand("t1.txt=\"MMDVM IDLE\"");
::sprintf(command, "t3.txt=\"%s\"", m_ipaddress.c_str());
sendCommand(command);
m_clockDisplayTimer.start();
m_mode = MODE_IDLE;
@ -226,10 +242,21 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
if (m_mode != MODE_DMR) {
sendCommand("page DMR");
if (slotNo == 1U)
if (slotNo == 1U) {
if (m_screenLayout == 2U) {
sendCommand("t2.pco=0");
sendCommand("t2.font=4");
}
sendCommand("t2.txt=\"2 Listening\"");
else
} else {
if (m_screenLayout == 2U) {
sendCommand("t0.pco=0");
sendCommand("t0.font=4");
}
sendCommand("t0.txt=\"1 Listening\"");
}
}
char text[30U];
@ -238,12 +265,24 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro
if (slotNo == 1U) {
::sprintf(text, "t0.txt=\"1 %s %s\"", type, src.c_str());
if (m_screenLayout == 2U) {
sendCommand("t0.pco=0");
sendCommand("t0.font=4");
}
sendCommand(text);
::sprintf(text, "t1.txt=\"%s%s\"", group ? "TG" : "", dst.c_str());
sendCommand(text);
} else {
::sprintf(text, "t2.txt=\"2 %s %s\"", type, src.c_str());
if (m_screenLayout == 2U) {
sendCommand("t2.pco=0");
sendCommand("t2.font=4");
}
sendCommand(text);
::sprintf(text, "t3.txt=\"%s%s\"", group ? "TG" : "", dst.c_str());
@ -306,6 +345,52 @@ void CNextion::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
}
}
void CNextion::writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type)
{
if (m_screenLayout < 2U)
return;
if (type[0] == ' ') {
if (slotNo == 1U)
sendCommand("t0.pco=33808");
else
sendCommand("t2.pco=33808");
return;
}
if (slotNo == 1U) {
char text[40U];
::sprintf(text, "t0.txt=\"1 %s %s\"", type, talkerAlias);
if (m_screenLayout == 2U) {
if (::strlen((char*)talkerAlias) > (16U-4U))
sendCommand("t0.font=3");
if (::strlen((char*)talkerAlias) > (20U-4U))
sendCommand("t0.font=2");
if (::strlen((char*)talkerAlias) > (24U-4U))
sendCommand("t0.font=1");
}
sendCommand("t0.pco=1024");
sendCommand(text);
} else {
char text[40U];
::sprintf(text, "t2.txt=\"2 %s %s\"", type, talkerAlias);
if (m_screenLayout == 2U) {
if (::strlen((char*)talkerAlias) > (16U-4U))
sendCommand("t2.font=3");
if (::strlen((char*)talkerAlias) > (20U-4U))
sendCommand("t2.font=2");
if (::strlen((char*)talkerAlias) > (24U-4U))
sendCommand("t2.font=1");
}
sendCommand("t2.pco=1024");
sendCommand(text);
}
}
void CNextion::writeDMRBERInt(unsigned int slotNo, float ber)
{
if (slotNo == 1U) {
@ -353,11 +438,23 @@ void CNextion::clearDMRInt(unsigned int slotNo)
{
if (slotNo == 1U) {
sendCommand("t0.txt=\"1 Listening\"");
if (m_screenLayout == 2U) {
sendCommand("t0.pco=0");
sendCommand("t0.font=4");
}
sendCommand("t1.txt=\"\"");
sendCommand("t4.txt=\"\"");
sendCommand("t6.txt=\"\"");
} else {
sendCommand("t2.txt=\"2 Listening\"");
if (m_screenLayout == 2U) {
sendCommand("t2.pco=0");
sendCommand("t2.font=4");
}
sendCommand("t3.txt=\"\"");
sendCommand("t5.txt=\"\"");
sendCommand("t7.txt=\"\"");
@ -568,6 +665,8 @@ void CNextion::clockInt(unsigned int ms)
void CNextion::close()
{
sendCommand("page MMDVM");
sendCommand("t1.txt=\"MMDVM STOPPED\"");
m_serial->close();
delete m_serial;
}

View file

@ -29,7 +29,7 @@
class CNextion : public CDisplay
{
public:
CNextion(const std::string& callsign, unsigned int dmrid, ISerialPort* serial, unsigned int brightness, bool displayClock, bool utc, unsigned int idleBrightness);
CNextion(const std::string& callsign, unsigned int dmrid, ISerialPort* serial, unsigned int brightness, bool displayClock, bool utc, unsigned int idleBrightness, unsigned int screenLayout);
virtual ~CNextion();
virtual bool open();
@ -48,6 +48,7 @@ protected:
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
virtual void writeDMRBERInt(unsigned int slotNo, float ber);
virtual void clearDMRInt(unsigned int slotNo);
@ -68,6 +69,7 @@ protected:
private:
std::string m_callsign;
std::string m_ipaddress;
unsigned int m_dmrid;
ISerialPort* m_serial;
unsigned int m_brightness;
@ -75,6 +77,7 @@ private:
bool m_displayClock;
bool m_utc;
unsigned int m_idleBrightness;
unsigned int m_screenLayout;
CTimer m_clockDisplayTimer;
unsigned int m_rssiAccum1;
unsigned int m_rssiAccum2;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

29
Nextion_ON7LDS/README Normal file
View file

@ -0,0 +1,29 @@
The files in this directory are Nextion screen layouts with better fonts than
the(rather ugly) standard Nextion fonts
There are some other changes:
* On the main screen there is a field to display the active ip address of the
device. On Linux it is preceded with the network interface name.
* DMR: if received, the Talker Alias is decoded and displayed. The TA will be
in green, so the user knows it is a decoded TA displaying.
This happens on-the-fly: as the parts of the TA arrive, they will immediately
be shown.
* If you want to change my screen layout, the only thing to keep in mind is
that the MMDVMHost program will select following font numbers:
default font for the TA field : font 4
TA >16 characters : font 3
TA >20 characters : font 2
TA >24 characters : font 1
There always have to be at least 5 fonts, of which font 1-4 are used for the
TA. If your display is wide enough to show all characters in one font, you
must copy this font to the lesser ('smaller') fonts.
i.e. : the 3.2" the display can show more than 31 characters (the maximum
TA length) in font 2, so this font is also copied to font 1.
* The screenlayout has to be selected with the parameter ScreenLayout in the
MMDVM.ini file under the Nextion section. This way, the extra function
to automatically change the font size, is activated.
0 = auto (future use, for now it's G4KLX layout)
1 = G4KLX layout
2 = ON7LDS layout

342
OLED.cpp
View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -18,68 +18,96 @@
#include "OLED.h"
//Logo MMDVM for Idle Screen
static unsigned char logo_glcd_bmp[] =
{ 0b00101011, 0b11010100,
0b01010111, 0b11101010,
0b01010111, 0b11101010,
0b00101011, 0b11010100,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000001, 0b10000000,
0b00000000, 0b00000000 };
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xF8, 0x03, 0xFC, 0x7F, 0x80, 0x3F, 0xC7, 0xFF, 0xFC, 0xF8, 0x00, 0xF9, 0xFC, 0x01, 0xFE,
0x01, 0xFC, 0x07, 0xFC, 0x7F, 0xC0, 0x7F, 0xC4, 0x00, 0x02, 0x48, 0x00, 0x91, 0xFE, 0x03, 0xFE,
0x03, 0xFC, 0x07, 0xFC, 0x7F, 0xC0, 0x7F, 0xC5, 0xFF, 0xF1, 0x24, 0x01, 0x23, 0xFE, 0x03, 0xFE,
0x03, 0xFE, 0x0F, 0xBC, 0x7B, 0xE0, 0xFB, 0xC5, 0x00, 0x09, 0x24, 0x01, 0x23, 0xDF, 0x07, 0xDE,
0x07, 0xDE, 0x0F, 0x3C, 0x79, 0xE0, 0xF3, 0xC5, 0x00, 0x05, 0x12, 0x02, 0x47, 0xCF, 0x07, 0x9E,
0x07, 0x9F, 0x1F, 0x3C, 0x79, 0xF1, 0xF3, 0xC5, 0x00, 0x05, 0x12, 0x02, 0x47, 0x8F, 0x8F, 0x9E,
0x0F, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC5, 0x00, 0x05, 0x09, 0x04, 0x8F, 0x87, 0x8F, 0x1E,
0x0F, 0x0F, 0xBE, 0x3C, 0x78, 0xFB, 0xE3, 0xC5, 0x00, 0x05, 0x09, 0x04, 0x8F, 0x07, 0xDF, 0x1E,
0x1F, 0x07, 0xFC, 0x3C, 0x78, 0x7F, 0xC3, 0xC5, 0x00, 0x05, 0x04, 0x89, 0x1F, 0x03, 0xFE, 0x1E,
0x1E, 0x03, 0xFC, 0x3C, 0x78, 0x7F, 0xC3, 0xC5, 0x00, 0x09, 0x04, 0x89, 0x1E, 0x01, 0xFE, 0x1E,
0x3E, 0x03, 0xF8, 0x3C, 0x78, 0x3F, 0x83, 0xC5, 0xFF, 0xF1, 0x02, 0x72, 0x3E, 0x01, 0xFC, 0x1E,
0x3C, 0x01, 0xF0, 0x3C, 0x78, 0x1F, 0x03, 0xC4, 0x00, 0x02, 0x02, 0x02, 0x3C, 0x00, 0xF8, 0x1E,
0x7C, 0x01, 0xF0, 0x3C, 0x78, 0x1F, 0x03, 0xC7, 0xFF, 0xFC, 0x01, 0xFC, 0x7C, 0x00, 0xF8, 0x1E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
//DMR 48x16 px
static unsigned char logo_dmr_bmp[] =
{ 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b10000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000001,
0b10111111, 0b11111000, 0b01111000, 0b00011110, 0b01111111, 0b11100001,
0b10111111, 0b11111110, 0b01111100, 0b00111110, 0b01100000, 0b00011001,
0b10110000, 0b00001110, 0b01100110, 0b01100110, 0b01100000, 0b00011001,
0b10110000, 0b00000110, 0b01100011, 0b11000110, 0b01100000, 0b00011001,
0b10110000, 0b00000110, 0b01100001, 0b10000110, 0b01100000, 0b00011001,
0b10110000, 0b00000110, 0b01100000, 0b00000110, 0b01111111, 0b11111001,
0b10110000, 0b00000110, 0b01100000, 0b00000110, 0b01111000, 0b00000001,
0b10110000, 0b00000110, 0b01100000, 0b00000110, 0b01101100, 0b00000001,
0b10110000, 0b00000110, 0b01100000, 0b00000110, 0b01100110, 0b00000001,
0b10110000, 0b00001110, 0b01100000, 0b00000110, 0b01100011, 0b00000001,
0b10111111, 0b11111110, 0b01100000, 0b00000110, 0b01100001, 0b10000001,
0b10011111, 0b11111000, 0b01100000, 0b00000110, 0b01100000, 0b11000001,
0b10000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000001,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111
};
//D-Star 64x16 px
//Logo D-Star 128x16 px
static unsigned char logo_dstar_bmp[] =
{ 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b10000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000001,
0b10000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000001,
0b10000001, 0b11111100, 0b00000000, 0b00111100, 0b00000000, 0b00000000, 0b00000000, 0b01000001,
0b10000001, 0b00000010, 0b00000000, 0b01000010, 0b01000000, 0b00000000, 0b00000000, 0b01000001,
0b10000001, 0b00000010, 0b00000000, 0b01000000, 0b01000000, 0b00000000, 0b00000000, 0b01000001,
0b10000001, 0b00000010, 0b00000000, 0b01000000, 0b01000000, 0b00000000, 0b00000000, 0b01000001,
0b10000001, 0b00000010, 0b01111111, 0b00111100, 0b01111000, 0b00111100, 0b00111100, 0b01000001,
0b10000001, 0b00000010, 0b00000000, 0b00000010, 0b01000000, 0b00000010, 0b01000010, 0b01000001,
0b10000001, 0b00000010, 0b00000000, 0b00000010, 0b01000000, 0b00111110, 0b01000000, 0b01000001,
0b10000001, 0b00000010, 0b00000000, 0b00000010, 0b01000000, 0b01000010, 0b01000000, 0b00000001,
0b10000001, 0b00000010, 0b00000000, 0b01000010, 0b01000010, 0b01000010, 0b01000000, 0b01000001,
0b10000001, 0b11111100, 0b00000000, 0b00111100, 0b00111100, 0b00111100, 0b01000000, 0b01000001,
0b10000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000001,
0b10000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000001,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111
};
{
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x03, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xF0, 0xFF, 0xFE, 0x07, 0x80, 0x3F, 0xF8,
0x00, 0x00, 0xC0, 0x07, 0xC1, 0xE0, 0x00, 0x00, 0x78, 0x7C, 0xFF, 0xFE, 0x0F, 0xC0, 0x3F, 0xFC,
0x00, 0x01, 0xC0, 0x07, 0x80, 0xF0, 0x00, 0x00, 0xE0, 0x3C, 0x07, 0x80, 0x0F, 0xC0, 0x78, 0x0E,
0x00, 0x03, 0xC0, 0x07, 0x80, 0x70, 0x00, 0x00, 0xE0, 0x38, 0x07, 0x00, 0x1B, 0xC0, 0x78, 0x0E,
0x00, 0x07, 0xC0, 0x07, 0x80, 0x70, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x00, 0x33, 0xC0, 0x70, 0x1E,
0x07, 0xFF, 0xFE, 0x07, 0x00, 0x70, 0x00, 0x01, 0xF8, 0x00, 0x07, 0x00, 0x63, 0xC0, 0x70, 0x3C,
0x01, 0xFF, 0xF8, 0x0F, 0x00, 0x71, 0xFF, 0xE0, 0xFF, 0xF0, 0x0E, 0x00, 0xE1, 0xE0, 0xFF, 0xE0,
0x00, 0x7F, 0xE0, 0x0F, 0x00, 0x60, 0x00, 0x00, 0x03, 0xF8, 0x0E, 0x00, 0xC1, 0xE0, 0xFF, 0xE0,
0x00, 0x3F, 0x80, 0x0E, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x0E, 0x01, 0xFF, 0xE0, 0xE0, 0x70,
0x00, 0x7F, 0x00, 0x1E, 0x00, 0xE0, 0x00, 0x03, 0x80, 0x70, 0x0C, 0x03, 0xFC, 0xE0, 0xE0, 0x30,
0x00, 0xFF, 0x00, 0x1E, 0x01, 0xC0, 0x00, 0x07, 0x80, 0xE0, 0x1C, 0x07, 0x00, 0xE1, 0xE0, 0x38,
0x01, 0xEF, 0x00, 0x1C, 0x07, 0x80, 0x00, 0x07, 0xC1, 0xE0, 0x1C, 0x06, 0x00, 0xF1, 0xC0, 0x38,
0x03, 0x87, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x1C, 0x0C, 0x00, 0xF3, 0xC0, 0x38,
0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
COLED::COLED(unsigned char displayType, unsigned char displayBrightness, bool displayInvert) :
//Logo DMR 128x16 px
static unsigned char logo_dmr_bmp[] =
{
0x00, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xF8, 0x00, 0x00, 0x1F, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x00,
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFC, 0x00, 0x00, 0x3F, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xE1, 0xFE, 0x00, 0x00, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x0F, 0xF1, 0xFF, 0x80, 0x01, 0xFF, 0x1F, 0x80, 0x00, 0x1F, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x03, 0xF9, 0xFF, 0xC0, 0x03, 0xFF, 0x1F, 0x80, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x01, 0xF9, 0xFF, 0xE0, 0x07, 0xFF, 0x1F, 0x80, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x01, 0xFD, 0xF3, 0xF0, 0x1F, 0x9F, 0x1F, 0x80, 0x00, 0x1F, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x00, 0xFD, 0xF1, 0xFC, 0x3F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x00, 0xFD, 0xF0, 0xFE, 0x7E, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x01, 0xFD, 0xF0, 0x7F, 0xFC, 0x1F, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x01, 0xF9, 0xF0, 0x1F, 0xF0, 0x1F, 0x1F, 0x81, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x07, 0xF9, 0xF0, 0x0F, 0xE0, 0x1F, 0x1F, 0x80, 0x7F, 0x00, 0x00, 0x00,
0x00, 0x01, 0xF8, 0x00, 0x3F, 0xF1, 0xF0, 0x07, 0xC0, 0x1F, 0x1F, 0x80, 0x3F, 0xC0, 0x00, 0x00,
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xC1, 0xF0, 0x03, 0x80, 0x1F, 0x1F, 0x80, 0x0F, 0xF0, 0x00, 0x00,
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0xF0, 0x00, 0x00, 0x1F, 0x1F, 0x80, 0x03, 0xFC, 0x00, 0x00,
0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x01, 0xF0, 0x00, 0x00, 0x1F, 0x1F, 0x80, 0x01, 0xFF, 0x00, 0x00
};
//Logo Fusion 128x16
const unsigned char logo_fusion_bmp [] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFC, 0x00, 0x1F, 0xE1, 0xFE, 0x1F, 0xFF, 0xF8, 0x7F, 0xC3, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE,
0x03, 0xFC, 0x00, 0x3F, 0xC3, 0xFC, 0x3F, 0x80, 0x00, 0x7F, 0x87, 0xF0, 0xFF, 0x0F, 0xF1, 0xFF,
0x07, 0xFF, 0xFC, 0x7F, 0x83, 0xF8, 0x7F, 0x80, 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0x1F, 0xE1, 0xFE,
0x0F, 0xFF, 0xF0, 0x7F, 0x07, 0xF0, 0xFF, 0xFF, 0xC1, 0xFF, 0x1F, 0xE1, 0xFE, 0x3F, 0xC3, 0xFC,
0x0F, 0xF0, 0x00, 0xFE, 0x0F, 0xE0, 0x7F, 0xFF, 0xE1, 0xFE, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC,
0x1F, 0xE0, 0x01, 0xFC, 0x1F, 0xE0, 0x1F, 0xFF, 0xE3, 0xFC, 0x3F, 0xC3, 0xF8, 0x7F, 0x87, 0xF8,
0x3F, 0xC0, 0x03, 0xFC, 0x3F, 0xC0, 0x00, 0x3F, 0xC7, 0xF8, 0x7F, 0x87, 0xF8, 0xFF, 0x0F, 0xF0,
0x7F, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0x07, 0xF8, 0x7F, 0xCF, 0xE1, 0xFF, 0x1F, 0xF8,
0x7F, 0x80, 0x01, 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x0F, 0xF0, 0x3F, 0xFF, 0x81, 0xFE, 0x1F, 0xF0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
COLED::COLED(unsigned char displayType, unsigned char displayBrightness, bool displayInvert, bool displayScroll) :
m_displayType(displayType),
m_displayBrightness(displayBrightness),
m_displayInvert(displayInvert)
m_displayInvert(displayInvert),
m_displayScroll(displayScroll)
{
}
@ -118,7 +146,7 @@ bool COLED::open()
display.print("Startup");
display.display();
return true;
return true;
}
void COLED::setIdleInt()
@ -127,12 +155,14 @@ void COLED::setIdleInt()
display.clearDisplay();
OLED_statusbar();
display.setCursor(0,display.height()/2);
display.setTextSize(2);
display.print("Idle");
display.setTextSize(1);
// display.setCursor(0,30);
// display.setTextSize(3);
// display.print("Idle");
// display.setTextSize(1);
display.startscrolldiagright(0x00,0x0f); //the MMDVM logo scrolls the whole screen
display.display();
display.startscrollright(0x02,0x0f);
}
void COLED::setErrorInt(const char* text)
@ -141,8 +171,10 @@ void COLED::setErrorInt(const char* text)
display.clearDisplay();
OLED_statusbar();
display.setCursor(0,OLED_LINE1);
display.printf("%s\n", text);
display.printf("%s\n",text);
display.display();
}
@ -152,151 +184,171 @@ void COLED::setLockoutInt()
display.clearDisplay();
OLED_statusbar();
display.setCursor(0,OLED_LINE1);
display.setCursor(0,30);
display.setTextSize(3);
display.print("Lockout");
display.setTextSize(1);
display.display();
}
void COLED::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
{
m_mode = MODE_DSTAR;
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
display.printf("%s %.8s/%4.4s", type, my1, my2);
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
display.clearDisplay();
display.fillRect(0,OLED_LINE1,display.width(),display.height(),BLACK); //clear everything beneath logo
display.setCursor(0,OLED_LINE2);
display.printf("via %.8s", reflector);
display.fillRect(0, OLED_LINE3, display.width(), 10, BLACK);
display.printf("%s %.8s/%4.4s",type,my1,my2);
display.setCursor(0,OLED_LINE3);
display.printf("%.8s <- %-8s", your, reflector);
display.printf("-> %.8s",your);
display.setCursor(0,OLED_LINE5);
display.printf("via %.8s",reflector);
OLED_statusbar();
display.display();
}
void COLED::clearDStarInt()
{
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
display.fillRect(0,OLED_LINE1, display.width(),display.height(),BLACK); //clear everything beneath the logo
display.setCursor(40,38);
display.print("Listening");
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
display.fillRect(0, OLED_LINE3, display.width(), 10, BLACK);
OLED_statusbar();
display.display();
}
void COLED::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
void COLED::writeDMRInt(unsigned int slotNo,const std::string& src,bool group,const std::string& dst,const char* type)
{
if (m_mode != MODE_DMR) {
display.clearDisplay();
display.clearDisplay();
m_mode = MODE_DMR;
if (slotNo == 1U)
{
display.fillRect(0, OLED_LINE3, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE3);
{
display.fillRect(0,OLED_LINE4,display.width(),20,BLACK); //20=> clear 2 lines
display.setCursor(0,OLED_LINE4);
display.print("2 Listening");
display.fillRect(0, OLED_LINE4, display.width(), 10, BLACK);
}
}
else
{
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
{
display.fillRect(0,OLED_LINE2,display.width(),20,BLACK); //20=> clear 2 lines
display.setCursor(0,OLED_LINE2);
display.print("1 Listening");
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
}
}
if (slotNo == 1U) {
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
display.printf("%i %s %s", slotNo, type, src.c_str());
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE2);
display.printf("%s%s", group ? "TG" : "", dst.c_str());
} else {
display.fillRect(0, OLED_LINE3, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE3);
display.printf("%i %s %s", slotNo, type, src.c_str());
display.fillRect(0, OLED_LINE4, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE4);
display.printf("%s%s", group ? "TG" : "", dst.c_str());
}
if (slotNo == 1U)
{
display.fillRect(0,OLED_LINE2,display.width(),20,BLACK);
display.setCursor(0,OLED_LINE2);
display.printf("%i %s %s",slotNo,type,src.c_str());
display.setCursor(0,OLED_LINE3);
display.printf("%s%s",group ? "TG" : "",dst.c_str());
}
else
{
display.fillRect(0,OLED_LINE4,display.width(),20,BLACK);
display.setCursor(0,OLED_LINE4);
display.printf("%i %s %s",slotNo,type,src.c_str());
display.setCursor(0,OLED_LINE5);
display.printf("%s%s", group ? "TG" : "", dst.c_str());
}
OLED_statusbar();
display.display();
}
void COLED::clearDMRInt(unsigned int slotNo)
{
OLED_statusbar();
if (slotNo == 1U)
{
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
{
display.fillRect(0, OLED_LINE2, display.width(), 20, BLACK);
display.setCursor(0,OLED_LINE2);
display.print("1 Listening");
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
}
}
else
{
display.fillRect(0, OLED_LINE3, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE3);
{
display.fillRect(0, OLED_LINE4, display.width(), 20, BLACK);
display.setCursor(0, OLED_LINE4);
display.print("2 Listening");
display.fillRect(0, OLED_LINE4, display.width(), 10, BLACK);
}
}
display.display();
}
void COLED::writeFusionInt(const char* source, const char* dest, const char* type, const char* origin)
{
m_mode = MODE_YSF;
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
display.printf("%s %.10s", type, source);
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
display.clearDisplay();
display.fillRect(0,OLED_LINE1,display.width(),display.height(),BLACK);
display.setCursor(0,OLED_LINE2);
display.printf("%s %.10s", type, source);
display.setCursor(0,OLED_LINE3);
display.printf(" %.10s", dest);
OLED_statusbar();
display.display();
}
void COLED::clearFusionInt()
{
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
display.fillRect(0, OLED_LINE1, display.width(), display.height(), BLACK);
display.setCursor(40,38);
display.print("Listening");
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
OLED_statusbar();
display.display();
}
void COLED::writeP25Int(const char* source, bool group, unsigned int dest, const char* type)
{
m_mode = MODE_P25;
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
display.printf("%s %.10s", type, source);
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
display.clearDisplay();
display.fillRect(0, OLED_LINE1, display.width(), display.height(), BLACK);
display.setCursor(0,OLED_LINE2);
display.printf("%s %.10s", type, source);
display.setCursor(0,OLED_LINE3);
display.printf(" %s%u", group ? "TG" : "", dest);
OLED_statusbar();
display.display();
}
void COLED::clearP25Int()
{
display.fillRect(0, OLED_LINE1, display.width(), 10, BLACK);
display.setCursor(0,OLED_LINE1);
display.fillRect(0, OLED_LINE1, display.width(), display.height(), BLACK);
display.setCursor(40,38);
display.print("Listening");
display.fillRect(0, OLED_LINE2, display.width(), 10, BLACK);
OLED_statusbar();
display.display();
}
void COLED::writeCWInt()
{
display.clearDisplay();
display.setCursor(0,display.height()/2);
display.setCursor(0,30);
display.setTextSize(3);
display.print("CW TX");
display.setTextSize(1);
display.display();
display.startscrollright(0x02,0x0f);
@ -305,16 +357,26 @@ void COLED::writeCWInt()
void COLED::clearCWInt()
{
display.clearDisplay();
display.setCursor(0,display.height()/2);
display.setTextSize(2);
display.setCursor(0,30);
display.setTextSize(3);
display.print("Idle");
display.setTextSize(1);
display.display();
display.startscrollright(0x02,0x0f);
display.startscrollleft(0x02,0x0f);
}
void COLED::close()
{
display.clearDisplay();
display.fillRect(0, 0, display.width(), 16, BLACK);
display.startscrollright(0x00,0x01);
display.setCursor(0,00);
display.setTextSize(2);
display.print("-CLOSE-");
display.display();
display.close();
}
@ -323,15 +385,19 @@ void COLED::OLED_statusbar()
display.stopscroll();
display.fillRect(0, 0, display.width(), 16, BLACK);
display.setTextColor(WHITE);
display.setCursor(0,0);
if (m_mode == MODE_DMR)
display.drawBitmap(0, 0, logo_dmr_bmp, 48, 16, WHITE);
display.drawBitmap(0, 0, logo_dmr_bmp, 128, 16, WHITE);
else if (m_mode == MODE_DSTAR)
display.drawBitmap(0, 0, logo_dstar_bmp, 64, 16, WHITE);
display.drawBitmap(0, 0, logo_dstar_bmp, 128, 16, WHITE);
else if (m_mode == MODE_YSF)
display.print("Fusion");
display.drawBitmap(0, 0, logo_fusion_bmp, 128, 16, WHITE);
else if (m_mode == MODE_P25)
display.print("P25");
else
display.drawBitmap(0, 0, logo_glcd_bmp, 16, 15, WHITE);
display.drawBitmap(0, 0, logo_glcd_bmp, 128, 16, WHITE);
if (m_displayScroll)
display.startscrollright(0x00,0x02);
}

6
OLED.h
View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -24,6 +24,7 @@
#define OLED_LINE2 26
#define OLED_LINE3 36
#define OLED_LINE4 46
#define OLED_LINE5 56
#include "Display.h"
#include "Defines.h"
@ -37,7 +38,7 @@
class COLED : public CDisplay
{
public:
COLED(unsigned char displayType, unsigned char displayBrighness, bool displayInvert);
COLED(unsigned char displayType, unsigned char displayBrighness, bool displayInvert, bool displayScroll);
virtual ~COLED();
virtual bool open();
@ -71,6 +72,7 @@ private:
unsigned char m_displayType;
unsigned char m_displayBrightness;
bool m_displayInvert;
bool m_displayScroll;
ArduiPi_OLED display;
void OLED_statusbar();

View file

@ -35,9 +35,12 @@ const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CP25Control::CP25Control(unsigned int nac, bool uidOverride, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper) :
CP25Control::CP25Control(unsigned int nac, unsigned int id, bool selfOnly, bool uidOverride, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, bool remoteGateway, CRSSIInterpolator* rssiMapper) :
m_nac(nac),
m_id(id),
m_selfOnly(selfOnly),
m_uidOverride(uidOverride),
m_remoteGateway(remoteGateway),
m_network(network),
m_display(display),
m_duplex(duplex),
@ -101,14 +104,9 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
{
assert(data != NULL);
// CUtils::dump(1U, "P25 Data", data, len);
bool sync = data[1U] == 0x01U;
if (data[0U] == TAG_LOST && m_rfState == RS_RF_LISTENING)
return false;
if (data[0U] == TAG_LOST) {
if (data[0U] == TAG_LOST && m_rfState == RS_RF_AUDIO) {
if (m_rssi != 0U)
LogMessage("P25, transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
@ -128,6 +126,11 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
return false;
}
if (data[0U] == TAG_LOST) {
m_rfState = RS_RF_LISTENING;
return false;
}
if (!sync && m_rfState == RS_RF_LISTENING)
return false;
@ -177,12 +180,45 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
if (duid == P25_DUID_LDU1) {
if (m_rfState == RS_RF_LISTENING) {
m_rfData.reset();
bool ret = m_rfData.decodeLDU1(data + 2U, m_network != NULL, m_uidOverride);
bool ret = m_rfData.decodeLDU1(data + 2U);
if (!ret) {
m_lastDUID = duid;
return false;
}
unsigned int srcId = m_rfData.getSrcId();
if (m_selfOnly) {
if (m_id > 99999999U) { // Check that the Config DMR-ID is bigger than 8 digits
if (srcId != m_id / 100U)
return false;
}
else if (m_id > 9999999U) { // Check that the Config DMR-ID is bigger than 7 digits
if (srcId != m_id / 10U)
return false;
}
else if (srcId != m_id) { // All other cases
return false;
}
}
if (!m_uidOverride) {
bool found = m_lookup->exists(srcId);
if (!found)
return false;
}
bool grp = m_rfData.getLCF() == P25_LCF_GROUP;
unsigned int dstId = m_rfData.getDstId();
std::string source = m_lookup->find(srcId);
LogMessage("P25, received RF transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
m_display->writeP25(source.c_str(), grp, dstId, "R");
m_rfState = RS_RF_AUDIO;
m_minRSSI = m_rssi;
m_maxRSSI = m_rssi;
m_aveRSSI = m_rssi;
@ -190,149 +226,141 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
createRFHeader();
writeNetwork(data + 2U, P25_DUID_HEADER, false);
} else {
} else if (m_rfState == RS_RF_AUDIO) {
writeNetwork(m_rfLDU, m_lastDUID, false);
}
// Regenerate Sync
CSync::addP25Sync(data + 2U);
if (m_rfState == RS_RF_AUDIO) {
// Regenerate Sync
CSync::addP25Sync(data + 2U);
// Regenerate NID
m_nid.encode(data + 2U, P25_DUID_LDU1);
// Regenerate NID
m_nid.encode(data + 2U, P25_DUID_LDU1);
// Regenerate LDU1 Data
m_rfData.encodeLDU1(data + 2U);
// Regenerate LDU1 Data
m_rfData.encodeLDU1(data + 2U);
// Regenerate the Low Speed Data
m_rfLSD.process(data + 2U);
// Regenerate the Low Speed Data
m_rfLSD.process(data + 2U);
// Regenerate Audio
unsigned int errors = m_audio.process(data + 2U);
LogDebug("P25, LDU1 audio, errs: %u/1233 (%.1f%%)", errors, float(errors) / 12.33F);
// Regenerate Audio
unsigned int errors = m_audio.process(data + 2U);
LogDebug("P25, LDU1 audio, errs: %u/1233 (%.1f%%)", errors, float(errors) / 12.33F);
m_display->writeP25BER(float(errors) / 12.33F);
m_display->writeP25BER(float(errors) / 12.33F);
m_rfBits += 1233U;
m_rfErrs += errors;
m_rfFrames++;
m_lastDUID = duid;
m_rfBits += 1233U;
m_rfErrs += errors;
m_rfFrames++;
m_lastDUID = duid;
// Add busy bits
addBusyBits(data + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
// Add busy bits
addBusyBits(data + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
#if defined(DUMP_P25)
writeFile(data + 2U, len - 2U);
writeFile(data + 2U, len - 2U);
#endif
::memcpy(m_rfLDU, data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
::memcpy(m_rfLDU, data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
if (m_duplex) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U);
if (m_duplex) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
m_display->writeP25RSSI(m_rssi);
return true;
}
if (m_rfState == RS_RF_LISTENING) {
unsigned int srcId = m_rfData.getSrcId();
bool grp = m_rfData.getLCF() == P25_LCF_GROUP;
unsigned int dstId = m_rfData.getDstId();
std::string source = m_lookup->find(srcId);
LogMessage("P25, received RF transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
m_display->writeP25(source.c_str(), grp, dstId, "R");
m_rfState = RS_RF_AUDIO;
}
m_display->writeP25RSSI(m_rssi);
} else if (duid == P25_DUID_LDU2) {
if (m_rfState == RS_RF_LISTENING)
return false;
if (m_rfState == RS_RF_AUDIO) {
writeNetwork(m_rfLDU, m_lastDUID, false);
writeNetwork(m_rfLDU, m_lastDUID, false);
// Regenerate Sync
CSync::addP25Sync(data + 2U);
// Regenerate Sync
CSync::addP25Sync(data + 2U);
// Regenerate NID
m_nid.encode(data + 2U, P25_DUID_LDU2);
// Regenerate NID
m_nid.encode(data + 2U, P25_DUID_LDU2);
// Add the dummy LDU2 data
m_rfData.encodeLDU2(data + 2U);
// Add the dummy LDU2 data
m_rfData.encodeLDU2(data + 2U);
// Regenerate the Low Speed Data
m_rfLSD.process(data + 2U);
// Regenerate the Low Speed Data
m_rfLSD.process(data + 2U);
// Regenerate Audio
unsigned int errors = m_audio.process(data + 2U);
LogDebug("P25, LDU2 audio, errs: %u/1233 (%.1f%%)", errors, float(errors) / 12.33F);
// Regenerate Audio
unsigned int errors = m_audio.process(data + 2U);
LogDebug("P25, LDU2 audio, errs: %u/1233 (%.1f%%)", errors, float(errors) / 12.33F);
m_display->writeP25BER(float(errors) / 12.33F);
m_display->writeP25BER(float(errors) / 12.33F);
m_rfBits += 1233U;
m_rfErrs += errors;
m_rfFrames++;
m_lastDUID = duid;
m_rfBits += 1233U;
m_rfErrs += errors;
m_rfFrames++;
m_lastDUID = duid;
// Add busy bits
addBusyBits(data + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
// Add busy bits
addBusyBits(data + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
#if defined(DUMP_P25)
writeFile(data + 2U, len - 2U);
writeFile(data + 2U, len - 2U);
#endif
::memcpy(m_rfLDU, data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
::memcpy(m_rfLDU, data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
if (m_duplex) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U);
if (m_duplex) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
m_display->writeP25RSSI(m_rssi);
return true;
}
m_display->writeP25RSSI(m_rssi);
} else if (duid == P25_DUID_TERM || duid == P25_DUID_TERM_LC) {
if (m_rfState == RS_RF_LISTENING)
return false;
if (m_rfState == RS_RF_AUDIO) {
writeNetwork(m_rfLDU, m_lastDUID, true);
writeNetwork(m_rfLDU, m_lastDUID, true);
::memset(data + 2U, 0x00U, P25_TERM_FRAME_LENGTH_BYTES);
::memset(data + 2U, 0x00U, P25_TERM_FRAME_LENGTH_BYTES);
// Regenerate Sync
CSync::addP25Sync(data + 2U);
// Regenerate Sync
CSync::addP25Sync(data + 2U);
// Regenerate NID
m_nid.encode(data + 2U, P25_DUID_TERM);
// Regenerate NID
m_nid.encode(data + 2U, P25_DUID_TERM);
// Add busy bits
addBusyBits(data + 2U, P25_TERM_FRAME_LENGTH_BITS, false, true);
// Add busy bits
addBusyBits(data + 2U, P25_TERM_FRAME_LENGTH_BITS, false, true);
m_rfState = RS_RF_LISTENING;
m_rfTimeout.stop();
m_rfData.reset();
m_lastDUID = duid;
m_rfState = RS_RF_LISTENING;
m_rfTimeout.stop();
m_rfData.reset();
m_lastDUID = duid;
if (m_rssi != 0U)
LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
if (m_rssi != 0U)
LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
m_display->clearP25();
m_display->clearP25();
#if defined(DUMP_P25)
closeFile();
closeFile();
#endif
writeNetwork(data + 2U, P25_DUID_TERM, true);
writeNetwork(data + 2U, P25_DUID_TERM, true);
if (m_duplex) {
data[0U] = TAG_EOT;
data[1U] = 0x00U;
writeQueueRF(data, P25_TERM_FRAME_LENGTH_BYTES + 2U);
if (m_duplex) {
data[0U] = TAG_EOT;
data[1U] = 0x00U;
writeQueueRF(data, P25_TERM_FRAME_LENGTH_BYTES + 2U);
}
}
} else {
return false;
}
return true;
return false;
}
unsigned int CP25Control::readModem(unsigned char* data)
@ -725,7 +753,10 @@ void CP25Control::createNetHeader()
m_netData.encodeHeader(buffer + 2U);
// Add busy bits
addBusyBits(buffer + 2U, P25_HDR_FRAME_LENGTH_BITS, false, true);
if (m_remoteGateway)
addBusyBits(buffer + 2U, P25_HDR_FRAME_LENGTH_BITS, true, false);
else
addBusyBits(buffer + 2U, P25_HDR_FRAME_LENGTH_BITS, false, true);
writeQueueNet(buffer, P25_HDR_FRAME_LENGTH_BYTES + 2U);
}
@ -766,7 +797,10 @@ void CP25Control::createNetLDU1()
m_netLSD.encode(buffer + 2U);
// Add busy bits
addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
if (m_remoteGateway)
addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
else
addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
writeQueueNet(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
@ -811,7 +845,10 @@ void CP25Control::createNetLDU2()
m_netLSD.encode(buffer + 2U);
// Add busy bits
addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
if (m_remoteGateway)
addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
else
addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true);
writeQueueNet(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
@ -835,7 +872,10 @@ void CP25Control::createNetTerminator()
m_nid.encode(buffer + 2U, P25_DUID_TERM);
// Add busy bits
addBusyBits(buffer + 2U, P25_TERM_FRAME_LENGTH_BITS, false, true);
if (m_remoteGateway)
addBusyBits(buffer + 2U, P25_TERM_FRAME_LENGTH_BITS, true, false);
else
addBusyBits(buffer + 2U, P25_TERM_FRAME_LENGTH_BITS, false, true);
writeQueueNet(buffer, P25_TERM_FRAME_LENGTH_BYTES + 2U);

View file

@ -36,7 +36,7 @@
class CP25Control {
public:
CP25Control(unsigned int nac, bool uidOverride, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper);
CP25Control(unsigned int nac, unsigned int id, bool selfOly, bool uidOverride, CP25Network* network, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, bool remoteGateway, CRSSIInterpolator* rssiMapper);
~CP25Control();
bool writeModem(unsigned char* data, unsigned int len);
@ -47,7 +47,10 @@ public:
private:
unsigned int m_nac;
unsigned int m_id;
bool m_selfOnly;
bool m_uidOverride;
bool m_remoteGateway;
CP25Network* m_network;
CDisplay* m_display;
bool m_duplex;

View file

@ -71,7 +71,7 @@ void CP25Data::encodeHeader(unsigned char* data)
CP25Utils::encode(DUMMY_HEADER, data, 114U, 780U);
}
bool CP25Data::decodeLDU1(const unsigned char* data, bool m_network, bool m_uidOverride)
bool CP25Data::decodeLDU1(const unsigned char* data)
{
assert(data != NULL);
@ -105,12 +105,7 @@ bool CP25Data::decodeLDU1(const unsigned char* data, bool m_network, bool m_uidO
return false;
}
// Simple validation of the source id - does not check if no network
unsigned int srcId = (rs[6U] << 16) + (rs[7U] << 8) + rs[8U];
if (m_network || (!m_network && !m_uidOverride)) {
if (srcId < 1000000U)
return false;
}
switch (rs[0U]) {
case P25_LCF_GROUP:

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -28,7 +28,7 @@ public:
void encodeHeader(unsigned char* data);
bool decodeLDU1(const unsigned char* data, bool m_network, bool m_uidOverride);
bool decodeLDU1(const unsigned char* data);
void encodeLDU1(unsigned char* data);
void encodeLDU2(unsigned char* data);

View file

@ -27,11 +27,11 @@
#include <cstring>
const unsigned char REC62[] = {
0x62U, 0x02U, 0x02U, 0x0CU, 0x0BU, 0x1BU, 0x5AU, 0x1AU, 0x2BU, 0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
0x62U, 0x02U, 0x02U, 0x0CU, 0x0BU, 0x12U, 0x64U, 0x00U, 0x00U, 0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
const unsigned char REC63[] = {
0x63U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x7AU};
0x63U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
const unsigned char REC64[] = {
0x64U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
@ -43,23 +43,23 @@ const unsigned char REC66[] = {
0x66U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
const unsigned char REC67[] = {
0x67U, 0xC4U, 0x52U, 0x9BU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
0x67U, 0xF0U, 0x9DU, 0x6AU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
const unsigned char REC68[] = {
0x68U, 0x9AU, 0xECU, 0xBAU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
0x68U, 0x19U, 0xD4U, 0x26U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
const unsigned char REC69[] = {
0x69U, 0xB9U, 0xD8U, 0x16U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
0x69U, 0xE0U, 0xEBU, 0x7BU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
const unsigned char REC6A[] = {
0x6AU, 0x00U, 0x00U, 0x06U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
0x6AU, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
const unsigned char REC6B[] = {
0x6BU, 0x02U, 0x02U, 0x0CU, 0x0BU, 0x1BU, 0x5AU, 0x1AU, 0x2BU, 0xACU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
0x6BU, 0x02U, 0x02U, 0x0CU, 0x0BU, 0x12U, 0x64U, 0x00U, 0x00U, 0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
const unsigned char REC6C[] = {
0x6CU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0xD6U};
0x6CU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
const unsigned char REC6D[] = {
0x6DU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
@ -80,7 +80,7 @@ const unsigned char REC72[] = {
0x72U, 0x9BU, 0xDCU, 0x75U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
const unsigned char REC73[] = {
0x73U, 0x00U, 0x00U, 0x06U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
0x73U, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
const unsigned char REC80[] = {
0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U};

View file

@ -1,8 +1,8 @@
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, and System Fusion.
On the D-Star side the MMDVMHost interfaces with the ircDDB Gateway, on DMR it can connect to BrandMeister, DMR+, or HB Link, on System Fusion it connects to the YSF Gateway. On P25 it connects to the P25 Gateway.
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. On P25 it connects to the P25 Gateway.
It builds on 32-bit and 64-bit Linux as well as on Windows using VS2015 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 2017 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)
@ -11,6 +11,7 @@ It builds on 32-bit and 64-bit Linux as well as on Windows using VS2015 on x86 a
- Nextion TFTs (sizes 2.4", 2.8", 3.2" and 3.5")
- TFT display sold by Hobbytronics in UK
- 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.
@ -20,4 +21,6 @@ The Hobbytronics TFT Display, which is a Pi-Hat, connects to the UART on the Ras
The OLED display needs a 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.
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

@ -0,0 +1,23 @@
# This file maps the raw RSSI values to dBm values to send to the DMR network. A number of data
# points should be entered and the software will use those to work out the in-between values.
#
# The format of the file is:
# Raw RSSI Value dBm Value
#
# provided by Wilm DL4OCH
# Data taken with F0DEI MMDVM v1.2 and 47k/27k divider in RSSI input
2263 -43
2235 -53
2108 -63
1910 -73
1809 -83
1649 -93 # S9
1514 -99 # S8
1389 -105 # S7
1287 -111 # S6
1153 -117 # S5
1041 -123 # S4
977 -129 # S3
940 -135 # S2
934 -141 # S1

View file

@ -237,8 +237,11 @@ CSerialController::~CSerialController()
bool CSerialController::open()
{
assert(m_fd == -1);
#if defined(__APPLE__)
m_fd = ::open(m_device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); /*open in block mode under OSX*/
#else
m_fd = ::open(m_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY, 0);
#endif
if (m_fd < 0) {
LogError("Cannot open device - %s", m_device.c_str());
return false;
@ -257,6 +260,23 @@ bool CSerialController::open()
return false;
}
#if defined(__APPLE__)
termios.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
termios.c_cflag &= ~CSIZE;
termios.c_cflag |= CS8; /* 8-bit characters */
termios.c_cflag &= ~PARENB; /* no parity bit */
termios.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
termios.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
termios.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 1;
#else
termios.c_lflag &= ~(ECHO | ECHOE | ICANON | IEXTEN | ISIG);
termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | IXOFF | IXANY);
termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS);
@ -264,6 +284,7 @@ bool CSerialController::open()
termios.c_oflag &= ~(OPOST);
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10;
#endif
switch (m_speed) {
case SERIAL_1200:
@ -327,9 +348,27 @@ bool CSerialController::open()
}
}
#if defined(__APPLE__)
setNonblock(false);
#endif
return true;
}
#if defined(__APPLE__)
int CSerialController::setNonblock(bool nonblock)
{
int flag = ::fcntl(m_fd, F_GETFD, 0);
if (nonblock)
flag |= O_NONBLOCK;
else
flag &= ~O_NONBLOCK;
return ::fcntl(m_fd, F_SETFL, flag);
}
#endif
int CSerialController::read(unsigned char* buffer, unsigned int length)
{
assert(buffer != NULL);
@ -344,13 +383,11 @@ int CSerialController::read(unsigned char* buffer, unsigned int length)
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_fd, &fds);
int n;
if (offset == 0U) {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
n = ::select(m_fd + 1, &fds, NULL, NULL, &tv);
if (n == 0)
return 0;
@ -380,6 +417,26 @@ int CSerialController::read(unsigned char* buffer, unsigned int length)
return length;
}
bool CSerialController::canWrite(){
#if defined(__APPLE__)
fd_set wset;
FD_ZERO(&wset);
FD_SET(m_fd, &wset);
struct timeval timeo;
timeo.tv_sec = 0;
timeo.tv_usec = 0;
int rc = select(m_fd + 1, NULL, &wset, NULL, &timeo);
if (rc >0 && FD_ISSET(m_fd, &wset))
return true;
return false;
#else
return true;
#endif
}
int CSerialController::write(const unsigned char* buffer, unsigned int length)
{
assert(buffer != NULL);
@ -389,9 +446,10 @@ int CSerialController::write(const unsigned char* buffer, unsigned int length)
return 0;
unsigned int ptr = 0U;
while (ptr < length) {
ssize_t n = ::write(m_fd, buffer + ptr, length - ptr);
ssize_t n = 0U;
if (canWrite())
n = ::write(m_fd, buffer + ptr, length - ptr);
if (n < 0) {
if (errno != EAGAIN) {
LogError("Error returned from write(), errno=%d", errno);

View file

@ -53,6 +53,10 @@ public:
virtual void close();
#if defined(__APPLE__)
virtual int setNonblock(bool nonblock);
#endif
private:
std::string m_device;
SERIAL_SPEED m_speed;
@ -65,6 +69,8 @@ private:
#if defined(_WIN32) || defined(_WIN64)
int readNonblock(unsigned char* buffer, unsigned int length);
#else
bool canWrite();
#endif
};

View file

@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20170501";
const char* VERSION = "20170719";
#endif

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,7 @@
#include "YSFPayload.h"
#include "RingBuffer.h"
#include "StopWatch.h"
#include "YSFFICH.h"
#include "Display.h"
#include "Defines.h"
#include "Timer.h"
@ -34,9 +35,11 @@
class CYSFControl {
public:
CYSFControl(const std::string& callsign, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool lowDeviation, bool remoteGateway, CRSSIInterpolator* rssiMapper);
CYSFControl(const std::string& callsign, bool selfOnly, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool lowDeviation, bool remoteGateway, CRSSIInterpolator* rssiMapper);
~CYSFControl();
void setSQL(bool on, unsigned char value);
bool writeModem(unsigned char* data, unsigned int len);
unsigned int readModem(unsigned char* data);
@ -45,11 +48,15 @@ public:
private:
unsigned char* m_callsign;
unsigned char* m_selfCallsign;
bool m_selfOnly;
CYSFNetwork* m_network;
CDisplay* m_display;
bool m_duplex;
bool m_lowDeviation;
bool m_remoteGateway;
bool m_sqlEnabled;
unsigned char m_sqlValue;
CRingBuffer<unsigned char> m_queue;
RPT_RF_STATE m_rfState;
RPT_NET_STATE m_netState;
@ -69,10 +76,7 @@ private:
unsigned char* m_rfDest;
unsigned char* m_netSource;
unsigned char* m_netDest;
unsigned char* m_lastFrame;
bool m_lastFrameValid;
unsigned char m_lastMode;
unsigned char m_lastMR;
CYSFFICH m_lastFICH;
unsigned char m_netN;
CYSFPayload m_rfPayload;
CYSFPayload m_netPayload;
@ -84,6 +88,10 @@ private:
unsigned int m_rssiCount;
FILE* m_fp;
bool processVWData(bool valid, unsigned char *data);
bool processDNData(bool valid, unsigned char *data);
bool processFRData(bool valid, unsigned char *data);
void writeQueueRF(const unsigned char* data);
void writeQueueNet(const unsigned char* data);
void writeNetwork(const unsigned char* data, unsigned int count);
@ -96,8 +104,7 @@ private:
bool writeFile(const unsigned char* data);
void closeFile();
bool insertSilence(const unsigned char* data, unsigned char n);
void insertSilence(unsigned int count);
bool checkCallsign(const unsigned char* callsign) const;
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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,7 +42,8 @@ const unsigned char YSF_DT_DATA_FR_MODE = 0x01U;
const unsigned char YSF_DT_VD_MODE2 = 0x02U;
const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U;
const unsigned char YSF_CM_GROUP = 0x00U;
const unsigned char YSF_CM_GROUP1 = 0x00U;
const unsigned char YSF_CM_GROUP2 = 0x01U;
const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
const unsigned char YSF_MR_NOT_BUSY = 0x01U;

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