From 51d6b328bd80cb27b8cbde211017052ce67fa848 Mon Sep 17 00:00:00 2001 From: "dennis.sheirer" Date: Sun, 18 Jan 2015 12:43:10 +0000 Subject: [PATCH] P25 - adds CRC-9 error detection to confirmed PDU message blocks --- src/decode/p25/Trellis_3_4_Rate.java | 17 ++++-- .../p25/message/pdu/PDUConfirmedMessage.java | 26 +++++++- src/decode/p25/reference/Encryption.java | 13 +++- src/dsp/fsk/P25MessageFramer.java | 2 +- src/edac/CRCP25.java | 61 ++++++++++++++++++- src/edac/CRCUtil.java | 15 +++-- 6 files changed, 119 insertions(+), 15 deletions(-) diff --git a/src/decode/p25/Trellis_3_4_Rate.java b/src/decode/p25/Trellis_3_4_Rate.java index 097b3745..3a0baf3b 100644 --- a/src/decode/p25/Trellis_3_4_Rate.java +++ b/src/decode/p25/Trellis_3_4_Rate.java @@ -114,13 +114,14 @@ public class Trellis_3_4_Rate add( c ); } - /* The final decoded survivor path should be at index 0 */ - Path path = mSurvivorPaths.get( 0 ); + /* The final decoded survivor path should be at path metrics tribit 0 */ + Path path = mPathMetrics.getPath( Tribit.T0 ); /* We should have a path with 50 nodes, counting the starting 000 node * and the flushing 000 node, otherwise there was an error */ if( path != null && path.getNodes().size() == 50 ) { + mLog.debug( path.toString() ); /* Clear the original message bits */ message.clear( start, end ); @@ -237,6 +238,11 @@ public class Trellis_3_4_Rate return 0; } + public Path getPath( Tribit tribit ) + { + return mMetrics.get( tribit ); + } + /** * Evaluates the path's metric against the current best path metric for * the final state tribit of the path. If the path's metric is higher @@ -424,6 +430,8 @@ public class Trellis_3_4_Rate StringBuilder sb = new StringBuilder(); sb.append( "PATH [" ); + sb.append( mNodes.size() ); + sb.append( "-" ); sb.append( mPathMetric ); sb.append( "] " ); @@ -633,9 +641,8 @@ public class Trellis_3_4_Rate */ public static void main( String[] args ) { - String raw = "0010001000010110011110101111110101110101110111010110011100000111011001011101111011110111011001000110001000100010001011011110001000100010101101110010001000101101010010100000101000001010000010101010"; -// String raw = "0010001100010110011110100111110101110101110111110110011100000111011001011101111011110111011001000110001000100010101011011110001000100010101101110010001000101101010010100000101000001010000010101010"; -// x x x x + String raw = "0010001001110110000100100000101000001010000010100000101000001010000010100000101000001010000010100000101000001010000010100000101000001010000010100000001101000100011101011011000001110110000001101111"; + BitSetBuffer message = BitSetBuffer.load( raw ); mLog.debug( "MSG: " + message.toString() ); diff --git a/src/decode/p25/message/pdu/PDUConfirmedMessage.java b/src/decode/p25/message/pdu/PDUConfirmedMessage.java index 40c629ab..8ef7968e 100644 --- a/src/decode/p25/message/pdu/PDUConfirmedMessage.java +++ b/src/decode/p25/message/pdu/PDUConfirmedMessage.java @@ -6,7 +6,8 @@ import org.slf4j.LoggerFactory; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.reference.DataUnitID; -import decode.p25.reference.Vendor; +import edac.CRC; +import edac.CRCP25; public class PDUConfirmedMessage extends PDUMessage { @@ -17,9 +18,29 @@ public class PDUConfirmedMessage extends PDUMessage AliasList aliasList ) { super( message, duid, aliasList ); + + checkCRC(); mLog.debug( toString() ); } + + private void checkCRC() + { + int blocks = getBlocksToFollowCount(); + + /* The NID and Header have already passed CRC */ + mCRC = new CRC[ 2 + blocks ]; + mCRC[ 0 ] = CRC.PASSED; + mCRC[ 1 ] = CRC.PASSED; + + for( int x = 0; x < getBlocksToFollowCount(); x++ ) + { + /* Data blocks start at 160 and every 144 thereafter */ + mCRC[ x + 2 ] = CRCP25.checkCRC9( mMessage, 160 + ( x * 144 ) ); + } + + //TODO: check the final 4-byte end of block sequence CRC + } /* Override for now */ public boolean isValid() @@ -36,6 +57,9 @@ public class PDUConfirmedMessage extends PDUMessage sb.append( getNAC() ); sb.append( " " ); sb.append( getDUID().getLabel() ); + + sb.append( " CRC " ); + sb.append( getErrorStatus() ); sb.append( " LLID:" ); sb.append( getLogicalLinkID() ); diff --git a/src/decode/p25/reference/Encryption.java b/src/decode/p25/reference/Encryption.java index 6a95ef7a..773f9eb3 100644 --- a/src/decode/p25/reference/Encryption.java +++ b/src/decode/p25/reference/Encryption.java @@ -12,7 +12,10 @@ public enum Encryption DES_OFB( 0x81 ), TRIPLE_DES_2_KEY( 0x82 ), TRIPLE_DES_3_KEY( 0x83 ), - AES( 0x84 ), + AES_256( 0x84 ), + DES_XL( 0x9F ), /* Motorola Proprietary */ + DVI_XL( 0xA0 ), /* Motorola Proprietary */ + DVP_XL( 0xA1 ), /* Motorola Proprietary */ ADP( 0xAA ), UNKNOWN( -1 ); @@ -46,7 +49,13 @@ public enum Encryption case 0x83: return TRIPLE_DES_3_KEY; case 0x84: - return AES; + return AES_256; + case 0x9F: + return DES_OFB; + case 0xA0: + return DVI_XL; + case 0xA1: + return DVP_XL; default: return UNKNOWN; } diff --git a/src/dsp/fsk/P25MessageFramer.java b/src/dsp/fsk/P25MessageFramer.java index 8d19ce97..1673137f 100644 --- a/src/dsp/fsk/P25MessageFramer.java +++ b/src/dsp/fsk/P25MessageFramer.java @@ -408,8 +408,8 @@ public class P25MessageFramer implements Listener if( current < blocks ) { - mMessageLength += 196; mMessage.setSize( mMessage.size() + 196 ); + mMessageLength = mMessage.size(); } else { diff --git a/src/edac/CRCP25.java b/src/edac/CRCP25.java index 72e07981..1c3dbfb0 100644 --- a/src/edac/CRCP25.java +++ b/src/edac/CRCP25.java @@ -51,6 +51,29 @@ public class CRCP25 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 }; + /** + * Confirmed Packet Data Unit CRC-9 checksums, generated by: + * + * long[] table = generate( 135, 9, 0x259l, 0x1FF, false, Parity.NONE ); + */ + public static final int[] CRC9_CHECKSUMS = new int[] + { + 0x1E7, 0x1F3, 0x1F9, 0x1FC, 0x0D2, 0x045, 0x122, 0x0BD, 0x15E, 0x083, + 0x141, 0x1A0, 0x0FC, 0x052, 0x005, 0x102, 0x0AD, 0x156, 0x087, 0x143, + 0x1A1, 0x1D0, 0x0C4, 0x04E, 0x00B, 0x105, 0x182, 0x0ED, 0x176, 0x097, + 0x14B, 0x1A5, 0x1D2, 0x0C5, 0x162, 0x09D, 0x14E, 0x08B, 0x145, 0x1A2, + 0x0FD, 0x17E, 0x093, 0x149, 0x1A4, 0x0FE, 0x053, 0x129, 0x194, 0x0E6, + 0x05F, 0x12F, 0x197, 0x1CB, 0x1E5, 0x1F2, 0x0D5, 0x16A, 0x099, 0x14C, + 0x08A, 0x069, 0x134, 0x0B6, 0x077, 0x13B, 0x19D, 0x1CE, 0x0CB, 0x165, + 0x1B2, 0x0F5, 0x17A, 0x091, 0x148, 0x088, 0x068, 0x018, 0x020, 0x03C, + 0x302, 0x035, 0x11A, 0x0A1, 0x150, 0x084, 0x06E, 0x01B, 0x10D, 0x186, + 0x0EF, 0x177, 0x1BB, 0x1DD, 0x1EE, 0x0DB, 0x16D, 0x1B6, 0x0F7, 0x17B, + 0x1BD, 0x1DE, 0x0C3, 0x161, 0x1B0, 0x0F4, 0x056, 0x007, 0x103, 0x181, + 0x1C0, 0x0CC, 0x04A, 0x009, 0x104, 0x0AE, 0x07B, 0x13D, 0x19E, 0x0E3, + 0x171, 0x1B8, 0x0F0, 0x054, 0x006, 0x02F, 0x117, 0x18B, 0x1C5, 0x1E2, + 0x0DD, 0x16E, 0x09B, 0x14D, 0x1A6 + }; + /** * CRC-32 checksums for PDU1 ( HEADER + 1 Block ) messages, generated by: * @@ -299,6 +322,40 @@ public class CRCP25 return CRC.FAILED_CRC; } + + /** + * Error detection for CRC-9 protected Confirmed Packet Data blocks. These + * data blocks have a slightly complicated structure because the checksum + * is located between bits 7-15, within a 144 bit block. The checksums + * were generated assuming that the message is contiguous from 0 - 134 bits. + * No data correction is performed. + */ + public static CRC checkCRC9( BitSetBuffer message, int messageStart ) + { + int calculated = 0x1FF; //Initial fill of all ones + + /* Iterate the set bits and XOR running checksum with lookup value */ + for (int i = message.nextSetBit( messageStart ); + i >= messageStart && i < messageStart + 144; + i = message.nextSetBit( i+1 ) ) + { + /* message bits before the CRC */ + if( i < ( messageStart + 7 ) ) + { + calculated ^= CRC9_CHECKSUMS[ i - messageStart ]; + } + /* message bits after the CRC */ + else if( i > ( messageStart + 15 ) ) + { + calculated ^= CRC9_CHECKSUMS[ i - messageStart - 9 ]; + } + } + + int checksum = message.getInt( messageStart + 7, messageStart + 15 ); + + return ( calculated ^ checksum ) == 0 ? CRC.PASSED : CRC.FAILED_CRC; + } + /** * Performs Galois 24/12/7 error detection and correction against the 12 @@ -375,13 +432,13 @@ public class CRCP25 public static void main( String[] args ) { - String raw = "0010011000001100101001010111110100010101011010011111110010101100001101111111110100000000000000000001001001101001100000010011101000000000000000001000110101001000000000010010011100111111111000110011110000111000011100000000000000001001111001000101101100001010"; + String raw = "000000010110100101010001000000000100010100000000000000000010000000011001001011100000000000000000011111110001000101001011100101110000101000110011"; BitSetBuffer message = BitSetBuffer.load( raw ); mLog.debug( "MSG:" + message.toString() ); - CRC results = correctPDU1( message ); + CRC results = checkCRC9( message, 0 ); mLog.debug( "COR:" + message.toString() ); diff --git a/src/edac/CRCUtil.java b/src/edac/CRCUtil.java index 2c47ce52..85bdcf39 100644 --- a/src/edac/CRCUtil.java +++ b/src/edac/CRCUtil.java @@ -153,10 +153,17 @@ public class CRCUtil public static void main( String[] args ) { mLog.debug( "Starting" ); - - long polynomial = 0xC75l; - - long[] table = generate( 12, 11, polynomial, 0x0, true, Parity.NONE ); + +// String raw = "000000001010001000000000100010100000000000000000010000000011001001011100000000000000000011111110001000101001011100101110000101000110011101101001"; +// BitSetBuffer message = BitSetBuffer.load( raw ); +// +// long polynomial = 0x259l; +// +// decode( message, 0, 135, polynomial, 9 ); +// +// mLog.debug( message.toString() ); + + long[] table = generate( 135, 9, 0x259l, 0, false, Parity.NONE ); mLog.debug( toCodeArray( table ) ); mLog.debug( "Finished" ); }