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 ) {