mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-15 10:07:26 -05:00
Golay24.checkAndCorrect indexed the word from bit 0 (getInt(0, 22), xor(12, ...), flip(index)) and took the parity over the whole message, so it was only right for a message that is exactly one 24-bit word. P25 TDULC words 2-12 and the DMR voice superframe words at 24 and 48 were "corrected" in the wrong bits. Decode any other word in a 24-bit copy and write it back. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
198 lines
6.2 KiB
Java
198 lines
6.2 KiB
Java
/*
|
|
* *****************************************************************************
|
|
* Copyright (C) 2014-2024 Dennis Sheirer
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>
|
|
* ****************************************************************************
|
|
*/
|
|
|
|
package io.github.dsheirer.edac;
|
|
|
|
import io.github.dsheirer.bits.BinaryMessage;
|
|
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/**
|
|
* Galois 24/12/7 decoder
|
|
*/
|
|
public class Golay24
|
|
{
|
|
private final static Logger mLog = LoggerFactory.getLogger(Golay24.class);
|
|
|
|
/**
|
|
* Galois 24/12 checksums generated by:
|
|
*
|
|
* CRCUtil.generate( 12, 11, 0xC75, 0x0, true );
|
|
*/
|
|
public static final int[] CHECKSUMS = new int[]
|
|
{
|
|
0x63A, 0x31D, 0x7B4, 0x3DA, 0x1ED, 0x6CC, 0x366, 0x1B3,
|
|
0x6E3, 0x54B, 0x49F, 0x475, 0x400, 0x200, 0x100, 0x080,
|
|
0x040, 0x020, 0x010, 0x008, 0x004, 0x002, 0x001
|
|
};
|
|
|
|
private static int calculateChecksum(BinaryMessage message, int startIndex)
|
|
{
|
|
int calculated = 0; //Starting value
|
|
|
|
/* Iterate the set bits and XOR running checksum with lookup value */
|
|
for(int i = message.nextSetBit(startIndex);
|
|
i >= startIndex && i < startIndex + 12;
|
|
i = message.nextSetBit(i + 1))
|
|
{
|
|
calculated ^= CHECKSUMS[i - startIndex];
|
|
}
|
|
|
|
return calculated;
|
|
}
|
|
|
|
/**
|
|
* Performs error detection and returns a corrected copy of the 24-bit
|
|
* message that starts at the start index.
|
|
*
|
|
* @param message - source message containing startIndex + 24 bits length
|
|
* @param startIndex - start of the 24-bit galois 24 protected bit set
|
|
* @return - corrected 24-bit galois value
|
|
*/
|
|
public static int checkAndCorrect(CorrectedBinaryMessage message, int startIndex)
|
|
{
|
|
//The correction below indexes the word from bit 0 and takes the parity over the whole message, so it is only
|
|
//correct for a message that is exactly the 24-bit word. Decode any other word in a 24-bit copy.
|
|
if(startIndex != 0 || message.size() != 24)
|
|
{
|
|
CorrectedBinaryMessage word = new CorrectedBinaryMessage(24);
|
|
int original = message.getInt(startIndex, startIndex + 23);
|
|
word.load(0, 24, original);
|
|
int result = checkAndCorrectWord(word);
|
|
int corrected = word.getInt(0, 23);
|
|
message.load(startIndex, 24, corrected);
|
|
message.incrementCorrectedBitCount(Integer.bitCount(original ^ corrected));
|
|
return result;
|
|
}
|
|
|
|
return checkAndCorrectWord(message);
|
|
}
|
|
|
|
/**
|
|
* Error detection and correction of a message that is exactly one 24-bit word.
|
|
*/
|
|
private static int checkAndCorrectWord(CorrectedBinaryMessage message)
|
|
{
|
|
int startIndex = 0;
|
|
boolean parityError = message.cardinality() % 2 != 0;
|
|
|
|
int syndrome = getSyndrome(message, startIndex);
|
|
|
|
/* No errors */
|
|
if(syndrome == 0)
|
|
{
|
|
if(parityError)
|
|
{
|
|
message.flip(startIndex + 23);
|
|
message.incrementCorrectedBitCount(1);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Get original message value */
|
|
int original = message.getInt(0, 22);
|
|
|
|
int index = -1;
|
|
int syndromeWeight = 3;
|
|
int errors = 0;
|
|
|
|
while(index < 23)
|
|
{
|
|
if(index != -1)
|
|
{
|
|
/* restore the previous flipped bit */
|
|
if(index > 0)
|
|
{
|
|
message.flip(index - 1);
|
|
}
|
|
|
|
message.flip(index);
|
|
|
|
syndromeWeight = 2;
|
|
}
|
|
|
|
syndrome = getSyndrome(message, startIndex);
|
|
|
|
if(syndrome > 0)
|
|
{
|
|
for(int i = 0; i < 23; i++)
|
|
{
|
|
|
|
errors = Integer.bitCount(syndrome);
|
|
|
|
if(errors <= syndromeWeight)
|
|
{
|
|
message.xor(12, 11, syndrome);
|
|
|
|
message.rotateRight(i, startIndex, startIndex + 22);
|
|
|
|
if(index >= 0)
|
|
{
|
|
errors++;
|
|
}
|
|
|
|
int corrected = message.getInt(0, 22);
|
|
|
|
if(Integer.bitCount(original ^ corrected) > 3)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
message.rotateLeft(startIndex, startIndex + 22);
|
|
syndrome = getSyndrome(message, startIndex);
|
|
}
|
|
}
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
private static int getSyndrome(BinaryMessage message, int startIndex)
|
|
{
|
|
int calculated = calculateChecksum(message, startIndex);
|
|
|
|
int checksum = message.getInt(startIndex + 12, startIndex + 22);
|
|
|
|
return (checksum ^ calculated);
|
|
}
|
|
|
|
public static void main(String[] args)
|
|
{
|
|
// CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("F3BB20"));
|
|
// CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("F0C5C0"));
|
|
CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("AFAC00"));
|
|
|
|
System.out.println("M:" + bm.toHexString());
|
|
int a = Golay24.checkAndCorrect(bm, 0);
|
|
System.out.println("M:" + bm.toHexString());
|
|
|
|
System.out.println("A:" + a);
|
|
}
|
|
}
|