P25 work in progress - adds CRC-CCITT error checking to TSBK messages and shows CRC correction state in the messages tab

This commit is contained in:
dennis.sheirer
2014-12-14 22:54:37 +00:00
parent 170688b95e
commit d6306a5e85
9 changed files with 569 additions and 255 deletions

View File

@@ -199,7 +199,8 @@ public class BitSetBuffer extends BitSet
}
else
{
throw new BitSetFullException( "bitset is full -- contains " + ( mPointer + 1 ) + " bits" );
throw new BitSetFullException( "bitset is full -- contains " +
( mPointer + 1 ) + " bits" );
}
}
@@ -268,24 +269,25 @@ public class BitSetBuffer extends BitSet
*/
public int getInt( int[] bits )
{
if( bits.length > 31 )
if( bits.length > 32 )
{
throw new IllegalArgumentException( "BitSetBuffer getInt() "
+ "array length must be less than 32 or the value exceeds "
+ "integer size" );
throw new IllegalArgumentException( "Overflow - must be 32 bits "
+ "or less to fit into a primitive integer value" );
}
int retVal = 0;
for( int x = 0; x < bits.length; x++ )
int value = 0;
for( int index: bits )
{
if( get( bits[ x ] ) )
value = Integer.rotateLeft( value, 1 );
if( get( index ) )
{
retVal += 1<<( bits.length - 1 - x );
value++;
}
}
return retVal;
return value;
}
/**
@@ -297,25 +299,28 @@ public class BitSetBuffer extends BitSet
*/
public long getLong( int[] bits )
{
if( bits.length > 63 )
if( bits.length > 64 )
{
throw new IllegalArgumentException( "BitSetBuffer getLong() "
+ "array length must be less than 64 or the value exceeds "
+ "a primitive long size" );
throw new IllegalArgumentException( "Overflow - must be 64 bits "
+ "or less to fit into a primitive long value" );
}
long retVal = 0;
for( int x = 0; x < bits.length; x++ )
long value = 0;
for( int index: bits )
{
if( get( bits[ x ] ) )
value = Long.rotateLeft( value, 1 );
if( get( index ) )
{
retVal += 1<<( bits.length - 1 - x );
value++;
}
}
return retVal;
return value;
}
/**
* Converts up to 63 bits from the bit array into an integer and then
@@ -328,13 +333,13 @@ public class BitSetBuffer extends BitSet
*/
public String getHex( int[] bits, int digitDisplayCount )
{
if( bits.length <= 31 )
if( bits.length <= 32 )
{
int value = getInt( bits );
return String.format( "%0" + digitDisplayCount + "X", value );
}
else if( bits.length <= 63 )
else if( bits.length <= 64 )
{
long value = getLong( bits );
@@ -351,13 +356,13 @@ public class BitSetBuffer extends BitSet
{
int length = lsb - msb;
if( length <= 31 )
if( length <= 32 )
{
int value = getInt( msb, lsb );
return String.format( "%0" + digitDisplayCount + "X", value );
}
else if( length <= 63 )
else if( length <= 64 )
{
long value = getLong( msb, lsb );
@@ -366,7 +371,7 @@ public class BitSetBuffer extends BitSet
else
{
throw new IllegalArgumentException( "BitSetBuffer.getHex() "
+ "maximum array length is 63 bits" );
+ "maximum array length is 64 bits" );
}
}
@@ -380,22 +385,23 @@ public class BitSetBuffer extends BitSet
{
if( end - start > 32 )
{
throw new IllegalArgumentException( "BitSetBuffer - requested bit "
+ "length [" + ( end - start ) + "] is larger than an "
+ "integer (32 bits)" );
throw new IllegalArgumentException( "Overflow - must be 32 bits "
+ "or less to fit into a primitive integer value" );
}
int retVal = 0;
int value = 0;
for( int x = start; x <= end; x++ )
{
value = Integer.rotateLeft( value, 1 );
if( get( x ) )
{
retVal += 1<<( end - x );
value++;;
}
}
return retVal;
return value;
}
/**
@@ -406,16 +412,116 @@ public class BitSetBuffer extends BitSet
*/
public long getLong( int start, int end )
{
long retVal = 0;
if( end - start > 64 )
{
throw new IllegalArgumentException( "Overflow - must be 64 bits "
+ "or less to fit into a primitive long value" );
}
long value = 0;
for( int x = start; x <= end; x++ )
{
value = Long.rotateLeft( value, 1 );
if( get( x ) )
{
retVal += 1<<( end - x );
value++;
}
}
return retVal;
return value;
}
/**
* Creates a buffer of size=width and fills the buffer with the fill value
* @param width - size of the buffer
* @param fill - initial fill value
* @return - filled buffer
*/
public static BitSetBuffer getBuffer( int width, long fill )
{
BitSetBuffer buffer = new BitSetBuffer( width );
buffer.load( 0, width, fill );
return buffer;
}
/**
* Loads the value into the buffer starting at the offset index, and
* assuming that the value represents (width) number of bits. The MSB of
* the value will be located at the offset and the LSB of the value will
* be located at ( offset + width ).
*
* @param offset - starting bit index for the MSB of the value
* @param width - representative bit width of the value
* @param value - value to be loaded into the buffer
*/
public void load( int offset, int width, long value )
{
for( int x = 0; x < width; x++ )
{
long mask = Long.rotateLeft( 1, width - x - 1 );
if( ( mask & value ) == mask )
{
set( offset + x );
}
}
}
/**
* Generates an array of message bit position indexes to support accessing
* a contiguous field value
*
* @param start - starting bit position of the field
* @param length - field length
* @return - array of field indexes
*/
public static int[] getFieldIndexes( int start, int length, boolean bigEndian )
{
int[] checksumIndexes = new int[ length ];
for( int x = 0; x < length; x++ )
{
if( bigEndian )
{
checksumIndexes[ length - x - 1 ] = start + x;
}
else
{
checksumIndexes[ x ] = start + x;
}
}
return checksumIndexes;
}
/**
* Creates a bitsetbuffer loaded from a string of zeros and ones
*
* @param message - string containing only zeros and ones
* @return - loaded buffer
*/
public static BitSetBuffer load( String message )
{
if( !message.matches( "[01]*" ) )
{
throw new IllegalArgumentException(
"Message must contain only zeros and ones" );
}
BitSetBuffer buffer = new BitSetBuffer( message.length() );
for( int x = 0; x < message.length(); x++ )
{
if( message.substring( x, x + 1 ).contentEquals( "1" ) )
{
buffer.set( x );
}
}
return buffer;
}
}

View File

@@ -47,6 +47,11 @@ public enum CRC
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++ )

