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:
dennis.sheirer
2015-03-29 13:25:36 +00:00
parent 52f2e3bdca
commit 023553c3bf
41 changed files with 1391 additions and 470 deletions

View File

@@ -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
View 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;
}
}

View File

@@ -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
View 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 );
}
}