diff --git a/p25/DataPacket.cpp b/p25/DataPacket.cpp index 715f778e..70ba948e 100644 --- a/p25/DataPacket.cpp +++ b/p25/DataPacket.cpp @@ -155,23 +155,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len) if (m_p25->m_rfState == RS_RF_DATA) { uint32_t blocksToFollow = m_rfDataHeader.getBlocksToFollow(); - - // confirmed extended addressing is unsupported - if (m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR && - m_rfDataHeader.getFormat() == PDU_FMT_CONFIRMED) { - LogWarning(LOG_RF, P25_PDU_STR ", unsupported confirmed enhanced addressing"); - - m_rfDataHeader.reset(); - m_rfSecondHeader.reset(); - m_rfDataBlockCnt = 0U; - m_rfPDUCount = 0U; - m_rfPDUBits = 0U; - m_p25->m_rfState = m_prevRfState; - return false; - } - // process second header if we're using enhanced addressing - if (m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR) { + if (m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR && + m_rfDataHeader.getFormat() == PDU_FMT_UNCONFIRMED) { ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); Utils::getBitRange(m_rfPDU, buffer, offset, P25_PDU_FEC_LENGTH_BITS); bool ret = m_rfSecondHeader.decode(buffer); @@ -223,10 +209,10 @@ bool DataPacket::process(uint8_t* data, uint32_t len) writeNetworkRF(P25_DT_DATA, buffer, P25_PDU_FEC_LENGTH_BYTES); } else { - if (m_rfData[i].getHalfRateTrellis()) - LogWarning(LOG_RF, P25_PDU_STR ", unfixable PDU data (1/2 rate or CRC)"); - else + if (m_rfData[i].getConfirmed()) LogWarning(LOG_RF, P25_PDU_STR ", unfixable PDU data (3/4 rate or CRC)"); + else + LogWarning(LOG_RF, P25_PDU_STR ", unfixable PDU data (1/2 rate or CRC)"); if (m_dumpPDUData) { Utils::dump(1U, "Unfixable PDU Data", buffer, P25_PDU_FEC_LENGTH_BYTES); @@ -404,12 +390,10 @@ bool DataPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, da } // Generate the PDU data - bool halfRate = m_netData[0].getHalfRateTrellis(); uint32_t dataOffset = 0U; for (uint32_t i = 0U; i < blocksToFollow; i++) { m_netData[i].setFormat((m_netDataHeader.getSAP() == PDU_SAP_EXT_ADDR) ? m_netSecondHeader : m_netDataHeader); m_netData[i].setSerialNo(i); - m_netData[i].setHalfRateTrellis(halfRate); m_netData[i].setData(m_pduUserData + dataOffset); ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); @@ -615,12 +599,10 @@ void DataPacket::writeRF_PDU() } // Generate the PDU data - bool halfRate = m_rfData[0].getHalfRateTrellis(); uint32_t dataOffset = 0U; for (uint32_t i = 0U; i < blocksToFollow; i++) { m_rfData[i].setFormat((m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR) ? m_rfSecondHeader : m_rfDataHeader); m_rfData[i].setSerialNo(i); - m_rfData[i].setHalfRateTrellis(halfRate); m_rfData[i].setData(m_pduUserData + dataOffset); ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); @@ -719,7 +701,6 @@ void DataPacket::writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong6 // Generate the PDU data m_rfData[0].setFormat(PDU_FMT_RSP); m_rfData[0].setSerialNo(0U); - m_rfData[0].setHalfRateTrellis(true); m_rfData[0].setData(buffer); ::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES); @@ -908,10 +889,10 @@ void DataPacket::writeNet_PDU() m_netDataBlockCnt++; } else { - if (m_netData[m_netDataBlockCnt].getHalfRateTrellis()) - LogWarning(LOG_NET, P25_PDU_STR ", unfixable PDU data (1/2 rate or CRC)"); - else + if (m_netData[m_netDataBlockCnt].getConfirmed()) LogWarning(LOG_NET, P25_PDU_STR ", unfixable PDU data (3/4 rate or CRC)"); + else + LogWarning(LOG_NET, P25_PDU_STR ", unfixable PDU data (1/2 rate or CRC)"); if (m_dumpPDUData) { Utils::dump(1U, "Unfixable PDU Data", buffer, P25_PDU_FEC_LENGTH_BYTES); diff --git a/p25/data/DataBlock.cpp b/p25/data/DataBlock.cpp index bb64e6bb..0746184b 100644 --- a/p25/data/DataBlock.cpp +++ b/p25/data/DataBlock.cpp @@ -48,10 +48,13 @@ using namespace p25; /// Initializes a new instance of the DataBlock class. /// DataBlock::DataBlock() : - m_halfRateTrellis(false), + m_confirmed(false), m_serialNo(0U), + m_llId(0U), + m_sap(0U), m_trellis(), m_fmt(PDU_FMT_CONFIRMED), + m_headerSap(0U), m_data(NULL) { m_data = new uint8_t[P25_PDU_CONFIRMED_DATA_LENGTH_BYTES]; @@ -79,31 +82,37 @@ bool DataBlock::decode(const uint8_t* data, const DataHeader header) uint8_t buffer[P25_PDU_CONFIRMED_LENGTH_BYTES]; ::memset(buffer, 0x00U, P25_PDU_CONFIRMED_LENGTH_BYTES); - // decode 3/4 rate Trellis - m_halfRateTrellis = false; - bool valid = m_trellis.decode34(data, buffer); - if (!valid) { - // decode 1/2 rate Trellis - m_halfRateTrellis = true; - valid = m_trellis.decode12(data, buffer); - if (!valid) { - return false; - } - } - // Utils::dump(1U, "PDU Data Block", buffer, P25_PDU_CONFIRMED_LENGTH_BYTES); m_fmt = header.getFormat(); + m_headerSap = header.getSAP(); if (m_fmt == PDU_FMT_CONFIRMED) { + m_confirmed = true; + bool valid = m_trellis.decode34(data, buffer); + if (!valid) { + return false; + } + m_serialNo = buffer[0] & 0xFEU; // Confirmed Data Serial No. uint16_t crc = ((buffer[0] & 0x01U) << 8) + buffer[1]; // CRC-9 Check Sum uint32_t count = P25_PDU_CONFIRMED_LENGTH_BYTES; if (m_serialNo == (header.getBlocksToFollow() - 1)) count = P25_PDU_CONFIRMED_LENGTH_BYTES - 4U; - for (uint32_t i = 2U; i < count; i++) { - m_data[i - 2U] = buffer[i]; // Payload Data + if (m_headerSap == PDU_SAP_EXT_ADDR) { + m_sap = buffer[5U] & 0x3FU; // Service Access Point + m_llId = (buffer[2U] << 16) + (buffer[3U] << 8) + buffer[4U]; // Logical Link ID + + // re-copy buffer to remove SAP and llId + for (uint32_t i = 6U; i < count; i++) { + m_data[i - 6U] = buffer[i]; // Payload Data + } + } + else { + for (uint32_t i = 2U; i < count; i++) { + m_data[i - 2U] = buffer[i]; // Payload Data + } } // compute CRC-9 for the packet @@ -116,6 +125,12 @@ bool DataBlock::decode(const uint8_t* data, const DataHeader header) LogMessage(LOG_P25, "P25_DUID_PDU, fmt = $%02X, crc = $%04X, computedCRC = $%04X", m_fmt, crc, computedCRC); } else if ((m_fmt == PDU_FMT_UNCONFIRMED) || (m_fmt == PDU_FMT_RSP)) { + m_confirmed = false; + bool valid = m_trellis.decode12(data, buffer); + if (!valid) { + return false; + } + for (uint32_t i = 0U; i < P25_PDU_UNCONFIRMED_LENGTH_BYTES; i++) { m_data[i] = buffer[i]; // Payload Data } @@ -145,17 +160,24 @@ void DataBlock::encode(uint8_t* data) ::memcpy(buffer + 1U, m_data, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); uint16_t crc = edac::CRC::crc9(buffer, P25_PDU_CONFIRMED_LENGTH_BYTES); - ::memcpy(buffer + 2U, m_data, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); - buffer[0] = ((m_serialNo & 0x7FU) << 1) + // Confirmed Data Serial No. - (crc >> 8); // CRC-9 Check Sum (b8) - buffer[1] = (crc & 0xFFU); // CRC-9 Check Sum (b0 - b7) + if (m_headerSap == PDU_SAP_EXT_ADDR) { + buffer[5U] = m_sap & 0x3FU; // Service Access Point + + buffer[2U] = (m_llId >> 16) & 0xFFU; // Logical Link ID + buffer[3U] = (m_llId >> 8) & 0xFFU; + buffer[4U] = (m_llId >> 0) & 0xFFU; - if (!m_halfRateTrellis) { - m_trellis.encode34(buffer, data); + ::memcpy(buffer + 6U, m_data, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES - 4U); } else { - m_trellis.encode12(buffer, data); + ::memcpy(buffer + 2U, m_data, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); } + + buffer[0U] = ((m_serialNo & 0x7FU) << 1) + // Confirmed Data Serial No. + (crc >> 8); // CRC-9 Check Sum (b8) + buffer[1U] = (crc & 0xFFU); // CRC-9 Check Sum (b0 - b7) + + m_trellis.encode34(buffer, data); } else if ((m_fmt == PDU_FMT_UNCONFIRMED) || (m_fmt == PDU_FMT_RSP)) { uint8_t buffer[P25_PDU_UNCONFIRMED_LENGTH_BYTES]; @@ -163,12 +185,7 @@ void DataBlock::encode(uint8_t* data) ::memcpy(buffer, m_data, P25_PDU_UNCONFIRMED_LENGTH_BYTES); - if (!m_halfRateTrellis) { - m_trellis.encode34(buffer, data); - } - else { - m_trellis.encode12(buffer, data); - } + m_trellis.encode12(buffer, data); } else { LogError(LOG_P25, "unknown FMT value in P25_DUID_PDU, fmt = $%02X", m_fmt); @@ -188,6 +205,12 @@ void DataBlock::setFormat(const uint8_t fmt) void DataBlock::setFormat(const DataHeader header) { m_fmt = header.getFormat(); + if (m_fmt == PDU_FMT_CONFIRMED) { + m_confirmed = true; + } + else { + m_confirmed = false; + } } /// Gets the data format. diff --git a/p25/data/DataBlock.h b/p25/data/DataBlock.h index 98799612..76245436 100644 --- a/p25/data/DataBlock.h +++ b/p25/data/DataBlock.h @@ -70,16 +70,22 @@ namespace p25 uint32_t getData(uint8_t* buffer) const; public: - /// Flag indicating whether or not the data block uses 1/2 rate Trellis. - __PROPERTY(bool, halfRateTrellis, HalfRateTrellis); + /// Flag indicating whether or not the data block is confirmed. + __PROPERTY(bool, confirmed, Confirmed); /// Sets the data block serial number. __PROPERTY(uint8_t, serialNo, SerialNo); + /// Logical link ID. + __PROPERTY(uint32_t, llId, LLId); + /// Service access point. + __PROPERTY(uint8_t, sap, SAP); + private: edac::Trellis m_trellis; uint8_t m_fmt; + uint8_t m_headerSap; uint8_t* m_data; };