implement initial DMR remote grant demand logic (this is mostly untested);

4.11f_maint
Bryan Biedenkapp 11 months ago
parent aedabceac7
commit 151275ce6f

@ -129,8 +129,14 @@ protocols:
# Flag indicating whether or not the source ID validation before granting disabled. # Flag indicating whether or not the source ID validation before granting disabled.
disableGrantSourceIdCheck: false disableGrantSourceIdCheck: false
# Flag indicating whether or not network calls will generate a channel grant.
# (This applies only in conventional operations where channel granting is utilized and RF-only talkgroup
# steering is required.)
disableNetworkGrant: false
# Flag indicating whether or not a TGID will be tested for affiliations before being granted. # Flag indicating whether or not a TGID will be tested for affiliations before being granted.
ignoreAffiliationCheck: false ignoreAffiliationCheck: false
# Flag indicating the host should send a network grant demand for conventional traffic.
convNetGrantDemand: false
# Flag indicating whether or not received RF embedded LC data only should be transmitted. # Flag indicating whether or not received RF embedded LC data only should be transmitted.
embeddedLCOnly: false embeddedLCOnly: false
# Flag indicating whether talker alias data should be dumped to the log. # Flag indicating whether talker alias data should be dumped to the log.

@ -1687,6 +1687,11 @@ void HostBridge::encodeDMRAudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
dmrData.setSrcId(srcId); dmrData.setSrcId(srcId);
dmrData.setDstId(dstId); dmrData.setDstId(dstId);
dmrData.setFLCO(FLCO::GROUP); dmrData.setFLCO(FLCO::GROUP);
if (m_grantDemand) {
dmrData.setControl(0x80U); // DMR remote grant demand flag
} else {
dmrData.setControl(0U);
}
dmrData.setN(m_dmrN); dmrData.setN(m_dmrN);
dmrData.setSeqNo(m_dmrSeqNo); dmrData.setSeqNo(m_dmrSeqNo);
dmrData.setBER(0U); dmrData.setBER(0U);

@ -30,6 +30,7 @@ NetData::NetData(const NetData& data) :
m_srcId(data.m_srcId), m_srcId(data.m_srcId),
m_dstId(data.m_dstId), m_dstId(data.m_dstId),
m_flco(data.m_flco), m_flco(data.m_flco),
m_control(data.m_control),
m_n(data.m_n), m_n(data.m_n),
m_seqNo(data.m_seqNo), m_seqNo(data.m_seqNo),
m_dataType(data.m_dataType), m_dataType(data.m_dataType),
@ -48,6 +49,7 @@ NetData::NetData() :
m_srcId(0U), m_srcId(0U),
m_dstId(0U), m_dstId(0U),
m_flco(FLCO::GROUP), m_flco(FLCO::GROUP),
m_control(0U),
m_n(0U), m_n(0U),
m_seqNo(0U), m_seqNo(0U),
m_dataType(DataType::IDLE), m_dataType(DataType::IDLE),
@ -76,6 +78,7 @@ NetData& NetData::operator=(const NetData& data)
m_srcId = data.m_srcId; m_srcId = data.m_srcId;
m_dstId = data.m_dstId; m_dstId = data.m_dstId;
m_flco = data.m_flco; m_flco = data.m_flco;
m_control = data.m_control;
m_dataType = data.m_dataType; m_dataType = data.m_dataType;
m_seqNo = data.m_seqNo; m_seqNo = data.m_seqNo;
m_n = data.m_n; m_n = data.m_n;

@ -85,6 +85,11 @@ namespace dmr
*/ */
__PROPERTY(defines::FLCO::E, flco, FLCO); __PROPERTY(defines::FLCO::E, flco, FLCO);
/**
* @brief
*/
__PROPERTY(uint8_t, control, Control);
/** /**
* @brief * @brief
*/ */

