From 26697a4656053e8d4d5873b9d53d8d2032ea09e6 Mon Sep 17 00:00:00 2001 From: s-s-s Date: Thu, 23 Feb 2017 19:31:34 +0300 Subject: [PATCH 01/18] Create DMRIDUpdateBMRU.sh Get latest IDs from the BrandMeister network database. Modified for users from Russia --- DMRIDUpdateBMRU.sh | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 DMRIDUpdateBMRU.sh diff --git a/DMRIDUpdateBMRU.sh b/DMRIDUpdateBMRU.sh new file mode 100644 index 0000000..404ef59 --- /dev/null +++ b/DMRIDUpdateBMRU.sh @@ -0,0 +1,97 @@ +#! /bin/bash + +############################################################################### +# +# DMRIDUpdate.sh +# +# Copyright (C) 2016 by Tony Corbett G0WFV +# edit by R2AJV +# +# 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/DMRIDUpdate.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 > ${DMRIDFILE} + +# Restart MMDVMHost +eval ${RESTARTCOMMAND} From ae4c5b7c8898990e90d8b07f7cb5d778a6fcf1be Mon Sep 17 00:00:00 2001 From: Sergei Date: Fri, 10 Mar 2017 13:40:45 +0300 Subject: [PATCH 02/18] DMRds.dat from the BM network A script make a file DMRds.dat from a database of one server of the BrandMeister network --- DMRIDUpdateBM.sh | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 DMRIDUpdateBM.sh diff --git a/DMRIDUpdateBM.sh b/DMRIDUpdateBM.sh new file mode 100644 index 0000000..bc40817 --- /dev/null +++ b/DMRIDUpdateBM.sh @@ -0,0 +1,97 @@ +#! /bin/bash + +############################################################################### +# +# DMRIDUpdate.sh +# +# Copyright (C) 2016 by Tony Corbett G0WFV +# edit by R2AJV +# +# 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 > ${DMRIDFILE} + +# Restart MMDVMHost +eval ${RESTARTCOMMAND} From fd5e0646276c72c38d5000c80e26a508f02ef9a4 Mon Sep 17 00:00:00 2001 From: Sergei Date: Fri, 10 Mar 2017 13:43:35 +0300 Subject: [PATCH 03/18] Rename DMRIDUpdateBMRU.sh to DMRIDUpdateBM.sh --- DMRIDUpdateBMRU.sh => DMRIDUpdateBM.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename DMRIDUpdateBMRU.sh => DMRIDUpdateBM.sh (100%) diff --git a/DMRIDUpdateBMRU.sh b/DMRIDUpdateBM.sh similarity index 100% rename from DMRIDUpdateBMRU.sh rename to DMRIDUpdateBM.sh From aa35de7f608633602e0e9398b09be53a3c3ffc6a Mon Sep 17 00:00:00 2001 From: Sergei Date: Fri, 10 Mar 2017 13:44:11 +0300 Subject: [PATCH 04/18] Update DMRIDUpdateBM.sh --- DMRIDUpdateBM.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DMRIDUpdateBM.sh b/DMRIDUpdateBM.sh index 404ef59..bc40817 100644 --- a/DMRIDUpdateBM.sh +++ b/DMRIDUpdateBM.sh @@ -41,7 +41,7 @@ # # ... and add the following line to the bottom of the file ... # -# 0 0 * * * /path/to/script/DMRIDUpdate.sh 1>/dev/null 2>&1 +# 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. # From 28a25457e5d91cc076e1a67808c9756e8d929cc9 Mon Sep 17 00:00:00 2001 From: Sergei Date: Sat, 11 Mar 2017 14:15:26 +0300 Subject: [PATCH 05/18] Data to RSSI.dat by RA4NHY The data to RSSI.dat by RA4NHY for the Motorola GM340UHF radio station --- RSSI/RSSI_gm340uhf_RA4NHY.dat | 106 ++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 RSSI/RSSI_gm340uhf_RA4NHY.dat diff --git a/RSSI/RSSI_gm340uhf_RA4NHY.dat b/RSSI/RSSI_gm340uhf_RA4NHY.dat new file mode 100644 index 0000000..1a84ffa --- /dev/null +++ b/RSSI/RSSI_gm340uhf_RA4NHY.dat @@ -0,0 +1,106 @@ +#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 +#Ivan, 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 From d7b81703640615481c6173e15d7fa40dea96cabb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 12 Mar 2017 19:06:47 +0000 Subject: [PATCH 06/18] Change of DMR timeout behaviour. --- DMRControl.cpp | 8 +- DMRControl.h | 4 +- DMRSlot.cpp | 205 +++++++++++++++++++++++++++++-------------------- DMRSlot.h | 4 +- MMDVMHost.cpp | 24 +++--- 5 files changed, 146 insertions(+), 99 deletions(-) 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/DMRSlot.cpp b/DMRSlot.cpp index bc73257..7552203 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); @@ -134,18 +136,18 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) 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; + 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 true; } if (data[0U] == TAG_LOST) { m_rfState = RS_RF_LISTENING; - return; + return false; } // Have we got RSSI bytes on the end? @@ -183,12 +185,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 +199,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 +228,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 +267,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 +292,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 +308,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) @@ -318,14 +327,16 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) 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(); + + 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 +344,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 +394,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 +413,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 +461,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 +505,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 +525,28 @@ 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); + if (!m_rfTimeout) { + data[0U] = TAG_DATA; + data[1U] = 0x00U; - writeNetworkRF(data, DT_VOICE_SYNC, errors); + if (m_duplex) + writeQueueRF(data); + + writeNetworkRF(data, DT_VOICE_SYNC, errors); + } m_display->writeDMRRSSI(m_slotNo, m_rssi); + + return !m_rfTimeout; } 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) { @@ -629,7 +651,8 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) data[0U] = TAG_DATA; data[1U] = 0x00U; - writeNetworkRF(data, DT_VOICE, errors); + if (!m_rfTimeout) + writeNetworkRF(data, DT_VOICE, errors); if (m_embeddedLCOnly) { // Only send the previously received LC @@ -641,8 +664,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len) emb.getData(data + 2U); } - if (m_duplex) - writeQueueRF(data); + if (!m_rfTimeout) { + if (m_duplex) + writeQueueRF(data); + } + + return !m_rfTimeout; } else if (m_rfState == RS_RF_LATE_ENTRY) { CDMREMB emb; emb.putData(data + 2U); @@ -650,7 +677,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 +689,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 +722,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 +787,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 +820,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 +843,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 +864,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 +890,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 +960,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_lastFrameValid = false; m_netTimeoutTimer.start(); + m_netTimeout = false; m_netFrames = 0U; m_netLost = 0U; @@ -974,6 +1009,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_lastFrameValid = false; m_netTimeoutTimer.start(); + m_netTimeout = false; if (m_duplex) { m_queue.clear(); @@ -1063,15 +1099,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 +1194,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_lastFrameValid = false; m_netTimeoutTimer.start(); + m_netTimeout = false; if (m_duplex) { m_queue.clear(); @@ -1231,7 +1271,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 +1404,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 +1535,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 +1604,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 +1617,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 +1656,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..9985879 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -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); From 90e2f14db40e707fa53fe156a21d45bc1bb5e242 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 12 Mar 2017 19:10:04 +0000 Subject: [PATCH 07/18] Update ISSUES.txt --- ISSUES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ISSUES.txt b/ISSUES.txt index 5bf6d41..8375c26 100644 --- a/ISSUES.txt +++ b/ISSUES.txt @@ -9,3 +9,5 @@ It seems like there is a need to add some idle frames at the beginning of a DMO YSF: There is an issue that need addressing: The data sent to aprs.fi from southern hemisphere users isn’t always correct. Maybe the GPS format used by YSF still has some secrets to reveal. P25: No obvious issues. + +General: The Windows serial handling isn't working with the STM32 series of devices. This needs investigating. From 8e23051a9509ffa741861bfc6bf3efd8c18b1027 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 12 Mar 2017 19:25:01 +0000 Subject: [PATCH 08/18] Refine the timeout handling. --- DMRSlot.cpp | 54 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 7552203..721fd5f 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -135,8 +135,13 @@ bool 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 true; + if (m_rfTimeout) { + writeEndRF(); + return false; + } else { + writeEndRF(true); + return true; + } } if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) { @@ -326,9 +331,13 @@ 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)); - writeEndRF(); - - return true; + if (m_rfTimeout) { + writeEndRF(); + return false; + } else { + writeEndRF(); + return true; + } } else if (dataType == DT_DATA_HEADER) { if (m_rfState == RS_RF_DATA) return true; @@ -530,6 +539,8 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) m_rfEmbeddedData[m_rfEmbeddedWriteN].reset(); + m_display->writeDMRRSSI(m_slotNo, m_rssi); + if (!m_rfTimeout) { data[0U] = TAG_DATA; data[1U] = 0x00U; @@ -538,11 +549,11 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) writeQueueRF(data); writeNetworkRF(data, DT_VOICE_SYNC, errors); + + return true; } - m_display->writeDMRRSSI(m_slotNo, m_rssi); - - return !m_rfTimeout; + return false; } else if (m_rfState == RS_RF_LISTENING) { m_rfEmbeddedLC.reset(); m_rfState = RS_RF_LATE_ENTRY; @@ -648,28 +659,29 @@ bool 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; - if (!m_rfTimeout) 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_rfTimeout) { if (m_duplex) writeQueueRF(data); + + return true; } - return !m_rfTimeout; + return false; } else if (m_rfState == RS_RF_LATE_ENTRY) { CDMREMB emb; emb.putData(data + 2U); From 3f094a7e77896df063b2bafcbd06a0dab4ff48de Mon Sep 17 00:00:00 2001 From: Sergei Date: Mon, 13 Mar 2017 08:46:02 +0300 Subject: [PATCH 09/18] Update RSSI_gm340uhf_RA4NHY.dat --- RSSI/RSSI_gm340uhf_RA4NHY.dat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RSSI/RSSI_gm340uhf_RA4NHY.dat b/RSSI/RSSI_gm340uhf_RA4NHY.dat index 1a84ffa..9d55e18 100644 --- a/RSSI/RSSI_gm340uhf_RA4NHY.dat +++ b/RSSI/RSSI_gm340uhf_RA4NHY.dat @@ -1,10 +1,10 @@ -#Data to RSSI.dat by RA4NHY +#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 -#Ivan, RA4NHY +#Anton, RA4NHY 1045 -43 1043 -46 From f2667cbd4f464c27563835eaf461cf22e37022c1 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 13 Mar 2017 08:28:38 +0000 Subject: [PATCH 10/18] Tweak the DMR return value. --- DMRSlot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 721fd5f..3e4f393 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -147,7 +147,7 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) { LogMessage("DMR Slot %u, RF data transmission lost", m_slotNo); writeEndRF(); - return true; + return false; } if (data[0U] == TAG_LOST) { From e26fdd60301e5b361964518da14495990a700e17 Mon Sep 17 00:00:00 2001 From: George Smart Date: Mon, 13 Mar 2017 17:12:15 +0000 Subject: [PATCH 11/18] Added -g and --git options to MMDVMHost binary Added -g and --git options to MMDVMHost binary, which then enable this to be called by the Dashboard, etc. Since the -v --version flag is parsed already, amending that flag could cause version mismatch issues. --- MMDVMHost.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 9985879..a8fe172 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -85,8 +85,11 @@ int main(int argc, char** argv) if ((arg == "-v") || (arg == "--version")) { ::fprintf(stdout, "MMDVMHost version %s\n", VERSION); return 0; + } else if((arg == "-g") || (arg == "--git")) { + ::fprintf(stdout, "MMDVMHost GitID #%.7s\n", gitversion); + return 0; } else if (arg.substr(0,1) == "-") { - ::fprintf(stderr, "Usage: MMDVMHost [-v|--version] [filename]\n"); + ::fprintf(stderr, "Usage: MMDVMHost [-v|--version] [-g|--git] [filename]\n"); return 1; } else { iniFile = argv[currentArg]; From 9d71de3ae0afa05e47a665062d5894e91f885813 Mon Sep 17 00:00:00 2001 From: George Smart Date: Mon, 13 Mar 2017 19:17:16 +0000 Subject: [PATCH 12/18] Changed to output git ID on --version Changed from --git to --version option for showing the GitID. --- MMDVMHost.cpp | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index a8fe172..ce3e515 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -78,24 +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 == "-g") || (arg == "--git")) { - ::fprintf(stdout, "MMDVMHost GitID #%.7s\n", gitversion); - return 0; - } else if (arg.substr(0,1) == "-") { - ::fprintf(stderr, "Usage: MMDVMHost [-v|--version] [-g|--git] [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); From d2660376f3da4d5a8ab44ae8a33a605d2f6217b2 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 13 Mar 2017 19:22:39 +0000 Subject: [PATCH 13/18] Modify the Windows serial handling. --- SerialController.cpp | 78 ++++++++++++++++---------------------------- SerialController.h | 5 +-- 2 files changed, 29 insertions(+), 54 deletions(-) diff --git a/SerialController.cpp b/SerialController.cpp index cef3754..4931922 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,19 @@ #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_writeOverlapped() { assert(!device.empty()); - - m_readBuffer = new unsigned char[BUFFER_LENGTH]; } CSerialController::~CSerialController() { - delete[] m_readBuffer; } bool CSerialController::open() @@ -145,10 +137,6 @@ bool CSerialController::open() 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,51 +167,41 @@ 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 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; + } - DWORD error = ::GetLastError(); - if (error != ERROR_IO_PENDING) { - LogError("Error from ReadFile: %04lx", error); - return -1; - } + if (status.cbInQue == 0UL) + return 0; - m_readPending = true; - } - - BOOL res = HasOverlappedIoCompleted(&m_readOverlapped); - if (!res) - return 0; + DWORD readLength = status.cbInQue; + if (length < status.cbInQue) + readLength = length; DWORD bytes = 0UL; - res = ::GetOverlappedResult(m_handle, &m_readOverlapped, &bytes, TRUE); - if (!res) { - LogError("Error from GetOverlappedResult (ReadFile): %04lx", ::GetLastError()); + BOOL res = ::ReadFile(m_handle, buffer, readLength, &bytes, &m_readOverlapped); + if (res) + return int(bytes); + + DWORD error = ::GetLastError(); + if (error != ERROR_IO_PENDING) { + LogError("Error from ReadFile for %s: %04lx", m_device.c_str(), error); return -1; } - ::memcpy(buffer, m_readBuffer, bytes); - m_readPending = false; + DWORD ret = ::WaitForSingleObject(m_readOverlapped.hEvent, 100UL); + if (ret != WAIT_OBJECT_0) { + LogError("Error from WaitForSIngleObject for %s: %04lx", m_device.c_str(), ret); + return -1; + } - return int(bytes); + return int(bytes); } int CSerialController::write(const unsigned char* buffer, unsigned int length) @@ -242,13 +220,13 @@ int CSerialController::write(const unsigned char* buffer, unsigned int length) if (!res) { DWORD error = ::GetLastError(); if (error != ERROR_IO_PENDING) { - LogError("Error from WriteFile: %04lx", error); + LogError("Error from WriteFile for %s: %04lx", m_device.c_str(), error); return -1; } res = ::GetOverlappedResult(m_handle, &m_writeOverlapped, &bytes, TRUE); if (!res) { - LogError("Error from GetOverlappedResult (WriteFile): %04lx", ::GetLastError()); + LogError("Error from GetOverlappedResult for %s: %04lx", m_device.c_str(), ::GetLastError()); return -1; } } diff --git a/SerialController.h b/SerialController.h index f34342c..a366e0a 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 @@ -61,9 +61,6 @@ private: 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 From 84f4418bdea117c89e8d35fc2605e3da6343a60a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 13 Mar 2017 19:35:29 +0000 Subject: [PATCH 14/18] Use normal blocking file functions for Windows serial I/O. --- SerialController.cpp | 78 ++++++++++++++------------------------------ SerialController.h | 2 -- 2 files changed, 24 insertions(+), 56 deletions(-) diff --git a/SerialController.cpp b/SerialController.cpp index 4931922..fba80ae 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -44,9 +44,7 @@ CSerialController::CSerialController(const std::string& device, SERIAL_SPEED spe m_device(device), m_speed(speed), m_assertRTS(assertRTS), -m_handle(INVALID_HANDLE_VALUE), -m_readOverlapped(), -m_writeOverlapped() +m_handle(INVALID_HANDLE_VALUE) { assert(!device.empty()); } @@ -63,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; @@ -131,12 +129,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); - return true; } @@ -170,38 +162,28 @@ int CSerialController::readNonblock(unsigned char* buffer, unsigned int length) if (length == 0U) return 0; - 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; - } - - if (status.cbInQue == 0UL) - return 0; - - DWORD readLength = status.cbInQue; - if (length < status.cbInQue) - readLength = length; - - DWORD bytes = 0UL; - BOOL res = ::ReadFile(m_handle, buffer, readLength, &bytes, &m_readOverlapped); - if (res) - return int(bytes); - - DWORD error = ::GetLastError(); - if (error != ERROR_IO_PENDING) { - LogError("Error from ReadFile for %s: %04lx", m_device.c_str(), error); + 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; } - DWORD ret = ::WaitForSingleObject(m_readOverlapped.hEvent, 100UL); - if (ret != WAIT_OBJECT_0) { - LogError("Error from WaitForSIngleObject for %s: %04lx", m_device.c_str(), ret); - return -1; - } + if (status.cbInQue == 0UL) + return 0; - return int(bytes); + 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); } int CSerialController::write(const unsigned char* buffer, unsigned int length) @@ -216,19 +198,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 for %s: %04lx", m_device.c_str(), error); - return -1; - } - - res = ::GetOverlappedResult(m_handle, &m_writeOverlapped, &bytes, TRUE); - if (!res) { - LogError("Error from GetOverlappedResult for %s: %04lx", m_device.c_str(), ::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; @@ -243,9 +216,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 a366e0a..edb8e2b 100644 --- a/SerialController.h +++ b/SerialController.h @@ -59,8 +59,6 @@ private: bool m_assertRTS; #if defined(_WIN32) || defined(_WIN64) HANDLE m_handle; - OVERLAPPED m_readOverlapped; - OVERLAPPED m_writeOverlapped; #else int m_fd; #endif From ddf75b987262a586e3252be119533bd979893bae Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 16 Mar 2017 11:02:05 +0000 Subject: [PATCH 15/18] Remove sensitivity to the state of DSR (DTR on the modem). --- SerialController.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/SerialController.cpp b/SerialController.cpp index fba80ae..67310c8 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -75,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()); From 2e345aad3867620bb117edbed59ab834041e9869 Mon Sep 17 00:00:00 2001 From: Sergei Date: Thu, 16 Mar 2017 14:07:11 +0300 Subject: [PATCH 16/18] some small editing to get data in right format some small editing to get data in right format --- DMRIDUpdateBM.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DMRIDUpdateBM.sh b/DMRIDUpdateBM.sh index bc40817..9007e41 100644 --- a/DMRIDUpdateBM.sh +++ b/DMRIDUpdateBM.sh @@ -91,7 +91,13 @@ then fi # Generate new file -curl 'http://registry.dstar.su/dmr/DMRIds.php' 2>/dev/null > ${DMRIDFILE} +wget http://registry.dstar.su/dmr/DMRIds.php -O DMRIds-temp1.dat +cat DMRIds-temp1.dat | sed -e 's/ /\t\t/g' > DMRIds-temp2.dat +cat DMRIds-temp2.dat | sed -e 's/\t/ /g' > DMRIds-temp3.dat +cat DMRIds-temp3.dat | sed -e 's/ / /g' > DMRIds.dat +rm -f DMRIds-temp1.dat +rm -f DMRIds-temp2.dat +rm -f DMRIds-temp3.dat # Restart MMDVMHost eval ${RESTARTCOMMAND} From 890fafd9af1b4150a11661b80195230ef4bec6e1 Mon Sep 17 00:00:00 2001 From: Sergei Date: Thu, 16 Mar 2017 15:41:46 +0300 Subject: [PATCH 17/18] Small code optimization by CT2JAY Small code optimization by CT2JAY --- DMRIDUpdateBM.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/DMRIDUpdateBM.sh b/DMRIDUpdateBM.sh index 9007e41..dfe4e86 100644 --- a/DMRIDUpdateBM.sh +++ b/DMRIDUpdateBM.sh @@ -6,6 +6,7 @@ # # 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 @@ -91,13 +92,7 @@ then fi # Generate new file -wget http://registry.dstar.su/dmr/DMRIds.php -O DMRIds-temp1.dat -cat DMRIds-temp1.dat | sed -e 's/ /\t\t/g' > DMRIds-temp2.dat -cat DMRIds-temp2.dat | sed -e 's/\t/ /g' > DMRIds-temp3.dat -cat DMRIds-temp3.dat | sed -e 's/ / /g' > DMRIds.dat -rm -f DMRIds-temp1.dat -rm -f DMRIds-temp2.dat -rm -f DMRIds-temp3.dat +curl 'http://registry.dstar.su/dmr/DMRIds.php' 2>/dev/null | sed -e 's/[[:space:]]\+/ /g' > ${DMRIDFILE} # Restart MMDVMHost eval ${RESTARTCOMMAND} From ef9b64a3bb4b27546b862cefa1d6d846d44fd698 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 18 Mar 2017 07:18:46 +0000 Subject: [PATCH 18/18] Remove the Windows serial port issue. --- ISSUES.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/ISSUES.txt b/ISSUES.txt index 8375c26..5bf6d41 100644 --- a/ISSUES.txt +++ b/ISSUES.txt @@ -9,5 +9,3 @@ It seems like there is a need to add some idle frames at the beginning of a DMO YSF: There is an issue that need addressing: The data sent to aprs.fi from southern hemisphere users isn’t always correct. Maybe the GPS format used by YSF still has some secrets to reveal. P25: No obvious issues. - -General: The Windows serial handling isn't working with the STM32 series of devices. This needs investigating.