From 34f8b0407f92716bc05b0eea4b0b732bf5d238f8 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sun, 13 Mar 2022 00:44:09 -0500 Subject: [PATCH] add experimental support for split NAC, this change adds a new txNAC configuration option to set the transmit NAC; --- config.example.yml | 1 + host/Host.cpp | 10 ++ p25/Control.cpp | 9 ++ p25/Control.h | 1 + p25/NID.cpp | 324 +++++++++++++++++++++++++++++++-------------- p25/NID.h | 36 +++-- 6 files changed, 277 insertions(+), 104 deletions(-) diff --git a/config.example.yml b/config.example.yml index 2da70f0e..277c7c82 100644 --- a/config.example.yml +++ b/config.example.yml @@ -98,6 +98,7 @@ system: - 1 colorCode: 1 nac: 293 +# txNAC: 293 pSuperGroup: FFFF netId: BB800 sysId: 001 diff --git a/host/Host.cpp b/host/Host.cpp index f6a00782..762bd304 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -1442,6 +1442,11 @@ bool Host::readParams() m_p25NAC = (uint32_t)::strtoul(rfssConfig["nac"].as("293").c_str(), NULL, 16); m_p25NAC = p25::P25Utils::nac(m_p25NAC); + uint32_t p25TxNAC = (uint32_t)::strtoul(rfssConfig["txNAC"].as("F7E").c_str(), NULL, 16); + if (p25TxNAC == m_p25NAC) { + LogWarning(LOG_HOST, "Only use txNAC when split NAC operations are needed. nac and txNAC should not be the same!"); + } + m_p25PatchSuperGroup = (uint32_t)::strtoul(rfssConfig["pSuperGroup"].as("FFFF").c_str(), NULL, 16); m_p25NetId = (uint32_t)::strtoul(rfssConfig["netId"].as("BB800").c_str(), NULL, 16); m_p25NetId = p25::P25Utils::netId(m_p25NetId); @@ -1466,6 +1471,11 @@ bool Host::readParams() LogInfo(" DMR Color Code: %u", m_dmrColorCode); LogInfo(" DMR Network Id: $%05X", m_dmrNetId); LogInfo(" P25 NAC: $%03X", m_p25NAC); + + if (p25TxNAC != 0xF7EU && p25TxNAC != m_p25NAC) { + LogInfo(" P25 Tx NAC: $%03X", p25TxNAC); + } + LogInfo(" P25 Patch Super Group: $%04X", m_p25PatchSuperGroup); LogInfo(" P25 Network Id: $%05X", m_p25NetId); LogInfo(" P25 System Id: $%03X", m_p25SysId); diff --git a/p25/Control.cpp b/p25/Control.cpp index ce6eca39..5cf1fd7b 100644 --- a/p25/Control.cpp +++ b/p25/Control.cpp @@ -86,6 +86,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod m_data(NULL), m_trunk(NULL), m_nac(nac), + m_txNAC(nac), m_timeout(timeout), m_modem(modem), m_network(network), @@ -279,6 +280,14 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s LogInfo(" Unit-to-Unit Availability Check: %s", m_trunk->m_unitToUnitAvailCheck ? "yes" : "no"); } + // are we overriding the NAC for split NAC operations? + uint32_t txNAC = (uint32_t)::strtoul(systemConf["config"]["txNAC"].as("F7E").c_str(), NULL, 16); + if (txNAC != 0xF7EU && txNAC != m_nac) { + LogMessage(LOG_P25, "Split NAC operations, setting Tx NAC to $%03X", txNAC); + m_txNAC = txNAC; + m_nid.setTxNAC(m_txNAC); + } + m_voice->resetRF(); m_voice->resetNet(); m_data->resetRF(); diff --git a/p25/Control.h b/p25/Control.h index 5adedb65..3eaef324 100644 --- a/p25/Control.h +++ b/p25/Control.h @@ -119,6 +119,7 @@ namespace p25 TrunkPacket* m_trunk; uint32_t m_nac; + uint32_t m_txNAC; uint32_t m_timeout; modem::Modem* m_modem; diff --git a/p25/NID.cpp b/p25/NID.cpp index 080a5ce9..f7288802 100644 --- a/p25/NID.cpp +++ b/p25/NID.cpp @@ -12,7 +12,7 @@ // /* * Copyright (C) 2016 by Jonathan Naylor G4KLX -* Copyright (C) 2017 by Bryan Biedenkapp N2PLL +* Copyright (C) 2017,2022 by Bryan Biedenkapp N2PLL * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,64 +54,24 @@ const uint32_t MAX_NID_ERRS = 7U;//5U; /// P25 Network Access Code. NID::NID(uint32_t nac) : m_duid(0U), - m_hdu(NULL), - m_tdu(NULL), - m_ldu1(NULL), - m_pdu(NULL), - m_tsdu(NULL), - m_ldu2(NULL), - m_tdulc(NULL) + m_nac(nac), + m_rxHdu(NULL), + m_rxTdu(NULL), + m_rxLdu1(NULL), + m_rxPdu(NULL), + m_rxTsdu(NULL), + m_rxLdu2(NULL), + m_rxTdulc(NULL), + m_splitNac(false), + m_txHdu(NULL), + m_txTdu(NULL), + m_txLdu1(NULL), + m_txPdu(NULL), + m_txTsdu(NULL), + m_txLdu2(NULL), + m_txTdulc(NULL) { - edac::BCH bch; - - m_hdu = new uint8_t[P25_NID_LENGTH_BYTES]; - m_hdu[0U] = (nac >> 4) & 0xFFU; - m_hdu[1U] = (nac << 4) & 0xF0U; - m_hdu[1U] |= P25_DUID_HDU; - bch.encode(m_hdu); - m_hdu[7U] &= 0xFEU; // Clear the parity bit - - m_tdu = new uint8_t[P25_NID_LENGTH_BYTES]; - m_tdu[0U] = (nac >> 4) & 0xFFU; - m_tdu[1U] = (nac << 4) & 0xF0U; - m_tdu[1U] |= P25_DUID_TDU; - bch.encode(m_tdu); - m_tdu[7U] &= 0xFEU; // Clear the parity bit - - m_ldu1 = new uint8_t[P25_NID_LENGTH_BYTES]; - m_ldu1[0U] = (nac >> 4) & 0xFFU; - m_ldu1[1U] = (nac << 4) & 0xF0U; - m_ldu1[1U] |= P25_DUID_LDU1; - bch.encode(m_ldu1); - m_ldu1[7U] |= 0x01U; // Set the parity bit - - m_pdu = new uint8_t[P25_NID_LENGTH_BYTES]; - m_pdu[0U] = (nac >> 4) & 0xFFU; - m_pdu[1U] = (nac << 4) & 0xF0U; - m_pdu[1U] |= P25_DUID_PDU; - bch.encode(m_pdu); - m_pdu[7U] &= 0xFEU; // Clear the parity bit - - m_tsdu = new uint8_t[P25_NID_LENGTH_BYTES]; - m_tsdu[0U] = (nac >> 4) & 0xFFU; - m_tsdu[1U] = (nac << 4) & 0xF0U; - m_tsdu[1U] |= P25_DUID_TSDU; - bch.encode(m_tsdu); - m_tsdu[7U] &= 0xFEU; // Clear the parity bit - - m_ldu2 = new uint8_t[P25_NID_LENGTH_BYTES]; - m_ldu2[0U] = (nac >> 4) & 0xFFU; - m_ldu2[1U] = (nac << 4) & 0xF0U; - m_ldu2[1U] |= P25_DUID_LDU2; - bch.encode(m_ldu2); - m_ldu2[7U] |= 0x01U; // Set the parity bit - - m_tdulc = new uint8_t[P25_NID_LENGTH_BYTES]; - m_tdulc[0U] = (nac >> 4) & 0xFFU; - m_tdulc[1U] = (nac << 4) & 0xF0U; - m_tdulc[1U] |= P25_DUID_TDULC; - bch.encode(m_tdulc); - m_tdulc[7U] &= 0xFEU; // Clear the parity bit + createRxNID(nac); } /// @@ -119,13 +79,23 @@ NID::NID(uint32_t nac) : /// NID::~NID() { - delete[] m_hdu; - delete[] m_tdu; - delete[] m_ldu1; - delete[] m_pdu; - delete[] m_tsdu; - delete[] m_ldu2; - delete[] m_tdulc; + delete[] m_rxHdu; + delete[] m_rxTdu; + delete[] m_rxLdu1; + delete[] m_rxPdu; + delete[] m_rxTsdu; + delete[] m_rxLdu2; + delete[] m_rxTdulc; + + if (m_splitNac) { + delete[] m_txHdu; + delete[] m_txTdu; + delete[] m_txLdu1; + delete[] m_txPdu; + delete[] m_txTsdu; + delete[] m_txLdu2; + delete[] m_txTdulc; + } } /// @@ -140,43 +110,43 @@ bool NID::decode(const uint8_t* data) uint8_t nid[P25_NID_LENGTH_BYTES]; P25Utils::decode(data, nid, 48U, 114U); - uint32_t errs = P25Utils::compare(nid, m_ldu1, P25_NID_LENGTH_BYTES); + uint32_t errs = P25Utils::compare(nid, m_rxLdu1, P25_NID_LENGTH_BYTES); if (errs < MAX_NID_ERRS) { m_duid = P25_DUID_LDU1; return true; } - errs = P25Utils::compare(nid, m_ldu2, P25_NID_LENGTH_BYTES); + errs = P25Utils::compare(nid, m_rxLdu2, P25_NID_LENGTH_BYTES); if (errs < MAX_NID_ERRS) { m_duid = P25_DUID_LDU2; return true; } - errs = P25Utils::compare(nid, m_tdu, P25_NID_LENGTH_BYTES); + errs = P25Utils::compare(nid, m_rxTdu, P25_NID_LENGTH_BYTES); if (errs < MAX_NID_ERRS) { m_duid = P25_DUID_TDU; return true; } - errs = P25Utils::compare(nid, m_tdulc, P25_NID_LENGTH_BYTES); + errs = P25Utils::compare(nid, m_rxTdulc, P25_NID_LENGTH_BYTES); if (errs < MAX_NID_ERRS) { m_duid = P25_DUID_TDULC; return true; } - errs = P25Utils::compare(nid, m_pdu, P25_NID_LENGTH_BYTES); + errs = P25Utils::compare(nid, m_rxPdu, P25_NID_LENGTH_BYTES); if (errs < MAX_NID_ERRS) { m_duid = P25_DUID_PDU; return true; } - errs = P25Utils::compare(nid, m_tsdu, P25_NID_LENGTH_BYTES); + errs = P25Utils::compare(nid, m_rxTsdu, P25_NID_LENGTH_BYTES); if (errs < MAX_NID_ERRS) { m_duid = P25_DUID_TSDU; return true; } - errs = P25Utils::compare(nid, m_hdu, P25_NID_LENGTH_BYTES); + errs = P25Utils::compare(nid, m_rxHdu, P25_NID_LENGTH_BYTES); if (errs < MAX_NID_ERRS) { m_duid = P25_DUID_HDU; return true; @@ -194,29 +164,191 @@ void NID::encode(uint8_t* data, uint8_t duid) const { assert(data != NULL); - switch (duid) { - case P25_DUID_HDU: - P25Utils::encode(m_hdu, data, 48U, 114U); - break; - case P25_DUID_TDU: - P25Utils::encode(m_tdu, data, 48U, 114U); - break; - case P25_DUID_LDU1: - P25Utils::encode(m_ldu1, data, 48U, 114U); - break; - case P25_DUID_PDU: - P25Utils::encode(m_pdu, data, 48U, 114U); - break; - case P25_DUID_TSDU: - P25Utils::encode(m_tsdu, data, 48U, 114U); - break; - case P25_DUID_LDU2: - P25Utils::encode(m_ldu2, data, 48U, 114U); - break; - case P25_DUID_TDULC: - P25Utils::encode(m_tdulc, data, 48U, 114U); - break; - default: - break; + if (m_splitNac) { + switch (duid) { + case P25_DUID_HDU: + P25Utils::encode(m_txHdu, data, 48U, 114U); + break; + case P25_DUID_TDU: + P25Utils::encode(m_txTdu, data, 48U, 114U); + break; + case P25_DUID_LDU1: + P25Utils::encode(m_txLdu1, data, 48U, 114U); + break; + case P25_DUID_PDU: + P25Utils::encode(m_txPdu, data, 48U, 114U); + break; + case P25_DUID_TSDU: + P25Utils::encode(m_txTsdu, data, 48U, 114U); + break; + case P25_DUID_LDU2: + P25Utils::encode(m_txLdu2, data, 48U, 114U); + break; + case P25_DUID_TDULC: + P25Utils::encode(m_txTdulc, data, 48U, 114U); + break; + default: + break; + } + } + else { + switch (duid) { + case P25_DUID_HDU: + P25Utils::encode(m_rxHdu, data, 48U, 114U); + break; + case P25_DUID_TDU: + P25Utils::encode(m_rxTdu, data, 48U, 114U); + break; + case P25_DUID_LDU1: + P25Utils::encode(m_rxLdu1, data, 48U, 114U); + break; + case P25_DUID_PDU: + P25Utils::encode(m_rxPdu, data, 48U, 114U); + break; + case P25_DUID_TSDU: + P25Utils::encode(m_rxTsdu, data, 48U, 114U); + break; + case P25_DUID_LDU2: + P25Utils::encode(m_rxLdu2, data, 48U, 114U); + break; + case P25_DUID_TDULC: + P25Utils::encode(m_rxTdulc, data, 48U, 114U); + break; + default: + break; + } + } +} + +/// +/// Helper to configure a separate Tx NAC. +/// +/// +void NID::setTxNAC(uint32_t nac) +{ + if (nac == m_nac) { + return; } + + m_splitNac = true; + createTxNID(nac); +} + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- +/// +/// +/// +/// +void NID::createRxNID(uint32_t nac) +{ + edac::BCH bch; + + m_rxHdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_rxHdu[0U] = (nac >> 4) & 0xFFU; + m_rxHdu[1U] = (nac << 4) & 0xF0U; + m_rxHdu[1U] |= P25_DUID_HDU; + bch.encode(m_rxHdu); + m_rxHdu[7U] &= 0xFEU; // Clear the parity bit + + m_rxTdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_rxTdu[0U] = (nac >> 4) & 0xFFU; + m_rxTdu[1U] = (nac << 4) & 0xF0U; + m_rxTdu[1U] |= P25_DUID_TDU; + bch.encode(m_rxTdu); + m_rxTdu[7U] &= 0xFEU; // Clear the parity bit + + m_rxLdu1 = new uint8_t[P25_NID_LENGTH_BYTES]; + m_rxLdu1[0U] = (nac >> 4) & 0xFFU; + m_rxLdu1[1U] = (nac << 4) & 0xF0U; + m_rxLdu1[1U] |= P25_DUID_LDU1; + bch.encode(m_rxLdu1); + m_rxLdu1[7U] |= 0x01U; // Set the parity bit + + m_rxPdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_rxPdu[0U] = (nac >> 4) & 0xFFU; + m_rxPdu[1U] = (nac << 4) & 0xF0U; + m_rxPdu[1U] |= P25_DUID_PDU; + bch.encode(m_rxPdu); + m_rxPdu[7U] &= 0xFEU; // Clear the parity bit + + m_rxTsdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_rxTsdu[0U] = (nac >> 4) & 0xFFU; + m_rxTsdu[1U] = (nac << 4) & 0xF0U; + m_rxTsdu[1U] |= P25_DUID_TSDU; + bch.encode(m_rxTsdu); + m_rxTsdu[7U] &= 0xFEU; // Clear the parity bit + + m_rxLdu2 = new uint8_t[P25_NID_LENGTH_BYTES]; + m_rxLdu2[0U] = (nac >> 4) & 0xFFU; + m_rxLdu2[1U] = (nac << 4) & 0xF0U; + m_rxLdu2[1U] |= P25_DUID_LDU2; + bch.encode(m_rxLdu2); + m_rxLdu2[7U] |= 0x01U; // Set the parity bit + + m_rxTdulc = new uint8_t[P25_NID_LENGTH_BYTES]; + m_rxTdulc[0U] = (nac >> 4) & 0xFFU; + m_rxTdulc[1U] = (nac << 4) & 0xF0U; + m_rxTdulc[1U] |= P25_DUID_TDULC; + bch.encode(m_rxTdulc); + m_rxTdulc[7U] &= 0xFEU; // Clear the parity bit +} + +/// +/// +/// +/// +void NID::createTxNID(uint32_t nac) +{ + edac::BCH bch; + + m_txHdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_txHdu[0U] = (nac >> 4) & 0xFFU; + m_txHdu[1U] = (nac << 4) & 0xF0U; + m_txHdu[1U] |= P25_DUID_HDU; + bch.encode(m_txHdu); + m_txHdu[7U] &= 0xFEU; // Clear the parity bit + + m_txTdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_txTdu[0U] = (nac >> 4) & 0xFFU; + m_txTdu[1U] = (nac << 4) & 0xF0U; + m_txTdu[1U] |= P25_DUID_TDU; + bch.encode(m_txTdu); + m_txTdu[7U] &= 0xFEU; // Clear the parity bit + + m_txLdu1 = new uint8_t[P25_NID_LENGTH_BYTES]; + m_txLdu1[0U] = (nac >> 4) & 0xFFU; + m_txLdu1[1U] = (nac << 4) & 0xF0U; + m_txLdu1[1U] |= P25_DUID_LDU1; + bch.encode(m_txLdu1); + m_txLdu1[7U] |= 0x01U; // Set the parity bit + + m_txPdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_txPdu[0U] = (nac >> 4) & 0xFFU; + m_txPdu[1U] = (nac << 4) & 0xF0U; + m_txPdu[1U] |= P25_DUID_PDU; + bch.encode(m_txPdu); + m_txPdu[7U] &= 0xFEU; // Clear the parity bit + + m_txTsdu = new uint8_t[P25_NID_LENGTH_BYTES]; + m_txTsdu[0U] = (nac >> 4) & 0xFFU; + m_txTsdu[1U] = (nac << 4) & 0xF0U; + m_txTsdu[1U] |= P25_DUID_TSDU; + bch.encode(m_txTsdu); + m_txTsdu[7U] &= 0xFEU; // Clear the parity bit + + m_txLdu2 = new uint8_t[P25_NID_LENGTH_BYTES]; + m_txLdu2[0U] = (nac >> 4) & 0xFFU; + m_txLdu2[1U] = (nac << 4) & 0xF0U; + m_txLdu2[1U] |= P25_DUID_LDU2; + bch.encode(m_txLdu2); + m_txLdu2[7U] |= 0x01U; // Set the parity bit + + m_txTdulc = new uint8_t[P25_NID_LENGTH_BYTES]; + m_txTdulc[0U] = (nac >> 4) & 0xFFU; + m_txTdulc[1U] = (nac << 4) & 0xF0U; + m_txTdulc[1U] |= P25_DUID_TDULC; + bch.encode(m_txTdulc); + m_txTdulc[7U] &= 0xFEU; // Clear the parity bit } diff --git a/p25/NID.h b/p25/NID.h index 6b630eea..b2045a84 100644 --- a/p25/NID.h +++ b/p25/NID.h @@ -12,7 +12,7 @@ // /* * Copyright (C) 2016 by Jonathan Naylor G4KLX -* Copyright (C) 2017 by Bryan Biedenkapp N2PLL +* Copyright (C) 2017,2022 by Bryan Biedenkapp N2PLL * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,18 +52,38 @@ namespace p25 /// Encodes P25 network identifier data. void encode(uint8_t* data, uint8_t duid) const; + /// Helper to configure a separate Tx NAC. + void setTxNAC(uint32_t nac); + public: /// Data unit ID. __READONLY_PROPERTY(uint8_t, duid, DUID); private: - uint8_t* m_hdu; - uint8_t* m_tdu; - uint8_t* m_ldu1; - uint8_t* m_pdu; - uint8_t* m_tsdu; - uint8_t* m_ldu2; - uint8_t* m_tdulc; + uint32_t m_nac; + + uint8_t* m_rxHdu; + uint8_t* m_rxTdu; + uint8_t* m_rxLdu1; + uint8_t* m_rxPdu; + uint8_t* m_rxTsdu; + uint8_t* m_rxLdu2; + uint8_t* m_rxTdulc; + + bool m_splitNac; + + uint8_t* m_txHdu; + uint8_t* m_txTdu; + uint8_t* m_txLdu1; + uint8_t* m_txPdu; + uint8_t* m_txTsdu; + uint8_t* m_txLdu2; + uint8_t* m_txTdulc; + + /// + void createRxNID(uint32_t nac); + /// + void createTxNID(uint32_t nac); }; } // namespace p25