mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-15 10:07:26 -05:00
Updates P25 C4FM and LSM decoders to provide demodulated bit streams
for recording using the new binary recorders/format.
This commit is contained in:
@@ -16,11 +16,12 @@
|
|||||||
package io.github.dsheirer.module.decode.p25;
|
package io.github.dsheirer.module.decode.p25;
|
||||||
|
|
||||||
import io.github.dsheirer.alias.AliasList;
|
import io.github.dsheirer.alias.AliasList;
|
||||||
|
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||||
import io.github.dsheirer.dsp.symbol.DibitToByteBufferAssembler;
|
import io.github.dsheirer.dsp.symbol.DibitToByteBufferAssembler;
|
||||||
import io.github.dsheirer.module.decode.Decoder;
|
import io.github.dsheirer.module.decode.Decoder;
|
||||||
import io.github.dsheirer.module.decode.DecoderType;
|
import io.github.dsheirer.module.decode.DecoderType;
|
||||||
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.buffer.IReusableByteBufferListener;
|
|
||||||
import io.github.dsheirer.sample.buffer.IReusableByteBufferProvider;
|
import io.github.dsheirer.sample.buffer.IReusableByteBufferProvider;
|
||||||
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
|
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
|
||||||
import io.github.dsheirer.sample.buffer.ReusableByteBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableByteBuffer;
|
||||||
@@ -29,11 +30,11 @@ import io.github.dsheirer.source.ISourceEventListener;
|
|||||||
import io.github.dsheirer.source.ISourceEventProvider;
|
import io.github.dsheirer.source.ISourceEventProvider;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
|
|
||||||
public abstract class P25Decoder extends Decoder
|
public abstract class P25Decoder extends Decoder implements ISourceEventListener, ISourceEventProvider,
|
||||||
implements ISourceEventListener, ISourceEventProvider, IReusableComplexBufferListener, Listener<ReusableComplexBuffer>,
|
IReusableComplexBufferListener, Listener<ReusableComplexBuffer>, IReusableByteBufferProvider
|
||||||
IReusableByteBufferProvider, IReusableByteBufferListener
|
|
||||||
{
|
{
|
||||||
private double mSampleRate;
|
private double mSampleRate;
|
||||||
|
private Broadcaster<Dibit> mDibitBroadcaster = new Broadcaster<>();
|
||||||
private DibitToByteBufferAssembler mByteBufferAssembler = new DibitToByteBufferAssembler(300);
|
private DibitToByteBufferAssembler mByteBufferAssembler = new DibitToByteBufferAssembler(300);
|
||||||
private P25MessageProcessor mMessageProcessor;
|
private P25MessageProcessor mMessageProcessor;
|
||||||
private AliasList mAliasList;
|
private AliasList mAliasList;
|
||||||
@@ -46,14 +47,15 @@ public abstract class P25Decoder extends Decoder
|
|||||||
mAliasList = aliasList;
|
mAliasList = aliasList;
|
||||||
mMessageProcessor = new P25MessageProcessor(mAliasList);
|
mMessageProcessor = new P25MessageProcessor(mAliasList);
|
||||||
mMessageProcessor.setMessageListener(getMessageListener());
|
mMessageProcessor.setMessageListener(getMessageListener());
|
||||||
|
mDibitBroadcaster.addListener(mByteBufferAssembler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assembler for packaging Dibit stream into reusable byte buffers.
|
* Assembler for packaging Dibit stream into reusable byte buffers.
|
||||||
*/
|
*/
|
||||||
protected DibitToByteBufferAssembler getByteBufferAssembler()
|
protected Broadcaster<Dibit> getDibitBroadcaster()
|
||||||
{
|
{
|
||||||
return mByteBufferAssembler;
|
return mDibitBroadcaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,7 +64,7 @@ public abstract class P25Decoder extends Decoder
|
|||||||
@Override
|
@Override
|
||||||
public void setBufferListener(Listener<ReusableByteBuffer> listener)
|
public void setBufferListener(Listener<ReusableByteBuffer> listener)
|
||||||
{
|
{
|
||||||
getByteBufferAssembler().setBufferListener(listener);
|
mByteBufferAssembler.setBufferListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,7 +73,7 @@ public abstract class P25Decoder extends Decoder
|
|||||||
@Override
|
@Override
|
||||||
public void removeBufferListener(Listener<ReusableByteBuffer> listener)
|
public void removeBufferListener(Listener<ReusableByteBuffer> listener)
|
||||||
{
|
{
|
||||||
getByteBufferAssembler().removeBufferListener(listener);
|
mByteBufferAssembler.removeBufferListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,7 +82,7 @@ public abstract class P25Decoder extends Decoder
|
|||||||
@Override
|
@Override
|
||||||
public boolean hasBufferListeners()
|
public boolean hasBufferListeners()
|
||||||
{
|
{
|
||||||
return getByteBufferAssembler().hasBufferListeners();
|
return mByteBufferAssembler.hasBufferListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double getSymbolRate()
|
protected double getSymbolRate()
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulator;
|
|||||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
||||||
import io.github.dsheirer.dsp.psk.pll.AdaptivePLLGainMonitor;
|
import io.github.dsheirer.dsp.psk.pll.AdaptivePLLGainMonitor;
|
||||||
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
||||||
import io.github.dsheirer.sample.Listener;
|
|
||||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -72,20 +71,20 @@ public class P25DecoderC4FM extends P25Decoder
|
|||||||
|
|
||||||
mQPSKDemodulator = new DQPSKDecisionDirectedDemodulator(mCostasLoop, mInterpolatingSampleBuffer);
|
mQPSKDemodulator = new DQPSKDecisionDirectedDemodulator(mCostasLoop, mInterpolatingSampleBuffer);
|
||||||
|
|
||||||
|
if(mMessageFramer != null)
|
||||||
|
{
|
||||||
|
getDibitBroadcaster().removeListener(mMessageFramer);
|
||||||
|
mMessageFramer.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
//The Costas Loop receives symbol-inversion correction requests when detected.
|
//The Costas Loop receives symbol-inversion correction requests when detected.
|
||||||
//The PLL gain monitor receives sync detect/loss signals from the message framer
|
//The PLL gain monitor receives sync detect/loss signals from the message framer
|
||||||
mMessageFramer = new P25MessageFramer(getAliasList(), mCostasLoop, mPLLGainMonitor);
|
mMessageFramer = new P25MessageFramer(getAliasList(), mCostasLoop, mPLLGainMonitor);
|
||||||
mMessageFramer.setListener(getMessageProcessor());
|
mMessageFramer.setListener(getMessageProcessor());
|
||||||
mMessageFramer.setSampleRate(sampleRate);
|
mMessageFramer.setSampleRate(sampleRate);
|
||||||
|
|
||||||
// mQPSKDemodulator.setSymbolListener(mMessageFramer);
|
mQPSKDemodulator.setSymbolListener(getDibitBroadcaster());
|
||||||
mQPSKDemodulator.setSymbolListener(getByteBufferAssembler());
|
getDibitBroadcaster().addListener(mMessageFramer);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Listener getReusableByteBufferListener()
|
|
||||||
{
|
|
||||||
return mMessageFramer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ public class P25DecoderC4FMInstrumented extends P25DecoderC4FM
|
|||||||
instrumented.setPLLFrequencyListener(mPLLFrequencyListener);
|
instrumented.setPLLFrequencyListener(mPLLFrequencyListener);
|
||||||
instrumented.setSymbolDecisionDataListener(mSymbolDecisionDataListener);
|
instrumented.setSymbolDecisionDataListener(mSymbolDecisionDataListener);
|
||||||
instrumented.setSamplesPerSymbolListener(mSamplesPerSymbolListener);
|
instrumented.setSamplesPerSymbolListener(mSamplesPerSymbolListener);
|
||||||
instrumented.setSymbolListener(getByteBufferAssembler());
|
instrumented.setSymbolListener(getDibitBroadcaster());
|
||||||
|
getDibitBroadcaster().addListener(mMessageFramer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setComplexSymbolListener(Listener<Complex> listener)
|
public void setComplexSymbolListener(Listener<Complex> listener)
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulator;
|
|||||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
||||||
import io.github.dsheirer.dsp.psk.pll.AdaptivePLLGainMonitor;
|
import io.github.dsheirer.dsp.psk.pll.AdaptivePLLGainMonitor;
|
||||||
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
||||||
import io.github.dsheirer.sample.Listener;
|
|
||||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
|
|
||||||
@@ -76,17 +75,17 @@ public class P25DecoderLSM extends P25Decoder
|
|||||||
|
|
||||||
//The Costas Loop receives symbol-inversion correction requests when detected.
|
//The Costas Loop receives symbol-inversion correction requests when detected.
|
||||||
//The PLL gain monitor receives sync detect/loss signals from the message framer
|
//The PLL gain monitor receives sync detect/loss signals from the message framer
|
||||||
|
if(mMessageFramer != null)
|
||||||
|
{
|
||||||
|
getDibitBroadcaster().removeListener(mMessageFramer);
|
||||||
|
mMessageFramer.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
mMessageFramer = new P25MessageFramer(getAliasList(), mCostasLoop, mPLLGainMonitor);
|
mMessageFramer = new P25MessageFramer(getAliasList(), mCostasLoop, mPLLGainMonitor);
|
||||||
mMessageFramer.setListener(getMessageProcessor());
|
mMessageFramer.setListener(getMessageProcessor());
|
||||||
mMessageFramer.setSampleRate(sampleRate);
|
mMessageFramer.setSampleRate(sampleRate);
|
||||||
// mQPSKDemodulator.setSymbolListener(mMessageFramer);
|
mQPSKDemodulator.setSymbolListener(getDibitBroadcaster());
|
||||||
mQPSKDemodulator.setSymbolListener(getByteBufferAssembler());
|
getDibitBroadcaster().addListener(mMessageFramer);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Listener getReusableByteBufferListener()
|
|
||||||
{
|
|
||||||
return mMessageFramer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ public class P25DecoderLSMInstrumented extends P25DecoderLSM
|
|||||||
instrumented.setPLLFrequencyListener(mPLLFrequencyListener);
|
instrumented.setPLLFrequencyListener(mPLLFrequencyListener);
|
||||||
instrumented.setSymbolDecisionDataListener(mSymbolDecisionDataListener);
|
instrumented.setSymbolDecisionDataListener(mSymbolDecisionDataListener);
|
||||||
instrumented.setSamplesPerSymbolListener(mSamplesPerSymbolListener);
|
instrumented.setSamplesPerSymbolListener(mSamplesPerSymbolListener);
|
||||||
instrumented.setSymbolListener(getByteBufferAssembler());
|
instrumented.setSymbolListener(getDibitBroadcaster());
|
||||||
|
getDibitBroadcaster().addListener(mMessageFramer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setComplexSymbolListener(Listener<Complex> listener)
|
public void setComplexSymbolListener(Listener<Complex> listener)
|
||||||
|
|||||||
@@ -32,14 +32,10 @@ import io.github.dsheirer.module.decode.p25.message.vselp.VSELP1Message;
|
|||||||
import io.github.dsheirer.module.decode.p25.message.vselp.VSELP2Message;
|
import io.github.dsheirer.module.decode.p25.message.vselp.VSELP2Message;
|
||||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.buffer.ReusableByteBuffer;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
public class P25MessageFramer implements Listener<Dibit>
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class P25MessageFramer implements Listener<ReusableByteBuffer>
|
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(P25MessageFramer.class);
|
private final static Logger mLog = LoggerFactory.getLogger(P25MessageFramer.class);
|
||||||
|
|
||||||
@@ -78,7 +74,7 @@ public class P25MessageFramer implements Listener<ReusableByteBuffer>
|
|||||||
private PLLPhaseInversionDetector mInversionDetector180;
|
private PLLPhaseInversionDetector mInversionDetector180;
|
||||||
|
|
||||||
private MultiSyncPatternMatcher mMatcher;
|
private MultiSyncPatternMatcher mMatcher;
|
||||||
private List<P25MessageAssembler> mAssemblers = new ArrayList<P25MessageAssembler>();
|
private P25MessageAssembler mMessageAssembler = new P25MessageAssembler();
|
||||||
|
|
||||||
private Listener<Message> mListener;
|
private Listener<Message> mListener;
|
||||||
private AliasList mAliasList;
|
private AliasList mAliasList;
|
||||||
@@ -105,13 +101,9 @@ public class P25MessageFramer implements Listener<ReusableByteBuffer>
|
|||||||
@Override
|
@Override
|
||||||
public void syncDetected()
|
public void syncDetected()
|
||||||
{
|
{
|
||||||
for(P25MessageAssembler assembler : mAssemblers)
|
if(!mMessageAssembler.isActive())
|
||||||
{
|
{
|
||||||
if(!assembler.isActive())
|
mMessageAssembler.setActive(true);
|
||||||
{
|
|
||||||
assembler.setActive(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,17 +115,6 @@ public class P25MessageFramer implements Listener<ReusableByteBuffer>
|
|||||||
});
|
});
|
||||||
|
|
||||||
mMatcher.add(mPrimarySyncDetector);
|
mMatcher.add(mPrimarySyncDetector);
|
||||||
|
|
||||||
/**
|
|
||||||
* We use two message assemblers to catch any sync detections, so that
|
|
||||||
* if we have a false trigger then we still have a chance to catch the
|
|
||||||
* valid message. If we have two false triggers before the arrival of
|
|
||||||
* the actual message sync, then the third or subsequent real or false
|
|
||||||
* sync pattern will produce a debug message indicating no assemblers
|
|
||||||
* are available..
|
|
||||||
*/
|
|
||||||
mAssemblers.add(new P25MessageAssembler());
|
|
||||||
mAssemblers.add(new P25MessageAssembler());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public P25MessageFramer(AliasList aliasList, IPhaseLockedLoop phaseLockedLoop, ISyncDetectListener syncDetectListener)
|
public P25MessageFramer(AliasList aliasList, IPhaseLockedLoop phaseLockedLoop, ISyncDetectListener syncDetectListener)
|
||||||
@@ -173,12 +154,7 @@ public class P25MessageFramer implements Listener<ReusableByteBuffer>
|
|||||||
|
|
||||||
public void dispose()
|
public void dispose()
|
||||||
{
|
{
|
||||||
for(P25MessageAssembler a : mAssemblers)
|
mMessageAssembler.dispose();
|
||||||
{
|
|
||||||
a.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
mAssemblers.clear();
|
|
||||||
|
|
||||||
mListener = null;
|
mListener = null;
|
||||||
mAliasList = null;
|
mAliasList = null;
|
||||||
@@ -200,29 +176,20 @@ public class P25MessageFramer implements Listener<ReusableByteBuffer>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void receive(ReusableByteBuffer reusableByteBuffer)
|
public void receive(Dibit symbol)
|
||||||
{
|
{
|
||||||
//process the buffer received
|
if(mMessageAssembler.isActive())
|
||||||
}
|
{
|
||||||
|
mMessageAssembler.receive(symbol);
|
||||||
|
|
||||||
// @Override
|
if(mMessageAssembler.complete())
|
||||||
// public void receive(Dibit symbol)
|
{
|
||||||
// {
|
mMessageAssembler.reset();
|
||||||
// for(P25MessageAssembler assembler : mAssemblers)
|
}
|
||||||
// {
|
}
|
||||||
// if(assembler.isActive())
|
|
||||||
// {
|
mMatcher.receive(symbol.getBit1(), symbol.getBit2());
|
||||||
// assembler.receive(symbol);
|
}
|
||||||
//
|
|
||||||
// if(assembler.complete())
|
|
||||||
// {
|
|
||||||
// assembler.reset();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// mMatcher.receive(symbol.getBit1(), symbol.getBit2());
|
|
||||||
// }
|
|
||||||
|
|
||||||
public void setListener(Listener<Message> listener)
|
public void setListener(Listener<Message> listener)
|
||||||
{
|
{
|
||||||
@@ -749,13 +716,9 @@ public class P25MessageFramer implements Listener<ReusableByteBuffer>
|
|||||||
mPhaseLockedLoop.correctInversion(mPllCorrection);
|
mPhaseLockedLoop.correctInversion(mPllCorrection);
|
||||||
|
|
||||||
/* Since we detected a sync pattern, start a message assembler */
|
/* Since we detected a sync pattern, start a message assembler */
|
||||||
for(P25MessageAssembler assembler : mAssemblers)
|
if(!mMessageAssembler.isActive())
|
||||||
{
|
{
|
||||||
if(!assembler.isActive())
|
mMessageAssembler.setActive(true);
|
||||||
{
|
|
||||||
assembler.setActive(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user