From 8b5a7ae7ec42d406c3bdad429a40e3b5c07a2070 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Wed, 24 Nov 2021 22:25:17 +0000 Subject: [PATCH] add experimental support for DMR TIII (note this will not accept registrations or grant requests); --- config.yml | 4 + dmr/Control.cpp | 53 +++++++- dmr/Control.h | 9 +- dmr/ControlPacket.cpp | 64 +++++---- dmr/ControlPacket.h | 2 + dmr/DMRDefines.h | 5 + dmr/Slot.cpp | 113 +++++++++++++++- dmr/Slot.h | 16 +++ dmr/lc/CSBK.cpp | 292 +++++++++++++++++++++++++----------------- dmr/lc/CSBK.h | 3 + host/Host.cpp | 118 +++++++++++++---- host/Host.h | 2 + p25/Control.cpp | 8 +- p25/Control.h | 2 +- p25/TrunkPacket.cpp | 2 +- p25/VoicePacket.cpp | 2 +- 16 files changed, 518 insertions(+), 177 deletions(-) diff --git a/config.yml b/config.yml index 9fc5e862..46b0a864 100644 --- a/config.yml +++ b/config.yml @@ -30,6 +30,10 @@ protocols: enable: false interval: 60 duration: 3 + control: + dedicated: false + enable: false + slot: 1 embeddedLCOnly: false dumpTAData: true dumpDataPacket: false diff --git a/dmr/Control.cpp b/dmr/Control.cpp index c29e8a8a..710b0b89 100644 --- a/dmr/Control.cpp +++ b/dmr/Control.cpp @@ -73,6 +73,8 @@ Control::Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool m_idenTable(idenTable), m_ridLookup(ridLookup), m_tidLookup(tidLookup), + m_tsccSlotNo(0U), + m_ccRunning(false), m_dumpCSBKData(dumpCSBKData), m_verbose(verbose), m_debug(debug) @@ -107,12 +109,60 @@ Control::~Control() /// /// /// -void Control::setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo) +/// +void Control::setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions) { yaml::Node systemConf = conf["system"]; yaml::Node dmrProtocol = conf["protocols"]["dmr"]; Slot::setSiteData(netId, siteId, channelId, channelNo); + + yaml::Node control = dmrProtocol["control"]; + bool enableTSCC = control["enable"].as(false); + bool dedicatedTSCC = false; + if (enableTSCC) { + dedicatedTSCC = control["dedicated"].as(false); + } + else { + dedicatedTSCC = false; + } + + m_tsccSlotNo = (uint8_t)control["slot"].as(0U); + switch (m_tsccSlotNo) { + case 1U: + m_slot1->setTSCC(enableTSCC, dedicatedTSCC); + break; + case 2U: + m_slot2->setTSCC(enableTSCC, dedicatedTSCC); + break; + default: + LogError(LOG_NET, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo); + break; + } + + if (printOptions) { + LogInfo(" TSCC Slot: %u", m_tsccSlotNo); + } +} + +/// +/// Sets a flag indicating whether the DMR control channel is running. +/// +/// +void Control::setCCRunning(bool ccRunning) +{ + m_ccRunning = ccRunning; + switch (m_tsccSlotNo) { + case 1U: + m_slot1->setCCRunning(ccRunning); + break; + case 2U: + m_slot2->setCCRunning(ccRunning); + break; + default: + LogError(LOG_NET, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo); + break; + } } /// @@ -151,6 +201,7 @@ bool Control::processWakeup(const uint8_t* data) if (m_verbose) { LogMessage(LOG_RF, "DMR, CSBKO_BSDWNACT, srcId = %u", srcId); } + return true; } diff --git a/dmr/Control.h b/dmr/Control.h index d04d1904..2e66bb8c 100644 --- a/dmr/Control.h +++ b/dmr/Control.h @@ -66,7 +66,11 @@ namespace dmr ~Control(); /// Helper to set DMR configuration options. - void setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo); + void setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions); + /// Gets a flag indicating whether the DMR control channel is running. + bool getCCRunning() { return m_ccRunning; } + /// Sets a flag indicating whether the DMR control channel is running. + void setCCRunning(bool ccRunning); /// Helper to process wakeup frames from the RF interface. bool processWakeup(const uint8_t* data); @@ -104,6 +108,9 @@ namespace dmr lookups::RadioIdLookup* m_ridLookup; lookups::TalkgroupIdLookup* m_tidLookup; + uint8_t m_tsccSlotNo; + bool m_ccRunning; + bool m_dumpCSBKData; bool m_verbose; bool m_debug; diff --git a/dmr/ControlPacket.cpp b/dmr/ControlPacket.cpp index 34e6a1f2..94c6b7ed 100644 --- a/dmr/ControlPacket.cpp +++ b/dmr/ControlPacket.cpp @@ -503,18 +503,16 @@ ControlPacket::~ControlPacket() } /// -/// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface. +/// Helper to write a TSCC Aloha broadcast packet on the RF interface. /// -/// -/// -void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd) +void ControlPacket::writeRF_TSCC_Aloha() { - if (m_verbose) { - LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), BCAST_ANNC_ANN_WD_TSCC (Announce-WD TSCC Channel), channelNo = %u, annWd = %u", - m_slot->m_slotNo, channelNo, annWd); + if (m_debug) { + LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_ALOHA (Aloha)", m_slot->m_slotNo); } - m_slot->m_rfSeqNo = 0U; + uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; + ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); SlotType slotType; slotType.setColorCode(m_slot->m_colorCode); @@ -522,19 +520,9 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd) lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData); csbk.setVerbose(m_dumpCSBKData); - csbk.setCSBKO(CSBKO_BROADCAST); + csbk.setCSBKO(CSBKO_ALOHA); csbk.setFID(FID_ETSI); - csbk.setAnncType(BCAST_ANNC_ANN_WD_TSCC); - csbk.setLogicalCh1(channelNo); - csbk.setAnnWdCh1(annWd); - - uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; - ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); - - // MBC frame 1 - csbk.setLastBlock(false); - // Regenerate the CSBK data csbk.encode(data + 2U); @@ -544,17 +532,45 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd) // Convert the Data Sync to be from the BS or MS as needed Sync::addDMRDataSync(data + 2U, m_slot->m_duplex); + m_slot->m_rfSeqNo = 0U; + data[0U] = TAG_DATA; data[1U] = 0x00U; if (m_slot->m_duplex) m_slot->writeQueueRF(data); +} - ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); +/// +/// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface. +/// +/// +/// +void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd) +{ + if (m_debug) { + LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), BCAST_ANNC_ANN_WD_TSCC (Announce-WD TSCC Channel), channelNo = %u, annWd = %u", + m_slot->m_slotNo, channelNo, annWd); + } - // MBC frame 2 - csbk.setLastBlock(false); - csbk.setCdef(true); + m_slot->m_rfSeqNo = 0U; + + SlotType slotType; + slotType.setColorCode(m_slot->m_colorCode); + slotType.setDataType(DT_CSBK); + + lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData); + csbk.setCdef(false); + csbk.setVerbose(m_dumpCSBKData); + csbk.setCSBKO(CSBKO_BROADCAST); + csbk.setFID(FID_ETSI); + + csbk.setAnncType(BCAST_ANNC_ANN_WD_TSCC); + csbk.setLogicalCh1(channelNo); + csbk.setAnnWdCh1(annWd); + + uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; + ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); // Regenerate the CSBK data csbk.encode(data + 2U); @@ -577,7 +593,7 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd) /// void ControlPacket::writeRF_TSCC_Bcast_Sys_Parm() { - if (m_verbose) { + if (m_debug) { LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), BCAST_ANNC_SITE_PARMS (Announce Site Parms)", m_slot->m_slotNo); } diff --git a/dmr/ControlPacket.h b/dmr/ControlPacket.h index 742b5889..806adee1 100644 --- a/dmr/ControlPacket.h +++ b/dmr/ControlPacket.h @@ -83,6 +83,8 @@ namespace dmr /// Finalizes a instance of the DataPacket class. ~ControlPacket(); + /// Helper to write a TSCC Aloha broadcast packet on the RF interface. + void writeRF_TSCC_Aloha(); /// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface. void writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd); /// Helper to write a TSCC Sys_Parm broadcast packet on the RF interface. diff --git a/dmr/DMRDefines.h b/dmr/DMRDefines.h index c472c86e..22733e5d 100644 --- a/dmr/DMRDefines.h +++ b/dmr/DMRDefines.h @@ -127,6 +127,8 @@ namespace dmr const uint8_t DMR_ALOHA_VER_151 = 0x00U; const uint8_t DMR_CHNULL = 0x00U; + + const uint16_t DMR_LOGICAL_CH_ABSOLUTE = 0xFFFU; // PDU Data Formats const uint8_t DPF_UDT = 0x00U; @@ -235,6 +237,9 @@ namespace dmr const uint8_t CSBKO_EXT_FNCT = 0x24U; // (DMRA) EXT FNCT - Extended Function const uint8_t CSBKO_NACK_RSP = 0x26U; // NACK RSP - Negative Acknowledgement Response const uint8_t CSBKO_BROADCAST = 0x28U; // BCAST - Announcement PDUs + const uint8_t CSBKO_PV_GRANT = 0x30U; // PV_GRANT - Private Voice Channel Grant + const uint8_t CSBKO_TV_GRANT = 0x31U; // TV_GRANT - Talkgroup Voice Channel Grant + const uint8_t CSBKO_BTV_GRANT = 0x32U; // BTV_GRANT - Broadcast Talkgroup Voice Channel Grant const uint8_t CSBKO_BSDWNACT = 0x38U; // BS DWN ACT - BS Outbound Activation const uint8_t CSBKO_PRECCSBK = 0x3DU; // PRE CSBK - Preamble CSBK diff --git a/dmr/Slot.cpp b/dmr/Slot.cpp index 8a6829c4..a200c93e 100644 --- a/dmr/Slot.cpp +++ b/dmr/Slot.cpp @@ -56,6 +56,7 @@ const uint16_t TSCC_MAX_CNT = 511U; uint32_t Slot::m_colorCode = 0U; SiteData Slot::m_siteData = SiteData(); +uint32_t Slot::m_channelNo = 0U; bool Slot::m_embeddedLCOnly = false; bool Slot::m_dumpTAData = true; @@ -141,6 +142,9 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz m_minRSSI(0U), m_aveRSSI(0U), m_rssiCount(0U), + m_ccSeq(0U), + m_ccRunning(false), + m_enableTSCC(false), m_dumpCSBKData(dumpCSBKData), m_verbose(verbose), m_debug(debug) @@ -162,6 +166,15 @@ Slot::~Slot() delete m_control; } +/// +/// Sets a flag indicating whether the DMR control channel is running. +/// +/// +void Slot::setCCRunning(bool ccRunning) +{ + m_ccRunning = ccRunning; +} + /// /// Process DMR data frame from the RF interface. /// @@ -260,6 +273,24 @@ bool Slot::processFrame(uint8_t *data, uint32_t len) if ((dataSync || voiceSync) && m_rfState != RS_RF_LISTENING) m_rfTGHang.start(); + // write and process TSCC CSBKs and short LC + if (m_enableTSCC && m_dedicatedTSCC) + { + if (dataSync) { + uint8_t dataType = data[1U] & 0x0FU; + + switch (dataType) + { + case DT_CSBK: + return m_control->process(data, len); + default: + break; + } + } + + return false; + } + if (dataSync) { uint8_t dataType = data[1U] & 0x0FU; @@ -369,12 +400,30 @@ void Slot::clock() } } - // increment the TSCC counter on every slot 1 clock - if (m_slotNo == 1U) { + if (m_enableTSCC) + { + // increment the TSCC counter on every slot 1 clock m_tsccCnt++; if (m_tsccCnt == TSCC_MAX_CNT) { m_tsccCnt = 0U; } + + if (m_ccSeq == 3U) { + m_ccSeq = 0U; + } + + if (m_dedicatedTSCC) { + setShortLC_TSCC(m_siteData, m_tsccCnt); + writeRF_ControlData(m_tsccCnt, m_ccSeq); + } + else { + if (m_ccRunning) { + setShortLC_TSCC(m_siteData, m_tsccCnt); + writeRF_ControlData(m_tsccCnt, m_ccSeq); + } + } + + m_ccSeq++; } m_rfTimeoutTimer.clock(ms); @@ -450,6 +499,17 @@ void Slot::setDebugVerbose(bool debug, bool verbose) m_verbose = m_voice->m_verbose = m_data->m_verbose = verbose = m_control->m_verbose; } +/// +/// Helper to enable and configure TSCC support for this slot. +/// +/// Flag indicating whether DMR TSCC is enabled on this slot. +/// Flag indicating whether DMR TSCC is dedicated on this slot. +void Slot::setTSCC(bool enable, bool dedicated) +{ + m_enableTSCC = enable; + m_dedicatedTSCC = dedicated; +} + /// /// Helper to initialize the DMR slot processor. /// @@ -521,6 +581,7 @@ void Slot::init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool void Slot::setSiteData(uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo) { m_siteData = SiteData(SITE_MODEL_SMALL, netId, siteId, 3U, false); + m_channelNo = channelNo; std::vector entries = m_idenTable->list(); for (auto it = entries.begin(); it != entries.end(); ++it) { @@ -650,7 +711,10 @@ void Slot::writeEndRF(bool writeEnd) m_rfState = RS_RF_LISTENING; if (m_netState == RS_NET_IDLE) { - setShortLC(m_slotNo, 0U); + if (m_enableTSCC) + setShortLC_TSCC(m_siteData, m_tsccCnt); + else + setShortLC(m_slotNo, 0U); } if (writeEnd) { @@ -765,6 +829,49 @@ void Slot::writeEndNet(bool writeEnd) m_netDataHeader = NULL; } +/// +/// Helper to write control channel packet data. +/// +/// +/// +void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n) +{ + uint8_t i = 0U, seqCnt = 0U; + + if (!m_enableTSCC) + return; + + // loop to generate 2 control sequences + if (frameCnt == 511U) { + seqCnt = 3U; + } + + do + { + if (m_debug) { + LogDebug(LOG_DMR, "writeRF_ControlData, frameCnt = %u, seq = %u", frameCnt, n); + } + + switch (n) + { + case 2: + m_control->writeRF_TSCC_Bcast_Ann_Wd(m_channelNo, true); + break; + case 1: + m_control->writeRF_TSCC_Aloha(); + break; + case 0: + default: + m_control->writeRF_TSCC_Bcast_Sys_Parm(); + break; + } + + if (seqCnt > 0U) + n++; + i++; + } while (i <= seqCnt); +} + /// /// /// diff --git a/dmr/Slot.h b/dmr/Slot.h index eb2637df..24740677 100644 --- a/dmr/Slot.h +++ b/dmr/Slot.h @@ -71,6 +71,9 @@ namespace dmr /// Finalizes a instance of the Slot class. ~Slot(); + /// Sets a flag indicating whether the DMR control channel is running. + void setCCRunning(bool ccRunning); + /// Process a data frame from the RF interface. bool processFrame(uint8_t* data, uint32_t len); /// Get frame data from data ring buffer. @@ -88,6 +91,9 @@ namespace dmr /// Helper to change the debug and verbose state. void setDebugVerbose(bool debug, bool verbose); + /// Helper to enable and configure TSCC support for this slot. + void setTSCC(bool enable, bool dedicated); + /// Helper to initialize the slot processor. static void init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, @@ -150,6 +156,12 @@ namespace dmr uint32_t m_aveRSSI; uint32_t m_rssiCount; + uint8_t m_ccSeq; + bool m_ccRunning; + + bool m_enableTSCC; + bool m_dedicatedTSCC; + bool m_dumpCSBKData; bool m_verbose; bool m_debug; @@ -157,6 +169,7 @@ namespace dmr static uint32_t m_colorCode; static SiteData m_siteData; + static uint32_t m_channelNo; static bool m_embeddedLCOnly; static bool m_dumpTAData; @@ -206,6 +219,9 @@ namespace dmr /// Helper to write network end of frame data. void writeEndNet(bool writeEnd = false); + /// Helper to write control channel packet data. + void writeRF_ControlData(uint16_t frameCnt, uint8_t n); + /// Helper to set the DMR short LC. static void setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco = FLCO_GROUP, bool voice = true); /// Helper to set the DMR short LC for TSCC. diff --git a/dmr/lc/CSBK.cpp b/dmr/lc/CSBK.cpp index 1f18692c..f678247d 100644 --- a/dmr/lc/CSBK.cpp +++ b/dmr/lc/CSBK.cpp @@ -211,6 +211,9 @@ void CSBK::encode(uint8_t* bytes) if (!m_Cdef) { m_data[1U] = m_FID; // Feature ID } + else { + m_data[1U] = m_colorCode & 0x0FU; // Cdef uses Color Code + } switch (m_CSBKO) { case CSBKO_ACK_RSP: @@ -267,6 +270,175 @@ void CSBK::encode(uint8_t* bytes) m_data[9U] = (m_dstId >> 0) & 0xFFU; break; + /* Tier III */ + case CSBKO_ALOHA: + { + ulong64_t csbkValue = 0U; + csbkValue = (csbkValue << 2) + 0U; // Reserved + csbkValue = (csbkValue << 1) + ((m_siteTSSync) ? 1U : 0U); // Site Time Slot Synchronization + csbkValue = (csbkValue << 3) + DMR_ALOHA_VER_151; // DMR Spec. Version (1.5.1) + csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset + csbkValue = (csbkValue << 1) + ((m_siteData.netActive()) ? 1U : 0U); // Site Networked + csbkValue = (csbkValue << 5) + (m_alohaMask & 0x1FU); // MS Mask + csbkValue = (csbkValue << 2) + 0U; // Service Function + csbkValue = (csbkValue << 4) + 0U; // + csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration + csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number + csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity + csbkValue = (csbkValue << 24) + m_srcId; // Source ID + + // split value into bytes + m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); + m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); + m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); + m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); + m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); + m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); + m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); + m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); + } + break; + + case CSBKO_PV_GRANT: + { + ulong64_t csbkValue = 0U; + csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1 + csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number + csbkValue = (csbkValue << 1) + 0U; // Reserved + csbkValue = (csbkValue << 1) + 0U; // Emergency + csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset + csbkValue = (csbkValue << 24) + m_dstId; // Talkgroup ID + csbkValue = (csbkValue << 24) + m_srcId; // Source ID + + // split value into bytes + m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); + m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); + m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); + m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); + m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); + m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); + m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); + m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); + } + break; + + case CSBKO_TV_GRANT: + case CSBKO_BTV_GRANT: + { + ulong64_t csbkValue = 0U; + csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1 + csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number + csbkValue = (csbkValue << 1) + 0U; // Late Entry + csbkValue = (csbkValue << 1) + 0U; // Emergency + csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset + csbkValue = (csbkValue << 24) + m_dstId; // Talkgroup ID + csbkValue = (csbkValue << 24) + m_srcId; // Source ID + + // split value into bytes + m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); + m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); + m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); + m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); + m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); + m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); + m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); + m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); + } + break; + + case CSBKO_BROADCAST: + { + ulong64_t csbkValue = 0U; + if (!m_Cdef) { + csbkValue = m_anncType; // Announcement Type + } + + switch (m_anncType) + { + case BCAST_ANNC_ANN_WD_TSCC: + { + // Broadcast Parms 1 + csbkValue = (csbkValue << 4) + 0U; // Reserved + csbkValue = (csbkValue << 4) + (m_colorCode & 0x0FU); // Color Code 1 + csbkValue = (csbkValue << 4) + (m_colorCode & 0x0FU); // Color Code 2 + csbkValue = (csbkValue << 1) + ((m_annWdCh1) ? 1U : 0U); // Announce/Withdraw Channel 1 + csbkValue = (csbkValue << 1) + ((m_annWdCh2) ? 1U : 0U); // Announce/Withdraw Channel 2 + + csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration + csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number + csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity + + // Broadcast Parms 2 + csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel 1 + csbkValue = (csbkValue << 12) + (m_logicalCh2 & 0xFFFU); // Logical Channel 2 + } + break; + case BCAST_ANNC_CHAN_FREQ: + { + uint32_t calcSpace = (uint32_t)(m_siteIdenEntry.chSpaceKhz() / 0.125); + float calcTxOffset = m_siteIdenEntry.txOffsetMhz() * 1000000; + const uint32_t multiple = 100000; + + // calculate Rx frequency + uint32_t rxFrequency = (uint32_t)((m_siteIdenEntry.baseFrequency() + ((calcSpace * 125) * m_logicalCh1)) + calcTxOffset); + + // generate frequency in mhz + uint32_t rxFreqMhz = rxFrequency + multiple / 2; + rxFreqMhz -= rxFreqMhz % multiple; + rxFreqMhz /= multiple * 10; + + // generate khz offset + uint32_t rxFreqKhz = rxFrequency - (rxFreqMhz * 1000000); + + // calculate Tx Frequency + uint32_t txFrequency = (uint32_t)((m_siteIdenEntry.baseFrequency() + ((calcSpace * 125) * m_logicalCh1))); + + // generate frequency in mhz + uint32_t txFreqMhz = txFrequency + multiple / 2; + txFreqMhz -= txFreqMhz % multiple; + txFreqMhz /= multiple * 10; + + // generate khz offset + uint32_t txFreqKhz = txFrequency - (txFreqMhz * 1000000); + + csbkValue = 0U; // Cdef Type (always 0 for ANN_WD_TSCC) + csbkValue = (csbkValue << 2) + 0U; // Reserved + csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel + csbkValue = (csbkValue << 10) + (txFreqMhz & 0x7FFU); // Transmit Freq Mhz + csbkValue = (csbkValue << 13) + (txFreqKhz & 0x3FFFU); // Transmit Freq Offset Khz + csbkValue = (csbkValue << 10) + (rxFreqMhz & 0x7FFU); // Receive Freq Mhz + csbkValue = (csbkValue << 13) + (rxFreqKhz & 0x3FFFU); // Receive Freq Khz + } + break; + case BCAST_ANNC_SITE_PARMS: + { + // Broadcast Parms 1 + csbkValue = (csbkValue << 14) + m_siteData.systemIdentity(true); // Site Identity (Broadcast Parms 1) + + csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration + csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number + csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity + + // Broadcast Parms 2 + csbkValue = (csbkValue << 1) + 0U; // Roaming TG Subscription/Attach + csbkValue = (csbkValue << 1) + ((m_hibernating) ? 1U : 0U); // TSCC Hibernating + csbkValue = (csbkValue << 22) + 0U; // Broadcast Parms 2 (Reserved) + } + break; + } + + // split value into bytes + m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); + m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); + m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); + m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); + m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); + m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); + m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); + m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); + } + break; + default: if (m_GI) { m_data[2U] |= 0x40U; // Group or Individual @@ -286,125 +458,6 @@ void CSBK::encode(uint8_t* bytes) m_data[8U] = (m_srcId >> 8) & 0xFFU; m_data[9U] = (m_srcId >> 0) & 0xFFU; break; - - /* Tier III */ - case CSBKO_ALOHA: - { - ulong64_t csbkValue = 0U; - csbkValue = (csbkValue << 2) + 0U; // Reserved - csbkValue = (csbkValue << 1) + ((m_siteTSSync) ? 1U : 0U); // Site Time Slot Synchronization - csbkValue = (csbkValue << 3) + DMR_ALOHA_VER_151; // DMR Spec. Version (1.5.1) - csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset - csbkValue = (csbkValue << 1) + ((m_siteData.netActive()) ? 1U : 0U); // Site Networked - csbkValue = (csbkValue << 5) + (m_alohaMask & 0x1FU); // MS Mask - csbkValue = (csbkValue << 2) + 0U; // Service Function - csbkValue = (csbkValue << 4) + 0U; // - csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration - csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number - csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity - csbkValue = (csbkValue << 24) + m_srcId; // Source ID - - // split value into bytes - m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); - m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); - m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); - m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); - m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); - m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); - m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); - m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); - break; - } - break; - case CSBKO_BROADCAST: - { - ulong64_t csbkValue = 0U; - if (!m_Cdef) { - csbkValue = m_anncType; // Announcement Type - } - - switch (m_anncType) - { - case BCAST_ANNC_ANN_WD_TSCC: - if (!m_Cdef) { - // Broadcast Parms 1 - csbkValue = (csbkValue << 4) + 0U; // Reserved - csbkValue = (csbkValue << 4) + (m_colorCode & 0x0FU); // Color Code 1 - csbkValue = (csbkValue << 4) + (m_colorCode & 0x0FU); // Color Code 2 - csbkValue = (csbkValue << 1) + ((m_annWdCh1) ? 1U : 0U); // Announce/Withdraw Channel 1 - csbkValue = (csbkValue << 1) + ((m_annWdCh2) ? 1U : 0U); // Announce/Withdraw Channel 2 - - csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration - csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number - csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity - - // Broadcast Parms 2 - csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel 1 - csbkValue = (csbkValue << 12) + (m_logicalCh2 & 0xFFFU); // Logical Channel 2 - } - else { - uint32_t calcSpace = (uint32_t)(m_siteIdenEntry.chSpaceKhz() / 0.125); - float calcTxOffset = m_siteIdenEntry.txOffsetMhz() * 1000000; - const uint32_t multiple = 100000; - - // calculate Rx frequency - uint32_t rxFrequency = (uint32_t)((m_siteIdenEntry.baseFrequency() + ((calcSpace * 125) * m_logicalCh1)) + calcTxOffset); - - // generate frequency in mhz - uint32_t rxFreqMhz = rxFrequency + multiple / 2; - rxFreqMhz -= rxFreqMhz % multiple; - rxFreqMhz /= multiple * 10; - - // generate khz offset - uint32_t rxFreqKhz = rxFrequency - (rxFreqMhz * 1000000); - - // calculate Tx Frequency - uint32_t txFrequency = (uint32_t)((m_siteIdenEntry.baseFrequency() + ((calcSpace * 125) * m_logicalCh1))); - - // generate frequency in mhz - uint32_t txFreqMhz = txFrequency + multiple / 2; - txFreqMhz -= txFreqMhz % multiple; - txFreqMhz /= multiple * 10; - - // generate khz offset - uint32_t txFreqKhz = txFrequency - (txFreqMhz * 1000000); - - csbkValue = (csbkValue << 8) + 0U; // Reserved - csbkValue = (csbkValue << 4) + 0U; // Cdef Type (always 0 for ANN_WD_TSCC) - csbkValue = (csbkValue << 2) + 0U; // Reserved - csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel - csbkValue = (csbkValue << 10) + txFreqMhz; // Transmit Freq Mhz - csbkValue = (csbkValue << 13) + txFreqKhz; // Transmit Freq Offset Khz - csbkValue = (csbkValue << 10) + rxFreqMhz; // Receive Freq Mhz - csbkValue = (csbkValue << 13) + rxFreqKhz; // Receive Freq Khz - } - break; - case BCAST_ANNC_SITE_PARMS: - // Broadcast Parms 1 - csbkValue = (csbkValue << 14) + m_siteData.systemIdentity(true); // Site Identity (Broadcast Parms 1) - - csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration - csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number - csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity - - // Broadcast Parms 2 - csbkValue = (csbkValue << 1) + 0U; // Roaming TG Subscription/Attach - csbkValue = (csbkValue << 1) + ((m_hibernating) ? 1U : 0U); // TSCC Hibernating - csbkValue = (csbkValue << 22) + 0U; // Broadcast Parms 2 (Reserved) - break; - } - - // split value into bytes - m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); - m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); - m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); - m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); - m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); - m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); - m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); - m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); - } - break; } m_data[10U] ^= CSBK_CRC_MASK[0U]; @@ -455,6 +508,7 @@ CSBK::CSBK(SiteData siteData) : m_logicalCh1(DMR_CHNULL), m_annWdCh2(false), m_logicalCh2(DMR_CHNULL), + m_slotNo(0U), m_siteTSSync(false), m_siteOffsetTiming(false), m_alohaMask(0U), diff --git a/dmr/lc/CSBK.h b/dmr/lc/CSBK.h index 05dfffe6..7f98ebfe 100644 --- a/dmr/lc/CSBK.h +++ b/dmr/lc/CSBK.h @@ -125,6 +125,9 @@ namespace dmr /// Broadcast Logical Channel ID 2. __PROPERTY(uint16_t, logicalCh2, LogicalCh2); + /// Logical Channel Slot Number. + __PROPERTY(uint8_t, slotNo, SlotNo); + /// Aloha Site Time Slot Synchronization. __PROPERTY(bool, siteTSSync, SiteTSSync); /// Aloha site users offset timing. diff --git a/host/Host.cpp b/host/Host.cpp index 82fab4ec..27484b7c 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -91,6 +91,7 @@ Host::Host(const std::string& confFile) : m_dmrEnabled(false), m_p25Enabled(false), m_p25CtrlChannel(false), + m_dmrCtrlChannel(false), m_duplex(false), m_fixedMode(false), m_timeout(180U), @@ -108,9 +109,13 @@ Host::Host(const std::string& confFile) : m_rxFrequency(0U), m_txFrequency(0U), m_channelId(0U), + m_channelNo(0U), m_idenTable(NULL), m_ridLookup(NULL), m_tidLookup(NULL), + m_dmrBeacons(false), + m_dmrTSCCData(false), + m_controlData(false), m_remoteControl(NULL) { UDPSocket::startup(); @@ -338,6 +343,8 @@ int Host::run() if (m_dmrEnabled) { yaml::Node dmrProtocol = protocolConf["dmr"]; m_dmrBeacons = dmrProtocol["beacons"]["enable"].as(false); + m_dmrTSCCData = dmrProtocol["control"]["enable"].as(false); + bool dmrCtrlChannel = dmrProtocol["control"]["dedicated"].as(false); bool embeddedLCOnly = dmrProtocol["embeddedLCOnly"].as(false); bool dmrDumpDataPacket = dmrProtocol["dumpDataPacket"].as(false); bool dmrRepeatDataPacket = dmrProtocol["repeatDataPacket"].as(true); @@ -384,10 +391,19 @@ int Host::run() g_fireDMRBeacon = true; } + LogInfo(" TSCC Control: %s", m_dmrTSCCData ? "yes" : "no"); + + if (m_dmrTSCCData) { + LogInfo(" TSCC Control Channel: %s", dmrCtrlChannel ? "yes" : "no"); + if (dmrCtrlChannel) { + m_dmrCtrlChannel = dmrCtrlChannel; + } + } + dmr = new dmr::Control(m_dmrColorCode, callHang, dmrQueueSize, embeddedLCOnly, dumpTAData, m_timeout, m_rfTalkgroupHang, m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, jitter, dmrDumpDataPacket, dmrRepeatDataPacket, dmrDumpCsbkData, dmrDebug, dmrVerbose); - dmr->setOptions(m_conf, m_dmrNetId, m_siteId, m_channelId, m_channelNo); + dmr->setOptions(m_conf, m_dmrNetId, m_siteId, m_channelId, m_channelNo, true); m_dmrTXTimer.setTimeout(txHang); @@ -479,16 +495,42 @@ int Host::run() g_killed = true; } + if (m_fixedMode && m_dmrEnabled && m_p25Enabled) { + ::LogError(LOG_HOST, "Cannot have DMR enabled and P25 enabled when using fixed state! Choose one protocol for fixed state operation."); + g_killed = true; + } + + // P25 control channel checks if (m_dmrEnabled && m_p25CtrlChannel) { ::LogError(LOG_HOST, "Cannot have DMR enabled when using dedicated P25 control!"); g_killed = true; } - if (m_fixedMode && m_dmrEnabled && m_p25Enabled) { - ::LogError(LOG_HOST, "Cannot have DMR enabled and P25 enabled when using fixed state! Choose one protocol for fixed state operation."); + if (!m_fixedMode && m_p25CtrlChannel) { + ::LogWarning(LOG_HOST, "Fixed mode should be enabled when using dedicated P25 control!"); + } + + if (!m_duplex && m_controlData) { + ::LogError(LOG_HOST, "Cannot have P25 control and simplex mode at the same time."); + g_killed = true; + } + + // DMR TSCC checks + if (m_p25Enabled && m_dmrCtrlChannel) { + ::LogError(LOG_HOST, "Cannot have P25 enabled when using dedicated DMR TSCC control!"); g_killed = true; } + if (!m_fixedMode && m_dmrCtrlChannel) { + ::LogWarning(LOG_HOST, "Fixed mode should be enabled when using dedicated DMR TSCC control!"); + } + + if (!m_duplex && m_dmrTSCCData) { + ::LogError(LOG_HOST, "Cannot have DMR TSCC control and simplex mode at the same time."); + g_killed = true; + } + + // DMR beacon checks if (m_dmrBeacons && m_controlData) { ::LogError(LOG_HOST, "Cannot have DMR roaming becaons and P25 control at the same time."); g_killed = true; @@ -499,11 +541,6 @@ int Host::run() g_killed = true; } - if (!m_duplex && m_controlData) { - ::LogError(LOG_HOST, "Cannot have P25 control and simplex mode at the same time."); - g_killed = true; - } - if (!g_killed) { // fixed more or P25 control channel will force a state change if (m_fixedMode || m_p25CtrlChannel) { @@ -561,6 +598,16 @@ int Host::run() } \ } + // Macro to interrupt a running DMR roaming beacon + #define INTERRUPT_DMR_BEACON \ + if (dmr != NULL) { \ + if (dmrBeaconDurationTimer.isRunning() && !dmrBeaconDurationTimer.hasExpired()) { \ + if (m_dmrTSCCData && !m_dmrCtrlChannel) \ + dmr->setCCRunning(false); \ + } \ + dmrBeaconDurationTimer.stop(); \ + } + // Macro to start DMR duplex idle transmission (or beacon) #define START_DMR_DUPLEX_IDLE(x) \ if (dmr != NULL) { \ @@ -630,10 +677,14 @@ int Host::run() m_modem->writeDMRData1(data, len); - dmrBeaconDurationTimer.stop(); + if (!dmr->getCCRunning()) { + INTERRUPT_DMR_BEACON; + } + if (g_interruptP25Control && p25CCDurationTimer.isRunning()) { p25CCDurationTimer.pause(); } + m_modeTimer.start(); } /* @@ -661,10 +712,14 @@ int Host::run() m_modem->writeDMRData2(data, len); - dmrBeaconDurationTimer.stop(); + if (!dmr->getCCRunning()) { + INTERRUPT_DMR_BEACON; + } + if (g_interruptP25Control && p25CCDurationTimer.isRunning()) { p25CCDurationTimer.pause(); } + m_modeTimer.start(); } /* @@ -693,7 +748,8 @@ int Host::run() if (m_state == STATE_P25) { m_modem->writeP25Data(data, len); - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; + if (g_interruptP25Control && p25CCDurationTimer.isRunning()) { p25CCDurationTimer.pause(); } @@ -775,7 +831,7 @@ int Host::run() setState(STATE_DMR); START_DMR_DUPLEX_IDLE(true); - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; } } @@ -787,7 +843,7 @@ int Host::run() dmr->processFrame1(data, len); - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; p25CCDurationTimer.stop(); } } @@ -805,7 +861,7 @@ int Host::run() // process slot 1 frames bool ret = dmr->processFrame1(data, len); if (ret) { - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; m_modeTimer.start(); @@ -832,7 +888,7 @@ int Host::run() setState(STATE_DMR); START_DMR_DUPLEX_IDLE(true); - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; } } @@ -844,7 +900,7 @@ int Host::run() dmr->processFrame2(data, len); - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; } } @@ -862,7 +918,7 @@ int Host::run() // process slot 2 frames bool ret = dmr->processFrame2(data, len); if (ret) { - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; m_modeTimer.start(); @@ -889,13 +945,13 @@ int Host::run() m_modeTimer.setTimeout(m_rfModeHang); setState(STATE_P25); - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; } else { ret = p25->writeEndRF(); if (ret) { - dmrBeaconDurationTimer.stop(); + INTERRUPT_DMR_BEACON; if (m_state == STATE_IDLE) { m_modeTimer.setTimeout(m_rfModeHang); @@ -1027,6 +1083,15 @@ int Host::run() /** DMR */ if (dmr != NULL) { + if (m_dmrTSCCData && m_dmrCtrlChannel) { + if (m_state != STATE_DMR) + setState(STATE_DMR); + + if (!m_modem->hasTX()) { + START_DMR_DUPLEX_IDLE(true); + } + } + // clock and check DMR roaming beacon interval timer dmrBeaconIntervalTimer.clock(ms); if ((dmrBeaconIntervalTimer.isRunning() && dmrBeaconIntervalTimer.hasExpired()) || g_fireDMRBeacon) { @@ -1035,12 +1100,17 @@ int Host::run() m_modeTimer.stop(); } - if (m_fixedMode) - START_DMR_DUPLEX_IDLE(true); - if (m_state != STATE_DMR) setState(STATE_DMR); + if (m_fixedMode) { + START_DMR_DUPLEX_IDLE(true); + } + + if (m_dmrTSCCData) { + dmr->setCCRunning(true); + } + g_fireDMRBeacon = false; LogDebug(LOG_HOST, "DMR, roaming beacon burst"); dmrBeaconIntervalTimer.start(); @@ -1059,6 +1129,10 @@ int Host::run() m_modeTimer.start(); } } + + if (m_dmrTSCCData) { + dmr->setCCRunning(false); + } } // clock and check DMR Tx timer diff --git a/host/Host.h b/host/Host.h index 2f3fc9e0..6cd841a5 100644 --- a/host/Host.h +++ b/host/Host.h @@ -84,6 +84,7 @@ private: bool m_p25CtrlChannel; bool m_p25CtrlBroadcast; + bool m_dmrCtrlChannel; bool m_duplex; bool m_fixedMode; @@ -114,6 +115,7 @@ private: lookups::TalkgroupIdLookup* m_tidLookup; bool m_dmrBeacons; + bool m_dmrTSCCData; bool m_controlData; uint8_t m_siteId; diff --git a/p25/Control.cpp b/p25/Control.cpp index 080ac2b1..38134bce 100644 --- a/p25/Control.cpp +++ b/p25/Control.cpp @@ -94,7 +94,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod m_legacyGroupReg(false), m_duplex(duplex), m_control(false), - m_continuousControl(false), + m_dedicatedControl(false), m_voiceOnControl(false), m_ackTSBKRequests(true), m_disableNetworkHDU(false), @@ -204,10 +204,10 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s yaml::Node control = p25Protocol["control"]; m_control = control["enable"].as(false); if (m_control) { - m_continuousControl = control["continuous"].as(false); + m_dedicatedControl = control["dedicated"].as(false); } else { - m_continuousControl = false; + m_dedicatedControl = false; } m_voiceOnControl = p25Protocol["voiceOnControl"].as(false); @@ -609,7 +609,7 @@ void Control::clock(uint32_t ms) m_trunk->releaseDstIdGrant(m_voice->m_netLC.getDstId(), false); } - if (m_continuousControl) { + if (m_dedicatedControl) { if (m_network != NULL) m_network->resetP25(); } diff --git a/p25/Control.h b/p25/Control.h index 6ba27458..8a82a79e 100644 --- a/p25/Control.h +++ b/p25/Control.h @@ -130,7 +130,7 @@ namespace p25 bool m_duplex; bool m_control; - bool m_continuousControl; + bool m_dedicatedControl; bool m_voiceOnControl; bool m_ackTSBKRequests; bool m_disableNetworkHDU; diff --git a/p25/TrunkPacket.cpp b/p25/TrunkPacket.cpp index afecfd16..442b60dd 100644 --- a/p25/TrunkPacket.cpp +++ b/p25/TrunkPacket.cpp @@ -1408,7 +1408,7 @@ void TrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite) if (!noNetwork) writeNetworkRF(data + 2U, true); - if (m_p25->m_continuousControl) { + if (m_p25->m_dedicatedControl) { writeRF_TSDU_MBF(clearBeforeWrite); return; } diff --git a/p25/VoicePacket.cpp b/p25/VoicePacket.cpp index 16899357..6ccf6449 100644 --- a/p25/VoicePacket.cpp +++ b/p25/VoicePacket.cpp @@ -651,7 +651,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) LogMessage(LOG_RF, P25_TDU_STR ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", m_rfFrames, m_rfBits, m_rfUndecodableLC, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits)); - if (m_p25->m_continuousControl) { + if (m_p25->m_dedicatedControl) { m_p25->m_tailOnIdle = false; writeRF_EndOfVoice(); }