Files
sdrtrunk/src/main/java/io/github/dsheirer/edac/CRCPassport.java
Denny 9316599dec Updates pull request from Roman Tsypuk to convert the build system from
ant to gradle.  Removes linux and windows application launch scripts and
produces an executable jar with all resources included.
2017-12-17 07:28:06 -05:00

216 lines
5.4 KiB
Java

/*******************************************************************************
* 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 io.github.dsheirer.edac;
import io.github.dsheirer.bits.BinaryMessage;
import java.util.BitSet;
/**
* 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 BinaryMessage correct( BinaryMessage 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( BinaryMessage bits )
{
return ( bits.cardinality() % 2 == 0 );
}
}