implement support for auto-affiliating units who can't affiliate in "enhanced" mode; better handle generating MBF CC data;

pull/1/head
Bryan Biedenkapp 6 years ago
parent a25a27143e
commit 95364cbcf1

@ -47,6 +47,7 @@ protocols:
voiceOnControl: false
inhibitIllegal: false
legacyGroupGrnt: true
legacyGroupReg: false
verifyAff: false
verifyReg: false
dumpDataPacket: false

@ -83,6 +83,7 @@ using namespace modem;
#define RCD_P25_PATCH_CMD "p25-patch"
#define RCD_P25_RELEASE_GRANTS "p25-rel-grnts"
#define RCD_P25_RELEASE_AFFS "p25-rel-affs"
const uint32_t RC_BUFFER_LENGTH = 100U;
@ -572,6 +573,22 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25)
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
}
}
else if (rcom == RCD_P25_RELEASE_AFFS) {
// Command is in the form of: "p25-rel-affs <group>"
if (p25 != NULL) {
uint32_t grp = getArgUInt32(args, 0U);
if (grp == 0) {
p25->trunk()->clearGrpAff(0, true);
}
else {
p25->trunk()->clearGrpAff(grp, false);
}
}
else {
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
}
}
else {
args.clear();
LogError(LOG_RCON, BAD_CMD_STR " (\"%s\")", rcom.c_str());

@ -89,6 +89,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
m_network(network),
m_inhibitIllegal(false),
m_legacyGroupGrnt(true),
m_legacyGroupReg(false),
m_duplex(duplex),
m_control(false),
m_continuousControl(false),
@ -112,6 +113,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
m_hangCount(3U * 8U),
m_preambleCount(0U),
m_ccFrameCnt(0U),
m_ccSeq(0U),
m_nid(nac),
m_rssiMapper(rssiMapper),
m_rssi(0U),
@ -181,6 +183,7 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
m_inhibitIllegal = p25Protocol["inhibitIllegal"].as<bool>(false);
m_legacyGroupGrnt = p25Protocol["legacyGroupGrnt"].as<bool>(true);
m_legacyGroupReg = p25Protocol["legacyGroupReg"].as<bool>(false);
m_trunk->m_verifyAff = p25Protocol["verifyAff"].as<bool>(false);
m_trunk->m_verifyReg = p25Protocol["verifyReg"].as<bool>(false);
@ -226,6 +229,7 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
LogInfo(" Inhibit Illegal: %s", m_inhibitIllegal ? "yes" : "no");
LogInfo(" Legacy Group Grant: %s", m_legacyGroupGrnt ? "yes" : "no");
LogInfo(" Legacy Group Registration: %s", m_legacyGroupReg ? "yes" : "no");
LogInfo(" Verify Affiliation: %s", m_trunk->m_verifyAff ? "yes" : "no");
LogInfo(" Verify Registration: %s", m_trunk->m_verifyReg ? "yes" : "no");
@ -455,13 +459,18 @@ bool Control::writeControlRF()
return false;
}
if (m_ccSeq == 5U) {
m_ccSeq = 0U;
}
if (m_ccFrameCnt == 254U) {
m_ccFrameCnt = 0U;
}
if (m_netState == RS_NET_IDLE && m_rfState == RS_RF_LISTENING) {
m_trunk->writeRF_ControlData(m_ccFrameCnt, true);
m_trunk->writeRF_ControlData(m_ccFrameCnt, m_ccSeq, true);
m_ccFrameCnt++;
m_ccSeq++;
return true;
}

@ -122,6 +122,7 @@ namespace p25
bool m_inhibitIllegal;
bool m_legacyGroupGrnt;
bool m_legacyGroupReg;
bool m_duplex;
bool m_control;
@ -151,7 +152,9 @@ namespace p25
uint32_t m_hangCount;
uint32_t m_preambleCount;
uint8_t m_ccFrameCnt;
uint8_t m_ccSeq;
NID m_nid;

