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();
}