add support for DMR T3 adjacent site broadcast;

pull/51/head
Bryan Biedenkapp 2 years ago
parent 3d752bc363
commit 4d776f6314

@ -71,7 +71,7 @@ master:
# Flag indicating whether or not a parrot TG call will generate a grant demand.
parrotGrantDemand: true
# Flag indicating whether or not a P25 ADJ_STS_BCAST will pass to any peers.
# Flag indicating whether or not a adjacent site broadcasts will pass to any peers.
disallowAdjStsBcast: false
# Flag indicating whether or not a P25 ADJ_STS_BCAST will pass to connected external peers.
disallowExtAdjStsBcast: true

@ -112,6 +112,8 @@ std::unique_ptr<CSBK> CSBKFactory::createCSBK(const uint8_t* data, uint8_t dataT
/** Tier 3 */
case CSBKO_ACK_RSP:
return decode(new CSBK_ACK_RSP(), data);
case CSBKO_BROADCAST:
return decode(new CSBK_BROADCAST(), data);
case CSBKO_MAINT:
return decode(new CSBK_MAINT(), data);

@ -31,6 +31,8 @@ CSBK_BROADCAST::CSBK_BROADCAST() : CSBK(),
m_hibernating(false),
m_annWdCh1(false),
m_annWdCh2(false),
m_requireReg(false),
m_systemId(0U),
m_backoffNo(1U)
{
m_CSBKO = CSBKO_BROADCAST;
@ -45,7 +47,34 @@ bool CSBK_BROADCAST::decode(const uint8_t* data)
{
assert(data != nullptr);
/* stub */
uint8_t csbk[DMR_CSBK_LENGTH_BYTES];
::memset(csbk, 0x00U, DMR_CSBK_LENGTH_BYTES);
bool ret = CSBK::decode(data, csbk);
if (!ret)
return false;
ulong64_t csbkValue = CSBK::toValue(csbk);
m_anncType = ((csbkValue >> 59) & 0x0FU); // Announcement Type
switch (m_anncType)
{
case BCAST_ANNC_ANN_WD_TSCC:
// Broadcast Params 1
m_colorCode = (uint8_t)((csbkValue >> 51) & 0x0FU); // Color Code 1
m_annWdCh1 = ((csbkValue >> 44) & 0x04U) == 0x04U; // Announce/Withdraw Channel 1
m_annWdCh2 = ((csbkValue >> 44) & 0x02U) == 0x02U; // Announce/Withdraw Channel 2
m_requireReg = ((csbkValue >> 44) & 0x01U) == 0x01U; // Require Registration
m_backoffNo = (uint8_t)((csbkValue >> 40) & 0x0FU); // Backoff Number
m_systemId = (uint8_t)((csbkValue >> 24) & 0xFFFFU); // Site Identity
// Broadcast Params 2
m_logicalCh1 = (uint32_t)((csbkValue >> 12) & 0xFFFU); // Logical Channel 1
m_logicalCh2 = (uint32_t)(csbkValue & 0xFFFU); // Logical Channel 2
break;
}
return true;
}
@ -74,9 +103,9 @@ void CSBK_BROADCAST::encode(uint8_t* data)
csbkValue = (csbkValue << 1) + ((m_annWdCh1) ? 1U : 0U); // Announce/Withdraw Channel 1
csbkValue = (csbkValue << 1) + ((m_annWdCh2) ? 1U : 0U); // Announce/Withdraw Channel 2
csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration
csbkValue = (csbkValue << 1) + ((m_requireReg) ? 1U : 0U); // Require Registration
csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number
csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity
csbkValue = (csbkValue << 16) + (m_systemId & 0xFFFFU); // Site Identity
// Broadcast Params 2
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel 1

@ -51,6 +51,11 @@ namespace dmr
/// <summary>Broadcast Announce/Withdraw Channel 2 Flag.</summary>
__PROPERTY(bool, annWdCh2, AnnWdCh2);
/// <summary>Require Registration.</summary>
__PROPERTY(bool, requireReg, RequireReg);
/// <summary>System Identity.</summary>
__PROPERTY(uint32_t, systemId, SystemId);
/// <summary>Backoff Number.</summary>
__PROPERTY(uint8_t, backoffNo, BackoffNo);

@ -159,7 +159,7 @@ void FNENetwork::setOptions(yaml::Node& conf, bool printOptions)
if (printOptions) {
LogInfo(" Maximum Permitted Connections: %u", m_softConnLimit);
LogInfo(" Disable P25 ADJ_STS_BCAST to any peers: %s", m_disallowAdjStsBcast ? "yes" : "no");
LogInfo(" Disable adjacent site broadcasts to any peers: %s", m_disallowAdjStsBcast ? "yes" : "no");
if (m_disallowAdjStsBcast) {
LogWarning(LOG_NET, "NOTICE: All P25 ADJ_STS_BCAST messages will be blocked and dropped!");
}

@ -544,6 +544,27 @@ bool TagDMRData::processCSBK(uint8_t* buffer, uint32_t peerId, dmr::data::Data&
.request(m_network->m_influxServer);
}
}
switch (csbk->getCSBKO()) {
case CSBKO_BROADCAST:
{
lc::csbk::CSBK_BROADCAST* osp = static_cast<lc::csbk::CSBK_BROADCAST*>(csbk.get());
if (osp->getAnncType() == BCAST_ANNC_ANN_WD_TSCC) {
if (m_network->m_disallowAdjStsBcast) {
// LogWarning(LOG_NET, "PEER %u, passing BCAST_ANNC_ANN_WD_TSCC to internal peers is prohibited, dropping", peerId);
return false;
} else {
if (m_network->m_verbose) {
LogMessage(LOG_NET, "DMR Slot %u, DT_CSBK, %s, sysId = $%03X, chNo = %u, peerId = %u", dmrData.getSlotNo(), csbk->toString().c_str(),
osp->getSystemId(), osp->getLogicalCh1(), peerId);
}
}
}
}
break;
default:
break;
}
} else {
LogWarning(LOG_NET, "PEER %u, passing CSBK that failed to decode? csbk == nullptr", peerId);
}

@ -1240,7 +1240,6 @@ int Host::run()
if (m_state != STATE_NXDN)
setState(STATE_NXDN);
//nxdn->writeAdjSSNetwork();
nxdn->setCCRunning(true);
// hide this message for continuous CC -- otherwise display every time we process
@ -1281,7 +1280,6 @@ int Host::run()
// the network
if (nxdnBcastIntervalTimer.isRunning() && nxdnBcastIntervalTimer.hasExpired()) {
if ((m_state == STATE_IDLE || m_state == STATE_NXDN) && !m_modem->hasTX()) {
//nxdn->writeAdjSSNetwork();
nxdnBcastIntervalTimer.start();
}
}

@ -83,6 +83,13 @@ bool Slot::m_verifyReg = false;
uint8_t Slot::m_alohaNRandWait = DEFAULT_NRAND_WAIT;
uint8_t Slot::m_alohaBackOff = 1U;
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t ADJ_SITE_TIMER_TIMEOUT = 60U;
const uint32_t ADJ_SITE_UPDATE_CNT = 5U;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
@ -125,6 +132,10 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_netTimeoutTimer(1000U, timeout),
m_netTGHang(1000U, 2U),
m_packetTimer(1000U, 0U, 50U),
m_adjSiteTable(),
m_adjSiteUpdateCnt(),
m_adjSiteUpdateTimer(1000U),
m_adjSiteUpdateInterval(ADJ_SITE_TIMER_TIMEOUT),
m_adjSiteUpdate(1000U, 75U),
m_ccPacketInterval(1000U, 0U, DMR_SLOT_TIME),
m_interval(),
@ -158,6 +169,7 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_tsccPayloadGroup(false),
m_tsccPayloadVoice(true),
m_tsccPayloadActRetry(1000U, 0U, 250U),
m_tsccAdjSSCnt(0U),
m_disableGrantSrcIdCheck(false),
m_lastLateEntry(0U),
m_supervisor(false),
@ -167,6 +179,13 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
{
m_interval.start();
m_adjSiteTable.clear();
m_adjSiteUpdateCnt.clear();
m_adjSiteUpdateInterval = ADJ_SITE_TIMER_TIMEOUT;
m_adjSiteUpdateTimer.setTimeout(m_adjSiteUpdateInterval);
m_adjSiteUpdateTimer.start();
m_voice = new Voice(this, m_network, m_embeddedLCOnly, m_dumpTAData, debug, verbose);
m_data = new Data(this, m_network, dumpDataPacket, repeatDataPacket, debug, verbose);
m_control = new ControlSignaling(this, m_network, dumpCSBKData, debug, verbose);
@ -475,17 +494,43 @@ void Slot::clock()
}
// do we need to network announce ourselves?
if (!m_adjSiteUpdate.isRunning()) {
m_adjSiteUpdate.start();
if (!m_adjSiteUpdateTimer.isRunning()) {
m_control->writeAdjSSNetwork();
m_adjSiteUpdateTimer.start();
}
m_adjSiteUpdate.clock(ms);
if (m_adjSiteUpdate.isRunning() && m_adjSiteUpdate.hasExpired()) {
m_adjSiteUpdateTimer.clock(ms);
if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) {
if (m_rfState == RS_RF_LISTENING && m_netState == RS_NET_IDLE) {
m_control->writeAdjSSNetwork();
if (m_network != nullptr)
m_network->announceAffiliationUpdate(m_affiliations->grpAffTable());
m_adjSiteUpdate.start();
m_adjSiteUpdateTimer.start();
}
}
// clock adjacent site and SCCB update timers
m_adjSiteUpdateTimer.clock(ms);
if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) {
// update adjacent site data
for (auto& entry : m_adjSiteUpdateCnt) {
uint8_t siteId = entry.first;
uint8_t updateCnt = entry.second;
if (updateCnt > 0U) {
updateCnt--;
}
if (updateCnt == 0U) {
AdjSiteData siteData = m_adjSiteTable[siteId];
LogWarning(LOG_NET, "DMR, Adjacent Site Status Expired, no data [FAILED], sysId = $%03X, chNo = %u",
siteData.systemIdentity, siteData.channelNo);
}
entry.second = updateCnt;
}
m_adjSiteUpdateTimer.setTimeout(m_adjSiteUpdateInterval);
m_adjSiteUpdateTimer.start();
}
if (m_ccPrevRunning && !m_ccRunning) {
@ -1374,6 +1419,17 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n)
switch (n)
{
/** required data */
case 0:
default:
m_control->writeRF_TSCC_Bcast_Sys_Parm();
break;
case 1:
m_control->writeRF_TSCC_Aloha();
break;
case 2:
m_control->writeRF_TSCC_Bcast_Ann_Wd(m_channelNo, true, m_siteData.systemIdentity(), m_siteData.requireReg());
break;
case 3:
{
std::unordered_map<uint32_t, uint32_t> grants = m_affiliations->grantTable();
@ -1406,15 +1462,29 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n)
}
}
break;
case 2:
m_control->writeRF_TSCC_Bcast_Ann_Wd(m_channelNo, true);
/** extra data */
case 4:
// write ADJSS
if (m_adjSiteTable.size() > 0) {
if (m_tsccAdjSSCnt >= m_adjSiteTable.size())
m_tsccAdjSSCnt = 0U;
uint8_t i = 0U;
for (auto entry : m_adjSiteTable) {
// no good very bad way of skipping entries...
if (i != m_tsccAdjSSCnt) {
i++;
continue;
}
else {
AdjSiteData site = entry.second;
m_control->writeRF_TSCC_Bcast_Ann_Wd(site.channelNo, true, site.systemIdentity, site.requireReg);
m_tsccAdjSSCnt++;
break;
case 1:
m_control->writeRF_TSCC_Aloha();
}
}
break;
case 0:
default:
m_control->writeRF_TSCC_Bcast_Sys_Parm();
}
break;
}

