From eacbc27143d13a60992ad6fb93ba43c3abc7f84a Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 22 Jun 2024 16:50:33 -0400 Subject: [PATCH] add marking of whether an inbound CAC is long or short; fix issue with short CAC not properly building a puncturing buffer (even tho short CAC doesn't do puncturing, its needed for NXDN convolution); correct CAC getData() return; remove deprecated code causing decoding offsets to be wrong resulting in invalid RCCHs; --- src/common/nxdn/channel/CAC.cpp | 54 +++++++++++++++++------ src/common/nxdn/channel/CAC.h | 2 + src/common/nxdn/channel/FACCH1.cpp | 2 +- src/common/nxdn/channel/SACCH.cpp | 2 +- src/common/nxdn/channel/UDCH.cpp | 2 +- src/common/nxdn/lc/rcch/RCCHFactory.cpp | 8 ---- src/host/nxdn/Control.cpp | 22 +++------ src/host/nxdn/packet/ControlSignaling.cpp | 9 ++-- 8 files changed, 56 insertions(+), 45 deletions(-) diff --git a/src/common/nxdn/channel/CAC.cpp b/src/common/nxdn/channel/CAC.cpp index 766d3770..bd0eeb36 100644 --- a/src/common/nxdn/channel/CAC.cpp +++ b/src/common/nxdn/channel/CAC.cpp @@ -120,6 +120,7 @@ CAC::CAC() : CAC::CAC(const CAC& data) : m_ran(0U), m_structure(ChStructure::SR_RCCH_SINGLE), + m_longInbound(false), m_idleBusy(true), m_txContinuous(false), m_receive(true), @@ -150,6 +151,8 @@ CAC& CAC::operator=(const CAC& data) m_ran = m_data[0U] & 0x3FU; m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U); + m_longInbound = data.m_longInbound; + m_idleBusy = data.m_idleBusy; m_txContinuous = data.m_txContinuous; m_receive = data.m_receive; @@ -185,9 +188,11 @@ bool CAC::decode(const uint8_t* data, bool longInbound) #endif if (longInbound) { + m_longInbound = longInbound; + // depuncture - uint8_t puncture[324U]; - ::memset(puncture, 0x00U, 324U); + uint8_t puncture[322U]; + ::memset(puncture, 0x00U, 322U); uint32_t n = 0U, index = 0U; for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) { @@ -214,7 +219,7 @@ bool CAC::decode(const uint8_t* data, bool longInbound) uint8_t s1 = puncture[n++]; if (!conv.decode(s0, s1)) { - LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution"); + LogError(LOG_NXDN, "CAC::decode(longInbound), failed to decode convolution, i = %u, n = %u", i); return false; } } @@ -222,13 +227,13 @@ bool CAC::decode(const uint8_t* data, bool longInbound) conv.chainback(m_data, NXDN_CAC_LONG_CRC_LENGTH_BITS); #if DEBUG_NXDN_CAC - Utils::dump(2U, "Decoded CAC", m_data, (NXDN_CAC_LONG_CRC_LENGTH_BITS / 8U) + 1U); + Utils::dump(2U, "Decoded Long CAC", m_data, (NXDN_CAC_LONG_CRC_LENGTH_BITS / 8U) + 1U); #endif // check CRC-16 bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_LONG_LENGTH_BITS); if (!ret) { - LogError(LOG_NXDN, "CAC::decode(), failed CRC-6 check"); + LogError(LOG_NXDN, "CAC::decode(longInbound), failed CRC-16 check"); return false; } @@ -248,17 +253,31 @@ bool CAC::decode(const uint8_t* data, bool longInbound) m_rxCRC = (crc[0U] << 8) | (crc[1U] << 0); } else { + // generate pass-thru bit buffer (no puncturing for short CAC) + uint8_t pass[322U]; + ::memset(pass, 0x00U, 322U); + + uint32_t n = 0U; + for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) { + bool b = READ_BIT(buffer, i); + pass[n++] = b ? 2U : 0U; + } + + for (uint32_t i = 0U; i < 8U; i++) { + pass[n++] = 0U; + } + // decode convolution edac::Convolution conv; conv.start(); - uint32_t n = 0U; + n = 0U; for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_CRC_LENGTH_BITS + 4U); i++) { - uint8_t s0 = buffer[n++]; - uint8_t s1 = buffer[n++]; + uint8_t s0 = pass[n++]; + uint8_t s1 = pass[n++]; if (!conv.decode(s0, s1)) { - LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution"); + LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution, i = %u, n = %u", i); return false; } } @@ -272,7 +291,7 @@ bool CAC::decode(const uint8_t* data, bool longInbound) // check CRC-16 bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_SHORT_LENGTH_BITS); if (!ret) { - LogError(LOG_NXDN, "CAC::decode(), failed CRC-6 check"); + LogError(LOG_NXDN, "CAC::decode(), failed CRC-16 check"); return false; } @@ -390,9 +409,16 @@ void CAC::getData(uint8_t* data) const assert(data != nullptr); uint32_t offset = 8U; - for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_LENGTH_BITS - 10); i++, offset++) { - bool b = READ_BIT(m_data, offset); - WRITE_BIT(data, i, b); + if (m_longInbound) { + for (uint32_t i = 0U; i < (NXDN_CAC_LONG_LENGTH_BITS - 8U); i++, offset++) { + bool b = READ_BIT(m_data, offset); + WRITE_BIT(data, i, b); + } + } else { + for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_LENGTH_BITS - 10U); i++, offset++) { + bool b = READ_BIT(m_data, offset); + WRITE_BIT(data, i, b); + } } } @@ -429,6 +455,8 @@ void CAC::copy(const CAC& data) m_ran = m_data[0U] & 0x3FU; m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U); + m_longInbound = data.m_longInbound; + m_idleBusy = data.m_idleBusy; m_txContinuous = data.m_txContinuous; m_receive = data.m_receive; diff --git a/src/common/nxdn/channel/CAC.h b/src/common/nxdn/channel/CAC.h index 1a53f99b..439a4358 100644 --- a/src/common/nxdn/channel/CAC.h +++ b/src/common/nxdn/channel/CAC.h @@ -53,6 +53,8 @@ namespace nxdn __PROPERTY(uint8_t, ran, RAN); /// __PROPERTY(defines::ChStructure::E, structure, Structure); + /// + __PROPERTY(bool, longInbound, LongInbound); /** Collision Control Field */ /// Idle/Busy. diff --git a/src/common/nxdn/channel/FACCH1.cpp b/src/common/nxdn/channel/FACCH1.cpp index a624c237..b5d92814 100644 --- a/src/common/nxdn/channel/FACCH1.cpp +++ b/src/common/nxdn/channel/FACCH1.cpp @@ -143,7 +143,7 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset) uint8_t s1 = puncture[n++]; if (!conv.decode(s0, s1)) { - LogError(LOG_NXDN, "FACCH1::decode(), failed to decode convolution"); + LogError(LOG_NXDN, "FACCH1::decode(), failed to decode convolution, i = %u, n = %u", i); return false; } } diff --git a/src/common/nxdn/channel/SACCH.cpp b/src/common/nxdn/channel/SACCH.cpp index dc7cb4a9..24fa77a9 100644 --- a/src/common/nxdn/channel/SACCH.cpp +++ b/src/common/nxdn/channel/SACCH.cpp @@ -145,7 +145,7 @@ bool SACCH::decode(const uint8_t* data) uint8_t s1 = puncture[n++]; if (!conv.decode(s0, s1)) { - LogError(LOG_NXDN, "SACCH::decode(), failed to decode convolution"); + LogError(LOG_NXDN, "SACCH::decode(), failed to decode convolution, i = %u, n = %u", i); return false; } } diff --git a/src/common/nxdn/channel/UDCH.cpp b/src/common/nxdn/channel/UDCH.cpp index d295352d..88e34fab 100644 --- a/src/common/nxdn/channel/UDCH.cpp +++ b/src/common/nxdn/channel/UDCH.cpp @@ -169,7 +169,7 @@ bool UDCH::decode(const uint8_t* data) uint8_t s1 = puncture[n++]; if (!conv.decode(s0, s1)) { - LogError(LOG_NXDN, "UDCH::decode(), failed to decode convolution"); + LogError(LOG_NXDN, "UDCH::decode(), failed to decode convolution, i = %u, n = %u", i); return false; } } diff --git a/src/common/nxdn/lc/rcch/RCCHFactory.cpp b/src/common/nxdn/lc/rcch/RCCHFactory.cpp index 8b62828c..7a9d2dd6 100644 --- a/src/common/nxdn/lc/rcch/RCCHFactory.cpp +++ b/src/common/nxdn/lc/rcch/RCCHFactory.cpp @@ -47,14 +47,6 @@ std::unique_ptr RCCHFactory::createRCCH(const uint8_t* data, uint32_t leng { assert(data != nullptr); - uint8_t rcch[22U]; - ::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U); - - for (uint32_t i = 0U; i < length; i++, offset++) { - bool b = READ_BIT(data, offset); - WRITE_BIT(rcch, i, b); - } - uint8_t messageType = data[0U] & 0x3FU; // Message Type // message type opcodes diff --git a/src/host/nxdn/Control.cpp b/src/host/nxdn/Control.cpp index 0ce729aa..93f0bf13 100644 --- a/src/host/nxdn/Control.cpp +++ b/src/host/nxdn/Control.cpp @@ -38,7 +38,7 @@ using namespace nxdn::packet; // Constants // --------------------------------------------------------------------------- -const uint8_t MAX_SYNC_BYTES_ERRS = 0U; +const uint8_t MAX_SYNC_BYTES_ERRS = 3U; const uint8_t SCRAMBLER[] = { 0x00U, 0x00U, 0x00U, 0x82U, 0xA0U, 0x88U, 0x8AU, 0x00U, 0xA2U, 0xA8U, 0x82U, 0x8AU, 0x82U, 0x02U, @@ -428,6 +428,10 @@ bool Control::processFrame(uint8_t* data, uint32_t len) for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++) errs += Utils::countBits8(syncBytes[i] ^ NXDN_FSW_BYTES[i]); + // silently ignore frames with errors greater then 2 times the maximum + if (errs > MAX_SYNC_BYTES_ERRS * 2U) + return false; + if (errs >= MAX_SYNC_BYTES_ERRS) { LogWarning(LOG_RF, "NXDN, possible sync word rejected, errs = %u, sync word = %02X %02X %02X", errs, syncBytes[0U], syncBytes[1U], syncBytes[2U]); @@ -470,15 +474,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len) LogDebug(LOG_RF, "NXDN, valid LICH, rfState = %u, netState = %u, rfct = %u, fct = %u", m_rfState, m_netState, rfct, fct); } - // are we interrupting a running CC? - if (m_ccRunning) { - if ((fct != FuncChannelType::CAC_INBOUND_SHORT) || (fct != FuncChannelType::CAC_INBOUND_LONG)) { - m_ccHalted = true; - } - } - bool ret = false; - if (rfct == RFChannelType::RCCH) { ret = m_control->process(fct, option, data, len); } @@ -493,14 +489,6 @@ bool Control::processFrame(uint8_t* data, uint32_t len) ret = m_voice->process(fct, option, data, len); break; } - - if (m_ccRunning) { - m_ccHalted = false; - } - } else { - if (m_ccRunning) { - m_ccHalted = false; - } } return ret; diff --git a/src/host/nxdn/packet/ControlSignaling.cpp b/src/host/nxdn/packet/ControlSignaling.cpp index 292bdea3..ba3e5527 100644 --- a/src/host/nxdn/packet/ControlSignaling.cpp +++ b/src/host/nxdn/packet/ControlSignaling.cpp @@ -138,8 +138,9 @@ bool ControlSignaling::process(FuncChannelType::E fct, ChOption::E option, uint8 channel::CAC cac; bool validCAC = cac.decode(data + 2U, (fct == FuncChannelType::CAC_INBOUND_LONG)); - if (m_nxdn->m_rfState == RS_RF_LISTENING && !validCAC) + if (m_nxdn->m_rfState == RS_RF_LISTENING && !validCAC) { return false; + } if (validCAC) { uint8_t ran = cac.getRAN(); @@ -367,7 +368,7 @@ void ControlSignaling::writeRF_Message(RCCH* rcch, bool noNetwork, bool imm) channel::LICH lich; lich.setRFCT(RFChannelType::RCCH); lich.setFCT(FuncChannelType::CAC_OUTBOUND); - lich.setOption(ChOption::DATA_COMMON); + lich.setOption(ChOption::DATA_NORMAL); lich.setOutbound(true); lich.encode(data + 2U); @@ -379,7 +380,7 @@ void ControlSignaling::writeRF_Message(RCCH* rcch, bool noNetwork, bool imm) // generate the CAC channel::CAC cac; cac.setRAN(m_nxdn->m_ran); - cac.setStructure(ChStructure::SR_SINGLE); + cac.setStructure(ChStructure::SR_RCCH_SINGLE); cac.setData(buffer); cac.encode(data + 2U); @@ -592,7 +593,7 @@ bool ControlSignaling::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uin req["dstId"].set(dstId); int ret = RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(), - HTTP_PUT, PUT_PERMIT_TG, req, voiceChData.ssl(), REST_QUICK_WAIT, m_nxdn->m_debug); + HTTP_PUT, PUT_PERMIT_TG, req, voiceChData.ssl(), REST_QUICK_WAIT / 2, m_nxdn->m_debug); if (ret != network::rest::http::HTTPPayload::StatusType::OK) { ::LogError((net) ? LOG_NET : LOG_RF, "NXDN, %s, failed to permit TG for use, chNo = %u", rcch->toString().c_str(), chNo); m_nxdn->m_affiliations.releaseGrant(dstId, false);