diff --git a/src/common/p25/SiteData.h b/src/common/p25/SiteData.h index fcca31e3..f0c84690 100644 --- a/src/common/p25/SiteData.h +++ b/src/common/p25/SiteData.h @@ -161,6 +161,7 @@ namespace p25 /** * @brief Helper to set adjacent site data. + * @param lra Location Registration Area. * @param sysId P25 System ID. * @param rfssId P25 RFSS ID. * @param siteId P25 Site ID. @@ -168,7 +169,7 @@ namespace p25 * @param channelNo Channel Number. * @param serviceClass Service class. */ - void setAdjSite(uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass) + void setAdjSite(uint8_t lra, uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass) { // sysId clamping sysId = P25Utils::sysId(sysId); @@ -191,7 +192,7 @@ namespace p25 channelNo = 4095U; } - m_lra = 0U; + m_lra = lra; m_netId = 0U; m_sysId = sysId; @@ -213,6 +214,20 @@ namespace p25 m_lto = 0; } + /** + * @brief Helper to set adjacent site data when the Location Registration Area is unavailable. + * @param sysId P25 System ID. + * @param rfssId P25 RFSS ID. + * @param siteId P25 Site ID. + * @param channelId Channel ID. + * @param channelNo Channel Number. + * @param serviceClass Service class. + */ + void setAdjSite(uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass) + { + setAdjSite(0U, sysId, rfssId, siteId, channelId, channelNo, serviceClass); + } + /** * @brief Equals operator. * @param data Instance of SiteData to copy. diff --git a/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.cpp b/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.cpp index 51019e28..44efd232 100644 --- a/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.cpp +++ b/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.cpp @@ -24,6 +24,7 @@ using namespace p25::lc::tsbk; /* Initializes a new instance of the OSP_ADJ_STS_BCAST class. */ OSP_ADJ_STS_BCAST::OSP_ADJ_STS_BCAST() : TSBK(), + m_adjLRA(s_siteData.lra()), m_adjCFVA(CFVA::FAILURE), m_adjSysId(0U), m_adjRfssId(0U), @@ -50,6 +51,8 @@ bool OSP_ADJ_STS_BCAST::decode(const uint8_t* data, bool rawTSBK) ulong64_t tsbkValue = TSBK::toValue(tsbk); + m_adjLRA = (uint8_t)((tsbkValue >> 56) & 0xFFU); // Location Registration Area + m_adjCFVA = (uint8_t)((tsbkValue >> 52) & 0x0FU); // CFVA m_adjSysId = (uint32_t)((tsbkValue >> 40) & 0xFFFU); // Site System ID m_adjRfssId = (uint8_t)((tsbkValue >> 32) & 0xFFU); // Site RFSS ID m_adjSiteId = (uint8_t)((tsbkValue >> 24) & 0xFFU); // Site ID @@ -68,9 +71,9 @@ void OSP_ADJ_STS_BCAST::encode(uint8_t* data, bool rawTSBK, bool noTrellis) ulong64_t tsbkValue = 0U; - tsbkValue = s_siteData.lra(); // Location Registration Area + tsbkValue = m_adjLRA; // Location Registration Area tsbkValue = (tsbkValue << 4) + m_adjCFVA; // CFVA - tsbkValue = (tsbkValue << 12) + s_siteData.sysId(); // System ID + tsbkValue = (tsbkValue << 12) + m_adjSysId; // System ID tsbkValue = (tsbkValue << 8) + m_adjRfssId; // RF Sub-System ID tsbkValue = (tsbkValue << 8) + m_adjSiteId; // Site ID tsbkValue = (tsbkValue << 4) + m_adjChannelId; // Channel ID @@ -98,6 +101,7 @@ void OSP_ADJ_STS_BCAST::copy(const OSP_ADJ_STS_BCAST& data) { TSBK::copy(data); + m_adjLRA = data.m_adjLRA; m_adjCFVA = data.m_adjCFVA; m_adjSysId = data.m_adjSysId; m_adjRfssId = data.m_adjRfssId; diff --git a/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.h b/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.h index f4c227d8..fc2ce0f0 100644 --- a/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.h +++ b/src/common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.h @@ -63,6 +63,10 @@ namespace p25 public: // Adjacent Site Data + /** + * @brief Adjacent site location registration area. + */ + DECLARE_PROPERTY(uint8_t, adjLRA, AdjSiteLRA); /** * @brief Adjacent site CFVA flags. */ diff --git a/src/common/p25/lc/tsbk/OSP_SCCB.cpp b/src/common/p25/lc/tsbk/OSP_SCCB.cpp index c962bc3d..e3b11e24 100644 --- a/src/common/p25/lc/tsbk/OSP_SCCB.cpp +++ b/src/common/p25/lc/tsbk/OSP_SCCB.cpp @@ -24,8 +24,12 @@ using namespace p25::lc::tsbk; /* Initializes a new instance of the OSP_SCCB class. */ OSP_SCCB::OSP_SCCB() : TSBK(), + m_sccbRfssId(s_siteData.rfssId()), + m_sccbSiteId(s_siteData.siteId()), m_sccbChannelId1(0U), - m_sccbChannelId2(0U) + m_sccbServiceClass1(ServiceClass::INVALID), + m_sccbChannelId2(0U), + m_sccbServiceClass2(ServiceClass::INVALID) { m_lco = TSBKO::OSP_SCCB; } @@ -36,7 +40,20 @@ bool OSP_SCCB::decode(const uint8_t* data, bool rawTSBK) { assert(data != nullptr); - /* stub */ + uint8_t tsbk[P25_TSBK_LENGTH_BYTES + 1U]; + ::memset(tsbk, 0x00U, P25_TSBK_LENGTH_BYTES); + + if (!TSBK::decode(data, tsbk, rawTSBK)) + return false; + + const ulong64_t tsbkValue = TSBK::toValue(tsbk); + + m_sccbRfssId = (uint8_t)((tsbkValue >> 56) & 0xFFU); + m_sccbSiteId = (uint8_t)((tsbkValue >> 48) & 0xFFU); + m_sccbChannelId1 = (uint16_t)((tsbkValue >> 32) & 0xFFFFU); + m_sccbServiceClass1 = (uint8_t)((tsbkValue >> 24) & 0xFFU); + m_sccbChannelId2 = (uint16_t)((tsbkValue >> 8) & 0xFFFFU); + m_sccbServiceClass2 = (uint8_t)(tsbkValue & 0xFFU); return true; } @@ -49,22 +66,12 @@ void OSP_SCCB::encode(uint8_t* data, bool rawTSBK, bool noTrellis) ulong64_t tsbkValue = 0U; - tsbkValue = s_siteData.rfssId(); // RF Sub-System ID - tsbkValue = (tsbkValue << 8) + s_siteData.siteId(); // Site ID + tsbkValue = m_sccbRfssId; // RF Sub-System ID + tsbkValue = (tsbkValue << 8) + m_sccbSiteId; // Site ID tsbkValue = (tsbkValue << 16) + m_sccbChannelId1; // SCCB Channel ID 1 - if (m_sccbChannelId1 > 0) { - tsbkValue = (tsbkValue << 8) + s_siteData.serviceClass(); // System Service Class - } - else { - tsbkValue = (tsbkValue << 8) + (ServiceClass::INVALID); // System Service Class - } + tsbkValue = (tsbkValue << 8) + m_sccbServiceClass1; // System Service Class tsbkValue = (tsbkValue << 16) + m_sccbChannelId2; // SCCB Channel ID 2 - if (m_sccbChannelId2 > 0) { - tsbkValue = (tsbkValue << 8) + s_siteData.serviceClass(); // System Service Class - } - else { - tsbkValue = (tsbkValue << 8) + (ServiceClass::INVALID); // System Service Class - } + tsbkValue = (tsbkValue << 8) + m_sccbServiceClass2; // System Service Class std::unique_ptr tsbk = TSBK::fromValue(tsbkValue); TSBK::encode(data, tsbk.get(), rawTSBK, noTrellis); @@ -87,6 +94,10 @@ void OSP_SCCB::copy(const OSP_SCCB& data) { TSBK::copy(data); + m_sccbRfssId = data.m_sccbRfssId; + m_sccbSiteId = data.m_sccbSiteId; m_sccbChannelId1 = data.m_sccbChannelId1; + m_sccbServiceClass1 = data.m_sccbServiceClass1; m_sccbChannelId2 = data.m_sccbChannelId2; + m_sccbServiceClass2 = data.m_sccbServiceClass2; } diff --git a/src/common/p25/lc/tsbk/OSP_SCCB.h b/src/common/p25/lc/tsbk/OSP_SCCB.h index 600b5e37..ad56c92c 100644 --- a/src/common/p25/lc/tsbk/OSP_SCCB.h +++ b/src/common/p25/lc/tsbk/OSP_SCCB.h @@ -63,13 +63,29 @@ namespace p25 public: /** - * @brief SCCB channel ID 1. + * @brief RF Sub-System ID containing the secondary control channels. */ - DECLARE_PROPERTY(uint8_t, sccbChannelId1, SCCBChnId1); + DECLARE_PROPERTY(uint8_t, sccbRfssId, SCCBRFSSId); /** - * @brief SCCB channel ID 2. + * @brief Site ID containing the secondary control channels. */ - DECLARE_PROPERTY(uint8_t, sccbChannelId2, SCCBChnId2); + DECLARE_PROPERTY(uint8_t, sccbSiteId, SCCBSiteId); + /** + * @brief Complete implicit SCCB channel value A. + */ + DECLARE_PROPERTY(uint16_t, sccbChannelId1, SCCBChnId1); + /** + * @brief System service class for SCCB channel A. + */ + DECLARE_PROPERTY(uint8_t, sccbServiceClass1, SCCBSvcClass1); + /** + * @brief Complete implicit SCCB channel value B. + */ + DECLARE_PROPERTY(uint16_t, sccbChannelId2, SCCBChnId2); + /** + * @brief System service class for SCCB channel B. + */ + DECLARE_PROPERTY(uint8_t, sccbServiceClass2, SCCBSvcClass2); DECLARE_COPY(OSP_SCCB); }; diff --git a/src/common/p25/lc/tsbk/OSP_SCCB_EXP.cpp b/src/common/p25/lc/tsbk/OSP_SCCB_EXP.cpp index 93680c23..7a2a5f2f 100644 --- a/src/common/p25/lc/tsbk/OSP_SCCB_EXP.cpp +++ b/src/common/p25/lc/tsbk/OSP_SCCB_EXP.cpp @@ -24,8 +24,13 @@ using namespace p25::lc::tsbk; /* Initializes a new instance of the OSP_SCCB_EXP class. */ OSP_SCCB_EXP::OSP_SCCB_EXP() : TSBK(), + m_sccbRfssId(s_siteData.rfssId()), + m_sccbSiteId(s_siteData.siteId()), m_sccbChannelId1(0U), - m_sccbChannelNo(0U) + m_sccbChannelNo(0U), + m_sccbChannelId2(0U), + m_sccbChannelNo2(0U), + m_sccbServiceClass(ServiceClass::INVALID) { m_lco = TSBKO::OSP_SCCB_EXP; } @@ -36,7 +41,21 @@ bool OSP_SCCB_EXP::decode(const uint8_t* data, bool rawTSBK) { assert(data != nullptr); - /* stub */ + uint8_t tsbk[P25_TSBK_LENGTH_BYTES + 1U]; + ::memset(tsbk, 0x00U, P25_TSBK_LENGTH_BYTES); + + if (!TSBK::decode(data, tsbk, rawTSBK)) + return false; + + const ulong64_t tsbkValue = TSBK::toValue(tsbk); + + m_sccbRfssId = (uint8_t)((tsbkValue >> 56) & 0xFFU); + m_sccbSiteId = (uint8_t)((tsbkValue >> 48) & 0xFFU); + m_sccbChannelId1 = (uint8_t)((tsbkValue >> 44) & 0x0FU); + m_sccbChannelNo = (uint32_t)((tsbkValue >> 32) & 0x0FFFU); + m_sccbChannelId2 = (uint8_t)((tsbkValue >> 20) & 0x0FU); + m_sccbChannelNo2 = (uint32_t)((tsbkValue >> 8) & 0x0FFFU); + m_sccbServiceClass = (uint8_t)(tsbkValue & 0xFFU); return true; } @@ -49,20 +68,15 @@ void OSP_SCCB_EXP::encode(uint8_t* data, bool rawTSBK, bool noTrellis) ulong64_t tsbkValue = 0U; - tsbkValue = s_siteData.rfssId(); // RF Sub-System ID - tsbkValue = (tsbkValue << 8) + s_siteData.siteId(); // Site ID + tsbkValue = m_sccbRfssId; // RF Sub-System ID + tsbkValue = (tsbkValue << 8) + m_sccbSiteId; // Site ID tsbkValue = (tsbkValue << 4) + m_sccbChannelId1; // Channel (T) ID tsbkValue = (tsbkValue << 12) + m_sccbChannelNo; // Channel (T) Number - tsbkValue = (tsbkValue << 12) + m_sccbChannelId1; // Channel (R) ID - tsbkValue = (tsbkValue << 12) + m_sccbChannelNo; // Channel (R) Number + tsbkValue = (tsbkValue << 12) + m_sccbChannelId2; // Channel (R) ID + tsbkValue = (tsbkValue << 12) + m_sccbChannelNo2; // Channel (R) Number - if (m_sccbChannelId1 > 0) { - tsbkValue = (tsbkValue << 8) + s_siteData.serviceClass(); // System Service Class - } - else { - tsbkValue = (tsbkValue << 8) + (ServiceClass::INVALID); // System Service Class - } + tsbkValue = (tsbkValue << 8) + m_sccbServiceClass; // System Service Class std::unique_ptr tsbk = TSBK::fromValue(tsbkValue); TSBK::encode(data, tsbk.get(), rawTSBK, noTrellis); @@ -85,6 +99,11 @@ void OSP_SCCB_EXP::copy(const OSP_SCCB_EXP& data) { TSBK::copy(data); + m_sccbRfssId = data.m_sccbRfssId; + m_sccbSiteId = data.m_sccbSiteId; m_sccbChannelId1 = data.m_sccbChannelId1; m_sccbChannelNo = data.m_sccbChannelNo; + m_sccbChannelId2 = data.m_sccbChannelId2; + m_sccbChannelNo2 = data.m_sccbChannelNo2; + m_sccbServiceClass = data.m_sccbServiceClass; } diff --git a/src/common/p25/lc/tsbk/OSP_SCCB_EXP.h b/src/common/p25/lc/tsbk/OSP_SCCB_EXP.h index dd9efb30..ceffd663 100644 --- a/src/common/p25/lc/tsbk/OSP_SCCB_EXP.h +++ b/src/common/p25/lc/tsbk/OSP_SCCB_EXP.h @@ -63,13 +63,33 @@ namespace p25 public: /** - * @brief SCCB channel ID 1. + * @brief RF Sub-System ID containing the secondary control channel. + */ + DECLARE_PROPERTY(uint8_t, sccbRfssId, SCCBRFSSId); + /** + * @brief Site ID containing the secondary control channel. + */ + DECLARE_PROPERTY(uint8_t, sccbSiteId, SCCBSiteId); + /** + * @brief Explicit SCCB transmit channel ID. */ DECLARE_PROPERTY(uint8_t, sccbChannelId1, SCCBChnId1); /** - * @brief Explicit SCCB channel number. + * @brief Explicit SCCB transmit channel number. */ DECLARE_PROPERTY(uint32_t, sccbChannelNo, SCCBChnNo); + /** + * @brief Explicit SCCB receive channel ID. + */ + DECLARE_PROPERTY(uint8_t, sccbChannelId2, SCCBChnId2); + /** + * @brief Explicit SCCB receive channel number. + */ + DECLARE_PROPERTY(uint32_t, sccbChannelNo2, SCCBChnNo2); + /** + * @brief System service class for the secondary control channel. + */ + DECLARE_PROPERTY(uint8_t, sccbServiceClass, SCCBSvcClass); DECLARE_COPY(OSP_SCCB_EXP); }; diff --git a/src/common/p25/lc/tsbk/TSBKFactory.cpp b/src/common/p25/lc/tsbk/TSBKFactory.cpp index b3d59eee..c3a437aa 100644 --- a/src/common/p25/lc/tsbk/TSBKFactory.cpp +++ b/src/common/p25/lc/tsbk/TSBKFactory.cpp @@ -232,6 +232,8 @@ std::unique_ptr TSBKFactory::createTSBK(const uint8_t* data, bool rawTSBK) return decode(new ISP_AUTH_SU_DMD(), data, rawTSBK); case TSBKO::OSP_ADJ_STS_BCAST: return decode(new OSP_ADJ_STS_BCAST(), data, rawTSBK); + case TSBKO::OSP_SCCB: + return decode(new OSP_SCCB(), data, rawTSBK); default: LogError(LOG_P25, "TSBKFactory::create(), unknown TSBK LCO value, mfId = $%02X, lco = $%02X", mfId, lco); break; diff --git a/src/host/p25/Control.cpp b/src/host/p25/Control.cpp index 2b30078e..d96cf813 100644 --- a/src/host/p25/Control.cpp +++ b/src/host/p25/Control.cpp @@ -1170,14 +1170,14 @@ void Control::clockSiteData(uint32_t ms) if (m_control->m_sccbUpdateCnt.size() > 0) { // update SCCB data for (auto& entry : m_control->m_sccbUpdateCnt) { - uint8_t rfssId = entry.first; + uint16_t channel = entry.first; uint8_t updateCnt = entry.second; if (updateCnt > 0U) { updateCnt--; } if (updateCnt == 0U) { - SiteData siteData = m_control->m_sccbTable[rfssId]; + SiteData siteData = m_control->m_sccbTable[channel]; LogWarning(LOG_NET, "P25, Secondary Control Channel Expired, no data [FAILED], sysId = $%03X, rfss = $%02X, site = $%02X, chNo = %u-%u, svcClass = $%02X", siteData.sysId(), siteData.rfssId(), siteData.siteId(), siteData.channelId(), siteData.channelNo(), siteData.serviceClass()); } diff --git a/src/host/p25/packet/ControlSignaling.cpp b/src/host/p25/packet/ControlSignaling.cpp index 6c64a2af..b73eef28 100644 --- a/src/host/p25/packet/ControlSignaling.cpp +++ b/src/host/p25/packet/ControlSignaling.cpp @@ -1019,7 +1019,9 @@ bool ControlSignaling::processNetwork(uint8_t* data, uint32_t len, lc::LC& contr } OSP_ADJ_STS_BCAST* osp = static_cast(tsbk.get()); - if (osp->getAdjSiteId() != m_p25->m_siteData.siteId()) { + if (osp->getAdjSiteSysId() != m_p25->m_siteData.sysId() || + osp->getAdjSiteRFSSId() != m_p25->m_siteData.rfssId() || + osp->getAdjSiteId() != m_p25->m_siteData.siteId()) { // update site table data SiteData site; try { @@ -1033,7 +1035,7 @@ bool ControlSignaling::processNetwork(uint8_t* data, uint32_t len, lc::LC& contr osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass()); } - site.setAdjSite(osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass()); + site.setAdjSite(osp->getAdjSiteLRA(), osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass()); m_adjSiteTable[site.siteId()] = site; m_adjSiteUpdateCnt[site.siteId()] = ADJ_SITE_UPDATE_CNT; @@ -1044,7 +1046,8 @@ bool ControlSignaling::processNetwork(uint8_t* data, uint32_t len, lc::LC& contr // update site table data SiteData site; try { - site = m_sccbTable.at(osp->getAdjSiteRFSSId()); + const uint16_t channel = (uint16_t)((osp->getAdjSiteChnId() << 12) | osp->getAdjSiteChnNo()); + site = m_sccbTable.at(channel); } catch (...) { site = SiteData(); @@ -1055,10 +1058,11 @@ bool ControlSignaling::processNetwork(uint8_t* data, uint32_t len, lc::LC& contr osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass()); } - site.setAdjSite(osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass()); + site.setAdjSite(osp->getAdjSiteLRA(), osp->getAdjSiteSysId(), osp->getAdjSiteRFSSId(), osp->getAdjSiteId(), osp->getAdjSiteChnId(), osp->getAdjSiteChnNo(), osp->getAdjSiteSvcClass()); - m_sccbTable[site.rfssId()] = site; - m_sccbUpdateCnt[site.rfssId()] = ADJ_SITE_UPDATE_CNT; + const uint16_t channel = (uint16_t)((site.channelId() << 12) | site.channelNo()); + m_sccbTable[channel] = site; + m_sccbUpdateCnt[channel] = ADJ_SITE_UPDATE_CNT; } return true; @@ -1415,6 +1419,7 @@ void ControlSignaling::writeAdjSSNetwork() // transmit adjacent site broadcast std::unique_ptr osp = std::make_unique(); osp->setSrcId(WUID_FNE); + osp->setAdjSiteLRA(m_p25->m_siteData.lra()); osp->setAdjSiteCFVA(cfva); osp->setAdjSiteSysId(m_p25->m_siteData.sysId()); osp->setAdjSiteRFSSId(m_p25->m_siteData.rfssId()); @@ -2462,6 +2467,7 @@ void ControlSignaling::queueRF_TSBK_Ctrl(uint8_t lco) } // transmit adjacent site broadcast + osp->setAdjSiteLRA(site.lra()); osp->setAdjSiteCFVA(cfva); osp->setAdjSiteSysId(site.sysId()); osp->setAdjSiteRFSSId(site.rfssId()); @@ -2501,8 +2507,13 @@ void ControlSignaling::queueRF_TSBK_Ctrl(uint8_t lco) // transmit SCCB broadcast osp->setLCO(TSBKO::OSP_SCCB_EXP); + osp->setSCCBRFSSId(site.rfssId()); + osp->setSCCBSiteId(site.siteId()); osp->setSCCBChnId1(site.channelId()); osp->setSCCBChnNo(site.channelNo()); + osp->setSCCBChnId2(site.channelId()); + osp->setSCCBChnNo2(site.channelNo()); + osp->setSCCBSvcClass(site.serviceClass()); tsbk = std::move(osp); m_mbfSCCBCnt++; diff --git a/src/host/p25/packet/ControlSignaling.h b/src/host/p25/packet/ControlSignaling.h index 3c81e0a8..b1d01894 100644 --- a/src/host/p25/packet/ControlSignaling.h +++ b/src/host/p25/packet/ControlSignaling.h @@ -249,8 +249,8 @@ namespace p25 std::unordered_map m_adjSiteTable; std::unordered_map m_adjSiteUpdateCnt; - std::unordered_map m_sccbTable; - std::unordered_map m_sccbUpdateCnt; + std::unordered_map m_sccbTable; + std::unordered_map m_sccbUpdateCnt; std::unordered_map m_llaDemandTable; std::vector m_llaDeferredAuthList; diff --git a/tests/p25/TSBK_Tests.cpp b/tests/p25/TSBK_Tests.cpp index f8d63e68..8b32959d 100644 --- a/tests/p25/TSBK_Tests.cpp +++ b/tests/p25/TSBK_Tests.cpp @@ -9,6 +9,8 @@ */ #include "host/Defines.h" #include "common/p25/lc/tsbk/OSP_SCCB.h" +#include "common/p25/lc/tsbk/OSP_SCCB_EXP.h" +#include "common/p25/lc/tsbk/OSP_ADJ_STS_BCAST.h" #include "common/p25/lc/tsbk/OSP_SYS_SRV_BCAST.h" #include "common/p25/lc/tsbk/OSP_GRP_AFF_Q.h" #include "common/p25/lc/tsbk/ISP_GRP_AFF_Q_RSP.h" @@ -66,6 +68,87 @@ TEST_CASE("TSBK", "[p25][tsbk]") { TSBK::setSiteData(previousSiteData); } + SECTION("Secondary_Control_Channel_Broadcast_Known_Bytes") { + OSP_SCCB source; + source.setSCCBRFSSId(0x21U); + source.setSCCBSiteId(0x43U); + source.setSCCBChnId1(0x1567U); + source.setSCCBSvcClass1(0xA5U); + source.setSCCBChnId2(0x2ABCU); + source.setSCCBSvcClass2(0x5AU); + + uint8_t raw[P25_TSBK_LENGTH_BYTES] = { 0U }; + source.encode(raw, true, true); + + const uint8_t expected[] = { 0x21U, 0x43U, 0x15U, 0x67U, 0xA5U, 0x2AU, 0xBCU, 0x5AU }; + CHECK(::memcmp(raw + 2U, expected, sizeof(expected)) == 0); + + OSP_SCCB decoded; + REQUIRE(decoded.decode(raw, true)); + CHECK(decoded.getSCCBRFSSId() == 0x21U); + CHECK(decoded.getSCCBSiteId() == 0x43U); + CHECK(decoded.getSCCBChnId1() == 0x1567U); + CHECK(decoded.getSCCBSvcClass1() == 0xA5U); + CHECK(decoded.getSCCBChnId2() == 0x2ABCU); + CHECK(decoded.getSCCBSvcClass2() == 0x5AU); + } + + SECTION("Secondary_Control_Channel_Broadcast_Explicit_Known_Bytes") { + OSP_SCCB_EXP source; + source.setSCCBRFSSId(0x21U); + source.setSCCBSiteId(0x43U); + source.setSCCBChnId1(0x01U); + source.setSCCBChnNo(0x567U); + source.setSCCBChnId2(0x02U); + source.setSCCBChnNo2(0xABCU); + source.setSCCBSvcClass(0xA5U); + + uint8_t raw[P25_TSBK_LENGTH_BYTES] = { 0U }; + source.encode(raw, true, true); + + const uint8_t expected[] = { 0x21U, 0x43U, 0x15U, 0x67U, 0x00U, 0x2AU, 0xBCU, 0xA5U }; + CHECK(::memcmp(raw + 2U, expected, sizeof(expected)) == 0); + + OSP_SCCB_EXP decoded; + REQUIRE(decoded.decode(raw, true)); + CHECK(decoded.getSCCBRFSSId() == 0x21U); + CHECK(decoded.getSCCBSiteId() == 0x43U); + CHECK(decoded.getSCCBChnId1() == 0x01U); + CHECK(decoded.getSCCBChnNo() == 0x567U); + CHECK(decoded.getSCCBChnId2() == 0x02U); + CHECK(decoded.getSCCBChnNo2() == 0xABCU); + CHECK(decoded.getSCCBSvcClass() == 0xA5U); + } + + SECTION("Adjacent_Status_Broadcast_Known_Bytes") { + OSP_ADJ_STS_BCAST source; + source.setAdjSiteLRA(0x12U); + source.setAdjSiteCFVA(0x0BU); + source.setAdjSiteSysId(0x345U); + source.setAdjSiteRFSSId(0x67U); + source.setAdjSiteId(0x89U); + source.setAdjSiteChnId(0x0AU); + source.setAdjSiteChnNo(0xBCDU); + source.setAdjSiteSvcClass(0x5AU); + + uint8_t raw[P25_TSBK_LENGTH_BYTES] = { 0U }; + source.encode(raw, true, true); + + const uint8_t expected[] = { 0x12U, 0xB3U, 0x45U, 0x67U, 0x89U, 0xABU, 0xCDU, 0x5AU }; + CHECK(::memcmp(raw + 2U, expected, sizeof(expected)) == 0); + + OSP_ADJ_STS_BCAST decoded; + REQUIRE(decoded.decode(raw, true)); + CHECK(decoded.getAdjSiteLRA() == 0x12U); + CHECK(decoded.getAdjSiteCFVA() == 0x0BU); + CHECK(decoded.getAdjSiteSysId() == 0x345U); + CHECK(decoded.getAdjSiteRFSSId() == 0x67U); + CHECK(decoded.getAdjSiteId() == 0x89U); + CHECK(decoded.getAdjSiteChnId() == 0x0AU); + CHECK(decoded.getAdjSiteChnNo() == 0xBCDU); + CHECK(decoded.getAdjSiteSvcClass() == 0x5AU); + } + SECTION("Group_Affiliation_Query_Known_Bytes") { OSP_GRP_AFF_Q query; query.setDstId(0x123456U);