refactor P25 LC; refactor DMR CSBK; better handle scenario where P25 may start without having received a HDU, in this case we will transmit without HDU which would be interpreted by SUs as a late entry condition (better helps encryption sync in some cases);

pull/1/head
Bryan Biedenkapp 5 years ago
parent 595f6f4dd9
commit 525ffd9471

@ -62,13 +62,6 @@ protocols:
callHang: 5
noStatusAck: false
noMessageAck: true
statusCmd:
enable: true
radioCheck: 1
radioInhibit: 0
radioUninhibit: 0
radioForceReg: 0
radioForceDereg: 0
silenceThreshold: 124
disableNetworkHDU: false
queueSize: 5000

@ -129,8 +129,7 @@ bool Control::processWakeup(const uint8_t* data)
return false;
// generate a new CSBK and check validity
lc::CSBK csbk = lc::CSBK();
csbk.setVerbose(m_dumpCSBKData);
lc::CSBK csbk = lc::CSBK(SiteData(), lookups::IdenTable(), m_dumpCSBKData);
bool valid = csbk.decode(data + 2U);
if (!valid)

@ -86,8 +86,7 @@ bool ControlPacket::process(uint8_t* data, uint32_t len)
if (dataType == DT_CSBK) {
// generate a new CSBK and check validity
lc::CSBK csbk = lc::CSBK();
csbk.setVerbose(m_dumpCSBKData);
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
bool valid = csbk.decode(data + 2U);
if (!valid)
@ -230,7 +229,7 @@ void ControlPacket::processNetwork(const data::Data & dmrData)
dmrData.getData(data + 2U);
if (dataType == DT_CSBK) {
lc::CSBK csbk = lc::CSBK();
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
bool valid = csbk.decode(data + 2U);
@ -399,7 +398,7 @@ void ControlPacket::writeRF_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_CSBK);
lc::CSBK csbk = lc::CSBK();
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_EXT_FNCT);
csbk.setFID(FID_DMRA);
@ -448,7 +447,7 @@ void ControlPacket::writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId)
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_CSBK);
lc::CSBK csbk = lc::CSBK();
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_CALL_ALRT);
csbk.setFID(FID_DMRA);
@ -521,13 +520,12 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_CSBK);
lc::CSBK csbk = lc::CSBK();
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_BROADCAST);
csbk.setFID(FID_ETSI);
csbk.setAnncType(BCAST_ANNC_ANN_WD_TSCC);
csbk.setSiteData(m_slot->m_siteData);
csbk.setLogicalCh1(channelNo);
csbk.setAnnWdCh1(annWd);
@ -557,7 +555,6 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
// MBC frame 2
csbk.setLastBlock(false);
csbk.setCdef(true);
csbk.setIdenTable(m_slot->m_idenEntry);
// Regenerate the CSBK data
csbk.encode(data + 2U);
@ -591,13 +588,12 @@ void ControlPacket::writeRF_TSCC_Bcast_Sys_Parm()
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_CSBK);
lc::CSBK csbk = lc::CSBK();
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_BROADCAST);
csbk.setFID(FID_ETSI);
csbk.setAnncType(BCAST_ANNC_SITE_PARMS);
csbk.setSiteData(m_slot->m_siteData);
// Regenerate the CSBK data
csbk.encode(data + 2U);

@ -48,7 +48,8 @@ namespace dmr
m_netId(1U),
m_siteId(1U),
m_parId(3U),
m_requireReg(false)
m_requireReg(false),
m_netActive(false)
{
/* stub */
}
@ -63,7 +64,8 @@ namespace dmr
m_netId(netId),
m_siteId(siteId),
m_parId(parId),
m_requireReg(requireReq)
m_requireReg(requireReq),
m_netActive(false)
{
// siteModel clamping
if (siteModel > SITE_MODEL_HUGE)
@ -143,6 +145,13 @@ namespace dmr
parId = 3U;
}
/// <summary>Helper to set the site network active flag.</summary>
/// <param name="netActive">Network active.</param>
void setNetActive(bool netActive)
{
m_netActive = netActive;
}
/// <summary>Returns the DMR system identity value.</summary>
/// <param name="msb"></param>
/// <returns></returns>
@ -197,6 +206,8 @@ namespace dmr
m_siteId = data.m_siteId;
m_requireReg = data.m_requireReg;
m_netActive = data.m_netActive;
}
return *this;
@ -213,6 +224,8 @@ namespace dmr
__READONLY_PROPERTY_PLAIN(uint8_t, parId, parId);
/// <summary>DMR require registration.</summary>
__READONLY_PROPERTY_PLAIN(bool, requireReg, requireReg);
/// <summary>Flag indicating whether this site is a linked active network member.</summary>
__READONLY_PROPERTY_PLAIN(bool, netActive, netActive);
};
} // namespace dmr

@ -360,6 +360,15 @@ void Slot::clock()
uint32_t ms = m_interval.elapsed();
m_interval.start();
if (m_network != NULL) {
if (m_network->getStatus() == network::NET_STAT_RUNNING) {
m_siteData.setNetActive(true);
}
else {
m_siteData.setNetActive(false);
}
}
// increment the TSCC counter on every slot 1 clock
if (m_slotNo == 1U) {
m_tsccCnt++;

@ -588,7 +588,7 @@ void VoicePacket::processNetwork(const data::Data& dmrData)
return;
lc::FullLC fullLC;
lc::LC * lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
lc::LC* lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
if (lc == NULL) {
LogWarning(LOG_NET, "DMR Slot %u, DT_VOICE_LC_HEADER, bad LC received from the network, replacing", m_slot->m_slotNo);
lc = new lc::LC(dmrData.getFLCO(), dmrData.getSrcId(), dmrData.getDstId());

@ -47,25 +47,23 @@ using namespace dmr;
/// <summary>
/// Initializes a new instance of the CSBK class.
/// </summary>
CSBK::CSBK() :
m_verbose(false),
m_CSBKO(CSBKO_NONE),
m_FID(0x00U),
m_lastBlock(true),
m_bsId(0U),
m_GI(false),
m_Cdef(false),
m_srcId(0U),
m_dstId(0U),
m_dataContent(false),
m_CBF(0U),
m_data(NULL),
m_siteData(),
m_siteNetActive(false)
/// <param name="siteData"></param>
/// <param name="entry"></param>
CSBK::CSBK(SiteData siteData, lookups::IdenTable entry) : CSBK(siteData)
{
m_data = new uint8_t[12U];
m_siteIdenEntry = entry;
}
reset();
/// <summary>
/// Initializes a new instance of the CSBK class.
/// </summary>
/// <param name="siteData"></param>
/// <param name="entry"></param>
/// <param name="verbose"></param>
CSBK::CSBK(SiteData siteData, lookups::IdenTable entry, bool verbose) : CSBK(siteData)
{
m_verbose = verbose;
m_siteIdenEntry = entry;
}
/// <summary>
@ -297,7 +295,7 @@ void CSBK::encode(uint8_t* bytes)
csbkValue = (csbkValue << 1) + ((m_siteTSSync) ? 1U : 0U); // Site Time Slot Synchronization
csbkValue = (csbkValue << 3) + DMR_ALOHA_VER_151; // DMR Spec. Version (1.5.1)
csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset
csbkValue = (csbkValue << 1) + ((m_siteNetActive) ? 1U : 0U); // Site Networked
csbkValue = (csbkValue << 1) + ((m_siteData.netActive()) ? 1U : 0U); // Site Networked
csbkValue = (csbkValue << 5) + (m_alohaMask & 0x1FU); // MS Mask
csbkValue = (csbkValue << 2) + 0U; // Service Function
csbkValue = (csbkValue << 4) + 0U; //
@ -426,58 +424,43 @@ void CSBK::encode(uint8_t* bytes)
bptc.encode(m_data, bytes);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void CSBK::reset()
{
m_colorCode = 0U;
m_backoffNo = 1U;
m_serviceType = 0U;
m_serviceOptions = 0U;
m_targetAddress = TGT_ADRS_TGID;
m_response = 0U;
/* Broadcast */
m_anncType = BCAST_ANNC_SITE_PARMS;
m_hibernating = false;
m_annWdCh1 = false;
m_logicalCh1 = DMR_CHNULL;
m_annWdCh2 = false;
m_logicalCh2 = DMR_CHNULL;
/* Aloha */
m_siteTSSync = false;
m_siteOffsetTiming = false;
}
/** Local Site data */
/// <summary>
/// Sets local configured site data.
/// </summary>
/// <param name="siteData">Site data.</param>
void CSBK::setSiteData(SiteData siteData)
{
m_siteData = siteData;
}
/// <summary>
/// Sets the identity lookup table entry.
/// </summary>
/// <param name="entry">Identity table entry.</param>
void CSBK::setIdenTable(lookups::IdenTable entry)
{
m_siteIdenEntry = entry;
}
/// <summary>
/// Sets a flag indicating whether or not networking is active.
/// Initializes a new instance of the CSBK class.
/// </summary>
/// <param name="netActive">Network active flag.</param>
void CSBK::setNetActive(bool netActive)
/// <param name="siteData"></param>
CSBK::CSBK(SiteData siteData) :
m_verbose(false),
m_CSBKO(CSBKO_NONE),
m_FID(0x00U),
m_lastBlock(true),
m_bsId(0U),
m_GI(false),
m_Cdef(false),
m_srcId(0U),
m_dstId(0U),
m_dataContent(false),
m_CBF(0U),
m_colorCode(0U),
m_backoffNo(1U),
m_serviceType(0U),
m_serviceOptions(0U),
m_targetAddress(TGT_ADRS_TGID),
m_response(0U),
m_anncType(BCAST_ANNC_SITE_PARMS),
m_hibernating(false),
m_annWdCh1(false),
m_logicalCh1(DMR_CHNULL),
m_annWdCh2(false),
m_logicalCh2(DMR_CHNULL),
m_siteTSSync(false),
m_siteOffsetTiming(false),
m_alohaMask(0U),
m_siteData(siteData),
m_siteIdenEntry(lookups::IdenTable()),
m_data(NULL)
{
m_siteNetActive = netActive;
m_data = new uint8_t[12U];
}

@ -48,7 +48,9 @@ namespace dmr
class HOST_SW_API CSBK {
public:
/// <summary>Initializes a new instance of the CSBK class.</summary>
CSBK();
CSBK(SiteData siteData, lookups::IdenTable entry);
/// <summary>Initializes a new instance of the CSBK class.</summary>
CSBK(SiteData siteData, lookups::IdenTable entry, bool verbose);
/// <summary>Finalizes a instance of the CSBK class.</summary>
~CSBK();
@ -57,17 +59,6 @@ namespace dmr
/// <summary>Encodes a DMR CSBK.</summary>
void encode(uint8_t* bytes);
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/** Local Site data */
/// <summary>Sets local configured site data.</summary>
void setSiteData(SiteData siteData);
/// <summary>Sets the identity lookup table entry.</summary>
void setIdenTable(lookups::IdenTable entry);
/// <summary>Sets a flag indicating whether or not networking is active.</summary>
void setNetActive(bool netActive);
public:
/// <summary>Flag indicating verbose log output.</summary>
__PROPERTY(bool, verbose, Verbose);
@ -141,13 +132,17 @@ namespace dmr
/// <summary>Aloha MS mask.</summary>
__PROPERTY(uint8_t, alohaMask, AlohaMask);
/** Local Site data */
/// <summary>Local Site Data.</summary>
__PROPERTY_PLAIN(SiteData, siteData, siteData);
/// <summary>Local Site Identity Entry.</summary>
__PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry, siteIdenEntry);
private:
uint8_t* m_data;
/// <summary>Initializes a new instance of the CSBK class.</summary>
CSBK(SiteData siteData);
/** Local Site data */
SiteData m_siteData;
lookups::IdenTable m_siteIdenEntry;
bool m_siteNetActive;
uint8_t* m_data;
};
} // namespace lc
} // namespace dmr