@ -45,6 +45,22 @@ namespace dmr
namespace packet { class HOST_SW_API Data; }
namespace packet { class HOST_SW_API ControlSignaling; }
// ---------------------------------------------------------------------------
// Structure Declaration
// This structure contains shortened data for adjacent sites.
// ---------------------------------------------------------------------------
struct AdjSiteData
{
public:
/// <summary>Channel Number.</summary>
uint32_t channelNo;
/// <summary>System Identity.</summary>
uint32_t systemIdentity;
/// <summary>DMR require registration.</summary>
bool requireReg;
};
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements core logic for handling DMR slots.
@ -164,6 +180,11 @@ namespace dmr
Timer m_netTGHang;
Timer m_packetTimer;
std::unordered_map<uint8_t, AdjSiteData> m_adjSiteTable;
std::unordered_map<uint8_t, uint8_t> m_adjSiteUpdateCnt;
Timer m_adjSiteUpdateTimer;
uint32_t m_adjSiteUpdateInterval;
Timer m_adjSiteUpdate;
Timer m_ccPacketInterval;
@ -208,6 +229,7 @@ namespace dmr
bool m_tsccPayloadGroup;
bool m_tsccPayloadVoice;
Timer m_tsccPayloadActRetry;
uint8_t m_tsccAdjSSCnt;
bool m_disableGrantSrcIdCheck;

