diff --git a/src/bits/BitSetBuffer.java b/src/bits/BitSetBuffer.java
index ed587f5f..3c8ef021 100644
--- a/src/bits/BitSetBuffer.java
+++ b/src/bits/BitSetBuffer.java
@@ -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;
+ }
}
diff --git a/src/crc/CRC.java b/src/crc/CRC.java
index b11e9083..a1f95764 100644
--- a/src/crc/CRC.java
+++ b/src/crc/CRC.java
@@ -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++ )
diff --git a/src/crc/CRCP25.java b/src/crc/CRCP25.java
new file mode 100644
index 00000000..901a1602
--- /dev/null
+++ b/src/crc/CRCP25.java
@@ -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
+ ******************************************************************************/
+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() );
+ }
+}
diff --git a/src/crc/CRCP25NetworkID.java b/src/crc/CRCP25NetworkID.java
deleted file mode 100644
index cf4763f8..00000000
--- a/src/crc/CRCP25NetworkID.java
+++ /dev/null
@@ -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
- ******************************************************************************/
-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;
- }
-}
diff --git a/src/crc/CRCUtil.java b/src/crc/CRCUtil.java
index 0c42a195..3bd2fe83 100644
--- a/src/crc/CRCUtil.java
+++ b/src/crc/CRCUtil.java
@@ -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();
+ }
}
diff --git a/src/decode/p25/P25ChannelState.java b/src/decode/p25/P25ChannelState.java
index 359266be..b3942971 100644
--- a/src/decode/p25/P25ChannelState.java
+++ b/src/decode/p25/P25ChannelState.java
@@ -131,7 +131,6 @@ public class P25ChannelState extends ChannelState
if( alias != null )
{
mSiteAlias = alias.getName();
-
}
else
{
diff --git a/src/decode/p25/message/P25Message.java b/src/decode/p25/message/P25Message.java
index 5956edcc..fc6442df 100644
--- a/src/decode/p25/message/P25Message.java
+++ b/src/decode/p25/message/P25Message.java
@@ -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
diff --git a/src/decode/p25/message/tsbk/TSBKMessage.java b/src/decode/p25/message/tsbk/TSBKMessage.java
index 1992c99b..3f326c4a 100644
--- a/src/decode/p25/message/tsbk/TSBKMessage.java
+++ b/src/decode/p25/message/tsbk/TSBKMessage.java
@@ -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()
diff --git a/src/dsp/fsk/P25MessageFramer.java b/src/dsp/fsk/P25MessageFramer.java
index 1622d7e5..cc294bbc 100644
--- a/src/dsp/fsk/P25MessageFramer.java
+++ b/src/dsp/fsk/P25MessageFramer.java
@@ -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
switch( mDUID )
{
case NID:
- CRC crc = CRCP25NetworkID.checkAndCorrect( mMessage );
+ CRC crc = CRCP25.correctNID( mMessage );
if( crc != CRC.FAILED_CRC )
{