mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 17:17:29 -05:00
P25 - added Header Data Unit (HDU) error detection and correction with Golay(18,6,8) and ReedSolomon(36,20,17).
This commit is contained in:
@@ -1,15 +1,21 @@
|
|||||||
package decode.p25.message.hdu;
|
package decode.p25.message.hdu;
|
||||||
|
|
||||||
import alias.Alias;
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
import bits.BinaryMessage;
|
import bits.BinaryMessage;
|
||||||
import decode.p25.message.P25Message;
|
import decode.p25.message.P25Message;
|
||||||
import decode.p25.reference.DataUnitID;
|
import decode.p25.reference.DataUnitID;
|
||||||
import decode.p25.reference.Encryption;
|
import decode.p25.reference.Encryption;
|
||||||
import edac.CRC;
|
import edac.CRC;
|
||||||
|
import edac.Golay18;
|
||||||
|
import edac.ReedSolomon_63_47_17;
|
||||||
|
|
||||||
public class HDUMessage extends P25Message
|
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,
|
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,
|
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 };
|
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 };
|
353,354,355,356,357,370,371 };
|
||||||
public static final int[] TALKGROUP_ID = { 372,373,374,375,388,389,390,391,
|
public static final int[] TALKGROUP_ID = { 372,373,374,375,388,389,390,391,
|
||||||
392,393,406,407,408,409,410,411 };
|
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,
|
public HDUMessage( BinaryMessage message, DataUnitID duid,
|
||||||
AliasList aliasList )
|
AliasList aliasList )
|
||||||
@@ -30,7 +80,7 @@ public class HDUMessage extends P25Message
|
|||||||
|
|
||||||
/* NID CRC is checked in the message framer, thus a constructed message
|
/* NID CRC is checked in the message framer, thus a constructed message
|
||||||
* means it passed the CRC */
|
* means it passed the CRC */
|
||||||
mCRC = new CRC[ 2 ];
|
mCRC = new CRC[ 3 ];
|
||||||
mCRC[ 0 ] = CRC.PASSED;
|
mCRC[ 0 ] = CRC.PASSED;
|
||||||
|
|
||||||
checkCRC();
|
checkCRC();
|
||||||
@@ -38,8 +88,103 @@ public class HDUMessage extends P25Message
|
|||||||
|
|
||||||
private void checkCRC()
|
private void checkCRC()
|
||||||
{
|
{
|
||||||
/* Do Golay(18,6,8) check here */
|
/* Golay( 18,6,18 ) error detection and correction */
|
||||||
/* Do RS(36,20,17) check here */
|
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
|
@Override
|
||||||
@@ -114,10 +259,8 @@ public class HDUMessage extends P25Message
|
|||||||
return getTalkgroupID();
|
return getTalkgroupID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Temporary override */
|
|
||||||
public boolean isValid()
|
public boolean isValid()
|
||||||
{
|
{
|
||||||
return true;
|
return mCRC[ 2 ] != null && mCRC[ 2 ] != CRC.FAILED_CRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import decode.p25.reference.Vendor;
|
|||||||
import decode.p25.reference.VendorLinkControlOpcode;
|
import decode.p25.reference.VendorLinkControlOpcode;
|
||||||
import edac.CRC;
|
import edac.CRC;
|
||||||
import edac.Golay24;
|
import edac.Golay24;
|
||||||
import edac.ReedSolomon_24_12_13;
|
import edac.ReedSolomon_63_47_17;
|
||||||
|
|
||||||
public class TDULinkControlMessage extends P25Message
|
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[] OPCODE = { 66,67,68,69,70,71 };
|
||||||
public static final int[] VENDOR = { 72,73,74,75,88,89,90,91 };
|
public static final int[] VENDOR = { 72,73,74,75,88,89,90,91 };
|
||||||
|
|
||||||
public static final ReedSolomon_24_12_13 mReedSolomonDecoder =
|
public static final ReedSolomon_63_47_17 mReedSolomonDecoder =
|
||||||
new ReedSolomon_24_12_13();
|
new ReedSolomon_63_47_17();
|
||||||
|
|
||||||
public TDULinkControlMessage( BinaryMessage message, DataUnitID duid,
|
public TDULinkControlMessage( BinaryMessage message, DataUnitID duid,
|
||||||
AliasList aliasList )
|
AliasList aliasList )
|
||||||
|
|||||||
54
src/edac/Golay18.java
Normal file
54
src/edac/Golay18.java
Normal file
@@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
* -----------------------------------------------------------------------
|
||||||
|
* 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
* 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.
|
* the max correctable errors (3), then the error bits are corrected.
|
||||||
* Otherwise the message is left intact and an error count greater than 3
|
* Otherwise the message is left intact and an error count greater than 3
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ package edac;
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
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
|
* Reed-Solomon RS(24,12,13) decoder
|
||||||
*/
|
*/
|
||||||
public ReedSolomon_24_12_13()
|
public ReedSolomon_63_47_17()
|
||||||
{
|
{
|
||||||
/* TT = 6 = maximum correctable bit errors */
|
/* TT = 6 = maximum correctable bit errors */
|
||||||
super( 6 );
|
super( 6 );
|
||||||
Reference in New Issue
Block a user