225
src/crc/CRCP25.java Normal file
View File

@@ -0,0 +1,225 @@
/*******************************************************************************
* 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 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_LENGTH = 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
*/
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
};
/**
* 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_LENGTH );
if( calculated == checksum )
{
return CRC.PASSED;
}
else
{
int errorLocation = getBitError( calculated ^ checksum,
NID_DUID_CHECKSUMS );
if( errorLocation >= 0 )
{
message.flip( errorLocation );
return CRC.CORRECTED;
}
}
return CRC.FAILED_CRC;
}
/**
*/
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 );
return CRC.CORRECTED;
}
}
return CRC.FAILED_CRC;
}
/**
* Calculates the value of the message checksum as a long
*/
public static long getLongChecksum( BitSetBuffer message,
int crcStart, int crcLength )
{
int[] checksumIndexes = BitSetBuffer
.getFieldIndexes( crcStart, crcLength, false );
return message.getLong( checksumIndexes );
}
/**
* Calculates the value of the message checksum as an integer
*/
public static int getIntChecksum( BitSetBuffer message,
int crcStart, int crcLength )
{
int[] checksumIndexes = BitSetBuffer
.getFieldIndexes( crcStart, crcLength, false );
return message.getInt( checksumIndexes );
}
/**
* 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 = "0010011000000111100010111111001111100001111010011110000100010010000001011001000000000000000000000000000000000000000000000000000000000000000000001101000111000011";
BitSetBuffer message = BitSetBuffer.load( raw );
mLog.debug( "MSG:" + message.toString() );
CRC results = correctCCITT80( message, 64, 144 );
mLog.debug( "Results: " + results.getDisplayText() );
}
}

View File

@@ -1,179 +0,0 @@
/*******************************************************************************
* 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;
/**
* P25 Data Unit ID CRC check utility. Corrects any single bit errors in
* either the message or the crc checksum.
*/
public class CRCP25NetworkID
{
private final static Logger mLog = LoggerFactory.getLogger( CRCP25NetworkID.class );
private static final int MESSAGE_START = 0;
private static final int CRC_START = 16;
private static final int CRC_END = 64;
private static long[] CHECKSUMS = new long[]
{
0xCD930BDD3B2Al, //NAC Bit 11 (MSB)
0xAB5A8E33A6BEl, //NAC Bit 10
0x983E4CC4E874l, //NAC Bit 9
0x4C1F2662743Al, //NAC Bit 8
0xEB9C98EC0136l, //NAC Bit 7
0xB85D47AB3BB0l, //NAC Bit 6
0x5C2EA3D59DD8l, //NAC Bit 5
0x2E1751EACEECl, //NAC Bit 4
0x170BA8F56776l, //NAC Bit 3
0xC616DFA78890l, //NAC Bit 2
0x630B6FD3C448l, //NAC Bit 1
0x3185B7E9E224l, //NAC Bit 0 (LSB)
0x18C2DBF4F112l, //DUID Bit 3 (MSB)
0xC1F2662743A2l, //DUID Bit 2
0xAD6A38CE9AFBl, //DUID Bit 1
0x9B2617BA7657l, //DUID Bit 0 (LSB)
//Single bit errors in the CRC Checksum
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,
};
/**
*
*/
public static CRC checkAndCorrect( BitSetBuffer message )
{
long 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 ];
}
long checksum = getChecksum( message );
if( calculated == checksum )
{
return CRC.PASSED;
}
else
{
int errorLocation = findBitError( calculated ^ checksum );
if( errorLocation >= 0 )
{
message.flip( errorLocation );
return CRC.CORRECTED;
}
}
return CRC.FAILED_CRC;
}
/**
* Returns the long value of the 48 bit crc checksum and parity bit
*/
public static long getChecksum( BitSet msg )
{
long checksum = 0;
for( int x = CRC_START; x < CRC_END; x++ )
{
if( msg.get( x ) )
{
checksum += Long.rotateLeft( 1, CRC_END - 1 - x );
}
}
return checksum;
}
/**
* Identifies any single bit error position that matches the checksum error.
*/
public static int findBitError( long checksumError )
{
/* One bit errors */
for( int x = 0; x < 64; x++ )
{
if( CHECKSUMS[ x ] == checksumError )
{
return x;
}
}
return -1;
}
}

