ensure TSCC SLCO's will not be sent at all if DMR CC mode is disabled; hide display of TSCC Slot number if DMR TSCC is not enabled; add payload channel CSBKs; prohibit processing of voice/data traffic on a TSCC slot; fix issue where writeRF_CSBK was only functioning for TSCC slots; fix issue handling slot number in some CSBKs; change order of operations for when TSCC payload channels are activated;

pull/24/head
Bryan Biedenkapp 3 years ago
parent 7e2e002b10
commit 86748665ba

@ -77,6 +77,7 @@ Control::Control(bool authoritative, uint32_t colorCode, uint32_t callHang, uint
m_idenTable(idenTable), m_idenTable(idenTable),
m_ridLookup(ridLookup), m_ridLookup(ridLookup),
m_tidLookup(tidLookup), m_tidLookup(tidLookup),
m_enableTSCC(false),
m_tsccCnt(0U), m_tsccCnt(0U),
m_tsccCntInterval(1000U, 0U, DMR_SLOT_TIME / 2U), m_tsccCntInterval(1000U, 0U, DMR_SLOT_TIME / 2U),
m_tsccSlotNo(0U), m_tsccSlotNo(0U),
@ -170,6 +171,8 @@ void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::vect
} }
} }
m_enableTSCC = enableTSCC;
uint32_t silenceThreshold = dmrProtocol["silenceThreshold"].as<uint32_t>(dmr::DEFAULT_SILENCE_THRESHOLD); uint32_t silenceThreshold = dmrProtocol["silenceThreshold"].as<uint32_t>(dmr::DEFAULT_SILENCE_THRESHOLD);
if (silenceThreshold > MAX_DMR_VOICE_ERRORS) { if (silenceThreshold > MAX_DMR_VOICE_ERRORS) {
LogWarning(LOG_DMR, "Silence threshold > %u, defaulting to %u", dmr::MAX_DMR_VOICE_ERRORS, dmr::DEFAULT_SILENCE_THRESHOLD); LogWarning(LOG_DMR, "Silence threshold > %u, defaulting to %u", dmr::MAX_DMR_VOICE_ERRORS, dmr::DEFAULT_SILENCE_THRESHOLD);
@ -186,8 +189,8 @@ void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::vect
m_slot2->setSilenceThreshold(silenceThreshold); m_slot2->setSilenceThreshold(silenceThreshold);
if (printOptions) { if (printOptions) {
LogInfo(" TSCC Slot: %u", m_tsccSlotNo);
if (enableTSCC) { if (enableTSCC) {
LogInfo(" TSCC Slot: %u", m_tsccSlotNo);
LogInfo(" TSCC Aloha Random Access Wait: %u", nRandWait); LogInfo(" TSCC Aloha Random Access Wait: %u", nRandWait);
LogInfo(" TSCC Aloha Backoff: %u", backOff); LogInfo(" TSCC Aloha Backoff: %u", backOff);
} }
@ -204,6 +207,11 @@ void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::vect
/// <param name="ccRunning"></param> /// <param name="ccRunning"></param>
void Control::setCCRunning(bool ccRunning) void Control::setCCRunning(bool ccRunning)
{ {
if (!m_enableTSCC) {
m_ccRunning = false;
return;
}
m_ccRunning = ccRunning; m_ccRunning = ccRunning;
switch (m_tsccSlotNo) { switch (m_tsccSlotNo) {
case 1U: case 1U:
@ -224,6 +232,11 @@ void Control::setCCRunning(bool ccRunning)
/// <param name="ccHalted"></param> /// <param name="ccHalted"></param>
void Control::setCCHalted(bool ccHalted) void Control::setCCHalted(bool ccHalted)
{ {
if (!m_enableTSCC) {
m_ccHalted = true;
return;
}
m_ccHalted = ccHalted; m_ccHalted = ccHalted;
switch (m_tsccSlotNo) { switch (m_tsccSlotNo) {
case 1U: case 1U:
@ -419,13 +432,14 @@ Slot* Control::getTSCCSlot() const
/// </summary> /// </summary>
/// <param name="slotNo">DMR slot number.</param> /// <param name="slotNo">DMR slot number.</param>
/// <param name="dstId"></param> /// <param name="dstId"></param>
/// <param name="srcId"></param>
/// <param name="group"></param> /// <param name="group"></param>
/// <param name="voice"></param> /// <param name="voice"></param>
void Control::tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group, bool voice) void Control::tsccActivateSlot(uint32_t slotNo, uint32_t dstId, uint32_t srcId, bool group, bool voice)
{ {
if (m_verbose) { if (m_verbose) {
LogMessage(LOG_DMR, "DMR Slot %u, payload activation, group = %u, dstId = %u", LogMessage(LOG_DMR, "DMR Slot %u, payload activation, srcId = %u, group = %u, dstId = %u",
slotNo, group, dstId); slotNo, srcId, group, dstId);
} }
// never allow the TSCC to become payload activated // never allow the TSCC to become payload activated
@ -437,11 +451,11 @@ void Control::tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group, bool
switch (slotNo) { switch (slotNo) {
case 1U: case 1U:
m_tsccPayloadActive = true; m_tsccPayloadActive = true;
m_slot1->setTSCCActivated(dstId, group, voice); m_slot1->setTSCCActivated(dstId, srcId, group, voice);
break; break;
case 2U: case 2U:
m_tsccPayloadActive = true; m_tsccPayloadActive = true;
m_slot2->setTSCCActivated(dstId, group, voice); m_slot2->setTSCCActivated(dstId, srcId, group, voice);
break; break;
default: default:
LogError(LOG_DMR, "DMR, invalid slot, TSCC payload activation, slotNo = %u", slotNo); LogError(LOG_DMR, "DMR, invalid slot, TSCC payload activation, slotNo = %u", slotNo);

@ -100,7 +100,7 @@ namespace dmr
/// <summary>Helper to return the slot carrying the TSCC.</summary> /// <summary>Helper to return the slot carrying the TSCC.</summary>
Slot* getTSCCSlot() const; Slot* getTSCCSlot() const;
/// <summary>Helper to payload activate the slot carrying granted payload traffic.</summary> /// <summary>Helper to payload activate the slot carrying granted payload traffic.</summary>
void tsccActivateSlot(uint32_t slotNo, uint32_t dstId, bool group, bool voice); void tsccActivateSlot(uint32_t slotNo, uint32_t dstId, uint32_t srcId, bool group, bool voice);
/// <summary>Helper to clear an activated payload slot.</summary> /// <summary>Helper to clear an activated payload slot.</summary>
void tsccClearActivatedSlot(uint32_t slotNo); void tsccClearActivatedSlot(uint32_t slotNo);
@ -141,6 +141,8 @@ namespace dmr
::lookups::RadioIdLookup* m_ridLookup; ::lookups::RadioIdLookup* m_ridLookup;
::lookups::TalkgroupIdLookup* m_tidLookup; ::lookups::TalkgroupIdLookup* m_tidLookup;
bool m_enableTSCC;
uint16_t m_tsccCnt; uint16_t m_tsccCnt;
Timer m_tsccCntInterval; Timer m_tsccCntInterval;

@ -302,6 +302,7 @@ namespace dmr
const uint8_t CSBKO_EXT_FNCT = 0x24U; // (DMRA) EXT FNCT - Extended Function 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_NACK_RSP = 0x26U; // NACK RSP - Negative Acknowledgement Response
const uint8_t CSBKO_BROADCAST = 0x28U; // BCAST - Announcement PDUs const uint8_t CSBKO_BROADCAST = 0x28U; // BCAST - Announcement PDUs
const uint8_t CSBKO_P_CLEAR = 0x2EU; // P_CLEAR - Payload Channel Clear
const uint8_t CSBKO_PV_GRANT = 0x30U; // PV_GRANT - Private Voice Channel Grant 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_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_BTV_GRANT = 0x32U; // BTV_GRANT - Broadcast Talkgroup Voice Channel Grant

@ -289,23 +289,15 @@ bool Slot::processFrame(uint8_t *data, uint32_t len)
if (dataSync) { if (dataSync) {
uint8_t dataType = data[1U] & 0x0FU; uint8_t dataType = data[1U] & 0x0FU;
// write and process TSCC CSBKs and short LC if (dataType == DT_CSBK) {
if (m_enableTSCC && m_dedicatedTSCC && m_slotNo == m_dmr->m_tsccSlotNo) { return m_control->process(data, len);
switch (dataType) }
{
case DT_CSBK:
return m_control->process(data, len);
default:
break;
}
if (m_enableTSCC && m_dedicatedTSCC)
return false; return false;
}
switch (dataType) switch (dataType)
{ {
case DT_CSBK:
return m_control->process(data, len);
case DT_VOICE_LC_HEADER: case DT_VOICE_LC_HEADER:
case DT_VOICE_PI_HEADER: case DT_VOICE_PI_HEADER:
return m_voice->process(data, len); return m_voice->process(data, len);
@ -600,6 +592,20 @@ void Slot::setTSCC(bool enable, bool dedicated)
} }
} }
/// <summary>
/// Helper to activate a TSCC payload slot.
/// </summary>
/// <param name="dstId"></param>
/// <param name="srcId"></param>
/// <param name="group"></param>
/// <param name="voice"></param>
void Slot::setTSCCActivated(uint32_t dstId, uint32_t srcId, bool group, bool voice)
{
m_tsccPayloadDstId = dstId;
m_tsccPayloadGroup = group;
m_tsccPayloadVoice = voice;
}
/// <summary> /// <summary>
/// Helper to set the voice error silence threshold. /// Helper to set the voice error silence threshold.
/// </summary> /// </summary>

@ -105,8 +105,8 @@ namespace dmr
/// <summary>Helper to enable and configure TSCC support for this slot.</summary> /// <summary>Helper to enable and configure TSCC support for this slot.</summary>
void setTSCC(bool enable, bool dedicated); void setTSCC(bool enable, bool dedicated);
/// <summary>Sets a flag indicating whether the slot is a TSCC payload slot.</summary> /// <summary>Helper to activate a TSCC payload slot.</summary>
void setTSCCActivated(uint32_t dstId, bool group, bool voice) { m_tsccPayloadDstId = dstId; m_tsccPayloadGroup = group; m_tsccPayloadVoice = voice; } void setTSCCActivated(uint32_t dstId, uint32_t srcId, bool group, bool voice);
/// <summary>Sets a flag indicating whether the DMR control channel can send permit-tg to voice channels.</summary> /// <summary>Sets a flag indicating whether the DMR control channel can send permit-tg to voice channels.</summary>
void setControlPermitTG(bool controlPermitTG) { m_controlPermitTG = controlPermitTG; } void setControlPermitTG(bool controlPermitTG) { m_controlPermitTG = controlPermitTG; }
/// <summary>Helper to set the voice error silence threshold.</summary> /// <summary>Helper to set the voice error silence threshold.</summary>

@ -37,6 +37,8 @@
#include "dmr/lc/csbk/CSBK_DVM_GIT_HASH.h" #include "dmr/lc/csbk/CSBK_DVM_GIT_HASH.h"
#include "dmr/lc/csbk/CSBK_EXT_FNCT.h" #include "dmr/lc/csbk/CSBK_EXT_FNCT.h"
#include "dmr/lc/csbk/CSBK_NACK_RSP.h" #include "dmr/lc/csbk/CSBK_NACK_RSP.h"
#include "dmr/lc/csbk/CSBK_P_CLEAR.h"
#include "dmr/lc/csbk/CSBK_P_GRANT.h"
#include "dmr/lc/csbk/CSBK_PD_GRANT.h" #include "dmr/lc/csbk/CSBK_PD_GRANT.h"
#include "dmr/lc/csbk/CSBK_PRECCSBK.h" #include "dmr/lc/csbk/CSBK_PRECCSBK.h"
#include "dmr/lc/csbk/CSBK_PV_GRANT.h" #include "dmr/lc/csbk/CSBK_PV_GRANT.h"

@ -72,7 +72,7 @@ void CSBK_PD_GRANT::encode(uint8_t* data)
ulong64_t csbkValue = 0U; ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1 csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number csbkValue = (csbkValue << 1) + ((m_slotNo == 2U) ? 1U : 0U); // Logical Slot Number
csbkValue = (csbkValue << 1) + 0U; // High Rate Flag - Always Single Slot Data csbkValue = (csbkValue << 1) + 0U; // High Rate Flag - Always Single Slot Data
csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency
csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset

@ -72,7 +72,7 @@ void CSBK_PV_GRANT::encode(uint8_t* data)
ulong64_t csbkValue = 0U; ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1 csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number csbkValue = (csbkValue << 1) + ((m_slotNo == 2U) ? 1U : 0U); // Logical Slot Number
csbkValue = (csbkValue << 1) + 0U; // Reserved csbkValue = (csbkValue << 1) + 0U; // Reserved
csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency
csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset

@ -0,0 +1,83 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Defines.h"
#include "dmr/lc/csbk/CSBK_P_CLEAR.h"
#include "Log.h"
#include "Utils.h"
using namespace dmr::lc::csbk;
using namespace dmr::lc;
using namespace dmr;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the CSBK_P_CLEAR class.
/// </summary>
CSBK_P_CLEAR::CSBK_P_CLEAR() : CSBK()
{
m_CSBKO = CSBKO_P_CLEAR;
}
/// <summary>
/// Decode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <returns>True, if CSBK was decoded, otherwise false.</returns>
bool CSBK_P_CLEAR::decode(const uint8_t* data)
{
assert(data != NULL);
/* stub */
return true;
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
void CSBK_P_CLEAR::encode(uint8_t* data)
{
assert(data != NULL);
ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + 0U; // Reserved
csbkValue = (csbkValue << 3) + 0U; // Reserved
csbkValue = (csbkValue << 1) + ((m_GI) ? 1U : 0U); // Group/Individual Flag
csbkValue = (csbkValue << 24) + m_dstId; // Talkgroup ID
csbkValue = (csbkValue << 24) + m_srcId; // Source Radio Address
std::unique_ptr<uint8_t[]> csbk = CSBK::fromValue(csbkValue);
CSBK::encode(data, csbk.get());
}

@ -0,0 +1,57 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_LC_CSBK__CSBK_P_CLEAR_H__)
#define __DMR_LC_CSBK__CSBK_P_CLEAR_H__
#include "Defines.h"
#include "dmr/lc/CSBK.h"
namespace dmr
{
namespace lc
{
namespace csbk
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements P_CLEAR - Payload Channel Clear
// ---------------------------------------------------------------------------
class HOST_SW_API CSBK_P_CLEAR : public CSBK {
public:
/// <summary>Initializes a new instance of the CSBK_P_CLEAR class.</summary>
CSBK_P_CLEAR();
/// <summary>Decode a control signalling block.</summary>
virtual bool decode(const uint8_t* data);
/// <summary>Encode a control signalling block.</summary>
virtual void encode(uint8_t* data);
};
} // namespace csbk
} // namespace lc
} // namespace dmr
#endif // __DMR_LC_CSBK__CSBK_P_CLEAR_H__

@ -0,0 +1,84 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Defines.h"
#include "dmr/lc/csbk/CSBK_P_GRANT.h"
#include "Log.h"
#include "Utils.h"
using namespace dmr::lc::csbk;
using namespace dmr::lc;
using namespace dmr;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the CSBK_P_GRANT class.
/// </summary>
CSBK_P_GRANT::CSBK_P_GRANT() : CSBK()
{
m_CSBKO = CSBKO_TV_GRANT;
}
/// <summary>
/// Decode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <returns>True, if CSBK was decoded, otherwise false.</returns>
bool CSBK_P_GRANT::decode(const uint8_t* data)
{
assert(data != NULL);
/* stub */
return true;
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
void CSBK_P_GRANT::encode(uint8_t* data)
{
assert(data != NULL);
ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + ((m_slotNo == 2U) ? 1U : 0U); // Logical Slot Number
csbkValue = (csbkValue << 1) + 0U; // High Rate Flag - Always Single Slot Data
csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 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 Radio Address
std::unique_ptr<uint8_t[]> csbk = CSBK::fromValue(csbkValue);
CSBK::encode(data, csbk.get());
}

@ -0,0 +1,57 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_LC_CSBK__CSBK_P_GRANT_H__)
#define __DMR_LC_CSBK__CSBK_P_GRANT_H__
#include "Defines.h"
#include "dmr/lc/CSBK.h"
namespace dmr
{
namespace lc
{
namespace csbk
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements P_GRANT - Payload Channel Talkgroup Voice Channel Grant
// ---------------------------------------------------------------------------
class HOST_SW_API CSBK_P_GRANT : public CSBK {
public:
/// <summary>Initializes a new instance of the CSBK_P_GRANT class.</summary>
CSBK_P_GRANT();
/// <summary>Decode a control signalling block.</summary>
virtual bool decode(const uint8_t* data);
/// <summary>Encode a control signalling block.</summary>
virtual void encode(uint8_t* data);
};
} // namespace csbk
} // namespace lc
} // namespace dmr
#endif // __DMR_LC_CSBK__CSBK_P_GRANT_H__

@ -72,7 +72,7 @@ void CSBK_TD_GRANT::encode(uint8_t* data)
ulong64_t csbkValue = 0U; ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1 csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number csbkValue = (csbkValue << 1) + ((m_slotNo == 2U) ? 1U : 0U); // Logical Slot Number
csbkValue = (csbkValue << 1) + 0U; // High Rate Flag - Always Single Slot Data csbkValue = (csbkValue << 1) + 0U; // High Rate Flag - Always Single Slot Data
csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency
csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset

@ -73,7 +73,7 @@ void CSBK_TV_GRANT::encode(uint8_t* data)
ulong64_t csbkValue = 0U; ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1 csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number csbkValue = (csbkValue << 1) + ((m_slotNo == 2U) ? 1U : 0U); // Logical Slot Number
csbkValue = (csbkValue << 1) + ((m_lateEntry) ? 1U : 0U);; // Late Entry csbkValue = (csbkValue << 1) + ((m_lateEntry) ? 1U : 0U);; // Late Entry
csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency
csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset

@ -650,50 +650,44 @@ ControlSignaling::~ControlSignaling()
/// <param name="clearBeforeWrite"></param> /// <param name="clearBeforeWrite"></param>
void ControlSignaling::writeRF_CSBK(lc::CSBK* csbk, bool clearBeforeWrite) void ControlSignaling::writeRF_CSBK(lc::CSBK* csbk, bool clearBeforeWrite)
{ {
Slot *m_tscc = m_slot->m_dmr->getTSCCSlot(); // don't add any frames if the queue is full
if (m_tscc != nullptr) { uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U;
if (!m_tscc->m_enableTSCC) uint32_t space = m_slot->m_queue.freeSpace();
return; if (space < (len + 1U)) {
return;
// don't add any frames if the queue is full }
uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U;
uint32_t space = m_tscc->m_queue.freeSpace();
if (space < (len + 1U)) {
return;
}
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
SlotType slotType; uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
slotType.setColorCode(m_tscc->m_colorCode); ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
slotType.setDataType(DT_CSBK);
// Regenerate the CSBK data SlotType slotType;
csbk->encode(data + 2U); slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_CSBK);
// Regenerate the Slot Type // Regenerate the CSBK data
slotType.encode(data + 2U); csbk->encode(data + 2U);
// Convert the Data Sync to be from the BS or MS as needed // Regenerate the Slot Type
Sync::addDMRDataSync(data + 2U, m_tscc->m_duplex); slotType.encode(data + 2U);
m_tscc->m_rfSeqNo = 0U; // Convert the Data Sync to be from the BS or MS as needed
Sync::addDMRDataSync(data + 2U, m_slot->m_duplex);
data[0U] = modem::TAG_DATA; m_slot->m_rfSeqNo = 0U;
data[1U] = 0x00U;
if (clearBeforeWrite) { data[0U] = modem::TAG_DATA;
if (m_tscc->m_slotNo == 1U) data[1U] = 0x00U;
m_tscc->m_modem->clearDMRData1();
if (m_tscc->m_slotNo == 2U)
m_tscc->m_modem->clearDMRData2();
m_tscc->m_queue.clear();
}
if (m_tscc->m_duplex) if (clearBeforeWrite) {
m_tscc->addFrame(data); if (m_slot->m_slotNo == 1U)
m_slot->m_modem->clearDMRData1();
if (m_slot->m_slotNo == 2U)
m_slot->m_modem->clearDMRData2();
m_slot->m_queue.clear();
} }
if (m_slot->m_duplex)
m_slot->addFrame(data);
} }
/// <summary> /// <summary>
@ -841,28 +835,6 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
::ActivityLog("DMR", true, "Slot %u group grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId); ::ActivityLog("DMR", true, "Slot %u group grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
} }
// if the channel granted isn't the same as the TSCC; remote activate the payload channel
if (chNo != m_tscc->m_channelNo) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object();
req["dstId"].set<uint32_t>(dstId);
req["slot"].set<uint8_t>(slot);
req["group"].set<bool>(grp);
bool voice = true;
req["voice"].set<bool>(voice);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
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, true);
}
// callback RCON to permit-tg on the specified voice channel // callback RCON to permit-tg on the specified voice channel
if (m_tscc->m_authoritative && m_tscc->m_controlPermitTG) { if (m_tscc->m_authoritative && m_tscc->m_controlPermitTG) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo); ::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
@ -881,11 +853,13 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
} }
} }
writeRF_CSBK_ACK_RSP(srcId, TS_ACK_RSN_MSG, (grp) ? 1U : 0U);
std::unique_ptr<CSBK_TV_GRANT> csbk = new_unique(CSBK_TV_GRANT); std::unique_ptr<CSBK_TV_GRANT> csbk = new_unique(CSBK_TV_GRANT);
if (broadcast) if (broadcast)
csbk->setCSBKO(CSBKO_BTV_GRANT); csbk->setCSBKO(CSBKO_BTV_GRANT);
csbk->setLogicalCh1(chNo); csbk->setLogicalCh1(chNo);
csbk->setSlotNo(slot - 1U); csbk->setSlotNo(slot);
if (m_verbose) { if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u", LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
@ -899,11 +873,6 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
// transmit group grant (x2) // transmit group grant (x2)
for (uint8_t i = 0; i < 2U; i++) for (uint8_t i = 0; i < 2U; i++)
writeRF_CSBK(csbk.get()); writeRF_CSBK(csbk.get());
}
else {
if (!net) {
::ActivityLog("DMR", true, "Slot %u individual grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
// if the channel granted isn't the same as the TSCC; remote activate the payload channel // if the channel granted isn't the same as the TSCC; remote activate the payload channel
if (chNo != m_tscc->m_channelNo) { if (chNo != m_tscc->m_channelNo) {
@ -911,20 +880,26 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) { if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object(); json::object req = json::object();
req["dstId"].set<uint32_t>(dstId); req["dstId"].set<uint32_t>(dstId);
req["srcId"].set<uint32_t>(srcId);
req["slot"].set<uint8_t>(slot); req["slot"].set<uint8_t>(slot);
req["group"].set<bool>(grp); req["group"].set<bool>(grp);
bool voice = true; bool voice = true;
req["voice"].set<bool>(voice); req["voice"].set<bool>(voice);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(), 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 { 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); ::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 { else {
m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp, true); m_slot->m_dmr->tsccActivateSlot(slot, dstId, srcId, grp, true);
}
}
else {
if (!net) {
::ActivityLog("DMR", true, "Slot %u individual grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
} }
// callback RCON to permit-tg on the specified voice channel // callback RCON to permit-tg on the specified voice channel
@ -945,9 +920,11 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
} }
} }
writeRF_CSBK_ACK_RSP(srcId, TS_ACK_RSN_MSG, (grp) ? 1U : 0U);
std::unique_ptr<CSBK_PV_GRANT> csbk = new_unique(CSBK_PV_GRANT); std::unique_ptr<CSBK_PV_GRANT> csbk = new_unique(CSBK_PV_GRANT);
csbk->setLogicalCh1(chNo); csbk->setLogicalCh1(chNo);
csbk->setSlotNo(slot - 1U); csbk->setSlotNo(slot);
if (m_verbose) { if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u", LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
@ -961,6 +938,29 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
// transmit private grant (x2) // transmit private grant (x2)
for (uint8_t i = 0; i < 2U; i++) for (uint8_t i = 0; i < 2U; i++)
writeRF_CSBK(csbk.get()); writeRF_CSBK(csbk.get());
// if the channel granted isn't the same as the TSCC; remote activate the payload channel
if (chNo != m_tscc->m_channelNo) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object();
req["dstId"].set<uint32_t>(dstId);
req["srcId"].set<uint32_t>(srcId);
req["slot"].set<uint8_t>(slot);
req["group"].set<bool>(grp);
bool voice = true;
req["voice"].set<bool>(voice);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
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, srcId, grp, true);
}
} }
return true; return true;
@ -1078,12 +1078,32 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
::ActivityLog("DMR", true, "Slot %u group grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId); ::ActivityLog("DMR", true, "Slot %u group grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
} }
writeRF_CSBK_ACK_RSP(srcId, TS_ACK_RSN_MSG, (grp) ? 1U : 0U);
std::unique_ptr<CSBK_TD_GRANT> csbk = new_unique(CSBK_TD_GRANT);
csbk->setLogicalCh1(chNo);
csbk->setSlotNo(slot);
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_DATA_CALL (Group Data Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
m_tscc->m_slotNo, emergency, privacy, broadcast, priority, csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId);
}
csbk->setEmergency(emergency);
csbk->setSrcId(srcId);
csbk->setDstId(dstId);
// transmit group grant (x2)
for (uint8_t i = 0; i < 2U; i++)
writeRF_CSBK(csbk.get());
// if the channel granted isn't the same as the TSCC; remote activate the payload channel // if the channel granted isn't the same as the TSCC; remote activate the payload channel
if (chNo != m_tscc->m_channelNo) { if (chNo != m_tscc->m_channelNo) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo); ::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) { if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object(); json::object req = json::object();
req["dstId"].set<uint32_t>(dstId); req["dstId"].set<uint32_t>(dstId);
req["srcId"].set<uint32_t>(srcId);
req["slot"].set<uint8_t>(slot); req["slot"].set<uint8_t>(slot);
req["group"].set<bool>(grp); req["group"].set<bool>(grp);
bool voice = false; bool voice = false;
@ -1097,15 +1117,22 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
} }
} }
else { else {
m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp, false); m_slot->m_dmr->tsccActivateSlot(slot, dstId, srcId, grp, false);
}
}
else {
if (!net) {
::ActivityLog("DMR", true, "Slot %u individual grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
} }
std::unique_ptr<CSBK_TD_GRANT> csbk = new_unique(CSBK_TD_GRANT); writeRF_CSBK_ACK_RSP(srcId, TS_ACK_RSN_MSG, (grp) ? 1U : 0U);
std::unique_ptr<CSBK_PD_GRANT> csbk = new_unique(CSBK_PD_GRANT);
csbk->setLogicalCh1(chNo); csbk->setLogicalCh1(chNo);
csbk->setSlotNo(slot - 1U); csbk->setSlotNo(slot);
if (m_verbose) { if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_DATA_CALL (Group Data Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u", LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_DATA_CALL (Individual Data Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
m_tscc->m_slotNo, emergency, privacy, broadcast, priority, csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId); m_tscc->m_slotNo, emergency, privacy, broadcast, priority, csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId);
} }
@ -1113,14 +1140,9 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
csbk->setSrcId(srcId); csbk->setSrcId(srcId);
csbk->setDstId(dstId); csbk->setDstId(dstId);
// transmit group grant (x2) // transmit private grant (x2)
for (uint8_t i = 0; i < 2U; i++) for (uint8_t i = 0; i < 2U; i++)
writeRF_CSBK(csbk.get()); writeRF_CSBK(csbk.get());
}
else {
if (!net) {
::ActivityLog("DMR", true, "Slot %u individual grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
// if the channel granted isn't the same as the TSCC; remote activate the payload channel // if the channel granted isn't the same as the TSCC; remote activate the payload channel
if (chNo != m_tscc->m_channelNo) { if (chNo != m_tscc->m_channelNo) {
@ -1128,6 +1150,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) { if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object(); json::object req = json::object();
req["dstId"].set<uint32_t>(dstId); req["dstId"].set<uint32_t>(dstId);
req["srcId"].set<uint32_t>(srcId);
req["slot"].set<uint8_t>(slot); req["slot"].set<uint8_t>(slot);
req["group"].set<bool>(grp); req["group"].set<bool>(grp);
bool voice = false; bool voice = false;
@ -1141,25 +1164,8 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
} }
} }
else { else {
m_slot->m_dmr->tsccActivateSlot(slot, dstId, grp, false); m_slot->m_dmr->tsccActivateSlot(slot, dstId, srcId, grp, false);
} }
std::unique_ptr<CSBK_PD_GRANT> csbk = new_unique(CSBK_PD_GRANT);
csbk->setLogicalCh1(chNo);
csbk->setSlotNo(slot - 1U);
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_DATA_CALL (Individual Data Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
m_tscc->m_slotNo, emergency, privacy, broadcast, priority, csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId);
}
csbk->setEmergency(emergency);
csbk->setSrcId(srcId);
csbk->setDstId(dstId);
// transmit private grant (x2)
for (uint8_t i = 0; i < 2U; i++)
writeRF_CSBK(csbk.get());
} }
return true; return true;
@ -1219,9 +1225,8 @@ void ControlSignaling::writeRF_CSBK_U_Reg_Rsp(uint32_t srcId, uint8_t serviceOpt
writeRF_CSBK(csbk.get()); writeRF_CSBK(csbk.get());
} }
/// <summary> /// <summary>
/// Helper to write a grant packet. /// Helper to write a TSCC late entry channel grant packet on the RF interface.
/// </summary> /// </summary>
/// <param name="dstId"></param> /// <param name="dstId"></param>
/// <param name="srcId"></param> /// <param name="srcId"></param>
@ -1234,11 +1239,50 @@ void ControlSignaling::writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t src
std::unique_ptr<CSBK_TV_GRANT> csbk = new_unique(CSBK_TV_GRANT); std::unique_ptr<CSBK_TV_GRANT> csbk = new_unique(CSBK_TV_GRANT);
csbk->setLogicalCh1(chNo); csbk->setLogicalCh1(chNo);
csbk->setSlotNo(slot - 1U); csbk->setSlotNo(slot);
csbk->setSrcId(srcId);
csbk->setDstId(dstId);
writeRF_CSBK(csbk.get());
}
/// <summary>
/// Helper to write a payload grant to a TSCC payload channel on the RF interface.
/// </summary>
/// <param name="dstId"></param>
/// <param name="srcId"></param>
void ControlSignaling::writeRF_CSBK_Payload_Grant(uint32_t dstId, uint32_t srcId, bool grp, bool voice)
{
std::unique_ptr<CSBK_P_GRANT> csbk = new_unique(CSBK_P_GRANT);
if (voice) {
if (grp) {
csbk->setCSBKO(CSBKO_TV_GRANT);
}
else {
csbk->setCSBKO(CSBKO_PV_GRANT);
}
}
else {
if (grp) {
csbk->setCSBKO(CSBKO_TD_GRANT);
}
else {
csbk->setCSBKO(CSBKO_PD_GRANT);
}
}
csbk->setLogicalCh1(m_slot->m_channelNo);
csbk->setSlotNo(m_slot->m_slotNo);
csbk->setSrcId(srcId); csbk->setSrcId(srcId);
csbk->setDstId(dstId); csbk->setDstId(dstId);
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBK_P_GRANT (Payload Grant), chNo = %u, slot = %u, srcId = %u, dstId = %u",
m_slot->m_slotNo, csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId);
}
writeRF_CSBK(csbk.get()); writeRF_CSBK(csbk.get());
} }

