correct P25 system service broadcast field packing, implement configurable WUID validity timing and properly encode blank Motorola BSI callsign characters;

pull/134/head
Bryan Biedenkapp 3 days ago
parent a0a670937e
commit a14bb62b0b

@ -326,8 +326,11 @@ protocols:
verifyReg: false
# Flag indicating automated 12-hour idle group affiliation timeout is disabled.
disableGrpAffTimeout: false
# Flag indicating automated 12-hour idle unit registration timeout is disabled.
# Flag indicating the WUID validity timeout is disabled. When true, the broadcast value is 255.
disableUnitRegTimeout: false
# WUID validity advertised in SYS_SRV_BCST. The value adds 30-minute increments to the
# four-hour minimum; 0 is four hours and 255 disables WUID expiration.
wuidValidity: 0
# Flag indicating the host requires LLA verification before allowing unit registration.
requireLLAForReg: false
# Flag indicating whether verbose dumping of P25 data packets is enabled.

@ -45,6 +45,7 @@ AffiliationLookup::AffiliationLookup(const std::string name, ChannelLookup* chan
m_chLookup(channelLookup),
m_disableUnitRegTimeout(false),
m_disableGrpAffTimeout(false),
m_unitRegTimeout(UNIT_REG_TIMEOUT),
m_verbose(verbose)
{
m_name = name;
@ -75,7 +76,7 @@ void AffiliationLookup::unitReg(uint32_t srcId, bool log)
m_unitRegTable.push_back(srcId);
m_unitRegTimers[srcId] = Timer(1000U, UNIT_REG_TIMEOUT);
m_unitRegTimers[srcId] = Timer(1000U, m_unitRegTimeout);
m_unitRegTimers[srcId].start();
if (m_verbose && log) {
@ -218,7 +219,7 @@ void AffiliationLookup::replaceUnitRegistrations(const std::vector<uint32_t>& re
replacementTimers.emplace(srcId, currentTimer->second);
}
else {
Timer timer(1000U, UNIT_REG_TIMEOUT);
Timer timer(1000U, m_unitRegTimeout);
timer.start();
replacementTimers.emplace(srcId, timer);
}

@ -287,6 +287,11 @@ namespace lookups
* @param disable Flag indicating idle unit registration timeout should be disabled.
*/
void setDisableUnitRegTimeout(bool disabled) { m_disableUnitRegTimeout = disabled; }
/**
* @brief Sets the idle unit registration timeout.
* @param timeout Timeout in seconds.
*/
void setUnitRegTimeout(uint32_t timeout) { m_unitRegTimeout = timeout; }
/**
* @brief Helper to determine if the group affiliation timeout is enabled or not.
@ -339,6 +344,7 @@ namespace lookups
bool m_disableUnitRegTimeout;
bool m_disableGrpAffTimeout;
uint32_t m_unitRegTimeout;
bool m_verbose;

@ -46,6 +46,7 @@ namespace p25
m_callsign("CHANGEME"),
m_chCnt(0U),
m_netActive(false),
m_wuidValidity(0U),
m_lto(0)
{
/* stub */
@ -75,6 +76,7 @@ namespace p25
m_callsign("CHANGEME"),
m_chCnt(0U),
m_netActive(false),
m_wuidValidity(0U),
m_lto(0)
{
// lra clamping
@ -148,6 +150,15 @@ namespace p25
m_netActive = netActive;
}
/**
* @brief Helper to set the WUID validity period advertised by this site.
* @param wuidValidity WUID validity field in 30-minute increments beyond four hours; 0xFF disables expiry.
*/
void setWuidValidity(uint8_t wuidValidity)
{
m_wuidValidity = wuidValidity;
}
/**
* @brief Helper to set adjacent site data.
* @param sysId P25 System ID.
@ -198,6 +209,7 @@ namespace p25
m_callsign = "ADJSITE ";
m_chCnt = -1; // don't store channel count for adjacent sites
m_netActive = true; // adjacent sites are explicitly network active
m_wuidValidity = 0U;
m_lto = 0;
}
@ -228,6 +240,8 @@ namespace p25
m_netActive = data.m_netActive;
m_wuidValidity = data.m_wuidValidity;
m_lto = data.m_lto;
}
@ -284,6 +298,10 @@ namespace p25
* @brief Flag indicating whether this site is a linked active network member.
*/
DECLARE_RO_PROPERTY_PLAIN(bool, netActive);
/**
* @brief WUID validity field in 30-minute increments beyond four hours; 0xFF disables expiry.
*/
DECLARE_RO_PROPERTY_PLAIN(uint8_t, wuidValidity);
/**
* @brief Local Time Offset.
*/

@ -45,14 +45,15 @@ void LC_SYS_SRV_BCAST::encode(uint8_t* data)
{
assert(data != nullptr);
const uint32_t services = (s_siteData.netActive()) ? SystemService::NET_ACTIVE : 0U | SYS_SRV_DEFAULT;
const uint32_t services = SYS_SRV_TRUNK | (s_siteData.netActive() ? SystemService::NET_ACTIVE : 0U);
ulong64_t rsValue = 0U;
m_implicit = true;
rsValue = 0U;
rsValue = (rsValue << 16) + services; // System Services Available
rsValue = s_siteData.wuidValidity(); // WUID Validity
rsValue = (rsValue << 8); // Request Priority Level
rsValue = (rsValue << 24) + services; // System Services Available
rsValue = (rsValue << 24) + services; // System Services Supported
std::unique_ptr<uint8_t[]> rs = TDULC::fromValue(rsValue);

@ -49,10 +49,12 @@ void OSP_MOT_CC_BSI::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
m_mfId = MFG_MOT;
tsbkValue = (s_siteCallsign[0] - 43U) & 0x3F; // Character 0
for (uint8_t i = 1; i < MOT_CALLSIGN_LENGTH_BYTES; i++) {
tsbkValue = (tsbkValue << 6) + ((s_siteCallsign[i] - 43U) & 0x3F); // Character 1 - 7
// encode the site callsign into the TSBK value using six-bit codes
for (uint8_t i = 0U; i < MOT_CALLSIGN_LENGTH_BYTES; i++) {
const uint8_t code = s_siteCallsign[i] == 0U || s_siteCallsign[i] == ' ' ? 0U : (s_siteCallsign[i] - 43U) & 0x3FU;
tsbkValue = (tsbkValue << 6) + code;
}
tsbkValue = (tsbkValue << 4) + s_siteData.channelId(); // Channel ID
tsbkValue = (tsbkValue << 12) + s_siteData.channelNo(); // Channel Number

@ -23,7 +23,11 @@ using namespace p25::lc::tsbk;
/* Initializes a new instance of the OSP_SYS_SRV_BCAST class. */
OSP_SYS_SRV_BCAST::OSP_SYS_SRV_BCAST() : TSBK()
OSP_SYS_SRV_BCAST::OSP_SYS_SRV_BCAST() : TSBK(),
m_wuidValidity(0U),
m_servicesAvailable(0U),
m_servicesSupported(0U),
m_requestPriority(0U)
{
m_lco = TSBKO::OSP_SYS_SRV_BCAST;
}
@ -34,7 +38,15 @@ bool OSP_SYS_SRV_BCAST::decode(const uint8_t* data, bool rawTSBK)
{
assert(data != nullptr);
/* stub */
DECLARE_UINT8_ARRAY(payload, P25_TSBK_LENGTH_BYTES);
if (!TSBK::decode(data, payload, rawTSBK))
return false;
const ulong64_t tsbkValue = TSBK::toValue(payload);
m_wuidValidity = (uint8_t)((tsbkValue >> 56) & 0xFFU); // WUID Validity
m_servicesAvailable = (uint32_t)((tsbkValue >> 32) & 0xFFFFFFU); // System Services Available
m_servicesSupported = (uint32_t)((tsbkValue >> 8) & 0xFFFFFFU); // System Services Supported
m_requestPriority = (uint8_t)(tsbkValue & 0xFFU); // Request Priority Level
return true;
}
@ -45,12 +57,14 @@ void OSP_SYS_SRV_BCAST::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
{
assert(data != nullptr);
const uint32_t services = (s_siteData.netActive()) ? SystemService::NET_ACTIVE : 0U | SYS_SRV_DEFAULT;
const uint32_t services = SYS_SRV_TRUNK | (s_siteData.netActive() ? SystemService::NET_ACTIVE : 0U);
ulong64_t tsbkValue = 0U;
tsbkValue = (tsbkValue << 16) + services; // System Services Available
tsbkValue = s_siteData.wuidValidity(); // WUID Validity
tsbkValue = (tsbkValue << 24) + services; // System Services Available
tsbkValue = (tsbkValue << 24) + services; // System Services Supported
tsbkValue = (tsbkValue << 8); // Request Priority Level
std::unique_ptr<uint8_t[]> tsbk = TSBK::fromValue(tsbkValue);
TSBK::encode(data, tsbk.get(), rawTSBK, noTrellis);

@ -60,6 +60,24 @@ namespace p25
* @returns std::string String representation of the TSBK.
*/
std::string toString(bool isp = false) override;
public:
/**
* @brief WUID validity field in 30-minute increments beyond four hours; 0xFF disables expiry.
*/
DECLARE_RO_PROPERTY(uint8_t, wuidValidity, WUIDValidity);
/**
* @brief Bitmap of services currently available at the site.
*/
DECLARE_RO_PROPERTY(uint32_t, servicesAvailable, ServicesAvailable);
/**
* @brief Bitmap of services supported by the site.
*/
DECLARE_RO_PROPERTY(uint32_t, servicesSupported, ServicesSupported);
/**
* @brief Lowest service-request priority currently accepted by the site.
*/
DECLARE_RO_PROPERTY(uint8_t, requestPriority, RequestPriority);
};
} // namespace tsbk
} // namespace lc

@ -402,6 +402,23 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
m_siteData = SiteData(netId, sysId, rfssId, siteId, 0U, channelId, channelNo, serviceClass, lto);
m_siteData.setCallsign(cwCallsign);
bool disableUnitRegTimeout = p25Protocol["disableUnitRegTimeout"].as<bool>(false);
uint32_t wuidValidity = p25Protocol["wuidValidity"].as<uint32_t>(0U);
if (wuidValidity > 0xFFU) {
LogWarning(LOG_P25, "WUID validity value exceeds 8 bits, defaulting to 0 (4 hours).");
wuidValidity = 0U;
}
disableUnitRegTimeout = disableUnitRegTimeout || wuidValidity == 0xFFU;
if (disableUnitRegTimeout)
wuidValidity = 0xFFU;
m_siteData.setWuidValidity((uint8_t)wuidValidity);
if (!disableUnitRegTimeout) {
const uint32_t wuidValiditySeconds = (4U * 60U * 60U) + (wuidValidity * 30U * 60U);
m_affiliations->setUnitRegTimeout(wuidValiditySeconds);
}
m_affiliations->setDisableUnitRegTimeout(disableUnitRegTimeout);
lc::LC::setSiteData(m_siteData);
lc::TDULC::setSiteData(m_siteData);
@ -422,9 +439,6 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
bool disableGrpAffTimeout = p25Protocol["disableGrpAffTimeout"].as<bool>(false);
m_affiliations->setDisableGrpAffTimeout(disableGrpAffTimeout);
bool disableUnitRegTimeout = p25Protocol["disableUnitRegTimeout"].as<bool>(false);
m_affiliations->setDisableUnitRegTimeout(disableUnitRegTimeout);
// set the grant release callback
m_affiliations->setReleaseGrantCallback([=](uint32_t chNo, uint32_t srcId, uint32_t dstId, uint8_t slot) {
m_control->m_telIntGrants.erase(dstId);

@ -9,6 +9,7 @@
*/
#include "host/Defines.h"
#include "common/p25/lc/tsbk/OSP_SCCB.h"
#include "common/p25/lc/tsbk/OSP_SYS_SRV_BCAST.h"
#include "common/p25/lc/tsbk/OSP_TSBK_RAW.h"
#include "common/p25/lc/tsbk/TSBKFactory.h"
#include "common/p25/data/DataBlock.h"
@ -33,6 +34,36 @@ TEST_CASE("TSBK", "[p25][tsbk]") {
REQUIRE(P25_TSBK_FEC_LENGTH_BITS == (P25_TSBK_FEC_LENGTH_BYTES * 8 - 4)); // 196 bits (Trellis)
}
SECTION("System_Service_Broadcast_Known_Bytes") {
const SiteData previousSiteData = TSBK::getSiteData();
SiteData siteData;
siteData.setNetActive(true);
siteData.setWuidValidity(0x02U);
TSBK::setSiteData(siteData);
OSP_SYS_SRV_BCAST source;
uint8_t raw[P25_TSBK_LENGTH_BYTES];
::memset(raw, 0x00U, sizeof(raw));
source.encode(raw, true, true);
const uint32_t expectedServices = SYS_SRV_TRUNK | SystemService::NET_ACTIVE;
const uint32_t servicesAvailable = GET_UINT24(raw, 3U)
const uint32_t servicesSupported = GET_UINT24(raw, 6U)
CHECK(raw[2U] == 0x02U);
CHECK(servicesAvailable == expectedServices);
CHECK(servicesSupported == expectedServices);
CHECK(raw[9U] == 0x00U);
OSP_SYS_SRV_BCAST broadcast;
REQUIRE(broadcast.decode(raw, true));
CHECK(broadcast.getWUIDValidity() == 0x02U);
CHECK(broadcast.getServicesAvailable() == expectedServices);
CHECK(broadcast.getServicesSupported() == expectedServices);
CHECK(broadcast.getRequestPriority() == 0x00U);
TSBK::setSiteData(previousSiteData);
}
SECTION("Emergency_Alarm_Request_Roundtrip") {
ISP_EMERG_ALRM_REQ source;
source.setSpecialInfo1(0x01U);

Loading…
Cancel
Save

Powered by TurnKey Linux.