implement some preliminary NXDN trunking;

pull/12/head
Bryan Biedenkapp 4 years ago
parent 7789470799
commit 2b3559be3c

@ -87,6 +87,8 @@ protocols:
duration: 1
voiceOnControl: false
disableCompositeFlag: false
verifyAff: false
verifyReg: false
dumpRcchData: false
callHang: 5
silenceThreshold: 14

@ -2208,7 +2208,7 @@ void HostCal::processNXDNBER(const uint8_t* buffer)
if (usc == NXDN_LICH_USC_SACCH_NS) {
if (m_berFrames == 0U) {
LogMessage(LOG_CAL, NXDN_MESSAGE_TYPE_VCALL ", 1031 Test Pattern Start");
LogMessage(LOG_CAL, "NXDN VCALL (Voice Call), 1031 Test Pattern Start");
timerStart();
m_berErrs = 0U;
@ -2217,7 +2217,7 @@ void HostCal::processNXDNBER(const uint8_t* buffer)
return;
} else {
float ber = float(m_berErrs * 100U) / float(m_berBits);
LogMessage(LOG_CAL, NXDN_MESSAGE_TYPE_TX_REL ", 1031 Test Pattern BER, frames: %u, errs: %.3f%% (%u/%u)", m_berFrames, ber, m_berErrs, m_berBits);
LogMessage(LOG_CAL, "NXDN TX_REL (Transmission Release), 1031 Test Pattern BER, frames: %u, errs: %.3f%% (%u/%u)", m_berFrames, ber, m_berErrs, m_berBits);
timerStop();
m_berErrs = 0U;
@ -2240,7 +2240,7 @@ void HostCal::processNXDNBER(const uint8_t* buffer)
m_berFrames++;
float ber = float(errors) / 1.88F;
LogMessage(LOG_CAL, NXDN_MESSAGE_TYPE_VCALL ", 1031 Test Pattern BER, (errs): %.3f%% (%u/188)", ber, errors);
LogMessage(LOG_CAL, "NXDN VCALL (Voice Call), 1031 Test Pattern BER, (errs): %.3f%% (%u/188)", ber, errors);
}
}
}

@ -32,7 +32,10 @@
#include "nxdn/NXDNDefines.h"
#include "nxdn/Control.h"
#include "nxdn/acl/AccessControl.h"
#include "nxdn/channel/UDCH.h"
#include "nxdn/lc/RTCH.h"
#include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h"
#include "edac/AMBEFEC.h"
#include "HostMain.h"
#include "Log.h"
@ -101,6 +104,7 @@ Control::Control(uint32_t ran, uint32_t callHang, uint32_t queueSize, uint32_t t
m_idenTable(idenTable),
m_ridLookup(ridLookup),
m_tidLookup(tidLookup),
m_affiliations("NXDN Affiliations", verbose),
m_idenEntry(),
m_queue(queueSize, "NXDN Frame"),
m_rfState(RS_RF_LISTENING),
@ -200,6 +204,9 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
yaml::Node systemConf = conf["system"];
yaml::Node nxdnProtocol = conf["protocols"]["nxdn"];
m_trunk->m_verifyAff = nxdnProtocol["verifyAff"].as<bool>(false);
m_trunk->m_verifyReg = nxdnProtocol["verifyReg"].as<bool>(false);
yaml::Node control = nxdnProtocol["control"];
m_control = control["enable"].as<bool>(false);
if (m_control) {
@ -241,12 +248,20 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
}
}
std::vector<uint32_t> availCh = voiceChNo;
for (auto it = availCh.begin(); it != availCh.end(); ++it) {
m_affiliations.addRFCh(*it);
}
if (printOptions) {
LogInfo(" Silence Threshold: %u (%.1f%%)", m_voice->m_silenceThreshold, float(m_voice->m_silenceThreshold) / 12.33F);
if (m_control) {
LogInfo(" Voice on Control: %s", m_voiceOnControl ? "yes" : "no");
}
LogInfo(" Verify Affiliation: %s", m_trunk->m_verifyAff ? "yes" : "no");
LogInfo(" Verify Registration: %s", m_trunk->m_verifyReg ? "yes" : "no");
}
if (m_voice != NULL) {
@ -286,8 +301,12 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits));
}
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_TX_REL ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits));
LogMessage(LOG_RF, "NXDN %s, total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_TX_REL), m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits));
if (m_control) {
m_affiliations.releaseGrant(m_rfLC.getDstId(), false);
}
writeEndRF();
return false;
@ -364,7 +383,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
ret = m_data->process(option, data, len);
}
else {
if (m_voiceOnControl) {
if (m_voiceOnControl && m_affiliations.isChBusy(m_siteData.channelNo())) {
ret = m_data->process(option, data, len);
}
}
@ -374,7 +393,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
ret = m_voice->process(fct, option, data, len);
}
else {
if (m_voiceOnControl) {
if (m_voiceOnControl && m_affiliations.isChBusy(m_siteData.channelNo())) {
ret = m_voice->process(fct, option, data, len);
}
}
@ -483,8 +502,14 @@ void Control::clock(uint32_t ms)
m_networkWatchdog.stop();
if (m_network != NULL)
m_network->resetNXDN();
if (m_control) {
m_affiliations.releaseGrant(m_netLC.getDstId(), false);
}
if (m_dedicatedControl) {
if (m_network != NULL)
m_network->resetNXDN();
}
m_netState = RS_NET_IDLE;
@ -670,6 +695,48 @@ bool Control::writeRF_ControlData()
return false;
}
/// <summary>
/// Helper to write a Tx release packet.
/// </summary>
/// <param name="noNetwork"></param>
void Control::writeRF_Message_Tx_Rel(bool noNetwork)
{
uint8_t data[NXDN_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, NXDN_FRAME_LENGTH_BYTES);
Sync::addNXDNSync(data + 2U);
channel::LICH lich;
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_UDCH);
lich.setOption(NXDN_LICH_USC_UDCH);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.encode(data + 2U);
uint8_t buffer[NXDN_UDCH_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_UDCH_LENGTH_BYTES);
m_rfLC.setMessageType(RTCH_MESSAGE_TYPE_TX_REL);
m_rfLC.encode(buffer, NXDH_UDCH_CRC_BITS);
channel::UDCH udch;
udch.setRAN(m_ran);
udch.setData(buffer);
udch.encode(data + 2U);
data[0U] = modem::TAG_DATA;
data[1U] = 0x00U;
scrambler(data + 2U);
if (!noNetwork)
m_data->writeNetwork(data, NXDN_FRAME_LENGTH_BYTES + 2U);
if (m_duplex) {
addFrame(data, NXDN_FRAME_LENGTH_BYTES + 2U);
}
}
/// <summary>
/// Helper to write RF end of frame data.
/// </summary>
@ -681,6 +748,10 @@ void Control::writeEndRF()
m_rfLC.reset();
m_rfTimeout.stop();
//m_queue.clear();
if (m_network != NULL)
m_network->resetNXDN();
}
/// <summary>

