P25 work in progress

This commit is contained in:
dennis.sheirer
2015-01-02 14:08:22 +00:00
parent 95ddadc598
commit 03460eeb19
122 changed files with 5372 additions and 279 deletions

73
src/edac/CRC.java Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}
}

View 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
View 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
View 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
View 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;
}
}

View 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 );
}
}