[WIP]Updates the MPT-1327 decoder to use the new AFSK1200 decoder

class.
This commit is contained in:
Denny
2018-06-11 04:32:30 -04:00
parent 9dda1f95a1
commit 1fdcb623a6
10 changed files with 400 additions and 271 deletions

View File

@@ -0,0 +1,21 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.bits;
public interface IBinarySymbolProcessor
{
void receive(boolean symbol);
}

View File

@@ -32,7 +32,7 @@ import java.util.List;
* Will extract multiple messages simultaneously, for each sync pattern that is
* encountered within the bitset bit stream.
*/
public class MessageFramer implements Listener<Boolean>, SyncDetectProvider
public class MessageFramer implements IBinarySymbolProcessor, Listener<Boolean>, SyncDetectProvider
{
private boolean[] mSyncPattern;
private int mMessageLength;

View File

@@ -15,7 +15,7 @@
******************************************************************************/
package io.github.dsheirer.dsp.afsk;
import io.github.dsheirer.bits.MessageFramer;
import io.github.dsheirer.bits.IBinarySymbolProcessor;
import io.github.dsheirer.buffer.FloatAveragingBuffer;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
@@ -96,7 +96,7 @@ public class AFSK1200Decoder implements Listener<ReusableBuffer>
protected AFSKSampleBuffer mSampleBuffer;
protected AFSKTimingErrorDetector mTimingErrorDetector = new AFSKTimingErrorDetector(SAMPLES_PER_SYMBOL);
private RealFIRFilter2 mBandPassFilter = new RealFIRFilter2(sBandPassFilterCoefficients);
protected MessageFramer mMessageFramer;
protected IBinarySymbolProcessor mBinarySymbolProcessor;
private boolean mSampleDecision;
//Resample to an integral of the baud rate 1200 baud * 6 samples per symbol = 7200.0 Hertz
@@ -155,20 +155,20 @@ public class AFSK1200Decoder implements Listener<ReusableBuffer>
protected void dispatch(boolean symbol)
{
if(mMessageFramer != null)
if(mBinarySymbolProcessor != null)
{
mMessageFramer.receive(mNormalOutput ? symbol : !symbol);
mBinarySymbolProcessor.receive(mNormalOutput ? symbol : !symbol);
}
}
/**
* Registers a listener to receive decoded LTR symbols.
*
* @param messageFramer to receive symbols.
* @param binarySymbolProcessor to receive symbols.
*/
public void setMessageFramer(MessageFramer messageFramer)
public void setSymbolProcessor(IBinarySymbolProcessor binarySymbolProcessor)
{
mMessageFramer = messageFramer;
mBinarySymbolProcessor = binarySymbolProcessor;
}
/**
@@ -176,7 +176,7 @@ public class AFSK1200Decoder implements Listener<ReusableBuffer>
*/
public void removeListener()
{
mMessageFramer = null;
mBinarySymbolProcessor = null;
}

View File

@@ -40,11 +40,7 @@ public class AFSK1200DecoderInstrumented extends AFSK1200Decoder
protected void dispatch(boolean symbol)
{
if(mMessageFramer != null)
{
mMessageFramer.receive(mNormalOutput ? symbol : !symbol);
}
super.dispatch(symbol);
mSymbolBroadcaster.broadcast(symbol);
}

View File

@@ -64,10 +64,10 @@ import io.github.dsheirer.module.decode.mdc1200.MDCDecoderState;
import io.github.dsheirer.module.decode.mdc1200.MDCMessageFilter;
import io.github.dsheirer.module.decode.mpt1327.DecodeConfigMPT1327;
import io.github.dsheirer.module.decode.mpt1327.MPT1327Decoder;
import io.github.dsheirer.module.decode.mpt1327.MPT1327Decoder.Sync;
import io.github.dsheirer.module.decode.mpt1327.MPT1327DecoderEditor;
import io.github.dsheirer.module.decode.mpt1327.MPT1327DecoderState;
import io.github.dsheirer.module.decode.mpt1327.MPT1327MessageFilter;
import io.github.dsheirer.module.decode.mpt1327.Sync;
import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM;
import io.github.dsheirer.module.decode.nbfm.NBFMDecoder;
import io.github.dsheirer.module.decode.nbfm.NBFMDecoderEditor;
@@ -175,15 +175,12 @@ public class DecoderFactory
break;
case MPT1327:
DecodeConfigMPT1327 mptConfig = (DecodeConfigMPT1327) decodeConfig;
ChannelMap channelMap = channelMapModel.getChannelMap(mptConfig.getChannelMapName());
Sync sync = mptConfig.getSync();
modules.add(new MPT1327Decoder(aliasList, sync));
modules.add(new MPT1327DecoderState(aliasList, channelMap, channelType, mptConfig.getCallTimeout() * 1000));
modules.add(new FMDemodulatorModule(CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE));
modules.add(new AudioModule(metadata));
if(channelType == ChannelType.STANDARD)
{
@@ -191,9 +188,6 @@ public class DecoderFactory
channel.getRecordConfiguration(), channel.getSystem(), channel.getSite(),
(aliasList != null ? aliasList.getName() : null), mptConfig.getTrafficChannelPoolSize()));
}
modules.add(new FMDemodulatorModule(CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE));
modules.add(new AudioModule(metadata));
break;
case PASSPORT:
modules.add(new PassportDecoder(decodeConfig, aliasList));

