From 41bdb11bf24f630c8adfaa366774d29f380fa718 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 10 Mar 2017 08:36:47 +0000 Subject: [PATCH 1/9] Add two DMR issues. --- ISSUES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ISSUES.txt b/ISSUES.txt index 9c136d8..5bf6d41 100644 --- a/ISSUES.txt +++ b/ISSUES.txt @@ -2,6 +2,10 @@ D-Star: No obvious issues. DMR: There is an issue where transmitted data (text messages) isn’t picked up as reliably from an MMDVM than (say) a Hytera repeater. In order to address this, I need to see a trace from a Hytera repeater transmitting text, both from cold (no tx) and when already running. The DMRRX receiver from the DV4RX code in my GitHub repository would do the job, provided you have a DV4mini and a repeater within range. +Timeouts aren't handled cleany, i.e. the repeater should go off transmit rather than stay on. + +It seems like there is a need to add some idle frames at the beginning of a DMO transmission in order allow older DMR radios to wake up. + 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. From 6844085db36cb912af436a8f02b840c197e5565b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 10 Mar 2017 08:41:56 +0000 Subject: [PATCH 2/9] Updated the copyright dates. --- MMDVMHost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 4d9ed6a..d360992 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -74,7 +74,7 @@ static void sigHandler(int signum) const char* HEADER1 = "This software is for use on amateur radio networks only,"; const char* HEADER2 = "it is to be used for educational purposes only. Its use on"; const char* HEADER3 = "commercial networks is strictly prohibited."; -const char* HEADER4 = "Copyright(C) 2015, 2016 by Jonathan Naylor, G4KLX and others"; +const char* HEADER4 = "Copyright(C) 2015-2017 by Jonathan Naylor, G4KLX and others"; int main(int argc, char** argv) { From 2bc3606ed4ae20d0249ff8c7ca7962b59fad3639 Mon Sep 17 00:00:00 2001 From: phl0 Date: Fri, 10 Mar 2017 11:00:31 +0100 Subject: [PATCH 3/9] Fix case errors with GitVersion.h --- Makefile | 6 +++--- Makefile.Pi | 6 +++--- Makefile.Pi.Adafruit | 6 +++--- Makefile.Pi.HD44780 | 6 +++--- Makefile.Pi.OLED | 6 +++--- Makefile.Pi.PCF8574 | 6 +++--- Makefile.Solaris | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index b1f1050..90346af 100644 --- a/Makefile +++ b/Makefile @@ -15,17 +15,17 @@ OBJECTS = \ all: MMDVMHost -MMDVMHost: gitversion.h $(OBJECTS) +MMDVMHost: GitVersion.h $(OBJECTS) $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h + $(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h # Export the current git version if the index file exists, else 000... -gitversion.h: +GitVersion.h: ifneq ("$(wildcard .git/index)","") echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ else diff --git a/Makefile.Pi b/Makefile.Pi index f683ec6..3ac85ad 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -15,17 +15,17 @@ OBJECTS = \ all: MMDVMHost -MMDVMHost: gitversion.h $(OBJECTS) +MMDVMHost: GitVersion.h $(OBJECTS) $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h + $(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h # Export the current git version if the index file exists, else 000... -gitversion.h: +GitVersion.h: ifneq ("$(wildcard .git/index)","") echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ else diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 16ecc2f..816f5ad 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -15,17 +15,17 @@ OBJECTS = \ all: MMDVMHost -MMDVMHost: gitversion.h $(OBJECTS) +MMDVMHost: GitVersion.h $(OBJECTS) $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h + $(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h # Export the current git version if the index file exists, else 000... -gitversion.h: +GitVersion.h: ifneq ("$(wildcard .git/index)","") echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ else diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 981af5e..13b5688 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -15,17 +15,17 @@ OBJECTS = \ all: MMDVMHost -MMDVMHost: gitversion.h $(OBJECTS) +MMDVMHost: GitVersion.h $(OBJECTS) $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h + $(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h # Export the current git version if the index file exists, else 000... -gitversion.h: +GitVersion.h: ifneq ("$(wildcard .git/index)","") echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ else diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 660fc88..000de85 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -15,17 +15,17 @@ OBJECTS = \ all: MMDVMHost -MMDVMHost: gitversion.h $(OBJECTS) +MMDVMHost: GitVersion.h $(OBJECTS) $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h + $(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h # Export the current git version if the index file exists, else 000... -gitversion.h: +GitVersion.h: ifneq ("$(wildcard .git/index)","") echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ else diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 2ea81dd..9164dab 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -15,17 +15,17 @@ OBJECTS = \ all: MMDVMHost -MMDVMHost: gitversion.h $(OBJECTS) +MMDVMHost: GitVersion.h $(OBJECTS) $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h + $(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h # Export the current git version if the index file exists, else 000... -gitversion.h: +GitVersion.h: ifneq ("$(wildcard .git/index)","") echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ else diff --git a/Makefile.Solaris b/Makefile.Solaris index 6113fa6..7136c1a 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -15,17 +15,17 @@ OBJECTS = \ all: MMDVMHost -MMDVMHost: gitversion.h $(OBJECTS) +MMDVMHost: GitVersion.h $(OBJECTS) $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h + $(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h # Export the current git version if the index file exists, else 000... -gitversion.h: +GitVersion.h: ifneq ("$(wildcard .git/index)","") echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ else From ae4c5b7c8898990e90d8b07f7cb5d778a6fcf1be Mon Sep 17 00:00:00 2001 From: Sergei Date: Fri, 10 Mar 2017 13:40:45 +0300 Subject: [PATCH 4/9] 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 28a25457e5d91cc076e1a67808c9756e8d929cc9 Mon Sep 17 00:00:00 2001 From: Sergei Date: Sat, 11 Mar 2017 14:15:26 +0300 Subject: [PATCH 5/9] 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 6/9] 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 7/9] 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 8/9] 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 f2667cbd4f464c27563835eaf461cf22e37022c1 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 13 Mar 2017 08:28:38 +0000 Subject: [PATCH 9/9] 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) {