@ -45,6 +45,7 @@
#include "lookups/IdenTableLookup.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
#include "lookups/AffiliationLookup.h"
#include "modem/Modem.h"
#include "RingBuffer.h"
#include "Timer.h"
@ -137,6 +138,7 @@ namespace nxdn
lookups::IdenTableLookup* m_idenTable;
lookups::RadioIdLookup* m_ridLookup;
lookups::TalkgroupIdLookup* m_tidLookup;
lookups::AffiliationLookup m_affiliations;
lookups::IdenTable m_idenEntry;
@ -182,6 +184,9 @@ namespace nxdn
/// <summary>Helper to write control channel frame data.</summary>
bool writeRF_ControlData();
/// <summary>Helper to write a Tx release packet.</summary>
void writeRF_Message_Tx_Rel(bool noNetwork);
/// <summary></summary>
void scrambler(uint8_t* data) const;

@ -33,11 +33,6 @@
#include "Defines.h"
// Message Type String(s)
#define NXDN_MESSAGE_TYPE_VCALL "MESSAGE_TYPE_VCALL (NXDN Voice Call)"
#define NXDN_MESSAGE_TYPE_TX_REL "MESSAGE_TYPE_TX_REL (NXDN Transmit Release)"
#define NXDN_MESSAGE_TYPE_DCALL "MESSAGE_TYPE_VCALL (NXDN Data Call)"
namespace nxdn
{
// ---------------------------------------------------------------------------
@ -172,25 +167,42 @@ namespace nxdn
const uint8_t DATA_RSP_CLASS_ACK_S = 0x01U;
const uint8_t DATA_RSP_CLASS_NACK = 0x03U;
const uint8_t NXDN_CAUSE_RESOURCE_NOT_AVAIL = 0x05U;
const uint8_t NXDN_CAUSE_RSRC_NOT_AVAIL_NETWORK = 0x51U;
const uint8_t NXDN_CAUSE_RSRC_NOT_AVAIL_TEMP = 0x52U;
const uint8_t NXDN_CAUSE_RSRC_NOT_AVAIL_QUEUED = 0x53U;
const uint8_t NXDN_CAUSE_SVC_UNAVAILABLE = 0x06U;
const uint8_t NXDN_CAUSE_PROC_ERROR = 0x07U;
const uint8_t NXDN_CAUSE_MM_NORMAL_1 = 0x01U;
const uint8_t NXDN_CAUSE_MM_NORMAL_2 = 0x04U;
const uint8_t NXDN_CAUSE_VD_NORMAL_1 = 0x01U;
const uint8_t NXDN_CAUSE_VD_NORMAL_2 = 0x02U;
const uint8_t NXDN_CAUSE_VD_QUEUED = 0x03U;
const uint8_t NXDN_CAUSE_SS_NORMAL = 0x00U;
const uint8_t NXDN_CAUSE_SS_NORMAL_1 = 0x01U;
const uint8_t NXDN_CAUSE_SS_NORMAL_2 = 0x02U;
const uint8_t NXDN_CAUSE_DREQ_NORMAL = 0x01U;
const uint8_t NXDN_CAUSE_DISC_NORMAL = 0x01U;
const uint8_t NXDN_CAUSE_DISC_NORMAL_TC = 0x02U;
const uint8_t NXDN_CAUSE_PROC_ERROR = 0x70U;
const uint8_t NXDN_CAUSE_PROC_ERROR_UNDEF = 0x71U;
const uint8_t NXDN_CAUSE_MM_REG_ACCEPTED = 0x01U;
const uint8_t NXDN_CAUSE_MM_LOC_ACPT_GRP_FAIL = 0x04U;
const uint8_t NXDN_CAUSE_MM_LOC_ACPT_GRP_REFUSE = 0x04U;
const uint8_t NXDN_CAUSE_MM_REG_FAILED = 0x06U;
const uint8_t NXDN_CAUSE_MM_REG_REFUSED = 0x08U;
const uint8_t NXDN_CAUSE_VD_ACCEPTED = 0x10U;
const uint8_t NXDN_CAUSE_VD_GRP_NOT_PERM = 0x11U;
const uint8_t NXDN_CAUSE_VD_REQ_UNIT_NOT_PERM = 0x12U;
const uint8_t NXDN_CAUSE_VD_TGT_UNIT_NOT_PERM = 0x13U;
const uint8_t NXDN_CAUSE_VD_REQ_UNIT_NOT_REG = 0x1CU;
const uint8_t NXDN_CAUSE_VD_QUE_CHN_RESOURCE_NOT_AVAIL = 0x30U;
const uint8_t NXDN_CAUSE_VD_QUE_TGT_UNIT_BUSY = 0x38U;
const uint8_t NXDN_CAUSE_VD_QUE_GRP_BUSY = 0x39U;
const uint8_t NXDN_CAUSE_SS_ACK_R = 0x01U;
const uint8_t NXDN_CAUSE_SS_ACK_S = 0x02U;
const uint8_t NXDN_CAUSE_SS_NACK = 0x08U;
const uint8_t NXDN_CAUSE_SS_ACCEPTED = 0x10U;
const uint8_t NXDN_CAUSE_SS_GRP_NOT_PERM = 0x11U;
const uint8_t NXDN_CAUSE_SS_REQ_UNIT_NOT_PERM = 0x12U;
const uint8_t NXDN_CAUSE_SS_TGT_UNIT_NOT_PERM = 0x13U;
const uint8_t NXDN_CAUSE_SS_REQ_UNIT_NOT_REG = 0x1CU;
const uint8_t NXDN_CAUSE_DREQ_USER = 0x10U;
const uint8_t NXDN_CAUSE_DREQ_OTHER = 0x1FU;
const uint8_t NXDN_CAUSE_DISC_USER = 0x10U;
const uint8_t NXDN_CAUSE_DISC_OTHER = 0x1FU;
const uint8_t NXDN_SIF1_DATA_CALL_SVC = 0x01U;
const uint8_t NXDN_SIF1_VOICE_CALL_SVC = 0x02U;

@ -157,7 +157,7 @@ void RCCH::reset()
m_version = 0U;
m_causeRsp = NXDN_CAUSE_MM_NORMAL_1;
m_causeRsp = NXDN_CAUSE_MM_REG_ACCEPTED;
m_grpVchNo = 0U;
@ -232,7 +232,7 @@ RCCH::RCCH(SiteData siteData) :
m_locId(0U),
m_regOption(0U),
m_version(0U),
m_causeRsp(NXDN_CAUSE_MM_NORMAL_1),
m_causeRsp(NXDN_CAUSE_MM_REG_ACCEPTED),
m_grpVchNo(0U),
m_callType(CALL_TYPE_UNSPECIFIED),
m_emergency(false),

@ -66,7 +66,7 @@ RTCH::RTCH() :
m_delayCount(0U),
m_algId(NXDN_CIPHER_TYPE_NONE),
m_kId(0U),
m_causeRsp(NXDN_CAUSE_VD_NORMAL_1),
m_causeRsp(NXDN_CAUSE_VD_ACCEPTED),
m_data(NULL)
{
m_data = new uint8_t[NXDN_RTCH_LC_LENGTH_BYTES];
@ -99,7 +99,7 @@ RTCH::RTCH(const RTCH& data) :
m_delayCount(0U),
m_algId(NXDN_CIPHER_TYPE_NONE),
m_kId(0U),
m_causeRsp(NXDN_CAUSE_VD_NORMAL_1),
m_causeRsp(NXDN_CAUSE_VD_ACCEPTED),
m_data(NULL)
{
copy(data);
@ -202,7 +202,7 @@ void RTCH::reset()
m_algId = NXDN_CIPHER_TYPE_NONE;
m_kId = 0U;
m_causeRsp = NXDN_CAUSE_VD_NORMAL_1;
m_causeRsp = NXDN_CAUSE_VD_ACCEPTED;
}
/// <summary>

@ -34,6 +34,7 @@
#include "nxdn/packet/Data.h"
#include "nxdn/acl/AccessControl.h"
#include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h"
#include "edac/CRC.h"
#include "HostMain.h"
#include "Log.h"
@ -108,7 +109,8 @@ using namespace nxdn::packet;
#define VALID_SRCID(_SRC_ID, _DST_ID, _GROUP) \
if (!acl::AccessControl::validateSrcId(_SRC_ID)) { \
if (m_lastRejectId == 0U || m_lastRejectId != _SRC_ID) { \
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_DCALL " denial, RID rejection, srcId = %u", _SRC_ID); \
LogWarning(LOG_RF, "NXDN %s denial, RID rejection, srcId = %u", \
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_DCALL_HDR), _SRC_ID); \
::ActivityLog("NXDN", true, "RF voice rejection from %u to %s%u ", _SRC_ID, _GROUP ? "TG " : "", _DST_ID); \
m_lastRejectId = _SRC_ID; \
} \
@ -124,7 +126,8 @@ using namespace nxdn::packet;
if (!_GROUP) { \
if (!acl::AccessControl::validateSrcId(_DST_ID)) { \
if (m_lastRejectId == 0 || m_lastRejectId != _DST_ID) { \
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_DCALL " denial, RID rejection, dstId = %u", _DST_ID); \
LogWarning(LOG_RF, "NXDN %s denial, RID rejection, dstId = %u", \
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_DCALL_HDR), _DST_ID); \
::ActivityLog("NXDN", true, "RF voice rejection from %u to %s%u ", _SRC_ID, _GROUP ? "TG " : "", _DST_ID); \
m_lastRejectId = _DST_ID; \
} \
@ -138,7 +141,8 @@ using namespace nxdn::packet;
else { \
if (!acl::AccessControl::validateTGId(_DST_ID)) { \
if (m_lastRejectId == 0 || m_lastRejectId != _DST_ID) { \
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_DCALL " denial, TGID rejection, dstId = %u", _DST_ID); \
LogWarning(LOG_RF, "NXDN %s denial, TGID rejection, dstId = %u", \
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_DCALL_HDR), _DST_ID); \
::ActivityLog("NXDN", true, "RF voice rejection from %u to %s%u ", _SRC_ID, _GROUP ? "TG " : "", _DST_ID); \
m_lastRejectId = _DST_ID; \
} \
@ -216,8 +220,8 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len)
VALID_DSTID(srcId, dstId, group);
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_DCALL ", srcId = %u, dstId = %u, ack = %u, blocksToFollow = %u, padCount = %u, firstFragment = %u, fragmentCount = %u",
srcId, dstId, lc.getPacketInfo().getDelivery(), lc.getPacketInfo().getBlockCount(), lc.getPacketInfo().getPadCount(), lc.getPacketInfo().getStart(), lc.getPacketInfo().getFragmentCount());
LogMessage(LOG_RF, "NXDN %s, srcId = %u, dstId = %u, ack = %u, blocksToFollow = %u, padCount = %u, firstFragment = %u, fragmentCount = %u",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_DCALL_HDR), srcId, dstId, lc.getPacketInfo().getDelivery(), lc.getPacketInfo().getBlockCount(), lc.getPacketInfo().getPadCount(), lc.getPacketInfo().getStart(), lc.getPacketInfo().getFragmentCount());
}
::ActivityLog("NXDN", true, "RF data transmission from %u to %s%u", srcId, group ? "TG " : "", dstId);
@ -267,8 +271,8 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len)
if (data[0U] == modem::TAG_EOT) {
::ActivityLog("NXDN", true, "RF ended RF data transmission");
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_TX_REL ", total frames: %d",
m_nxdn->m_voice->m_rfFrames);
LogMessage(LOG_RF, "NXDN %s, total frames: %d",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_TX_REL), m_nxdn->m_voice->m_rfFrames);
m_nxdn->writeEndRF();
}
@ -324,8 +328,8 @@ bool Data::processNetwork(uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32
VALID_DSTID(srcId, dstId, group);
if (m_verbose) {
LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_DCALL ", srcId = %u, dstId = %u, ack = %u, blocksToFollow = %u, padCount = %u, firstFragment = %u, fragmentCount = %u",
srcId, dstId, lc.getPacketInfo().getDelivery(), lc.getPacketInfo().getBlockCount(), lc.getPacketInfo().getPadCount(), lc.getPacketInfo().getStart(), lc.getPacketInfo().getFragmentCount());
LogMessage(LOG_NET, "NXDN %s, srcId = %u, dstId = %u, ack = %u, blocksToFollow = %u, padCount = %u, firstFragment = %u, fragmentCount = %u",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_DCALL_HDR), srcId, dstId, lc.getPacketInfo().getDelivery(), lc.getPacketInfo().getBlockCount(), lc.getPacketInfo().getPadCount(), lc.getPacketInfo().getStart(), lc.getPacketInfo().getFragmentCount());
}
::ActivityLog("NXDN", false, "network data transmission from %u to %s%u", srcId, group ? "TG " : "", dstId);
@ -371,8 +375,8 @@ bool Data::processNetwork(uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32
if (data[0U] == modem::TAG_EOT) {
::ActivityLog("NXDN", true, "network ended RF data transmission");
LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_TX_REL ", total frames: %d",
m_nxdn->m_voice->m_netFrames);
LogMessage(LOG_NET, "NXDN %s, total frames: %d",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_TX_REL), m_nxdn->m_voice->m_netFrames);
m_nxdn->writeEndNet();
}

