implement proper DMR NACK CSBK encoding; implement preliminary DMR grant support for individual and talkgroup calls;

2.0-maint
Bryan Biedenkapp 3 years ago
parent 07045c6b56
commit 4afaf6400d

@ -243,6 +243,7 @@ namespace dmr
const uint8_t TS_DENY_RSN_REG_REFUSED = 0x2AU;
const uint8_t TS_DENY_RSN_REG_DENIED = 0x2BU;
const uint8_t TS_DENY_RSN_MS_NOT_REG = 0x2DU;
const uint8_t TS_DENY_RSN_TGT_BUSY = 0x2EU;
const uint8_t TS_DENY_RSN_TGT_GROUP_NOT_VALID = 0x2FU;
const uint8_t MS_DENY_RSN_UNSUPPORTED_SVC = 0x00U;
@ -296,6 +297,8 @@ namespace dmr
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_PD_GRANT = 0x33U; // PD_GRANT - Private Data Channel Grant
const uint8_t CSBKO_TD_GRANT = 0x34U; // TD_GRANT - Talkgroup Data Channel Grant
const uint8_t CSBKO_BSDWNACT = 0x38U; // BS DWN ACT - BS Outbound Activation
const uint8_t CSBKO_PRECCSBK = 0x3DU; // PRE CSBK - Preamble CSBK

@ -106,8 +106,12 @@ bool AccessControl::validateTGId(uint32_t slotNo, uint32_t id)
if (tid.tgSlot() == 0)
return true; // TG Slot of 0 for the talkgroup entry means both
if (slotNo != 0) {
if (tid.tgSlot() != slotNo)
return false;
return true;
} else {
return true;
}
}

@ -244,7 +244,8 @@ void CSBK::encode(uint8_t* data)
csbkValue = (m_GI ? 0x40U : 0x00U) + // Source Type
(m_siteData.siteId() & 0x3FU); // Net + Site LSB
}
csbkValue = (csbkValue << 7) + (m_reason & 0xFFU); // Reason Code
csbkValue = (csbkValue << 7) + (m_response & 0x7FU); // Response Information
csbkValue = (csbkValue << 8) + (m_reason & 0xFFU); // Reason Code
csbkValue = (csbkValue << 25) + m_dstId; // Target Radio Address
csbkValue = (csbkValue << 24) + m_srcId; // Source Radio Address
break;
@ -270,7 +271,7 @@ void CSBK::encode(uint8_t* data)
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_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
@ -282,7 +283,29 @@ void CSBK::encode(uint8_t* data)
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_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
break;
case CSBKO_PD_GRANT:
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; // 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
break;
case CSBKO_TD_GRANT:
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; // 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