@ -742,7 +742,7 @@ UInt8Array BaseNetwork::createDMR_Message(uint32_t& length, const uint32_t strea
uint32_t slotNo = data.getSlotNo(); uint32_t slotNo = data.getSlotNo();
buffer[14U] = 0U; // Control Bits buffer[14U] = data.getControl(); // Control Bits
// Individual slot disabling // Individual slot disabling
if (slotNo == 1U && !m_slot1) { if (slotNo == 1U && !m_slot1) {

@ -176,6 +176,18 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, ::lookups::VoiceChDa
m_slot1->m_ignoreAffiliationCheck = ignoreAffiliationCheck; m_slot1->m_ignoreAffiliationCheck = ignoreAffiliationCheck;
m_slot2->m_ignoreAffiliationCheck = ignoreAffiliationCheck; m_slot2->m_ignoreAffiliationCheck = ignoreAffiliationCheck;
/*
** Network Grant Disables
*/
bool disableNetworkGrant = dmrProtocol["disableNetworkGrant"].as<bool>(false);
m_slot1->m_disableNetworkGrant = disableNetworkGrant;
m_slot2->m_disableNetworkGrant = disableNetworkGrant;
bool convNetGrantDemand = dmrProtocol["convNetGrantDemand"].as<bool>(false);
m_slot1->m_convNetGrantDemand = convNetGrantDemand;
m_slot2->m_convNetGrantDemand = convNetGrantDemand;
if (printOptions) { if (printOptions) {
if (enableTSCC) { if (enableTSCC) {
LogInfo(" TSCC Slot: %u", m_tsccSlotNo); LogInfo(" TSCC Slot: %u", m_tsccSlotNo);
@ -185,6 +197,9 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, ::lookups::VoiceChDa
LogInfo(" TSCC Disable Grant Source ID Check: yes"); LogInfo(" TSCC Disable Grant Source ID Check: yes");
} }
} }
if (disableNetworkGrant) {
LogInfo(" Disable Network Grants: yes");
}
LogInfo(" Ignore Affiliation Check: %s", ignoreAffiliationCheck ? "yes" : "no"); LogInfo(" Ignore Affiliation Check: %s", ignoreAffiliationCheck ? "yes" : "no");
LogInfo(" Notify Control: %s", notifyCC ? "yes" : "no"); LogInfo(" Notify Control: %s", notifyCC ? "yes" : "no");
@ -192,6 +207,7 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, ::lookups::VoiceChDa
LogInfo(" Frame Loss Threshold: %u", frameLossThreshold); LogInfo(" Frame Loss Threshold: %u", frameLossThreshold);
LogInfo(" Verify Registration: %s", Slot::m_verifyReg ? "yes" : "no"); LogInfo(" Verify Registration: %s", Slot::m_verifyReg ? "yes" : "no");
LogInfo(" Conventional Network Grant Demand: %s", convNetGrantDemand ? "yes" : "no");
} }
} }
@ -660,6 +676,8 @@ void Control::processNetwork()
uint32_t srcId = __GET_UINT16(buffer, 5U); uint32_t srcId = __GET_UINT16(buffer, 5U);
uint32_t dstId = __GET_UINT16(buffer, 8U); uint32_t dstId = __GET_UINT16(buffer, 8U);
uint8_t controlByte = buffer[14U];
FLCO::E flco = (buffer[15U] & 0x40U) == 0x40U ? FLCO::PRIVATE : FLCO::GROUP; FLCO::E flco = (buffer[15U] & 0x40U) == 0x40U ? FLCO::PRIVATE : FLCO::GROUP;
uint32_t slotNo = (buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; uint32_t slotNo = (buffer[15U] & 0x80U) == 0x80U ? 2U : 1U;
@ -691,6 +709,8 @@ void Control::processNetwork()
data.setDstId(dstId); data.setDstId(dstId);
data.setFLCO(flco); data.setFLCO(flco);
data.setControl(controlByte);
bool dataSync = (buffer[15U] & 0x20U) == 0x20U; bool dataSync = (buffer[15U] & 0x20U) == 0x20U;
bool voiceSync = (buffer[15U] & 0x10U) == 0x10U; bool voiceSync = (buffer[15U] & 0x10U) == 0x10U;

@ -152,6 +152,8 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_enableTSCC(false), m_enableTSCC(false),
m_dedicatedTSCC(false), m_dedicatedTSCC(false),
m_ignoreAffiliationCheck(false), m_ignoreAffiliationCheck(false),
m_disableNetworkGrant(false),
m_convNetGrantDemand(false),
m_tsccPayloadDstId(0U), m_tsccPayloadDstId(0U),
m_tsccPayloadSrcId(0U), m_tsccPayloadSrcId(0U),
m_tsccPayloadGroup(false), m_tsccPayloadGroup(false),
@ -426,9 +428,54 @@ void Slot::processNetwork(const data::NetData& dmrData)
DataType::E dataType = dmrData.getDataType(); DataType::E dataType = dmrData.getDataType();
// ignore non-CSBK data destined for the TSCC slot // ignore non-CSBK data destined for the TSCC slot
if (m_enableTSCC && m_dedicatedTSCC && m_slotNo == m_dmr->m_tsccSlotNo && if (m_enableTSCC && m_dedicatedTSCC && m_slotNo == m_dmr->m_tsccSlotNo) {
dataType != DataType::CSBK) { switch (dataType)
return; {
case DataType::CSBK:
break;
case DataType::VOICE_LC_HEADER:
case DataType::DATA_HEADER:
{
bool grantDemand = (dmrData.getControl() & 0x80U) == 0x80U;
bool unitToUnit = (dmrData.getControl() & 0x01U) == 0x01U;
if (grantDemand) {
if (m_disableNetworkGrant) {
return;
}
// if we're non-dedicated control, and if we're not in a listening or idle state, ignore any grant
// demands
if (!m_dedicatedTSCC && (m_rfState != RS_RF_LISTENING || m_netState != RS_NET_IDLE)) {
return;
}
// validate source RID
if (!acl::AccessControl::validateSrcId(dmrData.getSrcId())) {
return;
}
// validate the target ID, if the target is a talkgroup
if (!acl::AccessControl::validateTGId(dmrData.getSlotNo(), dmrData.getDstId())) {
return;
}
if (m_verbose) {
LogMessage(LOG_NET, "DMR Slot %u, remote grant demand, srcId = %u, dstId = %u, unitToUnit = %u",
m_slotNo, dmrData.getSrcId(), dmrData.getDstId(), unitToUnit);
}
// perform grant response logic
if (dataType == DataType::VOICE_LC_HEADER)
m_control->writeRF_CSBK_Grant(dmrData.getSrcId(), dmrData.getDstId(), 4U, !unitToUnit, true);
if (dataType == DataType::DATA_HEADER)
m_control->writeRF_CSBK_Data_Grant(dmrData.getSrcId(), dmrData.getDstId(), 4U, !unitToUnit, true);
}
}
return;
default:
return;
}
} }
switch (dataType) switch (dataType)
@ -1203,18 +1250,18 @@ void Slot::notifyCC_TouchGrant(uint32_t dstId)
/* Write data frame to the network. */ /* Write data frame to the network. */
void Slot::writeNetwork(const uint8_t* data, DataType::E dataType, uint8_t errors, bool noSequence) void Slot::writeNetwork(const uint8_t* data, DataType::E dataType, uint8_t control, uint8_t errors, bool noSequence)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(m_rfLC != nullptr); assert(m_rfLC != nullptr);
writeNetwork(data, dataType, m_rfLC->getFLCO(), m_rfLC->getSrcId(), m_rfLC->getDstId(), errors); writeNetwork(data, dataType, m_rfLC->getFLCO(), m_rfLC->getSrcId(), m_rfLC->getDstId(), control, errors);
} }
/* Write data frame to the network. */ /* Write data frame to the network. */
void Slot::writeNetwork(const uint8_t* data, DataType::E dataType, FLCO::E flco, uint32_t srcId, void Slot::writeNetwork(const uint8_t* data, DataType::E dataType, FLCO::E flco, uint32_t srcId,
uint32_t dstId, uint8_t errors, bool noSequence) uint32_t dstId, uint8_t control, uint8_t errors, bool noSequence)
{ {
assert(data != nullptr); assert(data != nullptr);
@ -1230,6 +1277,7 @@ void Slot::writeNetwork(const uint8_t* data, DataType::E dataType, FLCO::E flco,
dmrData.setSrcId(srcId); dmrData.setSrcId(srcId);
dmrData.setDstId(dstId); dmrData.setDstId(dstId);
dmrData.setFLCO(flco); dmrData.setFLCO(flco);
dmrData.setControl(control);
dmrData.setN(m_voice->m_rfN); dmrData.setN(m_voice->m_rfN);
dmrData.setSeqNo(m_rfSeqNo); dmrData.setSeqNo(m_rfSeqNo);
dmrData.setBER(errors); dmrData.setBER(errors);

@ -384,6 +384,8 @@ namespace dmr
bool m_enableTSCC; bool m_enableTSCC;
bool m_dedicatedTSCC; bool m_dedicatedTSCC;
bool m_ignoreAffiliationCheck; bool m_ignoreAffiliationCheck;
bool m_disableNetworkGrant;
bool m_convNetGrantDemand;
uint32_t m_tsccPayloadDstId; uint32_t m_tsccPayloadDstId;
uint32_t m_tsccPayloadSrcId; uint32_t m_tsccPayloadSrcId;
@ -488,10 +490,11 @@ namespace dmr
* @brief Write data frame to the network. * @brief Write data frame to the network.
* @param[in] data Buffer containing frame data to write to the network. * @param[in] data Buffer containing frame data to write to the network.
* @param dataType DMR Data Type for this frame. * @param dataType DMR Data Type for this frame.
* @param control Control Byte.
* @param errors Number of bit errors detected for this frame. * @param errors Number of bit errors detected for this frame.
* @param noSequence Flag indicating this frame carries no sequence number. * @param noSequence Flag indicating this frame carries no sequence number.
*/ */
void writeNetwork(const uint8_t* data, defines::DataType::E dataType, uint8_t errors = 0U, bool noSequence = false); void writeNetwork(const uint8_t* data, defines::DataType::E dataType, uint8_t control, uint8_t errors = 0U, bool noSequence = false);
/** /**
* @brief Write data frame to the network. * @brief Write data frame to the network.
* @param[in] data Buffer containing frame data to write to the network. * @param[in] data Buffer containing frame data to write to the network.
@ -499,11 +502,12 @@ namespace dmr
* @param flco Full-Link Control Opcode. * @param flco Full-Link Control Opcode.
* @param srcId Source Radio ID. * @param srcId Source Radio ID.
* @param dstId Destination ID. * @param dstId Destination ID.
* @param control Control Byte.
* @param errors Number of bit errors detected for this frame. * @param errors Number of bit errors detected for this frame.
* @param noSequence Flag indicating this frame carries no sequence number. * @param noSequence Flag indicating this frame carries no sequence number.
*/ */
void writeNetwork(const uint8_t* data, defines::DataType::E dataType, defines::FLCO::E flco, uint32_t srcId, void writeNetwork(const uint8_t* data, defines::DataType::E dataType, defines::FLCO::E flco, uint32_t srcId,
uint32_t dstId, uint8_t errors = 0U, bool noSequence = false); uint32_t dstId, uint8_t control, uint8_t errors = 0U, bool noSequence = false);
/** /**
* @brief Helper to write RF end of frame data. * @brief Helper to write RF end of frame data.

@ -379,7 +379,7 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len)
if (m_slot->m_duplex) if (m_slot->m_duplex)
m_slot->addFrame(data); m_slot->addFrame(data);
m_slot->writeNetwork(data, DataType::CSBK, gi ? FLCO::GROUP : FLCO::PRIVATE, srcId, dstId, 0U, true); m_slot->writeNetwork(data, DataType::CSBK, gi ? FLCO::GROUP : FLCO::PRIVATE, srcId, dstId, 0U, 0U, true);
} }
return true; return true;
@ -765,7 +765,7 @@ void ControlSignaling::writeNet_CSBK(lc::CSBK* csbk)
if (m_slot->m_duplex) if (m_slot->m_duplex)
m_slot->addFrame(data); m_slot->addFrame(data);
m_slot->writeNetwork(data, DataType::CSBK, csbk->getGI() ? FLCO::GROUP : FLCO::PRIVATE, csbk->getSrcId(), csbk->getDstId(), 0U, true); m_slot->writeNetwork(data, DataType::CSBK, csbk->getGI() ? FLCO::GROUP : FLCO::PRIVATE, csbk->getSrcId(), csbk->getDstId(), 0U, 0U, true);
} }
/* /*

@ -105,7 +105,7 @@ bool Data::process(uint8_t* data, uint32_t len)
data[0U] = modem::TAG_EOT; data[0U] = modem::TAG_EOT;
data[1U] = 0x00U; data[1U] = 0x00U;
m_slot->writeNetwork(data, DataType::TERMINATOR_WITH_LC); m_slot->writeNetwork(data, DataType::TERMINATOR_WITH_LC, 0U);
if (m_slot->m_duplex) { if (m_slot->m_duplex) {
for (uint32_t i = 0U; i < m_slot->m_hangCount; i++) for (uint32_t i = 0U; i < m_slot->m_hangCount; i++)
@ -250,7 +250,11 @@ bool Data::process(uint8_t* data, uint32_t len)
if (m_slot->m_duplex && m_repeatDataPacket) if (m_slot->m_duplex && m_repeatDataPacket)
m_slot->addFrame(data); m_slot->addFrame(data);
m_slot->writeNetwork(data, DataType::DATA_HEADER); uint8_t controlByte = 0U;
if (m_slot->m_convNetGrantDemand)
controlByte |= 0x80U; // Grant Demand Flag
m_slot->writeNetwork(data, DataType::DATA_HEADER, controlByte);
m_slot->m_rfState = RS_RF_DATA; m_slot->m_rfState = RS_RF_DATA;
m_slot->m_rfLastDstId = dstId; m_slot->m_rfLastDstId = dstId;
@ -323,7 +327,7 @@ bool Data::process(uint8_t* data, uint32_t len)
// convert the Data Sync to be from the BS or MS as needed // convert the Data Sync to be from the BS or MS as needed
Sync::addDMRDataSync(data + 2U, m_slot->m_duplex); Sync::addDMRDataSync(data + 2U, m_slot->m_duplex);
m_slot->writeNetwork(data, dataType); m_slot->writeNetwork(data, dataType, 0U);
if (m_slot->m_duplex && m_repeatDataPacket) { if (m_slot->m_duplex && m_repeatDataPacket) {
m_slot->addFrame(data); m_slot->addFrame(data);

@ -199,7 +199,11 @@ bool Voice::process(uint8_t* data, uint32_t len)
m_slot->addFrame(data); m_slot->addFrame(data);
} }
m_slot->writeNetwork(data, DataType::VOICE_LC_HEADER); uint8_t controlByte = 0U;
if (m_slot->m_convNetGrantDemand)
controlByte |= 0x80U; // Grant Demand Flag
m_slot->writeNetwork(data, DataType::VOICE_LC_HEADER, controlByte);
m_slot->m_rfState = RS_RF_AUDIO; m_slot->m_rfState = RS_RF_AUDIO;
m_slot->m_rfLastDstId = dstId; m_slot->m_rfLastDstId = dstId;
@ -246,7 +250,7 @@ bool Voice::process(uint8_t* data, uint32_t len)
if (m_slot->m_duplex) if (m_slot->m_duplex)
m_slot->addFrame(data); m_slot->addFrame(data);
m_slot->writeNetwork(data, DataType::VOICE_PI_HEADER); m_slot->writeNetwork(data, DataType::VOICE_PI_HEADER, 0U);
if (m_verbose) { if (m_verbose) {
LogMessage(LOG_RF, DMR_DT_VOICE_PI_HEADER ", slot = %u, algId = %u, kId = %u, dstId = %u", m_slot->m_slotNo, LogMessage(LOG_RF, DMR_DT_VOICE_PI_HEADER ", slot = %u, algId = %u, kId = %u, dstId = %u", m_slot->m_slotNo,
@ -304,7 +308,7 @@ bool Voice::process(uint8_t* data, uint32_t len)
if (m_slot->m_duplex) if (m_slot->m_duplex)
m_slot->addFrame(data); m_slot->addFrame(data);
m_slot->writeNetwork(data, DataType::VOICE_SYNC, errors); m_slot->writeNetwork(data, DataType::VOICE_SYNC, 0U, errors);
return true; return true;
} }
@ -458,7 +462,7 @@ bool Voice::process(uint8_t* data, uint32_t len)
data[0U] = modem::TAG_DATA; data[0U] = modem::TAG_DATA;
data[1U] = 0x00U; data[1U] = 0x00U;
m_slot->writeNetwork(data, DataType::VOICE, errors); m_slot->writeNetwork(data, DataType::VOICE, 0U, errors);
if (m_embeddedLCOnly) { if (m_embeddedLCOnly) {
// Only send the previously received LC // Only send the previously received LC
@ -561,7 +565,11 @@ bool Voice::process(uint8_t* data, uint32_t len)
m_slot->addFrame(start); m_slot->addFrame(start);
} }
m_slot->writeNetwork(start, DataType::VOICE_LC_HEADER); uint8_t controlByte = 0U;
if (m_slot->m_convNetGrantDemand)
controlByte |= 0x80U; // Grant Demand Flag
m_slot->writeNetwork(start, DataType::VOICE_LC_HEADER, controlByte);
m_rfN = data[1U] & 0x0FU; m_rfN = data[1U] & 0x0FU;
@ -610,7 +618,7 @@ bool Voice::process(uint8_t* data, uint32_t len)
if (m_slot->m_duplex) if (m_slot->m_duplex)
m_slot->addFrame(data); m_slot->addFrame(data);
m_slot->writeNetwork(data, DataType::VOICE, errors); m_slot->writeNetwork(data, DataType::VOICE, 0U, errors);
m_slot->m_rfState = RS_RF_AUDIO; m_slot->m_rfState = RS_RF_AUDIO;
@ -645,6 +653,8 @@ void Voice::processNetwork(const data::NetData& dmrData)
if (m_slot->m_netState == RS_NET_AUDIO) if (m_slot->m_netState == RS_NET_AUDIO)
return; return;
lc::FullLC fullLC; lc::FullLC fullLC;
std::unique_ptr<lc::LC> lc = fullLC.decode(data + 2U, DataType::VOICE_LC_HEADER); std::unique_ptr<lc::LC> lc = fullLC.decode(data + 2U, DataType::VOICE_LC_HEADER);
if (lc == nullptr) { if (lc == nullptr) {

Loading…
Cancel
Save

Powered by TurnKey Linux.