View File

@@ -34,21 +34,40 @@ public class Fleetsync2Decoder extends AbstractAFSKDecoder
private MessageFramer mMessageFramer;
private Fleetsync2MessageProcessor mMessageProcessor;
/**
* Constructs a decoder for Fleetsync II protocol
* @param afsk1200Decoder to use for decoding the symbols
* @param aliasList to assign aliases to decoded values
*/
public Fleetsync2Decoder(AFSK1200Decoder afsk1200Decoder, AliasList aliasList)
{
super(afsk1200Decoder);
init(aliasList);
}
/**
* Constructs a decoder for Fleetsync II protocol
* @param aliasList to assign aliases to decoded values
*/
public Fleetsync2Decoder(AliasList aliasList)
{
super(AFSK1200Decoder.Output.NORMAL);
init(aliasList);
}
/**
* Initializes the decoding chain.
* @param aliasList to assign to the message processor
*/
private void init(AliasList aliasList)
{
mMessageFramer = new MessageFramer(SyncPattern.FLEETSYNC2.getPattern(), MESSAGE_LENGTH);
getDecoder().setMessageFramer(mMessageFramer);
getDecoder().setSymbolProcessor(mMessageFramer);
mMessageProcessor = new Fleetsync2MessageProcessor(aliasList);
mMessageFramer.addMessageListener(mMessageProcessor);
mMessageProcessor.setMessageListener(getMessageListener());
}
public Fleetsync2Decoder(AliasList aliasList)
{
this(new AFSK1200Decoder(AFSK1200Decoder.Output.NORMAL), aliasList);
}
@Override
public DecoderType getDecoderType()
{

View File

@@ -20,7 +20,6 @@ package io.github.dsheirer.module.decode.mpt1327;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.mpt1327.MPT1327Decoder.Sync;
public class DecodeConfigMPT1327 extends DecodeConfiguration
{

View File

@@ -1,161 +1,65 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.module.decode.mpt1327;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.bits.IBinarySymbolProcessor;
import io.github.dsheirer.bits.MessageFramer;
import io.github.dsheirer.bits.SyncPattern;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.Filters;
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter_RB_RB;
import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter_RB_RB;
import io.github.dsheirer.dsp.fsk.FSK2Decoder;
import io.github.dsheirer.instrument.Instrumentable;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapGroup;
import io.github.dsheirer.instrument.tap.stream.BinaryTap;
import io.github.dsheirer.instrument.tap.stream.FloatBufferTap;
import io.github.dsheirer.instrument.tap.stream.FloatTap;
import io.github.dsheirer.module.decode.Decoder;
import io.github.dsheirer.dsp.afsk.AFSK1200Decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.real.IFilteredRealBufferListener;
import io.github.dsheirer.sample.real.RealBuffer;
import io.github.dsheirer.module.decode.afsk.AbstractAFSKDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* MPT1327 Decoder - 1200 baud 2FSK decoder that can process 48k sample rate
* complex or floating point samples and output fully framed MPT1327 control and
* traffic messages.
*/
public class MPT1327Decoder extends Decoder implements IFilteredRealBufferListener, Instrumentable
public class MPT1327Decoder extends AbstractAFSKDecoder implements IBinarySymbolProcessor
{
private final static Logger mLog = LoggerFactory.getLogger(MPT1327Decoder.class);
private static final FIRFilterSpecification HIGH_PASS_SPECIFICATION = FIRFilterSpecification.highPassBuilder()
.sampleRate( 24000 )
.stopBandCutoff( 800 )
.stopBandAmplitude( 0.0 )
.stopBandRipple( 0.03 )
.passBandStart( 1000 )
.passBandAmplitude( 1.0 )
.passBandRipple( 0.08 )
.build();
private static float[] HIGHPASS_FILTER;
static
{
try
{
HIGHPASS_FILTER = FilterFactory.getTaps(HIGH_PASS_SPECIFICATION);
}
catch(Exception e)
{
mLog.error("Couldn't design MPT1327 highpass filter");
}
}
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
private static final int sDECIMATED_SAMPLE_RATE = 24000;
/* Baud or Symbol Rate */
private static final int sSYMBOL_RATE = 1200;
/* Message length -- longest possible message is:
* 4xREVS + 16xSYNC + 64xADD1 + 64xDCW1 + 64xDCW2 + 64xDCW3 + 64xDCW4 */
private static final int sMESSAGE_LENGTH = 350;
private static final int MESSAGE_LENGTH = 350;
/* Instrumentation Taps */
private static final String INSTRUMENT_HB1_FILTER_TO_HIGH_PASS =
"Tap Point: Half-band Decimation Filter > < Low Pass Filter";
private static final String INSTRUMENT_HIGH_PASS_TO_DECODER =
"Tap Point: Low Pass Filter > < Decoder";
private static final String INSTRUMENT_DECODER_TO_FRAMER =
"Tap Point: Decoder > < Sync Detect/Message Framer";
private List<TapGroup> mAvailableTaps;
private HalfBandFilter_RB_RB mDecimationFilter;
private RealFIRFilter_RB_RB mHighPassFilter;
private FSK2Decoder mFSKDecoder;
private Broadcaster<Boolean> mSymbolBroadcaster;
private MessageFramer mControlMessageFramer;
private MessageFramer mTrafficMessageFramer;
private MPT1327MessageProcessor mMessageProcessor;
public MPT1327Decoder(AliasList aliasList, Sync sync)
{
/**
* Normal: 2FSK Decoder with inverted output
* French: 2FSK Decoder with normal output
*/
if(sync == Sync.NORMAL)
{
mFSKDecoder = new FSK2Decoder(24000, 1200, FSK2Decoder.Output.INVERTED);
}
else if(sync == Sync.FRENCH)
{
mFSKDecoder = new FSK2Decoder(24000, 1200, FSK2Decoder.Output.NORMAL);
}
else
{
throw new IllegalArgumentException("MPT1327 Decoder - unrecognized Sync type");
}
super((sync == Sync.NORMAL ? AFSK1200Decoder.Output.NORMAL : AFSK1200Decoder.Output.INVERTED));
/* Decimation filter - 48000 / 2 = 24000 output */
mDecimationFilter = new HalfBandFilter_RB_RB(Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0002f, true);
getDecoder().setSymbolProcessor(this);
//High-pass filter the audio to remove any DC component or CTCSS tones. The audio has already been low-pass
//filtered by the AudioDemodulation filter cutoff of 3400 Hz.
mHighPassFilter = new RealFIRFilter_RB_RB(HIGHPASS_FILTER, 1.0f);
mDecimationFilter.setListener(mHighPassFilter);
//Message framer for control channel messages
mControlMessageFramer = new MessageFramer(sync.getControlSyncPattern().getPattern(), MESSAGE_LENGTH);
mHighPassFilter.setListener(mFSKDecoder);
//Message framer for traffic channel massages
mTrafficMessageFramer = new MessageFramer(sync.getTrafficSyncPattern().getPattern(), MESSAGE_LENGTH);
mSymbolBroadcaster = new Broadcaster<Boolean>();
mFSKDecoder.setListener(mSymbolBroadcaster);
/* Message framer for control channel messages */
mControlMessageFramer = new MessageFramer(sync.getControlSyncPattern().getPattern(), sMESSAGE_LENGTH);
mSymbolBroadcaster.addListener(mControlMessageFramer);
/* Message framer for traffic channel massages */
mTrafficMessageFramer = new MessageFramer(sync.getTrafficSyncPattern().getPattern(), sMESSAGE_LENGTH);
mSymbolBroadcaster.addListener(mTrafficMessageFramer);
/* Fully decoded and framed messages processor */
//Fully decoded and framed messages processor
mMessageProcessor = new MPT1327MessageProcessor(aliasList);
mMessageProcessor.setMessageListener(getMessageListener());
mControlMessageFramer.addMessageListener(mMessageProcessor);
mTrafficMessageFramer.addMessageListener(mMessageProcessor);
}
@Override
public Listener<RealBuffer> getFilteredRealBufferListener()
public void receive(boolean symbol)
{
return mDecimationFilter;
mControlMessageFramer.receive(symbol);
mTrafficMessageFramer.receive(symbol);
}
@Override
@@ -164,6 +68,13 @@ public class MPT1327Decoder extends Decoder implements IFilteredRealBufferListen
return DecoderType.MPT1327;
}
@Override
public void reset()
{
mControlMessageFramer.reset();
mTrafficMessageFramer.reset();
}
/**
* Cleanup method
*/
@@ -171,128 +82,9 @@ public class MPT1327Decoder extends Decoder implements IFilteredRealBufferListen
{
super.dispose();
mSymbolBroadcaster.dispose();
mControlMessageFramer.dispose();
mFSKDecoder.dispose();
mDecimationFilter.dispose();
mMessageProcessor.dispose();
mControlMessageFramer.dispose();
mTrafficMessageFramer.dispose();
}
/* Instrumentation Taps */
@Override
public List<TapGroup> getTapGroups()
{
if(mAvailableTaps == null)
{
mAvailableTaps = new ArrayList<TapGroup>();
TapGroup group = new TapGroup("MPT-1327 Decoder");
group.add(new FloatTap(INSTRUMENT_HB1_FILTER_TO_HIGH_PASS, 0, 0.5f));
group.add(new FloatTap(INSTRUMENT_HIGH_PASS_TO_DECODER, 0, 0.5f));
group.add(new BinaryTap(INSTRUMENT_DECODER_TO_FRAMER, 0, 0.025f));
mAvailableTaps.add(group);
/* Add the taps from the FSK decoder */
mAvailableTaps.addAll(mFSKDecoder.getTapGroups());
}
return mAvailableTaps;
}
@Override
public void registerTap(Tap tap)
{
/* Send request to decoder */
mFSKDecoder.registerTap(tap);
switch(tap.getName())
{
case INSTRUMENT_HB1_FILTER_TO_HIGH_PASS:
FloatBufferTap hb1Tap = (FloatBufferTap) tap;
mDecimationFilter.setListener(hb1Tap);
hb1Tap.setListener(mHighPassFilter);
break;
case INSTRUMENT_HIGH_PASS_TO_DECODER:
FloatBufferTap lowTap = (FloatBufferTap) tap;
mHighPassFilter.setListener(lowTap);
lowTap.setListener(mFSKDecoder);
break;
case INSTRUMENT_DECODER_TO_FRAMER:
BinaryTap decoderTap = (BinaryTap) tap;
mFSKDecoder.setListener(decoderTap);
decoderTap.setListener(mSymbolBroadcaster);
break;
}
}
@Override
public void unregisterTap(Tap tap)
{
mFSKDecoder.unregisterTap(tap);
switch(tap.getName())
{
case INSTRUMENT_HB1_FILTER_TO_HIGH_PASS:
mDecimationFilter.setListener(mHighPassFilter);
break;
case INSTRUMENT_HIGH_PASS_TO_DECODER:
mHighPassFilter.setListener(mFSKDecoder);
break;
case INSTRUMENT_DECODER_TO_FRAMER:
mFSKDecoder.setListener(mSymbolBroadcaster);
break;
}
}
public enum Sync
{
NORMAL("Normal", SyncPattern.MPT1327_CONTROL, SyncPattern.MPT1327_TRAFFIC),
FRENCH("French", SyncPattern.MPT1327_CONTROL_FRENCH, SyncPattern.MPT1327_TRAFFIC_FRENCH);
private String mLabel;
private SyncPattern mControlSyncPattern;
private SyncPattern mTrafficSyncPattern;
private Sync(String label, SyncPattern controlPattern, SyncPattern trafficPattern)
{
mLabel = label;
mControlSyncPattern = controlPattern;
mTrafficSyncPattern = trafficPattern;
}
public String getLabel()
{
return mLabel;
}
public SyncPattern getControlSyncPattern()
{
return mControlSyncPattern;
}
public SyncPattern getTrafficSyncPattern()
{
return mTrafficSyncPattern;
}
public String toString()
{
return getLabel();
}
}
@Override
public void reset()
{
mControlMessageFramer.reset();
mTrafficMessageFramer.reset();
}
}

View File

@@ -0,0 +1,253 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.module.decode.mpt1327;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.bits.MessageFramer;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.Filters;
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter_RB_RB;
import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter_RB_RB;
import io.github.dsheirer.dsp.fsk.FSK2Decoder;
import io.github.dsheirer.instrument.Instrumentable;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapGroup;
import io.github.dsheirer.instrument.tap.stream.BinaryTap;
import io.github.dsheirer.instrument.tap.stream.FloatBufferTap;
import io.github.dsheirer.instrument.tap.stream.FloatTap;
import io.github.dsheirer.module.decode.Decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.real.IFilteredRealBufferListener;
import io.github.dsheirer.sample.real.RealBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* MPT1327 Decoder - 1200 baud 2FSK decoder that can process 48k sample rate
* complex or floating point samples and output fully framed MPT1327 control and
* traffic messages.
*/
public class MPT1327DecoderLegacy extends Decoder implements IFilteredRealBufferListener, Instrumentable
{
private final static Logger mLog = LoggerFactory.getLogger(MPT1327DecoderLegacy.class);
private static final FIRFilterSpecification HIGH_PASS_SPECIFICATION = FIRFilterSpecification.highPassBuilder()
.sampleRate( 24000 )
.stopBandCutoff( 800 )
.stopBandAmplitude( 0.0 )
.stopBandRipple( 0.03 )
.passBandStart( 1000 )
.passBandAmplitude( 1.0 )
.passBandRipple( 0.08 )
.build();
private static float[] HIGHPASS_FILTER;
static
{
try
{
HIGHPASS_FILTER = FilterFactory.getTaps(HIGH_PASS_SPECIFICATION);
}
catch(Exception e)
{
mLog.error("Couldn't design MPT1327 highpass filter");
}
}
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
private static final int sDECIMATED_SAMPLE_RATE = 24000;
/* Baud or Symbol Rate */
private static final int sSYMBOL_RATE = 1200;
/* Message length -- longest possible message is:
* 4xREVS + 16xSYNC + 64xADD1 + 64xDCW1 + 64xDCW2 + 64xDCW3 + 64xDCW4 */
private static final int sMESSAGE_LENGTH = 350;
/* Instrumentation Taps */
private static final String INSTRUMENT_HB1_FILTER_TO_HIGH_PASS =
"Tap Point: Half-band Decimation Filter > < Low Pass Filter";
private static final String INSTRUMENT_HIGH_PASS_TO_DECODER =
"Tap Point: Low Pass Filter > < Decoder";
private static final String INSTRUMENT_DECODER_TO_FRAMER =
"Tap Point: Decoder > < Sync Detect/Message Framer";
private List<TapGroup> mAvailableTaps;
private HalfBandFilter_RB_RB mDecimationFilter;
private RealFIRFilter_RB_RB mHighPassFilter;
private FSK2Decoder mFSKDecoder;
private Broadcaster<Boolean> mSymbolBroadcaster;
private MessageFramer mControlMessageFramer;
private MessageFramer mTrafficMessageFramer;
private MPT1327MessageProcessor mMessageProcessor;
public MPT1327DecoderLegacy(AliasList aliasList, Sync sync)
{
/**
* Normal: 2FSK Decoder with inverted output
* French: 2FSK Decoder with normal output
*/
if(sync == Sync.NORMAL)
{
mFSKDecoder = new FSK2Decoder(24000, 1200, FSK2Decoder.Output.INVERTED);
}
else if(sync == Sync.FRENCH)
{
mFSKDecoder = new FSK2Decoder(24000, 1200, FSK2Decoder.Output.NORMAL);
}
else
{
throw new IllegalArgumentException("MPT1327 Decoder - unrecognized Sync type");
}
/* Decimation filter - 48000 / 2 = 24000 output */
mDecimationFilter = new HalfBandFilter_RB_RB(Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0002f, true);
//High-pass filter the audio to remove any DC component or CTCSS tones. The audio has already been low-pass
//filtered by the AudioDemodulation filter cutoff of 3400 Hz.
mHighPassFilter = new RealFIRFilter_RB_RB(HIGHPASS_FILTER, 1.0f);
mDecimationFilter.setListener(mHighPassFilter);
mHighPassFilter.setListener(mFSKDecoder);
mSymbolBroadcaster = new Broadcaster<Boolean>();
mFSKDecoder.setListener(mSymbolBroadcaster);
/* Message framer for control channel messages */
mControlMessageFramer = new MessageFramer(sync.getControlSyncPattern().getPattern(), sMESSAGE_LENGTH);
mSymbolBroadcaster.addListener(mControlMessageFramer);
/* Message framer for traffic channel massages */
mTrafficMessageFramer = new MessageFramer(sync.getTrafficSyncPattern().getPattern(), sMESSAGE_LENGTH);
mSymbolBroadcaster.addListener(mTrafficMessageFramer);
/* Fully decoded and framed messages processor */
mMessageProcessor = new MPT1327MessageProcessor(aliasList);
mMessageProcessor.setMessageListener(getMessageListener());
mControlMessageFramer.addMessageListener(mMessageProcessor);
mTrafficMessageFramer.addMessageListener(mMessageProcessor);
}
@Override
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
@Override
public DecoderType getDecoderType()
{
return DecoderType.MPT1327;
}
/**
* Cleanup method
*/
public void dispose()
{
super.dispose();
mSymbolBroadcaster.dispose();
mControlMessageFramer.dispose();
mFSKDecoder.dispose();
mDecimationFilter.dispose();
mMessageProcessor.dispose();
mTrafficMessageFramer.dispose();
}
/* Instrumentation Taps */
@Override
public List<TapGroup> getTapGroups()
{
if(mAvailableTaps == null)
{
mAvailableTaps = new ArrayList<TapGroup>();
TapGroup group = new TapGroup("MPT-1327 Decoder");
group.add(new FloatTap(INSTRUMENT_HB1_FILTER_TO_HIGH_PASS, 0, 0.5f));
group.add(new FloatTap(INSTRUMENT_HIGH_PASS_TO_DECODER, 0, 0.5f));
group.add(new BinaryTap(INSTRUMENT_DECODER_TO_FRAMER, 0, 0.025f));
mAvailableTaps.add(group);
/* Add the taps from the FSK decoder */
mAvailableTaps.addAll(mFSKDecoder.getTapGroups());
}
return mAvailableTaps;
}
@Override
public void registerTap(Tap tap)
{
/* Send request to decoder */
mFSKDecoder.registerTap(tap);
switch(tap.getName())
{
case INSTRUMENT_HB1_FILTER_TO_HIGH_PASS:
FloatBufferTap hb1Tap = (FloatBufferTap) tap;
mDecimationFilter.setListener(hb1Tap);
hb1Tap.setListener(mHighPassFilter);
break;
case INSTRUMENT_HIGH_PASS_TO_DECODER:
FloatBufferTap lowTap = (FloatBufferTap) tap;
mHighPassFilter.setListener(lowTap);
lowTap.setListener(mFSKDecoder);
break;
case INSTRUMENT_DECODER_TO_FRAMER:
BinaryTap decoderTap = (BinaryTap) tap;
mFSKDecoder.setListener(decoderTap);
decoderTap.setListener(mSymbolBroadcaster);
break;
}
}
@Override
public void unregisterTap(Tap tap)
{
mFSKDecoder.unregisterTap(tap);
switch(tap.getName())
{
case INSTRUMENT_HB1_FILTER_TO_HIGH_PASS:
mDecimationFilter.setListener(mHighPassFilter);
break;
case INSTRUMENT_HIGH_PASS_TO_DECODER:
mHighPassFilter.setListener(mFSKDecoder);
break;
case INSTRUMENT_DECODER_TO_FRAMER:
mFSKDecoder.setListener(mSymbolBroadcaster);
break;
}
}
}

View File

@@ -0,0 +1,55 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.module.decode.mpt1327;
import io.github.dsheirer.bits.SyncPattern;
public enum Sync
{
NORMAL("Normal", SyncPattern.MPT1327_CONTROL, SyncPattern.MPT1327_TRAFFIC),
FRENCH("French", SyncPattern.MPT1327_CONTROL_FRENCH, SyncPattern.MPT1327_TRAFFIC_FRENCH);
private String mLabel;
private SyncPattern mControlSyncPattern;
private SyncPattern mTrafficSyncPattern;
Sync(String label, SyncPattern controlPattern, SyncPattern trafficPattern)
{
mLabel = label;
mControlSyncPattern = controlPattern;
mTrafficSyncPattern = trafficPattern;
}
public String getLabel()
{
return mLabel;
}
public SyncPattern getControlSyncPattern()
{
return mControlSyncPattern;
}
public SyncPattern getTrafficSyncPattern()
{
return mTrafficSyncPattern;
}
public String toString()
{
return getLabel();
}
}