From 0a94b0deb66ce838a78bc43c5775d5f9be7bfbb4 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 26 Mar 2021 22:21:20 +0000 Subject: [PATCH] Add the LICH CRC. --- M17CRC.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++------ M17CRC.h | 12 +++++--- M17Control.cpp | 36 ++++++++++++++---------- M17LSF.cpp | 8 +++--- 4 files changed, 101 insertions(+), 30 deletions(-) diff --git a/M17CRC.cpp b/M17CRC.cpp index cd41697eb..695511ef1 100644 --- a/M17CRC.cpp +++ b/M17CRC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -21,7 +21,7 @@ #include #include -const uint16_t CRC_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x64D4U, 0x8F8BU, 0xD6BEU, 0x7BC2U, 0x22F7U, 0xC9A8U, +const uint16_t CRC16_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x64D4U, 0x8F8BU, 0xD6BEU, 0x7BC2U, 0x22F7U, 0xC9A8U, 0x909DU, 0x4623U, 0x1F16U, 0xF449U, 0xAD7CU, 0xF784U, 0xAEB1U, 0x45EEU, 0x1CDBU, 0xCA65U, 0x9350U, 0x780FU, 0x213AU, 0x8C46U, 0xD573U, 0x3E2CU, 0x6719U, 0xB1A7U, 0xE892U, 0x03CDU, 0x5AF8U, 0xB63DU, 0xEF08U, 0x0457U, 0x5D62U, 0x8BDCU, 0xD2E9U, 0x39B6U, 0x6083U, 0xCDFFU, 0x94CAU, 0x7F95U, 0x26A0U, @@ -46,12 +46,30 @@ const uint16_t CRC_TABLE[] = {0x0000U, 0x5935U, 0xB26AU, 0xEB5FU, 0x3DE1U, 0x64D 0xAC02U, 0xF537U, 0x2389U, 0x7ABCU, 0x91E3U, 0xC8D6U, 0x65AAU, 0x3C9FU, 0xD7C0U, 0x8EF5U, 0x584BU, 0x017EU, 0xEA21U, 0xB314U}; -bool CM17CRC::checkCRC(const unsigned char* in, unsigned int nBytes) +const uint8_t CRC4_TABLE[] = { + 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, + 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, + 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, + 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2, 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, + 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, + 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, + 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, + 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, + 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, + 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, + 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, + 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, + 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, + 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, + 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, + 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2}; + +bool CM17CRC::checkCRC16(const unsigned char* in, unsigned int nBytes) { assert(in != NULL); assert(nBytes > 2U); - uint16_t crc = createCRC(in, nBytes - 2U); + uint16_t crc = createCRC16(in, nBytes - 2U); uint8_t temp[2U]; temp[0U] = (crc >> 8) & 0xFFU; @@ -60,26 +78,67 @@ bool CM17CRC::checkCRC(const unsigned char* in, unsigned int nBytes) return temp[0U] == in[nBytes - 2U] && temp[1U] == in[nBytes - 1U]; } -void CM17CRC::encodeCRC(unsigned char* in, unsigned int nBytes) +void CM17CRC::encodeCRC16(unsigned char* in, unsigned int nBytes) { assert(in != NULL); assert(nBytes > 2U); - uint16_t crc = createCRC(in, nBytes - 2U); + uint16_t crc = createCRC16(in, nBytes - 2U); in[nBytes - 2U] = (crc >> 8) & 0xFFU; in[nBytes - 1U] = (crc >> 0) & 0xFFU; } -uint16_t CM17CRC::createCRC(const unsigned char* in, unsigned int nBytes) +uint16_t CM17CRC::createCRC16(const unsigned char* in, unsigned int nBytes) { assert(in != NULL); uint16_t crc = 0xFFFFU; for (unsigned int i = 0U; i < nBytes; i++) - crc = (crc << 8) ^ CRC_TABLE[((crc >> 8) ^ uint16_t(in[i])) & 0x00FFU]; + crc = (crc << 8) ^ CRC16_TABLE[((crc >> 8) ^ uint16_t(in[i])) & 0x00FFU]; return crc; } +bool CM17CRC::checkCRC8(unsigned char* in, unsigned int nBytes) +{ + assert(in != NULL); + assert(nBytes > 1U); + + uint8_t save = in[nBytes - 1U] & 0x0FU; + + // Mask out the 4-bit CRC location + in[nBytes - 1U] &= 0xF0U; + + uint8_t crc = createCRC8(in, nBytes); + + // Restore the original CRC + in[nBytes - 1U] |= save; + + return save == crc; +} + +void CM17CRC::encodeCRC8(unsigned char* in, unsigned int nBytes) +{ + assert(in != NULL); + assert(nBytes > 1U); + + in[nBytes - 1U] &= 0xF0U; + + uint8_t crc = createCRC8(in, nBytes); + + in[nBytes - 1U] |= crc & 0x0FU; +} + +uint8_t CM17CRC::createCRC8(const unsigned char* in, unsigned int nBytes) +{ + assert(in != NULL); + + uint8_t crc = 0x0FU; + + for (unsigned int i = 0U; i < nBytes; i++) + crc = CRC4_TABLE[crc ^ in[i]]; + + return crc; +} diff --git a/M17CRC.h b/M17CRC.h index 22c8f31f1..5bc33bb35 100644 --- a/M17CRC.h +++ b/M17CRC.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -24,11 +24,15 @@ class CM17CRC { public: - static bool checkCRC(const unsigned char* in, unsigned int nBytes); - static void encodeCRC(unsigned char* in, unsigned int nBytes); + static bool checkCRC16(const unsigned char* in, unsigned int nBytes); + static void encodeCRC16(unsigned char* in, unsigned int nBytes); + + static bool checkCRC8(unsigned char* in, unsigned int nBytes); + static void encodeCRC8(unsigned char* in, unsigned int nBytes); private: - static uint16_t createCRC(const unsigned char* in, unsigned int nBytes); + static uint16_t createCRC16(const unsigned char* in, unsigned int nBytes); + static uint8_t createCRC8(const unsigned char* in, unsigned int nBytes); }; #endif diff --git a/M17Control.cpp b/M17Control.cpp index 37e2c2e98..10238ce21 100644 --- a/M17Control.cpp +++ b/M17Control.cpp @@ -169,7 +169,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char frame[M17_LSF_LENGTH_BYTES]; conv.decodeLinkSetup(data + 2U + M17_SYNC_LENGTH_BYTES, frame); - bool valid = CM17CRC::checkCRC(frame, M17_LSF_LENGTH_BYTES); + bool valid = CM17CRC::checkCRC16(frame, M17_LSF_LENGTH_BYTES); if (valid) { m_rfLSF.setLinkSetup(frame); @@ -196,6 +196,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) return true; } else { m_rfState = RS_RF_LATE_ENTRY; + return false; } } @@ -216,6 +217,9 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich); + if (!CM17CRC::checkCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES)) + return false; + m_rfLSFn = (lich4 >> 5) & 0x07U; m_rfLSF.setFragment(lich, m_rfLSFn); @@ -253,7 +257,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char frame[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES]; conv.decodeData(data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES, frame); - bool valid = CM17CRC::checkCRC(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); + bool valid = CM17CRC::checkCRC16(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); if (valid) { m_rfFN = (frame[0U] << 8) + (frame[1U] << 0); } else { @@ -279,7 +283,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) } // Add the CRC - CM17CRC::encodeCRC(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); + CM17CRC::encodeCRC16(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); } unsigned char rfData[2U + M17_FRAME_LENGTH_BYTES]; @@ -293,12 +297,15 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; m_rfLSF.getFragment(lich, m_rfLSFn); + // Add the fragment number + lich[5U] = (m_rfLSFn & 0x07U) << 5; + + // Add the CRC + CM17CRC::encodeCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the fragment number - frag4 |= (m_rfLSFn & 0x07U) << 5; - // Add Golay to the LICH fragment here unsigned int lich1 = CGolay24128::encode24128(frag1); unsigned int lich2 = CGolay24128::encode24128(frag2); @@ -362,11 +369,9 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len) LogMessage("M17, received RF end of transmission from %s to %s, %.1f seconds, BER: %.1f%%", source.c_str(), dest.c_str(), float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits)); writeEndRF(); } - - return true; } - return false; + return true; } unsigned int CM17Control::readModem(unsigned char* data) @@ -511,15 +516,18 @@ void CM17Control::writeNetwork() m_netFrames++; // Add the fragment LICH - unsigned char lich[M17_LSF_FRAGMENT_LENGTH_BYTES]; + unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES]; m_netLSF.getFragment(lich, m_netLSFn); + // Add the fragment number + lich[5U] = (m_netLSFn & 0x07U) << 5; + + // Add the CRC + CM17CRC::encodeCRC8(lich, M17_LICH_FRAGMENT_LENGTH_BYTES); + unsigned int frag1, frag2, frag3, frag4; CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4); - // Add the fragment number - frag4 |= (m_netLSFn & 0x07U) << 4; - // Add Golay to the LICH fragment here unsigned int lich1 = CGolay24128::encode24128(frag1); unsigned int lich2 = CGolay24128::encode24128(frag2); @@ -533,7 +541,7 @@ void CM17Control::writeNetwork() ::memcpy(payload, netData + 28U, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES); // Add the CRC - CM17CRC::encodeCRC(payload, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); + CM17CRC::encodeCRC16(payload, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES); // Add the Convolution FEC CM17Convolution conv; diff --git a/M17LSF.cpp b/M17LSF.cpp index 4d48f40c3..6caa1c48d 100644 --- a/M17LSF.cpp +++ b/M17LSF.cpp @@ -162,7 +162,7 @@ void CM17LSF::getLinkSetup(unsigned char* data) const ::memcpy(data, m_lsf, M17_LSF_LENGTH_BYTES); - CM17CRC::encodeCRC(data, M17_LSF_LENGTH_BYTES); + CM17CRC::encodeCRC16(data, M17_LSF_LENGTH_BYTES); } void CM17LSF::setLinkSetup(const unsigned char* data) @@ -171,14 +171,14 @@ void CM17LSF::setLinkSetup(const unsigned char* data) ::memcpy(m_lsf, data, M17_LSF_LENGTH_BYTES); - m_valid = CM17CRC::checkCRC(m_lsf, M17_LSF_LENGTH_BYTES); + m_valid = CM17CRC::checkCRC16(m_lsf, M17_LSF_LENGTH_BYTES); } void CM17LSF::getFragment(unsigned char* data, unsigned int n) const { assert(data != NULL); - CM17CRC::encodeCRC(m_lsf, M17_LSF_LENGTH_BYTES); + CM17CRC::encodeCRC16(m_lsf, M17_LSF_LENGTH_BYTES); ::memcpy(data, m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), M17_LSF_FRAGMENT_LENGTH_BYTES); } @@ -189,5 +189,5 @@ void CM17LSF::setFragment(const unsigned char* data, unsigned int n) ::memcpy(m_lsf + (n * M17_LSF_FRAGMENT_LENGTH_BYTES), data, M17_LSF_FRAGMENT_LENGTH_BYTES); - m_valid = CM17CRC::checkCRC(m_lsf, M17_LSF_LENGTH_BYTES); + m_valid = CM17CRC::checkCRC16(m_lsf, M17_LSF_LENGTH_BYTES); }