P25 - adds error detection and correction to the Link Control message in LDU1 voice messages and to the Encryption Sync message in LDU2 messages.

This commit is contained in:
dennis.sheirer
2015-04-04 09:59:38 +00:00
parent b8f4e682eb
commit fc8f2772ae
10 changed files with 488 additions and 104 deletions

View File

@@ -24,6 +24,6 @@
<classpathentry kind="lib" path="imports/logback-classic-1.1.2.jar"/>
<classpathentry kind="lib" path="imports/logback-core-1.1.2.jar"/>
<classpathentry kind="lib" path="imports/commons-io-2.4.jar"/>
<classpathentry kind="lib" path="/jmbe/library/jmbe-0.1.0.jar"/>
<classpathentry kind="lib" path="/jmbe/library/jmbe-0.1.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -37,14 +37,12 @@ public class P25MessageProcessor implements Listener<Message>
@Override
public void receive( Message message )
{
/* Debug - prints out the imbe message frames */
if( message instanceof LDUMessage )
{
((LDUMessage)message).getIMBEFrames();
}
/**
* Capture frequency band identifier messages and inject them into any
* messages that require band information in order to calculate the
* up-link and down-link frequencies for any numeric channel references
* contained within the message.
*/
if( message.isValid() )
{
/* Insert band identifier update messages into channel-type messages */
@@ -70,7 +68,14 @@ public class P25MessageProcessor implements Listener<Message>
mBandIdentifierMap.put( bandIdentifier.getIdentifier(),
bandIdentifier );
}
}
/**
* Broadcast all valid messages and any LDU voice messages regardless if
* they are valid or not, so that we don't miss any voice frames
*/
if( message.isValid() || message instanceof LDUMessage )
{
mBroadcaster.broadcast( message );
}
}

View File