View File

@@ -17,42 +17,182 @@
******************************************************************************/
package crc;
import java.util.BitSet;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import bits.BitSetBuffer;
public class CRCUtil
{
public static BitSet check( BitSet originalMessage,
int messageLength,
BitSet polynomial,
int polynomialLength )
{
//Make a copy of the message, since we're going to modify it
BitSet copy = originalMessage.get( 0, messageLength );
private final static Logger mLog = LoggerFactory.getLogger( CRCUtil.class );
//Iterate through the message bits
for( int x = 0; x < messageLength; x++ )
{
//If we're aligned against a starting 1 in the message, divide it
if( copy.get( 0 ) )
{
copy.xor( polynomial );
}
//Left shift the message
copy = copy.get( 1, messageLength + polynomialLength - x );
}
return copy.get( 0, polynomialLength );
}
public static void log( String message )
{
System.out.println( message );
}
public enum Status
{
PASS, FAIL, BITINVERTED, WORDINVERTED;
}
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, polynomial, crcSize, messageSize );
long checksum = message.getLong( checksumIndexes );
mLog.debug( "Index " + x + " Checksum:" + Long.toHexString( checksum ) );
crcTable[ x ] = checksum;
}
if( includeCRCBitErrors )
{
for( int x = 0; x < crcSize; x++ )
{
crcTable[ messageSize + x ] = Long.rotateLeft( 1, x );
}
}
return crcTable;
}
/**
* 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,
long polynomial,
int crcSize,
int messageSize )
{
int MESSAGE_START = 0;
for (int i = message.nextSetBit( MESSAGE_START );
i >= MESSAGE_START && 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 )
{
long crcCCITT = 0x11021l;
long initialFill = 0xFFFFl;
mLog.debug( "Starting" );
long[] table = generate( 80, 16, crcCCITT, initialFill, true );
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();
}
}

View File

@@ -131,7 +131,6 @@ public class P25ChannelState extends ChannelState
if( alias != null )
{
mSiteAlias = alias.getName();
}
else
{

View File

@@ -7,6 +7,7 @@ import message.Message;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import crc.CRC;
import decode.p25.message.tsbk.osp.control.IdentifierUpdate;
import decode.p25.reference.DataUnitID;
@@ -28,6 +29,8 @@ public class P25Message extends Message
protected DataUnitID mDUID;
protected AliasList mAliasList;
protected CRC[] mCRC;
public P25Message( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
@@ -52,7 +55,12 @@ public class P25Message extends Message
@Override
public String getErrorStatus()
{
return "UNK";
if( mCRC == null )
{
return "UNKNOWN";
}
return CRC.format( mCRC );
}
@Override

View File

@@ -2,6 +2,8 @@ package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import crc.CRC;
import crc.CRCP25;
import decode.p25.message.P25Message;
import decode.p25.message.tsbk.motorola.MotorolaOpcode;
import decode.p25.message.tsbk.vendor.VendorOpcode;
@@ -11,6 +13,7 @@ import decode.p25.reference.Vendor;
public class TSBKMessage extends P25Message
{
public static final int MESSAGE_START = 64;
public static final int LAST_BLOCK_FLAG = 64;
public static final int ENCRYPTED_FLAG = 65;
public static final int[] OPCODE = { 66,67,68,69,70,71 };
@@ -28,13 +31,20 @@ public class TSBKMessage extends P25Message
public static final int[] BLOCK10 = { 136,137,138,139,140,141,142,143 };
public static final int[] BLOCK11 = { 144,145,146,147,148,149,150,151 };
public static final int[] BLOCK12 = { 152,153,154,155,156,157,158,159 };
public static final int[] CRC = { 144,145,146,147,148,149,150,151,152,153,
154,155,156,157,158,159 };
public static final int CRC_START = 144;
public TSBKMessage( BitSetBuffer message, DataUnitID duid, AliasList aliasList )
{
super( message, duid, aliasList );
checkCRC();
}
protected void checkCRC()
{
mCRC = new CRC[ 1 ];
mCRC[ 0 ] = CRCP25.correctCCITT80( mMessage, MESSAGE_START, CRC_START );
}
public boolean isLastBlock()

View File

@@ -13,7 +13,7 @@ import bits.BitSetBuffer;
import bits.BitSetFullException;
import bits.SyncPatternMatcher;
import crc.CRC;
import crc.CRCP25NetworkID;
import crc.CRCP25;
import decode.p25.P25Interleave;
import decode.p25.TrellisHalfRate;
import decode.p25.message.P25Message;
@@ -220,7 +220,7 @@ public class P25MessageFramer implements Listener<Dibit>
switch( mDUID )
{
case NID:
CRC crc = CRCP25NetworkID.checkAndCorrect( mMessage );
CRC crc = CRCP25.correctNID( mMessage );
if( crc != CRC.FAILED_CRC )
{