@ -103,6 +103,8 @@ namespace dmr
/// <summary>Helper to write a TSCC late entry channel grant packet on the RF interface.</summary> /// <summary>Helper to write a TSCC late entry channel grant packet on the RF interface.</summary>
void writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t srcId); void writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t srcId);
/// <summary>Helper to write a payload grant to a TSCC payload channel on the RF interface.</summary>
void writeRF_CSBK_Payload_Grant(uint32_t dstId, uint32_t srcId, bool grp, bool voice);
/// <summary>Helper to write a TSCC Aloha broadcast packet on the RF interface.</summary> /// <summary>Helper to write a TSCC Aloha broadcast packet on the RF interface.</summary>
void writeRF_TSCC_Aloha(); void writeRF_TSCC_Aloha();

@ -1432,6 +1432,12 @@ void RESTAPI::restAPI_PutTSCCPayloadActivate(const HTTPPayload& request, HTTPPay
return; return;
} }
// validate destination ID is a integer within the JSON blob
if (!req["srcId"].is<uint32_t>()) {
errorPayload(reply, "source ID was not valid");
return;
}
// validate group flag is a boolean within the JSON blob // validate group flag is a boolean within the JSON blob
if (!req["group"].is<bool>()) { if (!req["group"].is<bool>()) {
errorPayload(reply, "group flag was not valid"); errorPayload(reply, "group flag was not valid");
@ -1445,6 +1451,7 @@ void RESTAPI::restAPI_PutTSCCPayloadActivate(const HTTPPayload& request, HTTPPay
} }
uint32_t dstId = req["dstId"].get<uint32_t>(); uint32_t dstId = req["dstId"].get<uint32_t>();
uint32_t srcId = req["srcId"].get<uint32_t>();
bool group = req["group"].get<bool>(); bool group = req["group"].get<bool>();
bool voice = req["voice"].get<bool>(); bool voice = req["voice"].get<bool>();
@ -1453,7 +1460,7 @@ void RESTAPI::restAPI_PutTSCCPayloadActivate(const HTTPPayload& request, HTTPPay
return; return;
} }
m_dmr->tsccActivateSlot(slot, dstId, group, voice); m_dmr->tsccActivateSlot(slot, dstId, srcId, group, voice);
} }
#else #else
errorPayload(reply, "DMR operations are unavailable", HTTPPayload::SERVICE_UNAVAILABLE); errorPayload(reply, "DMR operations are unavailable", HTTPPayload::SERVICE_UNAVAILABLE);

Loading…
Cancel
Save

Powered by TurnKey Linux.