From cfe4c9947822b244347564e931afd8dd18b184c6 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Thu, 22 Apr 2021 14:48:44 +0000 Subject: [PATCH] proper implementation for P25 confirmed PDU CRC-9; --- edac/CRC.cpp | 46 +++++++++++++++++--------------- edac/CRC.h | 3 ++- p25/data/DataBlock.cpp | 59 ++++++++++++++++++++++++++---------------- p25/data/DataBlock.h | 3 +++ 4 files changed, 66 insertions(+), 45 deletions(-) diff --git a/edac/CRC.cpp b/edac/CRC.cpp index 4c4c7a42..096ec6ef 100644 --- a/edac/CRC.cpp +++ b/edac/CRC.cpp @@ -68,20 +68,21 @@ const uint8_t CRC8_TABLE[] = { 0xFA, 0xFD, 0xF4, 0xF3, 0x01 }; const uint16_t CRC9_TABLE[] = { - 0x1E7, 0x1F3, 0x1F9, 0x1FC, 0x0D2, 0x045, 0x122, 0x0BD, 0x15E, 0x083, - 0x141, 0x1A0, 0x0FC, 0x052, 0x005, 0x102, 0x0AD, 0x156, 0x087, 0x143, - 0x1A1, 0x1D0, 0x0C4, 0x04E, 0x00B, 0x105, 0x182, 0x0ED, 0x176, 0x097, - 0x14B, 0x1A5, 0x1D2, 0x0C5, 0x162, 0x09D, 0x14E, 0x08B, 0x145, 0x1A2, - 0x0FD, 0x17E, 0x093, 0x149, 0x1A4, 0x0FE, 0x053, 0x129, 0x194, 0x0E6, - 0x05F, 0x12F, 0x197, 0x1CB, 0x1E5, 0x1F2, 0x0D5, 0x16A, 0x099, 0x14C, - 0x08A, 0x069, 0x134, 0x0B6, 0x077, 0x13B, 0x19D, 0x1CE, 0x0CB, 0x165, - 0x1B2, 0x0F5, 0x17A, 0x091, 0x148, 0x088, 0x068, 0x018, 0x020, 0x03C, - 0x032, 0x035, 0x11A, 0x0A1, 0x150, 0x084, 0x06E, 0x01B, 0x10D, 0x186, - 0x0EF, 0x177, 0x1BB, 0x1DD, 0x1EE, 0x0DB, 0x16D, 0x1B6, 0x0F7, 0x17B, - 0x1BD, 0x1DE, 0x0C3, 0x161, 0x1B0, 0x0F4, 0x056, 0x007, 0x103, 0x181, - 0x1C0, 0x0CC, 0x04A, 0x009, 0x104, 0x0AE, 0x07B, 0x13D, 0x19E, 0x0E3, - 0x171, 0x1B8, 0x0F0, 0x054, 0x006, 0x02F, 0x117, 0x18B, 0x1C5, 0x1E2, - 0x0DD, 0x16E, 0x09B, 0x14D, 0x1A6 }; + 0x1E7U, 0x1F3U, 0x1F9U, 0x1FCU, 0x0D2U, 0x045U, 0x122U, 0x0BDU, 0x15EU, 0x083, + 0x141U, 0x1A0U, 0x0FCU, 0x052U, 0x005U, 0x102U, 0x0ADU, 0x156U, 0x087U, 0x143, + 0x1A1U, 0x1D0U, 0x0C4U, 0x04EU, 0x00BU, 0x105U, 0x182U, 0x0EDU, 0x176U, 0x097, + 0x14BU, 0x1A5U, 0x1D2U, 0x0C5U, 0x162U, 0x09DU, 0x14EU, 0x08BU, 0x145U, 0x1A2, + 0x0FDU, 0x17EU, 0x093U, 0x149U, 0x1A4U, 0x0FEU, 0x053U, 0x129U, 0x194U, 0x0E6, + 0x05FU, 0x12FU, 0x197U, 0x1CBU, 0x1E5U, 0x1F2U, 0x0D5U, 0x16AU, 0x099U, 0x14C, + 0x08AU, 0x069U, 0x134U, 0x0B6U, 0x077U, 0x13BU, 0x19DU, 0x1CEU, 0x0CBU, 0x165, + 0x1B2U, 0x0F5U, 0x17AU, 0x091U, 0x148U, 0x088U, 0x068U, 0x018U, 0x020U, 0x03C, + 0x032U, 0x035U, 0x11AU, 0x0A1U, 0x150U, 0x084U, 0x06EU, 0x01BU, 0x10DU, 0x186, + 0x0EFU, 0x177U, 0x1BBU, 0x1DDU, 0x1EEU, 0x0DBU, 0x16DU, 0x1B6U, 0x0F7U, 0x17B, + 0x1BDU, 0x1DEU, 0x0C3U, 0x161U, 0x1B0U, 0x0F4U, 0x056U, 0x007U, 0x103U, 0x181, + 0x1C0U, 0x0CCU, 0x04AU, 0x009U, 0x104U, 0x0AEU, 0x07BU, 0x13DU, 0x19EU, 0x0E3, + 0x171U, 0x1B8U, 0x0F0U, 0x054U, 0x006U, 0x02FU, 0x117U, 0x18BU, 0x1C5U, 0x1E2, + 0x0DDU, 0x16EU, 0x09BU, 0x14DU, 0x1A6U +}; const uint16_t CCITT16_TABLE1[] = { 0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU, @@ -409,21 +410,24 @@ 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 length) +uint16_t CRC::crc9(const uint8_t* in, uint32_t bitlen) { assert(in != NULL); - uint16_t crc = 0U; + uint16_t crc = 0x00U; - uint32_t n = 0U; - for (uint32_t i = 0U; i < length; i++, n++) { - bool bit = READ_BIT(in, n); - if (bit) { + for (uint32_t i = 0; i < bitlen; i++) { + bool b = READ_BIT(in, i); + if (b) { crc ^= CRC9_TABLE[i]; } } + crc = ~crc; + crc &= 0x1FFU; + crc ^= 0x1FFU; + return crc; } diff --git a/edac/CRC.h b/edac/CRC.h index eae429cc..a6660657 100644 --- a/edac/CRC.h +++ b/edac/CRC.h @@ -64,7 +64,8 @@ namespace edac /// Generate 8-bit CRC. 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 length); }; } // namespace edac diff --git a/p25/data/DataBlock.cpp b/p25/data/DataBlock.cpp index 3b7678b2..549e58c2 100644 --- a/p25/data/DataBlock.cpp +++ b/p25/data/DataBlock.cpp @@ -92,15 +92,17 @@ bool DataBlock::decode(const uint8_t* data, const DataHeader header) return false; } + // determine the number of user data bytes + uint32_t count = P25_PDU_CONFIRMED_DATA_LENGTH_BYTES; + if (m_serialNo == (header.getBlocksToFollow() - 1) || + (m_headerSap == PDU_SAP_EXT_ADDR && m_serialNo == 0U)) + count = P25_PDU_CONFIRMED_DATA_LENGTH_BYTES - 4U; + // Utils::dump(1U, "PDU Confirmed Data Block", buffer, P25_PDU_CONFIRMED_LENGTH_BYTES); m_serialNo = (buffer[0] & 0xFEU) >> 1; // 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; - ::memset(m_data, 0x00U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); // if this is extended addressing and the first block decode the SAP and LLId @@ -119,14 +121,10 @@ bool DataBlock::decode(const uint8_t* data, const DataHeader header) } } - // compute CRC-9 for the packet - uint8_t crcBuffer[P25_PDU_CONFIRMED_DATA_LENGTH_BYTES + 1U]; - ::memset(crcBuffer, 0x00U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES + 1U); - - crcBuffer[0U] = (m_serialNo & 0xFEU) << 1; - Utils::setBitRange(m_data, crcBuffer, 7U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES * 8U); + // Utils::dump(1U, "PDU Data", m_data, count); - uint16_t computedCRC = edac::CRC::crc9(crcBuffer, 135U); + // compute CRC-9 for the packet + uint16_t computedCRC = confirmedCRC9(buffer); if (crc != computedCRC) { LogWarning(LOG_P25, "P25_DUID_PDU, fmt = $%02X, invalid crc = $%04X != $%04X (computed)", m_fmt, crc, computedCRC); @@ -162,21 +160,10 @@ void DataBlock::encode(uint8_t* data) assert(m_data != NULL); if (m_fmt == PDU_FMT_CONFIRMED) { - // compute CRC-9 for the packet - uint8_t crcBuffer[P25_PDU_CONFIRMED_DATA_LENGTH_BYTES + 1U]; - ::memset(crcBuffer, 0x00U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES + 1U); - - crcBuffer[0U] = (m_serialNo & 0xFEU) << 1; - Utils::setBitRange(m_data, crcBuffer, 7U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES * 8U); - - uint16_t computedCRC = edac::CRC::crc9(crcBuffer, 135U); - uint8_t buffer[P25_PDU_CONFIRMED_LENGTH_BYTES]; ::memset(buffer, 0x00U, P25_PDU_CONFIRMED_LENGTH_BYTES); - buffer[0U] = ((m_serialNo & 0xFEU) << 1) + // Confirmed Data Serial No. - (computedCRC >> 8); // CRC-9 Check Sum (b8) - buffer[1U] = (computedCRC & 0xFFU); // CRC-9 Check Sum (b0 - b7) + buffer[0U] = ((m_serialNo & 0xFEU) << 1); // Confirmed Data Serial No. // if this is extended addressing and the first block decode the SAP and LLId if (m_headerSap == PDU_SAP_EXT_ADDR && m_serialNo == 0U) { @@ -192,6 +179,10 @@ void DataBlock::encode(uint8_t* data) ::memcpy(buffer + 2U, m_data, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES); } + uint16_t crc = confirmedCRC9(buffer); + buffer[0U] = buffer[0U] + ((crc >> 8) & 0x01U); // CRC-9 Check Sum (b8) + buffer[1U] = (crc & 0xFFU); // CRC-9 Check Sum (b0 - b7) + // Utils::dump(1U, "PDU Confirmed Data Block", buffer, P25_PDU_CONFIRMED_LENGTH_BYTES); m_trellis.encode34(buffer, data); @@ -277,3 +268,25 @@ uint32_t DataBlock::getData(uint8_t* buffer) const return 0U; } } + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- +/// +/// +/// +/// +uint16_t DataBlock::confirmedCRC9(const uint8_t* buffer) +{ + // generate 135-bit CRC buffer + uint8_t* crcBuffer = new uint8_t[17U]; + ::memset(crcBuffer, 0x00U, 17U); + + Utils::setBitRange(buffer, crcBuffer, 0U, 7U); + + uint8_t* data = new uint8_t[P25_PDU_CONFIRMED_DATA_LENGTH_BYTES]; + Utils::getBitRange(buffer, data, 16U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES * 8); + Utils::setBitRange(data, crcBuffer, 7U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES * 8); + + return edac::CRC::crc9(crcBuffer, 135U); +} diff --git a/p25/data/DataBlock.h b/p25/data/DataBlock.h index 76245436..4f0a052c 100644 --- a/p25/data/DataBlock.h +++ b/p25/data/DataBlock.h @@ -88,6 +88,9 @@ namespace p25 uint8_t m_headerSap; uint8_t* m_data; + + /// + uint16_t confirmedCRC9(const uint8_t* buffer); }; } // namespace data } // namespace p25