mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
[WIP]Updates the MPT-1327 decoder to use the new AFSK1200 decoder
class.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user