@ -33,6 +33,7 @@
#include "nxdn/packet/Trunk.h"
#include "nxdn/acl/AccessControl.h"
#include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h"
#include "edac/CRC.h"
#include "HostMain.h"
#include "Log.h"
@ -46,6 +47,76 @@ using namespace nxdn::packet;
#include <cstring>
#include <ctime>
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
// Make sure control data is supported.
#define IS_SUPPORT_CONTROL_CHECK(_PCKT, _SRCID) \
if (!m_nxdn->m_control) { \
LogWarning(LOG_RF, "NXDN, %s denial, unsupported service, srcId = %u", \
NXDNUtils::messageTypeToString(_PCKT, true), _SRCID); \
writeRF_Message_Deny(NXDN_CAUSE_SVC_UNAVAILABLE, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
// Validate the source RID.
#define VALID_SRCID(_PCKT, _SRCID, _RSN) \
if (!acl::AccessControl::validateSrcId(_SRCID)) { \
LogWarning(LOG_RF, "NXDN, %s denial, RID rejection, srcId = %u", \
NXDNUtils::messageTypeToString(_PCKT, true), _SRCID); \
writeRF_Message_Deny(_RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
// Validate the target RID.
#define VALID_DSTID(_PCKT, _DSTID, _RSN) \
if (!acl::AccessControl::validateSrcId(_DSTID)) { \
LogWarning(LOG_RF, "NXDN, %s denial, RID rejection, dstId = %u", \
NXDNUtils::messageTypeToString(_PCKT, true), _DSTID); \
writeRF_Message_Deny(_RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
// Validate the talkgroup ID.
#define VALID_TGID(_PCKT, _DSTID, _RSN) \
if (!acl::AccessControl::validateTGId(_DSTID)) { \
LogWarning(LOG_RF, "NXDN, %s denial, TGID rejection, dstId = %u", \
NXDNUtils::messageTypeToString(_PCKT, true), _DSTID); \
writeRF_Message_Deny(_RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
// Verify the source RID is registered.
#define VERIFY_SRCID_REG(_PCKT, _SRCID, _RSN) \
if (!m_nxdn->m_affiliations.isUnitReg(_SRCID) && m_verifyReg) { \
LogWarning(LOG_RF, "NXDN, %s denial, RID not registered, srcId = %u", \
NXDNUtils::messageTypeToString(_PCKT, true), _SRCID); \
writeRF_Message_Deny(_RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
// Verify the source RID is affiliated.
#define VERIFY_SRCID_AFF(_PCKT, _SRCID, _DSTID, _RSN) \
if (!m_nxdn->m_affiliations.isGroupAff(_SRCID, _DSTID) && m_verifyAff) { \
LogWarning(LOG_RF, "NXDN, %s denial, RID not affiliated to TGID, srcId = %u, dstId = %u", \
NXDNUtils::messageTypeToString(_PCKT, true), _SRCID, _DSTID); \
writeRF_Message_Deny(_RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t GRANT_TIMER_TIMEOUT = 15U;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
@ -91,14 +162,68 @@ bool Trunk::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
return false;
}
// The layer3 data will only be correct if valid is true
RPT_RF_STATE prevRfState = m_nxdn->m_rfState;
if (m_nxdn->m_rfState != RS_RF_DATA) {
m_nxdn->m_rfState = RS_RF_DATA;
}
m_nxdn->m_queue.clear();
// the layer3 data will only be correct if valid is true
uint8_t buffer[NXDN_CAC_LENGTH_BYTES];
cac.getData(buffer);
m_rfLC.decode(buffer, NXDN_CAC_SHORT_IN_CRC_BITS);
// TODO TODO -- process incoming data
uint16_t srcId = m_rfLC.getSrcId();
uint16_t dstId = m_rfLC.getDstId();
switch (m_rfLC.getMessageType()) {
case RTCH_MESSAGE_TYPE_VCALL:
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK(RTCH_MESSAGE_TYPE_VCALL, srcId);
// validate the source RID
VALID_SRCID(RTCH_MESSAGE_TYPE_VCALL, srcId, NXDN_CAUSE_VD_REQ_UNIT_NOT_PERM);
// validate the talkgroup ID
VALID_TGID(RTCH_MESSAGE_TYPE_VCALL, dstId, NXDN_CAUSE_VD_TGT_UNIT_NOT_PERM);
// verify the source RID is affiliated
VERIFY_SRCID_AFF(RTCH_MESSAGE_TYPE_VCALL, srcId, dstId, NXDN_CAUSE_VD_REQ_UNIT_NOT_REG);
if (m_verbose) {
LogMessage(LOG_RF, "NXDN, %s, srcId = %u, dstId = %u", NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL, true), srcId, dstId);
}
writeRF_Message_Grant(true);
break;
case RCCH_MESSAGE_TYPE_REG:
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK(RCCH_MESSAGE_TYPE_REG, srcId);
if (m_verbose) {
LogMessage(LOG_RF, "NXDN %s, srcId = %u", NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_REG, true), srcId);
}
writeRF_Message_U_Reg_Rsp(srcId);
break;
case RCCH_MESSAGE_TYPE_GRP_REG:
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK(RCCH_MESSAGE_TYPE_GRP_REG, srcId);
if (m_verbose) {
LogMessage(LOG_RF, "NXDN %s, srcId = %u, dstId = %u", NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_GRP_REG, true), srcId, dstId);
}
writeRF_Message_Grp_Reg_Rsp(srcId, dstId);
break;
default:
LogError(LOG_RF, "NXDN, unhandled message type, messageType = $%02X", m_rfLC.getMessageType());
break;
}
m_nxdn->m_rfState = prevRfState;
return true;
}
@ -131,7 +256,28 @@ bool Trunk::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
/// <param name="ms"></param>
void Trunk::clock(uint32_t ms)
{
return;
if (m_nxdn->m_control) {
if (m_nxdn->m_network != NULL) {
if (m_nxdn->m_network->isHandlingChGrants() && m_nxdn->m_siteData.netActive()) {
bool grp = true;
uint32_t srcId = 0U;
uint32_t dstId = 0U;
uint32_t grpVchNo = 0U;
// do we have a grant response?
if (m_nxdn->m_network->readGrantRsp(grp, srcId, dstId, grpVchNo)) {
m_rfLC.setSrcId(srcId);
m_rfLC.setDstId(dstId);
m_rfLC.setGrpVchNo(grpVchNo);
writeRF_Message_Grant(grp, true, true, true);
}
}
}
// clock all the grant timers
m_nxdn->m_affiliations.clock(ms);
}
}
// ---------------------------------------------------------------------------
@ -149,6 +295,8 @@ void Trunk::clock(uint32_t ms)
Trunk::Trunk(Control* nxdn, network::BaseNetwork* network, bool dumpRCCHData, bool debug, bool verbose) :
m_nxdn(nxdn),
m_network(network),
m_verifyAff(false),
m_verifyReg(false),
m_rfLC(SiteData(), lookups::IdenTable()),
m_netLC(SiteData(), lookups::IdenTable()),
m_lastRejectId(0U),
@ -214,11 +362,11 @@ void Trunk::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
switch (n)
{
case 6:
writeRF_CC_Site_Info();
writeRF_CC_Message_Site_Info();
break;
case 0:
default:
writeRF_CC_Service_Info();
writeRF_CC_Message_Service_Info();
break;
}
@ -228,13 +376,328 @@ void Trunk::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
} while (i <= seqCnt);
}
/// <summary>
/// Helper to write a single-block RCCH packet.
/// </summary>
/// <param name="noNetwork"></param>
/// <param name="clearBeforeWrite"></param>
void Trunk::writeRF_Message(bool noNetwork, bool clearBeforeWrite)
{
if (!m_nxdn->m_control)
return;
uint8_t data[NXDN_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, NXDN_FRAME_LENGTH_BYTES);
Sync::addNXDNSync(data + 2U);
channel::LICH lich;
lich.setRFCT(NXDN_LICH_RFCT_RCCH);
lich.setFCT(NXDN_LICH_CAC_OUTBOUND);
lich.setOption(NXDN_LICH_DATA_NORMAL);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.encode(data + 2U);
uint8_t buffer[NXDN_RCCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES);
m_rfLC.encode(buffer, NXDN_CAC_OUT_CRC_BITS);
channel::CAC cac;
cac.setRAN(m_nxdn->m_ran);
cac.setData(buffer);
cac.encode(data + 2U);
data[0U] = modem::TAG_DATA;
data[1U] = 0x00U;
m_nxdn->scrambler(data + 2U);
if (!noNetwork)
writeNetwork(data, NXDN_FRAME_LENGTH_BYTES + 2U);
if (clearBeforeWrite) {
m_nxdn->m_modem->clearP25Data();
m_nxdn->m_queue.clear();
}
if (m_nxdn->m_duplex) {
m_nxdn->addFrame(data, NXDN_FRAME_LENGTH_BYTES + 2U);
}
}
/// <summary>
/// Helper to write a grant packet.
/// </summary>
/// <param name="grp"></param>
/// <param name="skip"></param>
/// <param name="net"></param>
/// <param name="skipNetCheck"></param>
/// <returns></returns>
bool Trunk::writeRF_Message_Grant(bool grp, bool skip, bool net, bool skipNetCheck)
{
uint8_t messageType = m_rfLC.getMessageType();
// do we have a network connection and are we handling grants at the network?
if (m_nxdn->m_network != NULL) {
if (m_nxdn->m_network->isHandlingChGrants() && m_nxdn->m_siteData.netActive() && !skipNetCheck) {
return m_nxdn->m_network->writeGrantReq(grp, m_rfLC.getSrcId(), m_rfLC.getDstId());
}
}
// are we skipping checking?
if (!skip) {
if (m_nxdn->m_rfState != RS_RF_LISTENING && m_nxdn->m_rfState != RS_RF_DATA) {
if (!net) {
LogWarning(LOG_RF, "NXDN, %s denied, traffic in progress, dstId = %u",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL, true), m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("NXDN", true, "group grant request from %u to TG %u denied", m_rfLC.getSrcId(), m_rfLC.getDstId());
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
if (m_nxdn->m_netState != RS_NET_IDLE && m_rfLC.getDstId() == m_nxdn->m_netLastDstId) {
if (!net) {
LogWarning(LOG_RF, "NXDN, %s denied, traffic in progress, dstId = %u",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL, true), m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("NXDN", true, "group grant request from %u to TG %u denied", m_rfLC.getSrcId(), m_rfLC.getDstId());
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
// don't transmit grants if the destination ID's don't match and the network TG hang timer is running
if (m_nxdn->m_rfLastDstId != 0U) {
if (m_nxdn->m_rfLastDstId != m_rfLC.getDstId() && (m_nxdn->m_rfTGHang.isRunning() && !m_nxdn->m_rfTGHang.hasExpired())) {
if (!net) {
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
}
if (!m_nxdn->m_affiliations.isGranted(m_rfLC.getDstId())) {
if (!m_nxdn->m_affiliations.isRFChAvailable()) {
if (grp) {
if (!net) {
LogWarning(LOG_RF, "NXDN, %s queued, no channels available, dstId = %u",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL, true), m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_CHN_RESOURCE_NOT_AVAIL, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("NXDN", true, "group grant request from %u to TG %u queued", m_rfLC.getSrcId(), m_rfLC.getDstId());
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
else {
if (!net) {
LogWarning(LOG_RF, "NXDN, %s queued, no channels available, dstId = %u",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL, true), m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_CHN_RESOURCE_NOT_AVAIL, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("P25", true, "unit-to-unit grant request from %u to %u queued", m_rfLC.getSrcId(), m_rfLC.getDstId());
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
}
else {
if (m_nxdn->m_affiliations.grantCh(m_rfLC.getDstId(), GRANT_TIMER_TIMEOUT)) {
uint32_t chNo = m_nxdn->m_affiliations.getGrantedCh(m_rfLC.getDstId());
m_rfLC.setGrpVchNo(chNo);
}
}
}
else {
uint32_t chNo = m_nxdn->m_affiliations.getGrantedCh(m_rfLC.getDstId());
m_rfLC.setGrpVchNo(chNo);
}
}
if (grp) {
if (!net) {
::ActivityLog("NXDN", true, "group grant request from %u to TG %u", m_rfLC.getSrcId(), m_rfLC.getDstId());
}
}
else {
if (!net) {
::ActivityLog("NXDN", true, "unit-to-unit grant request from %u to %u", m_rfLC.getSrcId(), m_rfLC.getDstId());
}
}
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "NXDN, %s, emerg = %u, encrypt = %u, prio = %u, chNo = %u, srcId = %u, dstId = %u",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL, true, true), m_rfLC.getEmergency(), m_rfLC.getEncrypted(),
m_rfLC.getPriority(), m_rfLC.getGrpVchNo(), m_rfLC.getSrcId(), m_rfLC.getDstId());
}
// transmit group grant
m_rfLC.setMessageType(RTCH_MESSAGE_TYPE_VCALL);
writeRF_Message(false, true);
m_rfLC.setMessageType(messageType);
return true;
}
/// <summary>
/// Helper to write a deny packet.
/// </summary>
/// <param name="reason"></param>
/// <param name="service"></param>
void Trunk::writeRF_Message_Deny(uint8_t reason, uint8_t service)
{
uint8_t messageType = m_rfLC.getMessageType();
m_rfLC.setMessageType(service);
m_rfLC.setCauseResponse(reason);
if (m_verbose) {
LogMessage(LOG_RF, "NXDN, %s, reason = $%02X, service = $%02X, srcId = %u, dstId = %u",
NXDNUtils::messageTypeToString(service, true), service, m_rfLC.getSrcId(), m_rfLC.getDstId());
}
writeRF_Message(false);
m_rfLC.setMessageType(messageType);
}
/// <summary>
/// Helper to write a group registration response packet.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
bool Trunk::writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId)
{
bool ret = false;
m_rfLC.setMessageType(RCCH_MESSAGE_TYPE_GRP_REG);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_ACCEPTED);
// validate the location ID
if (m_rfLC.getLocId() != m_nxdn->m_siteData.locId()) {
LogWarning(LOG_RF, "NXDN %s denial, LOCID rejection, locId = $%04X",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_GRP_REG, true), m_rfLC.getLocId());
::ActivityLog("NXDN", true, "group affiliation request from %u denied", srcId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
// validate the source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
LogWarning(LOG_RF, "NXDN %s denial, RID rejection, srcId = %u",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_GRP_REG, true), srcId);
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u denied", srcId, "TG ", dstId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
// validate the source RID is registered
if (!m_nxdn->m_affiliations.isUnitReg(srcId) && m_verifyReg) {
LogWarning(LOG_RF, "NXDN %s denial, RID not registered, srcId = %u",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_GRP_REG, true), srcId);
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u denied", srcId, "TG ", dstId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_REFUSED);
}
// validate the talkgroup ID
if (m_rfLC.getGroup()) {
if (dstId == 0U) {
LogWarning(LOG_RF, "NXDN %s, TGID 0, dstId = %u",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_GRP_REG, true), dstId);
}
else {
if (!acl::AccessControl::validateTGId(dstId)) {
LogWarning(LOG_RF, "NXDN %s denial, TGID rejection, dstId = %u",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_GRP_REG, true), dstId);
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u denied", srcId, "TG ", dstId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_LOC_ACPT_GRP_REFUSE);
}
}
}
if (m_rfLC.getCauseResponse() == NXDN_CAUSE_MM_REG_ACCEPTED) {
if (m_verbose) {
LogMessage(LOG_RF, "NXDN %s, srcId = %u, dstId = %u",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_GRP_REG, true, true), srcId, dstId);
}
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u", srcId, "TG ", dstId);
ret = true;
// update dynamic affiliation table
m_nxdn->m_affiliations.groupAff(srcId, dstId);
}
writeRF_Message(false);
return ret;
}
/// <summary>
/// Helper to write a unit registration response packet.
/// </summary>
/// <param name="srcId"></param>
void Trunk::writeRF_Message_U_Reg_Rsp(uint32_t srcId)
{
m_rfLC.setMessageType(RCCH_MESSAGE_TYPE_REG);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_ACCEPTED);
// validate the location ID
if (m_rfLC.getLocId() != m_nxdn->m_siteData.locId()) {
LogWarning(LOG_RF, "NXDN %s denial, LOCID rejection, locId = $%04X",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_REG, true), m_rfLC.getLocId());
::ActivityLog("NXDN", true, "unit registration request from %u denied", srcId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
// validate the source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
LogWarning(LOG_RF, "NXDN %s denial, RID rejection, srcId = %u",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_REG, true), srcId);
::ActivityLog("NXDN", true, "unit registration request from %u denied", srcId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
if (m_rfLC.getCauseResponse() == NXDN_CAUSE_MM_REG_ACCEPTED) {
if (m_verbose) {
LogMessage(LOG_RF, "NXDN %s, srcId = %u, locId = %u",
NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_REG, true, true), srcId, m_rfLC.getLocId());
}
::ActivityLog("NXDN", true, "unit registration request from %u", srcId);
// update dynamic unit registration table
if (!m_nxdn->m_affiliations.isUnitReg(srcId)) {
m_nxdn->m_affiliations.unitReg(srcId);
}
}
m_rfLC.setSrcId(srcId);
m_rfLC.setDstId(srcId);
writeRF_Message(true);
}
/// <summary>
/// Helper to write a CC SITE_INFO broadcast packet on the RF interface.
/// </summary>
void Trunk::writeRF_CC_Site_Info()
void Trunk::writeRF_CC_Message_Site_Info()
{
if (m_debug) {
LogMessage(LOG_RF, "NXDN, RCCH_MESSAGE_TYPE_SITE_INFO (Site Information)");
LogMessage(LOG_RF, "NXDN, %s", NXDNUtils::messageTypeToString(RCCH_MESSAGE_TYPE_SITE_INFO));
}
uint8_t data[NXDN_FRAME_LENGTH_BYTES + 2U];
@ -273,10 +736,10 @@ void Trunk::writeRF_CC_Site_Info()
/// <summary>
/// Helper to write a CC SRV_INFO broadcast packet on the RF interface.
/// </summary>
void Trunk::writeRF_CC_Service_Info()
void Trunk::writeRF_CC_Message_Service_Info()
{
if (m_debug) {
LogMessage(LOG_RF, "NXDN, MESSAGE_TYPE_SRV_INFO (Service Information)");
LogMessage(LOG_RF, "NXDN, %s", NXDNUtils::messageTypeToString(MESSAGE_TYPE_SRV_INFO));
}
uint8_t data[NXDN_FRAME_LENGTH_BYTES + 2U];

@ -78,6 +78,9 @@ namespace nxdn
network::BaseNetwork* m_network;
bool m_verifyAff;
bool m_verifyReg;
lc::RCCH m_rfLC;
lc::RCCH m_netLC;
@ -99,10 +102,22 @@ namespace nxdn
/// <summary>Helper to write control channel packet data.</summary>
void writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS);
/// <summary>Helper to write a single-block RCCH packet.</summary>
void writeRF_Message(bool noNetwork, bool clearBeforeWrite = false);
/// <summary>Helper to write a grant packet.</summary>
bool writeRF_Message_Grant(bool grp, bool skip = false, bool net = false, bool skipNetCheck = false);
/// <summary>Helper to write a deny packet.</summary>
void writeRF_Message_Deny(uint8_t reason, uint8_t service);
/// <summary>Helper to write a group registration response packet.</summary>
bool writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId);
/// <summary>Helper to write a unit registration response packet.</summary>
void writeRF_Message_U_Reg_Rsp(uint32_t srcId);
/// <summary>Helper to write a CC SITE_INFO broadcast packet on the RF interface.</summary>
void writeRF_CC_Site_Info();
void writeRF_CC_Message_Site_Info();
/// <summary>Helper to write a CC SRV_INFO broadcast packet on the RF interface.</summary>
void writeRF_CC_Service_Info();
void writeRF_CC_Message_Service_Info();
};
} // namespace packet
} // namespace nxdn

@ -36,6 +36,7 @@
#include "nxdn/acl/AccessControl.h"
#include "nxdn/Audio.h"
#include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h"
#include "edac/CRC.h"
#include "HostMain.h"
#include "Log.h"
@ -110,7 +111,8 @@ using namespace nxdn::packet;
#define VALID_SRCID(_SRC_ID, _DST_ID, _GROUP) \
if (!acl::AccessControl::validateSrcId(_SRC_ID)) { \
if (m_lastRejectId == 0U || m_lastRejectId != _SRC_ID) { \
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL " denial, RID rejection, srcId = %u", _SRC_ID); \
LogWarning(LOG_RF, "NXDN, %s denial, RID rejection, srcId = %u", \
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), _SRC_ID); \
::ActivityLog("NXDN", true, "RF voice rejection from %u to %s%u ", _SRC_ID, _GROUP ? "TG " : "", _DST_ID); \
m_lastRejectId = _SRC_ID; \
} \
@ -126,7 +128,8 @@ using namespace nxdn::packet;
if (!_GROUP) { \
if (!acl::AccessControl::validateSrcId(_DST_ID)) { \
if (m_lastRejectId == 0 || m_lastRejectId != _DST_ID) { \
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL " denial, RID rejection, dstId = %u", _DST_ID); \
LogWarning(LOG_RF, "NXDN %s denial, RID rejection, dstId = %u", \
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), _DST_ID); \
::ActivityLog("NXDN", true, "RF voice rejection from %u to %s%u ", _SRC_ID, _GROUP ? "TG " : "", _DST_ID); \
m_lastRejectId = _DST_ID; \
} \
@ -140,7 +143,8 @@ using namespace nxdn::packet;
else { \
if (!acl::AccessControl::validateTGId(_DST_ID)) { \
if (m_lastRejectId == 0 || m_lastRejectId != _DST_ID) { \
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL " denial, TGID rejection, dstId = %u", _DST_ID); \
LogWarning(LOG_RF, "NXDN %s denial, TGID rejection, dstId = %u", \
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), _DST_ID); \
::ActivityLog("NXDN", true, "RF voice rejection from %u to %s%u ", _SRC_ID, _GROUP ? "TG " : "", _DST_ID); \
m_lastRejectId = _DST_ID; \
} \
@ -237,6 +241,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
return false;
}
m_nxdn->m_rfLastDstId = lc.getDstId();
m_nxdn->m_rfLC = lc;
Sync::addNXDNSync(data + 2U);
@ -282,8 +287,8 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
float(m_rfFrames) / 12.5F, float(m_rfErrs * 100U) / float(m_rfBits));
}
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_TX_REL ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
m_rfFrames, m_rfBits, m_rfUndecodableLC, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits));
LogMessage(LOG_RF, "NXDN %s, total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_TX_REL), m_rfFrames, m_rfBits, m_rfUndecodableLC, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits));
m_nxdn->writeEndRF();
} else {
@ -299,8 +304,8 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
m_nxdn->m_rssiCount = 1U;
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%02X",
srcId, dstId, group, lc.getEmergency(), encrypted, lc.getPriority(), lc.getAlgId(), lc.getKId());
LogMessage(LOG_RF, "NXDN %s, srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%02X",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), srcId, dstId, group, lc.getEmergency(), encrypted, lc.getPriority(), lc.getAlgId(), lc.getKId());
}
::ActivityLog("NXDN", true, "RF %svoice transmission from %u to %s%u", encrypted ? "encrypted " : "", srcId, group ? "TG " : "", dstId);
@ -392,6 +397,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
// validate destination ID
VALID_DSTID(srcId, dstId, group);
m_nxdn->m_rfLastDstId = m_nxdn->m_rfLC.getDstId();
m_rfFrames = 0U;
m_rfErrs = 0U;
m_rfBits = 1U;
@ -404,8 +410,8 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
m_nxdn->m_rssiCount = 1U;
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%04X",
srcId, dstId, group, m_nxdn->m_rfLC.getEmergency(), encrypted, m_nxdn->m_rfLC.getPriority(), m_nxdn->m_rfLC.getAlgId(), m_nxdn->m_rfLC.getKId());
LogMessage(LOG_RF, "NXDN %s, srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%04X",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), srcId, dstId, group, m_nxdn->m_rfLC.getEmergency(), encrypted, m_nxdn->m_rfLC.getPriority(), m_nxdn->m_rfLC.getAlgId(), m_nxdn->m_rfLC.getKId());
}
::ActivityLog("NXDN", true, "RF %slate entry from %u to %s%u", encrypted ? "encrypted ": "", srcId, group ? "TG " : "", dstId);
@ -497,15 +503,16 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U, NXDN_NULL_AMBE, 9U);
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", exceeded lost audio threshold, filling in");
LogWarning(LOG_RF, "NXDN %s, exceeded lost audio threshold, filling in",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL));
}
m_rfErrs += errors;
m_rfBits += 188U;
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/141 (%.1f%%)",
errors, float(errors) / 1.88F);
LogMessage(LOG_RF, "NXDN %s, audio, errs = %u/141 (%.1f%%)",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), errors, float(errors) / 1.88F);
}
} else if (option == NXDN_LICH_STEAL_FACCH1_1) {
channel::FACCH1 facch1;
@ -528,15 +535,16 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U, NXDN_NULL_AMBE, 9U);
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", exceeded lost audio threshold, filling in");
LogWarning(LOG_RF, "NXDN %s, exceeded lost audio threshold, filling in",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL));
}
m_rfErrs += errors;
m_rfBits += 94U;
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)",
errors, float(errors) / 0.94F);
LogMessage(LOG_RF, "NXDN %s, audio, errs = %u/94 (%.1f%%)",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), errors, float(errors) / 0.94F);
}
} else if (option == NXDN_LICH_STEAL_FACCH1_2) {
edac::AMBEFEC ambe;
@ -554,15 +562,16 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 0U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U, NXDN_NULL_AMBE, 9U);
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", exceeded lost audio threshold, filling in");
LogWarning(LOG_RF, "NXDN %s, exceeded lost audio threshold, filling in",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL));
}
m_rfErrs += errors;
m_rfBits += 94U;
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)",
errors, float(errors) / 0.94F);
LogMessage(LOG_RF, "NXDN %s, audio, errs = %u/94 (%.1f%%)",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), errors, float(errors) / 0.94F);
}
channel::FACCH1 facch1;
@ -663,6 +672,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
return false;
}
m_nxdn->m_netLastDstId = lc.getDstId();
m_nxdn->m_netLC = lc;
Sync::addNXDNSync(data + 2U);
@ -699,8 +709,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
::ActivityLog("NXDN", false, "network end of transmission, %.1f seconds",
float(m_netFrames) / 12.5F);
LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_TX_REL ", total frames: %d",
m_netFrames);
LogMessage(LOG_NET, "NXDN %s, total frames: %d",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_TX_REL), m_netFrames);
m_nxdn->writeEndNet();
} else {
@ -709,8 +719,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
m_nxdn->m_netState = RS_NET_AUDIO;
if (m_verbose) {
LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%02X",
srcId, dstId, group, lc.getEmergency(), encrypted, lc.getPriority(), lc.getAlgId(), lc.getKId());
LogMessage(LOG_NET, "NXDN %s, srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%02X",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), srcId, dstId, group, lc.getEmergency(), encrypted, lc.getPriority(), lc.getAlgId(), lc.getKId());
}
::ActivityLog("NXDN", false, "network %svoice transmission from %u to %s%u", encrypted ? "encrypted " : "", srcId, group ? "TG " : "", dstId);
@ -802,6 +812,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
// validate destination ID
VALID_DSTID(srcId, dstId, group);
m_nxdn->m_netLastDstId = m_nxdn->m_netLC.getDstId();
m_rfFrames = 0U;
m_rfErrs = 0U;
m_rfBits = 1U;
@ -809,8 +820,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
m_nxdn->m_netState = RS_NET_AUDIO;
if (m_verbose) {
LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%04X",
srcId, dstId, group, m_nxdn->m_netLC.getEmergency(), encrypted, m_nxdn->m_netLC.getPriority(), m_nxdn->m_netLC.getAlgId(), m_nxdn->m_netLC.getKId());
LogMessage(LOG_NET, "NXDN %s, srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%04X",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), srcId, dstId, group, m_nxdn->m_netLC.getEmergency(), encrypted, m_nxdn->m_netLC.getPriority(), m_nxdn->m_netLC.getAlgId(), m_nxdn->m_netLC.getKId());
}
::ActivityLog("NXDN", false, "network %slate entry from %u to %s%u", encrypted ? "encrypted ": "", srcId, group ? "TG " : "", dstId);
@ -890,8 +901,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
m_rfBits += 188U;
if (m_verbose) {
LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/141 (%.1f%%)",
errors, float(errors) / 1.88F);
LogMessage(LOG_NET, "NXDN %s, audio, errs = %u/141 (%.1f%%)",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), errors, float(errors) / 1.88F);
}
} else if (option == NXDN_LICH_STEAL_FACCH1_1) {
channel::FACCH1 facch1;
@ -910,8 +921,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
m_rfBits += 94U;
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)",
errors, float(errors) / 0.94F);
LogMessage(LOG_RF, "NXDN %s, audio, errs = %u/94 (%.1f%%)",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), errors, float(errors) / 0.94F);
}
} else if (option == NXDN_LICH_STEAL_FACCH1_2) {
edac::AMBEFEC ambe;
@ -925,8 +936,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
m_rfBits += 94U;
if (m_verbose) {
LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)",
errors, float(errors) / 0.94F);
LogMessage(LOG_RF, "NXDN %s, audio, errs = %u/94 (%.1f%%)",
NXDNUtils::messageTypeToString(RTCH_MESSAGE_TYPE_VCALL), errors, float(errors) / 0.94F);
}
channel::FACCH1 facch1;
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);

Loading…
Cancel
Save

Powered by TurnKey Linux.