@ -1349,7 +1349,7 @@ void HostCal::processP25BER(const uint8_t* buffer)
else if (duid == P25_DUID_TSDU) {
timerStop();
lc::TSBK tsbk = lc::TSBK();
lc::TSBK tsbk = lc::TSBK(SiteData(), lookups::IdenTable());
bool ret = tsbk.decode(buffer + 1U);
if (!ret) {
LogWarning(LOG_CAL, "P25_DUID_TSDU (Trunking System Data Unit), undecodable LC");

@ -101,6 +101,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
m_idenTable(idenTable),
m_ridLookup(ridLookup),
m_tidLookup(tidLookup),
m_idenEntry(),
m_queue(queueSize, "P25 Control"),
m_rfState(RS_RF_LISTENING),
m_rfLastDstId(0U),
@ -119,6 +120,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
m_ccFrameCnt(0U),
m_ccSeq(0U),
m_nid(nac),
m_siteData(),
m_rssiMapper(rssiMapper),
m_rssi(0U),
m_maxRSSI(0U),
@ -160,7 +162,6 @@ void Control::reset()
m_rfState = RS_RF_LISTENING;
m_voice->resetRF();
m_trunk->resetRF();
m_data->resetRF();
m_queue.clear();
}
@ -186,8 +187,6 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
yaml::Node systemConf = conf["system"];
yaml::Node p25Protocol = conf["protocols"]["p25"];
m_trunk->setCallsign(cwCallsign);
m_tduPreambleCount = p25Protocol["tduPreambleCount"].as<uint32_t>(8U);
m_trunk->m_patchSuperGroup = pSuperGroup;
@ -202,14 +201,6 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
m_trunk->m_noStatusAck = p25Protocol["noStatusAck"].as<bool>(false);
m_trunk->m_noMessageAck = p25Protocol["noMessageAck"].as<bool>(true);
yaml::Node statusCmd = p25Protocol["statusCmd"];
m_trunk->m_statusCmdEnable = statusCmd["enable"].as<bool>(false);
m_trunk->m_statusRadioCheck = (uint8_t)statusCmd["radioCheck"].as<uint32_t>(0U);
m_trunk->m_statusRadioInhibit = (uint8_t)statusCmd["radioInhibit"].as<uint32_t>(0U);
m_trunk->m_statusRadioUninhibit = (uint8_t)statusCmd["radioUninhibit"].as<uint32_t>(0U);
m_trunk->m_statusRadioForceReg = (uint8_t)statusCmd["radioForceReg"].as<uint32_t>(0U);
m_trunk->m_statusRadioForceDereg = (uint8_t)statusCmd["radioForceDereg"].as<uint32_t>(0U);
yaml::Node control = p25Protocol["control"];
m_control = control["enable"].as<bool>(false);
if (m_control) {
@ -221,17 +212,35 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
m_voiceOnControl = p25Protocol["voiceOnControl"].as<bool>(false);
m_ackTSBKRequests = control["ackRequests"].as<bool>(true);
m_trunk->setServiceClass(m_control, m_voiceOnControl);
m_voice->m_silenceThreshold = p25Protocol["silenceThreshold"].as<uint32_t>(p25::DEFAULT_SILENCE_THRESHOLD);
m_disableNetworkHDU = p25Protocol["disableNetworkHDU"].as<bool>(false);
m_trunk->setSiteData(netId, sysId, rfssId, siteId, 0U, channelId, channelNo);
uint8_t serviceClass = P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA;
if (m_control) {
serviceClass |= P25_SVC_CLS_REG;
}
if (m_voiceOnControl) {
serviceClass |= P25_SVC_CLS_COMPOSITE;
}
m_siteData = SiteData(netId, sysId, rfssId, siteId, 0U, channelId, channelNo, serviceClass);
m_siteData.setCallsign(cwCallsign);
std::vector<lookups::IdenTable> entries = m_idenTable->list();
for (auto it = entries.begin(); it != entries.end(); ++it) {
lookups::IdenTable entry = *it;
if (entry.channelId() == channelId) {
m_idenEntry = entry;
break;
}
}
std::vector<uint32_t> availCh = voiceChNo;
m_trunk->m_voiceChCnt = (uint8_t)availCh.size();
m_trunk->setSiteChCnt((uint8_t)availCh.size());
m_siteData.setChCnt((uint8_t)availCh.size());
for (auto it = availCh.begin(); it != availCh.end(); ++it) {
m_trunk->m_voiceChTable.push_back(*it);
@ -255,15 +264,14 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
LogInfo(" No Status ACK: %s", m_trunk->m_noStatusAck ? "yes" : "no");
LogInfo(" No Message ACK: %s", m_trunk->m_noMessageAck ? "yes" : "no");
LogInfo(" Status Command Support: %s", m_trunk->m_statusCmdEnable ? "yes" : "no");
if (m_trunk->m_statusCmdEnable) {
LogInfo(" Status Radio Check: $%02X", m_trunk->m_statusRadioCheck);
LogInfo(" Status Radio Inhibit: $%02X", m_trunk->m_statusRadioInhibit);
LogInfo(" Status Radio Uninhibit: $%02X", m_trunk->m_statusRadioUninhibit);
LogInfo(" Status Radio Force Register: $%02X", m_trunk->m_statusRadioForceReg);
LogInfo(" Status Radio Force Deregister: $%02X", m_trunk->m_statusRadioForceDereg);
}
}
m_voice->resetRF();
m_voice->resetNet();
m_data->resetRF();
m_trunk->m_rfTSBK = lc::TSBK(m_siteData, m_idenEntry);
m_trunk->m_netTSBK = lc::TSBK(m_siteData, m_idenEntry);
}
/// <summary>
@ -342,9 +350,10 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
m_rfState = RS_RF_LISTENING;
m_voice->resetRF();
m_trunk->resetRF();
m_data->resetRF();
m_trunk->m_rfTSBK = lc::TSBK(m_siteData, m_idenEntry);
return false;
}
@ -561,10 +570,10 @@ void Control::clock(uint32_t ms)
processNetwork();
if (m_network->getStatus() == network::NET_STAT_RUNNING) {
m_trunk->setNetActive(true);
m_siteData.setNetActive(true);
}
else {
m_trunk->setNetActive(false);
m_siteData.setNetActive(false);
}
}
@ -610,7 +619,8 @@ void Control::clock(uint32_t ms)
m_tailOnIdle = true;
m_voice->resetNet();
m_trunk->resetNet();
m_trunk->m_netTSBK = lc::TSBK(m_siteData, m_idenEntry);
m_netTimeout.stop();
}
@ -620,12 +630,13 @@ void Control::clock(uint32_t ms)
m_queue.clear();
m_voice->resetRF();
m_voice->m_rfLastHDU.reset();
m_voice->resetNet();
m_trunk->resetRF();
m_trunk->resetNet();
m_data->resetRF();
m_trunk->m_rfTSBK = lc::TSBK(m_siteData, m_idenEntry);
m_trunk->m_netTSBK = lc::TSBK(m_siteData, m_idenEntry);
if (m_network != NULL)
m_network->resetP25();
@ -633,6 +644,17 @@ void Control::clock(uint32_t ms)
}
m_trunk->clock(ms);
// if the states are "idle" ensure LC data isn't being held in memory
if (m_rfState == RS_RF_LISTENING && m_netState == RS_NET_IDLE) {
m_voice->resetRF();
m_voice->resetNet();
m_data->resetRF();
m_trunk->m_rfTSBK = lc::TSBK(m_siteData, m_idenEntry);
m_trunk->m_netTSBK = lc::TSBK(m_siteData, m_idenEntry);
}
}
/// <summary>

@ -36,6 +36,7 @@
#include "p25/DataPacket.h"
#include "p25/VoicePacket.h"
#include "p25/NID.h"
#include "p25/SiteData.h"
#include "network/BaseNetwork.h"
#include "network/RemoteControl.h"
#include "lookups/RSSIInterpolator.h"
@ -138,6 +139,8 @@ namespace p25
lookups::RadioIdLookup* m_ridLookup;
lookups::TalkgroupIdLookup* m_tidLookup;
lookups::IdenTable m_idenEntry;
RingBuffer<uint8_t> m_queue;
RPT_RF_STATE m_rfState;
@ -163,6 +166,8 @@ namespace p25
NID m_nid;
SiteData m_siteData;
lookups::RSSIInterpolator* m_rssiMapper;
uint8_t m_rssi;
uint8_t m_maxRSSI;

@ -91,8 +91,6 @@ bool DataPacket::process(uint8_t* data, uint32_t len)
// handle individual DUIDs
if (duid == P25_DUID_PDU) {
m_p25->m_trunk->resetStatusCommand();
if (m_p25->m_rfState != RS_RF_DATA) {
m_rfDataHeader.reset();
m_rfDataBlockCnt = 0U;

@ -52,7 +52,10 @@ namespace p25
m_channelId(1U),
m_channelNo(1U),
m_serviceClass(P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA),
m_isAdjSite(false)
m_isAdjSite(false),
m_callsign("CHANGEME"),
m_chCnt(0U),
m_netActive(false)
{
/* stub */
}
@ -74,7 +77,10 @@ namespace p25
m_channelId(1U),
m_channelNo(1U),
m_serviceClass(P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA),
m_isAdjSite(false)
m_isAdjSite(false),
m_callsign("CHANGEME"),
m_chCnt(0U),
m_netActive(false)
{
// lra clamping
if (lra > 0xFFU) // clamp to $FF
@ -128,6 +134,27 @@ namespace p25
m_serviceClass = serviceClass;
}
/// <summary>Helper to set the site callsign.</summary>
/// <param name="callsign">Callsign.</param>
void setCallsign(std::string callsign)
{
m_callsign = callsign;
}
/// <summary>Helper to set the site channel count.</summary>
/// <param name="chCnt">Channel count.</param>
void setChCnt(uint8_t chCnt)
{
m_chCnt = m_chCnt;
}
/// <summary>Helper to set the site network active flag.</summary>
/// <param name="netActive">Network active.</param>
void setNetActive(bool netActive)
{
m_netActive = netActive;
}
/// <summary>Helper to set adjacent site data.</summary>
/// <param name="sysId">P25 System ID.</param>
/// <param name="rfssId">P25 RFSS ID.</param>
@ -179,6 +206,10 @@ namespace p25
m_serviceClass = serviceClass;
m_isAdjSite = true;
m_callsign = "ADJSITE ";
m_chCnt = -1; // don't store channel count for adjacent sites
m_netActive = true; // adjacent sites are explicitly network active
}
/// <summary>Equals operator.</summary>
@ -201,6 +232,11 @@ namespace p25
m_serviceClass = data.m_serviceClass;
m_isAdjSite = data.m_isAdjSite;
m_callsign = data.m_callsign;
m_chCnt = data.m_chCnt;
m_netActive = data.m_netActive;
}
return *this;
@ -225,6 +261,12 @@ namespace p25
__READONLY_PROPERTY_PLAIN(uint8_t, serviceClass, serviceClass);
/// <summary>Flag indicating whether this site data is for an adjacent site.</summary>
__READONLY_PROPERTY_PLAIN(bool, isAdjSite, isAdjSite);
/// <summary>Callsign.</summary>
__READONLY_PROPERTY_PLAIN(std::string, callsign, callsign);
/// <summary>Count of available channels.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, chCnt, chCnt);
/// <summary>Flag indicating whether this site is a linked active network member.</summary>
__READONLY_PROPERTY_PLAIN(bool, netActive, netActive);
};
} // namespace p25

