mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 09:07:27 -05:00
P25 audio decoder integration.
Auto-discovers the jmbe ( https://github.com/DSheirer/jmbe ) library at startup and provides decode P25 Phase 1 audio
This commit is contained in:
@@ -393,7 +393,7 @@ public class CRCP25
|
||||
while( x < tdulc.size() && passes )
|
||||
{
|
||||
|
||||
tdulc = Galois24.checkAndCorrect( tdulc, x );
|
||||
tdulc = Golay24.checkAndCorrect( tdulc, x );
|
||||
|
||||
passes = tdulc.getCRC() == CRC.PASSED;
|
||||
|
||||
|
||||
128
src/edac/Golay23.java
Normal file
128
src/edac/Golay23.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package edac;
|
||||
|
||||
import bits.BinaryMessage;
|
||||
|
||||
public class Golay23
|
||||
{
|
||||
public static final int MAX_CORRECTABLE_ERRORS = 3;
|
||||
|
||||
public static final int[] CHECKSUMS = new int[]
|
||||
{
|
||||
0x63A, 0x31D, 0x7B4, 0x3DA, 0x1ED, 0x6CC, 0x366, 0x1B3,
|
||||
0x6E3, 0x54B, 0x49F, 0x475, 0x400, 0x200, 0x100, 0x080,
|
||||
0x040, 0x020, 0x010, 0x008, 0x004, 0x002, 0x001
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements Golay(23,11,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
|
||||
* is returned.
|
||||
*
|
||||
* @param frame - message frame bitset
|
||||
* @param startIndex - first bit index of the golay protected bit sequence
|
||||
*
|
||||
* @return - number of detected errors
|
||||
*/
|
||||
public static int checkAndCorrect( BinaryMessage frame, int startIndex )
|
||||
{
|
||||
int syndrome = getSyndrome( frame, startIndex );
|
||||
|
||||
/* No errors */
|
||||
if( syndrome == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
BinaryMessage copy = frame.getSubMessage( startIndex, startIndex + 23 );
|
||||
|
||||
int index = -1;
|
||||
int syndromeWeight = MAX_CORRECTABLE_ERRORS;
|
||||
int errors = 0;
|
||||
|
||||
while( index < 23 )
|
||||
{
|
||||
if( index != -1 )
|
||||
{
|
||||
/* restore the previous flipped bit */
|
||||
if( index > 0 )
|
||||
{
|
||||
copy.flip( index - 1 );
|
||||
}
|
||||
|
||||
copy.flip( index );
|
||||
|
||||
syndromeWeight = MAX_CORRECTABLE_ERRORS - 1;
|
||||
}
|
||||
|
||||
syndrome = getSyndrome( copy, 0 );
|
||||
|
||||
if( syndrome > 0 )
|
||||
{
|
||||
for( int i = 0; i < 23; i++ )
|
||||
{
|
||||
errors = Integer.bitCount( syndrome );
|
||||
|
||||
if( errors <= syndromeWeight )
|
||||
{
|
||||
copy.xor( 12, 11, syndrome );
|
||||
|
||||
copy.rotateRight( i, 0, 22 );
|
||||
|
||||
if( index >= 0 )
|
||||
{
|
||||
errors ++;
|
||||
}
|
||||
|
||||
int corrected = copy.getInt( 0, 22 );
|
||||
int original = frame.getInt( startIndex, startIndex + 22 );
|
||||
|
||||
int errorCount = Integer.bitCount( original ^ corrected );
|
||||
|
||||
if( errorCount <= 3 )
|
||||
{
|
||||
frame.load( startIndex, 23, corrected );
|
||||
}
|
||||
|
||||
return errorCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy.rotateLeft( 0, 22 );
|
||||
syndrome = getSyndrome( copy, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return an error count greater than 3 to indicate failed correction attempt */
|
||||
return 4;
|
||||
}
|
||||
|
||||
private static int getSyndrome( BinaryMessage frame, int startIndex )
|
||||
{
|
||||
int calculated = calculateChecksum( frame, startIndex );
|
||||
|
||||
int checksum = frame.getInt( startIndex + 12, startIndex + 22 );
|
||||
|
||||
return ( checksum ^ calculated );
|
||||
}
|
||||
|
||||
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 + 12;
|
||||
i = frame.nextSetBit( i+1 ) )
|
||||
{
|
||||
calculated ^= CHECKSUMS[ i - startIndex ];
|
||||
}
|
||||
|
||||
return calculated;
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,9 @@ import bits.BinaryMessage;
|
||||
/**
|
||||
* Galois 24/12/7 decoder
|
||||
*/
|
||||
public class Galois24
|
||||
public class Golay24
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( Galois24.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger( Golay24.class );
|
||||
|
||||
/**
|
||||
* Galois 24/12 checksums generated by:
|
||||
@@ -60,6 +60,13 @@ public class Galois24
|
||||
return calculated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs error detection and returns a corrected copy of the 24-bit
|
||||
* message that starts at the start index.
|
||||
* @param message - source message containing startIndex + 24 bits length
|
||||
* @param startIndex - start of the 24-bit galois 24 protected bit set
|
||||
* @return - corrected 24-bit galois value
|
||||
*/
|
||||
public static BinaryMessage checkAndCorrect( BinaryMessage message, int startIndex )
|
||||
{
|
||||
boolean parityError = message.cardinality() % 2 != 0;
|
||||
@@ -149,7 +156,7 @@ public class Galois24
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
private static int getSyndrome( BinaryMessage message, int startIndex )
|
||||
{
|
||||
int calculated = calculateChecksum( message, startIndex );
|
||||
@@ -158,19 +165,4 @@ public class Galois24
|
||||
|
||||
return ( checksum ^ calculated );
|
||||
}
|
||||
|
||||
public static void main( String[] args )
|
||||
{
|
||||
String msg = "01001111011100100011011";
|
||||
|
||||
BinaryMessage message = BinaryMessage.load( msg );
|
||||
|
||||
mLog.debug( "MSG: " + message.toString() );
|
||||
|
||||
int x = 0;
|
||||
|
||||
message = checkAndCorrect( message, x );
|
||||
|
||||
mLog.debug( "MSG: " + message.toString() + " Pass:" + ( message.getCRC()== CRC.PASSED ) );
|
||||
}
|
||||
}
|
||||
117
src/edac/Hamming15.java
Normal file
117
src/edac/Hamming15.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package edac;
|
||||
|
||||
import bits.BinaryMessage;
|
||||
|
||||
public class Hamming15
|
||||
{
|
||||
private static int[] CHECKSUMS = new int[] { 0xF,0xE,0xD,0xC,0xB,0XA,0x9,
|
||||
0x7,0x6,0x5,0x3 };
|
||||
|
||||
/**
|
||||
* Performs error detection and correction of any single-bit errors.
|
||||
*
|
||||
* @param frame - binary frame containing a hamming(15,11,4) protected field
|
||||
*
|
||||
* @param startIndex - offset to the first bit of the field
|
||||
*
|
||||
* @return - 0 = no errors
|
||||
* 1 = a single-bit error was corrected
|
||||
* 2 = two or more errors detected - no corrections made
|
||||
*/
|
||||
public static int checkAndCorrect( BinaryMessage frame, int startIndex )
|
||||
{
|
||||
int syndrome = getSyndrome( frame, startIndex );
|
||||
|
||||
switch( syndrome )
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
frame.flip( startIndex + 14 ); //Parity 1
|
||||
return 1;
|
||||
case 2:
|
||||
frame.flip( startIndex + 13 ); //Parity 2
|
||||
return 1;
|
||||
case 3:
|
||||
frame.flip( startIndex + 10 ); //Data 1
|
||||
return 1;
|
||||
case 4:
|
||||
frame.flip( startIndex + 12 ); //Parity 4
|
||||
return 1;
|
||||
case 5:
|
||||
frame.flip( startIndex + 9 ); //Data 2
|
||||
return 1;
|
||||
case 6:
|
||||
frame.flip( startIndex + 8 ); //Data 3
|
||||
return 1;
|
||||
case 7:
|
||||
frame.flip( startIndex + 7 ); //Data 4
|
||||
return 1;
|
||||
case 8:
|
||||
frame.flip( startIndex + 11 ); //Parity 8
|
||||
return 1;
|
||||
case 9:
|
||||
frame.flip( startIndex + 6 ); //Data 5
|
||||
return 1;
|
||||
case 10:
|
||||
frame.flip( startIndex + 5 ); //Data 6
|
||||
return 1;
|
||||
case 11:
|
||||
frame.flip( startIndex + 4 ); //Data 7
|
||||
return 1;
|
||||
case 12:
|
||||
frame.flip( startIndex + 3 ); //Data 8
|
||||
return 1;
|
||||
case 13:
|
||||
frame.flip( startIndex + 2 ); //Data 9
|
||||
return 1;
|
||||
case 14:
|
||||
frame.flip( startIndex + 1 ); //Data 10
|
||||
return 1;
|
||||
case 15:
|
||||
frame.flip( startIndex ); //Data 11
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We'll never get to here */
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the checksum (Parity 8,4,2,1) for data (11 <> 1 ) bits.
|
||||
* @param frame - frame containing hamming(15) 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 + 11;
|
||||
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 + 11, startIndex + 14 );
|
||||
|
||||
return ( checksum ^ calculated );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user