add more P25 Phase 2 primitives for S-OEMI sync and Hamming (8,4,4) for P2 DUID handling;

r05a04_dev
Bryan Biedenkapp 3 weeks ago
parent 87cda7a3d3
commit 7c28cffb1b

@ -5,6 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2026 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "edac/Hamming.h" #include "edac/Hamming.h"
@ -360,3 +361,93 @@ void Hamming::encode17123(bool* d)
d[15] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10]; d[15] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10];
d[16] = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11]; d[16] = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11];
} }
/* Decode Hamming (8,4,4). */
bool Hamming::decode844(bool* d)
{
assert(d != nullptr);
// Hamming(8,4,4) extended code layout:
// d[0..3] = data bits (4 bits)
// d[4..6] = parity bits (3 bits) - Hamming(7,4,3) parity
// d[7] = overall parity bit (1 bit)
//
// Parity check matrix:
// P0 (d[4]) = d[0] ^ d[1] ^ d[3]
// P1 (d[5]) = d[0] ^ d[2] ^ d[3]
// P2 (d[6]) = d[1] ^ d[2] ^ d[3]
// P3 (d[7]) = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] (overall parity)
// Calculate syndrome bits for Hamming(7,4,3) portion
bool c0 = d[0] ^ d[1] ^ d[3] ^ d[4]; // Check P0
bool c1 = d[0] ^ d[2] ^ d[3] ^ d[5]; // Check P1
bool c2 = d[1] ^ d[2] ^ d[3] ^ d[6]; // Check P2
// Calculate overall parity
bool c3 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7];
// Build syndrome
unsigned char syndrome = 0x00U;
syndrome |= c0 ? 0x01U : 0x00U;
syndrome |= c1 ? 0x02U : 0x00U;
syndrome |= c2 ? 0x04U : 0x00U;
// If overall parity is wrong and syndrome is non-zero, single bit error
// If overall parity is wrong and syndrome is zero, error in parity bit d[7]
// If overall parity is correct and syndrome is non-zero, double bit error (uncorrectable)
// If both are correct, no error
if (c3) {
// Overall parity error detected
if (syndrome == 0x00U) {
// Error in overall parity bit
d[7] = !d[7];
return true;
}
else {
// Single bit error - syndrome tells us which bit
switch (syndrome) {
case 0x03U: d[0] = !d[0]; return true; // d0 position
case 0x05U: d[1] = !d[1]; return true; // d1 position
case 0x06U: d[2] = !d[2]; return true; // d2 position
case 0x07U: d[3] = !d[3]; return true; // d3 position
case 0x01U: d[4] = !d[4]; return true; // P0 position
case 0x02U: d[5] = !d[5]; return true; // P1 position
case 0x04U: d[6] = !d[6]; return true; // P2 position
default: return false; // Should not happen
}
}
}
else {
// Overall parity correct
if (syndrome == 0x00U) {
// No errors
return false;
}
else {
// Double bit error detected - uncorrectable
return false;
}
}
}
/* Encode Hamming (8,4,4). */
void Hamming::encode844(bool* d)
{
assert(d != nullptr);
// Hamming(8,4,4) extended code
// d[0..3] = data bits (input)
// d[4..6] = parity bits (calculated)
// d[7] = overall parity bit (calculated)
// Calculate Hamming(7,4,3) parity bits
d[4] = d[0] ^ d[1] ^ d[3]; // P0
d[5] = d[0] ^ d[2] ^ d[3]; // P1
d[6] = d[1] ^ d[2] ^ d[3]; // P2
// Calculate overall parity bit
d[7] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6];
}

@ -5,6 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2026 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -102,6 +103,18 @@ namespace edac
* @param d Boolean bit array. * @param d Boolean bit array.
*/ */
static void encode17123(bool* d); static void encode17123(bool* d);
/**
* @brief Decode Hamming (8,4,4).
* @param d Boolean bit array.
* @returns bool True, if bit errors are detected, otherwise false.
*/
static bool decode844(bool* d);
/**
* @brief Encode Hamming (8,4,4).
* @param d Boolean bit array.
*/
static void encode844(bool* d);
}; };
} // namespace edac } // namespace edac