@ -138,173 +138,6 @@ const uint32_t GRANT_TIMER_TIMEOUT = 15U;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Sets local configured site data.
/// </summary>
/// <param name="netId">P25 Network ID.</param>
/// <param name="sysId">P25 System ID.</param>
/// <param name="rfssId">P25 RFSS ID.</param>
/// <param name="siteId">P25 Site ID.</param>
/// <param name="lra">P25 Location Resource Area.</param>
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
void TrunkPacket::setSiteData(uint32_t netId, uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t lra,
uint8_t channelId, uint32_t channelNo)
{
uint8_t serviceClass = m_rfTSBK.getServiceClass();
m_siteData = SiteData(netId, sysId, rfssId, siteId, lra, channelId, channelNo, serviceClass);
m_rfTSBK.setSiteData(m_siteData);
m_rfTDULC.setSiteData(m_siteData);
m_p25->m_voice->m_rfLC.setSiteData(m_siteData);
m_netTSBK.setSiteData(m_siteData);
m_netTDULC.setSiteData(m_siteData);
m_p25->m_voice->m_netLC.setSiteData(m_siteData);
}
/// <summary>
/// Sets local configured site callsign.
/// </summary>
/// <param name="callsign"></param>
void TrunkPacket::setCallsign(std::string callsign)
{
m_rfTSBK.setCallsign(callsign);
m_netTSBK.setCallsign(callsign);
}
/// <summary>
/// Sets a flag indicating whether or not networking is active.
/// </summary>
/// <param name="active"></param>
void TrunkPacket::setNetActive(bool active)
{
m_rfTSBK.setNetActive(active);
m_rfTDULC.setNetActive(active);
m_netTSBK.setNetActive(active);
m_netTDULC.setNetActive(active);
}
/// <summary>
/// Sets the total number of channels at the site.
/// </summary>
/// <param name="chCnt"></param>
void TrunkPacket::setSiteChCnt(uint8_t chCnt)
{
m_rfTSBK.setSiteChCnt(chCnt);
m_netTSBK.setSiteChCnt(chCnt);
}
/// <summary>
/// Sets the service class for this site.
/// </summary>
/// <param name="control"></param>
/// <param name="voiceOnControl"></param>
void TrunkPacket::setServiceClass(bool control, bool voiceOnControl)
{
uint8_t serviceClass = P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA;
if (control) {
serviceClass |= P25_SVC_CLS_REG;
}
if (voiceOnControl) {
serviceClass |= P25_SVC_CLS_COMPOSITE;
}
m_rfTSBK.setServiceClass(serviceClass);
m_netTSBK.setServiceClass(serviceClass);
m_rfTDULC.setServiceClass(serviceClass);
m_netTDULC.setServiceClass(serviceClass);
m_p25->m_voice->m_rfLC.setServiceClass(serviceClass);
m_p25->m_voice->m_netLC.setServiceClass(serviceClass);
}
/// <summary>
/// Resets the data states for the RF interface.
/// </summary>
void TrunkPacket::resetRF()
{
m_rfTSBK.reset();
m_rfTDULC.reset();
}
/// <summary>
/// Resets the data states for the network.
/// </summary>
void TrunkPacket::resetNet()
{
m_netTSBK.reset();
m_netTDULC.reset();
}
/// <summary>
/// Sets the RF TSBK and TDULC data to match the given LC data.
/// </summary>
/// <param name="lc"></param>
void TrunkPacket::setRFLC(const lc::LC& lc)
{
m_rfTSBK.reset();
m_rfTDULC.reset();
m_rfTSBK.setProtect(lc.getProtect());
m_rfTDULC.setProtect(lc.getProtect());
m_rfTSBK.setMFId(lc.getMFId());
m_rfTDULC.setMFId(lc.getMFId());
m_rfTSBK.setSrcId(lc.getSrcId());
m_rfTDULC.setSrcId(lc.getSrcId());
m_rfTSBK.setDstId(lc.getDstId());
m_rfTDULC.setDstId(lc.getDstId());
m_rfTSBK.setGrpVchNo(lc.getGrpVchNo());
m_rfTDULC.setGrpVchNo(lc.getGrpVchNo());
m_rfTSBK.setEmergency(lc.getEmergency());
m_rfTDULC.setEmergency(lc.getEmergency());
m_rfTSBK.setEncrypted(lc.getEncrypted());
m_rfTDULC.setEncrypted(lc.getEmergency());
m_rfTSBK.setPriority(lc.getPriority());
m_rfTDULC.setPriority(lc.getPriority());
m_rfTSBK.setGroup(lc.getGroup());
m_rfTDULC.setGroup(lc.getGroup());
}
/// <summary>
/// Sets the network TSBK and TDULC data to match the given LC data.
/// </summary>
/// <param name="lc"></param>
void TrunkPacket::setNetLC(const lc::LC& lc)
{
m_netTSBK.reset();
m_netTDULC.reset();
m_netTSBK.setProtect(lc.getProtect());
m_netTDULC.setProtect(lc.getProtect());
m_netTSBK.setMFId(lc.getMFId());
m_netTDULC.setMFId(lc.getMFId());
m_netTSBK.setSrcId(lc.getSrcId());
m_netTDULC.setSrcId(lc.getSrcId());
m_netTSBK.setDstId(lc.getDstId());
m_netTDULC.setDstId(lc.getDstId());
m_netTSBK.setGrpVchNo(lc.getGrpVchNo());
m_netTDULC.setGrpVchNo(lc.getGrpVchNo());
m_netTSBK.setEmergency(lc.getEmergency());
m_netTDULC.setEmergency(lc.getEmergency());
m_netTSBK.setEncrypted(lc.getEncrypted());
m_netTDULC.setEncrypted(lc.getEmergency());
m_netTSBK.setPriority(lc.getPriority());
m_netTDULC.setPriority(lc.getPriority());
m_netTSBK.setGroup(lc.getGroup());
m_netTDULC.setGroup(lc.getGroup());
}
/// <summary>
/// Process a data frame from the RF interface.
/// </summary>
@ -334,8 +167,9 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
}
m_p25->m_queue.clear();
m_rfTSBK.reset();
m_netTSBK.reset();
m_rfTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
m_netTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
bool ret = m_rfTSBK.decode(data + 2U);
if (!ret) {
@ -347,8 +181,6 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
uint32_t srcId = m_rfTSBK.getSrcId();
uint32_t dstId = m_rfTSBK.getDstId();
resetStatusCommand(m_rfTSBK);
switch (m_rfTSBK.getLCO()) {
case TSBK_IOSP_GRP_VCH:
// make sure control data is supported
@ -448,23 +280,17 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
// validate the source RID
VALID_SRCID("TSBK_IOSP_STS_UPDT (Status Update)", TSBK_IOSP_STS_UPDT, srcId);
if ((m_statusSrcId == 0U) && (m_statusValue == 0U)) {
RF_TO_WRITE_NET();
}
RF_TO_WRITE_NET();
if (m_verbose) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_IOSP_STS_UPDT (Status Update), status = $%02X, srcId = %u", m_rfTSBK.getStatus(), srcId);
}
::ActivityLog("P25", true, "status update from %u", srcId);
if (!m_noStatusAck) {
writeRF_TSDU_ACK_FNE(srcId, TSBK_IOSP_STS_UPDT, false, false);
}
if (m_statusCmdEnable) {
preprocessStatusCommand();
}
::ActivityLog("P25", true, "status update from %u", srcId);
break;
case TSBK_IOSP_MSG_UPDT:
// validate the source RID
@ -487,16 +313,6 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
// validate the source RID
VALID_SRCID("TSBK_IOSP_CALL_ALRT (Call Alert)", TSBK_IOSP_CALL_ALRT, srcId);
// is status command mode enabled with status data?
if (m_statusCmdEnable) {
if (processStatusCommand(srcId, dstId)) {
m_p25->m_rfState = prevRfState;
return true;
}
resetStatusCommand();
}
// validate the target RID
VALID_DSTID("TSBK_IOSP_CALL_ALRT (Call Alert)", TSBK_IOSP_CALL_ALRT, dstId);
@ -548,18 +364,6 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
m_rfTSBK.getExtendedFunction(), dstId, srcId);
}
// is status control mode enabled with status data?
if (m_statusCmdEnable && (m_statusValue != 0U)) {
m_rfTSBK.setLCO(TSBK_IOSP_ACK_RSP);
m_rfTSBK.setAIV(true);
m_rfTSBK.setService(TSBK_IOSP_CALL_ALRT);
if (m_verbose) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_IOSP_ACK_RSP (Acknowledge Response), serviceType = $%02X, srcId = %u",
m_rfTSBK.getService(), m_statusSrcId);
}
}
// generate activity log entry
if (m_rfTSBK.getExtendedFunction() == P25_EXT_FNCT_CHECK_ACK) {
::ActivityLog("P25", true, "radio check response from %u to %u", dstId, srcId);
@ -572,7 +376,6 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
}
writeRF_TSDU_SBF(true);
resetStatusCommand();
break;
case TSBK_IOSP_GRP_AFF:
// make sure control data is supported
@ -677,8 +480,8 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
switch (duid) {
case P25_DUID_TSDU:
if (m_p25->m_netState == RS_NET_IDLE) {
m_rfTSBK.reset();
m_netTSBK.reset();
m_rfTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
m_netTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
bool ret = m_netTSBK.decode(data);
if (!ret) {
@ -691,7 +494,7 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
return false;
}
if (m_netTSBK.getAdjSiteId() != m_siteData.siteId()) {
if (m_netTSBK.getAdjSiteId() != m_p25->m_siteData.siteId()) {
// update site table data
SiteData site;
try {
@ -741,8 +544,6 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
uint32_t srcId = m_netTSBK.getSrcId();
uint32_t dstId = m_netTSBK.getDstId();
resetStatusCommand(m_netTSBK);
switch (m_netTSBK.getLCO()) {
case TSBK_IOSP_UU_ANS:
if (m_netTSBK.getResponse() > 0U) {
@ -820,8 +621,6 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_IOSP_EXT_FNCT (Extended Function), serviceType = $%02X, arg = %u, tgt = %u",
m_netTSBK.getService(), srcId, dstId);
}
resetStatusCommand();
break;
case TSBK_IOSP_GRP_AFF:
// ignore a network group affiliation command
@ -868,15 +667,13 @@ void TrunkPacket::writeAdjSSNetwork()
return;
}
m_rfTSBK.reset();
m_netTSBK.reset();
m_rfTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
m_netTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
if (m_network != NULL) {
uint8_t serviceClass = m_rfTSBK.getServiceClass();
if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_ADJ_STS_BCAST (Adjacent Site Status Broadcast), network announce, sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X",
m_siteData.sysId(), m_siteData.rfssId(), m_siteData.siteId(), m_siteData.channelId(), m_siteData.channelNo(), serviceClass);
m_p25->m_siteData.sysId(), m_p25->m_siteData.rfssId(), m_p25->m_siteData.siteId(), m_p25->m_siteData.channelId(), m_p25->m_siteData.channelNo(), m_p25->m_siteData.serviceClass());
}
uint8_t cfva = P25_CFVA_VALID;
@ -887,12 +684,12 @@ void TrunkPacket::writeAdjSSNetwork()
// transmit adjacent site broadcast
m_rfTSBK.setLCO(TSBK_OSP_ADJ_STS_BCAST);
m_rfTSBK.setAdjSiteCFVA(cfva);
m_rfTSBK.setAdjSiteSysId(m_siteData.sysId());
m_rfTSBK.setAdjSiteRFSSId(m_siteData.rfssId());
m_rfTSBK.setAdjSiteId(m_siteData.siteId());
m_rfTSBK.setAdjSiteChnId(m_siteData.channelId());
m_rfTSBK.setAdjSiteChnNo(m_siteData.channelNo());
m_rfTSBK.setAdjSiteSvcClass(serviceClass);
m_rfTSBK.setAdjSiteSysId(m_p25->m_siteData.sysId());
m_rfTSBK.setAdjSiteRFSSId(m_p25->m_siteData.rfssId());
m_rfTSBK.setAdjSiteId(m_p25->m_siteData.siteId());
m_rfTSBK.setAdjSiteChnId(m_p25->m_siteData.channelId());
m_rfTSBK.setAdjSiteChnNo(m_p25->m_siteData.channelNo());
m_rfTSBK.setAdjSiteSvcClass(m_p25->m_siteData.serviceClass());
RF_TO_WRITE_NET();
}
@ -1039,11 +836,11 @@ void TrunkPacket::releaseDstIdGrant(uint32_t dstId, bool releaseAll)
if (m_voiceGrantChCnt > 0U) {
m_voiceGrantChCnt--;
setSiteChCnt(m_voiceChCnt + m_voiceGrantChCnt);
m_p25->m_siteData.setChCnt(m_voiceChCnt + m_voiceGrantChCnt);
}
else {
m_voiceGrantChCnt = 0U;
setSiteChCnt(m_voiceChCnt);
m_p25->m_siteData.setChCnt(m_voiceChCnt);
}
m_grantTimers[dstId].stop();
@ -1086,24 +883,6 @@ void TrunkPacket::clearGrpAff(uint32_t dstId, bool releaseAll)
}
}
/// <summary>
/// Resets the state of the status commands.
/// </summary>
void TrunkPacket::resetStatusCommand()
{
// reset status control data
if (m_statusCmdEnable) {
if (m_statusSrcId != 0U && m_statusValue != 0U) {
if (m_verbose) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_IOSP_STS_UPDT (Status Update), canceled command mode, statusCurrentStatus = $%02X", m_statusValue);
}
}
m_statusSrcId = 0U;
m_statusValue = 0U;
}
}
/// <summary>
/// Updates the processor by the passed number of milliseconds.
/// </summary>
@ -1300,11 +1079,7 @@ void TrunkPacket::writeRF_TSDU_Mot_Patch(uint32_t group1, uint32_t group2, uint3
/// <param name="verbose">Flag indicating whether TSBK dumping is enabled.</param>
void TrunkPacket::setTSBKVerbose(bool verbose)
{
m_rfTSBK.setVerbose(verbose);
m_netTSBK.setVerbose(verbose);
m_rfTDULC.setVerbose(verbose);
m_netTDULC.setVerbose(verbose);
m_dumpTSBK = verbose;
}
// ---------------------------------------------------------------------------
@ -1324,15 +1099,13 @@ TrunkPacket::TrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpT
m_patchSuperGroup(0xFFFFU),
m_verifyAff(false),
m_verifyReg(false),
m_rfTSBK(),
m_netTSBK(),
m_rfTSBK(SiteData(), lookups::IdenTable()),
m_netTSBK(SiteData(), lookups::IdenTable()),
m_rfMBF(NULL),
m_mbfCnt(0U),
m_mbfIdenCnt(0U),
m_mbfAdjSSCnt(0U),
m_mbfSCCBCnt(0U),
m_rfTDULC(),
m_netTDULC(),
m_voiceChTable(),
m_adjSiteTable(),
m_adjSiteUpdateCnt(),
@ -1346,36 +1119,15 @@ TrunkPacket::TrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpT
m_voiceGrantChCnt(0U),
m_noStatusAck(false),
m_noMessageAck(true),
m_statusCmdEnable(false),
m_statusRadioCheck(0U),
m_statusRadioInhibit(0U),
m_statusRadioUninhibit(0U),
m_statusRadioForceReg(0U),
m_statusRadioForceDereg(0U),
m_statusSrcId(0U),
m_statusValue(0U),
m_siteData(),
m_adjSiteUpdateTimer(1000U),
m_adjSiteUpdateInterval(ADJ_SITE_TIMER_TIMEOUT),
m_dumpTSBK(false),
m_verbose(verbose),
m_debug(debug)
{
m_rfMBF = new uint8_t[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U];
::memset(m_rfMBF, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
// set metadata defaults
m_rfTSBK.setSiteData(m_siteData);
m_netTSBK.setSiteData(m_siteData);
m_rfTSBK.setCallsign("CHANGEME");
m_netTSBK.setCallsign("CHANGEME");
m_rfTSBK.setVerbose(dumpTSBKData);
m_netTSBK.setVerbose(dumpTSBKData);
m_rfTDULC.setSiteData(m_siteData);
m_netTDULC.setSiteData(m_siteData);
m_rfTDULC.setVerbose(dumpTSBKData);
m_netTDULC.setVerbose(dumpTSBKData);
m_voiceChTable.clear();
m_adjSiteTable.clear();
@ -1443,7 +1195,7 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
do
{
m_rfTSBK.reset();
m_rfTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
if (m_debug) {
LogDebug(LOG_P25, "writeRF_ControlData, mbfCnt = %u, frameCnt = %u, seq = %u, adjSS = %u", m_mbfCnt, frameCnt, n, adjSS);
@ -1523,9 +1275,9 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
/// <summary>
/// Helper to write a P25 TDU w/ link control packet.
/// </summary>
/// <param name="duid"></param>
/// <param name="lc"></param>
/// <param name="noNetwork"></param>
void TrunkPacket::writeRF_TDULC(uint8_t duid, bool noNetwork)
void TrunkPacket::writeRF_TDULC(lc::TDULC lc, bool noNetwork)
{
uint8_t data[P25_TDULC_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, P25_TDULC_FRAME_LENGTH_BYTES);
@ -1537,7 +1289,7 @@ void TrunkPacket::writeRF_TDULC(uint8_t duid, bool noNetwork)
m_p25->m_nid.encode(data + 2U, P25_DUID_TDULC);
// Generate TDULC Data
m_rfTDULC.encode(data + 2U);
lc.encode(data + 2U);
// Add busy bits
m_p25->addBusyBits(data + 2U, P25_TDULC_FRAME_LENGTH_BITS, true, true);
@ -1568,39 +1320,38 @@ void TrunkPacket::writeRF_TDULC(uint8_t duid, bool noNetwork)
void TrunkPacket::writeRF_TDULC_ChanRelease(bool grp, uint32_t srcId, uint32_t dstId)
{
uint32_t count = m_p25->m_hangCount / 2;
lc::TDULC lc = lc::TDULC(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
if (m_p25->m_control) {
for (uint32_t i = 0; i < count; i++) {
if ((srcId != 0U) && (dstId != 0U)) {
m_rfTDULC.setSrcId(srcId);
m_rfTDULC.setDstId(dstId);
m_rfTDULC.setEmergency(false);
lc.setSrcId(srcId);
lc.setDstId(dstId);
lc.setEmergency(false);
if (grp) {
m_rfTDULC.setLCO(LC_GROUP);
writeRF_TDULC(P25_DUID_TDULC, true);
lc.setLCO(LC_GROUP);
writeRF_TDULC(lc, true);
}
else {
m_rfTDULC.setLCO(LC_PRIVATE);
writeRF_TDULC(P25_DUID_TDULC, true);
lc.setLCO(LC_PRIVATE);
writeRF_TDULC(lc, true);
}
}
m_rfTDULC.setLCO(LC_NET_STS_BCAST);
writeRF_TDULC(P25_DUID_TDULC, true);
m_rfTDULC.setLCO(LC_RFSS_STS_BCAST);
writeRF_TDULC(P25_DUID_TDULC, true);
lc.setLCO(LC_NET_STS_BCAST);
writeRF_TDULC(lc, true);
lc.setLCO(LC_RFSS_STS_BCAST);
writeRF_TDULC(lc, true);
}
}
if (m_verbose) {
LogMessage(LOG_RF, P25_TDULC_STR ", LC_CALL_TERM (Call Termination), srcId = %u, dstId = %u", m_rfTDULC.getSrcId(), m_rfTDULC.getDstId());
LogMessage(LOG_RF, P25_TDULC_STR ", LC_CALL_TERM (Call Termination), srcId = %u, dstId = %u", lc.getSrcId(), lc.getDstId());
}
m_rfTDULC.setLCO(LC_CALL_TERM);
writeRF_TDULC(P25_DUID_TDULC, true);
m_rfTDULC.reset();
lc.setLCO(LC_CALL_TERM);
writeRF_TDULC(lc, true);
}
/// <summary>
@ -1777,7 +1528,7 @@ void TrunkPacket::queueRF_TSBK_Ctrl_MBF(uint8_t lco)
if (!m_p25->m_control)
return;
m_rfTSBK.reset();
m_rfTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_dumpTSBK);
switch (lco) {
case TSBK_OSP_IDEN_UP:
@ -1805,14 +1556,14 @@ void TrunkPacket::queueRF_TSBK_Ctrl_MBF(uint8_t lco)
// handle 700/800/900 identities
if (entry.baseFrequency() >= 762000000U) {
m_rfTSBK.setIdenTable(entry);
m_rfTSBK.siteIdenEntry(entry);
// transmit channel ident broadcast
m_rfTSBK.setLCO(TSBK_OSP_IDEN_UP);
}
else {
// handle as a VHF/UHF identity
m_rfTSBK.setIdenTable(entry);
m_rfTSBK.siteIdenEntry(entry);
// transmit channel ident broadcast
m_rfTSBK.setLCO(TSBK_OSP_IDEN_UP_VU);
@ -1867,12 +1618,7 @@ void TrunkPacket::queueRF_TSBK_Ctrl_MBF(uint8_t lco)
else {
cfva |= P25_CFVA_VALID;
}
/*
uint8_t serviceClass = site.serviceClass();
if ((serviceClass & P25_SVC_CLS_COMPOSITE) == P25_SVC_CLS_COMPOSITE) {
cfva |= P25_CFVA_CONV;
}
*/
// transmit adjacent site broadcast
m_rfTSBK.setLCO(TSBK_OSP_ADJ_STS_BCAST);
m_rfTSBK.setAdjSiteCFVA(cfva);
@ -2056,7 +1802,7 @@ bool TrunkPacket::writeRF_TSDU_Grant(bool grp, bool skip, bool net)
m_grantTimers[m_rfTSBK.getDstId()].start();
m_voiceGrantChCnt++;
setSiteChCnt(m_voiceChCnt + m_voiceGrantChCnt);
m_p25->m_siteData.setChCnt(m_voiceChCnt + m_voiceGrantChCnt);
}
}
else {
@ -2239,7 +1985,7 @@ void TrunkPacket::writeRF_TSDU_U_Reg_Rsp(uint32_t srcId)
m_rfTSBK.setResponse(P25_RSP_ACCEPT);
// validate the system ID
if (m_rfTSBK.getSysId() != m_siteData.sysId()) {
if (m_rfTSBK.getSysId() != m_p25->m_siteData.sysId()) {
LogWarning(LOG_RF, P25_TSDU_STR ", TSBK_IOSP_U_REG (Unit Registration Response) denial, SYSID rejection, sysId = $%03X", m_rfTSBK.getSysId());
::ActivityLog("P25", true, "unit registration request from %u denied", srcId);
m_rfTSBK.setResponse(P25_RSP_DENY);
@ -2424,7 +2170,8 @@ void TrunkPacket::writeNet_TSDU_From_RF(uint8_t* data)
/// <summary>
/// Helper to write a network P25 TDU w/ link control packet.
/// </summary>
void TrunkPacket::writeNet_TDULC()
/// <param name="lc"></param>
void TrunkPacket::writeNet_TDULC(lc::TDULC lc)
{
uint8_t buffer[P25_TDULC_FRAME_LENGTH_BYTES + 2U];
::memset(buffer, 0x00U, P25_TDULC_FRAME_LENGTH_BYTES + 2U);
@ -2439,7 +2186,7 @@ void TrunkPacket::writeNet_TDULC()
m_p25->m_nid.encode(buffer + 2U, P25_DUID_TDULC);
// Regenerate TDULC Data
m_netTDULC.encode(buffer + 2U);
lc.encode(buffer + 2U);
// Add busy bits
m_p25->addBusyBits(buffer + 2U, P25_TDULC_FRAME_LENGTH_BITS, true, true);
@ -2447,7 +2194,7 @@ void TrunkPacket::writeNet_TDULC()
m_p25->writeQueueNet(buffer, P25_TDULC_FRAME_LENGTH_BYTES + 2U);
if (m_verbose) {
LogMessage(LOG_NET, P25_TDULC_STR ", lc = $%02X, srcId = %u", m_netTDULC.getLCO(), m_netTDULC.getSrcId());
LogMessage(LOG_NET, P25_TDULC_STR ", lc = $%02X, srcId = %u", lc.getLCO(), lc.getSrcId());
}
if (m_p25->m_voice->m_netFrames > 0) {
@ -2463,7 +2210,6 @@ void TrunkPacket::writeNet_TDULC()
m_p25->m_netTimeout.stop();
m_p25->m_networkWatchdog.stop();
m_netTDULC.reset();
m_p25->m_netState = RS_NET_IDLE;
m_p25->m_tailOnIdle = true;
}
@ -2518,93 +2264,6 @@ void TrunkPacket::denialInhibit(uint32_t srcId)
}
}
/// <summary>
///
/// </summary>
/// <param name="tsbk"></param>
void TrunkPacket::resetStatusCommand(const lc::TSBK& tsbk)
{
// reset status control data if the status current mode is set and the LCO isn't CALL ALERT
if (m_statusCmdEnable && ((m_rfTSBK.getLCO() != TSBK_IOSP_CALL_ALRT) && (m_rfTSBK.getLCO() != TSBK_IOSP_EXT_FNCT))) {
resetStatusCommand();
}
}
/// <summary>
///
/// </summary>
void TrunkPacket::preprocessStatusCommand()
{
if (m_statusCmdEnable) {
m_statusSrcId = m_rfTSBK.getSrcId();
m_statusValue = m_rfTSBK.getStatus();
if (m_statusValue != 0U) {
if ((m_statusValue == m_statusRadioCheck) ||
(m_statusValue == m_statusRadioInhibit) || (m_statusValue == m_statusRadioUninhibit) ||
(m_statusValue == m_statusRadioForceReg) || (m_statusValue == m_statusRadioForceDereg)) {
if (m_verbose) {
LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_IOSP_STS_UPDT (Status Update), command mode, statusCurrentStatus = $%02X", m_statusValue);
}
}
else {
resetStatusCommand();
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
/// <returns></returns>
bool TrunkPacket::processStatusCommand(uint32_t srcId, uint32_t dstId)
{
// is status command mode enabled with status data?
if (m_statusCmdEnable && (m_statusValue != 0U)) {
// if the status srcId isn't the CALL ALERT srcId ignore
if (m_statusSrcId == srcId) {
if ((m_statusRadioCheck != 0U) && (m_statusValue == m_statusRadioCheck)) {
writeRF_TSDU_Ext_Func(P25_EXT_FNCT_CHECK, srcId, dstId);
}
else if ((m_statusRadioInhibit != 0U) && (m_statusValue == m_statusRadioInhibit)) {
writeRF_TSDU_Ext_Func(P25_EXT_FNCT_INHIBIT, P25_WUID_SYS, dstId);
}
else if ((m_statusRadioUninhibit != 0U) && (m_statusValue == m_statusRadioUninhibit)) {
writeRF_TSDU_Ext_Func(P25_EXT_FNCT_UNINHIBIT, P25_WUID_SYS, dstId);
}
else if ((m_statusRadioForceReg != 0U) && (m_statusValue == m_statusRadioForceReg)) {
// update dynamic unit registration table
if (!hasSrcIdUnitReg(srcId)) {
m_unitRegTable.push_back(srcId);
}
writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId);
}
else if ((m_statusRadioForceDereg != 0U) && (m_statusValue == m_statusRadioForceDereg)) {
writeRF_TSDU_U_Dereg_Ack(srcId);
}
else {
LogError(LOG_P25, P25_TSDU_STR ", unhandled command mode, statusCurrentStatus = $%02X, srcId = %u, dstId = %u", m_statusValue, srcId, dstId);
resetStatusCommand();
}
writeRF_TSDU_ACK_FNE(srcId, TSBK_IOSP_CALL_ALRT, false, false);
return true;
}
else {
if (m_verbose) {
LogWarning(LOG_P25, P25_TSDU_STR ", TSBK_IOSP_STS_UPDT (Status Update), illegal attempt by srcId = %u to access status command", srcId);
}
}
}
resetStatusCommand();
return false;
}
/// <summary>
/// Helper to add the idle status bits on P25 frame data.
/// </summary>

@ -34,7 +34,6 @@
#include "p25/lc/TSBK.h"
#include "p25/lc/TDULC.h"
#include "p25/Control.h"
#include "p25/SiteData.h"
#include "network/BaseNetwork.h"
#include "network/RemoteControl.h"
#include "Timer.h"
@ -60,27 +59,6 @@ namespace p25
class HOST_SW_API TrunkPacket {
public:
/// <summary>Sets local configured site data.</summary>
void setSiteData(uint32_t netId, uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t lra,
uint8_t channelId, uint32_t channelNo);
/// <summary>Sets local configured site callsign.</summary>
void setCallsign(std::string callsign);
/// <summary>Sets a flag indicating whether or not networking is active.</summary>
void setNetActive(bool active);
/// <summary>Sets the total number of channels at the site.</summary>
void setSiteChCnt(uint8_t chCnt);
/// <summary>Sets the service class for this site.</summary>
void setServiceClass(bool control, bool voiceOnControl);
/// <summary>Resets the data states for the RF interface.</summary>
void resetRF();
/// <summary>Resets the data states for the network.</summary>
void resetNet();
/// <summary>Sets the RF TSBK and TDULC data to match the given LC data.</summary>
void setRFLC(const lc::LC& lc);
/// <summary>Sets the network TSBK and TDULC data to match the given LC data.</summary>
void setNetLC(const lc::LC& lc);
/// <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>
@ -105,9 +83,6 @@ namespace p25
/// <summary>Helper to release group affiliations.</summary>
void clearGrpAff(uint32_t dstId, bool releaseAll);
/// <summary>Resets the state of the status commands.</summary>
void resetStatusCommand();
/// <summary>Updates the processor by the passed number of milliseconds.</summary>
void clock(uint32_t ms);
@ -150,9 +125,6 @@ namespace p25
uint8_t m_mbfAdjSSCnt;
uint8_t m_mbfSCCBCnt;
lc::TDULC m_rfTDULC;
lc::TDULC m_netTDULC;
std::vector<uint32_t> m_voiceChTable;
std::unordered_map<uint8_t, SiteData> m_adjSiteTable;
@ -173,21 +145,11 @@ namespace p25
bool m_noStatusAck;
bool m_noMessageAck;
bool m_statusCmdEnable;
uint8_t m_statusRadioCheck;
uint8_t m_statusRadioInhibit;
uint8_t m_statusRadioUninhibit;
uint8_t m_statusRadioForceReg;
uint8_t m_statusRadioForceDereg;
uint32_t m_statusSrcId;
uint8_t m_statusValue;
SiteData m_siteData;
Timer m_adjSiteUpdateTimer;
uint32_t m_adjSiteUpdateInterval;
bool m_dumpTSBK;
bool m_verbose;
bool m_debug;
@ -203,7 +165,7 @@ namespace p25
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);
void writeRF_TDULC(lc::TDULC lc, bool noNetwork);
/// <summary>Helper to write a P25 TDU w/ link control channel release packet.</summary>
void writeRF_TDULC_ChanRelease(bool grp, uint32_t srcId, uint32_t dstId);
@ -238,20 +200,13 @@ namespace p25
void writeNet_TSDU_From_RF(uint8_t* data);
/// <summary>Helper to write a network P25 TDU w/ link control packet.</summary>
void writeNet_TDULC();
void writeNet_TDULC(lc::TDULC lc);
/// <summary>Helper to write a network single-block P25 TSDU packet.</summary>
void writeNet_TSDU();
/// <summary>Helper to automatically inhibit a source ID on a denial.</summary>
void denialInhibit(uint32_t srcId);
/// <summary></summary>
void resetStatusCommand(const lc::TSBK& tsbk);
/// <summary></summary>
void preprocessStatusCommand();
/// <summary></summary>
bool processStatusCommand(uint32_t srcId, uint32_t dstId);
/// <summary>Helper to add the idle status bits on P25 frame data.</summary>
void addIdleBits(uint8_t* data, uint32_t length, bool b1, bool b2);
};

@ -60,9 +60,10 @@ const uint32_t VOC_LDU1_COUNT = 3U;
/// </summary>
void VoicePacket::resetRF()
{
m_rfLC.reset();
m_rfLastLDU1.reset();
m_rfLastLDU2.reset();
m_rfLC = lc::LC(m_p25->m_siteData);
//m_rfLastHDU = lc::LC(m_p25->m_siteData);
m_rfLastLDU1 = lc::LC(m_p25->m_siteData);
m_rfLastLDU2 = lc::LC(m_p25->m_siteData);;
m_rfFrames = 0U;
m_rfErrs = 0U;
@ -76,8 +77,9 @@ void VoicePacket::resetRF()
/// </summary>
void VoicePacket::resetNet()
{
m_netLC.reset();
m_netLastLDU1.reset();
m_netLC = lc::LC(m_p25->m_siteData);
m_netLastLDU1 = lc::LC(m_p25->m_siteData);
m_netFrames = 0U;
m_netLost = 0U;
m_vocLDU1Count = 0U;
@ -129,8 +131,6 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
// handle individual DUIDs
if (duid == P25_DUID_HDU) {
m_p25->m_trunk->resetStatusCommand();
m_lastDUID = P25_DUID_HDU;
if (m_p25->m_rfState == RS_RF_LISTENING && m_p25->m_ccRunning) {
@ -144,7 +144,8 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
resetRF();
resetNet();
bool ret = m_rfLC.decodeHDU(data + 2U);
lc::LC lc = lc::LC(m_p25->m_siteData);
bool ret = lc.decodeHDU(data + 2U);
if (!ret) {
LogWarning(LOG_RF, P25_HDU_STR ", undecodable LC");
m_rfUndecodableLC++;
@ -152,11 +153,11 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
if (m_verbose) {
LogMessage(LOG_RF, P25_HDU_STR ", HDU_BSDWNACT, dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId());
LogMessage(LOG_RF, P25_HDU_STR ", HDU_BSDWNACT, dstId = %u, algo = $%02X, kid = $%04X", lc.getDstId(), lc.getAlgId(), lc.getKId());
}
// don't process RF frames if the network isn't in a idle state and the RF destination is the network destination
if (m_p25->m_netState != RS_NET_IDLE && m_rfLC.getDstId() == m_p25->m_netLastDstId) {
if (m_p25->m_netState != RS_NET_IDLE && lc.getDstId() == m_p25->m_netLastDstId) {
LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing network traffic!");
resetRF();
return false;
@ -164,7 +165,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
// stop network frames from processing -- RF wants to transmit on a different talkgroup
if (m_p25->m_netState != RS_NET_IDLE) {
LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", m_rfLC.getDstId(),
LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", lc.getDstId(),
m_p25->m_netLastDstId);
resetNet();
@ -178,17 +179,14 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
m_p25->m_rfTGHang.start();
m_p25->m_rfLastDstId = m_rfLC.getDstId();
m_p25->m_rfLastDstId = lc.getDstId();
m_rfLastHDU.reset();
m_rfLastHDU = m_rfLC;
m_rfLastHDU = lc;
}
return true;
}
else if (duid == P25_DUID_LDU1) {
m_p25->m_trunk->resetStatusCommand();
bool alreadyDecoded = false;
m_lastDUID = P25_DUID_LDU1;
@ -199,16 +197,18 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
}
bool ret = m_rfLC.decodeLDU1(data + 2U);
lc::LC lc = lc::LC(m_p25->m_siteData);
bool ret = lc.decodeLDU1(data + 2U);
if (!ret) {
return false;
}
m_rfLastLDU1 = m_rfLC;
alreadyDecoded = true;
uint32_t srcId = lc.getSrcId();
uint32_t dstId = lc.getDstId();
bool group = lc.getGroup();
bool encrypted = lc.getEncrypted();
uint32_t srcId = m_rfLC.getSrcId();
uint32_t dstId = m_rfLC.getDstId();
alreadyDecoded = true;
// don't process RF frames if the network isn't in a idle state and the RF destination is the network destination
if (m_p25->m_netState != RS_NET_IDLE && dstId == m_p25->m_netLastDstId) {
@ -219,34 +219,32 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
// stop network frames from processing -- RF wants to transmit on a different talkgroup
if (m_p25->m_netState != RS_NET_IDLE) {
if (m_netLC.getSrcId() == srcId && m_netLC.getDstId() == dstId) {
LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing RF traffic (Are we in a voting condition?), rfSrcId = %u, rfDstId = %u, netSrcId = %u, netDstId = %u", m_rfLC.getSrcId(), m_rfLC.getDstId(),
srcId, dstId);
if (m_netLC.getSrcId() == srcId && m_p25->m_netLastDstId == dstId) {
LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing RF traffic (Are we in a voting condition?), rfSrcId = %u, rfDstId = %u, netSrcId = %u, netDstId = %u", srcId, dstId,
m_netLC.getSrcId(), m_p25->m_netLastDstId);
resetRF();
return false;
}
else {
LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", m_rfLC.getDstId(),
LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", dstId,
m_p25->m_netLastDstId);
resetNet();
/*
m_p25->writeRF_TDU(true);
*/
}
}
m_p25->m_trunk->setRFLC(m_rfLC);
m_p25->m_trunk->m_rfTSBK = lc::TSBK(&lc);
m_p25->m_trunk->m_rfTSBK.setVerbose(m_p25->m_trunk->m_dumpTSBK);
// validate the source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
if (m_lastRejectId == 0U || m_lastRejectId != srcId) {
LogWarning(LOG_RF, P25_HDU_STR " denial, RID rejection, srcId = %u", srcId);
if (m_p25->m_control) {
m_p25->m_trunk->writeRF_TSDU_Deny(P25_DENY_RSN_REQ_UNIT_NOT_VALID, (m_rfLC.getGroup() ? TSBK_IOSP_GRP_VCH : TSBK_IOSP_UU_VCH));
m_p25->m_trunk->writeRF_TSDU_Deny(P25_DENY_RSN_REQ_UNIT_NOT_VALID, (group ? TSBK_IOSP_GRP_VCH : TSBK_IOSP_UU_VCH));
m_p25->m_trunk->denialInhibit(srcId);
}
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, m_rfLC.getGroup() ? "TG " : "", dstId);
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId);
m_lastRejectId = srcId;
}
@ -257,7 +255,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
// is this a group or individual operation?
if (!m_rfLC.getGroup()) {
if (!group) {
// validate the target RID
if (!acl::AccessControl::validateSrcId(dstId)) {
if (m_lastRejectId == 0 || m_lastRejectId != dstId) {
@ -266,7 +264,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_p25->m_trunk->writeRF_TSDU_Deny(P25_DENY_RSN_TGT_UNIT_NOT_VALID, TSBK_IOSP_UU_VCH);
}
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, m_rfLC.getGroup() ? "TG " : "", dstId);
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId);
m_lastRejectId = dstId;
}
@ -285,7 +283,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_p25->m_trunk->writeRF_TSDU_Deny(P25_DENY_RSN_TGT_GROUP_NOT_VALID, TSBK_IOSP_GRP_VCH);
}
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, m_rfLC.getGroup() ? "TG " : "", dstId);
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId);
m_lastRejectId = dstId;
}
@ -298,15 +296,14 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
// verify the source RID is affiliated to the group TGID; only if control data
// is supported
if (m_rfLC.getGroup() && m_p25->m_control) {
if (!m_p25->m_trunk->hasSrcIdGrpAff(srcId, dstId) &&
m_p25->m_trunk->m_verifyAff) {
if (group && m_p25->m_control) {
if (!m_p25->m_trunk->hasSrcIdGrpAff(srcId, dstId) && m_p25->m_trunk->m_verifyAff) {
if (m_lastRejectId == 0 || m_lastRejectId != srcId) {
LogWarning(LOG_RF, P25_HDU_STR " denial, RID not affiliated to TGID, srcId = %u, dstId = %u", srcId, dstId);
m_p25->m_trunk->writeRF_TSDU_Deny(P25_DENY_RSN_REQ_UNIT_NOT_AUTH, TSBK_IOSP_GRP_VCH);
m_p25->m_trunk->writeRF_TSDU_U_Reg_Cmd(srcId);
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, m_rfLC.getGroup() ? "TG " : "", dstId);
::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId);
m_lastRejectId = srcId;
}
@ -317,11 +314,14 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
}
m_rfLC = lc;
m_rfLastLDU1 = m_rfLC;
m_lastRejectId = 0U;
::ActivityLog("P25", true, "RF %svoice transmission from %u to %s%u", m_rfLC.getEncrypted() ? "encrypted ": "", srcId, m_rfLC.getGroup() ? "TG " : "", dstId);
::ActivityLog("P25", true, "RF %svoice transmission from %u to %s%u", encrypted ? "encrypted ": "", srcId, group ? "TG " : "", dstId);
if (m_p25->m_control) {
if (m_rfLC.getGroup() && (m_lastPatchGroup != dstId) &&
if (group && (m_lastPatchGroup != dstId) &&
(dstId != m_p25->m_trunk->m_patchSuperGroup)) {
m_p25->m_trunk->writeRF_TSDU_Mot_Patch(dstId, 0U, 0U);
m_lastPatchGroup = dstId;
@ -331,7 +331,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
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_legacyGroupReg && group) {
if (!m_p25->m_trunk->hasSrcIdGrpAff(srcId, dstId)) {
if (!m_p25->m_trunk->writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId)) {
return false;
@ -339,7 +339,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
}
if (!m_p25->m_trunk->writeRF_TSDU_Grant(m_rfLC.getGroup(), false, false)) {
if (!m_p25->m_trunk->writeRF_TSDU_Grant(group, false, false)) {
return false;
}
}
@ -352,22 +352,9 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
// single-channel trunking or voice on control support?
if (m_p25->m_control && m_p25->m_voiceOnControl) {
m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets
m_p25->m_trunk->writeRF_TSDU_Grant(m_rfLC.getGroup(), true, false);
}
if (m_rfLC.getDstId() != m_rfLastHDU.getDstId()) {
m_rfLC.setDstId(m_rfLastHDU.getDstId());
m_p25->m_trunk->writeRF_TSDU_Grant(group, true, false);
}
m_rfLC.setAlgId(m_rfLastHDU.getAlgId());
m_rfLC.setKId(m_rfLastHDU.getKId());
uint8_t mi[P25_MI_LENGTH_BYTES];
m_rfLastHDU.getMI(mi);
m_rfLC.setMI(mi);
m_rfLastHDU.reset();
m_hadVoice = true;
m_p25->m_rfState = RS_RF_AUDIO;
@ -375,20 +362,50 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_p25->m_rfTGHang.start();
m_p25->m_rfLastDstId = dstId;
uint8_t buffer[P25_HDU_FRAME_LENGTH_BYTES + 2U];
::memset(buffer, 0x00U, P25_HDU_FRAME_LENGTH_BYTES + 2U);
// make sure we actually got a HDU -- otherwise treat the call as a late entry
if (m_rfLastHDU.getDstId() != 0U) {
// copy destination and encryption parameters from the last HDU received (if possible)
if (m_rfLC.getDstId() != m_rfLastHDU.getDstId()) {
m_rfLC.setDstId(m_rfLastHDU.getDstId());
}
// Generate Sync
Sync::addP25Sync(buffer + 2U);
m_rfLC.setAlgId(m_rfLastHDU.getAlgId());
m_rfLC.setKId(m_rfLastHDU.getKId());
// Generate NID
m_p25->m_nid.encode(buffer + 2U, P25_DUID_HDU);
uint8_t mi[P25_MI_LENGTH_BYTES];
m_rfLastHDU.getMI(mi);
m_rfLC.setMI(mi);
// Generate HDU
m_rfLC.encodeHDU(buffer + 2U);
uint8_t buffer[P25_HDU_FRAME_LENGTH_BYTES + 2U];
::memset(buffer, 0x00U, P25_HDU_FRAME_LENGTH_BYTES + 2U);
// Add busy bits
m_p25->addBusyBits(buffer + 2U, P25_HDU_FRAME_LENGTH_BITS, false, true);
// Generate Sync
Sync::addP25Sync(buffer + 2U);
// Generate NID
m_p25->m_nid.encode(buffer + 2U, P25_DUID_HDU);
// Generate HDU
m_rfLC.encodeHDU(buffer + 2U);
// Add busy bits
m_p25->addBusyBits(buffer + 2U, P25_HDU_FRAME_LENGTH_BITS, false, true);
writeNetworkRF(buffer, P25_DUID_HDU);
if (m_p25->m_duplex) {
buffer[0U] = TAG_DATA;
buffer[1U] = 0x00U;
m_p25->writeQueueRF(buffer, P25_HDU_FRAME_LENGTH_BYTES + 2U);
}
if (m_verbose) {
LogMessage(LOG_RF, P25_HDU_STR ", dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId());
}
}
else {
LogWarning(LOG_RF, P25_HDU_STR ", not transmitted; possible late entry, dstId = %u, algo = $%02X, kid = $%04X", m_rfLastHDU.getDstId(), m_rfLastHDU.getAlgId(), m_rfLastHDU.getKId());
}
m_rfFrames = 0U;
m_rfErrs = 0U;
@ -398,17 +415,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_p25->m_rfTimeout.start();
m_lastDUID = P25_DUID_HDU;
writeNetworkRF(buffer, P25_DUID_HDU);
if (m_p25->m_duplex) {
buffer[0U] = TAG_DATA;
buffer[1U] = 0x00U;
m_p25->writeQueueRF(buffer, P25_HDU_FRAME_LENGTH_BYTES + 2U);
}
if (m_verbose) {
LogMessage(LOG_RF, P25_HDU_STR ", dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId());
}
m_rfLastHDU = lc::LC(m_p25->m_siteData);
}
if (m_p25->m_rfState == RS_RF_AUDIO) {
@ -526,8 +533,6 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
}
else if (duid == P25_DUID_LDU2) {
m_p25->m_trunk->resetStatusCommand();
m_lastDUID = P25_DUID_LDU2;
if (m_p25->m_rfState == RS_RF_LISTENING) {
@ -606,8 +611,6 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
}
}
else if (duid == P25_DUID_TDU || duid == P25_DUID_TDULC) {
m_p25->m_trunk->resetStatusCommand();
if (m_p25->m_control) {
m_p25->m_trunk->releaseDstIdGrant(m_rfLC.getDstId(), false);
}
@ -619,8 +622,16 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_p25->m_rfTimeout.stop();
}
else
m_p25->m_trunk->writeRF_TDULC(duid, false);
else {
lc::TDULC tdulc = lc::TDULC(m_p25->m_siteData, m_p25->m_idenEntry, m_p25->m_trunk->m_dumpTSBK);
bool ret = tdulc.decode(data + 2U);
if (!ret) {
LogWarning(LOG_RF, P25_LDU2_STR ", undecodable TDULC");
}
else {
m_p25->m_trunk->writeRF_TDULC(tdulc, false);
}
}
if (m_p25->m_rfState == RS_RF_AUDIO) {
if (m_p25->m_rssi != 0U) {
@ -712,8 +723,6 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
::memcpy(m_netLDU1 + 200U, data + count, 16U);
count += 16U;
m_p25->m_trunk->resetStatusCommand();
m_netLastLDU1 = control;
checkNet_LDU2(control, lsd);
@ -765,21 +774,15 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
::memcpy(m_netLDU2 + 200U, data + count, 16U);
count += 16U;
m_p25->m_trunk->resetStatusCommand();
if (m_p25->m_netState == RS_NET_IDLE) {
m_p25->m_modem->clearP25Data();
m_p25->m_queue.clear();
resetRF();
m_rfLastHDU.reset();
m_netLC.reset();
m_netFrames = 0U;
m_netLost = 0U;
resetNet();
m_p25->m_trunk->resetRF();
m_p25->m_trunk->resetNet();
m_p25->m_trunk->m_rfTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_p25->m_trunk->m_dumpTSBK);
m_p25->m_trunk->m_netTSBK = lc::TSBK(m_p25->m_siteData, m_p25->m_idenEntry, m_p25->m_trunk->m_dumpTSBK);
writeNet_LDU1(control, lsd);
}
@ -805,12 +808,10 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
}
if (m_p25->m_netState != RS_NET_IDLE) {
m_p25->m_trunk->resetStatusCommand();
if (duid == P25_DUID_TDU)
writeNet_TDU();
else
m_p25->m_trunk->writeNet_TDULC();
resetNet();
}
break;
}
@ -869,12 +870,12 @@ VoicePacket::VoicePacket(Control* p25, network::BaseNetwork* network, bool debug
m_netFrames(0U),
m_netLost(0U),
m_audio(),
m_rfLC(),
m_rfLastHDU(),
m_rfLastLDU1(),
m_rfLastLDU2(),
m_netLC(),
m_netLastLDU1(),
m_rfLC(SiteData()),
m_rfLastHDU(SiteData()),
m_rfLastLDU1(SiteData()),
m_rfLastLDU2(SiteData()),
m_netLC(SiteData()),
m_netLastLDU1(SiteData()),
m_rfLSD(),
m_netLSD(),
m_netLDU1(NULL),
@ -959,17 +960,10 @@ void VoicePacket::writeRF_EndOfVoice()
uint32_t dstId = m_rfLC.getDstId();
resetRF();
m_rfLastHDU.reset();
resetNet();
// transmit channelNo release burst
m_p25->m_trunk->writeRF_TDULC_ChanRelease(grp, srcId, dstId);
/*
if (grp && (m_lastPatchGroup != 0U)) {
m_p25->m_trunk->writeRF_TSDU_Mot_Patch(m_p25->m_trunk->m_patchSuperGroup, 0U, 0U);
}
*/
}
/// <summary>
@ -1018,8 +1012,7 @@ void VoicePacket::writeNet_TDU()
m_p25->m_netTimeout.stop();
m_p25->m_networkWatchdog.stop();
m_netLC.reset();
m_netLastLDU1.reset();
resetNet();
m_p25->m_netState = RS_NET_IDLE;
m_p25->m_netLastDstId = 0U;
m_p25->m_tailOnIdle = true;
@ -1112,7 +1105,7 @@ void VoicePacket::writeNet_LDU1(const lc::LC& control, const data::LowSpeedData&
m_p25->m_trunk->touchDstIdGrant(m_rfLC.getDstId());
}
m_netLC.reset();
m_netLC = lc::LC(m_p25->m_siteData);
m_netLC.setLCO(lco);
m_netLC.setMFId(mfId);
m_netLC.setSrcId(srcId);
@ -1122,7 +1115,7 @@ void VoicePacket::writeNet_LDU1(const lc::LC& control, const data::LowSpeedData&
m_netLC.setEncrypted((serviceOptions & 0x40U) == 0x40U);
m_netLC.setPriority((serviceOptions & 0x07U));
m_rfLC.reset();
m_rfLC = lc::LC(m_p25->m_siteData);
m_rfLC.setMFId(mfId);
m_rfLC.setSrcId(srcId);
m_rfLC.setDstId(dstId);
@ -1152,8 +1145,10 @@ void VoicePacket::writeNet_LDU1(const lc::LC& control, const data::LowSpeedData&
m_netLC.setKId(kId);
m_rfLC.setKId(kId);
m_p25->m_trunk->setNetLC(m_netLC);
m_p25->m_trunk->setRFLC(m_rfLC);
m_p25->m_trunk->m_rfTSBK = lc::TSBK(&m_rfLC);
m_p25->m_trunk->m_rfTSBK.setVerbose(m_p25->m_trunk->m_dumpTSBK);
m_p25->m_trunk->m_netTSBK = lc::TSBK(&m_netLC);
m_p25->m_trunk->m_netTSBK.setVerbose(m_p25->m_trunk->m_dumpTSBK);
// validate source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
@ -1197,8 +1192,10 @@ void VoicePacket::writeNet_LDU1(const lc::LC& control, const data::LowSpeedData&
m_p25->m_netTimeout.stop();
m_p25->m_networkWatchdog.stop();
m_netLC.reset();
m_netLastLDU1.reset();
m_netLC = lc::LC(m_p25->m_siteData);
m_netLastLDU1 = lc::LC(m_p25->m_siteData);
m_p25->m_netState = RS_NET_IDLE;
m_p25->m_netLastDstId = 0U;
if (m_p25->m_rfState == RS_RF_REJECTED) {
@ -1248,7 +1245,7 @@ void VoicePacket::writeNet_LDU1(const lc::LC& control, const data::LowSpeedData&
}
else {
if (m_verbose) {
LogMessage(LOG_NET, P25_HDU_STR ", network does not transmit, dstId = %u, algo = $%02X, kid = $%04X", m_netLC.getDstId(), m_netLC.getAlgId(), m_netLC.getKId());
LogMessage(LOG_NET, P25_HDU_STR ", not transmitted; network HDU disabled, dstId = %u, algo = $%02X, kid = $%04X", m_netLC.getDstId(), m_netLC.getAlgId(), m_netLC.getKId());
}
}
}

@ -51,29 +51,39 @@ using namespace p25;
/// <summary>
/// Initializes a new instance of the LC class.
/// </summary>
/// <param name="siteData"></param>
LC::LC() :
m_protect(false),
m_lco(LC_GROUP),
m_mfId(P25_MFG_STANDARD),
m_srcId(0U),
m_dstId(0U),
m_serviceClass(P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA),
m_grpVchNo(0U),
m_emergency(false),
m_encrypted(false),
m_priority(4U),
m_group(true),
m_algId(P25_ALGO_UNENCRYPT),
m_kId(0U),
m_siteData(SiteData()),
m_rs(),
m_encryptOverride(false),
m_tsbkVendorSkip(false),
m_callTimer(0U),
m_mi(NULL),
m_siteData()
m_mi(NULL)
{
m_mi = new uint8_t[P25_MI_LENGTH_BYTES];
::memset(m_mi, 0x00U, P25_MI_LENGTH_BYTES);
}
reset();
/// <summary>
/// Initializes a new instance of the LC class.
/// </summary>
/// <param name="siteData"></param>
LC::LC(SiteData siteData) : LC()
{
m_siteData = siteData;
m_grpVchNo = m_siteData.channelNo();
}
/// <summary>
@ -98,8 +108,6 @@ LC& LC::operator=(const LC& data)
m_srcId = data.m_srcId;
m_dstId = data.m_dstId;
m_serviceClass = data.m_serviceClass;
m_grpVchNo = data.m_grpVchNo;
m_emergency = data.m_emergency;
@ -130,6 +138,8 @@ LC& LC::operator=(const LC& data)
m_encrypted = false;
}
}
m_siteData = data.m_siteData;
}
return *this;
@ -457,46 +467,6 @@ void LC::encodeLDU2(uint8_t * data)
// Utils::dump(2U, "LDU2 Interleave", data, P25_LDU_FRAME_LENGTH_BYTES + P25_PREAMBLE_LENGTH_BYTES);
}
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void LC::reset()
{
m_encryptOverride = false;
m_tsbkVendorSkip = false;
m_protect = false;
m_lco = LC_GROUP;
m_mfId = P25_MFG_STANDARD;
m_srcId = 0U;
m_dstId = 0U;
m_callTimer = 0U;
m_grpVchNo = m_siteData.channelNo();
/* Service Options */
m_emergency = false;
m_encrypted = false;
m_priority = 4U;
m_group = true;
/* HDU/LDU2 data */
m_algId = P25_ALGO_UNENCRYPT;
m_kId = 0x0000U;
::memset(m_mi, 0x00U, P25_MI_LENGTH_BYTES);
}
/** Local Site data */
/// <summary>Sets local configured site data.</summary>
/// <param name="siteData"></param>
void LC::setSiteData(SiteData siteData)
{
m_siteData = siteData;
}
/** Encryption data */
/// <summary>Sets the encryption message indicator.</summary>
/// <param name="mi"></param>
@ -644,7 +614,7 @@ void LC::encodeLC(uint8_t * rs)
rsValue = (rsValue << 8) + m_siteData.siteId(); // Site ID
rsValue = (rsValue << 4) + m_siteData.channelId(); // Channel ID
rsValue = (rsValue << 12) + m_siteData.channelNo(); // Channel Number
rsValue = (rsValue << 8) + m_serviceClass; // System Service Class
rsValue = (rsValue << 8) + m_siteData.serviceClass(); // System Service Class
break;
default:
LogError(LOG_P25, "unknown LC value, mfId = $%02X, lco = $%02X", m_mfId, m_lco);

@ -59,6 +59,8 @@ namespace p25
public:
/// <summary>Initializes a new instance of the LC class.</summary>
LC();
/// <summary>Initializes a new instance of the LC class.</summary>
LC(SiteData siteData);
/// <summary>Finalizes a instance of the LC class.</summary>
~LC();
@ -80,13 +82,6 @@ namespace p25
/// <summary>Encode a logical link data unit 2.</summary>
void encodeLDU2(uint8_t* data);
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/** Local Site data */
/// <summary>Sets local configured site data.</summary>
void setSiteData(SiteData siteData);
/** Encryption data */
/// <summary>Sets the encryption message indicator.</summary>
void setMI(const uint8_t* mi);
@ -107,9 +102,6 @@ namespace p25
/// <summary>Destination ID.</summary>
__PROPERTY(uint32_t, dstId, DstId);
/// <summary>Service class.</summary>
__PROPERTY(uint8_t, serviceClass, ServiceClass);
/// <summary>Voice channel number.</summary>
__PROPERTY(uint32_t, grpVchNo, GrpVchNo);
@ -129,6 +121,10 @@ namespace p25
/// <summary>Encryption key ID.</summary>
__PROPERTY(uint32_t, kId, KId);
/** Local Site data */
/// <summary>Local Site Data.</summary>
__PROPERTY_PLAIN(SiteData, siteData, siteData);
private:
friend class TSBK;
friend class TDULC;
@ -141,9 +137,6 @@ namespace p25
/** Encryption data */
uint8_t* m_mi;
/** Local Site data */
SiteData m_siteData;
/// <summary>Decode link control.</summary>
bool decodeLC(const uint8_t* rs);
/// <summary>Encode link control.</summary>

@ -49,26 +49,49 @@ using namespace p25;
/// <summary>
/// Initializes a new instance of the TDULC class.
/// </summary>
TDULC::TDULC() :
m_verbose(false),
m_protect(false),
m_lco(LC_GROUP),
m_mfId(P25_MFG_STANDARD),
m_srcId(0U),
m_dstId(0U),
m_serviceClass(P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA),
m_emergency(false),
m_encrypted(false),
m_priority(4U),
m_group(true),
m_rs(),
m_callTimer(0U),
m_siteData(),
m_siteNetActive(false)
/// <param name="siteData"></param>
/// <param name="entry"></param>
TDULC::TDULC(SiteData siteData, lookups::IdenTable entry) : TDULC(siteData)
{
m_siteIdenEntry = lookups::IdenTable();
m_siteIdenEntry = entry;
m_grpVchNo = m_siteData.channelNo();
}
reset();
/// <summary>
/// Initializes a new instance of the TDULC class.
/// </summary>
/// <param name="siteData"></param>
/// <param name="entry"></param>
/// <param name="verbose"></param>
TDULC::TDULC(SiteData siteData, lookups::IdenTable entry, bool verbose) : TDULC(siteData)
{
m_verbose = verbose;
m_siteIdenEntry = entry;
m_grpVchNo = m_siteData.channelNo();
}
/// <summary>
/// Initializes a new instance of the TDULC class.
/// </summary>
/// <param name="lc"></param>
TDULC::TDULC(LC* lc) : TDULC(lc->siteData())
{
m_protect = lc->m_protect;
m_lco = lc->m_lco;
m_mfId = lc->m_mfId;
m_srcId = lc->m_srcId;
m_dstId = lc->m_dstId;
m_grpVchNo = lc->m_grpVchNo;
m_emergency = lc->m_emergency;
m_encrypted = lc->m_encrypted;
m_priority = lc->m_priority;
m_group = lc->m_group;
m_callTimer = lc->m_callTimer;
}
/// <summary>
@ -79,6 +102,46 @@ TDULC::~TDULC()
/* stub */
}
/// <summary>
/// Equals operator.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
TDULC& TDULC::operator=(const TDULC& data)
{
if (this != &data) {
m_verbose = data.m_verbose;
m_protect = data.m_protect;
m_lco = data.m_lco;
m_mfId = data.m_mfId;
m_srcId = data.m_srcId;
m_dstId = data.m_dstId;
m_grpVchNo = data.m_grpVchNo;
m_adjCFVA = data.m_adjCFVA;
m_adjRfssId = data.m_adjRfssId;
m_adjSiteId = data.m_adjSiteId;
m_adjChannelId = data.m_adjChannelId;
m_adjChannelNo = data.m_adjChannelNo;
m_adjServiceClass = data.m_adjServiceClass;
m_emergency = data.m_emergency;
m_encrypted = data.m_encrypted;
m_priority = data.m_priority;
m_group = data.m_group;
m_callTimer = data.m_callTimer;
m_siteData = data.m_siteData;
m_siteIdenEntry = data.m_siteIdenEntry;
}
return *this;
}
/// <summary>
/// Decode a terminator data unit w/ link control.
/// </summary>
@ -151,66 +214,39 @@ void TDULC::encode(uint8_t * data)
// Utils::dump(2U, "TDULC Interleave", data, P25_TDULC_FRAME_LENGTH_BYTES + P25_PREAMBLE_LENGTH_BYTES);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Helper to reset data values to defaults.
/// Initializes a new instance of the TDULC class.
/// </summary>
void TDULC::reset()
/// <param name="siteData"></param>
TDULC::TDULC(SiteData siteData) :
m_verbose(false),
m_protect(false),
m_lco(LC_GROUP),
m_mfId(P25_MFG_STANDARD),
m_srcId(0U),
m_dstId(0U),
m_grpVchNo(0U),
m_adjCFVA(P25_CFVA_FAILURE),
m_adjRfssId(0U),
m_adjSiteId(0U),
m_adjChannelId(0U),
m_adjChannelNo(0U),
m_adjServiceClass(P25_SVC_CLS_INVALID),
m_emergency(false),
m_encrypted(false),
m_priority(4U),
m_group(true),
m_siteData(siteData),
m_siteIdenEntry(),
m_rs(),
m_callTimer(0U)
{
m_protect = false;
m_lco = LC_GROUP;
m_mfId = P25_MFG_STANDARD;
m_srcId = 0U;
m_dstId = 0U;
m_callTimer = 0U;
m_grpVchNo = m_siteData.channelNo();
m_adjCFVA = P25_CFVA_CONV | P25_CFVA_FAILURE;
m_adjRfssId = 0U;
m_adjSiteId = 0U;
m_adjChannelId = 0U;
m_adjChannelNo = 0U;
/* Service Options */
m_emergency = false;
m_encrypted = false;
m_priority = 4U;
m_group = true;
}
/** Local Site data */
/// <summary>
/// Sets local configured site data.
/// </summary>
/// <param name="siteData">Site data.</param>
void TDULC::setSiteData(SiteData siteData)
{
m_siteData = siteData;
}
/// <summary>
/// Sets the identity lookup table entry.
/// </summary>
/// <param name="entry">Identity table entry.</param>
void TDULC::setIdenTable(lookups::IdenTable entry)
{
m_siteIdenEntry = entry;
}
/// <summary>
/// Sets a flag indicating whether or not networking is active.
/// </summary>
/// <param name="netActive">Network active flag.</param>
void TDULC::setNetActive(bool netActive)
{
m_siteNetActive = netActive;
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Decode link control.
/// </summary>
@ -281,7 +317,7 @@ bool TDULC::decodeLC(const uint8_t* rs)
/// <param name="rs"></param>
void TDULC::encodeLC(uint8_t* rs)
{
const uint32_t services = (m_siteNetActive) ? P25_SYS_SRV_NET_ACTIVE : 0U | P25_SYS_SRV_DEFAULT;
const uint32_t services = (m_siteData.netActive()) ? P25_SYS_SRV_NET_ACTIVE : 0U | P25_SYS_SRV_DEFAULT;
ulong64_t rsValue = 0U;
rs[0U] = m_lco; // LCO
@ -376,7 +412,7 @@ void TDULC::encodeLC(uint8_t* rs)
rsValue = (rsValue << 8) + m_adjSiteId; // Site ID
rsValue = (rsValue << 4) + m_adjChannelId; // Channel ID
rsValue = (rsValue << 12) + m_adjChannelNo; // Channel Number
rsValue = (rsValue << 8) + m_serviceClass; // System Service Class
rsValue = (rsValue << 8) + m_adjServiceClass; // System Service Class
}
else {
LogError(LOG_P25, "invalid values for LC_ADJ_STS_BCAST, tsbkAdjSiteRFSSId = $%02X, tsbkAdjSiteId = $%02X, tsbkAdjSiteChannel = $%02X",
@ -393,7 +429,7 @@ void TDULC::encodeLC(uint8_t* rs)
rsValue = (rsValue << 8) + m_siteData.siteId(); // Site ID
rsValue = (rsValue << 4) + m_siteData.channelId(); // Channel ID
rsValue = (rsValue << 12) + m_siteData.channelNo(); // Channel Number
rsValue = (rsValue << 8) + m_serviceClass; // System Service Class
rsValue = (rsValue << 8) + m_siteData.serviceClass(); // System Service Class
break;
case LC_NET_STS_BCAST:
rs[0U] |= 0x40U; // Implicit Operation
@ -402,7 +438,7 @@ void TDULC::encodeLC(uint8_t* rs)
rsValue = (rsValue << 12) + m_siteData.sysId(); // System ID
rsValue = (rsValue << 4) + m_siteData.channelId(); // Channel ID
rsValue = (rsValue << 12) + m_siteData.channelNo(); // Channel Number
rsValue = (rsValue << 8) + m_serviceClass; // System Service Class
rsValue = (rsValue << 8) + m_siteData.serviceClass(); // System Service Class
break;
default:
LogError(LOG_P25, "unknown LC value, mfId = $%02X, lco = $%02X", m_mfId, m_lco);

@ -59,26 +59,22 @@ namespace p25
class HOST_SW_API TDULC {
public:
/// <summary>Initializes a new instance of the TDULC class.</summary>
TDULC();
TDULC(SiteData siteData, lookups::IdenTable entry);
/// <summary>Initializes a new instance of the TDULC class.</summary>
TDULC(SiteData siteData, lookups::IdenTable entry, bool verbose);
/// <summary>Initializes a new instance of the TDULC class.</summary>
TDULC(LC* lc);
/// <summary>Finalizes a instance of the TDULC class.</summary>
~TDULC();
/// <summary>Equals operator.</summary>
TDULC& operator=(const TDULC& data);
/// <summary>Decode a trunking signalling block.</summary>
bool decode(const uint8_t* data);
/// <summary>Encode a trunking signalling block.</summary>
void encode(uint8_t* data);
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/** Local Site data */
/// <summary>Sets local configured site data.</summary>
void setSiteData(SiteData siteData);
/// <summary>Sets the identity lookup table entry.</summary>
void setIdenTable(lookups::IdenTable entry);
/// <summary>Sets a flag indicating whether or not networking is active.</summary>
void setNetActive(bool netActive);
public:
/// <summary>Flag indicating verbose log output.</summary>
__PROPERTY(bool, verbose, Verbose);
@ -96,9 +92,6 @@ namespace p25
/// <summary>Destination ID.</summary>
__PROPERTY(uint32_t, dstId, DstId);
/// <summary>Service class.</summary>
__PROPERTY(uint8_t, serviceClass, ServiceClass);
/// <summary>Voice channel number.</summary>
__PROPERTY(uint32_t, grpVchNo, GrpVchNo);
@ -115,6 +108,8 @@ namespace p25
__PROPERTY(uint8_t, adjChannelId, AdjSiteChnId);
/// <summary>Adjacent site channel number.</summary>
__PROPERTY(uint32_t, adjChannelNo, AdjSiteChnNo);
/// <summary>Adjacent site service class.</summary>
__PROPERTY(uint8_t, adjServiceClass, AdjSiteSvcClass);
/** Service Options */
/// <summary>Flag indicating the emergency bits are set.</summary>
@ -126,18 +121,22 @@ namespace p25
/// <summary>Flag indicating a group/talkgroup operation.</summary>
__PROPERTY(bool, group, Group);
/** Local Site data */
/// <summary>Local Site Data.</summary>
__PROPERTY_PLAIN(SiteData, siteData, siteData);
/// <summary>Local Site Identity Entry.</summary>
__PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry, siteIdenEntry);
private:
/// <summary>Initializes a new instance of the TDULC class.</summary>
TDULC(SiteData siteData);
friend class LC;
friend class TSBK;
edac::RS634717 m_rs;
uint32_t m_callTimer;
/** Local Site data */
SiteData m_siteData;
lookups::IdenTable m_siteIdenEntry;
bool m_siteNetActive;
/// <summary>Decode link control.</summary>
bool decodeLC(const uint8_t* rs);
/// <summary>Encode link control.</summary>

@ -48,46 +48,45 @@ using namespace p25;
/// <summary>
/// Initializes a new instance of the TSBK class.
/// </summary>
TSBK::TSBK() :
m_verbose(false),
m_protect(false),
m_lco(LC_GROUP),
m_mfId(P25_MFG_STANDARD),
m_srcId(0U),
m_dstId(0U),
m_lastBlock(false),
m_aivFlag(true),
m_extendedAddrFlag(false),
m_serviceClass(P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA),
m_emergency(false),
m_encrypted(false),
m_priority(4U),
m_group(true),
m_rs(),
m_trellis(),
m_vendorSkip(false),
m_sndcpAutoAccess(true),
m_sndcpReqAccess(false),
m_sndcpDAC(1U),
m_siteData(),
m_siteNetActive(false),
m_siteChCnt(1U)
/// <param name="siteData"></param>
/// <param name="entry"></param>
TSBK::TSBK(SiteData siteData, lookups::IdenTable entry) : TSBK(siteData)
{
m_siteCallsign = new uint8_t[P25_MOT_CALLSIGN_LENGTH_BYTES];
::memset(m_siteCallsign, 0x00U, P25_MOT_CALLSIGN_LENGTH_BYTES);
m_siteIdenEntry = entry;
}
/// <summary>
/// Initializes a new instance of the TSBK class.
/// </summary>
/// <param name="siteData"></param>
/// <param name="entry"></param>
/// <param name="verbose"></param>
TSBK::TSBK(SiteData siteData, lookups::IdenTable entry, bool verbose) : TSBK(siteData)
{
m_verbose = verbose;
m_siteIdenEntry = entry;
}
/// <summary>
/// Initializes a new instance of the TSBK class.
/// </summary>
/// <param name="lc"></param>
TSBK::TSBK(LC* lc) : TSBK(lc->siteData())
{
m_protect = lc->m_protect;
m_lco = lc->m_lco;
m_mfId = lc->m_mfId;
m_siteCallsign[0] = 'C';
m_siteCallsign[1] = 'H';
m_siteCallsign[2] = 'A';
m_siteCallsign[3] = 'N';
m_siteCallsign[4] = 'G';
m_siteCallsign[5] = 'E';
m_siteCallsign[6] = 'M';
m_siteCallsign[7] = 'E';
m_srcId = lc->m_srcId;
m_dstId = lc->m_dstId;
m_siteIdenEntry = lookups::IdenTable();
m_grpVchNo = lc->m_grpVchNo;
reset();
m_emergency = lc->m_emergency;
m_encrypted = lc->m_encrypted;
m_priority = lc->m_priority;
m_group = lc->m_group;
}
/// <summary>
@ -98,6 +97,73 @@ TSBK::~TSBK()
delete[] m_siteCallsign;
}
/// <summary>
/// Equals operator.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
TSBK& TSBK::operator=(const TSBK& data)
{
if (this != &data) {
m_verbose = data.m_verbose;
m_protect = data.m_protect;
m_lco = data.m_lco;
m_mfId = data.m_mfId;
m_srcId = data.m_srcId;
m_dstId = data.m_dstId;
m_lastBlock = data.m_lastBlock;
m_aivFlag = data.m_aivFlag;
m_extendedAddrFlag = data.m_extendedAddrFlag;
m_service = data.m_service;
m_response = data.m_response;
m_netId = data.m_netId;
m_sysId = data.m_sysId;
m_grpVchNo = data.m_grpVchNo;
m_messageValue = data.m_messageValue;
m_statusValue = data.m_statusValue;
m_extendedFunction = data.m_extendedFunction;
m_adjCFVA = data.m_adjCFVA;
m_adjRfssId = data.m_adjRfssId;
m_adjSiteId = data.m_adjSiteId;
m_adjChannelId = data.m_adjChannelId;
m_adjChannelNo = data.m_adjChannelNo;
m_adjServiceClass = data.m_adjServiceClass;
m_sccbChannelId1 = data.m_sccbChannelId1;
m_sccbChannelId2 = data.m_sccbChannelId2;
m_sccbChannelNo = data.m_sccbChannelNo;
m_lra = data.m_lra;
m_patchSuperGroupId = data.m_patchSuperGroupId;
m_patchGroup1Id = data.m_patchGroup1Id;
m_patchGroup2Id = data.m_patchGroup2Id;
m_patchGroup3Id = data.m_patchGroup3Id;
m_emergency = data.m_emergency;
m_encrypted = data.m_encrypted;
m_priority = data.m_priority;
m_group = data.m_group;
m_siteData = data.m_siteData;
m_siteIdenEntry = data.m_siteIdenEntry;
m_siteCallsign = new uint8_t[P25_MOT_CALLSIGN_LENGTH_BYTES];
::memcpy(m_siteCallsign, data.m_siteCallsign, P25_MOT_CALLSIGN_LENGTH_BYTES);
}
return *this;
}
/// <summary>
/// Decode a trunking signalling block.
/// </summary>
@ -302,7 +368,7 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
{
assert(data != NULL);
const uint32_t services = (m_siteNetActive) ? P25_SYS_SRV_NET_ACTIVE : 0U | P25_SYS_SRV_DEFAULT;
const uint32_t services = (m_siteData.netActive()) ? P25_SYS_SRV_NET_ACTIVE : 0U | P25_SYS_SRV_DEFAULT;
uint8_t tsbk[P25_TSBK_LENGTH_BYTES];
::memset(tsbk, 0x00U, P25_TSBK_LENGTH_BYTES);
@ -446,7 +512,7 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
tsbkValue = (tsbkValue << 12) + m_sccbChannelNo; // Channel (R) Number
if (m_sccbChannelId1 > 0) {
tsbkValue = (tsbkValue << 8) + m_serviceClass; // System Service Class
tsbkValue = (tsbkValue << 8) + m_siteData.serviceClass(); // System Service Class
}
else {
tsbkValue = (tsbkValue << 8) + (P25_SVC_CLS_INVALID); // System Service Class
@ -512,14 +578,14 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
tsbkValue = (tsbkValue << 8) + m_siteData.siteId(); // Site ID
tsbkValue = (tsbkValue << 16) + m_sccbChannelId1; // SCCB Channel ID 1
if (m_sccbChannelId1 > 0) {
tsbkValue = (tsbkValue << 8) + m_serviceClass; // System Service Class
tsbkValue = (tsbkValue << 8) + m_siteData.serviceClass(); // System Service Class
}
else {
tsbkValue = (tsbkValue << 8) + (P25_SVC_CLS_INVALID); // System Service Class
}
tsbkValue = (tsbkValue << 16) + m_sccbChannelId2; // SCCB Channel ID 2
if (m_sccbChannelId2 > 0) {
tsbkValue = (tsbkValue << 8) + m_serviceClass; // System Service Class
tsbkValue = (tsbkValue << 8) + m_siteData.serviceClass(); // System Service Class
}
else {
tsbkValue = (tsbkValue << 8) + (P25_SVC_CLS_INVALID); // System Service Class
@ -528,13 +594,13 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
case TSBK_OSP_RFSS_STS_BCAST:
tsbkValue = m_siteData.lra(); // Location Registration Area
tsbkValue = (tsbkValue << 4) +
(m_siteNetActive) ? P25_CFVA_NETWORK : 0U; // CFVA
(m_siteData.netActive()) ? P25_CFVA_NETWORK : 0U; // CFVA
tsbkValue = (tsbkValue << 12) + m_siteData.sysId(); // System ID
tsbkValue = (tsbkValue << 8) + m_siteData.rfssId(); // RF Sub-System ID
tsbkValue = (tsbkValue << 8) + m_siteData.siteId(); // Site ID
tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID
tsbkValue = (tsbkValue << 12) + m_siteData.channelNo(); // Channel Number
tsbkValue = (tsbkValue << 8) + m_serviceClass; // System Service Class
tsbkValue = (tsbkValue << 8) + m_siteData.serviceClass(); // System Service Class
break;
case TSBK_OSP_NET_STS_BCAST:
tsbkValue = m_siteData.lra(); // Location Registration Area
@ -542,7 +608,7 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
tsbkValue = (tsbkValue << 12) + m_siteData.sysId(); // System ID
tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID
tsbkValue = (tsbkValue << 12) + m_siteData.channelNo(); // Channel Number
tsbkValue = (tsbkValue << 8) + m_serviceClass; // System Service Class
tsbkValue = (tsbkValue << 8) + m_siteData.serviceClass(); // System Service Class
break;
case TSBK_OSP_ADJ_STS_BCAST:
{
@ -754,57 +820,6 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
}
}
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void TSBK::reset()
{
m_vendorSkip = false;
m_protect = false;
m_lco = LC_GROUP;
m_mfId = P25_MFG_STANDARD;
m_srcId = 0U;
m_dstId = 0U;
m_lastBlock = true;
m_aivFlag = true;
m_extendedAddrFlag = false;
m_service = 0U;
m_response = P25_RSP_ACCEPT;
m_netId = P25_WACN_STD_DEFAULT;
m_sysId = P25_SID_STD_DEFAULT;
m_grpVchNo = m_siteData.channelNo();
m_messageValue = 0U;
m_statusValue = 0U;
m_extendedFunction = P25_EXT_FNCT_CHECK;
m_adjCFVA = P25_CFVA_FAILURE;
m_adjRfssId = 0U;
m_adjSiteId = 0U;
m_adjChannelId = 0U;
m_adjChannelNo = 0U;
m_adjServiceClass = P25_SVC_CLS_INVALID;
/* TSBK Patch Group data */
m_patchSuperGroupId = 0U;
m_patchGroup1Id = 0U;
m_patchGroup2Id = 0U;
m_patchGroup3Id = 0U;
/* Service Options */
m_emergency = false;
m_encrypted = false;
m_priority = 4U;
m_group = true;
}
/// <summary>
/// Sets the flag to skip vendor opcode processing.
/// </summary>
@ -814,18 +829,8 @@ void TSBK::setVendorSkip(bool skip)
m_vendorSkip = skip;
}
/** Local Site data */
/// <summary>
/// Sets local configured site data.
/// </summary>
/// <param name="siteData">Site data.</param>
void TSBK::setSiteData(SiteData siteData)
{
m_siteData = siteData;
}
/// <summary>
/// Sets local configured site callsign.
/// Sets the callsign.
/// </summary>
/// <param name="callsign">Callsign.</param>
void TSBK::setCallsign(std::string callsign)
@ -841,29 +846,60 @@ void TSBK::setCallsign(std::string callsign)
}
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Sets the identity lookup table entry.
/// </summary>
/// <param name="entry">Identity table entry.</param>
void TSBK::setIdenTable(lookups::IdenTable entry)
{
m_siteIdenEntry = entry;
}
/// <summary>
/// Sets a flag indicating whether or not networking is active.
/// </summary>
/// <param name="netActive">Network active flag.</param>
void TSBK::setNetActive(bool netActive)
{
m_siteNetActive = netActive;
}
/// <summary>
/// Sets the total number of channels at the site.
/// Initializes a new instance of the TSBK class.
/// </summary>
/// <param name="chCnt">Channel count.</param>
void TSBK::setSiteChCnt(uint8_t chCnt)
/// <param name="siteData"></param>
TSBK::TSBK(SiteData siteData) :
m_verbose(false),
m_protect(false),
m_lco(LC_GROUP),
m_mfId(P25_MFG_STANDARD),
m_srcId(0U),
m_dstId(0U),
m_lastBlock(false),
m_aivFlag(true),
m_extendedAddrFlag(false),
m_service(0U),
m_response(P25_RSP_ACCEPT),
m_netId(P25_WACN_STD_DEFAULT),
m_sysId(P25_SID_STD_DEFAULT),
m_grpVchNo(0U),
m_messageValue(0U),
m_statusValue(0U),
m_extendedFunction(P25_EXT_FNCT_CHECK),
m_adjCFVA(P25_CFVA_FAILURE),
m_adjRfssId(0U),
m_adjSiteId(0U),
m_adjChannelId(0U),
m_adjChannelNo(0U),
m_adjServiceClass(P25_SVC_CLS_INVALID),
m_sccbChannelId1(0U),
m_sccbChannelId2(0U),
m_sccbChannelNo(0U),
m_lra(0U),
m_patchSuperGroupId(0U),
m_patchGroup1Id(0U),
m_patchGroup2Id(0U),
m_patchGroup3Id(0U),
m_emergency(false),
m_encrypted(false),
m_priority(4U),
m_group(true),
m_siteData(siteData),
m_siteIdenEntry(),
m_rs(),
m_trellis(),
m_vendorSkip(false),
m_sndcpAutoAccess(true),
m_sndcpReqAccess(false),
m_sndcpDAC(1U),
m_siteCallsign(NULL)
{
m_siteChCnt = chCnt;
m_siteCallsign = new uint8_t[P25_MOT_CALLSIGN_LENGTH_BYTES];
::memset(m_siteCallsign, 0x00U, P25_MOT_CALLSIGN_LENGTH_BYTES);
setCallsign(siteData.callsign());
}

@ -59,32 +59,27 @@ namespace p25
class HOST_SW_API TSBK {
public:
/// <summary>Initializes a new instance of the TSBK class.</summary>
TSBK();
TSBK(SiteData siteData, lookups::IdenTable entry);
/// <summary>Initializes a new instance of the TSBK class.</summary>
TSBK(SiteData siteData, lookups::IdenTable entry, bool verbose);
/// <summary>Initializes a new instance of the TSBK class.</summary>
TSBK(LC* lc);
/// <summary>Finalizes a instance of the TSBK class.</summary>
~TSBK();
/// <summary>Equals operator.</summary>
TSBK& operator=(const TSBK& data);
/// <summary>Decode a trunking signalling block.</summary>
bool decode(const uint8_t* data);
/// <summary>Encode a trunking signalling block.</summary>
void encode(uint8_t* data, bool singleBlock);
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/// <summary>Sets the flag to skip vendor opcode processing.</summary>
void setVendorSkip(bool skip);
/** Local Site data */
/// <summary>Sets local configured site data.</summary>
void setSiteData(SiteData siteData);
/// <summary>Sets local configured site callsign.</summary>
/// <summary>Sets the callsign.</summary>
void setCallsign(std::string callsign);
/// <summary>Sets the identity lookup table entry.</summary>
void setIdenTable(lookups::IdenTable entry);
/// <summary>Sets a flag indicating whether or not networking is active.</summary>
void setNetActive(bool netActive);
/// <summary>Sets the total number of channels at the site.</summary>
void setSiteChCnt(uint8_t chCnt);
public:
/// <summary>Flag indicating verbose log output.</summary>
@ -112,10 +107,6 @@ namespace p25
/// <summary>Service type.</summary>
__PROPERTY(uint8_t, service, Service);
/// <summary>Service class.</summary>
__PROPERTY(uint8_t, serviceClass, ServiceClass);
/// <summary>Response type.</summary>
__PROPERTY(uint8_t, response, Response);
@ -148,7 +139,7 @@ namespace p25
__PROPERTY(uint8_t, adjChannelId, AdjSiteChnId);
/// <summary>Adjacent site channel number.</summary>
__PROPERTY(uint32_t, adjChannelNo, AdjSiteChnNo);
/// <summary>Adjacent site channel number.</summary>
/// <summary>Adjacent site service class.</summary>
__PROPERTY(uint8_t, adjServiceClass, AdjSiteSvcClass);
/** SCCB Data */
@ -183,7 +174,16 @@ namespace p25
/// <summary>Flag indicating a group/talkgroup operation.</summary>
__PROPERTY(bool, group, Group);
/** Local Site data */
/// <summary>Local Site Data.</summary>
__PROPERTY_PLAIN(SiteData, siteData, siteData);
/// <summary>Local Site Identity Entry.</summary>
__PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry, siteIdenEntry);
private:
/// <summary>Initializes a new instance of the TSBK class.</summary>
TSBK(SiteData siteData);
friend class LC;
friend class TDULC;
edac::RS634717 m_rs;
@ -195,11 +195,7 @@ namespace p25
uint16_t m_sndcpDAC;
/** Local Site data */
SiteData m_siteData;
uint8_t* m_siteCallsign;
lookups::IdenTable m_siteIdenEntry;
bool m_siteNetActive;
uint8_t m_siteChCnt;
};
} // namespace lc
} // namespace p25

Loading…
Cancel
Save

Powered by TurnKey Linux.