// SPDX-License-Identifier: AGPL-3.0-only
/**
* Digital Voice Modem - Fixed Network Equipment Core Library
* AGPLv3 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Fixed Network Equipment Core Library
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
* @license AGPLv3 License (https://opensource.org/licenses/AGPL-3.0)
*
* Copyright (C) 2022 Bryan Biedenkapp, N2PLL
*
*/
using System;
namespace fnecore.EDAC
{
///
/// Implements Hamming (15,11,3), (13,9,3), (10,6,3), (16,11,4) and
// (17,12,3) forward error correction.
///
public sealed class Hamming
{
/*
** Methods
*/
///
/// Decode Hamming (15,11,3).
///
/// Boolean bit array.
///
/// True, if bit errors are detected, otherwise false.
public static bool decode15113_1(bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the parity it should have
bool c0 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[6 + offset];
bool c1 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[7 + offset] ^ d[8 + offset] ^ d[9 + offset];
bool c2 = d[0 + offset] ^ d[1 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset] ^ d[10 + offset];
bool c3 = d[0 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[9 + offset] ^ d[10 + offset];
byte n = 0;
n |= (byte)((c0 != d[11 + offset]) ? 0x01U : 0x00U);
n |= (byte)((c1 != d[12 + offset]) ? 0x02U : 0x00U);
n |= (byte)((c2 != d[13 + offset]) ? 0x04U : 0x00U);
n |= (byte)((c3 != d[14 + offset]) ? 0x08U : 0x00U);
switch (n)
{
// Parity bit errors
case 0x01: d[11 + offset] = !d[11 + offset]; return true;
case 0x02: d[12 + offset] = !d[12 + offset]; return true;
case 0x04: d[13 + offset] = !d[13 + offset]; return true;
case 0x08: d[14 + offset] = !d[14 + offset]; return true;
// Data bit errors
case 0x0F: d[0 + offset] = !d[0 + offset]; return true;
case 0x07: d[1 + offset] = !d[1 + offset]; return true;
case 0x0B: d[2 + offset] = !d[2 + offset]; return true;
case 0x03: d[3 + offset] = !d[3 + offset]; return true;
case 0x0D: d[4 + offset] = !d[4 + offset]; return true;
case 0x05: d[5 + offset] = !d[5 + offset]; return true;
case 0x09: d[6 + offset] = !d[6 + offset]; return true;
case 0x0E: d[7 + offset] = !d[7 + offset]; return true;
case 0x06: d[8 + offset] = !d[8 + offset]; return true;
case 0x0A: d[9 + offset] = !d[9 + offset]; return true;
case 0x0C: d[10 + offset] = !d[10 + offset]; return true;
// No bit errors
default: return false;
}
}
///
/// Encode Hamming (15,11,3).
///
/// Boolean bit array.
///
public static void encode15113_1(ref bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this row should have
d[11 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[6 + offset];
d[12 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[7 + offset] ^ d[8 + offset] ^ d[9 + offset];
d[13 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset] ^ d[10 + offset];
d[14 + offset] = d[0 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[9 + offset] ^ d[10 + offset];
}
///
/// Decode Hamming (15,11,3).
///
/// Boolean bit array.
///
/// True, if bit errors are detected, otherwise false.
public static bool decode15113_2(bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this row should have
bool c0 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset];
bool c1 = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[9 + offset];
bool c2 = d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[9 + offset] ^ d[10 + offset];
bool c3 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[10 + offset];
byte n = 0x00;
n |= (byte)((c0 != d[11 + offset]) ? 0x01U : 0x00U);
n |= (byte)((c1 != d[12 + offset]) ? 0x02U : 0x00U);
n |= (byte)((c2 != d[13 + offset]) ? 0x04U : 0x00U);
n |= (byte)((c3 != d[14 + offset]) ? 0x08U : 0x00U);
switch (n)
{
// Parity bit errors
case 0x01: d[11 + offset] = !d[11 + offset]; return true;
case 0x02: d[12 + offset] = !d[12 + offset]; return true;
case 0x04: d[13 + offset] = !d[13 + offset]; return true;
case 0x08: d[14 + offset] = !d[14 + offset]; return true;
// Data bit errors
case 0x09: d[0 + offset] = !d[0 + offset]; return true;
case 0x0B: d[1 + offset] = !d[1 + offset]; return true;
case 0x0F: d[2 + offset] = !d[2 + offset]; return true;
case 0x07: d[3 + offset] = !d[3 + offset]; return true;
case 0x0E: d[4 + offset] = !d[4 + offset]; return true;
case 0x05: d[5 + offset] = !d[5 + offset]; return true;
case 0x0A: d[6 + offset] = !d[6 + offset]; return true;
case 0x0D: d[7 + offset] = !d[7 + offset]; return true;
case 0x03: d[8 + offset] = !d[8 + offset]; return true;
case 0x06: d[9 + offset] = !d[9 + offset]; return true;
case 0x0C: d[10 + offset] = !d[10 + offset]; return true;
// No bit errors
default: return false;
}
}
///
/// Encode Hamming (15,11,3).
///
/// Boolean bit array.
///
public static void encode15113_2(ref bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this row should have
d[11 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset];
d[12 + offset] = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[9 + offset];
d[13 + offset] = d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[9 + offset] ^ d[10 + offset];
d[14 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[10 + offset];
}
///
/// Decode Hamming (13,9,3).
///
/// Boolean bit array.
/// True, if bit errors are detected, otherwise false.
public static bool decode1393(bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this column should have
bool c0 = d[0 + offset] ^ d[1 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[6 + offset];
bool c1 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset];
bool c2 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset];
bool c3 = d[0 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[8 + offset];
byte n = 0x00;
n |= (byte)((c0 != d[9 + offset]) ? 0x01U : 0x00U);
n |= (byte)((c1 != d[10 + offset]) ? 0x02U : 0x00U);
n |= (byte)((c2 != d[11 + offset]) ? 0x04U : 0x00U);
n |= (byte)((c3 != d[12 + offset]) ? 0x08U : 0x00U);
switch (n)
{
// Parity bit errors
case 0x01: d[9 + offset] = !d[9 + offset]; return true;
case 0x02: d[10 + offset] = !d[10 + offset]; return true;
case 0x04: d[11 + offset] = !d[11 + offset]; return true;
case 0x08: d[12 + offset] = !d[12 + offset]; return true;
// Data bit erros
case 0x0F: d[0 + offset] = !d[0 + offset]; return true;
case 0x07: d[1 + offset] = !d[1 + offset]; return true;
case 0x0E: d[2 + offset] = !d[2 + offset]; return true;
case 0x05: d[3 + offset] = !d[3 + offset]; return true;
case 0x0A: d[4 + offset] = !d[4 + offset]; return true;
case 0x0D: d[5 + offset] = !d[5 + offset]; return true;
case 0x03: d[6 + offset] = !d[6 + offset]; return true;
case 0x06: d[7 + offset] = !d[7 + offset]; return true;
case 0x0C: d[8 + offset] = !d[8 + offset]; return true;
// No bit errors
default: return false;
}
}
///
/// Encode Hamming (13,9,3).
///
/// Boolean bit array.
///
public static void encode1393(ref bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this column should have
d[9 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[6 + offset];
d[10 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset];
d[11 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset];
d[12 + offset] = d[0 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[8 + offset];
}
///
/// Decode Hamming (10,6,3).
///
/// Boolean bit array.
///
/// True, if bit errors are detected, otherwise false.
public static bool decode1063(bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this column should have
bool c0 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[5 + offset];
bool c1 = d[0 + offset] ^ d[1 + offset] ^ d[3 + offset] ^ d[5 + offset];
bool c2 = d[0 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset];
bool c3 = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset];
byte n = 0x00;
n |= (byte)((c0 != d[6 + offset]) ? 0x01U : 0x00U);
n |= (byte)((c1 != d[7 + offset]) ? 0x02U : 0x00U);
n |= (byte)((c2 != d[8 + offset]) ? 0x04U : 0x00U);
n |= (byte)((c3 != d[9 + offset]) ? 0x08U : 0x00U);
switch (n)
{
// Parity bit errors
case 0x01: d[6 + offset] = !d[6 + offset]; return true;
case 0x02: d[7 + offset] = !d[7 + offset]; return true;
case 0x04: d[8 + offset] = !d[8 + offset]; return true;
case 0x08: d[9 + offset] = !d[9 + offset]; return true;
// Data bit erros
case 0x07: d[0 + offset] = !d[0 + offset]; return true;
case 0x0B: d[1 + offset] = !d[1 + offset]; return true;
case 0x0D: d[2 + offset] = !d[2 + offset]; return true;
case 0x0E: d[3 + offset] = !d[3 + offset]; return true;
case 0x0C: d[4 + offset] = !d[4 + offset]; return true;
case 0x03: d[5 + offset] = !d[5 + offset]; return true;
// No bit errors
default: return false;
}
}
///
/// Encode Hamming (10,6,3).
///
/// Boolean bit array.
///
public static void encode1063(ref bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this column should have
d[6 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[5 + offset];
d[7 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[3 + offset] ^ d[5 + offset];
d[8 + offset] = d[0 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset];
d[9 + offset] = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset];
}
///
/// Decode Hamming (16,11,4).
///
/// Boolean bit array.
///
/// True, if bit errors are detected or no bit errors, otherwise false if unrecoverable errors are detected.
public static bool decode16114(bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this column should have
bool c0 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset];
bool c1 = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[9 + offset];
bool c2 = d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[9 + offset] ^ d[10 + offset];
bool c3 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[10 + offset];
bool c4 = d[0 + offset] ^ d[2 + offset] ^ d[5 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[9 + offset] ^ d[10 + offset];
// Compare these with the actual bits
byte n = 0x00;
n |= (byte)((c0 != d[11 + offset]) ? 0x01U : 0x00U);
n |= (byte)((c1 != d[12 + offset]) ? 0x02U : 0x00U);
n |= (byte)((c2 != d[13 + offset]) ? 0x04U : 0x00U);
n |= (byte)((c3 != d[14 + offset]) ? 0x08U : 0x00U);
n |= (byte)((c4 != d[15 + offset]) ? 0x10U : 0x00U);
switch (n)
{
// Parity bit errors
case 0x01: d[11 + offset] = !d[11 + offset]; return true;
case 0x02: d[12 + offset] = !d[12 + offset]; return true;
case 0x04: d[13 + offset] = !d[13 + offset]; return true;
case 0x08: d[14 + offset] = !d[14 + offset]; return true;
case 0x10: d[15 + offset] = !d[15 + offset]; return true;
// Data bit errors
case 0x19: d[0 + offset] = !d[0 + offset]; return true;
case 0x0B: d[1 + offset] = !d[1 + offset]; return true;
case 0x1F: d[2 + offset] = !d[2 + offset]; return true;
case 0x07: d[3 + offset] = !d[3 + offset]; return true;
case 0x0E: d[4 + offset] = !d[4 + offset]; return true;
case 0x15: d[5 + offset] = !d[5 + offset]; return true;
case 0x1A: d[6 + offset] = !d[6 + offset]; return true;
case 0x0D: d[7 + offset] = !d[7 + offset]; return true;
case 0x13: d[8 + offset] = !d[8 + offset]; return true;
case 0x16: d[9 + offset] = !d[9 + offset]; return true;
case 0x1C: d[10 + offset] = !d[10 + offset]; return true;
// No bit errors
case 0x00: return true;
// Unrecoverable errors
default: return false;
}
}
///
/// Encode Hamming (10,6,3).
///
/// Boolean bit array.
///
public static void encode16114(ref bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
d[11 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[8 + offset];
d[12 + offset] = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[9 + offset];
d[13 + offset] = d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[9 + offset] ^ d[10 + offset];
d[14 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[4 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[10 + offset];
d[15 + offset] = d[0 + offset] ^ d[2 + offset] ^ d[5 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[9 + offset] ^ d[10 + offset];
}
///
/// Decode Hamming (17,12,3).
///
/// Boolean bit array.
///
/// True, if bit errors are detected or no bit errors, otherwise false if unrecoverable errors are detected.
public static bool decode17123(bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
// Calculate the checksum this column should have
bool c0 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[9 + offset];
bool c1 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[7 + offset] ^ d[8 + offset] ^ d[10 + offset];
bool c2 = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[8 + offset] ^ d[9 + offset] ^ d[11 + offset];
bool c3 = d[0 + offset] ^ d[1 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[10 + offset];
bool c4 = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[5 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[11 + offset];
// Compare these with the actual bits
byte n = 0x00;
n |= (byte)((c0 != d[12 + offset]) ? 0x01U : 0x00U);
n |= (byte)((c1 != d[13 + offset]) ? 0x02U : 0x00U);
n |= (byte)((c2 != d[14 + offset]) ? 0x04U : 0x00U);
n |= (byte)((c3 != d[15 + offset]) ? 0x08U : 0x00U);
n |= (byte)((c4 != d[16 + offset]) ? 0x10U : 0x00U);
switch (n)
{
// Parity bit errors
case 0x01: d[12 + offset] = !d[12 + offset]; return true;
case 0x02: d[13 + offset] = !d[13 + offset]; return true;
case 0x04: d[14 + offset] = !d[14 + offset]; return true;
case 0x08: d[15 + offset] = !d[15 + offset]; return true;
case 0x10: d[16 + offset] = !d[16 + offset]; return true;
// Data bit errors
case 0x1B: d[0 + offset] = !d[0 + offset]; return true;
case 0x1F: d[1 + offset] = !d[1 + offset]; return true;
case 0x17: d[2 + offset] = !d[2 + offset]; return true;
case 0x07: d[3 + offset] = !d[3 + offset]; return true;
case 0x0E: d[4 + offset] = !d[4 + offset]; return true;
case 0x1C: d[5 + offset] = !d[5 + offset]; return true;
case 0x11: d[6 + offset] = !d[6 + offset]; return true;
case 0x0B: d[7 + offset] = !d[7 + offset]; return true;
case 0x16: d[8 + offset] = !d[8 + offset]; return true;
case 0x05: d[9 + offset] = !d[9 + offset]; return true;
case 0x0A: d[10 + offset] = !d[10 + offset]; return true;
case 0x14: d[11 + offset] = !d[11 + offset]; return true;
// No bit errors
case 0x00: return true;
// Unrecoverable errors
default: return false;
}
}
///
/// Encode Hamming (17,12,3).
///
/// Boolean bit array.
///
public static void encode17123(ref bool[] d, int offset = 0)
{
if (d == null)
throw new NullReferenceException("d");
d[12 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[6 + offset] ^ d[7 + offset] ^ d[9 + offset];
d[13 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[7 + offset] ^ d[8 + offset] ^ d[10 + offset];
d[14 + offset] = d[1 + offset] ^ d[2 + offset] ^ d[3 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[8 + offset] ^ d[9 + offset] ^ d[11 + offset];
d[15 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[4 + offset] ^ d[5 + offset] ^ d[7 + offset] ^ d[10 + offset];
d[16 + offset] = d[0 + offset] ^ d[1 + offset] ^ d[2 + offset] ^ d[5 + offset] ^ d[6 + offset] ^ d[8 + offset] ^ d[11 + offset];
}
} // public sealed class Hamming
} // namespace fnecore.EDAC