mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 00:57:31 -05:00
P25 work in progress
This commit is contained in:
73
src/edac/CRC.java
Normal file
73
src/edac/CRC.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
public enum CRC
|
||||
{
|
||||
PASSED ( "*", "PASS" ),
|
||||
PASSED_INV ( "#", "PASS INVERTED" ),
|
||||
FAILED_CRC ( "f", "FAIL CRC" ),
|
||||
FAILED_PARITY( "p", "FAIL PARITY" ),
|
||||
CORRECTED ( "C", "CORRECTED" ),
|
||||
UNKNOWN ( "-", "UNKNOWN");
|
||||
|
||||
private String mAbbreviation;
|
||||
private String mDisplayText;
|
||||
|
||||
CRC( String abbreviation, String displayText )
|
||||
{
|
||||
mAbbreviation = abbreviation;
|
||||
mDisplayText = displayText;
|
||||
}
|
||||
|
||||
public String getAbbreviation()
|
||||
{
|
||||
return mAbbreviation;
|
||||
}
|
||||
|
||||
public String getDisplayText()
|
||||
{
|
||||
return mDisplayText;
|
||||
}
|
||||
|
||||
public static String format( CRC[] checks )
|
||||
{
|
||||
if( checks == null )
|
||||
{
|
||||
return CRC.UNKNOWN.getAbbreviation();
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for( int x = 0; x < checks.length; x++ )
|
||||
{
|
||||
CRC check = checks[ x ];
|
||||
|
||||
if( check != null )
|
||||
{
|
||||
sb.append( check.getAbbreviation() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( CRC.UNKNOWN.getAbbreviation() );
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
213
src/edac/CRCFleetsync.java
Normal file
213
src/edac/CRCFleetsync.java
Normal file
@@ -0,0 +1,213 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Fleetsync CRC checksum utility
|
||||
*
|
||||
* Fleetsync message blocks are 64 bits in length as follows:
|
||||
* 0 - 47: message bits
|
||||
* 48 - 62: CRC-15 check bits
|
||||
* 63: even parity bit
|
||||
*
|
||||
* Fleetsync uses a CRC-15 (0x6815) with an initial fill of 0x0001, coupled with
|
||||
* an even parity checkbit.
|
||||
*
|
||||
* CRC-15 Generating Polynomial: x15 + x14 + x13 + x11 + x4 + x2 + 1 (0x6815)
|
||||
*/
|
||||
public class CRCFleetsync
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( CRCFleetsync.class );
|
||||
|
||||
private static short[] sCHECKSUMS = new short[] {
|
||||
0x740A, // 111010000001010 Bit 0
|
||||
0x3A05, // 011101000000101 Bit 1
|
||||
0x6908, // 110100100001000 Bit 2
|
||||
0x3484, // 011010010000100 Bit 3
|
||||
0x1A42, // 001101001000010 Bit 4
|
||||
0x0D21, // 000110100100001 Bit 5
|
||||
0x729A, // 111001010011010 Bit 6
|
||||
0x394D, // 011100101001101 Bit 7
|
||||
0x68AC, // 110100010101100 Bit 8
|
||||
0x3456, // 011010001010110 Bit 9
|
||||
0x1A2B, // 001101000101011 Bit 10
|
||||
0x791F, // 111100100011111 Bit 11
|
||||
0x4885, // 100100010000101 Bit 12
|
||||
0x5048, // 101000001001000 Bit 13
|
||||
0x2824, // 010100000100100 Bit 14
|
||||
0x1412, // 001010000010010 Bit 15
|
||||
0x0A09, // 000101000001001 Bit 16
|
||||
0x710E, // 111000100001110 Bit 17
|
||||
0x3887, // 011100010000111 Bit 18
|
||||
0x6849, // 110100001001001 Bit 19
|
||||
0x402E, // 100000000101110 Bit 20
|
||||
0x2017, // 010000000010111 Bit 21
|
||||
0x6401, // 110010000000001 Bit 22
|
||||
0x460A, // 100011000001010 Bit 23
|
||||
0x2305, // 010001100000101 Bit 24
|
||||
0x6588, // 110010110001000 Bit 25
|
||||
0x32C4, // 011001011000100 Bit 26
|
||||
0x1962, // 001100101100010 Bit 27
|
||||
0x0CB1, // 000110010110001 Bit 28
|
||||
0x7252, // 111001001010010 Bit 29
|
||||
0x3929, // 011100100101001 Bit 30
|
||||
0x689E, // 110100010011110 Bit 31
|
||||
0x344F, // 011010001001111 Bit 32
|
||||
0x6E2D, // 110111000101101 Bit 33
|
||||
0x431C, // 100001100011100 Bit 34
|
||||
0x218E, // 010000110001110 Bit 35
|
||||
0x10C7, // 001000011000111 Bit 36
|
||||
0x7C69, // 111110001101001 Bit 37
|
||||
0x4A3E, // 100101000111110 Bit 38
|
||||
0x251F, // 010010100011111 Bit 39
|
||||
0x6685, // 110011010000101 Bit 40
|
||||
0x4748, // 100011101001000 Bit 41
|
||||
0x23A4, // 010001110100100 Bit 42
|
||||
0x11D2, // 001000111010010 Bit 43
|
||||
0x08E9, // 000100011101001 Bit 44
|
||||
0x707E, // 111000001111110 Bit 45
|
||||
0x383F, // 011100000111111 Bit 46
|
||||
0x6815, // 110100000010101 Bit 47
|
||||
|
||||
//Single bit errors in the CRC Checksum
|
||||
0x4000, //Bit 48
|
||||
0x2000, //Bit 49
|
||||
0x1000, //Bit 50
|
||||
0x0800, //Bit 51
|
||||
0x0400, //Bit 52
|
||||
0x0200, //Bit 53
|
||||
0x0100, //Bit 54
|
||||
0x0080, //Bit 55
|
||||
0x0040, //Bit 56
|
||||
0x0020, //Bit 57
|
||||
0x0010, //Bit 58
|
||||
0x0008, //Bit 59
|
||||
0x0004, //Bit 60
|
||||
0x0002, //Bit 61
|
||||
0x0001 //Bit 62
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if message bits 0 - 47 pass the Fleetsync CRC checksum
|
||||
* contained in bits 48 - 63, using a lookup table of CRC checksum values
|
||||
* derived from the CRC-15 value, and verifies the message has even parity
|
||||
*/
|
||||
public static CRC check( BitSet msg )
|
||||
{
|
||||
CRC crc = CRC.UNKNOWN;
|
||||
|
||||
int calculated = 1; //Starting value
|
||||
|
||||
//Check even parity
|
||||
if( msg.cardinality() % 2 == 0 )
|
||||
{
|
||||
//Iterate bits that are set and XOR running checksum with lookup value
|
||||
for (int i = msg.nextSetBit( 0 ); i >= 0 && i < 48; i = msg.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= sCHECKSUMS[ i ];
|
||||
}
|
||||
|
||||
if( calculated == getChecksum( msg ) )
|
||||
{
|
||||
crc = CRC.PASSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = CRC.FAILED_CRC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = CRC.FAILED_PARITY;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer value of the 15 bit crc checksum
|
||||
*/
|
||||
public static int getChecksum( BitSet msg )
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
for( int x = 0; x < 15; x++ )
|
||||
{
|
||||
if( msg.get( x + 48 ) )
|
||||
{
|
||||
retVal += 1<<( 14 - x );
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the errant bit positions and returns them in an array of
|
||||
* integer bit positions.
|
||||
*
|
||||
* Note: currently only detects single-bit errors
|
||||
*
|
||||
* @param msg to be checked for errors
|
||||
* @return - array of integer positions of bits that need flipped
|
||||
*/
|
||||
public static int[] findBitErrors( BitSet msg )
|
||||
{
|
||||
int[] retVal = null;
|
||||
|
||||
int checksum = getChecksum( msg );
|
||||
|
||||
//Remove the initial fill value (1)
|
||||
checksum ^= 1;
|
||||
|
||||
//Iterate set message bits, removing their respective checksum value
|
||||
//from the transmitted checksum, to arrive at the remainder
|
||||
for (int i = msg.nextSetBit( 0 ); i >= 0 && i < 48; i = msg.nextSetBit( i+1 ) )
|
||||
{
|
||||
checksum ^= sCHECKSUMS[ i ];
|
||||
}
|
||||
|
||||
//If at this point the checksum is 0, then we have a parity bit error
|
||||
if( checksum == 0 )
|
||||
{
|
||||
retVal = new int[ 1 ];
|
||||
retVal[ 0 ] = 63;
|
||||
}
|
||||
//Otherwise, try to lookup the syndrome for a single bit error
|
||||
else
|
||||
{
|
||||
for( int x = 0; x < 63; x++ )
|
||||
{
|
||||
if( checksum == sCHECKSUMS[ x ] )
|
||||
{
|
||||
//return this bit position
|
||||
retVal = new int[ 1 ];
|
||||
retVal[ 0 ] = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
212
src/edac/CRCLJ.java
Normal file
212
src/edac/CRCLJ.java
Normal file
@@ -0,0 +1,212 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import bits.BitSetBuffer;
|
||||
|
||||
/**
|
||||
* LJ CRC checksum utility
|
||||
*
|
||||
* LJ message blocks are 80 bits in length as follows:
|
||||
* 0 - 7: Bit reversals
|
||||
* 8 - 15: Sync pattern
|
||||
* 16 - 23: VRC
|
||||
* 24 - 31: LRC
|
||||
* 32 - 35: Function Code
|
||||
* 36 - 63: Address
|
||||
* 64 - 79: CRC
|
||||
*
|
||||
* Each field is transmitted in big-endian bit order, including the CRC. Only
|
||||
* the Function and Address fields are protected by the CRC.
|
||||
*
|
||||
* LJ uses a CRC-16 (0x6F63) with an initial fill of 0.
|
||||
*
|
||||
* Generating Polynomial: x14 + x13 + x11 + x10 + x9 + x8 + x6 + x5 + x1 + 1 (0x6F63)
|
||||
*/
|
||||
public class CRCLJ
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( CRCLJ.class );
|
||||
|
||||
private static final int MESSAGE_START = 32;
|
||||
private static final int CRC_START = 64;
|
||||
|
||||
private static int[] CHECKSUMS = new int[]
|
||||
{
|
||||
0x26EA, //Function 0 (LSB)
|
||||
0x1375, //Function 1
|
||||
0xBE0B, //Function 2
|
||||
0xE8B4, //Function 3 (MSB)
|
||||
0x745A, //Address 0 (LSB)
|
||||
0x3A2D, //Address 1
|
||||
0xAAA7, //Address 2
|
||||
0xE2E2, //Address 3
|
||||
0x7171, //Address 4
|
||||
0x8F09, //Address 5
|
||||
0xF035, //Address 6
|
||||
0xCFAB, //Address 7
|
||||
0xD064, //Address 8
|
||||
0x6832, //Address 9
|
||||
0x3419, //Address 10
|
||||
0xADBD, //Address 11
|
||||
0xE16F, //Address 12
|
||||
0xC706, //Address 13
|
||||
0x6383, //Address 14
|
||||
0x8670, //Address 15
|
||||
0x4338, //Address 16
|
||||
0x219C, //Address 17
|
||||
0x10CE, //Address 18
|
||||
0x0867, //Address 19
|
||||
0xB382, //Address 20
|
||||
0x59C1, //Address 21
|
||||
0x9B51, //Address 22
|
||||
0xFA19, //Address 23
|
||||
0xCABD, //Address 24
|
||||
0xD2EF, //Address 25
|
||||
0xDEC6, //Address 26
|
||||
0x6F63, //Address 27 (MSB)
|
||||
|
||||
//Single bit errors in the CRC Checksum
|
||||
0x8000, //CRC 0
|
||||
0x4000, //CRC 1
|
||||
0x2000, //CRC 2
|
||||
0x1000, //CRC 3
|
||||
0x0800, //CRC 4
|
||||
0x0400, //CRC 5
|
||||
0x0200, //CRC 6
|
||||
0x0100, //CRC 7
|
||||
0x0080, //CRC 8
|
||||
0x0040, //CRC 9
|
||||
0x0020, //CRC 10
|
||||
0x0010, //CRC 11
|
||||
0x0008, //CRC 12
|
||||
0x0004, //CRC 13
|
||||
0x0002, //CRC 14
|
||||
0x0001 //CRC 15
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if FUNCTION AND ADDRESS bits pass the LJ CRC checksum
|
||||
* using a lookup table of CRC checksum values derived from the CRC-16 value
|
||||
*/
|
||||
public static CRC checkAndCorrect( BitSetBuffer message )
|
||||
{
|
||||
int calculated = 0; //Starting value
|
||||
|
||||
/* Iterate the set bits and XOR running checksum with lookup value */
|
||||
for (int i = message.nextSetBit( MESSAGE_START );
|
||||
i >= MESSAGE_START && i < CRC_START;
|
||||
i = message.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= CHECKSUMS[ i - MESSAGE_START ];
|
||||
}
|
||||
|
||||
int checksum = getChecksum( message );
|
||||
|
||||
if( calculated == checksum )
|
||||
{
|
||||
return CRC.PASSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] errors = findBitErrors( calculated ^ checksum );
|
||||
|
||||
if( errors != null )
|
||||
{
|
||||
for( int error: errors )
|
||||
{
|
||||
message.flip( MESSAGE_START + error );
|
||||
}
|
||||
|
||||
return CRC.CORRECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return CRC.FAILED_CRC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer value of the 16 bit crc checksum
|
||||
*/
|
||||
public static int getChecksum( BitSet msg )
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
for( int x = 0; x < 16; x++ )
|
||||
{
|
||||
if( msg.get( x + CRC_START ) )
|
||||
{
|
||||
retVal += 1<<( 15 - x );
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies 1 or 2 bit error positions that match the checksum error value.
|
||||
*/
|
||||
public static int[] findBitErrors( int checksumError )
|
||||
{
|
||||
/* One bit errors */
|
||||
for( int x = 0; x < 48; x++ )
|
||||
{
|
||||
if( CHECKSUMS[ x ] == checksumError )
|
||||
{
|
||||
int[] errors = new int[ 1 ];
|
||||
|
||||
errors[ 0 ] = x;
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
/* Two bit errors */
|
||||
for( int x = 0; x < 48; x++ )
|
||||
{
|
||||
for( int y = 0; y < 48; y++ )
|
||||
{
|
||||
if( x != y &&
|
||||
( CHECKSUMS[ x ] ^ CHECKSUMS[ y ] ) == checksumError )
|
||||
{
|
||||
int[] errors = new int[ 2 ];
|
||||
|
||||
errors[ 0 ] = x;
|
||||
errors[ 1 ] = y;
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main( String[] args )
|
||||
{
|
||||
BitSetBuffer msg = BitSetBuffer.load( "01010101101010101010000100011000000000100001000110000000001000010001100000000010" );
|
||||
|
||||
CRC crc = checkAndCorrect( msg );
|
||||
|
||||
mLog.debug( "CRC:" + crc.getDisplayText() );
|
||||
}
|
||||
}
|
||||
185
src/edac/CRCLTR.java
Normal file
185
src/edac/CRCLTR.java
Normal file
@@ -0,0 +1,185 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import message.MessageDirection;
|
||||
|
||||
/**
|
||||
* LTR CRC checksum utility
|
||||
*
|
||||
* LTR message blocks are 41 bits in length as follows:
|
||||
* 0 - 9: Sync
|
||||
* 10 - 34: message bits
|
||||
* 35 - 41: CRC-7 check bits
|
||||
*
|
||||
* LTR uses a CRC-7 (0xFD) with an initial fill of 0x00.
|
||||
*
|
||||
* CRC-7 Generating Polynomial: x7 + x6 + x5 + x4 + x3 + x2 + 1 (0xFD)
|
||||
*/
|
||||
public class CRCLTR
|
||||
{
|
||||
private static byte[] sCHECKSUMS = new byte[]
|
||||
{
|
||||
0x38, //Area
|
||||
0x1C, //Channel 4
|
||||
0x0E, //Channel 3
|
||||
0x46, //Channel 2
|
||||
0x23, //Channel 1
|
||||
0x51, //Channel 0
|
||||
0x68, //Home 4
|
||||
0x75, //Home 3
|
||||
0x7A, //Home 2
|
||||
0x3D, //Home 1
|
||||
0x1F, //Home 0
|
||||
0x4F, //Group 7
|
||||
0x26, //Group 6
|
||||
0x52, //Group 5
|
||||
0x29, //Group 4
|
||||
0x15, //Group 3
|
||||
0x0B, //Group 2
|
||||
0x45, //Group 1
|
||||
0x62, //Group 0
|
||||
0x31, //Free 4
|
||||
0x19, //Free 3
|
||||
0x0D, //Free 2
|
||||
0x07, //Free 1
|
||||
0x43 //Free 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if message bits 10 - 34 pass the LTR CRC checksum
|
||||
* contained in bits 35 - 41, using a lookup table of CRC checksum values
|
||||
* derived from the CRC-7 value.
|
||||
*/
|
||||
public static CRC check( BitSet msg, MessageDirection direction )
|
||||
{
|
||||
CRC crc = CRC.UNKNOWN;
|
||||
|
||||
int calculated = getCalculatedChecksum( msg );
|
||||
int transmitted = getTransmittedChecksum( msg );
|
||||
|
||||
/* Normal CRC only for Outbound Status Word */
|
||||
if( direction == MessageDirection.OSW )
|
||||
{
|
||||
if( calculated == transmitted )
|
||||
{
|
||||
return CRC.PASSED;
|
||||
}
|
||||
}
|
||||
/* Normal or Inverted CRC for Inbound Status Word */
|
||||
else
|
||||
{
|
||||
if( ( calculated ^ 127 ) == transmitted )
|
||||
{
|
||||
return CRC.PASSED_INV;
|
||||
}
|
||||
else if( calculated == transmitted )
|
||||
{
|
||||
return CRC.PASSED;
|
||||
}
|
||||
}
|
||||
|
||||
return CRC.FAILED_CRC;
|
||||
}
|
||||
|
||||
public static byte[] getChecks()
|
||||
{
|
||||
return sCHECKSUMS;
|
||||
}
|
||||
|
||||
public static int getCalculatedChecksum( BitSet msg )
|
||||
{
|
||||
int calculated = 0;
|
||||
|
||||
//Iterate bits that are set and XOR running checksum with lookup value
|
||||
for (int i = msg.nextSetBit( 9 ); i >= 9 && i < 33; i = msg.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= sCHECKSUMS[ i - 9 ];
|
||||
}
|
||||
|
||||
return calculated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer value of the 7 bit crc checksum
|
||||
*/
|
||||
public static int getTransmittedChecksum( BitSet msg )
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
for( int x = 0; x < 7; x++ )
|
||||
{
|
||||
if( msg.get( x + 33 ) )
|
||||
{
|
||||
retVal += 1<<( 6 - x );
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the errant bit positions and returns them in an array of
|
||||
* integer bit positions.
|
||||
*
|
||||
* Note: currently only detects single-bit errors
|
||||
*
|
||||
* @param msg to be checked for errors
|
||||
* @return - array of integer positions of bits that need flipped
|
||||
*/
|
||||
public static int[] findBitErrors( BitSet msg )
|
||||
{
|
||||
int[] retVal = null;
|
||||
|
||||
int checksum = getTransmittedChecksum( msg );
|
||||
|
||||
//Remove the initial fill value (1)
|
||||
checksum ^= 1;
|
||||
|
||||
//Iterate set message bits, removing their respective checksum value
|
||||
//from the transmitted checksum, to arrive at the remainder
|
||||
for (int i = msg.nextSetBit( 0 ); i >= 0 && i < 47; i = msg.nextSetBit( i+1 ) )
|
||||
{
|
||||
checksum ^= sCHECKSUMS[ i ];
|
||||
}
|
||||
|
||||
//If at this point the checksum is 0, then the errant bit is the parity
|
||||
//bit
|
||||
if( checksum == 0 )
|
||||
{
|
||||
msg.flip( 62 );
|
||||
}
|
||||
//Otherwise, try to lookup the syndrome for a single bit error
|
||||
else
|
||||
{
|
||||
for( int x = 0; x < 47; x++ )
|
||||
{
|
||||
if( checksum == sCHECKSUMS[ x ] )
|
||||
{
|
||||
//return this bit position
|
||||
retVal = new int[ 1 ];
|
||||
retVal[ 0 ] = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
458
src/edac/CRCP25.java
Normal file
458
src/edac/CRCP25.java
Normal file
@@ -0,0 +1,458 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import bits.BitSetBuffer;
|
||||
|
||||
/**
|
||||
* P25 CRC check/correction methods
|
||||
*/
|
||||
public class CRCP25
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( CRCP25.class );
|
||||
|
||||
private static final int NID_MESSAGE_START = 0;
|
||||
private static final int NID_CRC_START = 16;
|
||||
private static final int NID_CRC_END = 48;
|
||||
|
||||
/**
|
||||
* Network ID and Data Unit ID checksums
|
||||
*/
|
||||
private static long[] NID_DUID_CHECKSUMS = new long[]
|
||||
{
|
||||
0xCD930BDD3B2Al, 0xAB5A8E33A6BEl, 0x983E4CC4E874l, 0x4C1F2662743Al,
|
||||
0xEB9C98EC0136l, 0xB85D47AB3BB0l, 0x5C2EA3D59DD8l, 0x2E1751EACEECl,
|
||||
0x170BA8F56776l, 0xC616DFA78890l, 0x630B6FD3C448l, 0x3185B7E9E224l,
|
||||
0x18C2DBF4F112l, 0xC1F2662743A2l, 0xAD6A38CE9AFBl, 0x9B2617BA7657l,
|
||||
0x800000000000l, 0x400000000000l, 0x200000000000l, 0x100000000000l,
|
||||
0x080000000000l, 0x040000000000l, 0x020000000000l, 0x010000000000l,
|
||||
0x008000000000l, 0x004000000000l, 0x002000000000l, 0x001000000000l,
|
||||
0x000800000000l, 0x000400000000l, 0x000200000000l, 0x000100000000l,
|
||||
0x000080000000l, 0x000040000000l, 0x000020000000l, 0x000010000000l,
|
||||
0x000008000000l, 0x000004000000l, 0x000002000000l, 0x000001000000l,
|
||||
0x000000800000l, 0x000000400000l, 0x000000200000l, 0x000000100000l,
|
||||
0x000000080000l, 0x000000040000l, 0x000000020000l, 0x000000010000l,
|
||||
0x000000008000l, 0x000000004000l, 0x000000002000l, 0x000000001000l,
|
||||
0x000000000800l, 0x000000000400l, 0x000000000200l, 0x000000000100l,
|
||||
0x000000000080l, 0x000000000040l, 0x000000000020l, 0x000000000010l,
|
||||
0x000000000008l, 0x000000000004l, 0x000000000002l, 0x000000000001l
|
||||
};
|
||||
|
||||
/**
|
||||
* CRC-CCITT 16-bit checksums for a message length of 80 bits plus 16
|
||||
* additional checksums representing CRC checksum bit errors
|
||||
*
|
||||
* Generated by:
|
||||
* CRCUtil.generate( 80, 16, 0x11021l, 0xFFFFl, true );
|
||||
*/
|
||||
public static final int[] CCITT_80_CHECKSUMS = new int[]
|
||||
{
|
||||
0x1BCB, 0x8DE5, 0xC6F2, 0x6B69, 0xB5B4, 0x52CA, 0x2175, 0x90BA, 0x404D,
|
||||
0xA026, 0x5803, 0xAC01, 0xD600, 0x6310, 0x3998, 0x14DC, 0x27E, 0x92F,
|
||||
0x8497, 0xC24B, 0xE125, 0xF092, 0x7059, 0xB82C, 0x5406, 0x2213, 0x9109,
|
||||
0xC884, 0x6C52, 0x3E39, 0x9F1C, 0x479E, 0x2BDF, 0x95EF, 0xCAF7, 0xE57B,
|
||||
0xF2BD, 0xF95E, 0x74BF, 0xBA5F, 0xDD2F, 0xEE97, 0xF74B, 0xFBA5, 0xFDD2,
|
||||
0x76F9, 0xBB7C, 0x55AE, 0x22C7, 0x9163, 0xC8B1, 0xE458, 0x7A3C, 0x350E,
|
||||
0x1297, 0x894B, 0xC4A5, 0xE252, 0x7939, 0xBC9C, 0x565E, 0x233F, 0x919F,
|
||||
0xC8CF, 0xE467, 0xF233, 0xF919, 0xFC8C, 0x7656, 0x333B, 0x999D, 0xCCCE,
|
||||
0x6E77, 0xB73B, 0xDB9D, 0xEDCE, 0x7EF7, 0xBF7B, 0xDFBD, 0xEFDE, 0x0001,
|
||||
0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,
|
||||
0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
||||
};
|
||||
|
||||
/**
|
||||
* CRC-32 checksums for PDU1 ( HEADER + 1 Block ) messages, generated by:
|
||||
*
|
||||
* CRCUtil.generate( 64, 32, 0x104C11DB7l, 0xFFFFFFFFl, true );
|
||||
*/
|
||||
public static final long[] PDU1_CHECKSUMS = new long[]
|
||||
{
|
||||
0x86FFAACCl, 0x411F5BBDl, 0xA08FADDEl, 0x52275834l, 0x2B7322C1l,
|
||||
0x95B99160l, 0x48BC466Bl, 0xA45E2335l, 0xD22F119Al, 0x6B770616l,
|
||||
0x37DB0DD0l, 0x198D0833l, 0x8CC68419l, 0xC663420Cl, 0x61512FDDl,
|
||||
0xB0A897EEl, 0x5A34C52Cl, 0x2F7AEC4Dl, 0x97BD7626l, 0x49BE35C8l,
|
||||
0x26BF943Fl, 0x935FCA1Fl, 0xC9AFE50Fl, 0xE4D7F287l, 0xF26BF943l,
|
||||
0xF935FCA1l, 0xFC9AFE50l, 0x7C2DF1F3l, 0xBE16F8F9l, 0xDF0B7C7Cl,
|
||||
0x6DE530E5l, 0xB6F29872l, 0x5919C2E2l, 0x2EEC6FAAl, 0x1516B90El,
|
||||
0x08EBD25Cl, 0x061567F5l, 0x830AB3FAl, 0x43E5D726l, 0x23926548l,
|
||||
0x13A9BC7Fl, 0x89D4DE3Fl, 0xC4EA6F1Fl, 0xE275378Fl, 0xF13A9BC7l,
|
||||
0xF89D4DE3l, 0xFC4EA6F1l, 0xFE275378l, 0x7D732767l, 0xBEB993B3l,
|
||||
0xDF5CC9D9l, 0xEFAE64ECl, 0x75B7BCADl, 0xBADBDE56l, 0x5F0D61F0l,
|
||||
0x2DE63E23l, 0x96F31F11l, 0xCB798F88l, 0x67DC491Fl, 0xB3EE248Fl,
|
||||
0xD9F71247l, 0xECFB8923l, 0xF67DC491l, 0xFB3EE248l, 0x00000001l,
|
||||
0x00000002l, 0x00000004l, 0x00000008l, 0x00000010l, 0x00000020l,
|
||||
0x00000040l, 0x00000080l, 0x00000100l, 0x00000200l, 0x00000400l,
|
||||
0x00000800l, 0x00001000l, 0x00002000l, 0x00004000l, 0x00008000l,
|
||||
0x00010000l, 0x00020000l, 0x00040000l, 0x00080000l, 0x00100000l,
|
||||
0x00200000l, 0x00400000l, 0x00800000l, 0x01000000l, 0x02000000l,
|
||||
0x04000000l, 0x08000000l, 0x10000000l, 0x20000000l, 0x40000000l,
|
||||
0x80000000l
|
||||
};
|
||||
|
||||
/**
|
||||
* CRC-32 checksums for PDU2 ( HEADER + 2 Blocks ) messages, generated by:
|
||||
*
|
||||
* CRCUtil.generate( 160, 32, 0x104C11DB7l, 0xFFFFFFFFl, true );
|
||||
*/
|
||||
public static final long[] PDU2_CHECKSUMS = new long[]
|
||||
{
|
||||
0x9D231959l, 0xCE918CACl, 0x6528488Dl, 0xB2942446l, 0x5B2A9CF8l,
|
||||
0x2FF5C0A7l, 0x97FAE053l, 0xCBFD7029l, 0xE5FEB814l, 0x709FD2D1l,
|
||||
0xB84FE968l, 0x5E477A6Fl, 0xAF23BD37l, 0xD791DE9Bl, 0xEBC8EF4Dl,
|
||||
0xF5E477A6l, 0x7892B508l, 0x3E29D45Fl, 0x9F14EA2Fl, 0xCF8A7517l,
|
||||
0xE7C53A8Bl, 0xF3E29D45l, 0xF9F14EA2l, 0x7E98298Al, 0x3D2C9A1El,
|
||||
0x1CF6C3D4l, 0x0C1BEF31l, 0x860DF798l, 0x41667517l, 0xA0B33A8Bl,
|
||||
0xD0599D45l, 0xE82CCEA2l, 0x7676E98Al, 0x395BFA1El, 0x1ECD73D4l,
|
||||
0x0D063731l, 0x86831B98l, 0x41210317l, 0xA090818Bl, 0xD04840C5l,
|
||||
0xE8242062l, 0x76729EEAl, 0x3959C1AEl, 0x1ECC6E0Cl, 0x0D06B9DDl,
|
||||
0x86835CEEl, 0x412120ACl, 0x22F01E8Dl, 0x91780F46l, 0x4ADC8978l,
|
||||
0x270ECA67l, 0x93876533l, 0xC9C3B299l, 0xE4E1D94Cl, 0x7010627Dl,
|
||||
0xB808313El, 0x5E649644l, 0x2D52C5F9l, 0x96A962FCl, 0x49343FA5l,
|
||||
0xA49A1FD2l, 0x502D8132l, 0x2A764E42l, 0x175BA9FAl, 0x09CD5A26l,
|
||||
0x068623C8l, 0x01239F3Fl, 0x8091CF9Fl, 0xC048E7CFl, 0xE02473E7l,
|
||||
0xF01239F3l, 0xF8091CF9l, 0xFC048E7Cl, 0x7C62C9E5l, 0xBE3164F2l,
|
||||
0x5D783CA2l, 0x2CDC908Al, 0x140EC69El, 0x0867ED94l, 0x06537811l,
|
||||
0x8329BC08l, 0x43F450DFl, 0xA1FA286Fl, 0xD0FD1437l, 0xE87E8A1Bl,
|
||||
0xF43F450Dl, 0xFA1FA286l, 0x7F6F5F98l, 0x3DD72117l, 0x9EEB908Bl,
|
||||
0xCF75C845l, 0xE7BAE422l, 0x71BDFCCAl, 0x3ABE70BEl, 0x1F3FB684l,
|
||||
0x0DFF5599l, 0x86FFAACCl, 0x411F5BBDl, 0xA08FADDEl, 0x52275834l,
|
||||
0x2B7322C1l, 0x95B99160l, 0x48BC466Bl, 0xA45E2335l, 0xD22F119Al,
|
||||
0x6B770616l, 0x37DB0DD0l, 0x198D0833l, 0x8CC68419l, 0xC663420Cl,
|
||||
0x61512FDDl, 0xB0A897EEl, 0x5A34C52Cl, 0x2F7AEC4Dl, 0x97BD7626l,
|
||||
0x49BE35C8l, 0x26BF943Fl, 0x935FCA1Fl, 0xC9AFE50Fl, 0xE4D7F287l,
|
||||
0xF26BF943l, 0xF935FCA1l, 0xFC9AFE50l, 0x7C2DF1F3l, 0xBE16F8F9l,
|
||||
0xDF0B7C7Cl, 0x6DE530E5l, 0xB6F29872l, 0x5919C2E2l, 0x2EEC6FAAl,
|
||||
0x1516B90El, 0x08EBD25Cl, 0x061567F5l, 0x830AB3FAl, 0x43E5D726l,
|
||||
0x23926548l, 0x13A9BC7Fl, 0x89D4DE3Fl, 0xC4EA6F1Fl, 0xE275378Fl,
|
||||
0xF13A9BC7l, 0xF89D4DE3l, 0xFC4EA6F1l, 0xFE275378l, 0x7D732767l,
|
||||
0xBEB993B3l, 0xDF5CC9D9l, 0xEFAE64ECl, 0x75B7BCADl, 0xBADBDE56l,
|
||||
0x5F0D61F0l, 0x2DE63E23l, 0x96F31F11l, 0xCB798F88l, 0x67DC491Fl,
|
||||
0xB3EE248Fl, 0xD9F71247l, 0xECFB8923l, 0xF67DC491l, 0xFB3EE248l,
|
||||
0x00000001l, 0x00000002l, 0x00000004l, 0x00000008l, 0x00000010l,
|
||||
0x00000020l, 0x00000040l, 0x00000080l, 0x00000100l, 0x00000200l,
|
||||
0x00000400l, 0x00000800l, 0x00001000l, 0x00002000l, 0x00004000l,
|
||||
0x00008000l, 0x00010000l, 0x00020000l, 0x00040000l, 0x00080000l,
|
||||
0x00100000l, 0x00200000l, 0x00400000l, 0x00800000l, 0x01000000l,
|
||||
0x02000000l, 0x04000000l, 0x08000000l, 0x10000000l, 0x20000000l,
|
||||
0x40000000l, 0x80000000l
|
||||
};
|
||||
|
||||
/**
|
||||
* CRC-32 checksums for PDU3 ( HEADER + 3 Blocks ) messages, generated by:
|
||||
*
|
||||
* CRCUtil.generate( 256, 32, 0x104C11DB7l, 0xFFFFFFFFl, true );
|
||||
*/
|
||||
public static final long[] PDU3_CHECKSUMS = new long[]
|
||||
{
|
||||
0xAA5FA470l, 0x574F5CE3l, 0xABA7AE71l, 0xD5D3D738l, 0x68896547l,
|
||||
0xB444B2A3l, 0xDA225951l, 0xED112CA8l, 0x74E8188Fl, 0xBA740C47l,
|
||||
0xDD3A0623l, 0xEE9D0311l, 0xF74E8188l, 0x79C7CE1Fl, 0xBCE3E70Fl,
|
||||
0xDE71F387l, 0xEF38F9C3l, 0xF79C7CE1l, 0xFBCE3E70l, 0x7F8791E3l,
|
||||
0xBFC3C8F1l, 0xDFE1E478l, 0x6D907CE7l, 0xB6C83E73l, 0xDB641F39l,
|
||||
0xEDB20F9Cl, 0x74B98915l, 0xBA5CC48Al, 0x5F4EEC9El, 0x2DC7F894l,
|
||||
0x14837291l, 0x8A41B948l, 0x4740527Fl, 0xA3A0293Fl, 0xD1D0149Fl,
|
||||
0xE8E80A4Fl, 0xF4740527l, 0xFA3A0293l, 0xFD1D0149l, 0xFE8E80A4l,
|
||||
0x7D27CE89l, 0xBE93E744l, 0x5D297D79l, 0xAE94BEBCl, 0x552AD185l,
|
||||
0xAA9568C2l, 0x572A3ABAl, 0x29F59386l, 0x169A4718l, 0x092DAD57l,
|
||||
0x8496D6ABl, 0xC24B6B55l, 0xE125B5AAl, 0x72F2540El, 0x3B19A4DCl,
|
||||
0x1FEC5CB5l, 0x8FF62E5Al, 0x459B99F6l, 0x20AD4220l, 0x12362FCBl,
|
||||
0x891B17E5l, 0xC48D8BF2l, 0x60264B22l, 0x3273AB4Al, 0x1B595B7El,
|
||||
0x0FCC2364l, 0x05869F69l, 0x82C34FB4l, 0x43012901l, 0xA1809480l,
|
||||
0x52A0C49Bl, 0xA950624Dl, 0xD4A83126l, 0x68349648l, 0x367AC5FFl,
|
||||
0x9B3D62FFl, 0xCD9EB17Fl, 0xE6CF58BFl, 0xF367AC5Fl, 0xF9B3D62Fl,
|
||||
0xFCD9EB17l, 0xFE6CF58Bl, 0xFF367AC5l, 0xFF9B3D62l, 0x7DAD106Al,
|
||||
0x3CB606EEl, 0x1C3B8DACl, 0x0C7D480Dl, 0x863EA406l, 0x417FDCD8l,
|
||||
0x22DF60B7l, 0x916FB05Bl, 0xC8B7D82Dl, 0xE45BEC16l, 0x704D78D0l,
|
||||
0x3A4632B3l, 0x9D231959l, 0xCE918CACl, 0x6528488Dl, 0xB2942446l,
|
||||
0x5B2A9CF8l, 0x2FF5C0A7l, 0x97FAE053l, 0xCBFD7029l, 0xE5FEB814l,
|
||||
0x709FD2D1l, 0xB84FE968l, 0x5E477A6Fl, 0xAF23BD37l, 0xD791DE9Bl,
|
||||
0xEBC8EF4Dl, 0xF5E477A6l, 0x7892B508l, 0x3E29D45Fl, 0x9F14EA2Fl,
|
||||
0xCF8A7517l, 0xE7C53A8Bl, 0xF3E29D45l, 0xF9F14EA2l, 0x7E98298Al,
|
||||
0x3D2C9A1El, 0x1CF6C3D4l, 0x0C1BEF31l, 0x860DF798l, 0x41667517l,
|
||||
0xA0B33A8Bl, 0xD0599D45l, 0xE82CCEA2l, 0x7676E98Al, 0x395BFA1El,
|
||||
0x1ECD73D4l, 0x0D063731l, 0x86831B98l, 0x41210317l, 0xA090818Bl,
|
||||
0xD04840C5l, 0xE8242062l, 0x76729EEAl, 0x3959C1AEl, 0x1ECC6E0Cl,
|
||||
0x0D06B9DDl, 0x86835CEEl, 0x412120ACl, 0x22F01E8Dl, 0x91780F46l,
|
||||
0x4ADC8978l, 0x270ECA67l, 0x93876533l, 0xC9C3B299l, 0xE4E1D94Cl,
|
||||
0x7010627Dl, 0xB808313El, 0x5E649644l, 0x2D52C5F9l, 0x96A962FCl,
|
||||
0x49343FA5l, 0xA49A1FD2l, 0x502D8132l, 0x2A764E42l, 0x175BA9FAl,
|
||||
0x09CD5A26l, 0x068623C8l, 0x01239F3Fl, 0x8091CF9Fl, 0xC048E7CFl,
|
||||
0xE02473E7l, 0xF01239F3l, 0xF8091CF9l, 0xFC048E7Cl, 0x7C62C9E5l,
|
||||
0xBE3164F2l, 0x5D783CA2l, 0x2CDC908Al, 0x140EC69El, 0x0867ED94l,
|
||||
0x06537811l, 0x8329BC08l, 0x43F450DFl, 0xA1FA286Fl, 0xD0FD1437l,
|
||||
0xE87E8A1Bl, 0xF43F450Dl, 0xFA1FA286l, 0x7F6F5F98l, 0x3DD72117l,
|
||||
0x9EEB908Bl, 0xCF75C845l, 0xE7BAE422l, 0x71BDFCCAl, 0x3ABE70BEl,
|
||||
0x1F3FB684l, 0x0DFF5599l, 0x86FFAACCl, 0x411F5BBDl, 0xA08FADDEl,
|
||||
0x52275834l, 0x2B7322C1l, 0x95B99160l, 0x48BC466Bl, 0xA45E2335l,
|
||||
0xD22F119Al, 0x6B770616l, 0x37DB0DD0l, 0x198D0833l, 0x8CC68419l,
|
||||
0xC663420Cl, 0x61512FDDl, 0xB0A897EEl, 0x5A34C52Cl, 0x2F7AEC4Dl,
|
||||
0x97BD7626l, 0x49BE35C8l, 0x26BF943Fl, 0x935FCA1Fl, 0xC9AFE50Fl,
|
||||
0xE4D7F287l, 0xF26BF943l, 0xF935FCA1l, 0xFC9AFE50l, 0x7C2DF1F3l,
|
||||
0xBE16F8F9l, 0xDF0B7C7Cl, 0x6DE530E5l, 0xB6F29872l, 0x5919C2E2l,
|
||||
0x2EEC6FAAl, 0x1516B90El, 0x08EBD25Cl, 0x061567F5l, 0x830AB3FAl,
|
||||
0x43E5D726l, 0x23926548l, 0x13A9BC7Fl, 0x89D4DE3Fl, 0xC4EA6F1Fl,
|
||||
0xE275378Fl, 0xF13A9BC7l, 0xF89D4DE3l, 0xFC4EA6F1l, 0xFE275378l,
|
||||
0x7D732767l, 0xBEB993B3l, 0xDF5CC9D9l, 0xEFAE64ECl, 0x75B7BCADl,
|
||||
0xBADBDE56l, 0x5F0D61F0l, 0x2DE63E23l, 0x96F31F11l, 0xCB798F88l,
|
||||
0x67DC491Fl, 0xB3EE248Fl, 0xD9F71247l, 0xECFB8923l, 0xF67DC491l,
|
||||
0xFB3EE248l, 0x00000001l, 0x00000002l, 0x00000004l, 0x00000008l,
|
||||
0x00000010l, 0x00000020l, 0x00000040l, 0x00000080l, 0x00000100l,
|
||||
0x00000200l, 0x00000400l, 0x00000800l, 0x00001000l, 0x00002000l,
|
||||
0x00004000l, 0x00008000l, 0x00010000l, 0x00020000l, 0x00040000l,
|
||||
0x00080000l, 0x00100000l, 0x00200000l, 0x00400000l, 0x00800000l,
|
||||
0x01000000l, 0x02000000l, 0x04000000l, 0x08000000l, 0x10000000l,
|
||||
0x20000000l, 0x40000000l, 0x80000000l
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs CRC check and corrects single-bit errors against the message.
|
||||
* @param message - bitsetbuffer containing a message of at least 64 bits.
|
||||
* @return - results of CRC check and/or correction attempt
|
||||
*/
|
||||
public static CRC correctNID( BitSetBuffer message )
|
||||
{
|
||||
long calculated = 0; //Starting value
|
||||
|
||||
/* Iterate the set bits and XOR running checksum with lookup value */
|
||||
for (int i = message.nextSetBit( NID_MESSAGE_START );
|
||||
i >= NID_MESSAGE_START && i < NID_CRC_START;
|
||||
i = message.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= NID_DUID_CHECKSUMS[ i - NID_MESSAGE_START ];
|
||||
}
|
||||
|
||||
long checksum = getLongChecksum( message, NID_CRC_START, NID_CRC_END );
|
||||
|
||||
if( calculated == checksum )
|
||||
{
|
||||
return CRC.PASSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errorLocation = getBitError( calculated ^ checksum,
|
||||
NID_DUID_CHECKSUMS );
|
||||
|
||||
if( errorLocation >= 0 )
|
||||
{
|
||||
message.flip( errorLocation + NID_MESSAGE_START );
|
||||
|
||||
return CRC.CORRECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return CRC.FAILED_CRC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs error detection and single-bit error correction against the
|
||||
* data blocks of a PDU1 message.
|
||||
*/
|
||||
public static CRC correctPDU1( BitSetBuffer message )
|
||||
{
|
||||
return correctPDU( message, PDU1_CHECKSUMS, 224 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs error detection and single-bit error correction against the
|
||||
* data blocks of a PDU2 message.
|
||||
*/
|
||||
public static CRC correctPDU2( BitSetBuffer message )
|
||||
{
|
||||
return correctPDU( message, PDU2_CHECKSUMS, 320 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs error detection and single-bit error correction against the
|
||||
* data blocks of a PDU3 message.
|
||||
*/
|
||||
public static CRC correctPDU3( BitSetBuffer message )
|
||||
{
|
||||
return correctPDU( message, PDU3_CHECKSUMS, 416 );
|
||||
}
|
||||
|
||||
public static CRC correctPDU( BitSetBuffer message, long[] checksums, int crcStart )
|
||||
{
|
||||
long calculated = 0; //Starting value
|
||||
|
||||
int messageStart = 160;
|
||||
|
||||
/* Iterate the set bits and XOR running checksum with lookup value */
|
||||
for (int i = message.nextSetBit( messageStart );
|
||||
i >= messageStart && i < crcStart;
|
||||
i = message.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= checksums[ i - messageStart ];
|
||||
}
|
||||
|
||||
long checksum = getLongChecksum( message, crcStart, 32 );
|
||||
|
||||
long error = calculated ^ checksum;
|
||||
|
||||
if( error == 0 || error == 0xFFFFFFFFl )
|
||||
{
|
||||
return CRC.PASSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errorLocation = getBitError( error, checksums );
|
||||
|
||||
if( errorLocation >= 0 )
|
||||
{
|
||||
message.flip( errorLocation + messageStart );
|
||||
|
||||
return CRC.CORRECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return CRC.FAILED_CRC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error detection and correction of single-bit errors for CCITT 16-bit
|
||||
* CRC protected 80-bit messages.
|
||||
*/
|
||||
public static CRC correctCCITT80( BitSetBuffer message,
|
||||
int messageStart,
|
||||
int crcStart )
|
||||
{
|
||||
int calculated = 0; //Starting value
|
||||
|
||||
/* Iterate the set bits and XOR running checksum with lookup value */
|
||||
for (int i = message.nextSetBit( messageStart );
|
||||
i >= messageStart && i < crcStart;
|
||||
i = message.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= CCITT_80_CHECKSUMS[ i - messageStart ];
|
||||
}
|
||||
|
||||
int checksum = getIntChecksum( message, crcStart, 16 );
|
||||
|
||||
int residual = calculated ^ checksum;
|
||||
|
||||
if( residual == 0 || residual == 0xFFFF )
|
||||
{
|
||||
return CRC.PASSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errorLocation = getBitError( residual, CCITT_80_CHECKSUMS );
|
||||
|
||||
if( errorLocation >= 0 )
|
||||
{
|
||||
message.flip( errorLocation + messageStart );
|
||||
|
||||
return CRC.CORRECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return CRC.FAILED_CRC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs Galois 24/12/7 error detection and correction against the 12
|
||||
* encoded 24-bit message segments following the 64-bit NID in the message
|
||||
*
|
||||
* @return - true if all 12 segments of the message can be checked/corrected
|
||||
*/
|
||||
public static boolean correctGalois24( BitSetBuffer tdulc )
|
||||
{
|
||||
boolean passes = true;
|
||||
|
||||
int x = 64;
|
||||
|
||||
while( x < tdulc.size() && passes )
|
||||
{
|
||||
passes = Galois24.checkAndCorrect( tdulc, x );
|
||||
|
||||
x += 24;
|
||||
}
|
||||
|
||||
return passes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the value of the message checksum as a long
|
||||
*/
|
||||
public static long getLongChecksum( BitSetBuffer message,
|
||||
int crcStart, int crcLength )
|
||||
{
|
||||
return message.getLong( crcStart, crcStart + crcLength - 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the value of the message checksum as an integer
|
||||
*/
|
||||
public static int getIntChecksum( BitSetBuffer message,
|
||||
int crcStart, int crcLength )
|
||||
{
|
||||
return message.getInt( crcStart, crcStart + crcLength - 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies any single bit error position that matches the checksum error.
|
||||
*/
|
||||
public static int getBitError( long checksumError, long[] checksums )
|
||||
{
|
||||
for( int x = 0; x < checksums.length; x++ )
|
||||
{
|
||||
if( checksums[ x ] == checksumError )
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies any single bit error position that matches the checksum error.
|
||||
*/
|
||||
public static int getBitError( int checksumError, int[] checksums )
|
||||
{
|
||||
for( int x = 0; x < checksums.length; x++ )
|
||||
{
|
||||
if( checksums[ x ] == checksumError )
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void main( String[] args )
|
||||
{
|
||||
String raw = "0010011000001100101001010111110100010101011010011111110010101100001101111111110100000000000000000001001001101001100000010011101000000000000000001000110101001000000000010010011100111111111000110011110000111000011100000000000000001001111001000101101100001010";
|
||||
|
||||
BitSetBuffer message = BitSetBuffer.load( raw );
|
||||
|
||||
mLog.debug( "MSG:" + message.toString() );
|
||||
|
||||
CRC results = correctPDU1( message );
|
||||
|
||||
mLog.debug( "COR:" + message.toString() );
|
||||
|
||||
mLog.debug( "Results: " + results.getDisplayText() );
|
||||
}
|
||||
}
|
||||
215
src/edac/CRCPassport.java
Normal file
215
src/edac/CRCPassport.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import bits.BitSetBuffer;
|
||||
|
||||
/**
|
||||
* Passport CRC checksum utility
|
||||
*
|
||||
* Passport message blocks are 68 bits in length as follows:
|
||||
* 0 - 8: Sync
|
||||
* 9 - 59: message bits
|
||||
* 60 - 67: CRC-7 check bits plus 1 parity
|
||||
*
|
||||
* Passport uses a CRC-7 (0x44) with an initial fill of 0x44 plus parity set.
|
||||
*
|
||||
* CRC-7 Generating Polynomial: x6 + x2 + 1 (0x44)
|
||||
*/
|
||||
public class CRCPassport
|
||||
{
|
||||
private static final byte sFILL_00 = (byte)0x00;
|
||||
|
||||
private static byte[] sCHECKSUMS = new byte[]
|
||||
{
|
||||
(byte)0x6E, //DCC 1
|
||||
(byte)0xBF, //DCC 0
|
||||
(byte)0xD6, //LCN 10
|
||||
(byte)0xE3, //LCN 9
|
||||
(byte)0xF8, //LCN 8
|
||||
(byte)0x7C, //LCN 7
|
||||
(byte)0x3E, //LCN 6
|
||||
(byte)0x97, //LCN 5
|
||||
(byte)0xC2, //LCN 4
|
||||
(byte)0xE9, //LCN 3
|
||||
(byte)0x75, //LCN 2
|
||||
(byte)0x3B, //LCN 1
|
||||
(byte)0x94, //LCN 0
|
||||
(byte)0x4A, //SITE 6
|
||||
(byte)0xAD, //SITE 5
|
||||
(byte)0x57, //SITE 4
|
||||
(byte)0xA2, //SITE 3
|
||||
(byte)0xD9, //SITE 2
|
||||
(byte)0x6D, //SITE 1
|
||||
(byte)0x37, //SITE 0
|
||||
(byte)0x92, //GROUP 15
|
||||
(byte)0xC1, //GROUP 14
|
||||
(byte)0x61, //GROUP 13
|
||||
(byte)0x31, //GROUP 12
|
||||
(byte)0x19, //GROUP 11
|
||||
(byte)0x0D, //GROUP 10
|
||||
(byte)0x07, //GROUP 9
|
||||
(byte)0x8A, //GROUP 8
|
||||
(byte)0xCD, //GROUP 7
|
||||
(byte)0x67, //GROUP 6
|
||||
(byte)0xBA, //GROUP 5
|
||||
(byte)0xD5, //GROUP 4
|
||||
(byte)0x6B, //GROUP 3
|
||||
(byte)0xBC, //GROUP 2
|
||||
(byte)0x5E, //GROUP 1
|
||||
(byte)0xA7, //GROUP 0
|
||||
(byte)0xDA, //TYPE 3
|
||||
(byte)0xE5, //TYPE 2
|
||||
(byte)0x73, //TYPE 1
|
||||
(byte)0xB0, //TYPE 0
|
||||
(byte)0x58, //FREE 10
|
||||
(byte)0x2C, //FREE 9
|
||||
(byte)0x16, //FREE 8
|
||||
(byte)0x83, //FREE 7
|
||||
(byte)0xC8, //FREE 6
|
||||
(byte)0x64, //FREE 5
|
||||
(byte)0x32, //FREE 4
|
||||
(byte)0x91, //FREE 3
|
||||
(byte)0x49, //FREE 2
|
||||
(byte)0x25, //FREE 1
|
||||
(byte)0x13 //FREE 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if message bits 9 - 59 pass the CRC checksum
|
||||
* contained in bits 60 - 68, using a lookup table of CRC checksum values
|
||||
* derived from the CRC-7 value and the final parity bit
|
||||
*/
|
||||
public static CRC check( BitSet msg )
|
||||
{
|
||||
CRC crc = CRC.UNKNOWN;
|
||||
|
||||
byte calculated = 0x0; //Starting value for an OSW
|
||||
|
||||
//Iterate bits that are set and XOR running checksum with lookup value
|
||||
for (int i = msg.nextSetBit( 9 ); i >= 9 && i <= 59; i = msg.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= sCHECKSUMS[ i - 9 ];
|
||||
}
|
||||
|
||||
//Apply the message checksum to derive the residual
|
||||
calculated ^= getChecksum( msg );
|
||||
|
||||
switch( (byte)calculated )
|
||||
{
|
||||
case sFILL_00:
|
||||
crc = CRC.PASSED;
|
||||
break;
|
||||
default:
|
||||
crc = CRC.FAILED_CRC;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
public static byte getResidual( BitSet msg )
|
||||
{
|
||||
byte calculated = 0x0; //Initial fill of zero
|
||||
|
||||
//Iterate bits that are set and XOR running checksum with lookup value
|
||||
for (int i = msg.nextSetBit( 9 ); i >= 9 && i <= 59; i = msg.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= sCHECKSUMS[ i - 9 ];
|
||||
}
|
||||
|
||||
calculated ^= getChecksum( msg );
|
||||
|
||||
return calculated;
|
||||
}
|
||||
|
||||
public static byte[] getChecks()
|
||||
{
|
||||
return sCHECKSUMS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer value of the 7 bit crc checksum
|
||||
*/
|
||||
public static byte getChecksum( BitSet msg )
|
||||
{
|
||||
byte retVal = 0x0;
|
||||
|
||||
for( int x = 0; x < 8; x++ )
|
||||
{
|
||||
if( msg.get( x + 60 ) )
|
||||
{
|
||||
retVal ^= (byte)( 1<<( 7 - x ) );
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial take on error correction. The majority of the errors detected
|
||||
* are in the final 2 bits, owing to the forward looking soft bit detection
|
||||
* used in the decoder. For right now, correct any messages where the
|
||||
* residual indicates that the final 1 or 2 bits are bad.
|
||||
*/
|
||||
public static BitSetBuffer correct( BitSetBuffer msg )
|
||||
{
|
||||
int residual = (int)( 0xFF & getResidual( msg ) );
|
||||
|
||||
switch( residual )
|
||||
{
|
||||
case 1:
|
||||
case 136:
|
||||
msg.flip( 67 );
|
||||
break;
|
||||
case 3:
|
||||
case 138:
|
||||
msg.flip( 66 );
|
||||
msg.flip( 67 );
|
||||
break;
|
||||
case 2:
|
||||
case 139:
|
||||
msg.flip( 66 );
|
||||
break;
|
||||
case 140:
|
||||
msg.flip( 65 );
|
||||
msg.flip( 67 );
|
||||
break;
|
||||
case 153:
|
||||
msg.flip( 67 );
|
||||
break;
|
||||
case 142:
|
||||
msg.flip( 65 );
|
||||
msg.flip( 66 );
|
||||
msg.flip( 67 );
|
||||
break;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an even parity check on the bitset. If the number of bits that
|
||||
* are set is an even number, then it passes the even parity check
|
||||
*/
|
||||
public static boolean isEvenParity( BitSetBuffer bits )
|
||||
{
|
||||
return ( bits.cardinality() % 2 == 0 );
|
||||
}
|
||||
}
|
||||
233
src/edac/CRCUtil.java
Normal file
233
src/edac/CRCUtil.java
Normal file
@@ -0,0 +1,233 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import bits.BitSetBuffer;
|
||||
|
||||
public class CRCUtil
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( CRCUtil.class );
|
||||
|
||||
public static long[] generate( int messageSize,
|
||||
int crcSize,
|
||||
long polynomial,
|
||||
long initialFill,
|
||||
boolean includeCRCBitErrors )
|
||||
{
|
||||
long[] crcTable = new long[ messageSize +
|
||||
( includeCRCBitErrors ? crcSize : 0 ) ];
|
||||
|
||||
int[] checksumIndexes = new int[ crcSize ];
|
||||
|
||||
for( int x = 0; x < crcSize; x++ )
|
||||
{
|
||||
checksumIndexes[ x ] = messageSize + x;
|
||||
}
|
||||
|
||||
for( int x = 0; x < messageSize; x++ )
|
||||
{
|
||||
BitSetBuffer message = new BitSetBuffer( messageSize + crcSize );
|
||||
|
||||
message.load( messageSize, crcSize, initialFill );
|
||||
|
||||
message.set( x );
|
||||
|
||||
message = decode( message, 0, messageSize, polynomial, crcSize );
|
||||
|
||||
long checksum = message.getLong( checksumIndexes );
|
||||
|
||||
crcTable[ x ] = checksum;
|
||||
}
|
||||
|
||||
if( includeCRCBitErrors )
|
||||
{
|
||||
for( int x = 0; x < crcSize; x++ )
|
||||
{
|
||||
crcTable[ messageSize + x ] = Long.rotateLeft( 1, x );
|
||||
}
|
||||
}
|
||||
|
||||
return crcTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the checksum table and treats the final bit of each check value
|
||||
* as a parity bit that complies with the request parity argument.
|
||||
*/
|
||||
public static long[] generate( int messageSize,
|
||||
int crcSize,
|
||||
long polynomial,
|
||||
long initialFill,
|
||||
boolean includeCRCBitErrors,
|
||||
Parity parity )
|
||||
{
|
||||
long[] table = generate( messageSize, crcSize, polynomial, initialFill,
|
||||
includeCRCBitErrors );
|
||||
|
||||
if( parity == Parity.NONE )
|
||||
{
|
||||
return table;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int x = 0; x < table.length; x++ )
|
||||
{
|
||||
table[ x ] <<= 1;
|
||||
|
||||
if( parity( table[ x ] ) != parity )
|
||||
{
|
||||
table[ x ] ^= 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Parity{ EVEN, ODD, NONE };
|
||||
|
||||
/* Determines the parity (number of 1 bits) for the value */
|
||||
public static Parity parity( long value )
|
||||
{
|
||||
return Long.bitCount( value ) % 2 == 0 ? Parity.EVEN : Parity.ODD;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs binary division of the polynomial into the message for bits
|
||||
* in index 0 to index messageLength - 1, leaving the results in the
|
||||
* checksum filed following the message.
|
||||
*
|
||||
* IN: MMMMMMMMMMMMMMMMCCCCCCCCCCC
|
||||
* OUT: 0000000000000000RRRRRRRRRRR
|
||||
*
|
||||
* M: Message
|
||||
* C: Checksum
|
||||
* R: Remainder
|
||||
*
|
||||
* @param message - message and crc
|
||||
* @param polynomial - crc polynomial - must be 1 bit longer than the crc width
|
||||
* @param messageSize - message length and start of the checksum
|
||||
*
|
||||
* @return message with all message bits zeroed out, and the remainder
|
||||
* placed in the crc field which starts at index messageLength
|
||||
*/
|
||||
public static BitSetBuffer decode( BitSetBuffer message,
|
||||
int messageStart,
|
||||
int messageSize,
|
||||
long polynomial,
|
||||
int crcSize )
|
||||
{
|
||||
for (int i = message.nextSetBit( messageStart );
|
||||
i >= messageStart && i < messageSize;
|
||||
i = message.nextSetBit( i+1 ) )
|
||||
{
|
||||
BitSetBuffer polySet = new BitSetBuffer( crcSize + i + 1 );
|
||||
|
||||
polySet.load( i, crcSize + 1, polynomial );
|
||||
|
||||
message.xor( polySet );
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public static void main( String[] args )
|
||||
{
|
||||
mLog.debug( "Starting" );
|
||||
|
||||
long polynomial = 0xC75l;
|
||||
|
||||
long[] table = generate( 12, 11, polynomial, 0x0, true, Parity.NONE );
|
||||
mLog.debug( toCodeArray( table ) );
|
||||
mLog.debug( "Finished" );
|
||||
}
|
||||
|
||||
public static String toCodeArray( long[] values )
|
||||
{
|
||||
boolean integerArray = true;
|
||||
|
||||
/* Determine the correct primitive type: int or long */
|
||||
for( long value: values )
|
||||
{
|
||||
if( value > Integer.MAX_VALUE || value < Integer.MIN_VALUE )
|
||||
{
|
||||
integerArray = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if( integerArray )
|
||||
{
|
||||
sb.append( "\npublic static final int[] CHECKSUMS = new int[]\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "\npublic static final long[] CHECKSUMS = new long[]\n" );
|
||||
}
|
||||
sb.append( "{\n" );
|
||||
|
||||
StringBuilder row = new StringBuilder();
|
||||
row.append( " " );
|
||||
|
||||
for( long value: values )
|
||||
{
|
||||
StringBuilder element = new StringBuilder();
|
||||
|
||||
element.append( "0x" );
|
||||
element.append( Long.toHexString( value ).toUpperCase() );
|
||||
|
||||
if( !integerArray )
|
||||
{
|
||||
element.append( "l" );
|
||||
}
|
||||
|
||||
element.append( ", " );
|
||||
|
||||
if( row.length() + element.length() <= 80 )
|
||||
{
|
||||
row.append( element.toString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( row.toString() );
|
||||
sb.append( "\n" );
|
||||
row = new StringBuilder();
|
||||
row.append( " " );
|
||||
|
||||
row.append( element.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
if( row.length() > 4 )
|
||||
{
|
||||
sb.append( row.toString() );
|
||||
sb.append( "\n" );
|
||||
}
|
||||
|
||||
sb.append( "};\n" );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
52
src/edac/Checksum.java
Normal file
52
src/edac/Checksum.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* Calculates a 7-bit checksum using an array of xor values from the
|
||||
* ChecksumType class
|
||||
*/
|
||||
public class Checksum
|
||||
{
|
||||
public static boolean validate7BitChecksum( BitSet message,
|
||||
byte messageChecksum,
|
||||
ChecksumType checksumType )
|
||||
{
|
||||
return ( messageChecksum & get7BitChecksum( message, checksumType ) ) == 0;
|
||||
}
|
||||
|
||||
public static byte get7BitChecksum( BitSet message,
|
||||
ChecksumType checksumType )
|
||||
{
|
||||
byte checksum = 0x00;
|
||||
|
||||
short[] checkValues = checksumType.getValues();
|
||||
|
||||
for( int x = 0; x < checkValues.length; x++ )
|
||||
{
|
||||
if( message.get( x ) )
|
||||
{
|
||||
checksum ^= checkValues[ x ];
|
||||
}
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
}
|
||||
96
src/edac/ChecksumTest.java
Normal file
96
src/edac/ChecksumTest.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class ChecksumTest
|
||||
{
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static void main( String[] args )
|
||||
{
|
||||
log( "START!" );
|
||||
|
||||
String msg = "111000001000010010001110";
|
||||
log( msg + " check:" + String.format( "%02X", Checksum.get7BitChecksum( load( msg ), ChecksumType.LTR ) ) );
|
||||
|
||||
log( "DONE!" );
|
||||
}
|
||||
|
||||
public static void log( String message )
|
||||
{
|
||||
System.out.println( message );
|
||||
}
|
||||
|
||||
public static String getString( BitSet bitset, int length )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for( int x = 0; x < length; x++ )
|
||||
{
|
||||
if( bitset.get( x ) )
|
||||
{
|
||||
sb.append( "1" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "0" );
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getStringReverse( BitSet bitset, int length )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for( int x = length - 1; x > -1; x-- )
|
||||
{
|
||||
if( bitset.get( x ) )
|
||||
{
|
||||
sb.append( "1" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "0" );
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public static BitSet load( String message )
|
||||
{
|
||||
BitSet retVal = new BitSet();
|
||||
|
||||
for( int x = 0; x < message.length(); x++ )
|
||||
{
|
||||
if( message.substring( x, x + 1 ).contentEquals( "1" ) )
|
||||
{
|
||||
retVal.set( x );
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
223
src/edac/ChecksumType.java
Normal file
223
src/edac/ChecksumType.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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 edac;
|
||||
|
||||
public enum ChecksumType
|
||||
{
|
||||
FLEETSYNC_ANI( new short[]
|
||||
{
|
||||
0x0000, //Unknown Always One
|
||||
0x0000, //Status Msg Flag
|
||||
0x14C3, //Status Message 6 001010011000011
|
||||
0x6908, //Status Message 5 110100100001000
|
||||
0x3484, //Status Message 4 011010010000100
|
||||
0x1A42, //Status Message 3 001101001000010
|
||||
0x0D21, //Status Message 2 000110100100001
|
||||
0x729A, //Status Message 1 111001010011010
|
||||
0x394D, //Status Message 0 011100101001101
|
||||
0x0000, //Type 7
|
||||
0x0000, //Type 6
|
||||
0x0000, //Type 5
|
||||
0x0000, //Type 4
|
||||
0x0000, //Type 3
|
||||
0x0000, //Type 2
|
||||
0x0000, //Type 1
|
||||
0x0000, //Type 0
|
||||
0x0000, //Fleet From 7
|
||||
0x0000, //Fleet From 6
|
||||
0x0000, //Fleet From 5
|
||||
0x0000, //Fleet From 4
|
||||
0x402E, //Fleet From 3 100000000101110
|
||||
0x2017, //Fleet From 2 010000000010111
|
||||
0x6401, //Fleet From 1 110010000000001
|
||||
0x460A, //Fleet From 0 100011000001010
|
||||
0x0000, //Ident From 11
|
||||
0x0000, //Ident From 10
|
||||
0x0000, //Ident From 9
|
||||
0x0000, //Ident From 8
|
||||
0x0CB1, //Ident From 7 000110010110001
|
||||
0x7252, //Ident From 6 111001001010010
|
||||
0x3929, //Ident From 5 011100100101001
|
||||
0x689E, //Ident From 4 110100010011110
|
||||
0x344F, //Ident From 3 011010001001111
|
||||
0x6E2D, //Ident From 2 110111000101101
|
||||
0x431C, //Ident From 1 100001100011100
|
||||
0x218E, //Ident From 0 010000110001110
|
||||
0x0000, //Ident To 11
|
||||
0x0000, //Ident To 10
|
||||
0x0000, //Ident To 9
|
||||
0x0000, //Ident To 8
|
||||
0x6685, //Ident To 7 110011010000101
|
||||
0x4748, //Ident To 6 100011101001000
|
||||
0x23A4, //Ident To 5 010001110100100
|
||||
0x11D2, //Ident To 4 001000111010010
|
||||
0x08E9, //Ident To 3 000100011101001
|
||||
0x707E, //Ident To 2 111000001111110
|
||||
0x383F, //Ident To 1 011100000111111
|
||||
0x6815, //Ident To 0 110100000010101
|
||||
}),
|
||||
|
||||
LTR( new short[]
|
||||
{ 0x0038, //Area
|
||||
0x001C, //Channel 4
|
||||
0x000E, //Channel 3
|
||||
0x0046, //Channel 2
|
||||
0x0023, //Channel 1
|
||||
0x0051, //Channel 0
|
||||
0x0068, //Home 4
|
||||
0x0075, //Home 3
|
||||
0x007A, //Home 2
|
||||
0x003D, //Home 1
|
||||
0x001F, //Home 0
|
||||
0x004F, //Group 7
|
||||
0x0026, //Group 6
|
||||
0x0052, //Group 5
|
||||
0x0029, //Group 4
|
||||
0x0015, //Group 3
|
||||
0x000B, //Group 2
|
||||
0x0045, //Group 1
|
||||
0x0062, //Group 0
|
||||
0x0031, //Free 4
|
||||
0x0019, //Free 3
|
||||
0x000D, //Free 2
|
||||
0x0007, //Free 1
|
||||
0x0043 //Free 0
|
||||
} ),
|
||||
|
||||
PASSPORT( new short[]
|
||||
{
|
||||
// 0x6e,
|
||||
// 0xbf,
|
||||
// 0xd6,
|
||||
// 0xe3,
|
||||
// 0xf8,
|
||||
// 0x7c,
|
||||
// 0x3e,
|
||||
// 0x97,
|
||||
// 0xc2,
|
||||
// 0xe9,
|
||||
// 0x75,
|
||||
// 0x3b,
|
||||
// 0x94,
|
||||
// 0x4a,
|
||||
// 0xad,
|
||||
// 0x57,
|
||||
// 0xa2,
|
||||
// 0xd9,
|
||||
// 0x6d,
|
||||
// 0x37,
|
||||
// 0x92,
|
||||
// 0xc1,
|
||||
// 0x61,
|
||||
// 0x31,
|
||||
// 0x19,
|
||||
// 0x0d,
|
||||
// 0x07,
|
||||
// 0x8a,
|
||||
// 0xcd,
|
||||
// 0x67,
|
||||
// 0xba,
|
||||
// 0xd5,
|
||||
// 0x6b, // 0111110
|
||||
// 0xbc, // 1111100
|
||||
// 0x5e, // 1101001
|
||||
// 0xa7, // 1000011
|
||||
// 0xda, // 0010111
|
||||
// 0xe5, // 0101110
|
||||
// 0x73, // 1011100
|
||||
// 0xb0, // 0101001
|
||||
// 0x58, // 1010010
|
||||
// 0x2c, // 0110101 Bit 43
|
||||
// 0x16, // 1101010
|
||||
// 0x83, // 1000101 Bit 45
|
||||
// 0xc8, // 0011011 Bit 46
|
||||
// 0x64, // 0110110
|
||||
// 0x32, // 1101100
|
||||
// 0x91, // 1001001
|
||||
// 0x49,
|
||||
// 0x25,
|
||||
// 0x13,
|
||||
} ),
|
||||
|
||||
MULTINET( new short[]
|
||||
{
|
||||
// 0x96, // 0010110
|
||||
// 0xAC, // 0101100
|
||||
// 0xd8, // 1011000
|
||||
// 0x21, // 0100001
|
||||
// 0x42, // 1000010
|
||||
// 0x95, // 0010101
|
||||
// 0xaa, // 0101010
|
||||
// 0xd4, // 1010100
|
||||
// 0x39, // 0111001
|
||||
// 0x72, // 1110010
|
||||
// 0xf5, // 1110101 Bit 10
|
||||
// 0x7b, // 1111011
|
||||
// 0xe7, // 1100111
|
||||
// 0x5f, // 1011111
|
||||
// 0xaf, // 0101111
|
||||
// 0xde, // 1011110
|
||||
// 0x2d, // 0101101
|
||||
// 0x5a, // 1011010
|
||||
// 0xa5, // 0100101
|
||||
// 0xca, // 1001010
|
||||
// 0x05, // 0000101
|
||||
// 0x0a, // 0001010
|
||||
// 0x14, // 0010100
|
||||
// 0x28, // 0101000
|
||||
// 0x50, // 1010000
|
||||
// 0xb1, // 0110001
|
||||
// 0xe2, // 1100010
|
||||
// 0x55, // 1010101
|
||||
// 0xbb, // 0111011
|
||||
// 0xf6, // 1110110
|
||||
// 0x7d, // 1111101
|
||||
// 0xeb, // 1101011
|
||||
// 0x47, // 1000111
|
||||
// 0x9f, // 0011111 Bit 33
|
||||
// 0xbe, // 0111110
|
||||
// 0xfc, // 1111100
|
||||
// 0x69, // 1101001
|
||||
// 0xc3, // 1000011
|
||||
// 0x17, // 0010111
|
||||
// 0x2e, // 0101110
|
||||
// 0x5c, // 1011100
|
||||
// 0xA9, // 0101001
|
||||
// 0xD2, // 1010010
|
||||
// 0x35, // 0110101 Bit 43
|
||||
// 0x6A, // 1101010
|
||||
// 0xC5, // 1000101 Bit 45
|
||||
// 0x1B, // 0011011 Bit 46
|
||||
// 0x36, // 0110110
|
||||
// 0x6C, // 1101100
|
||||
// 0xC9 // 1001001
|
||||
});
|
||||
|
||||
private short[] mValues;
|
||||
|
||||
ChecksumType( short[] values )
|
||||
{
|
||||
mValues = values;
|
||||
}
|
||||
|
||||
public short[] getValues()
|
||||
{
|
||||
return mValues;
|
||||
}
|
||||
|
||||
}
|
||||
173
src/edac/Galois24.java
Normal file
173
src/edac/Galois24.java
Normal file
@@ -0,0 +1,173 @@
|
||||
package edac;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import bits.BitSetBuffer;
|
||||
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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/>
|
||||
* -----------------------------------------------------------------------
|
||||
* Galois24 decoder based on Hank Wallace's tutorial/algorithm located at:
|
||||
* http://www.aqdi.com/golay.htm
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Galois 24/12/7 decoder
|
||||
*/
|
||||
public class Galois24
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( Galois24.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( BitSetBuffer 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;
|
||||
}
|
||||
|
||||
public static boolean checkAndCorrect( BitSetBuffer message, int startIndex )
|
||||
{
|
||||
boolean parityError = message.cardinality() % 2 != 0;
|
||||
|
||||
int syndrome = getSyndrome( message, startIndex );
|
||||
|
||||
/* No errors */
|
||||
if( syndrome == 0 )
|
||||
{
|
||||
if( parityError )
|
||||
{
|
||||
message.flip( startIndex + 23 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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 false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
message.rotateLeft( startIndex, startIndex + 22 );
|
||||
syndrome = getSyndrome( message, startIndex );
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getSyndrome( BitSetBuffer 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 )
|
||||
{
|
||||
/* NID + TDULC message */
|
||||
String msg = "0010011000001111100100110011000100111010000111010001000000000000000000000000000000000000000000000100101010010111000000000000000000000000000010010111101111111111000000000000000000000000000000000000000000000000000110001011100001111101010110111001001011010010101111010010000010110011101111111100100000010001111100011010010100001101111001111001100000111000";
|
||||
|
||||
BitSetBuffer message = BitSetBuffer.load( msg );
|
||||
|
||||
mLog.debug( "MSG: " + message.toString() );
|
||||
|
||||
int x = 64;
|
||||
|
||||
while( x < msg.length() )
|
||||
{
|
||||
boolean passes = checkAndCorrect( message, x );
|
||||
|
||||
mLog.debug( "X:" + x + " Pass:" + passes );
|
||||
x += 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
543
src/edac/ReedSolomon.java
Normal file
543
src/edac/ReedSolomon.java
Normal file
@@ -0,0 +1,543 @@
|
||||
package edac;
|
||||
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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/>
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
* Based on Ed Fuentetaja's DSD RS decoder, May 2014, at:
|
||||
* https://github.com/szechyjs/dsd/blob/master/ReedSolomon.hpp
|
||||
* --------------------------------------------------------------------
|
||||
* Adapted from Mr. Simon Rockliff's version at: http://www.eccpage.com/rs.c
|
||||
*
|
||||
* Simon Rockliff, University of Adelaide 21/9/89
|
||||
* 26/6/91 Slight modifications to remove a compiler dependent bug which
|
||||
* hadn't previously surfaced. A few extra comments added for clarity.
|
||||
* Appears to all work fine, ready for posting to net!
|
||||
*
|
||||
* Notice
|
||||
* --------
|
||||
* This program may be freely modified and/or given to whoever wants it.
|
||||
* A condition of such distribution is that the author's contribution be
|
||||
* acknowledged by his name being left in the comments heading the program,
|
||||
* however no responsibility is accepted for any financial or other loss which
|
||||
* may result from some unforseen errors or malfunctioning of the program
|
||||
* during use.
|
||||
* Simon Rockliff, 26th June 1991
|
||||
******************************************************************************/
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ReedSolomon
|
||||
{
|
||||
public final static Logger mLog = LoggerFactory.getLogger( ReedSolomon.class );
|
||||
|
||||
/* Golay field size GF( 2 ** MM ) */
|
||||
private static final int MM = 6;
|
||||
|
||||
/* Codeword Length: NN = 2 ** MM - 1 */
|
||||
private static final int NN = 63;
|
||||
|
||||
/* Hamming distance between codewords: NN - KK + 1 = 2 * TT + 1 */
|
||||
private static int KK;
|
||||
|
||||
/* Maximum number of errors that can be corrected */
|
||||
int TT;
|
||||
|
||||
int[] alpha_to;
|
||||
int[] index_of;
|
||||
int[] gg;
|
||||
|
||||
public ReedSolomon( int tt )
|
||||
{
|
||||
TT = tt;
|
||||
KK = NN - 2 * TT;
|
||||
|
||||
alpha_to = new int[ NN + 1 ];
|
||||
index_of = new int[ NN + 1 ];
|
||||
gg = new int[ NN - KK + 1 ];
|
||||
|
||||
/* P25 generator polynomial */
|
||||
int generator_polinomial[] = { 1, 1, 0, 0, 0, 0, 1 };
|
||||
|
||||
generate_gf( generator_polinomial );
|
||||
|
||||
gen_poly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Golay Field.
|
||||
*
|
||||
* Generates a GF( 2**mm ) from the irreducible polynomial
|
||||
* p(X) in pp[0]..pp[mm]
|
||||
*
|
||||
* Lookup tables:
|
||||
* index_of[] = polynomial form
|
||||
* alpha_to[] = contains j=alpha**i;
|
||||
*
|
||||
* Polynomial form -> Index form index_of[j=alpha**i] = i
|
||||
*
|
||||
* alpha_to = 2 is the primitive element of GF( 2**mm )
|
||||
*
|
||||
* @param generator_polinomial
|
||||
*/
|
||||
private void generate_gf( int[] generator_polinomial )
|
||||
{
|
||||
int i;
|
||||
int mask = 1;
|
||||
|
||||
alpha_to[ MM ] = 0;
|
||||
|
||||
for( i = 0; i < MM; i++ )
|
||||
{
|
||||
alpha_to[ i ] = mask;
|
||||
index_of[ alpha_to[ i ] ] = i;
|
||||
|
||||
if( generator_polinomial[ i ] != 0 )
|
||||
{
|
||||
alpha_to[ MM ] ^= mask;
|
||||
}
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
index_of[ alpha_to[ MM ] ] = MM;
|
||||
|
||||
mask >>= 1;
|
||||
|
||||
for ( i = MM + 1; i < NN; i++ )
|
||||
{
|
||||
if( alpha_to[ i - 1 ] >= mask )
|
||||
{
|
||||
alpha_to[ i ] = alpha_to[ MM ] ^ ( ( alpha_to[ i - 1 ] ^ mask ) << 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha_to[ i ] = alpha_to[ i - 1 ] << 1;
|
||||
}
|
||||
|
||||
index_of[ alpha_to[ i ] ] = i;
|
||||
}
|
||||
|
||||
index_of[ 0 ] = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the polynomial for a TT-error correction code.
|
||||
*
|
||||
* Length NN = ( 2 ** MM -1 ) Reed Solomon code from the product of
|
||||
* (X+alpha**i), i=1..2*tt
|
||||
*/
|
||||
private void gen_poly()
|
||||
{
|
||||
int i, j;
|
||||
|
||||
gg[ 0 ] = 2; /* primitive element alpha = 2 for GF(2**mm) */
|
||||
gg[ 1 ] = 1; /* g(x) = (X+alpha) initially */
|
||||
for( i = 2; i <= NN - KK; i++ )
|
||||
{
|
||||
gg[ i ] = 1;
|
||||
|
||||
for( j = i - 1; j > 0; j-- )
|
||||
{
|
||||
if( gg[ j ] != 0 )
|
||||
{
|
||||
gg[ j ] = gg[ j - 1 ] ^ alpha_to[ ( index_of[ gg[ j ] ] + i ) % NN ];
|
||||
}
|
||||
else
|
||||
{
|
||||
gg[ j ] = gg[ j - 1 ];
|
||||
}
|
||||
}
|
||||
|
||||
/* gg[0] can never be zero */
|
||||
gg[ 0 ] = alpha_to[ ( index_of[ gg[ 0 ] ] + i ) % NN ];
|
||||
}
|
||||
|
||||
/* convert gg[] to index form for quicker encoding */
|
||||
for( i = 0; i <= NN - KK; i++ )
|
||||
{
|
||||
gg[ i ] = index_of[ gg[ i ] ];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes
|
||||
* @param input
|
||||
* @param recd
|
||||
* @return
|
||||
*/
|
||||
/* assume we have received bits grouped into mm-bit symbols in recd[i],
|
||||
i=0..(nn-1), and recd[i] is polynomial form.
|
||||
We first compute the 2*tt syndromes by substituting alpha**i into rec(X) and
|
||||
evaluating, storing the syndromes in s[i], i=1..2tt (leave s[0] zero) .
|
||||
Then we use the Berlekamp iteration to find the error location polynomial
|
||||
elp[i]. If the degree of the elp is >tt, we cannot correct all the errors
|
||||
and hence just put out the information symbols uncorrected. If the degree of
|
||||
elp is <=tt, we substitute alpha**i , i=1..n into the elp to get the roots,
|
||||
hence the inverse roots, the error location numbers. If the number of errors
|
||||
located does not equal the degree of the elp, we have more than tt errors
|
||||
and cannot correct them. Otherwise, we then solve for the error value at
|
||||
the error location and correct the error. The procedure is that found in
|
||||
Lin and Costello. For the cases where the number of errors is known to be too
|
||||
large to correct, the information symbols as received are output (the
|
||||
advantage of systematic encoding is that hopefully some of the information
|
||||
symbols will be okay and that if we are in luck, the errors are in the
|
||||
parity part of the transmitted codeword). Of course, these insoluble cases
|
||||
can be returned as error flags to the calling routine if desired. */
|
||||
public boolean decode( final int[] input, int[] recd ) //input, output
|
||||
{
|
||||
int u, q;
|
||||
int[][] elp = new int[ NN - KK + 2 ][ NN - KK ];
|
||||
int[] d = new int[ NN - KK + 2 ];
|
||||
int[] l = new int[ NN - KK + 2 ];
|
||||
int[] u_lu = new int[ NN - KK + 2 ];
|
||||
int[] s = new int[ NN - KK + 1 ];
|
||||
int count = 0;
|
||||
boolean syn_error = false;
|
||||
int[] root = new int[ TT ];
|
||||
int[] loc = new int[ TT ];
|
||||
int[] z = new int[ TT + 1 ];
|
||||
int[] err = new int[ NN ];
|
||||
int[] reg = new int[ TT + 1 ];
|
||||
|
||||
boolean irrecoverable_error = false;
|
||||
|
||||
/* put recd[i] into index form (ie as powers of alpha) */
|
||||
for( int i = 0; i < NN; i++ )
|
||||
{
|
||||
recd[ i ] = index_of[ input[ i ] ];
|
||||
}
|
||||
|
||||
/* first form the syndromes */
|
||||
for( int i = 1; i <= NN - KK; i++ )
|
||||
{
|
||||
s[ i ] = 0;
|
||||
|
||||
for( int j = 0; j < NN; j++ )
|
||||
{
|
||||
if( recd[ j ] != -1 )
|
||||
{
|
||||
/* recd[j] in index form */
|
||||
s[ i ] ^= alpha_to[ ( recd[ j ] + i * j ) % NN ];
|
||||
}
|
||||
}
|
||||
|
||||
/* convert syndrome from polynomial form to index form */
|
||||
if( s[ i ] != 0 )
|
||||
{
|
||||
/* set flag if non-zero syndrome => error */
|
||||
syn_error = true;
|
||||
}
|
||||
|
||||
s[ i ] = index_of[ s[ i ] ];
|
||||
}
|
||||
|
||||
if( syn_error ) /* if errors, try and correct */
|
||||
{
|
||||
/* compute the error location polynomial via the Berlekamp iterative algorithm,
|
||||
following the terminology of Lin and Costello : d[u] is the 'mu'th
|
||||
discrepancy, where u='mu'+1 and 'mu' (the Greek letter!) is the step number
|
||||
ranging from -1 to 2*tt (see L&C), l[u] is the
|
||||
degree of the elp at that step, and u_l[u] is the difference between the
|
||||
step number and the degree of the elp.
|
||||
*/
|
||||
|
||||
/* initialise table entries */
|
||||
d[ 0 ] = 0; /* index form */
|
||||
d[ 1 ] = s[ 1 ]; /* index form */
|
||||
elp[ 0 ][ 0 ] = 0; /* index form */
|
||||
elp[ 1 ][ 0 ] = 1; /* polynomial form */
|
||||
|
||||
for( int i = 1; i < NN - KK; i++ )
|
||||
{
|
||||
elp[ 0 ][ i ] = -1; /* index form */
|
||||
elp[ 1 ][ i ] = 0; /* polynomial form */
|
||||
}
|
||||
|
||||
l[ 0 ] = 0;
|
||||
l[ 1 ] = 0;
|
||||
u_lu[ 0 ] = -1;
|
||||
u_lu[ 1 ] = 0;
|
||||
u = 0;
|
||||
|
||||
do
|
||||
{
|
||||
u++;
|
||||
|
||||
if( d[ u ] == -1 )
|
||||
{
|
||||
l[ u + 1 ] = l[ u ];
|
||||
|
||||
for( int i = 0; i <= l[ u ]; i++ )
|
||||
{
|
||||
elp[ u + 1 ][ i ] = elp[ u ][ i ];
|
||||
elp[ u ][ i ] = index_of[ elp[ u ][ i ] ];
|
||||
}
|
||||
}
|
||||
else
|
||||
/* search for words with greatest u_lu[q] for which d[q]!=0 */
|
||||
{
|
||||
q = u - 1;
|
||||
|
||||
while( ( d[ q ] == -1 ) && ( q > 0 ) )
|
||||
{
|
||||
q--;
|
||||
}
|
||||
|
||||
/* have found first non-zero d[q] */
|
||||
if( q > 0 )
|
||||
{
|
||||
int j = q;
|
||||
|
||||
do
|
||||
{
|
||||
j--;
|
||||
|
||||
if( ( d[ j ] != -1 ) && ( u_lu[ q ] < u_lu[ j ] ) )
|
||||
{
|
||||
q = j;
|
||||
}
|
||||
}
|
||||
while( j > 0 );
|
||||
};
|
||||
|
||||
/* have now found q such that d[u]!=0 and u_lu[q] is maximum */
|
||||
/* store degree of new elp polynomial */
|
||||
if( l[ u ] > l[ q ] + u - q )
|
||||
{
|
||||
l[ u + 1 ] = l[ u ];
|
||||
}
|
||||
else
|
||||
{
|
||||
l[ u + 1 ] = l[ q ] + u - q;
|
||||
}
|
||||
|
||||
/* form new elp(x) */
|
||||
for( int i = 0; i < NN - KK; i++ )
|
||||
{
|
||||
elp[ u + 1 ][ i ] = 0;
|
||||
}
|
||||
|
||||
for( int i = 0; i <= l[q]; i++ )
|
||||
{
|
||||
if( elp[ q ][ i ] != -1 )
|
||||
{
|
||||
elp[ u + 1 ][ i + u - q ] =
|
||||
alpha_to[ ( d[ u ] + NN - d[ q ]
|
||||
+ elp[ q ][ i ]) % NN ];
|
||||
}
|
||||
}
|
||||
for( int i = 0; i <= l[u]; i++ )
|
||||
{
|
||||
elp[ u + 1 ][ i ] ^= elp[ u ][ i ];
|
||||
elp[ u ][ i ] = index_of[ elp[ u ][ i ] ]; /*convert old elp value to index*/
|
||||
}
|
||||
}
|
||||
|
||||
u_lu[ u + 1 ] = u - l[ u + 1 ];
|
||||
|
||||
/* form (u+1)th discrepancy */
|
||||
if( u < NN - KK ) /* no discrepancy computed on last iteration */
|
||||
{
|
||||
if ( s[ u + 1 ] != -1 )
|
||||
{
|
||||
d[ u + 1 ] = alpha_to[ s[ u + 1 ] ];
|
||||
}
|
||||
else
|
||||
{
|
||||
d[ u + 1 ] = 0;
|
||||
}
|
||||
for( int i = 1; i <= l[ u + 1 ]; i++ )
|
||||
{
|
||||
if( ( s[ u + 1 - i ] != -1 ) && ( elp[ u + 1 ][ i] != 0 ) )
|
||||
{
|
||||
d[ u + 1 ] ^= alpha_to[ ( s[ u + 1 - i ]
|
||||
+ index_of[ elp[ u + 1 ][ i ] ] ) % NN ];
|
||||
}
|
||||
}
|
||||
|
||||
d[ u + 1 ] = index_of[ d[ u + 1 ] ]; /* put d[u+1] into index form */
|
||||
}
|
||||
}
|
||||
while( ( u < NN - KK ) && ( l[ u + 1 ] <= TT) );
|
||||
|
||||
u++;
|
||||
|
||||
if( l[ u ] <= TT ) /* can correct error */
|
||||
{
|
||||
/* put elp into index form */
|
||||
for( int i = 0; i <= l[u]; i++ )
|
||||
{
|
||||
elp[ u ][ i ] = index_of[ elp[ u ][ i ] ];
|
||||
}
|
||||
|
||||
/* find roots of the error location polynomial */
|
||||
for( int i = 1; i <= l[u]; i++ )
|
||||
{
|
||||
reg[ i ] = elp[ u ][ i ];
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for( int i = 1; i <= NN; i++ )
|
||||
{
|
||||
q = 1;
|
||||
|
||||
for( int j = 1; j <= l[u]; j++ )
|
||||
{
|
||||
if( reg[ j ] != -1 )
|
||||
{
|
||||
reg[ j ] = ( reg[ j ] + j ) % NN;
|
||||
q ^= alpha_to[ reg[ j ] ];
|
||||
};
|
||||
}
|
||||
|
||||
if( q == 0 ) /* store root and error location number indices */
|
||||
{
|
||||
root[ count ] = i;
|
||||
loc[ count ] = NN - i;
|
||||
count++;
|
||||
};
|
||||
};
|
||||
|
||||
if( count == l[ u ] ) /* no. roots = degree of elp hence <= tt errors */
|
||||
{
|
||||
/* form polynomial z(x) */
|
||||
for( int i = 1; i <= l[ u ]; i++ ) /* Z[0] = 1 always - do not need */
|
||||
{
|
||||
if( ( s[ i ] != -1 ) && ( elp[ u ][ i ] != -1 ) )
|
||||
{
|
||||
z[ i ] = alpha_to[ s[ i ] ] ^ alpha_to[ elp[ u ][ i ] ];
|
||||
}
|
||||
else if( ( s[ i ] != -1 ) && ( elp[ u ][ i ] == -1 ) )
|
||||
{
|
||||
z[ i ] = alpha_to[ s[ i ] ];
|
||||
}
|
||||
else if( ( s[ i ] == -1 ) && ( elp[ u ][ i ] != -1 ) )
|
||||
{
|
||||
z[ i ] = alpha_to[ elp[ u ][ i ] ];
|
||||
}
|
||||
else
|
||||
{
|
||||
z[ i ] = 0;
|
||||
}
|
||||
|
||||
for( int j = 1; j < i; j++ )
|
||||
{
|
||||
if( ( s[ j ] != -1 ) && ( elp[ u ][ i - j ] != -1 ) )
|
||||
{
|
||||
z[ i ] ^= alpha_to[ ( elp[ u ][ i - j ] + s[ j ] ) % NN ];
|
||||
}
|
||||
}
|
||||
|
||||
z[ i ] = index_of[ z[ i ] ]; /* put into index form */
|
||||
};
|
||||
|
||||
/* evaluate errors at locations given by error location numbers loc[i] */
|
||||
for( int i = 0; i < NN; i++ )
|
||||
{
|
||||
err[ i ] = 0;
|
||||
|
||||
if( recd[ i ] != -1 ) /* convert recd[] to polynomial form */
|
||||
{
|
||||
recd[ i ] = alpha_to[ recd[ i ] ];
|
||||
}
|
||||
else
|
||||
{
|
||||
recd[ i ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < l[ u ]; i++ ) /* compute numerator of error term first */
|
||||
{
|
||||
err[ loc[ i ] ] = 1; /* accounts for z[0] */
|
||||
|
||||
for( int j = 1; j <= l[ u ]; j++ )
|
||||
{
|
||||
if( z[ j ] != -1 )
|
||||
{
|
||||
err[ loc[ i ] ] ^= alpha_to[ ( z[ j ] + j * root[ i ] ) % NN ];
|
||||
}
|
||||
}
|
||||
|
||||
if( err[ loc[ i ] ] != 0 )
|
||||
{
|
||||
err[ loc[ i ] ] = index_of[ err[ loc[ i ] ] ];
|
||||
|
||||
q = 0; /* form denominator of error term */
|
||||
|
||||
for (int j = 0; j < l[u]; j++)
|
||||
{
|
||||
if (j != i)
|
||||
{
|
||||
q += index_of[1 ^ alpha_to[(loc[j] + root[i]) % NN]];
|
||||
}
|
||||
}
|
||||
|
||||
q = q % NN;
|
||||
err[loc[i]] = alpha_to[(err[loc[i]] - q + NN) % NN];
|
||||
recd[loc[i]] ^= err[loc[i]]; /*recd[i] must be in polynomial form */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no. roots != degree of elp => >tt errors and cannot solve */
|
||||
irrecoverable_error = true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* elp has degree >tt hence cannot solve */
|
||||
irrecoverable_error = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no non-zero syndromes => no errors: output received codeword */
|
||||
for (int i = 0; i < NN; i++)
|
||||
{
|
||||
if (recd[i] != -1) /* convert recd[] to polynomial form */
|
||||
{
|
||||
recd[i] = alpha_to[recd[i]];
|
||||
}
|
||||
else
|
||||
{
|
||||
recd[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( irrecoverable_error )
|
||||
{
|
||||
for (int i = 0; i < NN; i++) /* could return error flag if desired */
|
||||
{
|
||||
if (recd[i] != -1) /* convert recd[] to polynomial form */
|
||||
{
|
||||
recd[i] = alpha_to[recd[i]];
|
||||
}
|
||||
else
|
||||
{
|
||||
recd[i] = 0; /* just output received codeword as is */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return irrecoverable_error;
|
||||
}
|
||||
}
|
||||
31
src/edac/ReedSolomon_24_12_13.java
Normal file
31
src/edac/ReedSolomon_24_12_13.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package edac;
|
||||
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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/>
|
||||
******************************************************************************/
|
||||
|
||||
public class ReedSolomon_24_12_13 extends ReedSolomon
|
||||
{
|
||||
/**
|
||||
* Reed-Solomon RS(24,12,13) decoder
|
||||
*/
|
||||
public ReedSolomon_24_12_13()
|
||||
{
|
||||
/* TT = 6 = maximum correctable bit errors */
|
||||
super( 6 );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user