@ -339,6 +339,8 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_IOSP_GRP_VCH (Group Voice Channel Request), srcId = %u, dstId = %u", srcId, dstId);
}
::ActivityLog("P25", true, "received group grant request from %u to TG %u", srcId, dstId);
writeRF_TSDU_Grant(true, false);
break;
case TSBK_IOSP_UU_VCH:
@ -358,6 +360,8 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_IOSP_UU_VCH (Unit-to-Unit Voice Channel Request), srcId = %u, dstId = %u", srcId, dstId);
}
::ActivityLog("P25", true, "received unit-to-unit grant request from %u to %u", srcId, dstId);
writeRF_TSDU_UU_Ans_Req(srcId, dstId);
break;
case TSBK_IOSP_UU_ANS:
@ -375,6 +379,8 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
m_rfTSBK.getResponse(), srcId, dstId);
}
writeRF_TSDU_ACK_FNE(srcId, TSBK_IOSP_UU_ANS, true);
if (m_rfTSBK.getResponse() == P25_ANS_RSP_PROCEED) {
writeRF_TSDU_Grant(false, false);
}
@ -397,6 +403,8 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
m_rfTSBK.getResponse(), srcId);
}
writeRF_TSDU_ACK_FNE(srcId, TSBK_IOSP_TELE_INT_ANS, true);
if (m_rfTSBK.getResponse() == P25_ANS_RSP_PROCEED) {
//writeRF_TSDU_Grant(false);
writeRF_TSDU_Deny(P25_DENY_RSN_SYS_UNSUPPORTED_SVC, TSBK_IOSP_TELE_INT_ANS);
@ -677,6 +685,19 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
resetStatusCommand(m_netTSBK);
switch (m_netTSBK.getLCO()) {
case TSBK_IOSP_UU_ANS:
if (m_netTSBK.getResponse() > 0U) {
if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_IOSP_UU_ANS (Unit-to-Unit Answer Response), response = $%02X, srcId = %u, dstId = %u",
m_netTSBK.getResponse(), srcId, dstId);
}
}
else {
if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_IOSP_UU_ANS (Unit-to-Unit Answer Request), srcId = %u, dstId = %u", srcId, dstId);
}
}
break;
case TSBK_IOSP_STS_UPDT:
// validate the source RID
VALID_SRCID_NET("TSBK_IOSP_STS_UPDT (Status Update)", srcId);
@ -751,14 +772,14 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
break;
case TSBK_OSP_DENY_RSP:
if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_DENY_RSP (Deny Response), reason = %u, srcId = %u, dstId = %u",
m_netTSBK.getResponse(), m_netTSBK.getSrcId(), m_netTSBK.getDstId());
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_DENY_RSP (Deny Response), AIV = %u, reason = $%02X, srcId = %u, dstId = %u",
m_netTSBK.getAIV(), m_netTSBK.getResponse(), m_netTSBK.getSrcId(), m_netTSBK.getDstId());
}
break;
case TSBK_OSP_QUE_RSP:
if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_QUE_RSP (Queue Response), reason = %u, srcId = %u, dstId = %u",
m_netTSBK.getResponse(), m_netTSBK.getSrcId(), m_netTSBK.getDstId());
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_QUE_RSP (Queue Response), AIV = %u, reason = $%02X, srcId = %u, dstId = %u",
m_netTSBK.getAIV(), m_netTSBK.getResponse(), m_netTSBK.getSrcId(), m_netTSBK.getDstId());
}
break;
default:
@ -959,6 +980,42 @@ void TrunkPacket::releaseDstIdGrant(uint32_t dstId, bool releaseAll)
}
}
/// <summary>
/// Helper to release group affiliations.
/// </summary>
/// <param name="dstId"></param>
/// <param name="releaseAll"></param>
void TrunkPacket::clearGrpAff(uint32_t dstId, bool releaseAll)
{
if (dstId == 0U && !releaseAll) {
return;
}
std::vector<uint32_t> srcToRel = std::vector<uint32_t>();
if (dstId == 0U && releaseAll) {
LogWarning(LOG_RF, "P25, releasing all group affiliations");
for (auto it = m_grpAffTable.begin(); it != m_grpAffTable.end(); ++it) {
uint32_t srcId = it->first;
srcToRel.push_back(srcId);
}
}
else {
LogWarning(LOG_RF, "P25, releasing group affiliations, dstId = %u", dstId);
for (auto it = m_grpAffTable.begin(); it != m_grpAffTable.end(); ++it) {
uint32_t srcId = it->first;
uint32_t grpId = it->second;
if (grpId == dstId) {
srcToRel.push_back(srcId);
}
}
}
// release affiliations
for (auto it = srcToRel.begin(); it != srcToRel.end(); ++it) {
writeRF_TSDU_U_Dereg_Ack(*it);
}
}
/// <summary>
///
/// </summary>
@ -1258,99 +1315,64 @@ void TrunkPacket::writeNetworkRF(const uint8_t* data, bool autoReset)
/// Helper to write control channel packet data.
/// </summary>
/// <param name="frameCnt"></param>
/// <param name="n"></param>
/// <param name="adjSS"></param>
void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, bool adjSS)
void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
{
uint8_t i = 0U, seqCnt = 0U;
if (!m_p25->m_control) {
return;
}
// loop to generate 6 control sequences
if (frameCnt == 255U) {
seqCnt = 6U;
}
do
{
m_rfTSBK.reset();
bool alt = (frameCnt % 2) > 0U;
if (m_debug) {
LogDebug(LOG_P25, "writeRF_ControlData, mbfCnt = %u, frameCnt = %u, alt = %u, adjSS = %u", m_mbfCnt, frameCnt, alt, adjSS);
LogDebug(LOG_P25, "writeRF_ControlData, mbfCnt = %u, frameCnt = %u, seq = %u, adjSS = %u", m_mbfCnt, frameCnt, n, adjSS);
}
switch (n)
{
case 0:
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_IDEN_UP);
if (alt) {
// write rfss-net-rfss bcast
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_RFSS_STS_BCAST);
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_NET_STS_BCAST);
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_RFSS_STS_BCAST);
}
else {
// write net-rfss-net bcast
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_NET_STS_BCAST);
break;
case 1:
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_RFSS_STS_BCAST);
break;
case 2:
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_NET_STS_BCAST);
}
break;
case 3:
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_SNDCP_CH_ANN);
// LogDebug(LOG_P25, "writeRF_ControlData, before adjSS, mbfCnt = %u", m_mbfCnt);
break;
case 4:
// write ADJSS
if (adjSS && m_adjSiteTable.size() > 0) {
if (m_mbfAdjSSCnt >= m_adjSiteTable.size())
m_mbfAdjSSCnt = 0U;
uint8_t i = 0U;
for (auto it = m_adjSiteTable.begin(); it != m_adjSiteTable.end(); ++it) {
// no good very bad way of skipping entries...
if (i != m_mbfAdjSSCnt) {
i++;
continue;
if (adjSS) {
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_ADJ_STS_BCAST);
}
else {
m_rfTSBK.reset();
SiteData site = it->second;
uint8_t cfva = P25_CFVA_CONV | P25_CFVA_NETWORK;
if (m_adjSiteUpdateCnt[site.siteId()] == 0U) {
cfva |= P25_CFVA_FAILURE;
}
else {
cfva |= P25_CFVA_VALID;
}
// transmit adjacent site broadcast
m_rfTSBK.setLCO(TSBK_OSP_ADJ_STS_BCAST);
m_rfTSBK.setAdjSiteCFVA(cfva);
m_rfTSBK.setAdjSiteSysId(site.sysId());
m_rfTSBK.setAdjSiteRFSSId(site.rfssId());
m_rfTSBK.setAdjSiteId(site.siteId());
m_rfTSBK.setAdjSiteChnId(site.channelId());
m_rfTSBK.setAdjSiteChnNo(site.channelNo());
m_rfTSBK.setLastBlock(true); // always set last block
writeRF_TSDU_MBF();
m_mbfAdjSSCnt++;
break;
}
}
}
// LogDebug(LOG_P25, "writeRF_ControlData, after adjSS, mbfCnt = %u", m_mbfCnt);
if (seqCnt > 0U)
n++;
i++;
} while (i <= seqCnt);
// should we insert the BSI bursts?
bool bsi = (frameCnt % 127) == 0U;
if (bsi) {
bool bsi = (frameCnt % 64U) == 0U;
if (bsi || frameCnt == 255U) {
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_MOT_CC_BSI);
m_rfTSBK.reset();
// transmit CC BSI burst
m_rfTSBK.setLCO(TSBK_OSP_MOT_CC_BSI);
m_rfTSBK.setMFId(P25_MFG_MOT);
m_rfTSBK.setLastBlock(true); // always set last block
writeRF_TSDU_MBF();
}
// add padding after the 4th sequence
if (seqCnt > 4U) {
// pad MBF if we have 1 queued TSDUs
if (m_mbfCnt == 1U) {
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_RFSS_STS_BCAST);
@ -1369,6 +1391,7 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, bool adjSS)
else {
queueRF_TSBK_Ctrl_MBF(TSBK_OSP_RFSS_STS_BCAST);
}
if (m_debug) {
LogDebug(LOG_P25, "writeRF_ControlData, have 2 pad 1, mbfCnt = %u", m_mbfCnt);
}
@ -1377,6 +1400,7 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, bool adjSS)
// reset MBF count
m_mbfCnt = 0U;
}
}
/// <summary>
/// Helper to write a P25 TDU w/ link control packet.
@ -1669,6 +1693,10 @@ void TrunkPacket::queueRF_TSBK_Ctrl_MBF(uint8_t lco)
switch (lco) {
case TSBK_OSP_IDEN_UP:
{
if (m_debug) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_OSP_IDEN_UP (Identity Update)");
}
std::vector<lookups::IdenTable> entries = m_p25->m_idenTable->list();
if (m_mbfIdenCnt >= entries.size())
m_mbfIdenCnt = 0U;
@ -1723,6 +1751,52 @@ void TrunkPacket::queueRF_TSBK_Ctrl_MBF(uint8_t lco)
// transmit rfss status burst
m_rfTSBK.setLCO(TSBK_OSP_RFSS_STS_BCAST);
break;
case TSBK_OSP_ADJ_STS_BCAST:
// write ADJSS
if (m_adjSiteTable.size() > 0) {
if (m_mbfAdjSSCnt >= m_adjSiteTable.size())
m_mbfAdjSSCnt = 0U;
if (m_debug) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_OSP_ADJ_STS_BCAST (Adjacent Site Broadcast)");
}
uint8_t i = 0U;
for (auto it = m_adjSiteTable.begin(); it != m_adjSiteTable.end(); ++it) {
// no good very bad way of skipping entries...
if (i != m_mbfAdjSSCnt) {
i++;
continue;
}
else {
SiteData site = it->second;
uint8_t cfva = P25_CFVA_CONV | P25_CFVA_NETWORK;
if (m_adjSiteUpdateCnt[site.siteId()] == 0U) {
cfva |= P25_CFVA_FAILURE;
}
else {
cfva |= P25_CFVA_VALID;
}
// transmit adjacent site broadcast
m_rfTSBK.setLCO(TSBK_OSP_ADJ_STS_BCAST);
m_rfTSBK.setAdjSiteCFVA(cfva);
m_rfTSBK.setAdjSiteSysId(site.sysId());
m_rfTSBK.setAdjSiteRFSSId(site.rfssId());
m_rfTSBK.setAdjSiteId(site.siteId());
m_rfTSBK.setAdjSiteChnId(site.channelId());
m_rfTSBK.setAdjSiteChnNo(site.channelNo());
m_mbfAdjSSCnt++;
break;
}
}
}
else {
return; // don't create anything
}
break;
case TSBK_OSP_SNDCP_CH_ANN:
if (m_debug) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_OSP_SNDCP_CH_ANN (SNDCP Channel Announcement)");
@ -1880,7 +1954,7 @@ void TrunkPacket::writeRF_TSDU_UU_Ans_Req(uint32_t srcId, uint32_t dstId)
m_rfTSBK.setSrcId(srcId);
m_rfTSBK.setDstId(dstId);
m_rfTSBK.setVendorSkip(true);
writeRF_TSDU_SBF(true);
writeRF_TSDU_SBF(false);
m_rfTSBK.setLCO(lco);
m_rfTSBK.setVendorSkip(false);
@ -1929,7 +2003,7 @@ void TrunkPacket::writeRF_TSDU_Deny(uint8_t reason, uint8_t service)
m_rfTSBK.setLCO(TSBK_OSP_DENY_RSP);
m_rfTSBK.setService(service);
m_rfTSBK.setResponse(reason);
writeRF_TSDU_SBF(true);
writeRF_TSDU_SBF(false);
m_rfTSBK.setLCO(lco);
}
@ -1939,8 +2013,10 @@ void TrunkPacket::writeRF_TSDU_Deny(uint8_t reason, uint8_t service)
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
void TrunkPacket::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId)
bool TrunkPacket::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId)
{
bool ret = false;
m_rfTSBK.setLCO(TSBK_IOSP_GRP_AFF);
m_rfTSBK.setResponse(P25_RSP_ACCEPT);
m_rfTSBK.setPatchSuperGroupId(m_patchSuperGroup);
@ -1972,12 +2048,14 @@ void TrunkPacket::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId)
}
::ActivityLog("P25", true, "received group affiliation request from %u to %s %u", srcId, "TG ", dstId);
ret = true;
// update dynamic affiliation table
m_grpAffTable[srcId] = dstId;
}
writeRF_TSDU_SBF(false);
return ret;
}
/// <summary>
@ -2059,6 +2137,7 @@ void TrunkPacket::writeRF_TSDU_U_Dereg_Ack(uint32_t srcId)
}
m_rfTSBK.setSrcId(P25_WUID_SYS);
m_rfTSBK.setDstId(srcId);
writeRF_TSDU_SBF(false);
}
@ -2080,7 +2159,7 @@ void TrunkPacket::writeRF_TSDU_Queue(uint8_t reason, uint8_t service)
m_rfTSBK.setLCO(TSBK_OSP_QUE_RSP);
m_rfTSBK.setService(service);
m_rfTSBK.setResponse(reason);
writeRF_TSDU_SBF(true);
writeRF_TSDU_SBF(false);
m_rfTSBK.setLCO(lco);
}

