From ac22f0b783cdd3a14ab4831df4ee62602318bd71 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 16 Feb 2017 19:49:58 +0000 Subject: [PATCH] Add an optional error reply for D-Star. --- Conf.cpp | 9 +++- Conf.h | 2 + DStarControl.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++----- DStarControl.h | 5 ++- Defines.h | 5 ++- MMDVM.ini | 1 + MMDVMHost.cpp | 4 +- 7 files changed, 119 insertions(+), 15 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index 851dbe7..5bdd518 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -99,6 +99,7 @@ m_dstarEnabled(false), m_dstarModule("C"), m_dstarSelfOnly(false), m_dstarBlackList(), +m_dstarErrorReply(true), m_dmrEnabled(false), m_dmrBeacons(false), m_dmrId(0U), @@ -359,7 +360,8 @@ bool CConf::read() } p = ::strtok(NULL, ",\r\n"); } - } + } else if (::strcmp(key, "ErrorReply") == 0) + m_dstarErrorReply = ::atoi(value) == 1; } else if (section == SECTION_DMR) { if (::strcmp(key, "Enable") == 0) m_dmrEnabled = ::atoi(value) == 1; @@ -779,6 +781,11 @@ std::vector CConf::getDStarBlackList() const return m_dstarBlackList; } +bool CConf::getDStarErrorReply() const +{ + return m_dstarErrorReply; +} + bool CConf::getDMREnabled() const { return m_dmrEnabled; diff --git a/Conf.h b/Conf.h index 8aca5b0..d158130 100644 --- a/Conf.h +++ b/Conf.h @@ -90,6 +90,7 @@ public: std::string getDStarModule() const; bool getDStarSelfOnly() const; std::vector getDStarBlackList() const; + bool getDStarErrorReply() const; // The DMR section bool getDMREnabled() const; @@ -238,6 +239,7 @@ private: std::string m_dstarModule; bool m_dstarSelfOnly; std::vector m_dstarBlackList; + bool m_dstarErrorReply; bool m_dmrEnabled; bool m_dmrBeacons; diff --git a/DStarControl.cpp b/DStarControl.cpp index f8d4e9c..48713c1 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -36,10 +36,11 @@ bool CallsignCompare(const std::string& arg, const unsigned char* my) // #define DUMP_DSTAR -CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) : +CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool errorReply, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) : m_callsign(NULL), m_gateway(NULL), m_selfOnly(selfOnly), +m_errorReply(errorReply), m_blackList(blackList), m_network(network), m_display(display), @@ -58,6 +59,7 @@ m_rfTimeoutTimer(1000U, timeout), m_netTimeoutTimer(1000U, timeout), m_packetTimer(1000U, 0U, 300U), m_ackTimer(1000U, 0U, 750U), +m_errTimer(1000U, 0U, 750U), m_interval(), m_elapsed(), m_rfFrames(0U), @@ -126,6 +128,20 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) return false; } + if (type == TAG_LOST && m_rfState == RS_RF_INVALID) { + m_rfState = RS_RF_LISTENING; + + if (m_netState == RS_NET_IDLE) { + if (m_errorReply) + m_errTimer.start(); + + if (m_network != NULL) + m_network->reset(); + } + + return false; + } + if (type == TAG_LOST) { m_rfState = RS_RF_LISTENING; return false; @@ -177,6 +193,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) if (type == TAG_HEADER) { CDStarHeader header(data + 1U); + m_rfHeader = header; unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH]; header.getMyCall1(my1); @@ -184,7 +201,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) // Is this a transmission destined for a repeater? if (!header.isRepeater()) { LogMessage("D-Star, non repeater RF header received from %8.8s", my1); - m_rfState = RS_RF_REJECTED; + m_rfState = RS_RF_INVALID; return false; } @@ -194,7 +211,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) // Is it for us? if (::memcmp(callsign, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH) != 0) { LogMessage("D-Star, received RF header for wrong repeater (%8.8s) from %8.8s", callsign, my1); - m_rfState = RS_RF_REJECTED; + m_rfState = RS_RF_INVALID; return false; } @@ -225,9 +242,8 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) if (!m_rfTimeoutTimer.isRunning()) m_rfTimeoutTimer.start(); - m_rfHeader = header; - m_ackTimer.stop(); + m_errTimer.stop(); m_rfBits = 1U; m_rfErrs = 0U; @@ -271,6 +287,18 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } else if (type == TAG_EOT) { if (m_rfState == RS_RF_REJECTED) { m_rfState = RS_RF_LISTENING; + } else if (m_rfState == RS_RF_INVALID) { + m_rfState = RS_RF_LISTENING; + + if (m_netState == RS_NET_IDLE) { + if (m_errorReply) + m_errTimer.start(); + + if (m_network != NULL) + m_network->reset(); + } + + return false; } else if (m_rfState == RS_RF_AUDIO) { if (m_net) writeNetworkDataRF(DSTAR_END_PATTERN_BYTES, 0U, true); @@ -290,6 +318,8 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } else if (type == TAG_DATA) { if (m_rfState == RS_RF_REJECTED) { return false; + } else if (m_rfState == RS_RF_INVALID) { + return false; } else if (m_rfState == RS_RF_LISTENING) { // The sync is regenerated by the modem so can do exact match if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0) { @@ -340,8 +370,15 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) if (header == NULL) return false; + m_rfHeader = *header; + + unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH]; + header->getMyCall1(my1); + // Is this a transmission destined for a repeater? if (!header->isRepeater()) { + LogMessage("D-Star, non repeater RF header received from %8.8s", my1); + m_rfState = RS_RF_INVALID; delete header; return false; } @@ -351,19 +388,22 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) // Is it for us? if (::memcmp(callsign, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH) != 0) { + LogMessage("D-Star, received RF header for wrong repeater (%8.8s) from %8.8s", callsign, my1); + m_rfState = RS_RF_INVALID; delete header; return false; } - unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH]; - header->getMyCall1(my1); - if (m_selfOnly && ::memcmp(my1, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH - 1U) != 0) { + LogMessage("D-Star, invalid access attempt from %8.8s", my1); + m_rfState = RS_RF_REJECTED; delete header; return false; } if (!m_selfOnly && std::find_if(m_blackList.begin(), m_blackList.end(), std::bind(CallsignCompare, std::placeholders::_1, my1)) != m_blackList.end()) { + LogMessage("D-Star, invalid access attempt from %8.8s", my1); + m_rfState = RS_RF_REJECTED; delete header; return false; } @@ -385,8 +425,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) // Create a dummy start frame to replace the received frame m_ackTimer.stop(); - - m_rfHeader = *header; + m_errTimer.stop(); m_rfBits = 1U; m_rfErrs = 0U; @@ -550,6 +589,7 @@ void CDStarControl::writeNetwork() m_packetTimer.start(); //m_elapsed.start(); // commented out and placed lower down due to delay introduced somewhere below here. m_ackTimer.stop(); + m_errTimer.stop(); m_lastFrameValid = false; @@ -655,6 +695,12 @@ void CDStarControl::clock() m_ackTimer.stop(); } + m_errTimer.clock(ms); + if (m_errTimer.isRunning() && m_errTimer.hasExpired()) { + sendError(); + m_errTimer.stop(); + } + m_rfTimeoutTimer.clock(ms); m_netTimeoutTimer.clock(ms); @@ -1004,3 +1050,45 @@ void CDStarControl::sendAck() writeQueueEOTRF(); } + +void CDStarControl::sendError() +{ + unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH]; + m_rfHeader.getMyCall1(user); + + CDStarHeader header; + header.setUnavailable(true); + header.setMyCall1(m_callsign); + header.setYourCall(user); + header.setRPTCall1(m_callsign); + header.setRPTCall2(m_callsign); + + unsigned char data[DSTAR_HEADER_LENGTH_BYTES + 1U]; + header.get(data + 1U); + data[0U] = TAG_HEADER; + + writeQueueHeaderRF(data); + + writeQueueDataRF(DSTAR_NULL_FRAME_SYNC_BYTES); + + LINK_STATUS status = LS_NONE; + unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH]; + if (m_network != NULL) + m_network->getStatus(status, reflector); + + char text[40U]; + if (status == LS_LINKED_DEXTRA || status == LS_LINKED_DPLUS || status == LS_LINKED_DCS || status == LS_LINKED_CCS || status == LS_LINKED_LOOPBACK) + ::sprintf(text, "%-8.8s BER: %.1f%% ", reflector, float(m_rfErrs * 100U) / float(m_rfBits)); + else + ::sprintf(text, "BER: %.1f%% ", float(m_rfErrs * 100U) / float(m_rfBits)); + m_slowData.setText(text); + + ::memcpy(data, DSTAR_NULL_FRAME_DATA_BYTES, DSTAR_FRAME_LENGTH_BYTES + 1U); + + for (unsigned int i = 0U; i < 19U; i++) { + m_slowData.get(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES); + writeQueueDataRF(data); + } + + writeQueueEOTRF(); +} diff --git a/DStarControl.h b/DStarControl.h index 9eab5e3..84b4f3d 100644 --- a/DStarControl.h +++ b/DStarControl.h @@ -37,7 +37,7 @@ class CDStarControl { public: - CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper); + CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool errorReply, const std::vector& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper); ~CDStarControl(); bool writeModem(unsigned char* data, unsigned int len); @@ -50,6 +50,7 @@ private: unsigned char* m_callsign; unsigned char* m_gateway; bool m_selfOnly; + bool m_errorReply; std::vector m_blackList; CDStarNetwork* m_network; CDisplay* m_display; @@ -68,6 +69,7 @@ private: CTimer m_netTimeoutTimer; CTimer m_packetTimer; CTimer m_ackTimer; + CTimer m_errTimer; CStopWatch m_interval; CStopWatch m_elapsed; unsigned int m_rfFrames; @@ -112,6 +114,7 @@ private: void blankDTMF(unsigned char* data) const; void sendAck(); + void sendError(); }; #endif diff --git a/Defines.h b/Defines.h index 6b81e7a..22baf2d 100644 --- a/Defines.h +++ b/Defines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,7 +44,8 @@ enum RPT_RF_STATE { RS_RF_LATE_ENTRY, RS_RF_AUDIO, RS_RF_DATA, - RS_RF_REJECTED + RS_RF_REJECTED, + RS_RF_INVALID }; enum RPT_NET_STATE { diff --git a/MMDVM.ini b/MMDVM.ini index cacc2ff..4d899a3 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -62,6 +62,7 @@ Port=/dev/ttyACM1 Enable=1 Module=C SelfOnly=0 +ErrorReply=1 [DMR] Enable=1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 22e9707..d568199 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -329,15 +329,17 @@ int CMMDVMHost::run() std::string module = m_conf.getDStarModule(); bool selfOnly = m_conf.getDStarSelfOnly(); std::vector blackList = m_conf.getDStarBlackList(); + bool errorReply = m_conf.getDStarErrorReply(); LogInfo("D-Star Parameters"); LogInfo(" Module: %s", module.c_str()); LogInfo(" Self Only: %s", selfOnly ? "yes" : "no"); + LogInfo(" Error Reply: %s", errorReply ? "yes" : "no"); if (blackList.size() > 0U) LogInfo(" Black List: %u", blackList.size()); - dstar = new CDStarControl(m_callsign, module, selfOnly, blackList, m_dstarNetwork, m_display, m_timeout, m_duplex, rssi); + dstar = new CDStarControl(m_callsign, module, selfOnly, errorReply, blackList, m_dstarNetwork, m_display, m_timeout, m_duplex, rssi); } CDMRControl* dmr = NULL;