diff --git a/src/dmr/Control.cpp b/src/dmr/Control.cpp
index c61c31cb..13e6b148 100644
--- a/src/dmr/Control.cpp
+++ b/src/dmr/Control.cpp
@@ -420,7 +420,8 @@ Slot* Control::getTSCCSlot() const
/// DMR slot number.
///
///
-void Control::tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group)
+///
+void Control::tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group, bool voice)
{
if (m_verbose) {
LogMessage(LOG_DMR, "DMR Slot %u, payload activation, group = %u, dstId = %u",
@@ -436,11 +437,11 @@ void Control::tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group)
switch (slotNo) {
case 1U:
m_tsccPayloadActive = true;
- m_slot1->setTSCCActivated(dstId, group);
+ m_slot1->setTSCCActivated(dstId, group, voice);
break;
case 2U:
m_tsccPayloadActive = true;
- m_slot2->setTSCCActivated(dstId, group);
+ m_slot2->setTSCCActivated(dstId, group, voice);
break;
default:
LogError(LOG_DMR, "DMR, invalid slot, TSCC payload activation, slotNo = %u", slotNo);
diff --git a/src/dmr/Control.h b/src/dmr/Control.h
index 83bef7f1..ce6a1674 100644
--- a/src/dmr/Control.h
+++ b/src/dmr/Control.h
@@ -100,7 +100,7 @@ namespace dmr
/// Helper to return the slot carrying the TSCC.
Slot* getTSCCSlot() const;
/// Helper to payload activate the slot carrying granted payload traffic.
- void tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group);
+ void tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group, bool voice);
/// Helper to clear an activated payload slot.
void tsccClearActivatedSlot(uint32_t slotNo);
diff --git a/src/dmr/Slot.cpp b/src/dmr/Slot.cpp
index ef0c72b2..464a7248 100644
--- a/src/dmr/Slot.cpp
+++ b/src/dmr/Slot.cpp
@@ -158,6 +158,7 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_dedicatedTSCC(false),
m_tsccPayloadDstId(0U),
m_tsccPayloadGroup(false),
+ m_tsccPayloadVoice(true),
m_verbose(verbose),
m_debug(debug)
{
@@ -470,7 +471,7 @@ void Slot::clock()
if (m_rfState == RS_RF_LISTENING && m_netState == RS_NET_IDLE) {
if (m_tsccPayloadDstId > 0U) {
if ((m_dmr->m_tsccCnt % 2) > 0) {
- setShortLC(m_slotNo, m_tsccPayloadDstId, m_tsccPayloadGroup ? FLCO_GROUP : FLCO_PRIVATE, false);
+ setShortLC(m_slotNo, m_tsccPayloadDstId, m_tsccPayloadGroup ? FLCO_GROUP : FLCO_PRIVATE, m_tsccPayloadVoice);
}
}
}
diff --git a/src/dmr/Slot.h b/src/dmr/Slot.h
index 31e7af74..44298283 100644
--- a/src/dmr/Slot.h
+++ b/src/dmr/Slot.h
@@ -106,7 +106,7 @@ namespace dmr
/// Helper to enable and configure TSCC support for this slot.
void setTSCC(bool enable, bool dedicated);
/// Sets a flag indicating whether the slot is a TSCC payload slot.
- void setTSCCActivated(uint32_t dstId, bool group) { m_tsccPayloadDstId = dstId; m_tsccPayloadGroup = group; }
+ void setTSCCActivated(uint32_t dstId, bool group, bool voice) { m_tsccPayloadDstId = dstId; m_tsccPayloadGroup = group; m_tsccPayloadVoice = voice; }
/// Sets a flag indicating whether the DMR control channel can send permit-tg to voice channels.
void setControlPermitTG(bool controlPermitTG) { m_controlPermitTG = controlPermitTG; }
/// Helper to set the voice error silence threshold.
@@ -194,6 +194,7 @@ namespace dmr
uint32_t m_tsccPayloadDstId;
bool m_tsccPayloadGroup;
+ bool m_tsccPayloadVoice;
bool m_controlPermitTG;
@@ -264,7 +265,7 @@ namespace dmr
void writeRF_ControlData(uint16_t frameCnt, uint8_t n);
/// Clears the flag indicating whether the slot is a TSCC payload slot.
- void clearTSCCActivated() { m_tsccPayloadDstId = 0U; m_tsccPayloadGroup = false; }
+ void clearTSCCActivated() { m_tsccPayloadDstId = 0U; m_tsccPayloadGroup = false; m_tsccPayloadVoice = true; }
/// Helper to set the DMR short LC.
static void setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco = FLCO_GROUP, bool voice = true);
diff --git a/src/dmr/packet/ControlSignaling.cpp b/src/dmr/packet/ControlSignaling.cpp
index e29994a2..1baf9da0 100644
--- a/src/dmr/packet/ControlSignaling.cpp
+++ b/src/dmr/packet/ControlSignaling.cpp
@@ -849,16 +849,18 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
req["dstId"].set(dstId);
req["slot"].set(slot);
req["group"].set(grp);
+ bool voice = true;
+ req["voice"].set(voice);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
- HTTP_PUT, PUT_DMR_TSCC_PAYLOAD_ACT, req, m_tscc->m_debug);
+ HTTP_PUT, PUT_DMR_TSCC_PAYLOAD_ACT, req, m_tscc->m_debug);
}
else {
::LogError(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), failed to activate payload channel, chNo = %u, slot = %u", m_tscc->m_slotNo, chNo, slot);
}
}
else {
- m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp);
+ m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp, true);
}
// callback RCON to permit-tg on the specified voice channel
@@ -911,6 +913,8 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
req["dstId"].set(dstId);
req["slot"].set(slot);
req["group"].set(grp);
+ bool voice = true;
+ req["voice"].set(voice);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
HTTP_PUT, PUT_DMR_TSCC_PAYLOAD_ACT, req, m_tscc->m_debug);
@@ -920,7 +924,7 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
}
}
else {
- m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp);
+ m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp, true);
}
// callback RCON to permit-tg on the specified voice channel
@@ -1082,6 +1086,8 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
req["dstId"].set(dstId);
req["slot"].set(slot);
req["group"].set(grp);
+ bool voice = false;
+ req["voice"].set(voice);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
HTTP_PUT, PUT_DMR_TSCC_PAYLOAD_ACT, req, m_tscc->m_debug);
@@ -1091,7 +1097,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
}
}
else {
- m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp);
+ m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp, false);
}
std::unique_ptr csbk = new_unique(CSBK_TD_GRANT);
@@ -1124,6 +1130,8 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
req["dstId"].set(dstId);
req["slot"].set(slot);
req["group"].set(grp);
+ bool voice = false;
+ req["voice"].set(voice);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
HTTP_PUT, PUT_DMR_TSCC_PAYLOAD_ACT, req, m_tscc->m_debug);
@@ -1133,7 +1141,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
}
}
else {
- m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp);
+ m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp, false);
}
std::unique_ptr csbk = new_unique(CSBK_PD_GRANT);
diff --git a/src/network/RESTAPI.cpp b/src/network/RESTAPI.cpp
index fe563561..0f80a748 100644
--- a/src/network/RESTAPI.cpp
+++ b/src/network/RESTAPI.cpp
@@ -1438,15 +1438,22 @@ void RESTAPI::restAPI_PutTSCCPayloadActivate(const HTTPPayload& request, HTTPPay
return;
}
+ // validate voice flag is a boolean within the JSON blob
+ if (!req["voice"].is()) {
+ errorPayload(reply, "voice flag was not valid");
+ return;
+ }
+
uint32_t dstId = req["dstId"].get();
bool group = req["group"].get();
+ bool voice = req["voice"].get();
if (dstId == 0U) {
errorPayload(reply, "destination ID was not valid");
return;
}
- m_dmr->tsccActivateSlot(slot, dstId, group);
+ m_dmr->tsccActivateSlot(slot, dstId, group, voice);
}
#else
errorPayload(reply, "DMR operations are unavailable", HTTPPayload::SERVICE_UNAVAILABLE);