@ -118,6 +118,7 @@ using namespace dmr::packet;
// Constants
// ---------------------------------------------------------------------------
const uint32_t ADJ_SITE_UPDATE_CNT = 5U;
const uint32_t GRANT_TIMER_TIMEOUT = 15U;
// ---------------------------------------------------------------------------
@ -405,6 +406,40 @@ void ControlSignaling::processNetwork(const data::Data & dmrData)
if (csbko == CSBKO_BSDWNACT)
return;
// handle updating internal adjacent site information
if (csbko == CSBKO_BROADCAST) {
CSBK_BROADCAST* osp = static_cast<CSBK_BROADCAST*>(csbk.get());
if (osp->getAnncType() == BCAST_ANNC_ANN_WD_TSCC) {
if (!m_slot->m_enableTSCC) {
return;
}
if (osp->getSystemId() != m_slot->m_siteData.systemIdentity()) {
// update site table data
AdjSiteData site;
try {
site = m_slot->m_adjSiteTable.at(osp->getSystemId());
} catch (...) {
site = AdjSiteData();
}
if (m_verbose) {
LogMessage(LOG_NET, "DMR Slot %u, DT_CSBK, %s, sysId = $%03X, chNo = %u", m_slot->m_slotNo, csbk->toString().c_str(),
osp->getSystemId(), osp->getLogicalCh1());
}
site.channelNo = osp->getLogicalCh1();
site.systemIdentity = osp->getSystemId();
site.requireReg = osp->getRequireReg();
m_slot->m_adjSiteTable[site.systemIdentity] = site;
m_slot->m_adjSiteUpdateCnt[site.systemIdentity] = ADJ_SITE_UPDATE_CNT;
}
return;
}
}
uint32_t srcId = csbk->getSrcId();
uint32_t dstId = csbk->getDstId();
@ -583,6 +618,35 @@ void ControlSignaling::processNetwork(const data::Data & dmrData)
}
}
/// <summary>
/// Helper to write DMR adjacent site information to the network.
/// </summary>
void ControlSignaling::writeAdjSSNetwork()
{
if (!m_slot->m_enableTSCC) {
return;
}
if (m_slot->m_network != nullptr) {
// transmit adjacent site broadcast
std::unique_ptr<CSBK_BROADCAST> csbk = std::make_unique<CSBK_BROADCAST>();
csbk->siteIdenEntry(m_slot->m_idenEntry);
csbk->setCdef(false);
csbk->setAnncType(BCAST_ANNC_ANN_WD_TSCC);
csbk->setLogicalCh1(m_slot->m_channelNo);
csbk->setAnnWdCh1(true);
csbk->setSystemId(m_slot->m_siteData.systemIdentity());
csbk->setRequireReg(m_slot->m_siteData.requireReg());
if (m_verbose) {
LogMessage(LOG_NET, "DMR Slot %u, DT_CSBK, %s, network announce, sysId = $%03X, chNo = %u", m_slot->m_slotNo, csbk->toString().c_str(),
m_slot->m_siteData.systemIdentity(), m_slot->m_channelNo);
}
writeNet_CSBK(csbk.get());
}
}
/// <summary>
/// Helper to write a extended function packet on the RF interface.
/// </summary>
@ -703,6 +767,39 @@ void ControlSignaling::writeRF_CSBK(lc::CSBK* csbk, bool imm)
m_slot->addFrame(data, false, imm);
}
/// <summary>
/// Helper to write a network CSBK.
/// </summary>
/// <param name="csbk"></param>
void ControlSignaling::writeNet_CSBK(lc::CSBK* csbk)
{
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
SlotType slotType;
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_CSBK);
// Regenerate the CSBK data
csbk->encode(data + 2U);
// Regenerate the Slot Type
slotType.encode(data + 2U);
// Convert the Data Sync to be from the BS or MS as needed
Sync::addDMRDataSync(data + 2U, true);
m_slot->m_rfSeqNo = 0U;
data[0U] = modem::TAG_DATA;
data[1U] = 0x00U;
if (m_slot->m_duplex)
m_slot->addFrame(data);
m_slot->writeNetwork(data, DT_CSBK, csbk->getGI() ? FLCO_GROUP : FLCO_PRIVATE, csbk->getSrcId(), csbk->getDstId(), 0U, true);
}
/*
** Control Signalling Logic
*/
@ -1428,7 +1525,9 @@ void ControlSignaling::writeRF_TSCC_Aloha()
/// </summary>
/// <param name="channelNo"></param>
/// <param name="annWd"></param>
void ControlSignaling::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
/// <param name="systemIdentity"></param>
/// <param name="requireReg"></param>
void ControlSignaling::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd, uint32_t systemIdentity, bool requireReg)
{
m_slot->m_rfSeqNo = 0U;
@ -1438,6 +1537,8 @@ void ControlSignaling::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
csbk->setAnncType(BCAST_ANNC_ANN_WD_TSCC);
csbk->setLogicalCh1(channelNo);
csbk->setAnnWdCh1(annWd);
csbk->setSystemId(systemIdentity);
csbk->setRequireReg(requireReg);
if (m_debug) {
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, %s, channelNo = %u, annWd = %u",

@ -44,13 +44,17 @@ namespace dmr
// packets.
// ---------------------------------------------------------------------------
class HOST_SW_API ControlSignaling {
class HOST_SW_API ControlSignaling
{
public:
/// <summary>Process a data frame from the RF interface.</summary>
bool process(uint8_t* data, uint32_t len);
/// <summary>Process a data frame from the network.</summary>
void processNetwork(const data::Data& dmrData);
/// <summary>Helper to write P25 adjacent site information to the network.</summary>
void writeAdjSSNetwork();
/// <summary>Helper to write a extended function packet on the RF interface.</summary>
void writeRF_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId);
/// <summary>Helper to write a call alert packet on the RF interface.</summary>
@ -77,6 +81,8 @@ namespace dmr
void writeRF_CSBK_Imm(lc::CSBK *csbk) { writeRF_CSBK(csbk, true); }
/// <summary>Helper to write a CSBK packet.</summary>
void writeRF_CSBK(lc::CSBK* csbk, bool imm = false);
/// <summary>Helper to write a network CSBK packet.</summary>
void writeNet_CSBK(lc::CSBK* csbk);
/*
** Control Signalling Logic
@ -103,7 +109,7 @@ namespace dmr
/// <summary>Helper to write a TSCC Aloha broadcast packet on the RF interface.</summary>
void writeRF_TSCC_Aloha();
/// <summary>Helper to write a TSCC Ann-Wd broadcast packet on the RF interface.</summary>
void writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd);
void writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd, uint32_t systemIdentity, bool requireReg);
/// <summary>Helper to write a TSCC Sys_Parm broadcast packet on the RF interface.</summary>
void writeRF_TSCC_Bcast_Sys_Parm();
/// <summary>Helper to write a TSCC Git Hash broadcast packet on the RF interface.</summary>

Loading…
Cancel
Save

Powered by TurnKey Linux.