diff --git a/src/decode/p25/message/hdu/HDUMessage.java b/src/decode/p25/message/hdu/HDUMessage.java index cd3f5f45..9d3c63ae 100644 --- a/src/decode/p25/message/hdu/HDUMessage.java +++ b/src/decode/p25/message/hdu/HDUMessage.java @@ -1,15 +1,21 @@ package decode.p25.message.hdu; -import alias.Alias; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import alias.AliasList; import bits.BinaryMessage; import decode.p25.message.P25Message; import decode.p25.reference.DataUnitID; import decode.p25.reference.Encryption; import edac.CRC; +import edac.Golay18; +import edac.ReedSolomon_63_47_17; public class HDUMessage extends P25Message { + private final static Logger mLog = LoggerFactory.getLogger( HDUMessage.class ); + public static final int[] MESSAGE_INDICATOR_A = { 64,65,66,67,68,69,82,83, 84,85,86,87,100,101,102,103,104,105,118,119,120,121,122,123,136,137,138, 139,140,141,154,155,156,157,158,159 }; @@ -22,6 +28,50 @@ public class HDUMessage extends P25Message 353,354,355,356,357,370,371 }; public static final int[] TALKGROUP_ID = { 372,373,374,375,388,389,390,391, 392,393,406,407,408,409,410,411 }; + + public static final int[] GOLAY_WORD_STARTS = { 64,82,100,118,136,154,172, + 190,208,226,244,262,280,298,316,334,352,370,388,406,424,442,460,478, + 496,514,532,550,568,586,604,622,640,658,676,694 }; + + public static final int[] LC_HEX_0 = { 64,65,66,67,68,69 }; + public static final int[] LC_HEX_1 = { 82,83,84,85,86,87 }; + public static final int[] LC_HEX_2 = { 100,101,102,103,104,105 }; + public static final int[] LC_HEX_3 = { 118,119,120,121,122,123 }; + public static final int[] LC_HEX_4 = { 136,137,138,139,140,141 }; + public static final int[] LC_HEX_5 = { 154,155,156,157,158,159 }; + public static final int[] LC_HEX_6 = { 172,173,174,175,176,177 }; + public static final int[] LC_HEX_7 = { 190,191,192,193,194,195 }; + public static final int[] LC_HEX_8 = { 208,209,210,211,212,213 }; + public static final int[] LC_HEX_9 = { 226,227,228,229,230,231 }; + public static final int[] LC_HEX_10 = { 244,245,246,247,248,249 }; + public static final int[] LC_HEX_11 = { 262,263,264,265,266,267 }; + public static final int[] LC_HEX_12 = { 280,281,282,283,284,285 }; + public static final int[] LC_HEX_13 = { 298,299,300,301,302,303 }; + public static final int[] LC_HEX_14 = { 316,317,318,319,320,321 }; + public static final int[] LC_HEX_15 = { 334,335,336,337,338,339 }; + public static final int[] LC_HEX_16 = { 352,353,354,355,356,357 }; + public static final int[] LC_HEX_17 = { 370,371,372,373,374,375 }; + public static final int[] LC_HEX_18 = { 388,389,390,391,392,393 }; + public static final int[] LC_HEX_19 = { 406,407,408,409,410,411 }; + public static final int[] RS_HEX_0 = { 424,425,426,427,428,429 }; + public static final int[] RS_HEX_1 = { 442,443,444,445,446,447 }; + public static final int[] RS_HEX_2 = { 460,461,462,463,464,465 }; + public static final int[] RS_HEX_3 = { 478,479,480,481,482,483 }; + public static final int[] RS_HEX_4 = { 496,497,498,499,500,501 }; + public static final int[] RS_HEX_5 = { 514,515,516,517,518,519 }; + public static final int[] RS_HEX_6 = { 532,533,534,535,536,537 }; + public static final int[] RS_HEX_7 = { 550,551,552,553,554,555 }; + public static final int[] RS_HEX_8 = { 568,569,570,571,572,573 }; + public static final int[] RS_HEX_9 = { 586,587,588,589,590,591 }; + public static final int[] RS_HEX_10 = { 604,605,606,607,608,609 }; + public static final int[] RS_HEX_11 = { 622,623,624,625,626,627 }; + public static final int[] RS_HEX_12 = { 640,641,642,643,644,645 }; + public static final int[] RS_HEX_13 = { 658,659,660,661,662,663 }; + public static final int[] RS_HEX_14 = { 676,677,678,679,680,681 }; + public static final int[] RS_HEX_15 = { 694,695,696,697,698,699 }; + + public static final ReedSolomon_63_47_17 mReedSolomonDecoder = + new ReedSolomon_63_47_17(); public HDUMessage( BinaryMessage message, DataUnitID duid, AliasList aliasList ) @@ -30,7 +80,7 @@ public class HDUMessage extends P25Message /* NID CRC is checked in the message framer, thus a constructed message * means it passed the CRC */ - mCRC = new CRC[ 2 ]; + mCRC = new CRC[ 3 ]; mCRC[ 0 ] = CRC.PASSED; checkCRC(); @@ -38,8 +88,103 @@ public class HDUMessage extends P25Message private void checkCRC() { - /* Do Golay(18,6,8) check here */ - /* Do RS(36,20,17) check here */ + /* Golay( 18,6,18 ) error detection and correction */ + for( int index: GOLAY_WORD_STARTS ) + { + Golay18.checkAndCorrect( mMessage, index ); + } + + mCRC[ 1 ] = CRC.PASSED; + + /* Reed-Solomon( 36,20,17 ) error detection and correction + * Check the Reed-Solomon parity bits. The RS decoder expects the link + * control data and reed solomon parity hex codewords in reverse order. + * The RS(24,12,13) code used by P25 removes the left-hand 47 data hex + * words, so we replace them with zeros. */ + int[] input = new int [63]; + int[] output = new int [63]; + + input[ 0 ] = mMessage.getInt( RS_HEX_15 ); + input[ 1 ] = mMessage.getInt( RS_HEX_14 ); + input[ 2 ] = mMessage.getInt( RS_HEX_13 ); + input[ 3 ] = mMessage.getInt( RS_HEX_12 ); + input[ 4 ] = mMessage.getInt( RS_HEX_11 ); + input[ 5 ] = mMessage.getInt( RS_HEX_10 ); + input[ 6 ] = mMessage.getInt( RS_HEX_9 ); + input[ 7 ] = mMessage.getInt( RS_HEX_8 ); + input[ 8 ] = mMessage.getInt( RS_HEX_7 ); + input[ 9 ] = mMessage.getInt( RS_HEX_6 ); + input[ 10 ] = mMessage.getInt( RS_HEX_5 ); + input[ 11 ] = mMessage.getInt( RS_HEX_4 ); + input[ 12 ] = mMessage.getInt( RS_HEX_3 ); + input[ 13 ] = mMessage.getInt( RS_HEX_2 ); + input[ 14 ] = mMessage.getInt( RS_HEX_1 ); + input[ 15 ] = mMessage.getInt( RS_HEX_0 ); + + input[ 16 ] = mMessage.getInt( LC_HEX_19 ); + input[ 17 ] = mMessage.getInt( LC_HEX_18 ); + input[ 18 ] = mMessage.getInt( LC_HEX_17 ); + input[ 19 ] = mMessage.getInt( LC_HEX_16 ); + input[ 20 ] = mMessage.getInt( LC_HEX_15 ); + input[ 21 ] = mMessage.getInt( LC_HEX_14 ); + input[ 22 ] = mMessage.getInt( LC_HEX_13 ); + input[ 23 ] = mMessage.getInt( LC_HEX_12 ); + input[ 24 ] = mMessage.getInt( LC_HEX_11 ); + input[ 25 ] = mMessage.getInt( LC_HEX_10 ); + input[ 26 ] = mMessage.getInt( LC_HEX_9 ); + input[ 27 ] = mMessage.getInt( LC_HEX_8 ); + input[ 28 ] = mMessage.getInt( LC_HEX_7 ); + input[ 29 ] = mMessage.getInt( LC_HEX_6 ); + input[ 30 ] = mMessage.getInt( LC_HEX_5 ); + input[ 31 ] = mMessage.getInt( LC_HEX_4 ); + input[ 32 ] = mMessage.getInt( LC_HEX_3 ); + input[ 33 ] = mMessage.getInt( LC_HEX_2 ); + input[ 34 ] = mMessage.getInt( LC_HEX_1 ); + input[ 35 ] = mMessage.getInt( LC_HEX_0 ); + /* indexes 36 - 62 are defaulted to zero */ + + boolean irrecoverableErrors = mReedSolomonDecoder.decode( input, output ); + + if( irrecoverableErrors ) + { + mCRC[ 2 ] = CRC.FAILED_CRC; + } + else + { + mCRC[ 2 ] = CRC.PASSED; + + /* Only fix the codeword data hex codewords */ + repairHexCodeword( input, output, 16, LC_HEX_19 ); + repairHexCodeword( input, output, 17, LC_HEX_18 ); + repairHexCodeword( input, output, 18, LC_HEX_17 ); + repairHexCodeword( input, output, 19, LC_HEX_16 ); + repairHexCodeword( input, output, 20, LC_HEX_15 ); + repairHexCodeword( input, output, 21, LC_HEX_14 ); + repairHexCodeword( input, output, 22, LC_HEX_13 ); + repairHexCodeword( input, output, 23, LC_HEX_12 ); + repairHexCodeword( input, output, 24, LC_HEX_11 ); + repairHexCodeword( input, output, 25, LC_HEX_10 ); + repairHexCodeword( input, output, 26, LC_HEX_9 ); + repairHexCodeword( input, output, 27, LC_HEX_8 ); + repairHexCodeword( input, output, 28, LC_HEX_7 ); + repairHexCodeword( input, output, 29, LC_HEX_6 ); + repairHexCodeword( input, output, 30, LC_HEX_5 ); + repairHexCodeword( input, output, 31, LC_HEX_4 ); + repairHexCodeword( input, output, 32, LC_HEX_3 ); + repairHexCodeword( input, output, 33, LC_HEX_2 ); + repairHexCodeword( input, output, 34, LC_HEX_1 ); + repairHexCodeword( input, output, 35, LC_HEX_0 ); + } + } + + private void repairHexCodeword( int[] input, int[] output, int index, int[] indexSet ) + { + if( input[ index ] != output[ index ] ) + { + mLog.debug( "Fixing index: " + index ); + mMessage.load( indexSet[ 0 ], 6, output[ index ] ); + mCRC[ 2 ] = CRC.CORRECTED; + } } @Override @@ -114,10 +259,8 @@ public class HDUMessage extends P25Message return getTalkgroupID(); } - /* Temporary override */ public boolean isValid() { - return true; + return mCRC[ 2 ] != null && mCRC[ 2 ] != CRC.FAILED_CRC; } - } diff --git a/src/decode/p25/message/tdu/lc/TDULinkControlMessage.java b/src/decode/p25/message/tdu/lc/TDULinkControlMessage.java index 4012224d..08042085 100644 --- a/src/decode/p25/message/tdu/lc/TDULinkControlMessage.java +++ b/src/decode/p25/message/tdu/lc/TDULinkControlMessage.java @@ -13,7 +13,7 @@ import decode.p25.reference.Vendor; import decode.p25.reference.VendorLinkControlOpcode; import edac.CRC; import edac.Golay24; -import edac.ReedSolomon_24_12_13; +import edac.ReedSolomon_63_47_17; public class TDULinkControlMessage extends P25Message { @@ -49,8 +49,8 @@ public class TDULinkControlMessage extends P25Message public static final int[] OPCODE = { 66,67,68,69,70,71 }; public static final int[] VENDOR = { 72,73,74,75,88,89,90,91 }; - public static final ReedSolomon_24_12_13 mReedSolomonDecoder = - new ReedSolomon_24_12_13(); + public static final ReedSolomon_63_47_17 mReedSolomonDecoder = + new ReedSolomon_63_47_17(); public TDULinkControlMessage( BinaryMessage message, DataUnitID duid, AliasList aliasList ) diff --git a/src/edac/Golay18.java b/src/edac/Golay18.java new file mode 100644 index 00000000..b374de50 --- /dev/null +++ b/src/edac/Golay18.java @@ -0,0 +1,54 @@ +package edac; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import bits.BinaryMessage; + +/******************************************************************************* + * 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 + * ----------------------------------------------------------------------- + * Galois24 decoder based on Hank Wallace's tutorial/algorithm located at: + * http://www.aqdi.com/golay.htm + ******************************************************************************/ + +/** + * Golay 18/6/8 decoder. Uses the Golay24 edac class to perform edac on Golay + * 18 messages by treating the Golay 18 message as a Golay 24 message with the + * left-most 6 bits set to zero. + */ +public class Golay18 +{ + private final static Logger mLog = LoggerFactory.getLogger( Golay18.class ); + + /** + * Performs error detection and correction. + */ + public static void checkAndCorrect( BinaryMessage message, int startIndex ) + { + int value = message.getInt( startIndex, startIndex + 17 ); + + BinaryMessage temp = new BinaryMessage( 24 ); + temp.load( 6, 18, value ); + + BinaryMessage corrected = Golay24.checkAndCorrect( temp, 0 ); + + int correctedValue = corrected.getInt( 6, 23 ); + + message.load( startIndex, 18, correctedValue ); + } +} diff --git a/src/edac/Golay23.java b/src/edac/Golay23.java index b1c47b81..b5173958 100644 --- a/src/edac/Golay23.java +++ b/src/edac/Golay23.java @@ -14,7 +14,7 @@ public class Golay23 }; /** - * Implements Golay(23,11,7) error detection and correction. Returns the + * Implements Golay(23,12,7) error detection and correction. Returns the * number of detected errors. If the error count is less than or equal to * the max correctable errors (3), then the error bits are corrected. * Otherwise the message is left intact and an error count greater than 3 diff --git a/src/edac/ReedSolomon_24_12_13.java b/src/edac/ReedSolomon_63_47_17.java similarity index 91% rename from src/edac/ReedSolomon_24_12_13.java rename to src/edac/ReedSolomon_63_47_17.java index 28af356f..590686ac 100644 --- a/src/edac/ReedSolomon_24_12_13.java +++ b/src/edac/ReedSolomon_63_47_17.java @@ -18,12 +18,12 @@ package edac; * along with this program. If not, see ******************************************************************************/ -public class ReedSolomon_24_12_13 extends BerlekempMassey_63 +public class ReedSolomon_63_47_17 extends BerlekempMassey_63 { /** * Reed-Solomon RS(24,12,13) decoder */ - public ReedSolomon_24_12_13() + public ReedSolomon_63_47_17() { /* TT = 6 = maximum correctable bit errors */ super( 6 );