From 71a15707db79ffa0f48202b0e9251fa2d384723b Mon Sep 17 00:00:00 2001 From: "dennis.sheirer" Date: Fri, 3 Apr 2015 15:36:50 +0000 Subject: [PATCH] P25 Audio Decoder - changed sync pattern matcher to allow up to 2 bit mismatches on audio message frames when in the middle of a call. Encrypted audio is still going to the audio output -- have to add error detection and correction to the ldu link control messages before I can use the encryption flag as a valid sentinel value. --- src/bits/SyncPatternMatcher.java | 40 +++++++++++++++++++-- src/decode/p25/P25Decoder.java | 12 +++---- src/decode/p25/P25MessageFramer.java | 14 +++++++- src/decode/p25/audio/P25AudioOutput.java | 15 +++++++- src/decode/p25/message/ldu/LDU2Message.java | 9 +++-- 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/bits/SyncPatternMatcher.java b/src/bits/SyncPatternMatcher.java index 09b77ecc..675b655b 100644 --- a/src/bits/SyncPatternMatcher.java +++ b/src/bits/SyncPatternMatcher.java @@ -23,7 +23,7 @@ package bits; * * Note: works for sync patterns up to 63 bits (integer size - 1 ) long. * If a 64 bit or larger sync pattern is applied, then the wrapping feature - * of the Integer.rotate methods will wrap the MSB around to the LSB and + * of the Long.rotate methods will wrap the MSB around to the LSB and * corrupt the matching value. * */ @@ -32,6 +32,8 @@ public class SyncPatternMatcher private long mBits = 0; private long mMask = 0; private long mSync = 0; + private boolean mSoftMode = false; + private int mSoftModeErrorThreshold = 0; public SyncPatternMatcher( boolean[] syncPattern ) { @@ -54,6 +56,21 @@ public class SyncPatternMatcher mMask = getMask( sync ); } + /** + * Constructs the sync pattern matcher and defines the soft mode maximum + * number of bit errors to allow in the pattern match. + * + * @param sync pattern + * @param softModeErrorThreshold - maximum bit errors (ie pattern mismatch + * positions) when considering a sync match + */ + public SyncPatternMatcher( long sync, int softModeErrorThreshold ) + { + this( sync ); + + mSoftModeErrorThreshold = softModeErrorThreshold; + } + /** * Generates an all ones mask corresponding to the sync pattern */ @@ -91,6 +108,25 @@ public class SyncPatternMatcher */ public boolean matches() { - return ( mBits == mSync ); + if( mSoftMode ) + { + long difference = mBits ^ mSync; + + return difference == 0 || + Long.bitCount( difference ) <= mSoftModeErrorThreshold; + } + else + { + return ( mBits == mSync ); + } + } + + /** + * Sets the sync pattern matcher in soft mode which allows up to the soft + * mode threshold number of bit errors when considering a sync pattern match + */ + public void setSoftMode( boolean softMode ) + { + mSoftMode = softMode; } } diff --git a/src/decode/p25/P25Decoder.java b/src/decode/p25/P25Decoder.java index 52b55ed7..89ebb57f 100644 --- a/src/decode/p25/P25Decoder.java +++ b/src/decode/p25/P25Decoder.java @@ -88,7 +88,7 @@ public class P25Decoder extends Decoder /* Message framers and handlers */ private P25MessageFramer mNormalFramer; - private P25MessageFramer mInvertedFramer; +// private P25MessageFramer mInvertedFramer; private P25MessageProcessor mMessageProcessor; /* Audio */ @@ -114,9 +114,9 @@ public class P25Decoder extends Decoder FrameSync.P25_PHASE1.getSync(), 64, false, mAliasList ); mNormalFramer.setListener( mMessageProcessor ); - mInvertedFramer = new P25MessageFramer( - FrameSync.P25_PHASE1_INVERTED.getSync(), 64, true, mAliasList ); - mInvertedFramer.setListener( mMessageProcessor ); +// mInvertedFramer = new P25MessageFramer( +// FrameSync.P25_PHASE1_INVERTED.getSync(), 64, true, mAliasList ); +// mInvertedFramer.setListener( mMessageProcessor ); /* Setup demodulation chains based on sample type (real or complex) and * modulation (C4FM or CQPSK) */ @@ -139,7 +139,7 @@ public class P25Decoder extends Decoder mCQPSKDemodulator.setListener( mCQPSKSlicer ); mCQPSKSlicer.addListener( mNormalFramer ); - mCQPSKSlicer.addListener( mInvertedFramer ); +// mCQPSKSlicer.addListener( mInvertedFramer ); } else /* C4FM */ { @@ -172,7 +172,7 @@ public class P25Decoder extends Decoder mSymbolFilter.setListener( mC4FMSlicer ); mC4FMSlicer.addListener( mNormalFramer ); - mC4FMSlicer.addListener( mInvertedFramer ); +// mC4FMSlicer.addListener( mInvertedFramer ); } mAudioOutput = new P25AudioOutput( resourceManager ); diff --git a/src/decode/p25/P25MessageFramer.java b/src/decode/p25/P25MessageFramer.java index b61ca44a..7e4286ae 100644 --- a/src/decode/p25/P25MessageFramer.java +++ b/src/decode/p25/P25MessageFramer.java @@ -34,6 +34,8 @@ import edac.CRCP25; public class P25MessageFramer implements Listener { + private static final int SYNC_PATTERN_MISMATCH_THRESHOLD = 2; + private final static Logger mLog = LoggerFactory.getLogger( P25MessageFramer.class ); @@ -80,7 +82,7 @@ public class P25MessageFramer implements Listener boolean inverted, AliasList aliasList ) { - mMatcher = new SyncPatternMatcher( sync ); + mMatcher = new SyncPatternMatcher( sync, SYNC_PATTERN_MISMATCH_THRESHOLD ); mInverted = inverted; mAliasList = aliasList; @@ -256,10 +258,12 @@ public class P25MessageFramer implements Listener break; case HDU: mComplete = true; + mMatcher.setSoftMode( true ); dispatch( new HDUMessage( mMessage.copy(), mDUID, mAliasList ) ); break; case LDU1: mComplete = true; + mMatcher.setSoftMode( true ); LDU1Message ldu1 = new LDU1Message( mMessage.copy(), mDUID, mAliasList ); @@ -269,9 +273,12 @@ public class P25MessageFramer implements Listener break; case LDU2: mComplete = true; + mMatcher.setSoftMode( true ); dispatch( new LDU2Message( mMessage.copy(), mDUID, mAliasList ) ); break; case PDU0: + mMatcher.setSoftMode( false ); + /* Remove interleaving */ P25Interleave.deinterleaveData( mMessage, PDU0_BEGIN, PDU0_END ); @@ -390,6 +397,8 @@ public class P25MessageFramer implements Listener mComplete = true; break; case PDUC: + mMatcher.setSoftMode( true ); + /* De-interleave the latest block*/ P25Interleave.deinterleaveData( mMessage, mMessage.size() - 196, mMessage.size() ); @@ -438,10 +447,12 @@ public class P25MessageFramer implements Listener } break; case TDU: + mMatcher.setSoftMode( true ); dispatch( new TDUMessage( mMessage.copy(), mDUID, mAliasList ) ); mComplete = true; break; case TDULC: + mMatcher.setSoftMode( true ); TDULinkControlMessage tdulc = new TDULinkControlMessage( mMessage.copy(), mDUID, mAliasList ); @@ -452,6 +463,7 @@ public class P25MessageFramer implements Listener mComplete = true; break; case TSBK1: + mMatcher.setSoftMode( true ); /* Remove interleaving */ P25Interleave.deinterleaveData( mMessage, TSBK_BEGIN, TSBK_END ); diff --git a/src/decode/p25/audio/P25AudioOutput.java b/src/decode/p25/audio/P25AudioOutput.java index 6ff7a950..728e7d50 100644 --- a/src/decode/p25/audio/P25AudioOutput.java +++ b/src/decode/p25/audio/P25AudioOutput.java @@ -7,6 +7,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Control; +import javax.sound.sampled.FloatControl; +import javax.sound.sampled.FloatControl.Type; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; @@ -20,7 +23,6 @@ import audio.AudioType; import audio.IAudioOutput; import audio.IAudioTypeListener; import audio.SquelchListener; -import audio.SquelchListener.SquelchState; import controller.ResourceManager; import controller.ThreadPoolManager; import controller.ThreadPoolManager.ThreadType; @@ -145,6 +147,17 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener, /* Open the audio line with room for two buffers */ mOutput.open( IMBEAudioFormat.PCM_SIGNED_8KHZ_16BITS, PROCESSED_AUDIO_FRAME_SIZE * 2 ); + + Control[] controls = mOutput.getControls(); + + FloatControl gain = (FloatControl)mOutput + .getControl( FloatControl.Type.MASTER_GAIN ); + + if( gain != null ) + { +// gain.setValue( 4.0f ); + } + mCanProcessAudio = true; } else diff --git a/src/decode/p25/message/ldu/LDU2Message.java b/src/decode/p25/message/ldu/LDU2Message.java index e0175f66..90842044 100644 --- a/src/decode/p25/message/ldu/LDU2Message.java +++ b/src/decode/p25/message/ldu/LDU2Message.java @@ -44,19 +44,24 @@ public class LDU2Message extends LDUMessage { StringBuilder sb = new StringBuilder(); - sb.append( super.getMessageStub() ); Encryption encryption = getEncryption(); if( encryption != Encryption.UNENCRYPTED ) { - sb.append( "ENCRYPTION:" ); + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " " ); + sb.append( getDUID().getLabel() ); + + sb.append( " ENCRYPTED VOICE:" ); sb.append( encryption.name() ); sb.append( " KEY ID:" + getKeyID() ); sb.append( " MSG INDICATOR:" + getMessageIndicator() ); } else { + sb.append( super.getMessageStub() ); sb.append( "UNENCRYPTED" ); }