@ -66,6 +66,11 @@ namespace p25
const uint32_t P25_P2_FRAME_LENGTH_BYTES = 40U; const uint32_t P25_P2_FRAME_LENGTH_BYTES = 40U;
const uint32_t P25_P2_FRAME_LENGTH_BITS = P25_P2_FRAME_LENGTH_BYTES * 8U; const uint32_t P25_P2_FRAME_LENGTH_BITS = P25_P2_FRAME_LENGTH_BYTES * 8U;
const uint32_t P25_P2_IEMI_LENGTH_BITS = 312U;
const uint32_t P25_P2_IEMI_LENGTH_BYTES = (P25_P2_IEMI_LENGTH_BITS / 8U) + 1U;
const uint32_t P25_P2_SOEMI_LENGTH_BITS = 270U;
const uint32_t P25_P2_SOEMI_LENGTH_BYTES = (P25_P2_SOEMI_LENGTH_BITS / 8U) + 1U;
const uint32_t P25_NID_LENGTH_BYTES = 8U; const uint32_t P25_NID_LENGTH_BYTES = 8U;
const uint32_t P25_NID_LENGTH_BITS = P25_NID_LENGTH_BYTES * 8U; const uint32_t P25_NID_LENGTH_BITS = P25_NID_LENGTH_BYTES * 8U;
@ -852,6 +857,24 @@ namespace p25
}; };
} }
// TIA-102.BBAD-D Section 4.2
/** @brief Phase 2 MAC 4V/SACCH Offset(s) */
namespace P2_MAC_HEADER_OFFSET {
/** @brief Phase 2 MAC 4V/SACCH Offset(s) */
enum : uint8_t {
FIRST_4V_NEXT = 0x00U, //!< First 4V Next non-SACCH Burst on Slot
FIRST_4V_2ND = 0x01U, //!< First 4V Second non-SACCH Burst on Slot
FIRST_4V_3RD = 0x02U, //!< First 4V Third non-SACCH Burst on Slot
FIRST_4V_4TH = 0x03U, //!< First 4V Fourth non-SACCH Burst on Slot
FIRST_4V_5TH = 0x04U, //!< First 4V Fifth non-SACCH Burst on Slot
FIRST_4V_6TH = 0x05U, //!< First 4V Sixth non-SACCH Burst on Slot (Inbound Reserved)
INBOUND_RANDOM_SACCH = 0x06U, //!< Inbound Random SACCH (Outbound Reserved)
NO_VOICE_OR_UNK = 0x07U //!< No Voice or Unknown
};
}
// TIA-102.BBAD-D Section 3 // TIA-102.BBAD-D Section 3
/** @brief Phase 2 MAC MCO Partitioning */ /** @brief Phase 2 MAC MCO Partitioning */
namespace P2_MAC_MCO_PARTITION { namespace P2_MAC_MCO_PARTITION {

@ -5,7 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2024,2026 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "Defines.h" #include "Defines.h"
@ -30,3 +30,17 @@ void Sync::addP25Sync(uint8_t* data)
::memcpy(data, P25_SYNC_BYTES, P25_SYNC_LENGTH_BYTES); ::memcpy(data, P25_SYNC_BYTES, P25_SYNC_LENGTH_BYTES);
} }
/* Helper to append P25 Phase 2 S-OEMI sync bytes to the passed buffer. */
void Sync::addP25P2_SOEMISync(uint8_t* data)
{
assert(data != nullptr);
for (uint32_t i = 0U; i < P25_P2_OEMI_SYNC_LENGTH_BITS; i++) {
uint32_t n = i + 4U + 134U; // this skips the 4 bits of the DUID and remaining 134 bits of Field 1 and 2 for
// a S-OEMI
bool b = READ_BIT(P25_P2_OEMI_SYNC_BYTES, i);
WRITE_BIT(data, n, b);
}
}

@ -5,6 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2026 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -35,6 +36,12 @@ namespace p25
* @param data Buffer to append P25 sync bytes to. * @param data Buffer to append P25 sync bytes to.
*/ */
static void addP25Sync(uint8_t* data); static void addP25Sync(uint8_t* data);
/**
* @brief Helper to append P25 Phase 2 S-OEMI sync bytes to the passed buffer.
* @param data Buffer to append P25 Phase 2 OEMI sync bytes to.
*/
static void addP25P2_SOEMISync(uint8_t* data);
}; };
} // namespace p25 } // namespace p25

Loading…
Cancel
Save

Powered by TurnKey Linux.