@ -70,42 +70,48 @@ using namespace dmr::packet;
#define IS_SUPPORT_CONTROL_CHECK(_PCKT_STR, _PCKT, _SRCID) \
if (!m_slot->m_dmr->getTSCCSlot()->m_enableTSCC) { \
LogWarning(LOG_RF, "DMR Slot %u, " _PCKT_STR " denial, unsupported service, srcId = %u", m_slot->m_slotNo, _SRCID); \
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_SYS_UNSUPPORTED_SVC, _PCKT); \
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_SYS_UNSUPPORTED_SVC, 0U); \
return false; \
}
// Validate the source RID.
#define VALID_SRCID(_PCKT_STR, _PCKT, _SRCID, _RSN) \
#define VALID_SRCID(_PCKT_STR, _PCKT, _SRCID) \
if (!acl::AccessControl::validateSrcId(_SRCID)) { \
LogWarning(LOG_RF, "DMR Slot %u, " _PCKT_STR " denial, RID rejection, srcId = %u", m_slot->m_slotNo, _SRCID); \
writeRF_CSBK_ACK_RSP(_RSN, _PCKT); \
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_PERM_USER_REFUSED, 0U); \
return false; \
}
// Validate the target RID.
#define VALID_DSTID(_PCKT_STR, _PCKT, _DSTID, _RSN) \
#define VALID_DSTID(_PCKT_STR, _PCKT, _DSTID) \
if (!acl::AccessControl::validateSrcId(_DSTID)) { \
LogWarning(LOG_RF, "DMR Slot %u, " _PCKT_STR " denial, RID rejection, dstId = %u", m_slot->m_slotNo, _DSTID); \
writeRF_CSBK_ACK_RSP(_RSN, _PCKT); \
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TEMP_USER_REFUSED, 0U); \
return false; \
}
// Validate the talkgroup ID.
#define VALID_TGID(_PCKT_STR, _PCKT, _DSTID, _RSN) \
if (!acl::AccessControl::validateTGId(_DSTID)) { \
#define VALID_TGID(_PCKT_STR, _PCKT, _DSTID) \
if (!acl::AccessControl::validateTGId(0U, _DSTID)) { \
LogWarning(LOG_RF, "DMR Slot %u, " _PCKT_STR " denial, TGID rejection, dstId = %u", m_slot->m_slotNo, _DSTID); \
writeRF_CSBK_ACK_RSP(_RSN, _PCKT); \
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TGT_GROUP_NOT_VALID, 0U); \
return false; \
}
// Verify the source RID is registered.
#define VERIFY_SRCID_REG(_PCKT_STR, _PCKT, _SRCID, _RSN) \
#define VERIFY_SRCID_REG(_PCKT_STR, _PCKT, _SRCID) \
if (!m_slot->m_affiliations->isUnitReg(_SRCID) && m_slot->m_verifyReg) { \
LogWarning(LOG_RF, "DMR Slot %u, " _PCKT_STR " denial, RID not registered, srcId = %u", m_slot->m_slotNo, _SRCID); \
writeRF_CSBK_ACK_RSP(_RSN, _PCKT); \
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_PERM_USER_REFUSED, 0U); \
return false; \
}
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t GRANT_TIMER_TIMEOUT = 15U;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
@ -189,24 +195,66 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len)
handled = true;
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), emerg = %u, prio = %u, serviceKind = $%02X, serviceOptions = $%02X, serviceExtra = $%02X, srcId = %u, dstId = %u",
m_slot->m_slotNo, csbk.getEmergency(), csbk.getPriority(), csbk.getServiceKind(), csbk.getServiceOptions(), csbk.getServiceExtra(), csbk.getSrcId(), csbk.getDstId());
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), serviceKind = $%02X, serviceOptions = $%02X, serviceExtra = $%02X, srcId = %u, dstId = %u",
m_slot->m_slotNo, csbk.getServiceKind(), csbk.getServiceOptions(), csbk.getServiceExtra(), csbk.getSrcId(), csbk.getDstId());
}
switch (csbk.getServiceKind()) {
case SVC_KIND_IND_VOICE_CALL:
// TODO TODO TODO
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, srcId);
// validate the source RID
VALID_SRCID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, srcId);
// validate the target RID
VALID_DSTID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, dstId);
// verify the source RID is registered
VERIFY_SRCID_REG("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, srcId);
writeRF_CSBK_Grant(srcId, dstId, csbk.getServiceOptions(), false);
break;
case SVC_KIND_GRP_VOICE_CALL:
// TODO TODO TODO
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call)", SVC_KIND_GRP_VOICE_CALL, srcId);
// validate the source RID
VALID_SRCID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call)", SVC_KIND_GRP_VOICE_CALL, srcId);
// validate the talkgroup ID
VALID_TGID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call)", SVC_KIND_GRP_VOICE_CALL, dstId);
writeRF_CSBK_Grant(srcId, dstId, csbk.getServiceOptions(), true);
break;
case SVC_KIND_IND_DATA_CALL:
case SVC_KIND_IND_UDT_DATA_CALL:
// TODO TODO TODO
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, srcId);
// validate the source RID
VALID_SRCID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, srcId);
// validate the target RID
VALID_DSTID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, dstId);
// verify the source RID is registered
VERIFY_SRCID_REG("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call)", SVC_KIND_IND_VOICE_CALL, srcId);
writeRF_CSBK_Data_Grant(srcId, dstId, csbk.getServiceOptions(), false);
break;
case SVC_KIND_GRP_DATA_CALL:
case SVC_KIND_GRP_UDT_DATA_CALL:
// TODO TODO TODO
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call)", SVC_KIND_GRP_VOICE_CALL, srcId);
// validate the source RID
VALID_SRCID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call)", SVC_KIND_GRP_VOICE_CALL, srcId);
// validate the talkgroup ID
VALID_TGID("DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call)", SVC_KIND_GRP_VOICE_CALL, dstId);
writeRF_CSBK_Data_Grant(srcId, dstId, csbk.getServiceOptions(), true);
break;
case SVC_KIND_REG_SVC:
// make sure control data is supported
@ -360,8 +408,8 @@ void ControlSignaling::processNetwork(const data::Data & dmrData)
::ActivityLog("DMR", false, "Slot %u call alert request from %u to %u", m_slot->m_slotNo, srcId, dstId);
} else {
if (m_verbose) {
LogMessage(LOG_NET, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), emerg = %u, prio = %u, serviceKind = $%02X, serviceOptions = $%02X, serviceExtra = $%02X, srcId = %u, dstId = %u",
m_slot->m_slotNo, csbk.getEmergency(), csbk.getPriority(), csbk.getServiceKind(), csbk.getServiceOptions(), csbk.getServiceExtra(), csbk.getSrcId(), csbk.getDstId());
LogMessage(LOG_NET, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), serviceKind = $%02X, serviceOptions = $%02X, serviceExtra = $%02X, srcId = %u, dstId = %u",
m_slot->m_slotNo, csbk.getServiceKind(), csbk.getServiceOptions(), csbk.getServiceExtra(), csbk.getSrcId(), csbk.getDstId());
}
}
break;
@ -618,19 +666,346 @@ void ControlSignaling::writeRF_CSBK(lc::CSBK csbk, bool clearBeforeWrite)
/// Helper to write a deny packet.
/// </summary>
/// <param name="reason"></param>
/// <param name="service"></param>
void ControlSignaling::writeRF_CSBK_ACK_RSP(uint8_t reason, uint8_t service)
/// <param name="responseInfo"></param>
void ControlSignaling::writeRF_CSBK_ACK_RSP(uint8_t reason, uint8_t responseInfo)
{
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_ACK_RSP);
csbk.setFID(FID_ETSI);
csbk.setResponse(responseInfo);
csbk.setReason(reason);
writeRF_CSBK(csbk);
}
/// <summary>
/// Helper to write a deny packet.
/// </summary>
/// <param name="reason"></param>
/// <param name="service"></param>
void ControlSignaling::writeRF_CSBK_NACK_RSP(uint8_t reason, uint8_t service)
{
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_NACK_RSP);
csbk.setFID(FID_ETSI);
csbk.setServiceKind(service);
csbk.setReason(reason);
writeRF_CSBK(csbk);
}
/// <summary>
/// Helper to write a grant packet.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
/// <param name="serviceOptions"></param>
/// <param name="grp"></param>
/// <param name="skip"></param>
/// <param name="net"></param>
/// <param name="skipNetCheck"></param>
/// <returns></returns>
bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOptions, bool grp, bool skip, bool net, bool skipNetCheck)
{
Slot *m_tscc = m_slot->m_dmr->getTSCCSlot();
bool emergency = ((serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool privacy = ((serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Privacy Flag
bool broadcast = ((serviceOptions & 0xFFU) & 0x10U) == 0x10U; // Broadcast Flag
uint8_t priority = ((serviceOptions & 0xFFU) & 0x03U); // Priority
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setFID(FID_ETSI);
if (dstId == DMR_WUID_ALL) {
return true; // do not generate grant packets for $FFFF (All Call) TGID
}
// do we have a network connection and are we handling grants at the network?
if (m_tscc->m_network != NULL) {
if (m_tscc->m_network->isHandlingChGrants() && m_tscc->m_siteData.netActive() && !skipNetCheck) {
return m_tscc->m_network->writeGrantReq(grp, srcId, dstId);
}
}
// are we skipping checking?
if (!skip) {
if (m_slot->m_rfState != RS_RF_LISTENING && m_slot->m_rfState != RS_RF_DATA) {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_VOICE_CALL (Voice Call) denied, traffic in progress, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u denied", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
if (m_slot->m_netState != RS_NET_IDLE && dstId == m_slot->m_netLastDstId) {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_VOICE_CALL (Voice Call) denied, traffic in progress, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u denied", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
// don't transmit grants if the destination ID's don't match and the network TG hang timer is running
if (m_slot->m_rfLastDstId != 0U) {
if (m_slot->m_rfLastDstId != dstId && (m_slot->m_rfTGHang.isRunning() && !m_slot->m_rfTGHang.hasExpired())) {
if (!net) {
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
}
if (!m_tscc->m_affiliations->isGranted(dstId)) {
if (!m_tscc->m_affiliations->isRFChAvailable()) {
if (grp) {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call) queued, no channels available, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_SYS_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u queued", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
else {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call) queued, no channels available, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_SYS_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u queued", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
}
else {
if (m_tscc->m_affiliations->grantCh(dstId, GRANT_TIMER_TIMEOUT)) {
uint32_t chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
csbk.setLogicalCh1(chNo);
csbk.setSlotNo(0U);
//m_tscc->m_siteData.setChCnt(m_tscc->m_affiliations->getRFChCnt() + m_tscc->m_affiliations->getGrantedRFChCnt());
}
}
}
else {
uint32_t chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
csbk.setLogicalCh1(chNo);
csbk.setSlotNo(0U);
m_tscc->m_affiliations->touchGrant(dstId);
}
}
if (grp) {
if (!net) {
::ActivityLog("DMR", true, "Slot %u group grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
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",
m_tscc->m_slotNo, emergency, privacy, broadcast, priority, csbk.getLogicalCh1(), csbk.getSlotNo(), srcId, dstId);
}
// transmit group grant
csbk.setCSBKO(CSBKO_TV_GRANT);
if (broadcast)
csbk.setCSBKO(CSBKO_BTV_GRANT);
csbk.setSrcId(srcId);
csbk.setDstId(dstId);
csbk.setEmergency(emergency);
writeRF_CSBK(csbk);
}
else {
if (!net) {
::ActivityLog("DMR", true, "Slot %u individual grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
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",
m_tscc->m_slotNo, emergency, privacy, broadcast, priority, csbk.getLogicalCh1(), csbk.getSlotNo(), srcId, dstId);
}
// transmit private grant
csbk.setCSBKO(CSBKO_PV_GRANT);
csbk.setSrcId(srcId);
csbk.setDstId(dstId);
csbk.setEmergency(emergency);
writeRF_CSBK(csbk);
}
return true;
}
/// <summary>
/// Helper to write a data grant packet.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
/// <param name="serviceOptions"></param>
/// <param name="grp"></param>
/// <param name="skip"></param>
/// <param name="net"></param>
/// <returns></returns>
bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOptions, bool grp, bool skip, bool net)
{
Slot *m_tscc = m_slot->m_dmr->getTSCCSlot();
bool emergency = ((serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool privacy = ((serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Privacy Flag
bool broadcast = ((serviceOptions & 0xFFU) & 0x10U) == 0x10U; // Broadcast Flag
uint8_t priority = ((serviceOptions & 0xFFU) & 0x03U); // Priority
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setFID(FID_ETSI);
if (dstId == DMR_WUID_ALL) {
return true; // do not generate grant packets for $FFFF (All Call) TGID
}
// are we skipping checking?
if (!skip) {
if (m_slot->m_rfState != RS_RF_LISTENING && m_slot->m_rfState != RS_RF_DATA) {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_DATA_CALL (Data Call) denied, traffic in progress, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u denied", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
if (m_slot->m_netState != RS_NET_IDLE && dstId == m_slot->m_netLastDstId) {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_DATA_CALL (Data Call) denied, traffic in progress, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u denied", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
// don't transmit grants if the destination ID's don't match and the network TG hang timer is running
if (m_slot->m_rfLastDstId != 0U) {
if (m_slot->m_rfLastDstId != dstId && (m_slot->m_rfTGHang.isRunning() && !m_slot->m_rfTGHang.hasExpired())) {
if (!net) {
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_TGT_BUSY, (grp) ? 1U : 0U);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
}
if (!m_tscc->m_affiliations->isGranted(dstId)) {
if (!m_tscc->m_affiliations->isRFChAvailable()) {
if (grp) {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_DATA_CALL (Group Data Call) queued, no channels available, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_SYS_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u queued", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
else {
if (!net) {
LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_DATA_CALL (Individual Data Call) queued, no channels available, dstId = %u", m_tscc->m_slotNo, dstId);
writeRF_CSBK_ACK_RSP(TS_DENY_RSN_SYS_BUSY, (grp) ? 1U : 0U);
::ActivityLog("DMR", true, "Slot %u group grant request %u to TG %u queued", m_tscc->m_slotNo, srcId, dstId);
m_slot->m_rfState = RS_RF_REJECTED;
}
return false;
}
}
else {
if (m_tscc->m_affiliations->grantCh(dstId, GRANT_TIMER_TIMEOUT)) {
uint32_t chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
csbk.setLogicalCh1(chNo);
csbk.setSlotNo(0U);
//m_tscc->m_siteData.setChCnt(m_tscc->m_affiliations->getRFChCnt() + m_tscc->m_affiliations->getGrantedRFChCnt());
}
}
}
else {
uint32_t chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
csbk.setLogicalCh1(chNo);
csbk.setSlotNo(0U);
m_tscc->m_affiliations->touchGrant(dstId);
}
}
if (grp) {
if (!net) {
::ActivityLog("DMR", true, "Slot %u group grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
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);
}
// transmit group grant
csbk.setCSBKO(CSBKO_TD_GRANT);
csbk.setSrcId(srcId);
csbk.setDstId(dstId);
csbk.setEmergency(emergency);
writeRF_CSBK(csbk);
}
else {
if (!net) {
::ActivityLog("DMR", true, "Slot %u individual grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
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);
}
// transmit private grant
csbk.setCSBKO(CSBKO_PD_GRANT);
csbk.setSrcId(srcId);
csbk.setDstId(dstId);
csbk.setEmergency(emergency);
writeRF_CSBK(csbk);
}
return true;
}
/// <summary>
/// Helper to write a unit registration response packet.
/// </summary>

@ -91,7 +91,13 @@ namespace dmr
void writeRF_CSBK(lc::CSBK csbk, bool clearBeforeWrite = false);
/// <summary>Helper to write a ACK RSP packet.</summary>
void writeRF_CSBK_ACK_RSP(uint8_t reason, uint8_t service);
void writeRF_CSBK_ACK_RSP(uint8_t reason, uint8_t responseInfo);
/// <summary>Helper to write a NACK RSP packet.</summary>
void writeRF_CSBK_NACK_RSP(uint8_t reason, uint8_t service);
/// <summary>Helper to write a grant packet.</summary>
bool writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOptions, bool grp, bool skip = false, bool net = false, bool skipNetCheck = false);
/// <summary>Helper to write a data grant packet.</summary>
bool writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOptions, bool grp, bool skip = false, bool net = false);
/// <summary>Helper to write a unit registration response packet.</summary>
void writeRF_CSBK_U_Reg_Rsp(uint32_t srcId, uint8_t serviceOptions);

Loading…
Cancel
Save

Powered by TurnKey Linux.