mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Adds CRC checksum validation to LJ1200 messages (using Eric Cottrell's CRC polynomial)
This commit is contained in:
205
src/crc/CRCLJ.java
Normal file
205
src/crc/CRCLJ.java
Normal file
@@ -0,0 +1,205 @@
|
||||
/*******************************************************************************
|
||||
* 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 crc;
|
||||
|
||||
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 (MSB)
|
||||
0x1375, //Function 1
|
||||
0xBE0B, //Function 2
|
||||
0xE8B4, //Function 3 (LSB)
|
||||
0x745A, //Address 0 (MSB)
|
||||
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
|
||||
|
||||
//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 message bits 16 - 47 pass the LJ CRC checksum
|
||||
* contained in bits 48 - 63, using a lookup table of CRC checksum values
|
||||
* derived from the CRC-16 value
|
||||
*/
|
||||
public static CRC checkAndCorrect( BitSetBuffer msg )
|
||||
{
|
||||
int calculated = 0; //Starting value
|
||||
|
||||
/* Iterate the set bits and XOR running checksum with lookup value */
|
||||
for (int i = msg.nextSetBit( MESSAGE_START );
|
||||
i >= MESSAGE_START && i < CRC_START;
|
||||
i = msg.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= CHECKSUMS[ i - MESSAGE_START ];
|
||||
}
|
||||
|
||||
int checksum = getChecksum( msg );
|
||||
|
||||
if( calculated == getChecksum( msg ) )
|
||||
{
|
||||
return CRC.PASSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] errors = findBitErrors( calculated ^ checksum );
|
||||
|
||||
if( errors != null )
|
||||
{
|
||||
for( int error: errors )
|
||||
{
|
||||
msg.flip( MESSAGE_START + error );
|
||||
}
|
||||
|
||||
return CRC.CORRECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return CRC.FAILED_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 < 16; x++ )
|
||||
{
|
||||
if( msg.get( x + CRC_START ) )
|
||||
{
|
||||
retVal += 1<<( 15 - x );
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit position of any bit checksums that match the checksum
|
||||
* error pattern.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user