diff --git a/Makefile b/Makefile index 1db893d0..904e221c 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ HOST_OBJECTS = \ lookups/RSSIInterpolator.o \ lookups/TalkgroupIdLookup.o \ nxdn/acl/AccessControl.o \ + nxdn/channel/CAC.o \ nxdn/channel/FACCH1.o \ nxdn/channel/LICH.o \ nxdn/channel/SACCH.o \ diff --git a/edac/CRC.cpp b/edac/CRC.cpp index 15d46fda..43e00c86 100644 --- a/edac/CRC.cpp +++ b/edac/CRC.cpp @@ -484,17 +484,17 @@ uint16_t CRC::crc9(const uint8_t* in, uint32_t bitLength) /// Check 6-bit CRC. /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// True, if CRC is valid, otherwise false. -bool CRC::checkCRC6(const uint8_t* in, uint32_t length) +bool CRC::checkCRC6(const uint8_t* in, uint32_t bitLength) { assert(in != NULL); - uint8_t crc = createCRC6(in, length); + uint8_t crc = createCRC6(in, bitLength); uint8_t temp[1U]; temp[0U] = 0x00U; - uint32_t j = length; + uint32_t j = bitLength; for (uint32_t i = 2U; i < 8U; i++, j++) { bool b = READ_BIT(in, j); WRITE_BIT(temp, i, b); @@ -502,7 +502,7 @@ bool CRC::checkCRC6(const uint8_t* in, uint32_t length) #if DEBUG_CRC uint32_t inCrc = temp[0U]; - LogDebug(LOG_HOST, "CRC::checkCRC6(), crc = $%08X, in = $%08X, len = %u", crc32, inCrc, length); + LogDebug(LOG_HOST, "CRC::checkCRC6(), crc = $%08X, in = $%08X, bitlen = %u", crc32, inCrc, bitLength); #endif return crc == temp[0U]; @@ -512,23 +512,23 @@ bool CRC::checkCRC6(const uint8_t* in, uint32_t length) /// Encode 6-bit CRC. /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// True, if CRC is valid, otherwise false. -void CRC::addCRC6(uint8_t* in, uint32_t length) +void CRC::addCRC6(uint8_t* in, uint32_t bitLength) { assert(in != NULL); uint8_t crc[1U]; - crc[0U] = createCRC6(in, length); + crc[0U] = createCRC6(in, bitLength); - uint32_t n = length; + uint32_t n = bitLength; for (uint32_t i = 2U; i < 8U; i++, n++) { bool b = READ_BIT(crc, i); WRITE_BIT(in, n, b); } #if DEBUG_CRC - LogDebug(LOG_HOST, "CRC::addCRC6(), crc = $%04X, len = %u", crc[0U], length); + LogDebug(LOG_HOST, "CRC::addCRC6(), crc = $%04X, bitlen = %u", crc[0U], bitLength); #endif } @@ -536,13 +536,13 @@ void CRC::addCRC6(uint8_t* in, uint32_t length) /// Check 12-bit CRC. /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// True, if CRC is valid, otherwise false. -bool CRC::checkCRC12(const uint8_t* in, uint32_t length) +bool CRC::checkCRC12(const uint8_t* in, uint32_t bitLength) { assert(in != NULL); - uint16_t crc = createCRC12(in, length); + uint16_t crc = createCRC12(in, bitLength); uint8_t temp1[2U]; temp1[0U] = (crc >> 8) & 0xFFU; temp1[1U] = (crc >> 0) & 0xFFU; @@ -550,15 +550,15 @@ bool CRC::checkCRC12(const uint8_t* in, uint32_t length) uint8_t temp2[2U]; temp2[0U] = 0x00U; temp2[1U] = 0x00U; - uint32_t j = length; + uint32_t j = bitLength; for (uint32_t i = 4U; i < 16U; i++, j++) { bool b = READ_BIT(in, j); WRITE_BIT(temp2, i, b); } #if DEBUG_CRC - uint16_t inCrc = (temp2[length - 2U] << 8) | (temp2[length - 1U] << 0); - LogDebug(LOG_HOST, "CRC:checkCRC12(), crc = $%04X, in = $%04X, len = %u", crc, inCrc, length); + uint16_t inCrc = (temp2[0U] << 8) | (temp2[1U] << 0); + LogDebug(LOG_HOST, "CRC:checkCRC12(), crc = $%04X, in = $%04X, bitlen = %u", crc, inCrc, bitLength); #endif return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U]; @@ -568,26 +568,26 @@ bool CRC::checkCRC12(const uint8_t* in, uint32_t length) /// Encode 12-bit CRC. /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// True, if CRC is valid, otherwise false. -void CRC::addCRC12(uint8_t* in, uint32_t length) +void CRC::addCRC12(uint8_t* in, uint32_t bitLength) { assert(in != NULL); - uint16_t crc = createCRC12(in, length); + uint16_t crc = createCRC12(in, bitLength); uint8_t temp[2U]; temp[0U] = (crc >> 8) & 0xFFU; temp[1U] = (crc >> 0) & 0xFFU; - uint32_t n = length; + uint32_t n = bitLength; for (uint32_t i = 4U; i < 16U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(in, n, b); } #if DEBUG_CRC - LogDebug(LOG_HOST, "CRC::addCRC12(), crc = $%04X, len = %u", crc, length); + LogDebug(LOG_HOST, "CRC::addCRC12(), crc = $%04X, bitlen = %u", crc, bitLength); #endif } @@ -595,13 +595,13 @@ void CRC::addCRC12(uint8_t* in, uint32_t length) /// Check 15-bit CRC. /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// True, if CRC is valid, otherwise false. -bool CRC::checkCRC15(const uint8_t* in, uint32_t length) +bool CRC::checkCRC15(const uint8_t* in, uint32_t bitLength) { assert(in != NULL); - uint16_t crc = createCRC15(in, length); + uint16_t crc = createCRC15(in, bitLength); uint8_t temp1[2U]; temp1[0U] = (crc >> 8) & 0xFFU; temp1[1U] = (crc >> 0) & 0xFFU; @@ -609,15 +609,15 @@ bool CRC::checkCRC15(const uint8_t* in, uint32_t length) uint8_t temp2[2U]; temp2[0U] = 0x00U; temp2[1U] = 0x00U; - uint32_t j = length; + uint32_t j = bitLength; for (uint32_t i = 1U; i < 16U; i++, j++) { bool b = READ_BIT(in, j); WRITE_BIT(temp2, i, b); } #if DEBUG_CRC - uint16_t inCrc = (temp2[length - 2U] << 8) | (temp2[length - 1U] << 0); - LogDebug(LOG_HOST, "CRC:checkCRC15(), crc = $%04X, in = $%04X, len = %u", crc, inCrc, length); + uint16_t inCrc = (temp2[0U] << 8) | (temp2[1U] << 0); + LogDebug(LOG_HOST, "CRC:checkCRC15(), crc = $%04X, in = $%04X, bitlen = %u", crc, inCrc, bitLength); #endif return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U]; @@ -627,26 +627,85 @@ bool CRC::checkCRC15(const uint8_t* in, uint32_t length) /// Encode 15-bit CRC. /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// True, if CRC is valid, otherwise false. -void CRC::addCRC15(uint8_t* in, uint32_t length) +void CRC::addCRC15(uint8_t* in, uint32_t bitLength) { assert(in != NULL); - uint16_t crc = createCRC15(in, length); + uint16_t crc = createCRC15(in, bitLength); uint8_t temp[2U]; temp[0U] = (crc >> 8) & 0xFFU; temp[1U] = (crc >> 0) & 0xFFU; - uint32_t n = length; + uint32_t n = bitLength; for (uint32_t i = 1U; i < 16U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(in, n, b); } #if DEBUG_CRC - LogDebug(LOG_HOST, "CRC::addCRC15(), crc = $%04X, len = %u", crc, length); + LogDebug(LOG_HOST, "CRC::addCRC15(), crc = $%04X, bitlen = %u", crc, bitLength); +#endif +} + +/// +/// Check 16-bit CRC. +/// +/// Input byte array. +/// Length of byte array in bits. +/// True, if CRC is valid, otherwise false. +bool CRC::checkCRC16(const uint8_t* in, uint32_t bitLength) +{ + assert(in != NULL); + + uint16_t crc = createCRC15(in, bitLength); + uint8_t temp1[2U]; + temp1[0U] = (crc >> 8) & 0xFFU; + temp1[1U] = (crc >> 0) & 0xFFU; + + uint8_t temp2[2U]; + temp2[0U] = 0x00U; + temp2[1U] = 0x00U; + uint32_t j = bitLength; + for (uint32_t i = 1U; i < 16U; i++, j++) { + bool b = READ_BIT(in, j); + WRITE_BIT(temp2, i, b); + } + +#if DEBUG_CRC + uint16_t inCrc = (temp2[0U] << 8) | (temp2[1U] << 0); + LogDebug(LOG_HOST, "CRC:checkCRC16(), crc = $%04X, in = $%04X, bitlen = %u", crc, inCrc, bitLength); +#endif + + return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U]; +} + +/// +/// Encode 16-bit CRC. +/// +/// Input byte array. +/// Length of byte array in bits. +/// True, if CRC is valid, otherwise false. +void CRC::addCRC16(uint8_t* in, uint32_t bitLength) +{ + assert(in != NULL); + + uint16_t crc = createCRC15(in, bitLength); + + uint8_t temp[2U]; + temp[0U] = (crc >> 8) & 0xFFU; + temp[1U] = (crc >> 0) & 0xFFU; + + uint32_t n = bitLength; + for (uint32_t i = 1U; i < 16U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(in, n, b); + } + +#if DEBUG_CRC + LogDebug(LOG_HOST, "CRC::addCRC16(), crc = $%04X, bitlen = %u", crc, bitLength); #endif } @@ -658,13 +717,13 @@ void CRC::addCRC15(uint8_t* in, uint32_t length) /// /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// -uint8_t CRC::createCRC6(const uint8_t* in, uint32_t length) +uint8_t CRC::createCRC6(const uint8_t* in, uint32_t bitLength) { uint8_t crc = 0x3FU; - for (uint32_t i = 0U; i < length; i++) { + for (uint32_t i = 0U; i < bitLength; i++) { bool bit1 = READ_BIT(in, i) != 0x00U; bool bit2 = (crc & 0x20U) == 0x20U; @@ -681,13 +740,13 @@ uint8_t CRC::createCRC6(const uint8_t* in, uint32_t length) /// /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// -uint16_t CRC::createCRC12(const uint8_t* in, uint32_t length) +uint16_t CRC::createCRC12(const uint8_t* in, uint32_t bitLength) { uint16_t crc = 0x0FFFU; - for (uint32_t i = 0U; i < length; i++) { + for (uint32_t i = 0U; i < bitLength; i++) { bool bit1 = READ_BIT(in, i) != 0x00U; bool bit2 = (crc & 0x0800U) == 0x0800U; @@ -704,13 +763,13 @@ uint16_t CRC::createCRC12(const uint8_t* in, uint32_t length) /// /// /// Input byte array. -/// Length of byte array. +/// Length of byte array in bits. /// -uint16_t CRC::createCRC15(const uint8_t* in, uint32_t length) +uint16_t CRC::createCRC15(const uint8_t* in, uint32_t bitLength) { uint16_t crc = 0x7FFFU; - for (uint32_t i = 0U; i < length; i++) { + for (uint32_t i = 0U; i < bitLength; i++) { bool bit1 = READ_BIT(in, i) != 0x00U; bool bit2 = (crc & 0x4000U) == 0x4000U; @@ -722,3 +781,26 @@ uint16_t CRC::createCRC15(const uint8_t* in, uint32_t length) return crc & 0x7FFFU; } + +/// +/// +/// +/// Input byte array. +/// Length of byte array in bits. +/// +uint16_t CRC::createCRC16(const uint8_t* in, uint32_t bitLength) +{ + uint16_t crc = 0xFFFFU; + + for (uint32_t i = 0U; i < bitLength; i++) { + bool bit1 = READ_BIT(in, i) != 0x00U; + bool bit2 = (crc & 0x8000U) == 0x8000U; + + crc <<= 1; + + if (bit1 ^ bit2) + crc ^= 0x1021U; + } + + return crc & 0xFFFFU; +} diff --git a/edac/CRC.h b/edac/CRC.h index ee88b5ee..cd74577f 100644 --- a/edac/CRC.h +++ b/edac/CRC.h @@ -69,27 +69,34 @@ namespace edac static uint16_t crc9(const uint8_t* in, uint32_t bitLength); /// Check 6-bit CRC. - static bool checkCRC6(const uint8_t* in, uint32_t length); + static bool checkCRC6(const uint8_t* in, uint32_t bitLength); /// Encode 6-bit CRC. - static void addCRC6(uint8_t* in, uint32_t length); + static void addCRC6(uint8_t* in, uint32_t bitLength); /// Check 12-bit CRC. - static bool checkCRC12(const uint8_t* in, uint32_t length); + static bool checkCRC12(const uint8_t* in, uint32_t bitLength); /// Encode 12-bit CRC. - static void addCRC12(uint8_t* in, uint32_t length); + static void addCRC12(uint8_t* in, uint32_t bitLength); /// Check 15-bit CRC. - static bool checkCRC15(const uint8_t* in, uint32_t length); + static bool checkCRC15(const uint8_t* in, uint32_t bitLength); /// Encode 15-bit CRC. - static void addCRC15(uint8_t* in, uint32_t length); + static void addCRC15(uint8_t* in, uint32_t bitLength); + + /// Check 16-bit CRC-CCITT. + static bool checkCRC16(const uint8_t* in, uint32_t bitLength); + /// Encode 15-bit CRC. + static void addCRC16(uint8_t* in, uint32_t bitLength); private: /// - static uint8_t createCRC6(const uint8_t* in, uint32_t length); + static uint8_t createCRC6(const uint8_t* in, uint32_t bitLength); + /// + static uint16_t createCRC12(const uint8_t* in, uint32_t bitLength); /// - static uint16_t createCRC12(const uint8_t* in, uint32_t length); + static uint16_t createCRC15(const uint8_t* in, uint32_t bitLength); /// - static uint16_t createCRC15(const uint8_t* in, uint32_t length); + static uint16_t createCRC16(const uint8_t* in, uint32_t bitLength); }; } // namespace edac diff --git a/nxdn/NXDNDefines.h b/nxdn/NXDNDefines.h index a23d2743..3c397556 100644 --- a/nxdn/NXDNDefines.h +++ b/nxdn/NXDNDefines.h @@ -57,12 +57,59 @@ namespace nxdn const uint32_t NXDN_LICH_LENGTH_BITS = 16U; const uint32_t NXDN_LICH_LENGTH_BYTES = NXDN_LICH_LENGTH_BITS / 8U; - const uint32_t NXDN_SACCH_LENGTH_BITS = 60U; - const uint32_t NXDN_SACCH_LENGTH_BYTES = NXDN_SACCH_LENGTH_BITS / 8U; - const uint32_t NXDN_FACCH1_LENGTH_BITS = 144U; + const uint32_t NXDN_SACCH_FEC_LENGTH_BITS = 60U; // Puncture and Interleave Length + const uint32_t NXDN_SACCH_FEC_LENGTH_BYTES = (NXDN_SACCH_FEC_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_SACCH_FEC_CONV_LENGTH_BITS = 72U; // Convolution Length + const uint32_t NXDN_SACCH_FEC_CONV_LENGTH_BYTES = NXDN_SACCH_FEC_CONV_LENGTH_BITS / 8U; + const uint32_t NXDN_SACCH_LENGTH_BITS = 36U; // Data + CRC-6 + 4-bit NULL + const uint32_t NXDN_SACCH_LENGTH_BYTES = (NXDN_SACCH_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_SACCH_CRC_BITS = 26U; // Data + + const uint32_t NXDN_FACCH1_FEC_LENGTH_BITS = 144U; // Puncture and Interleave Length + const uint32_t NXDN_FACCH1_FEC_LENGTH_BYTES = NXDN_FACCH1_FEC_LENGTH_BITS / 8U; + const uint32_t NXDN_FACCH1_FEC_CONV_LENGTH_BITS = 192U; // Convolution Length + const uint32_t NXDN_FACCH1_FEC_CONV_LENGTH_BYTES = NXDN_FACCH1_FEC_CONV_LENGTH_BITS / 8U; + const uint32_t NXDN_FACCH1_LENGTH_BITS = 96U; // Data + CRC-12 + 4-bit NULL const uint32_t NXDN_FACCH1_LENGTH_BYTES = NXDN_FACCH1_LENGTH_BITS / 8U; - const uint32_t NXDN_FACCH2_LENGTH_BITS = 348U; - const uint32_t NXDN_FACCH2_LENGTH_BYTES = NXDN_FACCH2_LENGTH_BITS / 8U; + const uint32_t NXDN_FACCH1_CRC_BITS = 80U; // Data + + const uint32_t NXDN_UDCH_FEC_LENGTH_BITS = 348U; // Puncture and Interleave Length + const uint32_t NXDN_UDCH_FEC_LENGTH_BYTES = (NXDN_UDCH_FEC_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_UDCH_FEC_CONV_LENGTH_BITS = 406U; // Convolution Length + const uint32_t NXDN_UDCH_FEC_CONV_LENGTH_BYTES = (NXDN_UDCH_FEC_CONV_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_UDCH_LENGTH_BITS = 203U; // Data + CRC-15 + 4-bit NULL + const uint32_t NXDN_UDCH_LENGTH_BYTES = (NXDN_UDCH_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDH_UDCH_CRC_BITS = 184U; // Data + + const uint32_t NXDN_CAC_LENGTH_BITS = 384U; + const uint32_t NXDN_CAC_LENGTH_BYTES = (NXDN_CAC_LENGTH_BITS / 8U); + + const uint32_t NXDN_CAC_OUT_FEC_LENGTH_BITS = 300U; // Puncture and Interleave Length + const uint32_t NXDN_CAC_OUT_FEC_LENGTH_BYTES = (NXDN_CAC_OUT_FEC_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_CAC_OUT_FEC_CONV_LENGTH_BITS = 350U; // Convolution Length + const uint32_t NXDN_CAC_OUT_FEC_CONV_LENGTH_BYTES = (NXDN_CAC_OUT_FEC_CONV_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_CAC_OUT_LENGTH_BITS = 175U; // Data + CRC-16 + 4-bit NULL + const uint32_t NXDN_CAC_OUT_LENGTH_BYTES = (NXDN_CAC_OUT_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_CAC_OUT_CRC_BITS = 155U; // Data + + const uint32_t NXDN_CAC_IN_FEC_LENGTH_BITS = 252U; // Puncture and Interleave Length + const uint32_t NXDN_CAC_IN_FEC_LENGTH_BYTES = (NXDN_CAC_IN_FEC_LENGTH_BITS / 8U) + 1U; + + const uint32_t NXDN_CAC_LONG_IN_FEC_CONV_LENGTH_BITS = 312U; // Convolution Length + const uint32_t NXDN_CAC_LONG_IN_FEC_CONV_LENGTH_BYTES = NXDN_CAC_LONG_IN_FEC_CONV_LENGTH_BITS / 8U; + const uint32_t NXDN_CAC_LONG_IN_LENGTH_BITS = 156U; // Data + CRC-16 + 4-bit NULL + const uint32_t NXDN_CAC_LONG_IN_LENGTH_BYTES = (NXDN_CAC_LONG_IN_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_CAC_LONG_IN_CRC_BITS = 136U; // Data + + const uint32_t NXDN_CAC_SHORT_IN_FEC_LENGTH_BITS = 252U; // Interleave Length + const uint32_t NXDN_CAC_SHORT_IN_FEC_LENGTH_BYTES = (NXDN_CAC_SHORT_IN_FEC_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_CAC_SHORT_IN_LENGTH_BITS = 126U; // Data + CRC-16 + 4-bit NULL + const uint32_t NXDN_CAC_SHORT_IN_LENGTH_BYTES = (NXDN_CAC_SHORT_IN_LENGTH_BITS / 8U) + 1U; + const uint32_t NXDN_CAC_SHORT_IN_CRC_BITS = 106U; // Data + + const uint32_t NXDN_E_POST_FIELD_BITS = 24U; + + const uint8_t POST_FIELD[] = { 0x57U, 0x75U, 0xFDU }; const uint32_t NXDN_FSW_LICH_SACCH_LENGTH_BITS = NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS; const uint32_t NXDN_FSW_LICH_SACCH_LENGTH_BYTES = NXDN_FSW_LICH_SACCH_LENGTH_BITS / 8U; @@ -72,11 +119,19 @@ namespace nxdn const uint8_t NXDN_LICH_RFCT_RDCH = 2U; const uint8_t NXDN_LICH_RFCT_RTCH_C = 3U; + const uint8_t NXDN_LICH_CAC_OUTBOUND = 0U; + const uint8_t NXDN_LICH_CAC_INBOUND_LONG = 1U; + const uint8_t NXDN_LICH_CAC_INBOUND_SHORT = 3U; + const uint8_t NXDN_LICH_USC_SACCH_NS = 0U; const uint8_t NXDN_LICH_USC_UDCH = 1U; const uint8_t NXDN_LICH_USC_SACCH_SS = 2U; const uint8_t NXDN_LICH_USC_SACCH_SS_IDLE = 3U; + const uint8_t NXDN_LICH_DATA_NORMAL = 0U; + const uint8_t NXDN_LICH_DATA_IDLE = 1U; + const uint8_t NXDN_LICH_DATA_COMMON = 2U; + const uint8_t NXDN_LICH_STEAL_NONE = 3U; const uint8_t NXDN_LICH_STEAL_FACCH1_2 = 2U; const uint8_t NXDN_LICH_STEAL_FACCH1_1 = 1U; diff --git a/nxdn/channel/CAC.cpp b/nxdn/channel/CAC.cpp new file mode 100644 index 00000000..6123f56d --- /dev/null +++ b/nxdn/channel/CAC.cpp @@ -0,0 +1,356 @@ +/** +* 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 +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 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 "nxdn/channel/CAC.h" +#include "nxdn/Convolution.h" +#include "nxdn/NXDNDefines.h" +#include "edac/CRC.h" +#include "Log.h" +#include "Utils.h" + +using namespace edac; +using namespace nxdn; +using namespace nxdn::channel; + +#include +#include +#include + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const uint32_t INTERLEAVE_TABLE_OUT[] = { + 0U, 25U, 50U, 75U, 100U, 125U, 150U, 175U, 200U, 225U, 250U, 275U, + 1U, 26U, 51U, 76U, 101U, 126U, 151U, 176U, 201U, 226U, 251U, 276U, + 2U, 27U, 52U, 77U, 102U, 127U, 152U, 177U, 202U, 227U, 252U, 277U, + 3U, 28U, 53U, 78U, 103U, 128U, 153U, 178U, 203U, 228U, 253U, 278U, + 4U, 29U, 54U, 79U, 104U, 129U, 154U, 179U, 204U, 229U, 254U, 279U, + 5U, 30U, 55U, 80U, 105U, 130U, 155U, 180U, 205U, 230U, 255U, 280U, + 6U, 31U, 56U, 81U, 106U, 131U, 156U, 181U, 206U, 231U, 256U, 281U, + 7U, 32U, 57U, 82U, 107U, 132U, 157U, 182U, 207U, 232U, 257U, 282U, + 8U, 33U, 58U, 83U, 108U, 133U, 158U, 183U, 208U, 233U, 258U, 283U, + 9U, 34U, 59U, 84U, 109U, 134U, 159U, 184U, 209U, 234U, 259U, 284U, + 10U, 35U, 60U, 85U, 110U, 135U, 160U, 185U, 210U, 235U, 260U, 285U, + 11U, 36U, 61U, 86U, 111U, 136U, 161U, 186U, 211U, 236U, 261U, 286U, + 12U, 37U, 62U, 87U, 112U, 137U, 162U, 187U, 212U, 237U, 262U, 287U, + 13U, 38U, 63U, 88U, 113U, 138U, 163U, 188U, 213U, 238U, 263U, 288U, + 14U, 39U, 64U, 89U, 114U, 139U, 164U, 189U, 214U, 239U, 264U, 289U, + 15U, 40U, 65U, 90U, 115U, 140U, 165U, 190U, 215U, 240U, 265U, 290U, + 16U, 41U, 66U, 91U, 116U, 141U, 166U, 191U, 216U, 241U, 266U, 291U, + 17U, 42U, 67U, 92U, 117U, 142U, 167U, 192U, 217U, 242U, 267U, 292U, + 18U, 43U, 68U, 93U, 118U, 143U, 168U, 193U, 218U, 243U, 268U, 293U, + 19U, 44U, 69U, 94U, 119U, 144U, 169U, 194U, 219U, 244U, 269U, 294U, + 20U, 45U, 70U, 95U, 120U, 145U, 170U, 195U, 220U, 245U, 270U, 295U, + 21U, 46U, 71U, 96U, 121U, 146U, 171U, 196U, 221U, 246U, 271U, 296U, + 22U, 47U, 72U, 97U, 122U, 147U, 172U, 197U, 222U, 247U, 272U, 297U, + 23U, 48U, 73U, 98U, 123U, 148U, 173U, 198U, 223U, 248U, 273U, 298U, + 24U, 49U, 74U, 99U, 124U, 149U, 174U, 199U, 224U, 249U, 274U, 299U }; + +const uint32_t INTERLEAVE_TABLE_IN[] = { + 0U, 21U, 42U, 63U, 84U, 105U, 126U, 147U, 168U, 189U, 210U, 231U, + 1U, 22U, 43U, 64U, 85U, 106U, 127U, 148U, 169U, 190U, 211U, 232U, + 2U, 23U, 44U, 65U, 86U, 107U, 128U, 149U, 170U, 191U, 212U, 233U, + 3U, 24U, 45U, 66U, 87U, 108U, 129U, 150U, 171U, 192U, 213U, 234U, + 4U, 25U, 46U, 67U, 88U, 109U, 130U, 151U, 172U, 193U, 214U, 235U, + 5U, 26U, 47U, 68U, 89U, 110U, 131U, 152U, 173U, 194U, 215U, 236U, + 6U, 27U, 48U, 69U, 90U, 111U, 132U, 153U, 174U, 195U, 216U, 237U, + 7U, 28U, 49U, 70U, 91U, 112U, 133U, 154U, 175U, 196U, 217U, 238U, + 8U, 29U, 50U, 71U, 92U, 113U, 134U, 155U, 176U, 197U, 218U, 239U, + 9U, 30U, 51U, 72U, 93U, 114U, 135U, 156U, 177U, 198U, 219U, 240U, + 10U, 31U, 52U, 73U, 94U, 115U, 136U, 157U, 178U, 199U, 220U, 241U, + 11U, 32U, 53U, 74U, 95U, 116U, 137U, 158U, 179U, 200U, 221U, 242U, + 12U, 33U, 54U, 75U, 96U, 117U, 138U, 159U, 180U, 201U, 222U, 243U, + 13U, 34U, 55U, 76U, 97U, 118U, 139U, 160U, 181U, 202U, 223U, 244U, + 14U, 35U, 56U, 77U, 98U, 119U, 140U, 161U, 182U, 203U, 224U, 245U, + 15U, 36U, 57U, 78U, 99U, 120U, 141U, 162U, 183U, 204U, 225U, 246U, + 16U, 37U, 58U, 79U, 100U, 121U, 142U, 163U, 184U, 205U, 226U, 247U, + 17U, 38U, 59U, 80U, 101U, 122U, 143U, 164U, 185U, 206U, 227U, 248U, + 18U, 39U, 60U, 81U, 102U, 123U, 144U, 165U, 186U, 207U, 228U, 249U, + 19U, 40U, 61U, 82U, 103U, 124U, 145U, 166U, 187U, 208U, 229U, 250U, + 20U, 41U, 62U, 83U, 104U, 125U, 146U, 167U, 188U, 209U, 230U, 251U }; + +const uint32_t PUNCTURE_LIST_OUT[] = { + 3U, 11U, 17U, 25U, 31U, 39U, 45U, 53U, 59U, 67U, + 73U, 81U, 87U, 95U, 101U, 109U, 115U, 123U, 129U, 137U, + 143U, 151U, 157U, 165U, 171U, 179U, 185U, 193U, 199U, 207U, + 213U, 221U, 227U, 235U, 241U, 249U, 255U, 263U, 269U, 277U, + 283U, 291U, 297U, 305U, 311U, 319U, 325U, 333U, 339U, 347U }; + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/// +/// Initializes a new instance of the CAC class. +/// +CAC::CAC() : + m_verbose(false), + m_ran(0U), + m_data(NULL) +{ + m_data = new uint8_t[NXDN_CAC_OUT_LENGTH_BYTES]; +} + +/// +/// Initializes a copy instance of the CAC class. +/// +/// +CAC::CAC(const CAC& data) : + m_verbose(false), + m_ran(0U), + m_data(NULL) +{ + copy(data); +} + +/// +/// Finalizes a instance of CAC class. +/// +CAC::~CAC() +{ + delete[] m_data; +} + +/// +/// Equals operator. +/// +/// +/// +CAC& CAC::operator=(const CAC& data) +{ + if (&data != this) { + ::memcpy(m_data, data.m_data, NXDN_CAC_OUT_LENGTH_BYTES); + + m_verbose = data.m_verbose; + + m_ran = m_data[0U] & 0x3FU; + } + + return *this; +} + +/// +/// Decode a slow associated control channel. +/// +/// +/// True, if CAC was decoded, otherwise false. +bool CAC::decode(const uint8_t* data) +{ + assert(data != NULL); + + uint8_t buffer[NXDN_CAC_IN_FEC_LENGTH_BYTES + 1U]; + + // deinterleave + for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) { + uint32_t n = INTERLEAVE_TABLE_IN[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; + bool b = READ_BIT(data, n); + WRITE_BIT(buffer, i, b); + } + +#if DEBUG_NXDN_CAC + Utils::dump(2U, "CAC::decode(), CAC Raw", buffer, NXDN_CAC_IN_FEC_LENGTH_BYTES); +#endif + + // TODO TODO -- Long CAC Puncturing + + // decode convolution + Convolution conv; + conv.start(); + + uint32_t n = 0U; + for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_IN_LENGTH_BITS + 4U); i++) { + uint8_t s0 = buffer[n++]; + uint8_t s1 = buffer[n++]; + + conv.decode(s0, s1); + } + + conv.chainback(m_data, NXDN_CAC_SHORT_IN_LENGTH_BITS); + + if (m_verbose) { + Utils::dump(2U, "Decoded CAC", m_data, NXDN_CAC_SHORT_IN_LENGTH_BYTES); + } + + // check CRC-16 + bool ret = CRC::checkCRC16(m_data, NXDN_CAC_SHORT_IN_CRC_BITS); + if (!ret) { + LogError(LOG_NXDN, "SACCH::decode(), failed CRC-6 check"); + return false; + } + + // store recieved CRC-16 + uint8_t crc[2U]; + ::memset(crc, 0x00U, 2U); + + uint32_t j = NXDN_CAC_SHORT_IN_CRC_BITS; + for (uint32_t i = 1U; i < 16U; i++, j++) { + bool b = READ_BIT(m_data, j); + WRITE_BIT(crc, i, b); + } + + m_rxCRC = (crc[0U] << 8) | (crc[1U] << 0); + + m_ran = m_data[0U] & 0x3FU; + + return true; +} + +/// +/// Encode a slow associated control channel. +/// +/// +void CAC::encode(uint8_t* data) const +{ + assert(data != NULL); + + m_data[0U] &= 0xC0U; + m_data[0U] |= m_ran; + + uint8_t buffer[NXDN_CAC_OUT_LENGTH_BYTES]; + ::memset(buffer, 0x00U, NXDN_CAC_OUT_LENGTH_BYTES); + + for (uint32_t i = 0U; i < NXDN_CAC_OUT_CRC_BITS; i++) { + bool b = READ_BIT(m_data, i); + WRITE_BIT(buffer, i, b); + } + + CRC::addCRC16(buffer, NXDN_CAC_OUT_CRC_BITS); + + if (m_verbose) { + Utils::dump(2U, "Encoded CAC", buffer, NXDN_CAC_OUT_LENGTH_BYTES); + } + + // encode convolution + uint8_t convolution[NXDN_CAC_OUT_FEC_CONV_LENGTH_BYTES]; + Convolution conv; + conv.encode(buffer, convolution, NXDN_CAC_OUT_LENGTH_BITS); + +#if DEBUG_NXDN_CAC + Utils::dump(2U, "CAC::encode(), CAC Convolution", convolution, NXDN_CAC_OUT_FEC_CONV_LENGTH_BYTES); +#endif + + // puncture + uint8_t puncture[NXDN_CAC_OUT_FEC_LENGTH_BYTES]; + uint32_t n = 0U, index = 0U; + for (uint32_t i = 0U; i < NXDN_CAC_OUT_FEC_CONV_LENGTH_BITS; i++) { + if (i != PUNCTURE_LIST_OUT[index]) { + bool b = READ_BIT(convolution, i); + WRITE_BIT(puncture, n, b); + n++; + } else { + index++; + } + } + + // interleave + for (uint32_t i = 0U; i < NXDN_CAC_OUT_FEC_LENGTH_BITS; i++) { + uint32_t n = INTERLEAVE_TABLE_OUT[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; + bool b = READ_BIT(puncture, i); + WRITE_BIT(data, n, b); + } + +#if DEBUG_NXDN_CAC + Utils::dump(2U, "CAC::encode(), CAC Puncture and Interleave", data, NXDN_CAC_OUT_FEC_LENGTH_BYTES); +#endif + + // apply control field + uint8_t control[3U]; + ::memset(control, 0x00U, 3U); + + uint8_t parity = 0x01U; + if (m_idleBusy && m_txContinuous) + parity = 0x03U; + + control[0U] = ((m_idleBusy ? 0x03U : 0x01U) << 22) + ((m_txContinuous ? 0x03U : 0x01U) << 20) + + (parity << 18) + ((m_receive ? 0x03U : 0x01U) << 16); + control[1U] = (m_rxCRC >> 8U); + control[2U] = (m_rxCRC >> 0U); + + uint32_t offset = NXDN_CAC_OUT_FEC_LENGTH_BITS; + for (uint32_t i = 0U; i < NXDN_E_POST_FIELD_BITS; i++, offset++) { + bool b = READ_BIT(control, i); + WRITE_BIT(data, offset + i, b); + } + + // post field + offset = NXDN_CAC_OUT_FEC_LENGTH_BITS + NXDN_E_POST_FIELD_BITS; + for (uint32_t i = 0U; i < NXDN_E_POST_FIELD_BITS; i++, offset++) { + bool b = READ_BIT(POST_FIELD, i); + WRITE_BIT(data, offset + i, b); + } +} + +/// +/// Gets the raw CAC data. +/// +/// +void CAC::getData(uint8_t* data) const +{ + assert(data != NULL); + + uint32_t offset = 8U; + for (uint32_t i = 0U; i < (NXDN_CAC_LONG_IN_CRC_BITS - 8); i++, offset++) { + bool b = READ_BIT(m_data, offset); + WRITE_BIT(data, i, b); + } +} + +/// +/// Sets the raw CAC data. +/// +/// +void CAC::setData(const uint8_t* data) +{ + assert(data != NULL); + + uint32_t offset = 8U; + for (uint32_t i = 0U; i < (NXDN_CAC_OUT_CRC_BITS - 8); i++, offset++) { + bool b = READ_BIT(data, i); + WRITE_BIT(m_data, offset, b); + } + + m_ran = m_data[0U] & 0x3FU; +} + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/// +/// Internal helper to copy the the class. +/// +/// +void CAC::copy(const CAC& data) +{ + m_data = new uint8_t[NXDN_CAC_OUT_LENGTH_BYTES]; + ::memcpy(m_data, data.m_data, NXDN_CAC_OUT_LENGTH_BYTES); + + m_ran = m_data[0U] & 0x3FU; +} diff --git a/nxdn/channel/CAC.h b/nxdn/channel/CAC.h new file mode 100644 index 00000000..3b771052 --- /dev/null +++ b/nxdn/channel/CAC.h @@ -0,0 +1,92 @@ +/** +* 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 +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 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. +*/ +#if !defined(__NXDN_CHANNEL__CAC_H__) +#define __NXDN_CHANNEL__CAC_H__ + +#include "Defines.h" + +namespace nxdn +{ + namespace channel + { + // --------------------------------------------------------------------------- + // Class Declaration + // Implements NXDN Common Access Channel. + // --------------------------------------------------------------------------- + + class HOST_SW_API CAC { + public: + /// Initializes a new instance of the CAC class. + CAC(); + /// Initializes a copy instance of the CAC class. + CAC(const CAC& data); + /// Finalizes a instance of the CAC class. + ~CAC(); + + /// Equals operator. + CAC& operator=(const CAC& data); + + /// Decode a common access channel. + bool decode(const uint8_t* data); + /// Encode a common access channel. + void encode(uint8_t* data) const; + + /// Gets the raw CAC data. + void getData(uint8_t* data) const; + /// Sets the raw CAC data. + void setData(const uint8_t* data); + + public: + /// Flag indicating verbose log output. + __PROPERTY(bool, verbose, Verbose); + + /** Common Data */ + /// Radio Access Number + __PROPERTY(uint8_t, ran, RAN); + + /** Collision Control Field */ + /// Idle/Busy. + __PROPERTY(bool, idleBusy, IdleBusy); + /// Tx Continuously. + __PROPERTY(bool, txContinuous, TxContinuous); + /// Receive/No Receive. + __PROPERTY(bool, receive, Receive); + + private: + uint8_t* m_data; + uint16_t m_rxCRC; + + /// Internal helper to copy the class. + void copy(const CAC& data); + }; + } // namespace channel +} // namespace nxdn + +#endif // __NXDN_CHANNEL__CAC_H__ diff --git a/nxdn/channel/FACCH1.cpp b/nxdn/channel/FACCH1.cpp index 4d79d9dd..fae4d773 100644 --- a/nxdn/channel/FACCH1.cpp +++ b/nxdn/channel/FACCH1.cpp @@ -75,7 +75,7 @@ FACCH1::FACCH1() : m_verbose(false), m_data(NULL) { - m_data = new uint8_t[12U]; + m_data = new uint8_t[NXDN_FACCH1_LENGTH_BYTES]; } /// @@ -105,7 +105,7 @@ FACCH1::~FACCH1() FACCH1& FACCH1::operator=(const FACCH1& data) { if (&data != this) { - ::memcpy(m_data, data.m_data, 12U); + ::memcpy(m_data, data.m_data, NXDN_FACCH1_LENGTH_BYTES); m_verbose = data.m_verbose; } @@ -122,33 +122,34 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset) { assert(data != NULL); - uint8_t buffer[NXDN_FACCH1_LENGTH_BYTES]; - for (uint32_t i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { + uint8_t buffer[NXDN_FACCH1_FEC_LENGTH_BYTES]; + + // deinterleave + for (uint32_t i = 0U; i < NXDN_FACCH1_FEC_LENGTH_BITS; i++) { uint32_t n = INTERLEAVE_TABLE[i] + offset; bool b = READ_BIT(data, n); WRITE_BIT(buffer, i, b); } #if DEBUG_NXDN_FACCH1 - Utils::dump(2U, "FACCH1::decode(), FACCH1 Raw", buffer, NXDN_FACCH1_LENGTH_BYTES); + Utils::dump(2U, "FACCH1::decode(), FACCH1 Raw", buffer, NXDN_FACCH1_FEC_LENGTH_BYTES); #endif - // deinterleave - uint8_t interleave[210U]; - uint32_t n = 0U; - uint32_t index = 0U; - for (uint32_t i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { + // depuncture + uint8_t puncture[210U]; + uint32_t n = 0U, index = 0U; + for (uint32_t i = 0U; i < NXDN_FACCH1_FEC_LENGTH_BITS; i++) { if (n == PUNCTURE_LIST[index]) { - interleave[n++] = 1U; + puncture[n++] = 1U; index++; } bool b = READ_BIT(buffer, i); - interleave[n++] = b ? 2U : 0U; + puncture[n++] = b ? 2U : 0U; } for (uint32_t i = 0U; i < 8U; i++) { - interleave[n++] = 0U; + puncture[n++] = 0U; } // decode convolution @@ -156,21 +157,21 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset) conv.start(); n = 0U; - for (uint32_t i = 0U; i < 100U; i++) { - uint8_t s0 = interleave[n++]; - uint8_t s1 = interleave[n++]; + for (uint32_t i = 0U; i < (NXDN_FACCH1_LENGTH_BITS + 4U); i++) { + uint8_t s0 = puncture[n++]; + uint8_t s1 = puncture[n++]; conv.decode(s0, s1); } - conv.chainback(m_data, 96U); + conv.chainback(m_data, NXDN_FACCH1_LENGTH_BITS); if (m_verbose) { - Utils::dump(2U, "Decoded FACCH1", m_data, 12U); + Utils::dump(2U, "Decoded FACCH1", m_data, NXDN_FACCH1_LENGTH_BYTES); } // check CRC-12 - bool ret = CRC::checkCRC12(m_data, 80U); + bool ret = CRC::checkCRC12(m_data, NXDN_FACCH1_CRC_BITS); if (!ret) { LogError(LOG_NXDN, "FACCH1::decode(), failed CRC-12 check"); return false; @@ -188,30 +189,29 @@ void FACCH1::encode(uint8_t* data, uint32_t offset) const { assert(data != NULL); - if (m_verbose) { - Utils::dump(2U, "Encoded FACCH1", m_data, 12U); - } + uint8_t buffer[NXDN_FACCH1_LENGTH_BYTES]; + ::memset(buffer, 0x00U, NXDN_FACCH1_LENGTH_BYTES); + ::memcpy(buffer, m_data, NXDN_FACCH1_LENGTH_BYTES - 2U); - uint8_t buffer[12U]; - ::memset(buffer, 0x00U, 12U); - ::memcpy(buffer, m_data, 10U); + CRC::addCRC12(buffer, NXDN_FACCH1_CRC_BITS); - CRC::addCRC12(buffer, 80U); + if (m_verbose) { + Utils::dump(2U, "Encoded FACCH1", buffer, NXDN_FACCH1_LENGTH_BYTES); + } // encode convolution - uint8_t convolution[24U]; + uint8_t convolution[NXDN_FACCH1_FEC_CONV_LENGTH_BYTES]; Convolution conv; - conv.encode(buffer, convolution, 96U); + conv.encode(buffer, convolution, NXDN_FACCH1_LENGTH_BITS); #if DEBUG_NXDN_FACCH1 - Utils::dump(2U, "FACCH1::encode(), FACCH1 Convolution", convolution, 24U); + Utils::dump(2U, "FACCH1::encode(), FACCH1 Convolution", convolution, NXDN_FACCH1_FEC_CONV_LENGTH_BYTES); #endif - // interleave and puncture - uint8_t raw[18U]; - uint32_t n = 0U; - uint32_t index = 0U; - for (uint32_t i = 0U; i < 192U; i++) { + // puncture + uint8_t raw[NXDN_FACCH1_FEC_LENGTH_BYTES]; + uint32_t n = 0U, index = 0U; + for (uint32_t i = 0U; i < NXDN_FACCH1_FEC_CONV_LENGTH_BITS; i++) { if (i != PUNCTURE_LIST[index]) { bool b = READ_BIT(convolution, i); WRITE_BIT(raw, n, b); @@ -221,14 +221,15 @@ void FACCH1::encode(uint8_t* data, uint32_t offset) const } } - for (uint32_t i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { + // interleave + for (uint32_t i = 0U; i < NXDN_FACCH1_FEC_LENGTH_BITS; i++) { uint32_t n = INTERLEAVE_TABLE[i] + offset; bool b = READ_BIT(raw, i); WRITE_BIT(data, n, b); } #if DEBUG_NXDN_SACCH - Utils::dump(2U, "FACCH1::encode(), FACCH1 Interleave", raw, 18U); + Utils::dump(2U, "FACCH1::encode(), FACCH1 Puncture and Interleave", data, NXDN_FACCH1_FEC_LENGTH_BYTES); #endif } @@ -240,7 +241,7 @@ void FACCH1::getData(uint8_t* data) const { assert(data != NULL); - ::memcpy(data, m_data, 10U); + ::memcpy(data, m_data, NXDN_FACCH1_LENGTH_BYTES - 2U); } /// @@ -251,7 +252,7 @@ void FACCH1::setData(const uint8_t* data) { assert(data != NULL); - ::memcpy(m_data, data, 10U); + ::memcpy(m_data, data, NXDN_FACCH1_LENGTH_BYTES - 2U); } // --------------------------------------------------------------------------- @@ -264,8 +265,8 @@ void FACCH1::setData(const uint8_t* data) /// void FACCH1::copy(const FACCH1& data) { - m_data = new uint8_t[12U]; - ::memcpy(m_data, data.m_data, 12U); + m_data = new uint8_t[NXDN_FACCH1_LENGTH_BYTES]; + ::memcpy(m_data, data.m_data, NXDN_FACCH1_LENGTH_BYTES); m_verbose = data.m_verbose; } diff --git a/nxdn/channel/SACCH.cpp b/nxdn/channel/SACCH.cpp index d79d2cc3..460a27a0 100644 --- a/nxdn/channel/SACCH.cpp +++ b/nxdn/channel/SACCH.cpp @@ -70,7 +70,7 @@ SACCH::SACCH() : m_structure(0U), m_data(NULL) { - m_data = new uint8_t[5U]; + m_data = new uint8_t[NXDN_SACCH_LENGTH_BYTES]; } /// @@ -102,7 +102,7 @@ SACCH::~SACCH() SACCH& SACCH::operator=(const SACCH& data) { if (&data != this) { - ::memcpy(m_data, data.m_data, 5U); + ::memcpy(m_data, data.m_data, NXDN_SACCH_LENGTH_BYTES); m_verbose = data.m_verbose; @@ -122,33 +122,34 @@ bool SACCH::decode(const uint8_t* data) { assert(data != NULL); - uint8_t buffer[NXDN_SACCH_LENGTH_BYTES + 1U]; - for (uint32_t i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) { + uint8_t buffer[NXDN_SACCH_FEC_LENGTH_BYTES]; + + // deinterleave + for (uint32_t i = 0U; i < NXDN_SACCH_FEC_LENGTH_BITS; i++) { uint32_t n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; bool b = READ_BIT(data, n); WRITE_BIT(buffer, i, b); } #if DEBUG_NXDN_SACCH - Utils::dump(2U, "SACCH::decode(), SACCH Raw", buffer, NXDN_SACCH_LENGTH_BYTES + 1U); + Utils::dump(2U, "SACCH::decode(), SACCH Raw", buffer, NXDN_SACCH_FEC_LENGTH_BYTES); #endif - // deinterleave - uint8_t interleave[90U]; - uint32_t n = 0U; - uint32_t index = 0U; - for (uint32_t i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) { + // depuncture + uint8_t puncture[90U]; + uint32_t n = 0U, index = 0U; + for (uint32_t i = 0U; i < NXDN_SACCH_FEC_LENGTH_BITS; i++) { if (n == PUNCTURE_LIST[index]) { - interleave[n++] = 1U; + puncture[n++] = 1U; index++; } bool b = READ_BIT(buffer, i); - interleave[n++] = b ? 2U : 0U; + puncture[n++] = b ? 2U : 0U; } for (uint32_t i = 0U; i < 8U; i++) { - interleave[n++] = 0U; + puncture[n++] = 0U; } // decode convolution @@ -156,21 +157,21 @@ bool SACCH::decode(const uint8_t* data) conv.start(); n = 0U; - for (uint32_t i = 0U; i < 40U; i++) { - uint8_t s0 = interleave[n++]; - uint8_t s1 = interleave[n++]; + for (uint32_t i = 0U; i < (NXDN_SACCH_LENGTH_BITS + 4U); i++) { + uint8_t s0 = puncture[n++]; + uint8_t s1 = puncture[n++]; conv.decode(s0, s1); } - conv.chainback(m_data, 36U); + conv.chainback(m_data, NXDN_SACCH_LENGTH_BITS); if (m_verbose) { - Utils::dump(2U, "Decoded SACCH", m_data, 5U); + Utils::dump(2U, "Decoded SACCH", m_data, NXDN_SACCH_LENGTH_BYTES); } // check CRC-6 - bool ret = CRC::checkCRC6(m_data, 26U); + bool ret = CRC::checkCRC6(m_data, NXDN_SACCH_CRC_BITS); if (!ret) { LogError(LOG_NXDN, "SACCH::decode(), failed CRC-6 check"); return false; @@ -196,51 +197,51 @@ void SACCH::encode(uint8_t* data) const m_data[0U] &= 0x3FU; m_data[0U] |= (m_structure << 6) & 0xC0U; - if (m_verbose) { - Utils::dump(2U, "Encoded SACCH", m_data, 5U); - } + uint8_t buffer[NXDN_SACCH_LENGTH_BYTES]; + ::memset(buffer, 0x00U, NXDN_SACCH_LENGTH_BYTES); - uint8_t buffer[5U]; - ::memset(buffer, 0x00U, 5U); - - for (uint32_t i = 0U; i < 26U; i++) { + for (uint32_t i = 0U; i < NXDN_SACCH_CRC_BITS; i++) { bool b = READ_BIT(m_data, i); WRITE_BIT(buffer, i, b); } - CRC::addCRC6(buffer, 26U); + CRC::addCRC6(buffer, NXDN_SACCH_CRC_BITS); + + if (m_verbose) { + Utils::dump(2U, "Encoded SACCH", buffer, NXDN_SACCH_LENGTH_BYTES); + } // encode convolution - uint8_t convolution[9U]; + uint8_t convolution[NXDN_SACCH_FEC_CONV_LENGTH_BYTES]; Convolution conv; - conv.encode(buffer, convolution, 36U); + conv.encode(buffer, convolution, NXDN_SACCH_LENGTH_BITS); #if DEBUG_NXDN_SACCH - Utils::dump(2U, "SACCH::encode(), SACCH Convolution", convolution, 9U); + Utils::dump(2U, "SACCH::encode(), SACCH Convolution", convolution, NXDN_SACCH_FEC_CONV_LENGTH_BYTES); #endif - // interleave and puncture - uint8_t raw[8U]; - uint32_t n = 0U; - uint32_t index = 0U; - for (uint32_t i = 0U; i < 72U; i++) { + // puncture + uint8_t puncture[NXDN_SACCH_FEC_LENGTH_BYTES]; + uint32_t n = 0U, index = 0U; + for (uint32_t i = 0U; i < NXDN_SACCH_FEC_CONV_LENGTH_BITS; i++) { if (i != PUNCTURE_LIST[index]) { bool b = READ_BIT(convolution, i); - WRITE_BIT(raw, n, b); + WRITE_BIT(puncture, n, b); n++; } else { index++; } } - for (uint32_t i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) { + // interleave + for (uint32_t i = 0U; i < NXDN_SACCH_FEC_LENGTH_BITS; i++) { uint32_t n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; - bool b = READ_BIT(raw, i); + bool b = READ_BIT(puncture, i); WRITE_BIT(data, n, b); } #if DEBUG_NXDN_SACCH - Utils::dump(2U, "SACCH::encode(), SACCH Interleave", raw, 8U); + Utils::dump(2U, "SACCH::encode(), SACCH Puncture and Interleave", data, NXDN_SACCH_FEC_LENGTH_BYTES); #endif } @@ -253,7 +254,7 @@ void SACCH::getData(uint8_t* data) const assert(data != NULL); uint32_t offset = 8U; - for (uint32_t i = 0U; i < 18U; i++, offset++) { + for (uint32_t i = 0U; i < (NXDN_SACCH_CRC_BITS - 8); i++, offset++) { bool b = READ_BIT(m_data, offset); WRITE_BIT(data, i, b); } @@ -268,7 +269,7 @@ void SACCH::setData(const uint8_t* data) assert(data != NULL); uint32_t offset = 8U; - for (uint32_t i = 0U; i < 18U; i++, offset++) { + for (uint32_t i = 0U; i < (NXDN_SACCH_CRC_BITS - 8); i++, offset++) { bool b = READ_BIT(data, i); WRITE_BIT(m_data, offset, b); } @@ -287,8 +288,8 @@ void SACCH::setData(const uint8_t* data) /// void SACCH::copy(const SACCH& data) { - m_data = new uint8_t[5U]; - ::memcpy(m_data, data.m_data, 5U); + m_data = new uint8_t[NXDN_SACCH_LENGTH_BYTES]; + ::memcpy(m_data, data.m_data, NXDN_SACCH_LENGTH_BYTES); m_ran = m_data[0U] & 0x3FU; m_structure = (m_data[0U] >> 6) & 0x03U; diff --git a/nxdn/channel/UDCH.cpp b/nxdn/channel/UDCH.cpp index b498c7e6..7a0cce5e 100644 --- a/nxdn/channel/UDCH.cpp +++ b/nxdn/channel/UDCH.cpp @@ -98,7 +98,7 @@ UDCH::UDCH() : m_ran(0U), m_data(NULL) { - m_data = new uint8_t[26U]; + m_data = new uint8_t[NXDN_UDCH_LENGTH_BYTES]; } /// @@ -129,7 +129,7 @@ UDCH::~UDCH() UDCH& UDCH::operator=(const UDCH& data) { if (&data != this) { - ::memcpy(m_data, data.m_data, 26U); + ::memcpy(m_data, data.m_data, NXDN_UDCH_LENGTH_BYTES); m_verbose = data.m_verbose; @@ -148,33 +148,34 @@ bool UDCH::decode(const uint8_t* data) { assert(data != NULL); - uint8_t buffer[NXDN_FACCH2_LENGTH_BYTES + 1U]; - for (uint32_t i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) { + uint8_t buffer[NXDN_UDCH_FEC_LENGTH_BYTES]; + + // deinterleave + for (uint32_t i = 0U; i < NXDN_UDCH_FEC_LENGTH_BITS; i++) { uint32_t n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; bool b = READ_BIT(data, n); WRITE_BIT(buffer, i, b); } #if DEBUG_NXDN_UDCH - Utils::dump(2U, "UDCH::decode(), UDCH Raw", buffer, NXDN_FACCH2_LENGTH_BYTES + 1U); + Utils::dump(2U, "UDCH::decode(), UDCH Raw", buffer, NXDN_UDCH_FEC_LENGTH_BYTES); #endif - // deinterleave - uint8_t interleave[420U]; - uint32_t n = 0U; - uint32_t index = 0U; - for (uint32_t i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) { + // depuncture + uint8_t puncture[420U]; + uint32_t n = 0U, index = 0U; + for (uint32_t i = 0U; i < NXDN_UDCH_FEC_LENGTH_BITS; i++) { if (n == PUNCTURE_LIST[index]) { - interleave[n++] = 1U; + puncture[n++] = 1U; index++; } bool b = READ_BIT(buffer, i); - interleave[n++] = b ? 2U : 0U; + puncture[n++] = b ? 2U : 0U; } for (uint32_t i = 0U; i < 8U; i++) { - interleave[n++] = 0U; + puncture[n++] = 0U; } // decode convolution @@ -182,21 +183,21 @@ bool UDCH::decode(const uint8_t* data) conv.start(); n = 0U; - for (uint32_t i = 0U; i < 207U; i++) { - uint8_t s0 = interleave[n++]; - uint8_t s1 = interleave[n++]; + for (uint32_t i = 0U; i < (NXDN_UDCH_LENGTH_BITS + 4U); i++) { + uint8_t s0 = puncture[n++]; + uint8_t s1 = puncture[n++]; conv.decode(s0, s1); } - conv.chainback(m_data, 203U); + conv.chainback(m_data, NXDN_UDCH_LENGTH_BITS); if (m_verbose) { - Utils::dump(2U, "Decoded UDCH", m_data, 26U); + Utils::dump(2U, "Decoded UDCH", m_data, NXDN_UDCH_LENGTH_BYTES); } // check CRC-15 - bool ret = CRC::checkCRC15(m_data, 26U); + bool ret = CRC::checkCRC15(m_data, NXDH_UDCH_CRC_BITS); if (!ret) { LogError(LOG_NXDN, "UDCH::decode(), failed CRC-15 check"); return false; @@ -217,47 +218,47 @@ void UDCH::encode(uint8_t* data) const m_data[0U] = m_ran; - if (m_verbose) { - Utils::dump(2U, "Encoded UDCH", m_data, 26U); - } - - uint8_t buffer[25U]; - ::memset(buffer, 0x00U, 25U); + uint8_t buffer[NXDN_UDCH_LENGTH_BYTES]; + ::memset(buffer, 0x00U, NXDN_UDCH_LENGTH_BYTES); ::memcpy(buffer, m_data, 23U); - CRC::addCRC15(buffer, 184U); + CRC::addCRC15(buffer, NXDH_UDCH_CRC_BITS); + + if (m_verbose) { + Utils::dump(2U, "Encoded UDCH", m_data, NXDN_UDCH_LENGTH_BYTES); + } // encode convolution - uint8_t convolution[51U]; + uint8_t convolution[NXDN_UDCH_FEC_CONV_LENGTH_BYTES]; Convolution conv; - conv.encode(buffer, convolution, 203U); + conv.encode(buffer, convolution, NXDN_UDCH_LENGTH_BITS); #if DEBUG_NXDN_UDCH - Utils::dump(2U, "UDCH::encode(), UDCH Convolution", convolution, 51U); + Utils::dump(2U, "UDCH::encode(), UDCH Convolution", convolution, NXDN_UDCH_FEC_CONV_LENGTH_BYTES); #endif - // interleave and puncture - uint8_t raw[44U]; - uint32_t n = 0U; - uint32_t index = 0U; - for (uint32_t i = 0U; i < 406U; i++) { + // puncture + uint8_t puncture[NXDN_UDCH_FEC_LENGTH_BYTES]; + uint32_t n = 0U, index = 0U; + for (uint32_t i = 0U; i < NXDN_UDCH_FEC_CONV_LENGTH_BITS; i++) { if (i != PUNCTURE_LIST[index]) { bool b = READ_BIT(convolution, i); - WRITE_BIT(raw, n, b); + WRITE_BIT(puncture, n, b); n++; } else { index++; } } - for (uint32_t i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) { + // interleave + for (uint32_t i = 0U; i < NXDN_UDCH_FEC_LENGTH_BITS; i++) { uint32_t n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; - bool b = READ_BIT(raw, i); + bool b = READ_BIT(puncture, i); WRITE_BIT(data, n, b); } #if DEBUG_NXDN_UDCH - Utils::dump(2U, "UDCH::encode(), UDCH Interleave", raw, 44U); + Utils::dump(2U, "UDCH::encode(), UDCH Puncture and Interleave", data, NXDN_UDCH_FEC_LENGTH_BYTES); #endif }