@@ -33,26 +33,26 @@ public class HDUMessage extends P25Message
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[] CW_HEX_0 = { 64,65,66,67,68,69 };
public static final int[] CW_HEX_1 = { 82,83,84,85,86,87 };
public static final int[] CW_HEX_2 = { 100,101,102,103,104,105 };
public static final int[] CW_HEX_3 = { 118,119,120,121,122,123 };
public static final int[] CW_HEX_4 = { 136,137,138,139,140,141 };
public static final int[] CW_HEX_5 = { 154,155,156,157,158,159 };
public static final int[] CW_HEX_6 = { 172,173,174,175,176,177 };
public static final int[] CW_HEX_7 = { 190,191,192,193,194,195 };
public static final int[] CW_HEX_8 = { 208,209,210,211,212,213 };
public static final int[] CW_HEX_9 = { 226,227,228,229,230,231 };
public static final int[] CW_HEX_10 = { 244,245,246,247,248,249 };
public static final int[] CW_HEX_11 = { 262,263,264,265,266,267 };
public static final int[] CW_HEX_12 = { 280,281,282,283,284,285 };
public static final int[] CW_HEX_13 = { 298,299,300,301,302,303 };
public static final int[] CW_HEX_14 = { 316,317,318,319,320,321 };
public static final int[] CW_HEX_15 = { 334,335,336,337,338,339 };
public static final int[] CW_HEX_16 = { 352,353,354,355,356,357 };
public static final int[] CW_HEX_17 = { 370,371,372,373,374,375 };
public static final int[] CW_HEX_18 = { 388,389,390,391,392,393 };
public static final int[] CW_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 };
@@ -70,8 +70,10 @@ public class HDUMessage extends P25Message
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 };
/* Reed-Solomon(36,20,17) code protects the header word. Maximum
* correctable errors are: Hamming Distance(17) / 2 = 8 */
public static final ReedSolomon_63_47_17 mReedSolomonDecoder =
new ReedSolomon_63_47_17();
new ReedSolomon_63_47_17( 8 );
public HDUMessage( BinaryMessage message, DataUnitID duid,
AliasList aliasList )
@@ -121,26 +123,26 @@ public class HDUMessage extends P25Message
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 );
input[ 16 ] = mMessage.getInt( CW_HEX_19 );
input[ 17 ] = mMessage.getInt( CW_HEX_18 );
input[ 18 ] = mMessage.getInt( CW_HEX_17 );
input[ 19 ] = mMessage.getInt( CW_HEX_16 );
input[ 20 ] = mMessage.getInt( CW_HEX_15 );
input[ 21 ] = mMessage.getInt( CW_HEX_14 );
input[ 22 ] = mMessage.getInt( CW_HEX_13 );
input[ 23 ] = mMessage.getInt( CW_HEX_12 );
input[ 24 ] = mMessage.getInt( CW_HEX_11 );
input[ 25 ] = mMessage.getInt( CW_HEX_10 );
input[ 26 ] = mMessage.getInt( CW_HEX_9 );
input[ 27 ] = mMessage.getInt( CW_HEX_8 );
input[ 28 ] = mMessage.getInt( CW_HEX_7 );
input[ 29 ] = mMessage.getInt( CW_HEX_6 );
input[ 30 ] = mMessage.getInt( CW_HEX_5 );
input[ 31 ] = mMessage.getInt( CW_HEX_4 );
input[ 32 ] = mMessage.getInt( CW_HEX_3 );
input[ 33 ] = mMessage.getInt( CW_HEX_2 );
input[ 34 ] = mMessage.getInt( CW_HEX_1 );
input[ 35 ] = mMessage.getInt( CW_HEX_0 );
/* indexes 36 - 62 are defaulted to zero */
boolean irrecoverableErrors = mReedSolomonDecoder.decode( input, output );
@@ -154,26 +156,26 @@ public class HDUMessage extends P25Message
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 );
repairHexCodeword( input, output, 16, CW_HEX_19 );
repairHexCodeword( input, output, 17, CW_HEX_18 );
repairHexCodeword( input, output, 18, CW_HEX_17 );
repairHexCodeword( input, output, 19, CW_HEX_16 );
repairHexCodeword( input, output, 20, CW_HEX_15 );
repairHexCodeword( input, output, 21, CW_HEX_14 );
repairHexCodeword( input, output, 22, CW_HEX_13 );
repairHexCodeword( input, output, 23, CW_HEX_12 );
repairHexCodeword( input, output, 24, CW_HEX_11 );
repairHexCodeword( input, output, 25, CW_HEX_10 );
repairHexCodeword( input, output, 26, CW_HEX_9 );
repairHexCodeword( input, output, 27, CW_HEX_8 );
repairHexCodeword( input, output, 28, CW_HEX_7 );
repairHexCodeword( input, output, 29, CW_HEX_6 );
repairHexCodeword( input, output, 30, CW_HEX_5 );
repairHexCodeword( input, output, 31, CW_HEX_4 );
repairHexCodeword( input, output, 32, CW_HEX_3 );
repairHexCodeword( input, output, 33, CW_HEX_2 );
repairHexCodeword( input, output, 34, CW_HEX_1 );
repairHexCodeword( input, output, 35, CW_HEX_0 );
}
}
@@ -181,7 +183,6 @@ public class HDUMessage extends P25Message
{
if( input[ index ] != output[ index ] )
{
mLog.debug( "Fixing index: " + index );
mMessage.load( indexSet[ 0 ], 6, output[ index ] );
mCRC[ 2 ] = CRC.CORRECTED;
}

View File

@@ -2,12 +2,13 @@ package decode.p25.message.ldu;
import alias.AliasList;
import bits.BinaryMessage;
import decode.p25.P25Interleave;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.LinkControlOpcode;
import decode.p25.reference.Vendor;
import decode.p25.reference.VendorLinkControlOpcode;
import edac.CRC;
import edac.Hamming10;
import edac.ReedSolomon_63_47_17;
public class LDU1Message extends LDUMessage
{
@@ -25,6 +26,40 @@ public class LDU1Message extends LDUMessage
// public static final int[] OCTET_7 = { 732,733,734,735,740,741,742,743 };
// public static final int[] OCTET_8 = { 744,745,750,751,752,753,754,755 };
public static final int[] GOLAY_WORD_STARTS = {
352,362,372,382,536,546,556,566,720,730,740,750,904,914,924,934,1088,
1098,1108,1118,1272,1282,1292,1302 };
public static final int[] CW_HEX_0 = { 352,353,354,355,356,357 };
public static final int[] CW_HEX_1 = { 362,363,364,365,366,367 };
public static final int[] CW_HEX_2 = { 372,373,374,375,376,377 };
public static final int[] CW_HEX_3 = { 382,383,384,385,386,387 };
public static final int[] CW_HEX_4 = { 536,537,538,539,540,541 };
public static final int[] CW_HEX_5 = { 546,547,548,549,550,551 };
public static final int[] CW_HEX_6 = { 556,557,558,559,560,561 };
public static final int[] CW_HEX_7 = { 566,567,568,569,570,571 };
public static final int[] CW_HEX_8 = { 720,721,722,723,724,725 };
public static final int[] CW_HEX_9 = { 730,731,732,733,734,735 };
public static final int[] CW_HEX_10 = { 740,741,742,743,744,745 };
public static final int[] CW_HEX_11 = { 750,751,752,753,754,755 };
public static final int[] RS_HEX_0 = { 904,905,906,907,908,909 };
public static final int[] RS_HEX_1 = { 914,915,916,917,918,919 };
public static final int[] RS_HEX_2 = { 924,925,926,927,928,929 };
public static final int[] RS_HEX_3 = { 934,935,936,937,938,939 };
public static final int[] RS_HEX_4 = { 1088,1089,1090,1091,1092,1093 };
public static final int[] RS_HEX_5 = { 1098,1099,1100,1101,1102,1103 };
public static final int[] RS_HEX_6 = { 1108,1109,1110,1111,1112,1113 };
public static final int[] RS_HEX_7 = { 1118,1119,1120,1121,1122,1123 };
public static final int[] RS_HEX_8 = { 1272,1273,1274,1275,1276,1277 };
public static final int[] RS_HEX_9 = { 1282,1283,1284,1285,1286,1287 };
public static final int[] RS_HEX_10 = { 1292,1293,1294,1295,1296,1297 };
public static final int[] RS_HEX_11 = { 1302,1303,1304,1305,1306,1307 };
/* Reed-Solomon(24,12,13) code protects the link control word. Maximum
* correctable errors are: Hamming Distance(13) / 2 = 6 */
public static final ReedSolomon_63_47_17 mReedSolomonDecoder =
new ReedSolomon_63_47_17( 6 );
public LDU1Message( BinaryMessage message, DataUnitID duid,
AliasList aliasList )
{
@@ -33,14 +68,12 @@ public class LDU1Message extends LDUMessage
/* 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;
//TODO: edac on link control octets
checkCRC();
}
/**
* Subclass constructor from an existing LDU1Message
*/
@@ -51,9 +84,97 @@ public class LDU1Message extends LDUMessage
mCRC = message.mCRC;
}
private void checkCRC()
{
mCRC[ 1 ] = CRC.PASSED;
/* Hamming( 10,6,3 ) error detection and correction */
for( int index: GOLAY_WORD_STARTS )
{
int errors = Hamming10.checkAndCorrect( mMessage, index );
if( errors > 1 )
{
mCRC[ 1 ] = CRC.FAILED_CRC;
}
}
/* Reed-Solomon( 24,16,9 ) error detection and correction
* Check the Reed-Solomon parity bits. The RS decoder expects the code
* words and reed solomon parity hex codewords in reverse order.
*
* Since this is a truncated RS(63) codes, we pad the code with zeros */
int[] input = new int [63];
int[] output = new int [63];
input[ 0 ] = mMessage.getInt( RS_HEX_11 );
input[ 1 ] = mMessage.getInt( RS_HEX_10 );
input[ 2 ] = mMessage.getInt( RS_HEX_9 );
input[ 3 ] = mMessage.getInt( RS_HEX_8 );
input[ 4 ] = mMessage.getInt( RS_HEX_7 );
input[ 5 ] = mMessage.getInt( RS_HEX_6 );
input[ 6 ] = mMessage.getInt( RS_HEX_5 );
input[ 7 ] = mMessage.getInt( RS_HEX_4 );
input[ 8 ] = mMessage.getInt( RS_HEX_3 );
input[ 9 ] = mMessage.getInt( RS_HEX_2 );
input[ 10 ] = mMessage.getInt( RS_HEX_1 );
input[ 11 ] = mMessage.getInt( RS_HEX_0 );
input[ 12 ] = mMessage.getInt( CW_HEX_11 );
input[ 13 ] = mMessage.getInt( CW_HEX_10 );
input[ 14 ] = mMessage.getInt( CW_HEX_9 );
input[ 15 ] = mMessage.getInt( CW_HEX_8 );
input[ 16 ] = mMessage.getInt( CW_HEX_7 );
input[ 17 ] = mMessage.getInt( CW_HEX_6 );
input[ 18 ] = mMessage.getInt( CW_HEX_5 );
input[ 19 ] = mMessage.getInt( CW_HEX_4 );
input[ 20 ] = mMessage.getInt( CW_HEX_3 );
input[ 21 ] = mMessage.getInt( CW_HEX_2 );
input[ 22 ] = mMessage.getInt( CW_HEX_1 );
input[ 23 ] = mMessage.getInt( CW_HEX_0 );
/* indexes 24 - 62 are defaulted to zero */
boolean irrecoverableErrors = mReedSolomonDecoder.decode( input, output );
if( irrecoverableErrors )
{
mCRC[ 2 ] = CRC.FAILED_CRC;
}
else
{
/* Since we've detected that we can correct the RS words, mark the
* hamming crc as corrected as well, if it is currently failed */
if( mCRC[ 1 ] == CRC.FAILED_CRC )
{
mCRC[ 1 ] = CRC.CORRECTED;
}
mCRC[ 2 ] = CRC.PASSED;
/* Only fix the codeword data hex codewords */
repairHexCodeword( input, output, 12, CW_HEX_11 );
repairHexCodeword( input, output, 13, CW_HEX_10 );
repairHexCodeword( input, output, 14, CW_HEX_9 );
repairHexCodeword( input, output, 15, CW_HEX_8 );
repairHexCodeword( input, output, 16, CW_HEX_7 );
repairHexCodeword( input, output, 17, CW_HEX_6 );
repairHexCodeword( input, output, 18, CW_HEX_5 );
repairHexCodeword( input, output, 19, CW_HEX_4 );
repairHexCodeword( input, output, 20, CW_HEX_3 );
repairHexCodeword( input, output, 21, CW_HEX_2 );
repairHexCodeword( input, output, 22, CW_HEX_1 );
repairHexCodeword( input, output, 23, CW_HEX_0 );
}
}
private void repairHexCodeword( int[] input, int[] output, int index, int[] indexSet )
{
if( input[ index ] != output[ index ] )
{
mMessage.load( indexSet[ 0 ], 6, output[ index ] );
mCRC[ 2 ] = CRC.CORRECTED;
}
}
@Override

View File

@@ -1,22 +1,19 @@
package decode.p25.message.ldu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import alias.AliasList;
import bits.BinaryMessage;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Encryption;
import edac.CRC;
import edac.Hamming10;
import edac.ReedSolomon_63_47_17;
public class LDU2Message extends LDUMessage
{
// public static final int[] OCTET_0 = { 352,353,354,355,356,357,362,363 };
// public static final int[] OCTET_1 = { 364,365,366,367,372,373,374,375 };
// public static final int[] OCTET_2 = { 376,377,382,383,384,385,386,387 };
// public static final int[] OCTET_3 = { 536,537,538,539,540,541,546,547 };
// public static final int[] OCTET_4 = { 548,549,550,551,556,557,558,559 };
// public static final int[] OCTET_5 = { 560,561,566,567,568,569,570,571 };
// public static final int[] OCTET_6 = { 720,721,722,723,724,725,730,731 };
// public static final int[] OCTET_7 = { 732,733,734,735,740,741,742,743 };
// public static final int[] OCTET_8 = { 744,745,750,751,752,753,754,755 };
private final static Logger mLog = LoggerFactory.getLogger( LDU2Message.class );
public static final int[] MESSAGE_INDICATOR_A = { 352,353,354,355,356,357,
362,363,364,365,366,367,372,373,374,375,376,377,382,383,384,385,386,387,
@@ -28,6 +25,40 @@ public class LDU2Message extends LDUMessage
public static final int[] KEY_ID = { 916,917,918,919,924,925,926,927,928,
929,934,935,936,937,938,939 };
public static final int[] GOLAY_WORD_STARTS = {
352,362,372,382,536,546,556,566,720,730,740,750,904,914,924,934,1088,
1098,1108,1118,1272,1282,1292,1302 };
public static final int[] CW_HEX_0 = { 352,353,354,355,356,357 };
public static final int[] CW_HEX_1 = { 362,363,364,365,366,367 };
public static final int[] CW_HEX_2 = { 372,373,374,375,376,377 };
public static final int[] CW_HEX_3 = { 382,383,384,385,386,387 };
public static final int[] CW_HEX_4 = { 536,537,538,539,540,541 };
public static final int[] CW_HEX_5 = { 546,547,548,549,550,551 };
public static final int[] CW_HEX_6 = { 556,557,558,559,560,561 };
public static final int[] CW_HEX_7 = { 566,567,568,569,570,571 };
public static final int[] CW_HEX_8 = { 720,721,722,723,724,725 };
public static final int[] CW_HEX_9 = { 730,731,732,733,734,735 };
public static final int[] CW_HEX_10 = { 740,741,742,743,744,745 };
public static final int[] CW_HEX_11 = { 750,751,752,753,754,755 };
public static final int[] CW_HEX_12 = { 904,905,906,907,908,909 };
public static final int[] CW_HEX_13 = { 914,915,916,917,918,919 };
public static final int[] CW_HEX_14 = { 924,925,926,927,928,929 };
public static final int[] CW_HEX_15 = { 934,935,936,937,938,939 };
public static final int[] RS_HEX_0 = { 1088,1089,1090,1091,1092,1093 };
public static final int[] RS_HEX_1 = { 1098,1099,1100,1101,1102,1103 };
public static final int[] RS_HEX_2 = { 1108,1109,1110,1111,1112,1113 };
public static final int[] RS_HEX_3 = { 1118,1119,1120,1121,1122,1123 };
public static final int[] RS_HEX_4 = { 1272,1273,1274,1275,1276,1277 };
public static final int[] RS_HEX_5 = { 1282,1283,1284,1285,1286,1287 };
public static final int[] RS_HEX_6 = { 1292,1293,1294,1295,1296,1297 };
public static final int[] RS_HEX_7 = { 1302,1303,1304,1305,1306,1307 };
/* Reed-Solomon(24,16,9) code protects the encryption sync word. Maximum
* correctable errors are: Hamming Distance(9) / 2 = 4 */
public static final ReedSolomon_63_47_17 mReedSolomonDecoder =
new ReedSolomon_63_47_17( 4 );
public LDU2Message( BinaryMessage message, DataUnitID duid,
AliasList aliasList )
{
@@ -35,10 +66,108 @@ public class LDU2Message extends LDUMessage
/* 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();
}
private void checkCRC()
{
mCRC[ 1 ] = CRC.PASSED;
/* Hamming( 10,6,3 ) error detection and correction */
for( int index: GOLAY_WORD_STARTS )
{
int errors = Hamming10.checkAndCorrect( mMessage, index );
if( errors > 1 )
{
mCRC[ 1 ] = CRC.FAILED_CRC;
}
}
/* Reed-Solomon( 24,16,9 ) error detection and correction
* Check the Reed-Solomon parity bits. The RS decoder expects the code
* words and reed solomon parity hex codewords in reverse order.
*
* Since this is a truncated RS(63) codes, we pad the code with zeros */
int[] input = new int [63];
int[] output = new int [63];
input[ 0 ] = mMessage.getInt( RS_HEX_7 );
input[ 1 ] = mMessage.getInt( RS_HEX_6 );
input[ 2 ] = mMessage.getInt( RS_HEX_5 );
input[ 3 ] = mMessage.getInt( RS_HEX_4 );
input[ 4 ] = mMessage.getInt( RS_HEX_3 );
input[ 5 ] = mMessage.getInt( RS_HEX_2 );
input[ 6 ] = mMessage.getInt( RS_HEX_1 );
input[ 7 ] = mMessage.getInt( RS_HEX_0 );
input[ 8 ] = mMessage.getInt( CW_HEX_15 );
input[ 9 ] = mMessage.getInt( CW_HEX_14 );
input[ 10 ] = mMessage.getInt( CW_HEX_13 );
input[ 11 ] = mMessage.getInt( CW_HEX_12 );
input[ 12 ] = mMessage.getInt( CW_HEX_11 );
input[ 13 ] = mMessage.getInt( CW_HEX_10 );
input[ 14 ] = mMessage.getInt( CW_HEX_9 );
input[ 15 ] = mMessage.getInt( CW_HEX_8 );
input[ 16 ] = mMessage.getInt( CW_HEX_7 );
input[ 17 ] = mMessage.getInt( CW_HEX_6 );
input[ 18 ] = mMessage.getInt( CW_HEX_5 );
input[ 19 ] = mMessage.getInt( CW_HEX_4 );
input[ 20 ] = mMessage.getInt( CW_HEX_3 );
input[ 21 ] = mMessage.getInt( CW_HEX_2 );
input[ 22 ] = mMessage.getInt( CW_HEX_1 );
input[ 23 ] = mMessage.getInt( CW_HEX_0 );
/* indexes 24 - 62 are defaulted to zero */
boolean irrecoverableErrors = mReedSolomonDecoder.decode( input, output );
if( irrecoverableErrors )
{
mCRC[ 2 ] = CRC.FAILED_CRC;
}
else
{
/* Since we've detected that we can correct the RS words, mark the
* hamming crc as corrected as well, if it is currently failed */
if( mCRC[ 1 ] == CRC.FAILED_CRC )
{
mCRC[ 1 ] = CRC.CORRECTED;
}
mCRC[ 2 ] = CRC.PASSED;
/* Only fix the codeword data hex codewords */
repairHexCodeword( input, output, 8, CW_HEX_15 );
repairHexCodeword( input, output, 9, CW_HEX_14 );
repairHexCodeword( input, output, 10, CW_HEX_13 );
repairHexCodeword( input, output, 11, CW_HEX_12 );
repairHexCodeword( input, output, 12, CW_HEX_11 );
repairHexCodeword( input, output, 13, CW_HEX_10 );
repairHexCodeword( input, output, 14, CW_HEX_9 );
repairHexCodeword( input, output, 15, CW_HEX_8 );
repairHexCodeword( input, output, 16, CW_HEX_7 );
repairHexCodeword( input, output, 17, CW_HEX_6 );
repairHexCodeword( input, output, 18, CW_HEX_5 );
repairHexCodeword( input, output, 19, CW_HEX_4 );
repairHexCodeword( input, output, 20, CW_HEX_3 );
repairHexCodeword( input, output, 21, CW_HEX_2 );
repairHexCodeword( input, output, 22, CW_HEX_1 );
repairHexCodeword( input, output, 23, CW_HEX_0 );
}
}
private void repairHexCodeword( int[] input, int[] output, int index, int[] indexSet )
{
if( input[ index ] != output[ index ] )
{
mMessage.load( indexSet[ 0 ], 6, output[ index ] );
mCRC[ 2 ] = CRC.CORRECTED;
}
}
@Override
public String getMessage()
{
@@ -71,12 +200,6 @@ public class LDU2Message extends LDUMessage
return sb.toString();
}
/* Temporary override */
public boolean isValid()
{
return true;
}
public String getMessageIndicator()
{
StringBuilder sb = new StringBuilder();
@@ -97,6 +220,15 @@ public class LDU2Message extends LDUMessage
return mMessage.getInt( KEY_ID );
}
public static void main( String[] args )
{
String msg = "001010100000101010011010001001001001010011000111000111110111001100000010000101001011110111111000001100111100110000000010001110011011001101101101101101110011110011010000101111001111000011000010110010011110110010000100101101101001100000100000100001011100000000001110011111011000100100000000011011100000111111111101111010110111000111100011010111111110111000000000000000000000000000000000000000000100100001110110101111011000011010010100011001000101001011100101111011000001101100010101111001000100001111011111011001111110100111001100110110000000000000000000000000000000000000000000000101000001011110111010110010000100010110001100001101001110111001000111100100111011011011110101011111011000010100110111001000101000010011101010000000000000000000000000000000000000000001001000001000011011110110011110011001111100100000111000101001110111011110101001000101001100001110001100000000110000110000001011110000000101100110000011100000000000000000000000000000000111011001010000111111111111110000110110011000100101011000001111110000101000101111010101010101000100110111000100100111110010101010000100111010111010111010001011010010001011011001001001011100000101000010010010111100000110010000101010000110101100101111100110111100010001011011110101001011010100010000111000010000001001001001101000100110101011110100111100011111110101100000011011011001000001010100011001010100110000111100101011100110110011111100011011111110100111011101011111100001111011000101100011101000110001101000000000000000000000000000000000010001101101011101111010101010000111011011101001011111001110111001000010101011010000001011010111010000011011001100010110001010001000010001101101";
BinaryMessage message = BinaryMessage.load( msg );
LDU2Message ldu2 = new LDU2Message( message, DataUnitID.LDU2, null );
mLog.debug( ldu2.getMessage() );
mLog.debug( "CRC: " + CRC.format( ldu2.getCRCResults() ));
}
}

View File

@@ -68,9 +68,9 @@ public class LDUMessage extends P25Message
return mMessage.getHex( LOW_SPEED_DATA, 4 );
}
/* Temporary override */
public boolean isValid()
{
// return mCRC[ 2 ] != null && mCRC[ 2 ] != CRC.FAILED_CRC;
return true;
}

View File

@@ -49,8 +49,10 @@ 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 };
/* Reed-Solomon(24,12,13) code protects the link control word. Maximum
* correctable errors are: Hamming Distance(13) / 2 = 6 */
public static final ReedSolomon_63_47_17 mReedSolomonDecoder =
new ReedSolomon_63_47_17();
new ReedSolomon_63_47_17( 6 );
public TDULinkControlMessage( BinaryMessage message, DataUnitID duid,
AliasList aliasList )

View File

@@ -95,9 +95,9 @@ public class BerlekempMassey_63
*
* alpha_to = 2 is the primitive element of GF( 2**mm )
*
* @param generator_polinomial
* @param generator_polynomial
*/
private void generate_gf( int[] generator_polinomial )
private void generate_gf( int[] generator_polynomial )
{
int i;
int mask = 1;
@@ -109,7 +109,7 @@ public class BerlekempMassey_63
alpha_to[ i ] = mask;
index_of[ alpha_to[ i ] ] = i;
if( generator_polinomial[ i ] != 0 )
if( generator_polynomial[ i ] != 0 )
{
alpha_to[ MM ] ^= mask;
}

116
src/edac/Hamming10.java Normal file
View File

@@ -0,0 +1,116 @@
package edac;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import bits.BinaryMessage;
public class Hamming10
{
private final static Logger mLog = LoggerFactory.getLogger( Hamming10.class );
private static int[] CHECKSUMS = new int[] { 0xE,0xD,0xB,0X7,0x3,0xC };
/**
* Performs error detection and correction of any single-bit errors. This
* is a truncated version of the Hamming15 class.
*
* @param frame - binary frame containing a Hamming(10,6,3) protected field
*
* @param startIndex - offset to the first bit of the field
*
* @return - 0 = no errors
* 1 = a single-bit error was corrected
*/
public static int checkAndCorrect( BinaryMessage frame, int startIndex )
{
int syndrome = getSyndrome( frame, startIndex );
switch( syndrome )
{
case 0:
return 0;
case 1:
frame.flip( startIndex + 9 ); //Parity 1
return 1;
case 2:
frame.flip( startIndex + 8 ); //Parity 2
return 1;
case 3:
frame.flip( startIndex + 4 ); //Data 2
return 1;
case 4:
frame.flip( startIndex + 7 ); //Parity 4
return 1;
case 5:
return 2;
case 6:
return 2;
case 7:
frame.flip( startIndex + 3 ); //Data 3
return 1;
case 8:
frame.flip( startIndex + 6 ); //Parity 8
return 1;
case 9:
return 2;
case 10:
return 2;
case 11:
frame.flip( startIndex + 2 ); //Data 4
return 1;
case 12:
frame.flip( startIndex + 5 ); //Data 1
return 1;
case 13:
frame.flip( startIndex + 1 ); //Data 5
return 1;
case 14:
frame.flip( startIndex + 0 ); //Data 6
return 1;
case 15:
return 2;
}
/* We'll never get to here */
return 2;
}
/**
* Calculates the checksum (Parity 8,4,2,1) for data (6 <> 1 ) bits.
* @param frame - frame containing hamming(10) protected word
* @param startIndex - start bit index of the hamming protected word
* @return parity value, 0 - 15
*/
private static int calculateChecksum( BinaryMessage frame, int startIndex )
{
int calculated = 0; //Starting value
/* Iterate the set bits and XOR running checksum with lookup value */
for (int i = frame.nextSetBit( startIndex );
i >= startIndex && i < startIndex + 6;
i = frame.nextSetBit( i+1 ) )
{
calculated ^= CHECKSUMS[ i - startIndex ];
}
return calculated;
}
/**
* Calculates the syndrome - xor of the calculated checksum and the actual
* checksum.
*
* @param frame - binary frame containing a hamming(15,11,4) protected word
* @param startIndex - of bit 0 of the hamming protected word
* @return - 0 (no errors) or 1 (single bit error corrected)
*/
private static int getSyndrome( BinaryMessage frame, int startIndex )
{
int calculated = calculateChecksum( frame, startIndex );
int checksum = frame.getInt( startIndex + 6, startIndex + 9 );
return ( checksum ^ calculated );
}
}

View File

@@ -21,11 +21,18 @@ package edac;
public class ReedSolomon_63_47_17 extends BerlekempMassey_63
{
/**
* Reed-Solomon RS(24,12,13) decoder
* Reed-Solomon RS(63,47,17) decoder. This can also be used for error detection
* and correction of the following RS codes:
*
* RS(36,20,17) - max 8 errors
* RS(24,16,9) - max 4 errors
* RS(24,12,13) - max 6 errors
*
* The maximum correctable errors is determined by (n-k)/2, or hamming
* distance divided by 2.
*/
public ReedSolomon_63_47_17()
public ReedSolomon_63_47_17( int maximumCorrectableErrors )
{
/* TT = 6 = maximum correctable bit errors */
super( 6 );
super( maximumCorrectableErrors );
}
}