From c4104d41ec23abca9d47ccb2d6ced4cea82ccec3 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Tue, 4 Oct 2022 19:47:55 -0400 Subject: [PATCH] merge upstream changes for AMBEFEC and Golay (this changes how audio FEC is done, and may cause artifacts on DMR and NXDN); --- edac/AMBEFEC.cpp | 292 +++++++++++++++++++++++++------------------- edac/AMBEFEC.h | 19 +-- edac/Golay24128.cpp | 34 +++--- edac/Golay24128.h | 8 +- p25/lc/LC.cpp | 5 +- 5 files changed, 206 insertions(+), 152 deletions(-) diff --git a/edac/AMBEFEC.cpp b/edac/AMBEFEC.cpp index 614b0be0..64163d40 100644 --- a/edac/AMBEFEC.cpp +++ b/edac/AMBEFEC.cpp @@ -11,8 +11,9 @@ // Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // /* -* Copyright (C) 2010,2014,2016 by Jonathan Naylor G4KLX +* Copyright (C) 2010,2014,2016,2021 by Jonathan Naylor G4KLX * Copyright (C) 2016 Mathias Weyland, HB9FRV +* Copyright (C) 2018-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 @@ -32,6 +33,7 @@ #include "edac/AMBEFEC.h" #include "edac/Golay24128.h" #include "edac/Hamming.h" +#include "Utils.h" using namespace edac; @@ -72,24 +74,12 @@ uint32_t AMBEFEC::regenerateDMR(uint8_t* bytes) const uint32_t c1 = 0U, c2 = 0U, c3 = 0U; uint32_t MASK = 0x800000U; - for (uint32_t i = 0U; i < 24U; i++) { - uint32_t a1Pos = DMR_A_TABLE[i]; - uint32_t b1Pos = DMR_B_TABLE[i]; - uint32_t c1Pos = DMR_C_TABLE[i]; - + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t a1Pos = AMBE_A_TABLE[i]; uint32_t a2Pos = a1Pos + 72U; if (a2Pos >= 108U) a2Pos += 48U; - uint32_t b2Pos = b1Pos + 72U; - if (b2Pos >= 108U) - b2Pos += 48U; - uint32_t c2Pos = c1Pos + 72U; - if (c2Pos >= 108U) - c2Pos += 48U; - uint32_t a3Pos = a1Pos + 192U; - uint32_t b3Pos = b1Pos + 192U; - uint32_t c3Pos = c1Pos + 192U; if (READ_BIT(bytes, a1Pos)) a1 |= MASK; @@ -97,57 +87,81 @@ uint32_t AMBEFEC::regenerateDMR(uint8_t* bytes) const a2 |= MASK; if (READ_BIT(bytes, a3Pos)) a3 |= MASK; + } + + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t b1Pos = AMBE_B_TABLE[i]; + uint32_t b2Pos = b1Pos + 72U; + if (b2Pos >= 108U) + b2Pos += 48U; + uint32_t b3Pos = b1Pos + 192U; + if (READ_BIT(bytes, b1Pos)) b1 |= MASK; if (READ_BIT(bytes, b2Pos)) b2 |= MASK; if (READ_BIT(bytes, b3Pos)) - b3 |= MASK; - if (READ_BIT(bytes, c1Pos)) - c1 |= MASK; - if (READ_BIT(bytes, c2Pos)) - c2 |= MASK; - if (READ_BIT(bytes, c3Pos)) - c3 |= MASK; - - MASK >>= 1; - } - - uint32_t errors = regenerate(a1, b1, c1, true); - errors += regenerate(a2, b2, c2, true); - errors += regenerate(a3, b3, c3, true); + b3 |= MASK; + } + + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t c1Pos = AMBE_C_TABLE[i]; + uint32_t c2Pos = c1Pos + 72U; + if (c2Pos >= 108U) + c2Pos += 48U; + uint32_t c3Pos = c1Pos + 192U; + + if (READ_BIT(bytes, c1Pos)) + c1 |= MASK; + if (READ_BIT(bytes, c2Pos)) + c2 |= MASK; + if (READ_BIT(bytes, c3Pos)) + c3 |= MASK; + } + + uint32_t errors = regenerate(a1, b1, c1); + errors += regenerate(a2, b2, c2); + errors += regenerate(a3, b3, c3); MASK = 0x800000U; - for (uint32_t i = 0U; i < 24U; i++) { - uint32_t a1Pos = DMR_A_TABLE[i]; - uint32_t b1Pos = DMR_B_TABLE[i]; - uint32_t c1Pos = DMR_C_TABLE[i]; - + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t a1Pos = AMBE_A_TABLE[i]; uint32_t a2Pos = a1Pos + 72U; if (a2Pos >= 108U) a2Pos += 48U; - uint32_t b2Pos = b1Pos + 72U; - if (b2Pos >= 108U) - b2Pos += 48U; - uint32_t c2Pos = c1Pos + 72U; - if (c2Pos >= 108U) - c2Pos += 48U; - uint32_t a3Pos = a1Pos + 192U; - uint32_t b3Pos = b1Pos + 192U; - uint32_t c3Pos = c1Pos + 192U; WRITE_BIT(bytes, a1Pos, a1 & MASK); WRITE_BIT(bytes, a2Pos, a2 & MASK); WRITE_BIT(bytes, a3Pos, a3 & MASK); + } + + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t b1Pos = AMBE_B_TABLE[i]; + uint32_t b2Pos = b1Pos + 72U; + if (b2Pos >= 108U) + b2Pos += 48U; + uint32_t b3Pos = b1Pos + 192U; + WRITE_BIT(bytes, b1Pos, b1 & MASK); WRITE_BIT(bytes, b2Pos, b2 & MASK); WRITE_BIT(bytes, b3Pos, b3 & MASK); + } + + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t c1Pos = AMBE_C_TABLE[i]; + uint32_t c2Pos = c1Pos + 72U; + if (c2Pos >= 108U) + c2Pos += 48U; + uint32_t c3Pos = c1Pos + 192U; + WRITE_BIT(bytes, c1Pos, c1 & MASK); WRITE_BIT(bytes, c2Pos, c2 & MASK); WRITE_BIT(bytes, c3Pos, c3 & MASK); - - MASK >>= 1; } return errors; @@ -167,24 +181,12 @@ uint32_t AMBEFEC::measureDMRBER(const uint8_t* bytes) const uint32_t c1 = 0U, c2 = 0U, c3 = 0U; uint32_t MASK = 0x800000U; - for (uint32_t i = 0U; i < 24U; i++) { - uint32_t a1Pos = DMR_A_TABLE[i]; - uint32_t b1Pos = DMR_B_TABLE[i]; - uint32_t c1Pos = DMR_C_TABLE[i]; - + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t a1Pos = AMBE_A_TABLE[i]; uint32_t a2Pos = a1Pos + 72U; if (a2Pos >= 108U) a2Pos += 48U; - uint32_t b2Pos = b1Pos + 72U; - if (b2Pos >= 108U) - b2Pos += 48U; - uint32_t c2Pos = c1Pos + 72U; - if (c2Pos >= 108U) - c2Pos += 48U; - uint32_t a3Pos = a1Pos + 192U; - uint32_t b3Pos = b1Pos + 192U; - uint32_t c3Pos = c1Pos + 192U; if (READ_BIT(bytes, a1Pos)) a1 |= MASK; @@ -192,25 +194,43 @@ uint32_t AMBEFEC::measureDMRBER(const uint8_t* bytes) const a2 |= MASK; if (READ_BIT(bytes, a3Pos)) a3 |= MASK; + } + + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t b1Pos = AMBE_B_TABLE[i]; + uint32_t b2Pos = b1Pos + 72U; + if (b2Pos >= 108U) + b2Pos += 48U; + uint32_t b3Pos = b1Pos + 192U; + if (READ_BIT(bytes, b1Pos)) b1 |= MASK; if (READ_BIT(bytes, b2Pos)) b2 |= MASK; if (READ_BIT(bytes, b3Pos)) - b3 |= MASK; - if (READ_BIT(bytes, c1Pos)) - c1 |= MASK; - if (READ_BIT(bytes, c2Pos)) - c2 |= MASK; - if (READ_BIT(bytes, c3Pos)) - c3 |= MASK; - - MASK >>= 1; - } - - uint32_t errors = regenerate(a1, b1, c1, true); - errors += regenerate(a2, b2, c2, true); - errors += regenerate(a3, b3, c3, true); + b3 |= MASK; + } + + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t c1Pos = AMBE_C_TABLE[i]; + uint32_t c2Pos = c1Pos + 72U; + if (c2Pos >= 108U) + c2Pos += 48U; + uint32_t c3Pos = c1Pos + 192U; + + if (READ_BIT(bytes, c1Pos)) + c1 |= MASK; + if (READ_BIT(bytes, c2Pos)) + c2 |= MASK; + if (READ_BIT(bytes, c3Pos)) + c3 |= MASK; + } + + uint32_t errors = regenerate(a1, b1, c1); + errors += regenerate(a2, b2, c2); + errors += regenerate(a3, b3, c3); return errors; } @@ -499,7 +519,7 @@ uint32_t AMBEFEC::regenerateNXDN(uint8_t* bytes) const uint32_t a = 0U; uint32_t MASK = 0x800000U; for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { - uint32_t aPos = DMR_A_TABLE[i]; + uint32_t aPos = AMBE_A_TABLE[i]; if (READ_BIT(bytes, aPos)) a |= MASK; } @@ -507,7 +527,7 @@ uint32_t AMBEFEC::regenerateNXDN(uint8_t* bytes) const uint32_t b = 0U; MASK = 0x400000U; for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { - uint32_t bPos = DMR_B_TABLE[i]; + uint32_t bPos = AMBE_B_TABLE[i]; if (READ_BIT(bytes, bPos)) b |= MASK; } @@ -515,34 +535,72 @@ uint32_t AMBEFEC::regenerateNXDN(uint8_t* bytes) const uint32_t c = 0U; MASK = 0x1000000U; for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { - uint32_t cPos = DMR_C_TABLE[i]; + uint32_t cPos = AMBE_C_TABLE[i]; if (READ_BIT(bytes, cPos)) c |= MASK; } - uint32_t errors = regenerate(a, b, c, true); + uint32_t errors = regenerate(a, b, c); MASK = 0x800000U; for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { - uint32_t aPos = DMR_A_TABLE[i]; + uint32_t aPos = AMBE_A_TABLE[i]; WRITE_BIT(bytes, aPos, a & MASK); } MASK = 0x400000U; for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { - uint32_t bPos = DMR_B_TABLE[i]; + uint32_t bPos = AMBE_B_TABLE[i]; WRITE_BIT(bytes, bPos, b & MASK); } MASK = 0x1000000U; for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { - uint32_t cPos = DMR_C_TABLE[i]; + uint32_t cPos = AMBE_C_TABLE[i]; WRITE_BIT(bytes, cPos, c & MASK); } return errors; } + +/// +/// Returns the number of errors on the NXDN BER input bytes. +/// +/// +/// Count of errors. +uint32_t AMBEFEC::measureNXDNBER(uint8_t* bytes) const +{ + assert(bytes != NULL); + + uint32_t a = 0U; + uint32_t MASK = 0x800000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t aPos = AMBE_A_TABLE[i]; + if (READ_BIT(bytes, aPos)) + a |= MASK; + } + + uint32_t b = 0U; + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t bPos = AMBE_B_TABLE[i]; + if (READ_BIT(bytes, bPos)) + b |= MASK; + } + + uint32_t c = 0U; + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t cPos = AMBE_C_TABLE[i]; + if (READ_BIT(bytes, cPos)) + c |= MASK; + } + + uint32_t errors = regenerate(a, b, c); + return errors; +} + // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- @@ -553,60 +611,44 @@ uint32_t AMBEFEC::regenerateNXDN(uint8_t* bytes) const /// /// /// -/// +/// /// -uint32_t AMBEFEC::regenerate(uint32_t& a, uint32_t& b, uint32_t& c, bool b23) const +uint32_t AMBEFEC::regenerate(uint32_t& a, uint32_t& b, uint32_t& c, bool ignoreParity) const { - uint32_t old_a = a; - uint32_t old_b = b; - - // For the b23 bypass - bool b24 = (b & 0x01U) == 0x01U; - - uint32_t data = Golay24128::decode24128(a); - - uint32_t new_a = Golay24128::encode24128(data); + uint32_t old_a = a; + uint32_t old_b = b; - // The PRNG - uint32_t p = PRNG_TABLE[data]; + uint32_t data; + bool valid = Golay24128::decode24128(a, data); + if (!valid && !ignoreParity) { + a = 0xF00292U; + b = 0x0E0B20U; + c = 0x000000U; + return 10U; // An invalid A block gives an error count of 10 + } - b ^= p; + a = Golay24128::encode24128(data); - uint32_t datb = Golay24128::decode24128(b); + // PRNG + uint32_t p = PRNG_TABLE[data] >> 1; + b ^= p; - uint32_t new_b = Golay24128::encode24128(datb); + uint32_t datb = Golay24128::decode23127(b); + b = Golay24128::encode23127(datb) >> 1; - new_b ^= p; + b ^= p; - if (b23) { - new_b &= 0xFFFFFEU; - new_b |= b24 ? 0x01U : 0x00U; - } - - uint32_t errsA = 0U, errsB = 0U; - - uint32_t v = new_a ^ old_a; - while (v != 0U) { - v &= v - 1U; - errsA++; - } + uint32_t v = a ^ old_a; + uint32_t errsA = Utils::countBits32(v); - v = new_b ^ old_b; - while (v != 0U) { - v &= v - 1U; - errsB++; - } - - if (b23) { - if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) { - a = 0xF00292U; - b = 0x0E0B20U; - c = 0x000000U; - } - } + v = b ^ old_b; + uint32_t errsB = Utils::countBits32(v); - a = new_a; - b = new_b; + if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) { + a = 0xF00292U; + b = 0x0E0B20U; + c = 0x000000U; + } - return errsA + errsB; + return errsA + errsB; } diff --git a/edac/AMBEFEC.h b/edac/AMBEFEC.h index 8ce82b7d..63593b1e 100644 --- a/edac/AMBEFEC.h +++ b/edac/AMBEFEC.h @@ -11,7 +11,8 @@ // Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // /* -* Copyright (C) 2010,2014,2016 by Jonathan Naylor G4KLX +* Copyright (C) 2010,2014,2016,2021 by Jonathan Naylor G4KLX +* Copyright (C) 2018-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 @@ -450,15 +451,15 @@ namespace edac 0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U, 0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U }; - const uint32_t DMR_A_TABLE[] = { + const uint32_t AMBE_A_TABLE[] = { 0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U, 48U, 52U, 56U, 60U, 64U, 68U, 1U, 5U, 9U, 13U, 17U, 21U }; - const uint32_t DMR_B_TABLE[] = { + const uint32_t AMBE_B_TABLE[] = { 25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, - 2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U, 46U }; - const uint32_t DMR_C_TABLE[] = { - 50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U, 23U, - 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U }; + 2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U }; + const uint32_t AMBE_C_TABLE[] = { + 46U, 50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U, + 23U, 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U }; const uint32_t IMBE_INTERLEAVE[] = { 0, 7, 12, 19, 24, 31, 36, 43, 48, 55, 60, 67, 72, 79, 84, 91, 96, 103, 108, 115, 120, 127, 132, 139, @@ -493,10 +494,12 @@ namespace edac /// Regenerates the NXDN AMBE FEC for the input bytes. uint32_t regenerateNXDN(uint8_t* bytes) const; + /// Returns the number of errors on the NXDN BER input bytes. + uint32_t measureNXDNBER(uint8_t* bytes) const; private: /// - uint32_t regenerate(uint32_t& a, uint32_t& b, uint32_t& c, bool b23) const; + uint32_t regenerate(uint32_t& a, uint32_t& b, uint32_t& c, bool ignoreParity = true) const; }; } // namespace edac diff --git a/edac/Golay24128.cpp b/edac/Golay24128.cpp index a3fa7f65..abd541c8 100644 --- a/edac/Golay24128.cpp +++ b/edac/Golay24128.cpp @@ -31,6 +31,7 @@ */ #include "Defines.h" #include "edac/Golay24128.h" +#include "Utils.h" using namespace edac; @@ -1100,28 +1101,33 @@ uint32_t Golay24128::decode23127(uint32_t code) /// Decode Golay (24,12,8) FEC. /// /// +/// /// -uint32_t Golay24128::decode24128(uint32_t code) +bool Golay24128::decode24128(uint32_t code, uint32_t& out) { - return decode23127(code >> 1); + uint32_t syndrome = getSyndrome23127(code >> 1); + uint32_t error_pattern = DECODING_TABLE_23127[syndrome] << 1; + + out = code ^ error_pattern; + + bool valid = (Utils::countBits32(syndrome) < 3U) || !(Utils::countBits32(out) & 1); + out >>= 12; + + return valid; } /// /// Decode Golay (24,12,8) FEC. /// -/// Golay FEC encoded data byte array +/// Golay FEC encoded data byte array +/// /// -uint32_t Golay24128::decode24128(uint8_t* bytes) +bool Golay24128::decode24128(uint8_t* bytes, uint32_t& out) { assert(bytes != NULL); - uint32_t code = bytes[0U]; - code <<= 8; - code |= bytes[1U]; - code <<= 8; - code |= bytes[2U]; - - return decode23127(code >> 1); + uint32_t code = (bytes[0U] << 16) | (bytes[1U] << 8) | (bytes[2U] << 0); + return decode24128(code, out); } /// @@ -1156,8 +1162,8 @@ void Golay24128::decode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen) v1 = ((r3 << 16) & 0xff0000) | ((r4 << 8) & 0x00ff00) | ((r5 << 0) & 0x0000ff); // decode each symbol into a 12-bit symbol - m0_hat = decode24128(v0); - m1_hat = decode24128(v1); + decode24128(v0, m0_hat); + decode24128(v1, m1_hat); // unpack two 12-bit symbols into three 8-bit bytes data[i + 0] = ((m0_hat >> 4) & 0xff); @@ -1178,7 +1184,7 @@ void Golay24128::decode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen) v0 = ((r0 << 16) & 0xff0000) | ((r1 << 8) & 0x00ff00) | ((r2) & 0x0000ff); // decode into a 12-bit symbol - m0_hat = decode24128(v0); + decode24128(v0, m0_hat); // retain last 8 bits of 12-bit symbol data[i] = m0_hat & 0xff; diff --git a/edac/Golay24128.h b/edac/Golay24128.h index 63c14b21..8bb64054 100644 --- a/edac/Golay24128.h +++ b/edac/Golay24128.h @@ -11,8 +11,8 @@ // Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // /* -* Copyright (C) 2010,2016 by Jonathan Naylor G4KLX -* Copyright (C) 2017 by Bryan Biedenkapp N2PLL +* Copyright (C) 2010,2016,2021 by Jonathan Naylor G4KLX +* 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 @@ -46,9 +46,9 @@ namespace edac /// Decode Golay (23,12,7) FEC. static uint32_t decode23127(uint32_t code); /// Decode Golay (24,12,8) FEC. - static uint32_t decode24128(uint32_t code); + static bool decode24128(uint32_t code, uint32_t& out); /// Decode Golay (24,12,8) FEC. - static uint32_t decode24128(uint8_t* bytes); + static bool decode24128(uint8_t* bytes, uint32_t& out); /// Decode Golay (24,12,8) FEC. static void decode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen); diff --git a/p25/lc/LC.cpp b/p25/lc/LC.cpp index c0896e28..38c029e6 100644 --- a/p25/lc/LC.cpp +++ b/p25/lc/LC.cpp @@ -768,7 +768,10 @@ void LC::decodeHDUGolay(const uint8_t * data, uint8_t * raw) uint32_t g0 = 0U; for (uint32_t j = 0U; j < 18U; j++) g0 = (g0 << 1) | (golay[j] ? 0x01U : 0x00U); - uint32_t c0data = edac::Golay24128::decode24128(g0); + + uint32_t c0data = 0U; + edac::Golay24128::decode24128(g0, c0data); + for (int j = 5; j >= 0; j--) { golay[j] = (c0data & 0x01U) == 0x01U; c0data >>= 1;