diff --git a/Conf.cpp b/Conf.cpp index 03e881a..6091f78 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -161,6 +161,7 @@ m_dmrCallHang(10U), m_dmrTXHang(4U), m_dmrModeHang(10U), m_dmrOVCM(DMR_OVCM_OFF), +m_dmrProtect(false), m_fusionEnabled(false), m_fusionLowDeviation(false), m_fusionRemoteGateway(false), @@ -753,7 +754,8 @@ bool CConf::read() m_dmrOVCM = DMR_OVCM_OFF; break; } - } + } else if (::strcmp(key, "Protect") == 0) + m_dmrProtect = ::atoi(value) == 1; } else if (section == SECTION_FUSION) { if (::strcmp(key, "Enable") == 0) m_fusionEnabled = ::atoi(value) == 1; @@ -1643,6 +1645,11 @@ DMR_OVCM_TYPES CConf::getDMROVCM() const return m_dmrOVCM; } +bool CConf::getDMRProtect() const +{ + return m_dmrProtect; +} + bool CConf::getFusionEnabled() const { return m_fusionEnabled; diff --git a/Conf.h b/Conf.h index e3d9d1e..6f210a5 100644 --- a/Conf.h +++ b/Conf.h @@ -144,6 +144,7 @@ public: unsigned int getDMRTXHang() const; unsigned int getDMRModeHang() const; DMR_OVCM_TYPES getDMROVCM() const; + bool getDMRProtect() const; // The System Fusion section bool getFusionEnabled() const; @@ -481,6 +482,7 @@ private: unsigned int m_dmrTXHang; unsigned int m_dmrModeHang; DMR_OVCM_TYPES m_dmrOVCM; + bool m_dmrProtect; bool m_fusionEnabled; bool m_fusionLowDeviation; diff --git a/DMRControl.cpp b/DMRControl.cpp index 5761080..3cedb5a 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -21,7 +21,7 @@ #include #include -CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : +CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm, bool protect) : m_colorCode(colorCode), m_modem(modem), m_network(network), @@ -38,7 +38,7 @@ m_lookup(lookup) // Load black and white lists to DMRAccessControl CDMRAccessControl::init(blacklist, whitelist, slot1TGWhitelist, slot2TGWhitelist, selfOnly, prefixes, id); - CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi, jitter, ovcm); + CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi, jitter, ovcm, protect); } CDMRControl::~CDMRControl() diff --git a/DMRControl.h b/DMRControl.h index 9144194..30cccdf 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -31,7 +31,7 @@ class CDMRControl { public: - CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); + CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm, bool protect); ~CDMRControl(); bool processWakeup(const unsigned char* data); diff --git a/DMRSlot.cpp b/DMRSlot.cpp index e66e11c..7720b0a 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -44,6 +44,7 @@ bool CDMRSlot::m_duplex = true; CDMRLookup* CDMRSlot::m_lookup = NULL; unsigned int CDMRSlot::m_hangCount = 3U * 17U; DMR_OVCM_TYPES CDMRSlot::m_ovcm = DMR_OVCM_OFF; +bool CDMRSlot::m_protect = false; CRSSIInterpolator* CDMRSlot::m_rssiMapper = NULL; @@ -222,6 +223,15 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) unsigned int dstId = lc->getDstId(); FLCO flco = lc->getFLCO(); + if (!m_protect) { + if (lc->getPF()) { + LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); + delete lc; + m_rfState = RS_RF_LISTENING; + return false; + } + } + if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); delete lc; @@ -320,10 +330,12 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) data[0U] = TAG_DATA; data[1U] = 0x00U; - if (m_duplex) - writeQueueRF(data); + if (m_protect) { + if (m_duplex) + writeQueueRF(data); - writeNetworkRF(data, DT_VOICE_PI_HEADER); + writeNetworkRF(data, DT_VOICE_PI_HEADER); + } return true; } else if (dataType == DT_TERMINATOR_WITH_LC) { @@ -810,6 +822,15 @@ bool CDMRSlot::writeModem(unsigned char *data, unsigned int len) unsigned int dstId = lc->getDstId(); FLCO flco = lc->getFLCO(); + if (!m_protect) { + if (lc->getPF()) { + LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); + delete lc; + m_rfState = RS_RF_LISTENING; + return false; + } + } + if (!CDMRAccessControl::validateSrcId(srcId)) { LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId); delete lc; @@ -1246,7 +1267,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; - writeQueueNet(data); + if (m_protect) + writeQueueNet(data); #if defined(DUMP_DMR) writeFile(data); @@ -1957,7 +1979,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data) m_queue.addData(data, len); } -void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) +void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm, bool protect) { assert(modem != NULL); assert(display != NULL); @@ -1974,6 +1996,7 @@ void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData m_lookup = lookup; m_hangCount = callHang * 17U; m_ovcm = ovcm; + m_protect = protect; m_rssiMapper = rssiMapper; diff --git a/DMRSlot.h b/DMRSlot.h index d3d58a2..11756a4 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -62,7 +62,7 @@ public: void enable(bool enabled); - static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); + static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm, bool protect); private: unsigned int m_slotNo; @@ -125,6 +125,7 @@ private: static CDMRLookup* m_lookup; static unsigned int m_hangCount; static DMR_OVCM_TYPES m_ovcm; + static bool m_protect; static CRSSIInterpolator* m_rssiMapper; diff --git a/DStarControl.cpp b/DStarControl.cpp index d6a42ac..c7ba73b 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -129,7 +129,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) unsigned char type = data[0U]; - if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) { + if (type == TAG_LOST && ((m_rfState == RS_RF_AUDIO) || (m_rfState == RS_RF_DATA))) { unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH]; unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH]; unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH]; @@ -320,7 +320,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } return false; - } else if (m_rfState == RS_RF_AUDIO) { + } else if ((m_rfState == RS_RF_AUDIO) || (m_rfState == RS_RF_DATA)) { if (m_net) writeNetworkDataRF(DSTAR_END_PATTERN_BYTES, 0U, true); @@ -354,37 +354,75 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) // 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) { m_rfSlowData.start(); + m_rfN = 0U; m_rfState = RS_RF_LATE_ENTRY; } return false; } - if (m_rfState == RS_RF_AUDIO) { + if ((m_rfState == RS_RF_AUDIO) || (m_rfState == RS_RF_DATA)) { // 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) { m_rfSlowData.start(); m_rfN = 0U; } + } - // Regenerate the sync and send the RSSI data to the display - if (m_rfN == 0U) { - CSync::addDStarSync(data + 1U); - m_display->writeDStarRSSI(m_rssi); - } + if (m_rfState == RS_RF_AUDIO) { + m_rfSlowData.peakSlowData(data + 1U, m_rfN); + unsigned char type = m_rfSlowData.getType(); - unsigned int errors = 0U; - if (!m_rfHeader.isDataPacket()) { - errors = m_fec.regenerateDStar(data + 1U); - m_display->writeDStarBER(float(errors) / 0.48F); - m_rfErrs += errors; + if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_BEGIN) { + LogMessage("D-Star, starting fast data mode"); + m_rfState = RS_RF_DATA; } + } + + if (m_rfState == RS_RF_DATA) { + LogDebug("D-Star, fast data sequence no. %u", m_rfN); m_rfBits += 48U; m_rfFrames++; + if (m_net) + writeNetworkDataRF(data, 0U, false); + + if (m_duplex) + writeQueueDataRF(data); + + m_rfSlowData.peakSlowData(data + 1U, m_rfN); + bool complete = m_rfSlowData.isComplete(); + + if (complete) { + unsigned char type = m_rfSlowData.getType(); + if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_END) { + LogMessage("D-Star, leaving fast data mode"); + m_rfState = RS_RF_AUDIO; + } + } + + m_rfN = (m_rfN + 1U) % 21U; + } else if (m_rfState == RS_RF_AUDIO) { + // Send the RSSI data to the display + if (m_rfN == 0U) + m_display->writeDStarRSSI(m_rssi); + + unsigned int errors = 0U; + if (::memcmp(data + 1U, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) == 0) { + LogDebug("D-Star, audio sequence no. %u, null audio", m_rfN); + } else { + errors = m_fec.regenerateDStar(data + 1U); + LogDebug("D-Star, audio sequence no. %u, errs: %u/48 (%.1f%%)", m_rfN, errors, float(errors) / 0.48F); + m_display->writeDStarBER(float(errors) / 0.48F); + } + + m_rfErrs += errors; + m_rfBits += 48U; + m_rfFrames++; + if (m_rfN != 0U) { - const unsigned char* text = m_rfSlowData.addText(data + 1U); + const unsigned char* text = m_rfSlowData.addText(data + 1U, m_rfN); if (text != NULL) LogMessage("D-Star, RF slow data text = \"%s\"", text); } @@ -398,15 +436,20 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } m_rfN = (m_rfN + 1U) % 21U; - } else if (m_rfState == RS_RF_LATE_ENTRY) { + } + + if (m_rfState == RS_RF_LATE_ENTRY) { // 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) { m_rfSlowData.reset(); + m_rfN = 0U; return false; } else { - CDStarHeader* header = m_rfSlowData.addHeader(data + 1U); - if (header == NULL) + CDStarHeader* header = m_rfSlowData.addHeader(data + 1U, m_rfN); + if (header == NULL) { + m_rfN = (m_rfN + 1U) % 21U; return false; + } m_rfHeader = *header; delete header; @@ -503,12 +546,14 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } unsigned int errors = 0U; - if (!m_rfHeader.isDataPacket()) { + if (::memcmp(data + 1U, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) == 0) { + LogDebug("D-Star, audio sequence no. %u, null audio", m_rfN); + } else { errors = m_fec.regenerateDStar(data + 1U); LogDebug("D-Star, audio sequence no. %u, errs: %u/48 (%.1f%%)", m_rfN, errors, float(errors) / 0.48F); - m_rfErrs += errors; } + m_rfErrs += errors; m_rfBits += 48U; if (m_net) @@ -521,8 +566,6 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) m_rfState = RS_RF_AUDIO; - m_rfN = (m_rfN + 1U) % 21U; - if (m_netState == RS_NET_IDLE) { m_display->writeDStar((char*)my1, (char*)my2, (char*)your, "R", " "); m_display->writeDStarRSSI(m_rssi); @@ -530,6 +573,8 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } LogMessage("D-Star, received RF late entry from %8.8s/%4.4s to %8.8s", my1, my2, your); + + m_rfN = (m_rfN + 1U) % 21U; } } else { CUtils::dump("D-Star, unknown data from modem", data, DSTAR_FRAME_LENGTH_BYTES + 1U); @@ -601,7 +646,7 @@ void CDStarControl::writeNetwork() if (!m_enabled) return; - if (m_rfState == RS_RF_AUDIO && m_netState == RS_NET_IDLE) + if (((m_rfState == RS_RF_AUDIO) || (m_rfState == RS_RF_DATA)) && (m_netState == RS_NET_IDLE)) return; m_networkWatchdog.start(); @@ -666,12 +711,9 @@ void CDStarControl::writeNetwork() LogMessage("D-Star, received network header from %8.8s/%4.4s to %8.8s", my1, my2, your); } - // Something just above here introduces a large delay forcing erroneous(?) insertion of silence packets. - // Starting the elapsed timer here instead of the commented out position above solves that. m_elapsed.start(); - } else if (type == TAG_EOT) { - if (m_netState != RS_NET_AUDIO) + if ((m_netState != RS_NET_AUDIO) && (m_netState != RS_NET_DATA)) return; writeQueueEOTNet(); @@ -695,48 +737,96 @@ void CDStarControl::writeNetwork() writeEndNet(); } else if (type == TAG_DATA) { - if (m_netState != RS_NET_AUDIO) - return; + if ((m_netState == RS_NET_AUDIO) || (m_netState == RS_NET_DATA)) { + unsigned char n = data[1U]; - unsigned int errors = 0U; - unsigned char n = data[1U]; + // 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) { + m_netSlowData.start(); + } else { + m_netSlowData.peakSlowData(data + 1U, n); - if (!m_netHeader.isDataPacket()) - errors = m_fec.regenerateDStar(data + 2U); - - blankDTMF(data + 2U); - - data[1U] = TAG_DATA; - - // Insert silence and reject if in the past - bool ret = insertSilence(data + 1U, n); - if (!ret) - return; - - m_netErrs += errors; - m_netBits += 48U; - - m_netN = n; - - // Regenerate the sync - if (n == 0U) { - CSync::addDStarSync(data + 2U); - m_netSlowData.start(); + if (m_netState == RS_NET_AUDIO) { + unsigned char type = m_netSlowData.getType(); + if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_BEGIN) { + LogMessage("D-Star, starting fast data mode"); + m_netState = RS_NET_DATA; + } + } + } } - if (n != 0U) { - const unsigned char* text = m_netSlowData.addText(data + 2U); - if (text != NULL) - LogMessage("D-Star, network slow data text = \"%s\"", text); - } + if (m_netState == RS_NET_AUDIO) { + unsigned char n = data[1U]; - m_packetTimer.start(); - m_netFrames++; + unsigned int errors = 0U; + if (::memcmp(data + 2U, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) != 0) { + errors = m_fec.regenerateDStar(data + 2U); + blankDTMF(data + 2U); + } + + data[1U] = TAG_DATA; + + // Insert silence and reject if in the past + bool ret = insertSilence(data + 1U, n); + if (!ret) + return; + + m_netErrs += errors; + m_netBits += 48U; + + m_netN = n; + + // Regenerate the sync + if (m_netN == 0U) { + CSync::addDStarSync(data + 2U); + m_netSlowData.start(); + } else { + const unsigned char* text = m_netSlowData.addText(data + 2U, m_netN); + if (text != NULL) + LogMessage("D-Star, network slow data text = \"%s\"", text); + } + + m_packetTimer.start(); + m_netFrames++; #if defined(DUMP_DSTAR) - writeFile(data + 1U, length - 1U); + writeFile(data + 1U, length - 1U); #endif - writeQueueDataNet(data + 1U); + writeQueueDataNet(data + 1U); + } + + if (m_netState == RS_NET_DATA) { + m_netN = data[1U]; + + data[1U] = TAG_DATA; + + m_netBits += 48U; + + // Regenerate the sync + if (m_netN == 0U) { + CSync::addDStarSync(data + 2U); + m_netSlowData.start(); + } else { + m_netSlowData.peakSlowData(data + 2U, m_netN); + bool complete = m_netSlowData.isComplete(); + if (complete) { + unsigned char type = m_netSlowData.getType(); + if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_END) { + LogMessage("D-Star, leaving fast data mode"); + m_netState = RS_NET_AUDIO; + } + } + } + + m_packetTimer.start(); + m_netFrames++; + +#if defined(DUMP_DSTAR) + writeFile(data + 1U, length - 1U); +#endif + writeQueueDataNet(data + 1U); + } } else { CUtils::dump("D-Star, unknown data from network", data, DSTAR_FRAME_LENGTH_BYTES + 1U); } diff --git a/DStarDefines.h b/DStarDefines.h index 6ac7f06..d7caeb0 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -44,14 +44,14 @@ const unsigned int DSTAR_DATA_FRAME_LENGTH_BYTES = 3U; const unsigned int DSTAR_LONG_CALLSIGN_LENGTH = 8U; const unsigned int DSTAR_SHORT_CALLSIGN_LENGTH = 4U; -const unsigned char DSTAR_SLOW_DATA_TYPE_MASK = 0xF0U; -const unsigned char DSTAR_SLOW_DATA_TYPE_GPSDATA = 0x30U; -const unsigned char DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U; -const unsigned char DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U; -const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA01 = 0x80U; -const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA16 = 0x90U; -const unsigned char DSTAR_SLOW_DATA_TYPE_SQUELCH = 0xC0U; -const unsigned char DSTAR_SLOW_DATA_LENGTH_MASK = 0x0FU; +const unsigned char DSTAR_SLOW_DATA_TYPE_MASK = 0xF0U; +const unsigned char DSTAR_SLOW_DATA_TYPE_GPSDATA = 0x30U; +const unsigned char DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U; +const unsigned char DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U; +const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA_END = 0x80U; +const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA_BEGIN = 0x90U; +const unsigned char DSTAR_SLOW_DATA_TYPE_SQUELCH = 0xC0U; +const unsigned char DSTAR_SLOW_DATA_LENGTH_MASK = 0x0FU; // Data Frames are always scrambled using the first three bytes of // DSTAR_SCRAMBLER_BYTES, and Voice Frames are scrambled with all nine diff --git a/DStarSlowData.cpp b/DStarSlowData.cpp index 5f11b70..9aec2e6 100644 --- a/DStarSlowData.cpp +++ b/DStarSlowData.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2023 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2023,2025 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 @@ -33,7 +33,8 @@ m_buffer(NULL), m_text(NULL), m_textPtr(0U), m_textBits(0x00U), -m_state(SDD_FIRST) +m_type(0x00U), +m_complete(false) { m_header = new unsigned char[50U]; // DSTAR_HEADER_LENGTH_BYTES m_buffer = new unsigned char[DSTAR_DATA_FRAME_LENGTH_BYTES * 2U]; @@ -47,24 +48,33 @@ CDStarSlowData::~CDStarSlowData() delete[] m_text; } -CDStarHeader* CDStarSlowData::addHeader(const unsigned char* data) +void CDStarSlowData::peakSlowData(const unsigned char* data, unsigned int n) { assert(data != NULL); - switch (m_state) { - case SDD_FIRST: + if ((n % 2U) == 0U) { + m_type = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U]; + m_complete = false; + } else { + m_complete = true; + } +} + +CDStarHeader* CDStarSlowData::addHeader(const unsigned char* data, unsigned int n) +{ + assert(data != NULL); + + if ((n % 2U) == 0U) { + m_type = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U]; m_buffer[0U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U]; m_buffer[1U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U]; m_buffer[2U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U]; - m_state = SDD_SECOND; - return NULL; - - case SDD_SECOND: + m_complete = false; + } else { m_buffer[3U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U]; m_buffer[4U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U]; m_buffer[5U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U]; - m_state = SDD_FIRST; - break; + m_complete = true; } if ((m_buffer[0U] & DSTAR_SLOW_DATA_TYPE_MASK) != DSTAR_SLOW_DATA_TYPE_HEADER) @@ -95,24 +105,21 @@ CDStarHeader* CDStarSlowData::addHeader(const unsigned char* data) return new CDStarHeader(m_header); } -const unsigned char* CDStarSlowData::addText(const unsigned char* data) +const unsigned char* CDStarSlowData::addText(const unsigned char* data, unsigned int n) { assert(data != NULL); - switch (m_state) { - case SDD_FIRST: + if ((n % 2U) == 0U) { + m_type = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U]; m_buffer[0U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U]; m_buffer[1U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U]; m_buffer[2U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U]; - m_state = SDD_SECOND; - return NULL; - - case SDD_SECOND: + m_complete = false; + } else { m_buffer[3U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U]; m_buffer[4U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U]; m_buffer[5U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U]; - m_state = SDD_FIRST; - break; + m_complete = true; } switch (m_buffer[0U]) { @@ -160,7 +167,7 @@ const unsigned char* CDStarSlowData::addText(const unsigned char* data) if (m_textBits != 0x0FU) return NULL; - CUtils::dump(1U, "D-STar slow data text", m_text, 20U); + CUtils::dump(1U, "D-Star slow data text", m_text, 20U); m_textBits = 0x00U; @@ -172,14 +179,16 @@ void CDStarSlowData::start() ::memset(m_header, 0x00U, DSTAR_HEADER_LENGTH_BYTES); m_ptr = 0U; - m_state = SDD_FIRST; + m_type = 0x00U; + m_complete = false; m_textBits = 0x00U; } void CDStarSlowData::reset() { m_ptr = 0U; - m_state = SDD_FIRST; + m_type = 0x00U; + m_complete = false; m_textBits = 0x00U; } @@ -233,3 +242,13 @@ void CDStarSlowData::getSlowData(unsigned char* data) data[2U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[2U]; } } + +unsigned char CDStarSlowData::getType() const +{ + return m_type & DSTAR_SLOW_DATA_TYPE_MASK; +} + +bool CDStarSlowData::isComplete() const +{ + return m_complete; +} diff --git a/DStarSlowData.h b/DStarSlowData.h index eaedf45..ee529d5 100644 --- a/DStarSlowData.h +++ b/DStarSlowData.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2023 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2023,2025 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 @@ -26,9 +26,14 @@ public: CDStarSlowData(); ~CDStarSlowData(); - CDStarHeader* addHeader(const unsigned char* data); + void peakSlowData(const unsigned char* data, unsigned int n); - const unsigned char* addText(const unsigned char* data); + CDStarHeader* addHeader(const unsigned char* data, unsigned int n); + + const unsigned char* addText(const unsigned char* data, unsigned int n); + + unsigned char getType() const; + bool isComplete() const; void start(); void reset(); @@ -43,13 +48,8 @@ private: unsigned char* m_text; unsigned int m_textPtr; unsigned char m_textBits; - - enum SDD_STATE { - SDD_FIRST, - SDD_SECOND - }; - - SDD_STATE m_state; + unsigned char m_type; + bool m_complete; }; #endif diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 7501213..f420281 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -541,6 +541,7 @@ int CMMDVMHost::run() m_dmrRFModeHang = m_conf.getDMRModeHang(); dmrBeacons = m_conf.getDMRBeacons(); DMR_OVCM_TYPES ovcm = m_conf.getDMROVCM(); + bool protect = m_conf.getDMRProtect(); if (txHang > m_dmrRFModeHang) txHang = m_dmrRFModeHang; @@ -584,6 +585,9 @@ int CMMDVMHost::run() else if (ovcm == DMR_OVCM_FORCE_OFF) LogInfo(" OVCM: off (forced)"); + if (protect) + LogInfo(" Protect: yes"); + switch (dmrBeacons) { case DMR_BEACONS_NETWORK: { unsigned int dmrBeaconDuration = m_conf.getDMRBeaconDuration(); @@ -613,7 +617,7 @@ int CMMDVMHost::run() break; } - m_dmr = new CDMRControl(id, colorCode, callHang, selfOnly, embeddedLCOnly, dumpTAData, prefixes, blackList, whiteList, slot1TGWhiteList, slot2TGWhiteList, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, m_dmrLookup, rssi, jitter, ovcm); + m_dmr = new CDMRControl(id, colorCode, callHang, selfOnly, embeddedLCOnly, dumpTAData, prefixes, blackList, whiteList, slot1TGWhiteList, slot2TGWhiteList, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, m_dmrLookup, rssi, jitter, ovcm, protect); m_dmrTXTimer.setTimeout(txHang); } diff --git a/Version.h b/Version.h index 7fac374..bb8d3e3 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20250227"; +const char* VERSION = "20250312"; #endif