@ -100,6 +100,8 @@ namespace p25
void touchDstIdGrant(uint32_t dstId);
/// <summary>Helper to release the channel grant for the destination ID.</summary>
void releaseDstIdGrant(uint32_t dstId, bool releaseAll);
/// <summary>Helper to release group affiliations.</summary>
void clearGrpAff(uint32_t dstId, bool releaseAll);
/// <summary></summary>
void resetStatusCommand();
@ -191,7 +193,7 @@ namespace p25
void writeNetworkRF(const uint8_t* data, bool autoReset);
/// <summary>Helper to write control channel packet data.</summary>
void writeRF_ControlData(uint8_t frameCnt, bool adjSS);
void writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS);
/// <summary>Helper to write a P25 TDU w/ link control packet.</summary>
void writeRF_TDULC(uint8_t duid, bool noNetwork);
@ -217,7 +219,7 @@ namespace p25
/// <summary>Helper to write a deny packet.</summary>
void writeRF_TSDU_Deny(uint8_t reason, uint8_t service);
/// <summary>Helper to write a group affiliation response packet.</summary>
void writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId);
bool writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId);
/// <summary>Helper to write a unit registration response packet.</summary>
void writeRF_TSDU_U_Reg_Rsp(uint32_t srcId);
/// <summary>Helper to write a unit de-registration acknowledge packet.</summary>

