diff --git a/DMRControl.cpp b/DMRControl.cpp index eb9a857..291351d 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -85,18 +85,18 @@ bool CDMRControl::processWakeup(const unsigned char* data) return false; } -void CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len) +bool CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len) { assert(data != NULL); - m_slot1.writeModem(data, len); + return m_slot1.writeModem(data, len); } -void CDMRControl::writeModemSlot2(unsigned char *data, unsigned int len) +bool CDMRControl::writeModemSlot2(unsigned char *data, unsigned int len) { assert(data != NULL); - m_slot2.writeModem(data, len); + return m_slot2.writeModem(data, len); } unsigned int CDMRControl::readModemSlot1(unsigned char *data) diff --git a/DMRControl.h b/DMRControl.h index b000790..acfe072 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -36,8 +36,8 @@ public: bool processWakeup(const unsigned char* data); - void writeModemSlot1(unsigned char* data, unsigned int len); - void writeModemSlot2(unsigned char* data, unsigned int len); + bool writeModemSlot1(unsigned char* data, unsigned int len); + bool writeModemSlot2(unsigned char* data, unsigned int len); unsigned int readModemSlot1(unsigned char* data); unsigned int readModemSlot2(unsigned char* data); diff --git a/DMRIDUpdateBM.sh b/DMRIDUpdateBM.sh new file mode 100644 index 0000000..dfe4e86 --- /dev/null +++ b/DMRIDUpdateBM.sh @@ -0,0 +1,98 @@ +#! /bin/bash + +############################################################################### +# +# DMRIDUpdate.sh +# +# Copyright (C) 2016 by Tony Corbett G0WFV +# edit by R2AJV +# edit by CT2JAY +# +# 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. +# +############################################################################### +# +# On a Linux based system, such as a Raspberry Pi, this script will perform all +# the steps required to maintain the DMRIds.dat (or similar) file for you. +# +# It is designed to run from crontab and will download the latest IDs from the +# BM network database and optionally keep a backup of previously +# created files for you. +# +# It will also prune the number of backup files according to a value specified +# by you in the configuration below. +# +# When done, it will restart MMDVMHost to make the ID changes take effect. +# +# To install in root's crontab use the command ... +# +# sudo crontab -e +# +# ... and add the following line to the bottom of the file ... +# +# 0 0 * * * /path/to/script/DMRIDUpdateBM.sh 1>/dev/null 2>&1 +# +# ... where /path/to/script/ should be replaced by the path to this script. +# +############################################################################### +# +# CONFIGURATION +# +# Full path to DMR ID file +DMRIDFILE=/path/to/DMR/ID/file/DMRIds.dat +# +# How many DMR ID files do you want backed up (0 = do not keep backups) +DMRFILEBACKUP=1 +# +# Command line to restart MMDVMHost +RESTARTCOMMAND="systemctl restart mmdvmhost.service" +# RESTARTCOMMAND="killall MMDVMHost ; /path/to/MMDVMHost/executable/MMDVMHost /path/to/MMDVM/ini/file/MMDVM.ini" + +############################################################################### +# +# Do not edit below here +# +############################################################################### + +# Check we are root +if [ "$(id -u)" != "0" ] +then + echo "This script must be run as root" 1>&2 + exit 1 +fi + +# Create backup of old file +if [ ${DMRFILEBACKUP} -ne 0 ] +then + cp ${DMRIDFILE} ${DMRIDFILE}.$(date +%d%m%y) +fi + +# Prune backups +BACKUPCOUNT=$(ls ${DMRIDFILE}.* | wc -l) +BACKUPSTODELETE=$(expr ${BACKUPCOUNT} - ${DMRFILEBACKUP}) + +if [ ${BACKUPCOUNT} -gt ${DMRFILEBACKUP} ] +then + for f in $(ls -tr ${DMRIDFILE}.* | head -${BACKUPSTODELETE}) + do + rm $f + done +fi + +# Generate new file +curl 'http://registry.dstar.su/dmr/DMRIds.php' 2>/dev/null | sed -e 's/[[:space:]]\+/ /g' > ${DMRIDFILE} + +# Restart MMDVMHost +eval ${RESTARTCOMMAND} diff --git a/DMRSlot.cpp b/DMRSlot.cpp index bc73257..3e4f393 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -100,6 +100,8 @@ m_rfBits(1U), m_netBits(1U), m_rfErrs(0U), m_netErrs(0U), +m_rfTimeout(false), +m_netTimeout(false), m_lastFrame(NULL), m_lastFrameValid(false), m_rssi(0U), @@ -124,7 +126,7 @@ CDMRSlot::~CDMRSlot() delete[] m_lastFrame; } -void CDMRSlot::writeModem(unsigned char *data, unsigned int len) +bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) { assert(data != NULL); @@ -133,19 +135,24 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) LogMessage("DMR Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); else LogMessage("DMR Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits)); - writeEndRF(true); - return; + if (m_rfTimeout) { + writeEndRF(); + return false; + } else { + writeEndRF(true); + return true; + } } if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) { LogMessage("DMR Slot %u, RF data transmission lost", m_slotNo); writeEndRF(); - return; + return false; } if (data[0U] == TAG_LOST) { m_rfState = RS_RF_LISTENING; - return; + return false; } // Have we got RSSI bytes on the end? @@ -183,12 +190,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) if (dataType == DT_VOICE_LC_HEADER) { if (m_rfState == RS_RF_AUDIO) - return; + return true; CDMRFullLC fullLC; CDMRLC* lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER); if (lc == NULL) - return; + return false; unsigned int srcId = lc->getSrcId(); unsigned int dstId = lc->getDstId(); @@ -197,13 +204,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); delete lc; - return; + return false; } if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) { LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); delete lc; - return; + return false; } m_rfLC = lc; @@ -226,6 +233,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) data[1U] = 0x00U; m_rfTimeoutTimer.start(); + m_rfTimeout = false; m_rfFrames = 0U; m_rfSeqNo = 0U; @@ -264,9 +272,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) } LogMessage("DMR Slot %u, received RF voice header from %s to %s%s", m_slotNo, src.c_str(), flco == FLCO_GROUP ? "TG " : "", dst.c_str()); + + return true; } else if (dataType == DT_VOICE_PI_HEADER) { if (m_rfState != RS_RF_AUDIO) - return; + return false; // Regenerate the Slot Type slotType.getData(data + 2U); @@ -287,9 +297,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) writeQueueRF(data); writeNetworkRF(data, DT_VOICE_PI_HEADER); + + return true; } else if (dataType == DT_TERMINATOR_WITH_LC) { if (m_rfState != RS_RF_AUDIO) - return; + return false; // Regenerate the LC data CDMRFullLC fullLC; @@ -301,15 +313,17 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = TAG_EOT; - data[1U] = 0x00U; + if (!m_rfTimeout) { + data[0U] = TAG_EOT; + data[1U] = 0x00U; - writeNetworkRF(data, DT_TERMINATOR_WITH_LC); - writeNetworkRF(data, DT_TERMINATOR_WITH_LC); + writeNetworkRF(data, DT_TERMINATOR_WITH_LC); + writeNetworkRF(data, DT_TERMINATOR_WITH_LC); - if (m_duplex) { - for (unsigned int i = 0U; i < m_hangCount; i++) - writeQueueRF(data); + if (m_duplex) { + for (unsigned int i = 0U; i < m_hangCount; i++) + writeQueueRF(data); + } } if (m_rssi != 0U) @@ -317,15 +331,21 @@ void 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)); - writeEndRF(); + if (m_rfTimeout) { + writeEndRF(); + return false; + } else { + writeEndRF(); + return true; + } } else if (dataType == DT_DATA_HEADER) { if (m_rfState == RS_RF_DATA) - return; + return true; CDMRDataHeader dataHeader; bool valid = dataHeader.put(data + 2U); if (!valid) - return; + return false; bool gi = dataHeader.getGI(); unsigned int srcId = dataHeader.getSrcId(); @@ -333,12 +353,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); - return; + return false; } if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) { LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); - return; + return false; } m_rfFrames = dataHeader.getBlocks(); @@ -383,15 +403,17 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo); writeEndRF(); } + + return true; } else if (dataType == DT_CSBK) { CDMRCSBK csbk; bool valid = csbk.put(data + 2U); if (!valid) - return; + return false; CSBKO csbko = csbk.getCSBKO(); if (csbko == CSBKO_BSDWNACT) - return; + return false; bool gi = csbk.getGI(); unsigned int srcId = csbk.getSrcId(); @@ -400,12 +422,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) if (srcId != 0U || dstId != 0U) { if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); - return; + return false; } if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) { LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); - return; + return false; } } @@ -448,9 +470,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) LogWarning("DMR Slot %u, unhandled RF CSBK type - 0x%02X", m_slotNo, csbko); break; } + + 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; + return false; // Regenerate the rate 1/2 payload if (dataType == DT_RATE_12_DATA) { @@ -490,6 +514,8 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo); writeEndRF(); } + + return true; } } else if (audioSync) { if (m_rfState == RS_RF_AUDIO) { @@ -508,23 +534,30 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) m_rfBits += 141U; m_rfFrames++; - data[0U] = TAG_DATA; - data[1U] = 0x00U; - m_rfEmbeddedReadN = (m_rfEmbeddedReadN + 1U) % 2U; m_rfEmbeddedWriteN = (m_rfEmbeddedWriteN + 1U) % 2U; m_rfEmbeddedData[m_rfEmbeddedWriteN].reset(); - if (m_duplex) - writeQueueRF(data); - - writeNetworkRF(data, DT_VOICE_SYNC, errors); - m_display->writeDMRRSSI(m_slotNo, m_rssi); + + if (!m_rfTimeout) { + data[0U] = TAG_DATA; + data[1U] = 0x00U; + + if (m_duplex) + writeQueueRF(data); + + writeNetworkRF(data, DT_VOICE_SYNC, errors); + + return true; + } + + return false; } else if (m_rfState == RS_RF_LISTENING) { m_rfEmbeddedLC.reset(); m_rfState = RS_RF_LATE_ENTRY; + return false; } } else { if (m_rfState == RS_RF_AUDIO) { @@ -626,23 +659,29 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) emb.setLCSS(lcss); emb.getData(data + 2U); - data[0U] = TAG_DATA; - data[1U] = 0x00U; + if (!m_rfTimeout) { + data[0U] = TAG_DATA; + data[1U] = 0x00U; - writeNetworkRF(data, DT_VOICE, errors); + writeNetworkRF(data, DT_VOICE, errors); - if (m_embeddedLCOnly) { - // Only send the previously received LC - lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN); + if (m_embeddedLCOnly) { + // Only send the previously received LC + lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN); - // Regenerate the EMB - emb.setColorCode(m_colorCode); - emb.setLCSS(lcss); - emb.getData(data + 2U); + // Regenerate the EMB + emb.setColorCode(m_colorCode); + emb.setLCSS(lcss); + emb.getData(data + 2U); + } + + if (m_duplex) + writeQueueRF(data); + + return true; } - if (m_duplex) - writeQueueRF(data); + return false; } else if (m_rfState == RS_RF_LATE_ENTRY) { CDMREMB emb; emb.putData(data + 2U); @@ -650,7 +689,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) // If we haven't received an LC yet, then be strict on the color code unsigned char colorCode = emb.getColorCode(); if (colorCode != m_colorCode) - return; + return false; m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS()); CDMRLC* lc = m_rfEmbeddedLC.getLC(); @@ -662,13 +701,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); delete lc; - return; + return false; } if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) { LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId); delete lc; - return; + return false; } m_rfLC = lc; @@ -695,6 +734,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) start[1U] = 0x00U; m_rfTimeoutTimer.start(); + m_rfTimeout = false; m_rfFrames = 0U; m_rfSeqNo = 0U; @@ -759,9 +799,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) } LogMessage("DMR Slot %u, received RF late entry from %s to %s%s", m_slotNo, src.c_str(), flco == FLCO_GROUP ? "TG " : "", dst.c_str()); + + return true; } } } + + return false; } unsigned int CDMRSlot::readModem(unsigned char* data) @@ -788,14 +832,8 @@ void CDMRSlot::writeEndRF(bool writeEnd) m_display->clearDMR(m_slotNo); } - m_rfTimeoutTimer.stop(); - - m_rfFrames = 0U; - m_rfErrs = 0U; - m_rfBits = 1U; - if (writeEnd) { - if (m_netState == RS_NET_IDLE && m_duplex) { + if (m_netState == RS_NET_IDLE && m_duplex && !m_rfTimeout) { // Create a dummy start end frame unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -817,6 +855,13 @@ void CDMRSlot::writeEndRF(bool writeEnd) } } + m_rfTimeoutTimer.stop(); + m_rfTimeout = false; + + m_rfFrames = 0U; + m_rfErrs = 0U; + m_rfBits = 1U; + delete m_rfLC; m_rfLC = NULL; } @@ -831,17 +876,7 @@ void CDMRSlot::writeEndNet(bool writeEnd) m_lastFrameValid = false; - m_networkWatchdog.stop(); - m_netTimeoutTimer.stop(); - m_packetTimer.stop(); - - m_netFrames = 0U; - m_netLost = 0U; - - m_netErrs = 0U; - m_netBits = 1U; - - if (writeEnd) { + if (writeEnd && !m_netTimeout) { // Create a dummy start end frame unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -867,6 +902,17 @@ void CDMRSlot::writeEndNet(bool writeEnd) } } + m_networkWatchdog.stop(); + m_netTimeoutTimer.stop(); + m_packetTimer.stop(); + m_netTimeout = false; + + m_netFrames = 0U; + m_netLost = 0U; + + m_netErrs = 0U; + m_netBits = 1U; + delete m_netLC; m_netLC = NULL; @@ -926,6 +972,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_lastFrameValid = false; m_netTimeoutTimer.start(); + m_netTimeout = false; m_netFrames = 0U; m_netLost = 0U; @@ -974,6 +1021,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_lastFrameValid = false; m_netTimeoutTimer.start(); + m_netTimeout = false; if (m_duplex) { m_queue.clear(); @@ -1063,15 +1111,18 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Convert the Data Sync to be from the BS or MS as needed CSync::addDMRDataSync(data + 2U, m_duplex); - data[0U] = TAG_EOT; - data[1U] = 0x00U; + if (!m_netTimeout) { + data[0U] = TAG_EOT; + data[1U] = 0x00U; - if (m_duplex) { - for (unsigned int i = 0U; i < m_hangCount; i++) - writeQueueNet(data); - } else { - for (unsigned int i = 0U; i < 3U; i++) - writeQueueNet(data); + if (m_duplex) { + for (unsigned int i = 0U; i < m_hangCount; i++) + writeQueueNet(data); + } + else { + for (unsigned int i = 0U; i < 3U; i++) + writeQueueNet(data); + } } #if defined(DUMP_DMR) @@ -1155,6 +1206,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_lastFrameValid = false; m_netTimeoutTimer.start(); + m_netTimeout = false; if (m_duplex) { m_queue.clear(); @@ -1231,7 +1283,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) insertSilence(data, dmrData.getSeqNo()); } - writeQueueNet(data); + if (!m_netTimeout) + writeQueueNet(data); m_netEmbeddedReadN = (m_netEmbeddedReadN + 1U) % 2U; m_netEmbeddedWriteN = (m_netEmbeddedWriteN + 1U) % 2U; @@ -1363,7 +1416,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) insertSilence(data, dmrData.getSeqNo()); } - writeQueueNet(data); + if (!m_netTimeout) + writeQueueNet(data); m_packetTimer.start(); m_elapsed.start(); @@ -1493,7 +1547,20 @@ void CDMRSlot::clock() m_interval.start(); m_rfTimeoutTimer.clock(ms); + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) { + if (!m_rfTimeout) { + LogMessage("DMR Slot %u, RF user has timed out", m_slotNo); + m_rfTimeout = true; + } + } + m_netTimeoutTimer.clock(ms); + if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) { + if (!m_netTimeout) { + LogMessage("DMR Slot %u, network user has timed out", m_slotNo); + m_netTimeout = true; + } + } if (m_netState == RS_NET_AUDIO || m_netState == RS_NET_DATA) { m_networkWatchdog.clock(ms); @@ -1549,12 +1616,7 @@ void CDMRSlot::writeQueueRF(const unsigned char *data) } m_queue.addData(&len, 1U); - - // If the timeout has expired, replace the audio with idles to keep the slot busy - if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) - m_queue.addData(m_idle, len); - else - m_queue.addData(data, len); + m_queue.addData(data, len); } void CDMRSlot::writeNetworkRF(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId, unsigned char errors) @@ -1567,10 +1629,6 @@ void CDMRSlot::writeNetworkRF(const unsigned char* data, unsigned char dataType, if (m_network == NULL) return; - // Don't send to the network if the timeout has expired - if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) - return; - CDMRData dmrData; dmrData.setSlotNo(m_slotNo); dmrData.setDataType(dataType); @@ -1610,12 +1668,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data) } m_queue.addData(&len, 1U); - - // If the timeout has expired, replace the audio with idles to keep the slot busy - if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) - m_queue.addData(m_idle, len); - else - m_queue.addData(data, len); + m_queue.addData(data, len); } void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter) diff --git a/DMRSlot.h b/DMRSlot.h index d9a18b5..cde13a9 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -42,7 +42,7 @@ public: CDMRSlot(unsigned int slotNo, unsigned int timeout); ~CDMRSlot(); - void writeModem(unsigned char* data, unsigned int len); + bool writeModem(unsigned char* data, unsigned int len); unsigned int readModem(unsigned char* data); @@ -89,6 +89,8 @@ private: unsigned int m_netBits; unsigned int m_rfErrs; unsigned int m_netErrs; + bool m_rfTimeout; + bool m_netTimeout; unsigned char* m_lastFrame; bool m_lastFrameValid; unsigned char m_rssi; diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index d360992..ce3e515 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -78,21 +78,21 @@ const char* HEADER4 = "Copyright(C) 2015-2017 by Jonathan Naylor, G4KLX and othe int main(int argc, char** argv) { - const char* iniFile = DEFAULT_INI_FILE; - if (argc > 1) { - for (int currentArg = 1; currentArg < argc; ++currentArg) { - std::string arg = argv[currentArg]; - if ((arg == "-v") || (arg == "--version")) { - ::fprintf(stdout, "MMDVMHost version %s\n", VERSION); - return 0; - } else if (arg.substr(0,1) == "-") { - ::fprintf(stderr, "Usage: MMDVMHost [-v|--version] [filename]\n"); - return 1; - } else { - iniFile = argv[currentArg]; - } - } - } + const char* iniFile = DEFAULT_INI_FILE; + if (argc > 1) { + for (int currentArg = 1; currentArg < argc; ++currentArg) { + std::string arg = argv[currentArg]; + if ((arg == "-v") || (arg == "--version")) { + ::fprintf(stdout, "MMDVMHost version %s git #%.7s\n", VERSION, gitversion); + return 0; + } else if (arg.substr(0,1) == "-") { + ::fprintf(stderr, "Usage: MMDVMHost [-v|--version] [filename]\n"); + return 1; + } else { + iniFile = argv[currentArg]; + } + } + } #if !defined(_WIN32) && !defined(_WIN64) ::signal(SIGTERM, sigHandler); @@ -484,11 +484,13 @@ int CMMDVMHost::run() m_dmrTXTimer.start(); } } else { - dmr->writeModemSlot1(data, len); - dmrBeaconTimer.stop(); - m_modeTimer.start(); - if (m_duplex) - m_dmrTXTimer.start(); + bool ret = dmr->writeModemSlot1(data, len); + if (ret) { + dmrBeaconTimer.stop(); + m_modeTimer.start(); + if (m_duplex) + m_dmrTXTimer.start(); + } } } else if (m_mode != MODE_LOCKOUT) { LogWarning("DMR modem data received when in mode %u", m_mode); @@ -519,11 +521,13 @@ int CMMDVMHost::run() m_dmrTXTimer.start(); } } else { - dmr->writeModemSlot2(data, len); - dmrBeaconTimer.stop(); - m_modeTimer.start(); - if (m_duplex) - m_dmrTXTimer.start(); + bool ret = dmr->writeModemSlot2(data, len); + if (ret) { + dmrBeaconTimer.stop(); + m_modeTimer.start(); + if (m_duplex) + m_dmrTXTimer.start(); + } } } else if (m_mode != MODE_LOCKOUT) { LogWarning("DMR modem data received when in mode %u", m_mode); diff --git a/RSSI/RSSI_gm340uhf_RA4NHY.dat b/RSSI/RSSI_gm340uhf_RA4NHY.dat new file mode 100644 index 0000000..9d55e18 --- /dev/null +++ b/RSSI/RSSI_gm340uhf_RA4NHY.dat @@ -0,0 +1,106 @@ +#The data to RSSI.dat by RA4NHY +#Values in the RSSI.dat file are obtained using the MMDVMCal calibration program (S mode), the high-frequency generator and the Motorola GM340UHF radio station. +#For different radio stations, the values are slightly different. +#For example, for those GM340 that I had, the discrepancy is about 10 dB. +#Therefore, it is desirable to carry out calibration for each radio station. +#More about RSSI and a homebrew MMDVM node you can read here https://drive.google.com/file/d/0B_UNZTdPtyZUUjN2d2llV0RtNTQ/view but unfortunately in Russian only +#Anton, RA4NHY + +1045 -43 +1043 -46 +1042 -47 +1041 -48 +1039 -49 +1036 -50 +1030 -51 +1024 -52 +1017 -53 +1009 -54 +1003 -55 +992 -56 +980 -57 +967 -58 +955 -59 +941 -60 +929 -61 +916 -62 +905 -63 +893 -64 +884 -65 +874 -66 +865 -67 +856 -68 +848 -69 +839 -70 +831 -71 +823 -72 +815 -73 +805 -74 +799 -75 +789 -76 +778 -77 +767 -78 +757 -79 +746 -80 +737 -81 +727 -82 +719 -83 +711 -84 +704 -85 +696 -86 +689 -87 +682 -88 +674 -89 +667 -90 +659 -91 +650 -92 +641 -93 +630 -94 +621 -95 +610 -96 +598 -97 +586 -98 +575 -99 +564 -100 +554 -101 +544 -102 +535 -103 +526 -104 +521 -105 +512 -106 +504 -107 +495 -108 +486 -109 +477 -110 +468 -111 +458 -112 +449 -113 +439 -114 +431 -115 +421 -116 +412 -117 +404 -118 +395 -119 +387 -120 +381 -121 +374 -122 +368 -123 +363 -124 +360 -125 +355 -126 +352 -127 +348 -128 +345 -129 +344 -130 +342 -131 +340 -132 +339 -133 +338 -134 +337 -135 +336 -136 +335 -137 +334 -138 +333 -139 +332 -140 +331 -141 +330 -142 diff --git a/SerialController.cpp b/SerialController.cpp index cef3754..67310c8 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004,2007-2011,2013,2014-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2002-2004,2007-2011,2013,2014-2017 by Jonathan Naylor G4KLX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * * This program is free software; you can redistribute it and/or modify @@ -40,27 +40,17 @@ #if defined(_WIN32) || defined(_WIN64) -const unsigned int BUFFER_LENGTH = 1000U; - CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) : m_device(device), m_speed(speed), m_assertRTS(assertRTS), -m_handle(INVALID_HANDLE_VALUE), -m_readOverlapped(), -m_writeOverlapped(), -m_readBuffer(NULL), -m_readLength(0U), -m_readPending(false) +m_handle(INVALID_HANDLE_VALUE) { assert(!device.empty()); - - m_readBuffer = new unsigned char[BUFFER_LENGTH]; } CSerialController::~CSerialController() { - delete[] m_readBuffer; } bool CSerialController::open() @@ -71,7 +61,7 @@ bool CSerialController::open() std::string baseName = m_device.substr(4U); // Convert "\\.\COM10" to "COM10" - m_handle = ::CreateFileA(m_device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + m_handle = ::CreateFileA(m_device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (m_handle == INVALID_HANDLE_VALUE) { LogError("Cannot open device - %s, err=%04lx", m_device.c_str(), ::GetLastError()); return false; @@ -85,17 +75,18 @@ bool CSerialController::open() return false; } - dcb.BaudRate = DWORD(m_speed); - dcb.ByteSize = 8; - dcb.Parity = NOPARITY; - dcb.fParity = FALSE; - dcb.StopBits = ONESTOPBIT; - dcb.fInX = FALSE; - dcb.fOutX = FALSE; - dcb.fOutxCtsFlow = FALSE; - dcb.fOutxDsrFlow = FALSE; - dcb.fDtrControl = DTR_CONTROL_DISABLE; - dcb.fRtsControl = RTS_CONTROL_DISABLE; + dcb.BaudRate = DWORD(m_speed); + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.fParity = FALSE; + dcb.StopBits = ONESTOPBIT; + dcb.fInX = FALSE; + dcb.fOutX = FALSE; + dcb.fOutxCtsFlow = FALSE; + dcb.fOutxDsrFlow = FALSE; + dcb.fDsrSensitivity = FALSE; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fRtsControl = RTS_CONTROL_DISABLE; if (::SetCommState(m_handle, &dcb) == 0) { LogError("Cannot set the attributes for %s, err=%04lx", m_device.c_str(), ::GetLastError()); @@ -139,16 +130,6 @@ bool CSerialController::open() ::ClearCommError(m_handle, &errCode, NULL); - ::memset(&m_readOverlapped, 0x00U, sizeof(OVERLAPPED)); - ::memset(&m_writeOverlapped, 0x00U, sizeof(OVERLAPPED)); - - m_readOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); - m_writeOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); - - m_readLength = 0U; - m_readPending = false; - ::memset(m_readBuffer, 0x00U, BUFFER_LENGTH); - return true; } @@ -179,49 +160,29 @@ int CSerialController::readNonblock(unsigned char* buffer, unsigned int length) assert(m_handle != INVALID_HANDLE_VALUE); assert(buffer != NULL); - if (length > BUFFER_LENGTH) - length = BUFFER_LENGTH; - - if (m_readPending && length != m_readLength) { - ::CancelIo(m_handle); - m_readPending = false; - } - - m_readLength = length; - if (length == 0U) return 0; - if (!m_readPending) { - DWORD bytes = 0UL; - BOOL res = ::ReadFile(m_handle, m_readBuffer, m_readLength, &bytes, &m_readOverlapped); - if (res) { - ::memcpy(buffer, m_readBuffer, bytes); - return int(bytes); - } - - DWORD error = ::GetLastError(); - if (error != ERROR_IO_PENDING) { - LogError("Error from ReadFile: %04lx", error); - return -1; - } - - m_readPending = true; - } - - BOOL res = HasOverlappedIoCompleted(&m_readOverlapped); - if (!res) - return 0; - - DWORD bytes = 0UL; - res = ::GetOverlappedResult(m_handle, &m_readOverlapped, &bytes, TRUE); - if (!res) { - LogError("Error from GetOverlappedResult (ReadFile): %04lx", ::GetLastError()); + DWORD errors; + COMSTAT status; + if (::ClearCommError(m_handle, &errors, &status) == 0) { + LogError("Error from ClearCommError for %s, err=%04lx", m_device.c_str(), ::GetLastError()); return -1; } - ::memcpy(buffer, m_readBuffer, bytes); - m_readPending = false; + if (status.cbInQue == 0UL) + return 0; + + DWORD readLength = status.cbInQue; + if (length < readLength) + readLength = length; + + DWORD bytes = 0UL; + BOOL ret = ::ReadFile(m_handle, buffer, readLength, &bytes, NULL); + if (!ret) { + LogError("Error from ReadFile for %s: %04lx", m_device.c_str(), ::GetLastError()); + return -1; + } return int(bytes); } @@ -238,19 +199,10 @@ int CSerialController::write(const unsigned char* buffer, unsigned int length) while (ptr < length) { DWORD bytes = 0UL; - BOOL res = ::WriteFile(m_handle, buffer + ptr, length - ptr, &bytes, &m_writeOverlapped); - if (!res) { - DWORD error = ::GetLastError(); - if (error != ERROR_IO_PENDING) { - LogError("Error from WriteFile: %04lx", error); - return -1; - } - - res = ::GetOverlappedResult(m_handle, &m_writeOverlapped, &bytes, TRUE); - if (!res) { - LogError("Error from GetOverlappedResult (WriteFile): %04lx", ::GetLastError()); - return -1; - } + BOOL ret = ::WriteFile(m_handle, buffer + ptr, length - ptr, &bytes, NULL); + if (!ret) { + LogError("Error from WriteFile for %s: %04lx", m_device.c_str(), ::GetLastError()); + return -1; } ptr += bytes; @@ -265,9 +217,6 @@ void CSerialController::close() ::CloseHandle(m_handle); m_handle = INVALID_HANDLE_VALUE; - - ::CloseHandle(m_readOverlapped.hEvent); - ::CloseHandle(m_writeOverlapped.hEvent); } #else diff --git a/SerialController.h b/SerialController.h index f34342c..edb8e2b 100644 --- a/SerialController.h +++ b/SerialController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004,2007-2009,2011-2013,2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 by Jonathan Naylor G4KLX * Copyright (C) 1999-2001 by Thomas Sailor HB9JNX * * This program is free software; you can redistribute it and/or modify @@ -59,11 +59,6 @@ private: bool m_assertRTS; #if defined(_WIN32) || defined(_WIN64) HANDLE m_handle; - OVERLAPPED m_readOverlapped; - OVERLAPPED m_writeOverlapped; - unsigned char* m_readBuffer; - unsigned int m_readLength; - bool m_readPending; #else int m_fd; #endif