From e931d8d26ec64b139117c57ffdf1e73c40dcf29e Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 5 Mar 2022 14:40:55 -0500 Subject: [PATCH] remove standalone P25 DataRspHeader class and merge it into DataHeader; further enhance the P25 DataHeader to better match the TIA spec; clean up some code and variable references; --- DVMHost.vcxproj | 2 - DVMHost.vcxproj.filters | 6 - Makefile | 1 - Makefile.arm | 1 - Makefile.rpi-arm | 1 - edac/CRC.cpp | 8 +- edac/CRC.h | 2 +- host/calibrate/HostCal.cpp | 9 +- p25/DataPacket.cpp | 257 +++++++++++++++++-------------------- p25/DataPacket.h | 5 +- p25/data/DataBlock.h | 1 + p25/data/DataHeader.cpp | 132 +++++++++++++------ p25/data/DataHeader.h | 28 +++- p25/data/DataRspHeader.cpp | 198 ---------------------------- p25/data/DataRspHeader.h | 94 -------------- 15 files changed, 244 insertions(+), 501 deletions(-) delete mode 100644 p25/data/DataRspHeader.cpp delete mode 100644 p25/data/DataRspHeader.h diff --git a/DVMHost.vcxproj b/DVMHost.vcxproj index 24635be7..11a50ad2 100644 --- a/DVMHost.vcxproj +++ b/DVMHost.vcxproj @@ -210,7 +210,6 @@ - @@ -290,7 +289,6 @@ - diff --git a/DVMHost.vcxproj.filters b/DVMHost.vcxproj.filters index 8feda304..5917e50d 100644 --- a/DVMHost.vcxproj.filters +++ b/DVMHost.vcxproj.filters @@ -338,9 +338,6 @@ Header Files\network - - Header Files\p25\data - Header Files\dmr @@ -568,9 +565,6 @@ Source Files\network - - Source Files\p25\data - Source Files\dmr diff --git a/Makefile b/Makefile index 642ce6f4..230af041 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,6 @@ OBJECTS = \ p25/acl/AccessControl.o \ p25/data/DataBlock.o \ p25/data/DataHeader.o \ - p25/data/DataRspHeader.o \ p25/data/LowSpeedData.o \ p25/dfsi/LC.o \ p25/edac/Trellis.o \ diff --git a/Makefile.arm b/Makefile.arm index 4f00fbf5..9d114099 100644 --- a/Makefile.arm +++ b/Makefile.arm @@ -41,7 +41,6 @@ OBJECTS = \ p25/acl/AccessControl.o \ p25/data/DataBlock.o \ p25/data/DataHeader.o \ - p25/data/DataRspHeader.o \ p25/data/LowSpeedData.o \ p25/dfsi/LC.o \ p25/edac/Trellis.o \ diff --git a/Makefile.rpi-arm b/Makefile.rpi-arm index 6b5bb3fd..0c7bfb1a 100644 --- a/Makefile.rpi-arm +++ b/Makefile.rpi-arm @@ -42,7 +42,6 @@ OBJECTS = \ p25/acl/AccessControl.o \ p25/data/DataBlock.o \ p25/data/DataHeader.o \ - p25/data/DataRspHeader.o \ p25/data/LowSpeedData.o \ p25/dfsi/LC.o \ p25/edac/Trellis.o \ diff --git a/edac/CRC.cpp b/edac/CRC.cpp index 294ba855..905da1e0 100644 --- a/edac/CRC.cpp +++ b/edac/CRC.cpp @@ -449,15 +449,15 @@ uint8_t CRC::crc8(const uint8_t *in, uint32_t length) /// Generate 9-bit CRC. /// /// Input byte array. -/// Length of byte array in bits. +/// Length of byte array in bits. /// Calculated 9-bit CRC value. -uint16_t CRC::crc9(const uint8_t* in, uint32_t bitlen) +uint16_t CRC::crc9(const uint8_t* in, uint32_t bitLength) { assert(in != NULL); uint16_t crc = 0x00U; - for (uint32_t i = 0; i < bitlen; i++) { + for (uint32_t i = 0; i < bitLength; i++) { bool b = READ_BIT(in, i); if (b) { if (i < 7U) { @@ -473,7 +473,7 @@ uint16_t CRC::crc9(const uint8_t* in, uint32_t bitlen) crc ^= 0x1FFU; #if DEBUG_CRC - LogDebug(LOG_HOST, "CRC:crc9(), crc = $%03X, bitlen = %u", crc, bitlen); + LogDebug(LOG_HOST, "CRC:crc9(), crc = $%03X, bitlen = %u", crc, bitLength); #endif return crc; diff --git a/edac/CRC.h b/edac/CRC.h index af8dfe50..660f0c5a 100644 --- a/edac/CRC.h +++ b/edac/CRC.h @@ -66,7 +66,7 @@ namespace edac static uint8_t crc8(const uint8_t* in, uint32_t length); /// Generate 9-bit CRC. - static uint16_t crc9(const uint8_t* in, uint32_t bitlen); + static uint16_t crc9(const uint8_t* in, uint32_t bitLength); }; } // namespace edac diff --git a/host/calibrate/HostCal.cpp b/host/calibrate/HostCal.cpp index 780c0e5e..4036369b 100644 --- a/host/calibrate/HostCal.cpp +++ b/host/calibrate/HostCal.cpp @@ -13,7 +13,7 @@ /* * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2017,2018 by Andy Uribe CA6JAU -* Copyright (C) 2017-2021 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 @@ -1741,9 +1741,10 @@ void HostCal::processP25BER(const uint8_t* buffer) Utils::dump(1U, "Unfixable PDU Data", rfPDU + P25_SYNC_LENGTH_BYTES + P25_NID_LENGTH_BYTES, P25_PDU_HEADER_LENGTH_BYTES); } else { - LogMessage(LOG_CAL, P25_PDU_STR ", fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u", - dataHeader.getFormat(), dataHeader.getSAP(), dataHeader.getFullMessage(), dataHeader.getBlocksToFollow(), dataHeader.getPadCount(), - dataHeader.getN(), dataHeader.getSeqNo()); + LogMessage(LOG_CAL, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, mfId = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, lastFragment = %u, hdrOffset = %u", + dataHeader.getAckNeeded(), dataHeader.getOutbound(), dataHeader.getFormat(), dataHeader.getMFId(), dataHeader.getSAP(), dataHeader.getFullMessage(), + dataHeader.getBlocksToFollow(), dataHeader.getPadCount(), dataHeader.getNs(), dataHeader.getFSN(), dataHeader.getLastFragment(), + dataHeader.getHeaderOffset()); } delete[] rfPDU; diff --git a/p25/DataPacket.cpp b/p25/DataPacket.cpp index 7c6da2e8..65948bd0 100644 --- a/p25/DataPacket.cpp +++ b/p25/DataPacket.cpp @@ -96,7 +96,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len) m_rfDataBlockCnt = 0U; m_rfPDUCount = 0U; m_rfPDUBits = 0U; - + + ::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U); + m_p25->m_rfState = RS_RF_DATA; ::memset(m_pduUserData, 0x00U, P25_MAX_PDU_COUNT * P25_PDU_CONFIRMED_LENGTH_BYTES + 2U); @@ -131,9 +133,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len) } if (m_verbose) { - LogMessage(LOG_RF, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, hdrOffset = %u", - m_rfDataHeader.getAckNeeded(), m_rfDataHeader.getOutbound(), m_rfDataHeader.getFormat(), m_rfDataHeader.getSAP(), m_rfDataHeader.getFullMessage(), - m_rfDataHeader.getBlocksToFollow(), m_rfDataHeader.getPadCount(), m_rfDataHeader.getN(), m_rfDataHeader.getSeqNo(), + LogMessage(LOG_RF, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, mfId = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, lastFragment = %u, hdrOffset = %u", + m_rfDataHeader.getAckNeeded(), m_rfDataHeader.getOutbound(), m_rfDataHeader.getFormat(), m_rfDataHeader.getMFId(), m_rfDataHeader.getSAP(), m_rfDataHeader.getFullMessage(), + m_rfDataHeader.getBlocksToFollow(), m_rfDataHeader.getPadCount(), m_rfDataHeader.getNs(), m_rfDataHeader.getFSN(), m_rfDataHeader.getLastFragment(), m_rfDataHeader.getHeaderOffset()); } @@ -175,9 +177,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len) } if (m_verbose) { - LogMessage(LOG_RF, P25_PDU_STR ", fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, hdrOffset = %u, llId = %u", - m_rfSecondHeader.getFormat(), m_rfSecondHeader.getSAP(), m_rfSecondHeader.getFullMessage(), - m_rfSecondHeader.getBlocksToFollow(), m_rfSecondHeader.getPadCount(), m_rfSecondHeader.getN(), m_rfSecondHeader.getSeqNo(), + LogMessage(LOG_RF, P25_PDU_STR ", fmt = $%02X, mfId = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, lastFragment = %u, hdrOffset = %u, llId = %u", + m_rfSecondHeader.getFormat(), m_rfSecondHeader.getMFId(), m_rfSecondHeader.getSAP(), m_rfSecondHeader.getFullMessage(), + m_rfSecondHeader.getBlocksToFollow(), m_rfSecondHeader.getPadCount(), m_rfSecondHeader.getNs(), m_rfSecondHeader.getFSN(), m_rfSecondHeader.getLastFragment(), m_rfSecondHeader.getHeaderOffset(), m_rfSecondHeader.getLLId()); } @@ -334,7 +336,7 @@ bool DataPacket::process(uint8_t* data, uint32_t len) LogMessage(LOG_RF, P25_PDU_STR ", repeating PDU, llId = %u", (m_rfUseSecondHeader) ? m_rfSecondHeader.getLLId() : m_rfDataHeader.getLLId()); } - writeRF_PDU(); // re-generate PDU and send it on + writeRF_PDU_Buffered(); // re-generate buffered PDU and send it on } ::ActivityLog("P25", true, "end of RF data transmission"); @@ -607,29 +609,76 @@ void DataPacket::writeNetworkRF(const uint8_t dataType, const uint8_t *data, uin /// /// Helper to write a P25 PDU packet. /// -void DataPacket::writeRF_PDU() +/// +/// +/// +/// This simply takes data packed into m_rfPDU and transmits it. +void DataPacket::writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls) +{ + assert(pdu != NULL); + assert(bitLength > 0U); + + uint8_t data[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U]; + ::memset(data, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U); + + if (m_debug) { + Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", pdu, bitLength / 8U); + } + + // Add the data + uint32_t newBitLength = P25Utils::encode(pdu, data + 2U, bitLength); + uint32_t newByteLength = newBitLength / 8U; + if ((newBitLength % 8U) > 0U) + newByteLength++; + + // Regenerate Sync + Sync::addP25Sync(data + 2U); + + // Regenerate NID + m_p25->m_nid.encode(data + 2U, P25_DUID_PDU); + + // Add busy bits + m_p25->addBusyBits(data + 2U, newBitLength, false, true); + + if (m_p25->m_duplex) { + data[0U] = TAG_DATA; + data[1U] = 0x00U; + m_p25->writeQueueRF(data, newByteLength + 2U); + } + + // add trailing null pad; only if control data isn't being transmitted + if (!m_p25->m_ccRunning && !noNulls) { + m_p25->writeRF_Nulls(); + } +} + +/// +/// Helper to re-write a received P25 PDU packet. +/// +/// This will take buffered received PDU data and repeat it over the air. +void DataPacket::writeRF_PDU_Buffered() { uint32_t bitLength = ((m_rfDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS; - ::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U); - - uint8_t buffer[P25_PDU_FEC_LENGTH_BYTES]; - ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); + uint8_t data[bitLength / 8U]; + ::memset(data, 0x00U, bitLength / 8U); + uint8_t block[P25_PDU_FEC_LENGTH_BYTES]; + ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); uint32_t blocksToFollow = m_rfDataHeader.getBlocksToFollow(); // Generate the PDU header and 1/2 rate Trellis - m_rfDataHeader.encode(buffer); - Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS); + m_rfDataHeader.encode(block); + Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS); offset += P25_PDU_FEC_LENGTH_BITS; // Generate the second PDU header if (m_rfUseSecondHeader) { - ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); + ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); - m_rfSecondHeader.encode(buffer); - Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS); + m_rfSecondHeader.encode(block); + Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS); offset += P25_PDU_FEC_LENGTH_BITS; blocksToFollow--; @@ -642,47 +691,15 @@ void DataPacket::writeRF_PDU() m_rfData[i].setSerialNo(i); m_rfData[i].setData(m_pduUserData + dataOffset); - ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); - m_rfData[i].encode(buffer); - Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS); + ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); + m_rfData[i].encode(block); + Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS); offset += P25_PDU_FEC_LENGTH_BITS; dataOffset += (m_rfDataHeader.getFormat() == PDU_FMT_CONFIRMED) ? P25_PDU_CONFIRMED_DATA_LENGTH_BYTES : P25_PDU_UNCONFIRMED_LENGTH_BYTES; } - if (m_debug) { - Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", m_rfPDU, bitLength / 8U); - } - - uint8_t pdu[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U]; - - // Add the data - uint32_t newBitLength = P25Utils::encode(m_rfPDU, pdu + 2U, bitLength); - uint32_t newByteLength = newBitLength / 8U; - if ((newBitLength % 8U) > 0U) - newByteLength++; - - // Regenerate Sync - Sync::addP25Sync(pdu + 2U); - - // Regenerate NID - m_p25->m_nid.encode(pdu + 2U, P25_DUID_PDU); - - // Add busy bits - m_p25->addBusyBits(pdu + 2U, newBitLength, false, true); - - ::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U); - - if (m_p25->m_duplex) { - pdu[0U] = TAG_DATA; - pdu[1U] = 0x00U; - m_p25->writeQueueRF(pdu, newByteLength + 2U); - } - - // add trailing null pad; only if control data isn't being transmitted - if (!m_p25->m_ccRunning) { - m_p25->writeRF_Nulls(); - } + writeRF_PDU(data, bitLength); } /// @@ -696,85 +713,62 @@ void DataPacket::writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong6 if ((regType != PDU_REG_TYPE_RSP_ACCPT) && (regType != PDU_REG_TYPE_RSP_DENY)) return; - uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS); // + P25_PREAMBLE_LENGTH_BITS; + uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS; - uint8_t buffer[P25_PDU_FEC_LENGTH_BYTES]; - ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); + uint8_t data[bitLength / 8U]; + ::memset(data, 0x00U, bitLength / 8U); + uint8_t block[P25_PDU_FEC_LENGTH_BYTES]; + ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); - DataRspHeader rspHeader = DataRspHeader(); + DataHeader rspHeader = DataHeader(); + rspHeader.setFormat(PDU_FMT_RSP); rspHeader.setOutbound(true); rspHeader.setClass(PDU_ACK_CLASS_ACK); rspHeader.setType(PDU_ACK_TYPE_ACK); + rspHeader.setStatus(m_rfDataHeader.getNs()); rspHeader.setLLId(llId); if (m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR) { rspHeader.setSrcLLId(P25_WUID_FNE); - rspHeader.setExtended(true); + rspHeader.setFullMessage(true); } else { - rspHeader.setExtended(false); + rspHeader.setFullMessage(false); } rspHeader.setBlocksToFollow(1U); // Generate the PDU header and 1/2 rate Trellis - rspHeader.encode(buffer); - Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS); + rspHeader.encode(block); + Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS); offset += P25_PDU_FEC_LENGTH_BITS; // build registration response data - ::memset(buffer, 0x00U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); + ::memset(block, 0x00U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); - buffer[0U] = (regType << 4); // Registration Type & Options - buffer[1U] = (llId >> 16) & 0xFFU; // Logical Link ID - buffer[2U] = (llId >> 8) & 0xFFU; - buffer[3U] = (llId >> 0) & 0xFFU; + block[0U] = (regType << 4); // Registration Type & Options + block[1U] = (llId >> 16) & 0xFFU; // Logical Link ID + block[2U] = (llId >> 8) & 0xFFU; + block[3U] = (llId >> 0) & 0xFFU; if (regType == PDU_REG_TYPE_RSP_ACCPT) { - buffer[8U] = (ipAddr >> 24) & 0xFFU; // IP Address - buffer[9U] = (ipAddr >> 16) & 0xFFU; - buffer[10U] = (ipAddr >> 8) & 0xFFU; - buffer[11U] = (ipAddr >> 0) & 0xFFU; + block[8U] = (ipAddr >> 24) & 0xFFU; // IP Address + block[9U] = (ipAddr >> 16) & 0xFFU; + block[10U] = (ipAddr >> 8) & 0xFFU; + block[11U] = (ipAddr >> 0) & 0xFFU; } - edac::CRC::addCRC32(buffer, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); + edac::CRC::addCRC32(block, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); // Generate the PDU data m_rfData[0].setFormat(PDU_FMT_RSP); m_rfData[0].setConfirmed(true); m_rfData[0].setSerialNo(0U); - m_rfData[0].setData(buffer); + m_rfData[0].setData(block); - ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); - m_rfData[0].encode(buffer); - Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS); + ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); + m_rfData[0].encode(block); + Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS); - if (m_debug) { - Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", m_rfPDU, bitLength / 8U); - } - - uint8_t pdu[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U]; - - // Regenerate Sync - Sync::addP25Sync(pdu + 2U); - - // Regenerate NID - m_p25->m_nid.encode(pdu + 2U, P25_DUID_PDU); - - // Add the data - uint32_t newBitLength = P25Utils::encode(m_rfPDU, pdu + 2U, 114U, bitLength); - uint32_t newByteLength = newBitLength / 8U; - if ((newBitLength % 8U) > 0U) - newByteLength++; - - // Add busy bits - m_p25->addBusyBits(pdu + 2U, newBitLength, false, true); - - ::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U); - - if (m_p25->m_duplex) { - pdu[0U] = TAG_DATA; - pdu[1U] = 0x00U; - m_p25->writeQueueRF(pdu, newByteLength + 2U); - } + writeRF_PDU(data, bitLength); } /// @@ -788,52 +782,35 @@ void DataPacket::writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uin if (ackClass == PDU_ACK_CLASS_ACK && ackType != PDU_ACK_TYPE_ACK) return; - uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS); // + P25_PREAMBLE_LENGTH_BITS; + uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS; - uint8_t buffer[P25_PDU_FEC_LENGTH_BYTES]; - ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); + uint8_t data[bitLength / 8U]; + ::memset(data, 0x00U, bitLength / 8U); + uint8_t block[P25_PDU_FEC_LENGTH_BYTES]; + ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES); - DataRspHeader rspHeader = DataRspHeader(); + DataHeader rspHeader = DataHeader(); + rspHeader.setFormat(PDU_FMT_RSP); rspHeader.setOutbound(true); rspHeader.setClass(ackClass); rspHeader.setType(ackType); + rspHeader.setStatus(m_rfDataHeader.getNs()); rspHeader.setLLId(llId); - rspHeader.setSrcLLId(P25_WUID_FNE); + if (m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR) { + rspHeader.setSrcLLId(P25_WUID_FNE); + rspHeader.setFullMessage(true); + } + else { + rspHeader.setFullMessage(false); + } rspHeader.setBlocksToFollow(0U); // Generate the PDU header and 1/2 rate Trellis - rspHeader.encode(buffer); - Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS); - - if (m_debug) { - Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", m_rfPDU, bitLength / 8U); - } - - uint8_t pdu[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U]; - - // Regenerate Sync - Sync::addP25Sync(pdu + 2U); - - // Regenerate NID - m_p25->m_nid.encode(pdu + 2U, P25_DUID_PDU); - - // Add the data - uint32_t newBitLength = P25Utils::encode(m_rfPDU, pdu + 2U, 114U, bitLength); - uint32_t newByteLength = newBitLength / 8U; - if ((newBitLength % 8U) > 0U) - newByteLength++; + rspHeader.encode(block); + Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS); - // Add busy bits - m_p25->addBusyBits(pdu + 2U, newBitLength, false, true); - - ::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U); - - if (m_p25->m_duplex) { - pdu[0U] = TAG_DATA; - pdu[1U] = 0x00U; - m_p25->writeQueueRF(pdu, newByteLength + 2U); - } + writeRF_PDU(data, bitLength); } /// @@ -875,7 +852,7 @@ void DataPacket::writeNet_PDU_Header() if (m_verbose) { LogMessage(LOG_NET, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, hdrOffset = %u", m_netDataHeader.getAckNeeded(), m_netDataHeader.getOutbound(), m_netDataHeader.getFormat(), m_netDataHeader.getSAP(), m_netDataHeader.getFullMessage(), - m_netDataHeader.getBlocksToFollow(), m_netDataHeader.getPadCount(), m_netDataHeader.getN(), m_netDataHeader.getSeqNo(), + m_netDataHeader.getBlocksToFollow(), m_netDataHeader.getPadCount(), m_netDataHeader.getNs(), m_netDataHeader.getFSN(), m_netDataHeader.getHeaderOffset()); } diff --git a/p25/DataPacket.h b/p25/DataPacket.h index 47e839d3..0f350d24 100644 --- a/p25/DataPacket.h +++ b/p25/DataPacket.h @@ -34,7 +34,6 @@ #include "Defines.h" #include "p25/data/DataBlock.h" #include "p25/data/DataHeader.h" -#include "p25/data/DataRspHeader.h" #include "p25/data/LowSpeedData.h" #include "p25/lc/LC.h" #include "p25/Control.h" @@ -115,7 +114,9 @@ namespace p25 void writeNetworkRF(const uint8_t dataType, const uint8_t* data, uint32_t len); /// Helper to write a P25 PDU packet. - void writeRF_PDU(); + void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false); + /// Helper to re-write a received P25 PDU packet. + void writeRF_PDU_Buffered(); /// Helper to write a PDU registration response. void writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong64_t ipAddr); /// Helper to write a PDU acknowledge response. diff --git a/p25/data/DataBlock.h b/p25/data/DataBlock.h index 7a00582d..da1b09bb 100644 --- a/p25/data/DataBlock.h +++ b/p25/data/DataBlock.h @@ -74,6 +74,7 @@ namespace p25 /// Flag indicating this is the last block in a sequence of block. __PROPERTY(bool, lastBlock, LastBlock); + /// Logical link ID. __PROPERTY(uint32_t, llId, LLId); /// Service access point. diff --git a/p25/data/DataHeader.cpp b/p25/data/DataHeader.cpp index 3f27ac72..f0232c84 100644 --- a/p25/data/DataHeader.cpp +++ b/p25/data/DataHeader.cpp @@ -49,12 +49,19 @@ DataHeader::DataHeader() : m_sap(0U), m_mfId(P25_MFG_STANDARD), m_llId(0U), - m_fullMessage(false), - m_sync(false), - m_n(0U), - m_seqNo(0U), + m_F(true), + m_S(false), + m_fsn(0U), + m_Ns(0U), + m_lastFragment(true), m_headerOffset(0U), + m_srcLlId(0U), + m_rspClass(PDU_ACK_CLASS_NACK), + m_rspType(PDU_ACK_TYPE_NACK_ILLEGAL), + m_rspStatus(0U), m_ambtOpcode(0U), + m_ambtField8(0U), + m_ambtField9(0U), m_trellis(), m_blocksToFollow(0U), m_padCount(0U), @@ -97,23 +104,20 @@ bool DataHeader::decode(const uint8_t* data) m_ackNeeded = (header[0U] & 0x40U) == 0x40U; // Acknowledge Needed m_outbound = (header[0U] & 0x20U) == 0x20U; // Inbound/Outbound - m_fmt = header[0U] & 0x1F; // Packet Format m_sap = header[1U] & 0x3FU; // Service Access Point + m_mfId = header[2U]; // Mfg Id. m_llId = (header[3U] << 16) + (header[4U] << 8) + header[5U]; // Logical Link ID - m_fullMessage = (header[6U] & 0x80U) == 0x80U; // Full Message Flag - + m_F = (header[6U] & 0x80U) == 0x80U; // Full Message Flag m_blocksToFollow = header[6U] & 0x7FU; // Block Frames to Follow - if (m_fmt == PDU_FMT_AMBT) { + + m_padCount = header[7U] & 0x1FU; // Pad Count + if (m_fmt == PDU_FMT_RSP || m_fmt == PDU_FMT_AMBT) { m_padCount = 0; - m_ambtOpcode = header[7U] & 0x3FU; // AMBT Opcode - } - else { - m_padCount = header[7U] & 0x1FU; // Pad Count } if (m_fmt == PDU_FMT_CONFIRMED) { @@ -123,23 +127,40 @@ bool DataHeader::decode(const uint8_t* data) m_dataOctets = 12 * m_blocksToFollow - 4 - m_padCount; } - if (m_fmt == PDU_FMT_AMBT) { - m_sync = false; + switch (m_fmt) { + case PDU_FMT_CONFIRMED: + m_S = (header[8U] & 0x80U) == 0x80U; // Re-synchronize Flag - m_n = 0U; - m_seqNo = 0U; - m_headerOffset = 0U; + m_Ns = (header[8U] >> 4) & 0x07U; // Packet Sequence No. + m_fsn = header[8U] & 0x07U; // Fragment Sequence No. + m_lastFragment = (header[8U] & 0x08U) == 0x08U; // Last Fragment Flag + m_headerOffset = header[9U] & 0x3FU; // Data Header Offset + break; + case PDU_FMT_RSP: + m_ackNeeded = false; + m_sap = PDU_SAP_USER_DATA; + m_rspClass = (header[1U] >> 6) & 0x03U; // Response Class + m_rspType = (header[1U] >> 3) & 0x07U; // Response Type + m_rspStatus = header[1U] & 0x07U; // Response Status + if (!m_F) { + m_srcLlId = (header[7U] << 16) + (header[8U] << 8) + header[9U]; // Source Logical Link ID + } + break; + case PDU_FMT_AMBT: + m_ambtOpcode = header[7U] & 0x3FU; // AMBT Opcode m_ambtField8 = header[8U]; // AMBT Field 8 m_ambtField9 = header[9U]; // AMBT Field 9 - } - else { - m_sync = (header[8U] & 0x80U) == 0x80U; // Re-synchronize Flag - - m_n = (header[8U] >> 4) & 0x07U; // Packet Sequence No. - m_seqNo = header[8U] & 0x0FU; // Fragment Sequence No. - - m_headerOffset = header[9U] & 0x3FU; // Data Header Offset + // fall-thru + case PDU_FMT_UNCONFIRMED: + default: + m_ackNeeded = false; + m_S = false; + + m_Ns = 0U; + m_fsn = 0U; + m_headerOffset = 0U; + break; } return true; @@ -156,6 +177,10 @@ void DataHeader::encode(uint8_t* data) uint8_t header[P25_PDU_HEADER_LENGTH_BYTES]; ::memset(header, 0x00U, P25_PDU_HEADER_LENGTH_BYTES); + if (m_fmt == PDU_FMT_UNCONFIRMED || m_fmt == PDU_FMT_RSP) { + m_ackNeeded = false; + } + header[0U] = (m_ackNeeded ? 0x40U : 0x00U) + // Acknowledge Needed (m_outbound ? 0x20U : 0x00U) + // Inbound/Outbound (m_fmt & 0x1FU); // Packet Format @@ -169,29 +194,47 @@ void DataHeader::encode(uint8_t* data) header[4U] = (m_llId >> 8) & 0xFFU; header[5U] = (m_llId >> 0) & 0xFFU; - header[6U] = (m_fullMessage ? 0x80U : 0x00U) + // Full Message Flag + header[6U] = (m_F ? 0x80U : 0x00U) + // Full Message Flag (m_blocksToFollow & 0x7FU); // Blocks Frames to Follow - if (m_fmt == PDU_FMT_AMBT) { - header[7U] = (m_ambtOpcode & 0x3FU); // AMBT Opcode - header[8U] = m_ambtField8; // AMBT Field 8 - header[9U] = m_ambtField9; // AMBT Field 9 - } - else { + switch (m_fmt) { + case PDU_FMT_CONFIRMED: header[7U] = (m_padCount & 0x1FU); // Pad Count - header[8U] = (m_sync ? 0x80U : 0x00U) + // Re-synchronize Flag - ((m_n << 4) & 0x07U) + // Packet Sequence No. - (m_seqNo & 0x0F); // Fragment Sequence No. + header[8U] = (m_S ? 0x80U : 0x00U) + // Re-synchronize Flag + ((m_Ns << 4) & 0x07U) + // Packet Sequence No. + (m_lastFragment ? 0x08U : 0x00U) + // Last Fragment Flag + (m_fsn & 0x07); // Fragment Sequence No. header[9U] = m_headerOffset & 0x3FU; // Data Header Offset + break; + case PDU_FMT_RSP: + header[1U] = ((m_rspClass & 0x03U) << 6) + // Response Class + ((m_rspType & 0x07U) << 3) + // Response Type + ((m_rspStatus & 0x07U)); // Response Status + if (!m_F) { + header[7U] = (m_srcLlId >> 16) & 0xFFU; // Source Logical Link ID + header[8U] = (m_srcLlId >> 8) & 0xFFU; + header[9U] = (m_srcLlId >> 0) & 0xFFU; + } + break; + case PDU_FMT_AMBT: + header[7U] = (m_ambtOpcode & 0x3FU); // AMBT Opcode + header[8U] = m_ambtField8; // AMBT Field 8 + header[9U] = m_ambtField9; // AMBT Field 9 + break; + case PDU_FMT_UNCONFIRMED: + default: + header[8U] = 0x00U; + header[9U] = m_headerOffset & 0x3FU; // Data Header Offset + break; } // compute CRC-CCITT 16 edac::CRC::addCCITT162(header, P25_PDU_HEADER_LENGTH_BYTES); #if DEBUG_P25_PDU_DATA - Utils::dump(1U, "P25, DataHeader::encode(), PDU Header Data", data, P25_PDU_HEADER_LENGTH_BYTES); + Utils::dump(1U, "P25, DataHeader::encode(), PDU Header Data", header, P25_PDU_HEADER_LENGTH_BYTES); #endif // encode 1/2 rate Trellis @@ -212,19 +255,28 @@ void DataHeader::reset() m_mfId = P25_MFG_STANDARD; m_llId = 0U; - m_fullMessage = false; + m_F = true; m_blocksToFollow = 0U; m_padCount = 0U; m_dataOctets = 0U; - m_sync = false; + m_S = false; - m_n = 0U; - m_seqNo = 0U; + m_Ns = 0U; + m_fsn = 0U; + m_lastFragment = true; m_headerOffset = 0U; + + m_srcLlId = 0U; + m_rspClass = PDU_ACK_CLASS_NACK; + m_rspType = PDU_ACK_TYPE_NACK_ILLEGAL; + m_rspStatus = 0U; + m_ambtOpcode = 0U; + m_ambtField8 = 0U; + m_ambtField9 = 0U; } /// Gets the total number of data octets. diff --git a/p25/data/DataHeader.h b/p25/data/DataHeader.h index 4e05eab6..408e2eea 100644 --- a/p25/data/DataHeader.h +++ b/p25/data/DataHeader.h @@ -82,16 +82,30 @@ namespace p25 /// Logical link ID. __PROPERTY(uint32_t, llId, LLId); /// Flag indicating whether or not this data packet is a full message. - __PROPERTY(bool, fullMessage, FullMessage); - /// - __PROPERTY(bool, sync, Sync); - /// - __PROPERTY(uint8_t, n, N); - /// Data packet sequence number. - __PROPERTY(uint8_t, seqNo, SeqNo); + /// When a response header, this represents the extended flag. + __PROPERTY(bool, F, FullMessage); + /// Synchronize Flag. + __PROPERTY(bool, S, Synchronize); + /// Fragment Sequence Number. + __PROPERTY(uint8_t, fsn, FSN); + /// Send Sequence Number. + __PROPERTY(uint8_t, Ns, Ns); + /// Flag indicating whether or not this is the last fragment in a message. + __PROPERTY(bool, lastFragment, LastFragment); /// Offset of the header. __PROPERTY(uint8_t, headerOffset, HeaderOffset); + /** Response Data */ + /// Source Logical link ID. + __PROPERTY(uint32_t, srcLlId, SrcLLId); + /// Response class. + __PROPERTY(uint8_t, rspClass, Class); + /// Response type. + __PROPERTY(uint8_t, rspType, Type); + /// Response status. + __PROPERTY(uint8_t, rspStatus, Status); + + /** AMBT Data */ /// Alternate Trunking Block Opcode __PROPERTY(uint8_t, ambtOpcode, AMBTOpcode); /// Alternate Trunking Block Field 8 diff --git a/p25/data/DataRspHeader.cpp b/p25/data/DataRspHeader.cpp deleted file mode 100644 index bac1e79d..00000000 --- a/p25/data/DataRspHeader.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/** -* Digital Voice Modem - Host Software -* GPLv2 Open Source. Use is subject to license terms. -* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -* -* @package DVM / Host Software -* -*/ -/* -* Copyright (C) 2020,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 -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -#include "Defines.h" -#include "p25/P25Defines.h" -#include "p25/data/DataRspHeader.h" -#include "edac/CRC.h" -#include "Utils.h" - -using namespace p25::data; -using namespace p25; - -#include -#include -#include - -// --------------------------------------------------------------------------- -// Public Class Members -// --------------------------------------------------------------------------- -/// -/// Initializes a new instance of the DataRspHeader class. -/// -DataRspHeader::DataRspHeader() : - m_outbound(true), - m_rspClass(PDU_ACK_CLASS_NACK), - m_rspType(PDU_ACK_TYPE_NACK_ILLEGAL), - m_rspStatus(0U), - m_mfId(P25_MFG_STANDARD), - m_llId(0U), - m_srcLlId(0U), - m_extended(true), - m_trellis(), - m_blocksToFollow(0U), - m_dataOctets(0U) -{ - /* stub */ -} - -/// -/// Finalizes a instance of the DataRspHeader class. -/// -DataRspHeader::~DataRspHeader() -{ - /* stub */ -} - -/// -/// Decodes P25 PDU data response header. -/// -/// -/// True, if PDU data response header was decoded, otherwise false. -bool DataRspHeader::decode(const uint8_t* data) -{ - assert(data != NULL); - - uint8_t header[P25_PDU_HEADER_LENGTH_BYTES]; - ::memset(header, 0x00U, P25_PDU_HEADER_LENGTH_BYTES); - - // decode 1/2 rate Trellis & check CRC-CCITT 16 - bool valid = m_trellis.decode12(data, header); - if (valid) - valid = edac::CRC::checkCCITT162(header, P25_PDU_HEADER_LENGTH_BYTES); - if (!valid) { - return false; - } - -#if DEBUG_P25_PDU_DATA - Utils::dump(1U, "P25, DataRspHeader::decode(), PDU Response Header Data", data, P25_PDU_HEADER_LENGTH_BYTES); -#endif - - m_outbound = (header[0U] & 0x20U) == 0x20U; // Inbound/Outbound - - m_rspClass = (header[1U] >> 6) & 0x03U; // Response Class - m_rspType = (header[1U] >> 3) & 0x07U; // Response Type - m_rspStatus = header[1U] & 0x07U; // Response Status - - m_mfId = header[2U]; // Mfg Id. - - m_llId = (header[3U] << 16) + (header[4U] << 8) + header[5U]; // Logical Link ID - - m_extended = (header[6U] & 0x80U) == 0x80U; // Extended Addressing - m_blocksToFollow = header[6U] & 0x7FU; // Block Frames to Follow - - m_srcLlId = (header[7U] << 16) + (header[8U] << 8) + header[9U]; // Source Logical Link ID - - return true; -} - -/// -/// Encodes P25 PDU data response header. -/// -/// -void DataRspHeader::encode(uint8_t* data) -{ - assert(data != NULL); - - uint8_t header[P25_PDU_HEADER_LENGTH_BYTES]; - ::memset(header, 0x00U, P25_PDU_HEADER_LENGTH_BYTES); - - header[0U] = PDU_FMT_RSP; - header[0U] = (m_outbound ? 0x20U : 0x00U) + // Inbound/Outbound - (PDU_FMT_RSP & 0x1FU); // Packet Format - - header[1U] = ((m_rspClass & 0x03U) << 6) + // Response Class - ((m_rspType & 0x07U) << 3) + // Response Type - ((m_rspStatus & 0x07U)); // Response Status - - header[2U] = m_mfId; // Mfg Id. - - header[3U] = (m_llId >> 16) & 0xFFU; // Logical Link ID - header[4U] = (m_llId >> 8) & 0xFFU; - header[5U] = (m_llId >> 0) & 0xFFU; - - header[6U] = (m_extended ? 0x80U : 0x00U) + // Extended Addressing - (m_blocksToFollow & 0x7FU); // Blocks Frames to Follow - - header[7U] = (m_srcLlId >> 16) & 0xFFU; // Source Logical Link ID - header[8U] = (m_srcLlId >> 8) & 0xFFU; - header[9U] = (m_srcLlId >> 0) & 0xFFU; - - // compute CRC-CCITT 16 - edac::CRC::addCCITT162(header, P25_PDU_HEADER_LENGTH_BYTES); - -#if DEBUG_P25_PDU_DATA - Utils::dump(1U, "P25, DataRspHeader::encode(), PDU Response Header Data", header, P25_PDU_HEADER_LENGTH_BYTES); -#endif - - // encode 1/2 rate Trellis - m_trellis.encode12(header, data); -} - -/// -/// Helper to reset data values to defaults. -/// -void DataRspHeader::reset() -{ - m_outbound = false; - - m_rspClass = PDU_ACK_CLASS_NACK; - m_rspType = PDU_ACK_TYPE_NACK_ILLEGAL; - m_rspStatus = 0U; - - m_mfId = P25_MFG_STANDARD; - m_llId = 0U; - m_srcLlId = 0U; - - m_extended = true; - - m_blocksToFollow = 0U; - m_dataOctets = 0U; -} - -/// Gets the total number of data octets. -/// -uint32_t DataRspHeader::getDataOctets() const -{ - return m_dataOctets; -} - -/** Common Data */ -/// Sets the total number of blocks to follow this header. -/// -void DataRspHeader::setBlocksToFollow(uint8_t blocksToFollow) -{ - m_blocksToFollow = blocksToFollow; - - // recalculate count of data octets - m_dataOctets = 16 * m_blocksToFollow - 4; -} - -/// Gets the total number of blocks to follow this header. -/// -uint8_t DataRspHeader::getBlocksToFollow() const -{ - return m_blocksToFollow; -} diff --git a/p25/data/DataRspHeader.h b/p25/data/DataRspHeader.h deleted file mode 100644 index 76ba4215..00000000 --- a/p25/data/DataRspHeader.h +++ /dev/null @@ -1,94 +0,0 @@ -/** -* Digital Voice Modem - Host Software -* GPLv2 Open Source. Use is subject to license terms. -* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -* -* @package DVM / Host Software -* -*/ -/* -* Copyright (C) 2020 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 -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -#if !defined(__P25_DATA__DATA_RSP_HEADER_H__) -#define __P25_DATA__DATA_RSP_HEADER_H__ - -#include "Defines.h" -#include "p25/edac/Trellis.h" - -#include - -namespace p25 -{ - namespace data - { - // --------------------------------------------------------------------------- - // Class Declaration - // Represents the data response header for PDU P25 packets. - // --------------------------------------------------------------------------- - - class HOST_SW_API DataRspHeader { - public: - /// Initializes a new instance of the DataRspHeader class. - DataRspHeader(); - /// Finalizes a instance of the DataRspHeader class. - ~DataRspHeader(); - - /// Decodes P25 PDU data response header. - bool decode(const uint8_t* data); - /// Encodes P25 PDU data response header. - void encode(uint8_t* data); - - /// Helper to reset data values to defaults. - void reset(); - - /// Gets the total number of data octets. - uint32_t getDataOctets() const; - - /** Common Data */ - /// Sets the total number of blocks to follow this header. - void setBlocksToFollow(uint8_t blocksToFollow); - /// Gets the total number of blocks to follow this header. - uint8_t getBlocksToFollow() const; - - public: - /// Flag indicating if this is an outbound data packet. - __PROPERTY(bool, outbound, Outbound); - /// Response class. - __PROPERTY(uint8_t, rspClass, Class); - /// Response type. - __PROPERTY(uint8_t, rspType, Type); - /// Response status. - __PROPERTY(uint8_t, rspStatus, Status); - /// Manufacturer ID. - __PROPERTY(uint8_t, mfId, MFId); - /// Logical link ID. - __PROPERTY(uint32_t, llId, LLId); - /// Source Logical link ID. - __PROPERTY(uint32_t, srcLlId, SrcLLId); - /// Flag indicating whether or not this response packet is to extended addressing. - __PROPERTY(bool, extended, Extended); - - private: - edac::Trellis m_trellis; - - uint8_t m_blocksToFollow; - uint32_t m_dataOctets; - }; - } // namespace data -} // namespace p25 - -#endif // __P25_DATA__DATA_RSP_HEADER_H__