@ -129,7 +129,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_p25->writeRF_Preamble();
if (!m_p25->m_ccRunning) {
m_p25->m_trunk->writeRF_ControlData(127U, false);
m_p25->m_trunk->writeRF_ControlData(255U, 0U, false);
}
}
@ -235,6 +235,16 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
// if the group wasn't granted out -- explicitly grant the group
if (!m_p25->m_trunk->hasDstIdGranted(dstId)) {
if (m_p25->m_legacyGroupGrnt) {
// are we auto-registering legacy radios to groups?
if (m_p25->m_legacyGroupReg && m_rfLC.getGroup()) {
if (!m_p25->m_trunk->hasSrcIdGrpAff(srcId, dstId)) {
m_p25->m_trunk->m_skipSBFPreamble = true; // HACK: force an SBF to skip generating preambles
if (!m_p25->m_trunk->writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId)) {
return false;
}
}
}
m_p25->m_trunk->m_skipSBFPreamble = true; // HACK: force an SBF to skip generating preambles
if (!m_p25->m_trunk->writeRF_TSDU_Grant(m_rfLC.getGroup(), false)) {
return false;
@ -693,7 +703,7 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
m_p25->m_trunk->resetNet();
if (!m_p25->m_ccRunning) {
m_p25->m_trunk->writeRF_ControlData(127U, false);
m_p25->m_trunk->writeRF_ControlData(255U, 0U, false);
}
writeNet_HDU(control, lsd);
@ -740,7 +750,7 @@ bool VoicePacket::writeEndRF()
writeRF_EndOfVoice();
if (!m_p25->m_ccRunning) {
m_p25->m_trunk->writeRF_ControlData(127U, false);
m_p25->m_trunk->writeRF_ControlData(255U, 0U, false);
m_p25->writeControlEndRF();
}

@ -156,6 +156,8 @@ bool TSBK::decode(const uint8_t* data)
case TSBK_IOSP_U_REG:
case TSBK_ISP_CAN_SRV_REQ:
case TSBK_ISP_GRP_AFF_Q_RSP:
case TSBK_OSP_DENY_RSP:
case TSBK_OSP_QUE_RSP:
case TSBK_ISP_U_DEREG_REQ:
case TSBK_OSP_U_DEREG_ACK:
case TSBK_ISP_LOC_REG_REQ:
@ -252,6 +254,14 @@ bool TSBK::decode(const uint8_t* data)
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFU); // Talkgroup Address
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break;
case TSBK_OSP_DENY_RSP:
case TSBK_OSP_QUE_RSP:
m_aivFlag = (((tsbkValue >> 56) & 0xFFU) & 0x80U) == 0x80U; // Additional Info. Flag
m_service = (uint8_t)((tsbkValue >> 56) & 0x3FU); // Service Type
m_response = (uint8_t)((tsbkValue >> 48) & 0xFFU); // Reason
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFFFU); // Target Radio Address
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break;
case TSBK_ISP_U_DEREG_REQ:
case TSBK_OSP_U_DEREG_ACK:
m_netId = (uint32_t)((tsbkValue >> 36) & 0xFFFFFU); // Network ID

Loading…
Cancel
Save

Powered by TurnKey Linux.