[WIP] Cleanup. Removes the legacy Instrumentable, Taps, etc and related

gui components.  Refactors the new DecoderFX application to the
instrument package.
This commit is contained in:
Denny
2018-06-15 07:27:17 -04:00
parent 2cd3b73633
commit f4793f3cfd
76 changed files with 74 additions and 4581 deletions

View File

@@ -1,302 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.dsp.fsk;
import io.github.dsheirer.buffer.BooleanAveragingBuffer;
import io.github.dsheirer.dsp.symbol.SymbolEvent;
import io.github.dsheirer.dsp.symbol.SymbolEvent.Shift;
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.SymbolEventTap;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.real.RealBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
/**
* Binary Frequency Shift Keying (FSK) decoder. Implements a BFSK correlation
* decoder. Provides normal or inverted decoded output. Requires the symbol
* rate to be an integer multiple of the sample rate.
*
* Implements a correlation decoder that correlates a modulated FSK signal upon
* against a one-baud delayed version of itself, converting all float samples to
* binary (0 or 1), and uses XOR to produce the correlation value. Low pass
* filtering smoothes the correlated output.
*
* Automatically aligns to symbol timing during symbol transitions (0 to 1, or
* 1 to 0) by inspecting the samples at the symbol edges and advancing or
* retarding symbol window to maintain continuous symbol alignment.
*
* Use a DC-removal filter prior to this decoder to ensure samples don't have
* a DC component.
*
* Implements instrumentable interface, so that slice events can be received
* externally to analyze decoder performance.
*/
public class FSK2Decoder implements Instrumentable, Listener<RealBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(FSK2Decoder.class);
public enum Output
{
NORMAL, INVERTED
}
/* Instrumentation taps */
private static final String INSTRUMENT_DECISION =
"Tap Point: FSK2 Symbol Decision";
private List<TapGroup> mAvailableTaps;
private ArrayList<SymbolEventTap> mTaps = new ArrayList<SymbolEventTap>();
private Listener<Boolean> mListener;
private BooleanAveragingBuffer mDelayBuffer;
private BooleanAveragingBuffer mLowPassFilter;
private Slicer mSlicer;
private boolean mNormalOutput;
private int mSamplesPerSymbol;
private int mSymbolRate;
public FSK2Decoder(int sampleRate, int symbolRate, Output output)
{
/* Ensure we're using an integral symbolRate of the sampleRate */
assert (sampleRate % symbolRate == 0);
mSamplesPerSymbol = (int) (sampleRate / symbolRate);
mNormalOutput = (output == Output.NORMAL);
mSymbolRate = symbolRate;
mDelayBuffer = new BooleanAveragingBuffer(mSamplesPerSymbol);
mLowPassFilter = new BooleanAveragingBuffer(mSamplesPerSymbol);
mSlicer = new Slicer(mSamplesPerSymbol);
}
/**
* Disposes of all references to prepare for garbage collection
*/
public void dispose()
{
mListener = null;
}
/**
* Primary sample input
*/
@Override
public void receive(RealBuffer buffer)
{
for(float sample : buffer.getSamples())
{
/* Square the sample. Greater than zero is a 1 (true) and less than
* zero is a 0 (false) */
boolean bitSample = (sample >= 0.0f);
/* Feed the delay buffer and fetch the one-baud delayed sample */
boolean delayedBitSample = mDelayBuffer.get(bitSample);
/* Correlation: xor current bit with delayed bit */
boolean softBit = bitSample ^ delayedBitSample;
/* Low pass filter to smooth the correlated values */
boolean filteredSoftBit = mLowPassFilter.getAverage(softBit);
/* Send the filtered correlated bit to the slicer */
mSlicer.receive(filteredSoftBit);
}
}
/**
* Registers a listener to receive the decoded FSK bits
*/
public void setListener(Listener<Boolean> listener)
{
mListener = listener;
}
/**
* Removes the listener
*/
public void removeListener(Listener<Boolean> listener)
{
mListener = null;
}
/**
* Symbol slicer with auto-aligning baud timing
*/
public class Slicer
{
private BitSet mBitSet = new BitSet();
private int mSymbolLength;
private int mDecisionThreshold;
private int mSampleCounter;
public Slicer(int samplesPerSymbol)
{
mSymbolLength = samplesPerSymbol;
mDecisionThreshold = (int) (mSymbolLength / 2);
/* Adjust for an odd number of samples per baud */
if(mSymbolLength % 2 == 1)
{
mDecisionThreshold++;
}
}
public void receive(boolean softBit)
{
if(mSampleCounter >= 0)
{
if(softBit)
{
mBitSet.set(mSampleCounter);
}
else
{
mBitSet.clear(mSampleCounter);
}
}
mSampleCounter++;
if(mSampleCounter >= mSymbolLength)
{
boolean decision = mBitSet.cardinality() >= mDecisionThreshold;
send(decision);
/* Shift timing left if the left bit in the bitset is opposite
* the decision and the right bit is the same */
if((mBitSet.get(0) ^ decision) &&
(!(mBitSet.get(mSymbolLength - 1) ^ decision)))
{
sendTapEvent(mBitSet, Shift.LEFT, decision);
reset();
mSampleCounter--;
}
/* Shift timing right if the left bit is the same as the
* decision and the right bit is opposite */
else if((!(mBitSet.get(0) ^ decision)) &&
(mBitSet.get(mSymbolLength - 1) ^ decision))
{
sendTapEvent(mBitSet, Shift.RIGHT, decision);
/* Last bit from previous symbol to pre-fill next symbol */
boolean previousSoftBit = mBitSet.get(mSymbolLength - 1);
reset();
if(previousSoftBit)
{
mBitSet.set(0);
}
mSampleCounter++;
}
/* No shift */
else
{
sendTapEvent(mBitSet, Shift.NONE, decision);
reset();
}
}
}
/**
* Sends the bit decision to the listener
*/
private void send(boolean decision)
{
if(mListener != null)
{
mListener.receive(mNormalOutput ? decision : !decision);
}
}
private void reset()
{
mBitSet.clear();
mSampleCounter = 0;
}
/**
* Sends instrumentation tap event to all registered listeners
*/
private void sendTapEvent(BitSet bitset, Shift shift, boolean decision)
{
for(SymbolEventTap tap : mTaps)
{
SymbolEvent event =
new SymbolEvent(bitset.get(0, mSymbolLength),
mSymbolLength,
decision,
shift);
tap.receive(event);
}
}
}
/**
* Get instrumentation taps
*/
@Override
public List<TapGroup> getTapGroups()
{
if(mAvailableTaps == null)
{
mAvailableTaps = new ArrayList<TapGroup>();
TapGroup tapGroup = new TapGroup("FSK2 Decoder");
tapGroup.add(new SymbolEventTap(INSTRUMENT_DECISION, 0, .025f));
mAvailableTaps.add(tapGroup);
}
return mAvailableTaps;
}
/**
* Add instrumentation tap
*/
@Override
public void registerTap(Tap tap)
{
if(tap instanceof SymbolEventTap && !mTaps.contains(tap))
{
mTaps.add((SymbolEventTap) tap);
}
}
/**
* Remove instrumentation tap
*/
@Override
public void unregisterTap(Tap tap)
{
mTaps.remove(tap);
}
}

View File

@@ -1,149 +0,0 @@
package io.github.dsheirer.dsp.symbol;
import io.github.dsheirer.instrument.tap.stream.SymbolEventTap;
import io.github.dsheirer.sample.Listener;
import java.util.BitSet;
/**
* Symbol slicer with auto-aligning baud timing
*/
public class Slicer implements Listener<Boolean>
{
public enum Output{ NORMAL, INVERTED };
private BitSet mBitSet = new BitSet();
private int mSymbolLength;
private int mDecisionThreshold;
private int mSampleCounter;
private SymbolEventTap mSymbolEventTap;
private boolean mNormalOutput = true;
private Listener<Boolean> mListener;
public Slicer( Output output, int samplesPerSymbol )
{
mNormalOutput = ( output == Output.NORMAL );
mSymbolLength = samplesPerSymbol;
/* Round up */
mDecisionThreshold = (int)( mSymbolLength / 2 ) + ( mSymbolLength % 2 );
}
public void receive( Boolean sample )
{
if( mSampleCounter >= 0 )
{
if( sample )
{
mBitSet.set( mSampleCounter );
}
else
{
mBitSet.clear( mSampleCounter );
}
}
mSampleCounter++;
if( mSampleCounter >= mSymbolLength )
{
boolean decision = mBitSet.cardinality() >= mDecisionThreshold;
send( decision );
/* Shift timing left if the left bit in the bitset is opposite
* the decision and the right bit is the same */
if( ( mBitSet.get( 0 ) ^ decision ) &&
( !( mBitSet.get( mSymbolLength - 1 ) ^ decision ) ) )
{
sendTapEvent( mBitSet, SymbolEvent.Shift.LEFT, decision );
reset();
mSampleCounter--;
}
/* Shift timing right if the left bit is the same as the
* decision and the right bit is opposite */
else if( ( !( mBitSet.get( 0 ) ^ decision ) ) &&
( mBitSet.get( mSymbolLength - 1 ) ^ decision ) )
{
sendTapEvent( mBitSet, SymbolEvent.Shift.RIGHT, decision );
/* Last bit from previous symbol to pre-fill next symbol */
boolean previousSoftBit = mBitSet.get( mSymbolLength - 1 );
reset();
if( previousSoftBit )
{
mBitSet.set( 0 );
}
mSampleCounter++;
}
/* No shift */
else
{
sendTapEvent( mBitSet, SymbolEvent.Shift.NONE, decision );
reset();
}
}
}
/**
* Sends the bit decision to the listener
*/
private void send( boolean decision )
{
if( mListener != null )
{
mListener.receive( mNormalOutput ? decision : !decision );
}
}
private void reset()
{
mBitSet.clear();
mSampleCounter = 0;
}
public void setListener( Listener<Boolean> listener)
{
mListener = listener;
}
public void removeListener( Listener<Boolean> listener )
{
mListener = null;
}
/**
* Sends instrumentation tap event to all registered listeners
*/
private void sendTapEvent(BitSet bitset, SymbolEvent.Shift shift, boolean decision )
{
if( mSymbolEventTap != null )
{
SymbolEvent event =
new SymbolEvent( bitset.get( 0, mSymbolLength ),
mSymbolLength,
decision,
shift );
mSymbolEventTap.receive( event );
}
}
public void addTap( SymbolEventTap tap )
{
mSymbolEventTap = tap;
}
public void removeTap()
{
mSymbolEventTap = null;
}
}

View File

@@ -13,9 +13,9 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer;
package io.github.dsheirer.instrument;
import io.github.dsheirer.instrument.gui.viewer.decoder.DecoderPaneFactory;
import io.github.dsheirer.instrument.decoder.DecoderPaneFactory;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25Decoder;
import javafx.application.Application;

View File

@@ -1,54 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapGroup;
import java.util.List;
/**
* Interface for classes that want to expose internal data, streams or events
* to external listeners.
*/
public interface Instrumentable
{
/**
* Returns the list of available tap point groups. Use the addTap() and
* removeTap() to register a tap on the instrumentable class and then add
* your TapListener(s) to the registered tap.
*/
public List<TapGroup> getTapGroups();
/**
* Registers a tap on the instrumentable object.
*
* @param tap - one of the tap(s) obtained from getTaps() from the
* instrumentable source
*/
public void registerTap( Tap tap );
/**
* Unregisters a tap on the instrumentable object, if the tap is currently
* registered.
*
* @param tap - one of the tap(s) obtained from getTaps() from the
* instrumentable source
*/
public void unregisterTap( Tap tap );
}

View File

@@ -1,82 +0,0 @@
/*******************************************************************************
* 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.instrument;
import io.github.dsheirer.controller.channel.Channel.ChannelType;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapGroup;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.module.ProcessingChain;
import io.github.dsheirer.source.Source;
import java.util.ArrayList;
import java.util.List;
public class InstrumentableProcessingChain extends ProcessingChain implements Instrumentable
{
public InstrumentableProcessingChain()
{
super(ChannelType.STANDARD);
}
public void setSource(Source source) throws IllegalStateException
{
mSource = source;
}
@Override
public List<TapGroup> getTapGroups()
{
List<TapGroup> groups = new ArrayList<>();
for(Module module : getModules())
{
if(module instanceof Instrumentable)
{
groups.addAll(((Instrumentable)module).getTapGroups());
}
}
return groups;
}
@Override
public void registerTap(Tap tap)
{
for(Module module : getModules())
{
if(module instanceof Instrumentable)
{
((Instrumentable)module).registerTap(tap);
}
}
}
@Override
public void unregisterTap(Tap tap)
{
for(Module module : getModules())
{
if(module instanceof Instrumentable)
{
((Instrumentable)module).unregisterTap(tap);
}
}
}
}

View File

@@ -13,9 +13,9 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer;
package io.github.dsheirer.instrument;
import io.github.dsheirer.instrument.gui.viewer.decoder.AbstractDecoderPane;
import io.github.dsheirer.instrument.decoder.AbstractDecoderPane;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;

View File

@@ -1,4 +1,19 @@
package io.github.dsheirer.instrument.gui.viewer;
/*******************************************************************************
* 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.instrument;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;

View File

@@ -13,10 +13,10 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer;
package io.github.dsheirer.instrument;
import io.github.dsheirer.instrument.gui.viewer.decoder.AbstractDecoderPane;
import io.github.dsheirer.instrument.gui.viewer.decoder.DecoderPaneFactory;
import io.github.dsheirer.instrument.decoder.AbstractDecoderPane;
import io.github.dsheirer.instrument.decoder.DecoderPaneFactory;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25Decoder;
import javafx.scene.layout.BorderPane;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.buffer.ComplexCircularBuffer;
import io.github.dsheirer.dsp.gain.ComplexGain;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.buffer.ComplexCircularBuffer;
import io.github.dsheirer.dsp.gain.ComplexGain;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.sample.Listener;
import javafx.collections.FXCollections;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.buffer.DoubleCircularBuffer;
import io.github.dsheirer.sample.Listener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.dsp.psk.SymbolDecisionData;
import io.github.dsheirer.sample.Listener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.buffer.DoubleCircularBuffer;
import io.github.dsheirer.dsp.fm.FMDemodulator;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.message.Message;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoderInstrumented;
import javafx.beans.value.ChangeListener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.buffer.DoubleCircularBuffer;
import io.github.dsheirer.sample.Listener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.buffer.RealCircularBuffer;
import io.github.dsheirer.sample.Listener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.Complex;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.chart;
package io.github.dsheirer.instrument.chart;
import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoderInstrumented;
import javafx.beans.value.ChangeListener;

View File

@@ -13,13 +13,13 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.instrument.gui.viewer.chart.AFSK1200SampleBufferChart;
import io.github.dsheirer.instrument.gui.viewer.chart.AFSK1200ZeroCrossingErrorDetectorChart;
import io.github.dsheirer.instrument.gui.viewer.chart.DecodedSymbolChart;
import io.github.dsheirer.instrument.gui.viewer.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.instrument.gui.viewer.chart.RealSampleLineChart;
import io.github.dsheirer.instrument.chart.AFSK1200SampleBufferChart;
import io.github.dsheirer.instrument.chart.AFSK1200ZeroCrossingErrorDetectorChart;
import io.github.dsheirer.instrument.chart.DecodedSymbolChart;
import io.github.dsheirer.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.instrument.chart.RealSampleLineChart;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25Decoder;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.fleetsync2.Fleetsync2DecoderInstrumented;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.module.decode.DecoderType;

View File

@@ -13,11 +13,11 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.instrument.gui.viewer.chart.LTRNetSampleBufferChart;
import io.github.dsheirer.instrument.gui.viewer.chart.RealSampleLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.ZeroCrossingErrorDetectorChart;
import io.github.dsheirer.instrument.chart.LTRNetSampleBufferChart;
import io.github.dsheirer.instrument.chart.RealSampleLineChart;
import io.github.dsheirer.instrument.chart.ZeroCrossingErrorDetectorChart;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.message.MessageDirection;
import io.github.dsheirer.module.decode.DecoderType;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.module.decode.DecoderType;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.module.decode.DecoderType;

View File

@@ -13,13 +13,13 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.instrument.gui.viewer.chart.ComplexSampleLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.DoubleLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.EyeDiagramChart;
import io.github.dsheirer.instrument.gui.viewer.chart.PhaseLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.SymbolChart;
import io.github.dsheirer.instrument.chart.ComplexSampleLineChart;
import io.github.dsheirer.instrument.chart.DoubleLineChart;
import io.github.dsheirer.instrument.chart.EyeDiagramChart;
import io.github.dsheirer.instrument.chart.PhaseLineChart;
import io.github.dsheirer.instrument.chart.SymbolChart;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25DecoderC4FMInstrumented;

View File

@@ -13,13 +13,13 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.instrument.gui.viewer.chart.ComplexSampleLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.DoubleLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.EyeDiagramChart;
import io.github.dsheirer.instrument.gui.viewer.chart.PhaseLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.SymbolChart;
import io.github.dsheirer.instrument.chart.ComplexSampleLineChart;
import io.github.dsheirer.instrument.chart.DoubleLineChart;
import io.github.dsheirer.instrument.chart.EyeDiagramChart;
import io.github.dsheirer.instrument.chart.PhaseLineChart;
import io.github.dsheirer.instrument.chart.SymbolChart;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25DecoderLSMInstrumented;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;

View File

@@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.instrument.gui.viewer.decoder;
package io.github.dsheirer.instrument.decoder;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.module.decode.DecoderType;

View File

@@ -1,77 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.gui;
import io.github.dsheirer.gui.control.ConstellationViewer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.source.IFrameLocationListener;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
public class ConstellationPanel extends JInternalFrame
implements IFrameLocationListener, Listener<Complex>
{
private static final long serialVersionUID = 1L;
private ConstellationViewer mConstellation = new ConstellationViewer( 48000, 4800 );
public ConstellationPanel()
{
initGui();
}
private void initGui()
{
setLayout( new MigLayout( "insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]" ) );
setTitle( "Constellation View" );
setPreferredSize( new Dimension( 300, 300 ) );
setSize( 300, 300 );
setResizable( true );
setClosable( true );
setIconifiable( true );
setMaximizable( false );
add( mConstellation );
}
@Override
public void frameLocationUpdated( int location )
{
// TODO Auto-generated method stub
}
@Override
public void frameLocationReset()
{
// TODO Auto-generated method stub
}
@Override
public void receive( Complex sample )
{
mConstellation.receive( sample );
}
}

View File

@@ -1,102 +0,0 @@
package io.github.dsheirer.instrument.gui;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.ChannelModel;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.module.decode.DecodeConfigurationEditor;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.source.IControllableFileSource;
import net.miginfocom.swing.MigLayout;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DecoderSelectionFrame extends JInternalFrame
{
private static final long serialVersionUID = 1L;
private Channel mChannel = new Channel();
private DecodeConfigurationEditor mDecodeEditor = new DecodeConfigurationEditor(null);
private PlaylistManager mPlaylistManager;
private IControllableFileSource mSource;
private JDesktopPane mDesktop;
public DecoderSelectionFrame(JDesktopPane desktop, IControllableFileSource source)
{
AliasModel aliasModel = new AliasModel();
BroadcastModel broadcastModel = new BroadcastModel(null);
ChannelModel channelModel = new ChannelModel();
ChannelMapModel channelMapModel = new ChannelMapModel();
mPlaylistManager = new PlaylistManager(aliasModel, broadcastModel, channelModel, channelMapModel);
mDesktop = desktop;
mSource = source;
mDecodeEditor.setItem(mChannel);
initGUI();
}
private void initGUI()
{
setLayout(new MigLayout("", "[grow,fill]", "[][][grow,fill]"));
setTitle("Decoders");
setPreferredSize(new Dimension(700, 450));
setSize(700, 450);
setResizable(true);
setClosable(true);
setIconifiable(true);
setMaximizable(false);
add(mDecodeEditor, "wrap");
add(new AddDecoderButton(), "span");
}
public class AddDecoderButton extends JButton
{
private static final long serialVersionUID = 1L;
public AddDecoderButton()
{
super("Add");
addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
mDecodeEditor.save();
Channel channel = mDecodeEditor.getItem();
if(channel != null)
{
DecodeConfiguration config = channel.getDecodeConfiguration();
if( config != null )
{
DecoderViewFrame decoderFrame = new DecoderViewFrame(mPlaylistManager, channel, mSource );
decoderFrame.setVisible( true );
mDesktop.add( decoderFrame );
}
}
}
});
}
}
}

View File

@@ -1,355 +0,0 @@
/*******************************************************************************
* 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.instrument.gui;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.ChannelModel;
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.instrument.Instrumentable;
import io.github.dsheirer.instrument.InstrumentableProcessingChain;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapGroup;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import io.github.dsheirer.instrument.tap.stream.BinaryTap;
import io.github.dsheirer.instrument.tap.stream.BinaryTapViewPanel;
import io.github.dsheirer.instrument.tap.stream.ComplexSampleTap;
import io.github.dsheirer.instrument.tap.stream.ComplexSampleTapViewPanel;
import io.github.dsheirer.instrument.tap.stream.ComplexTap;
import io.github.dsheirer.instrument.tap.stream.ComplexTapViewPanel;
import io.github.dsheirer.instrument.tap.stream.DibitTap;
import io.github.dsheirer.instrument.tap.stream.DibitTapViewPanel;
import io.github.dsheirer.instrument.tap.stream.EyeDiagramDataTap;
import io.github.dsheirer.instrument.tap.stream.EyeDiagramDataTapPanel;
import io.github.dsheirer.instrument.tap.stream.FloatTap;
import io.github.dsheirer.instrument.tap.stream.FloatTapViewPanel;
import io.github.dsheirer.instrument.tap.stream.QPSKTap;
import io.github.dsheirer.instrument.tap.stream.QPSKTapPanel;
import io.github.dsheirer.instrument.tap.stream.SymbolEventTap;
import io.github.dsheirer.instrument.tap.stream.SymbolEventTapViewPanel;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.module.decode.DecoderFactory;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.log.EventLogManager;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.source.IControllableFileSource;
import io.github.dsheirer.source.Source;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashMap;
import java.util.List;
public class DecoderViewFrame extends JInternalFrame implements Listener<Message>
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger(DecoderViewFrame.class);
private DecodeConfiguration mDecodeConfig;
private InstrumentableProcessingChain mProcessingChain;
private IControllableFileSource mSource;
private HashMap<Tap,TapViewPanel> mPanelMap = new HashMap<Tap,TapViewPanel>();
public DecoderViewFrame(PlaylistManager playlistManager, Channel channel, IControllableFileSource source)
{
mSource = source;
mDecodeConfig = channel.getDecodeConfiguration();
mProcessingChain = new InstrumentableProcessingChain();
ChannelModel channelModel = new ChannelModel();
ChannelMapModel channelMapModel = new ChannelMapModel();
ChannelProcessingManager channelProcessingManager = new ChannelProcessingManager(channelModel, channelMapModel,
new AliasModel(), new EventLogManager(), null, null);
List<Module> modules = DecoderFactory.getModules(channelModel, channelMapModel, channelProcessingManager,
new AliasModel(), channel, mProcessingChain.getChannelState().getMutableMetadata());
mProcessingChain.addModules(modules);
mProcessingChain.addMessageListener(this);
mProcessingChain.setSource((Source) mSource);
mProcessingChain.start();
initGui();
}
private void initGui()
{
setLayout(new MigLayout("insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]"));
setTitle("Decoder [" + mDecodeConfig.getDecoderType().getDisplayString() + "]");
setPreferredSize(new Dimension(450, 250));
setSize(450, 250);
setResizable(true);
setClosable(true);
setIconifiable(true);
setMaximizable(false);
addMouseListener(new MouseListener()
{
@Override
public void mouseClicked(MouseEvent me)
{
if(me.getButton() == MouseEvent.BUTTON3)
{
JPopupMenu popup = new JPopupMenu();
popup.add(getTapContextMenu());
if(!mPanelMap.values().isEmpty())
{
popup.add(new JSeparator());
for(TapViewPanel panel : mPanelMap.values())
{
popup.add(panel.getContextMenu());
}
}
popup.show(DecoderViewFrame.this, me.getX(), me.getY());
}
}
@Override
public void mouseEntered(MouseEvent arg0)
{
}
@Override
public void mouseExited(MouseEvent arg0)
{
}
@Override
public void mousePressed(MouseEvent arg0)
{
}
@Override
public void mouseReleased(MouseEvent arg0)
{
}
});
}
private JMenu getTapContextMenu()
{
JMenu menu = new JMenu("Modules");
if(mProcessingChain != null)
{
for(Module module : mProcessingChain.getModules())
{
if(module instanceof Instrumentable)
{
List<TapGroup> groups = ((Instrumentable) module).getTapGroups();
for(TapGroup group : groups)
{
menu.add(new TapGroupMenu(group));
}
}
}
}
return menu;
}
public void add(Tap tap)
{
TapViewPanel panel = null;
switch(tap.getType())
{
case EVENT_SYNC_DETECT:
break;
case STREAM_BINARY:
panel = new BinaryTapViewPanel((BinaryTap) tap);
break;
case STREAM_COMPLEX:
panel = new ComplexTapViewPanel((ComplexTap) tap);
break;
case STREAM_COMPLEX_SAMPLE:
panel = new ComplexSampleTapViewPanel((ComplexSampleTap) tap);
break;
case STREAM_DIBIT:
panel = new DibitTapViewPanel((DibitTap) tap);
break;
case STREAM_EYE_DIAGRAM:
panel = new EyeDiagramDataTapPanel((EyeDiagramDataTap) tap);
break;
case STREAM_FLOAT:
panel = new FloatTapViewPanel((FloatTap) tap);
break;
case STREAM_QPSK:
panel = new QPSKTapPanel((QPSKTap) tap);
break;
case STREAM_SYMBOL:
panel = new SymbolEventTapViewPanel((SymbolEventTap) tap);
break;
}
if(panel != null)
{
add(panel, "span");
validate();
mPanelMap.put(tap, panel);
for(Module module : mProcessingChain.getModules())
{
if(module instanceof Instrumentable)
{
((Instrumentable) module).registerTap(tap);
}
}
}
else
{
mLog.info("Tap panel is null, couldn't add for tap " +
tap.getName() + "[" + tap.getType().toString() + "]");
}
}
public void remove(Tap tap)
{
for(Module module : mProcessingChain.getModules())
{
if(module instanceof Instrumentable)
{
((Instrumentable) module).unregisterTap(tap);
}
}
TapViewPanel panel = mPanelMap.get(tap);
remove(panel);
validate();
mPanelMap.remove(tap);
}
public class AddAllTapsItem extends JMenuItem
{
private static final long serialVersionUID = 1L;
private final List<Tap> mTaps;
public AddAllTapsItem(final List<Tap> taps)
{
super("All Taps");
mTaps = taps;
addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
for(Tap tap : mTaps)
{
DecoderViewFrame.this.add(tap);
}
}
});
}
}
public class TapSelectionItem extends JCheckBoxMenuItem
{
private static final long serialVersionUID = 1L;
private Tap mTap;
public TapSelectionItem(Tap tap)
{
super(tap.getName());
mTap = tap;
if(mPanelMap.keySet().contains(tap))
{
setSelected(true);
}
addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
if(mPanelMap.keySet().contains(mTap))
{
DecoderViewFrame.this.remove(mTap);
}
else
{
DecoderViewFrame.this.add(mTap);
}
}
});
}
}
@Override
public void receive(Message message)
{
mLog.info(message.toString());
}
public class TapGroupMenu extends JMenu
{
private static final long serialVersionUID = 1L;
private TapGroup mTapGroup;
public TapGroupMenu(TapGroup tapGroup)
{
super(tapGroup.getName());
mTapGroup = tapGroup;
add(new AddAllTapsItem(mTapGroup.getTaps()));
add(new JSeparator());
for(Tap tap : mTapGroup.getTaps())
{
add(new TapSelectionItem(tap));
}
}
}
}

View File

@@ -1,101 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.gui;
import io.github.dsheirer.instrument.tap.TapListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
public class SampleModel<T> extends Observable implements TapListener<T>
{
private final static Logger mLog =
LoggerFactory.getLogger( SampleModel.class );
private int mSampleCount = 2000;
private int mDelay = 0;
private ArrayList<T> mSamples = new ArrayList<T>();
public SampleModel()
{
}
public List<T> getSamples()
{
return Collections.unmodifiableList( mSamples );
}
public void clearSamples()
{
mSamples.clear();
changed();
}
public int getSampleCount()
{
return mSampleCount;
}
public void setSampleCount( int count )
{
mSampleCount = count;
changed();
}
public void setDelay( int delay )
{
mDelay = delay;
}
public int getDelay()
{
return mDelay;
}
@Override
public void receive( T t )
{
if( mDelay > 0 )
{
mDelay--;
}
else
{
mSamples.add( t );
while( mSamples.size() > mSampleCount )
{
mSamples.remove( 0 );
}
}
changed();
}
private void changed()
{
setChanged();
notifyObservers();
}
}

View File

@@ -1,215 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.gui;
import io.github.dsheirer.source.IControllableFileSource;
import io.github.dsheirer.source.IFrameLocationListener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.IOException;
public class SourceControllerFrame extends JInternalFrame
implements IFrameLocationListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( SourceControllerFrame.class );
private IControllableFileSource mSource;
private JDesktopPane mDesktop;
private JLabel mCurrentPosition = new JLabel( "0" );
public SourceControllerFrame( IControllableFileSource source,
JDesktopPane desktop )
{
mSource = source;
mSource.setListener( this );
mDesktop = desktop;
initGui();
}
private void initGui()
{
setTitle( "Source [" + mSource.getFile().getAbsolutePath() + "]" );
setPreferredSize( new Dimension( 670, 70 ) );
setSize( 670, 70 );
setResizable( true );
setClosable( true );
setIconifiable( true );
setMaximizable( false );
JPanel panel = new JPanel();
panel.setLayout( new MigLayout() );
JButton decoderButton = new JButton( "Decoders" );
decoderButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
DecoderSelectionFrame frame =
new DecoderSelectionFrame( mDesktop, mSource );
frame.setVisible( true );
mDesktop.add( frame );
}
} );
}
} );
panel.add( decoderButton );
panel.add( new JLabel( "Skip:" ) );
panel.add( new SkipFramesField( mSource ) );
panel.add( new NextFrameButton( mSource, "> 1", 1 ) );
panel.add( new NextFrameButton( mSource, "> 10", 10 ) );
panel.add( new NextFrameButton( mSource, "> 100", 100 ) );
panel.add( new NextFrameButton( mSource, "> 1000", 1000 ) );
panel.add( new JLabel( "Posn:" ) );
panel.add( mCurrentPosition, "wrap" );
add( panel );
}
public class NextFrameButton extends JButton
{
private static final long serialVersionUID = 1L;
private IControllableFileSource mSource;
private int mFrames;
public NextFrameButton( IControllableFileSource source,
String label, int frames )
{
super( label );
mSource = source;
mFrames = frames;
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
mSource.next( mFrames );
}
catch ( IOException e )
{
mLog.error( "Viewer - reading frames [" + mFrames +
"] from source", e );
JOptionPane.showMessageDialog( SourceControllerFrame.this,
"Can't read " + mFrames + " more frames [" +
e.getLocalizedMessage() + "]",
"Wave File Error",
JOptionPane.ERROR_MESSAGE );
}
}
} );
}
} );
}
}
public class SkipFramesField extends JTextField
{
private static final long serialVersionUID = 1L;
private IControllableFileSource mSource;
public SkipFramesField( IControllableFileSource source )
{
super( "0" );
mSource = source;
setMinimumSize( new Dimension( 100, getHeight() ) );
addFocusListener( new FocusListener()
{
@Override
public void focusGained( FocusEvent arg0 ) {}
@Override
public void focusLost( FocusEvent arg0 )
{
try
{
int framesToSkip = Integer.parseInt( getText() );
mSource.next( framesToSkip, false );
}
catch( Exception e )
{
mLog.error( "WaveSourceFrame - error skipping frames", e );
JOptionPane.showMessageDialog( SourceControllerFrame.this,
"Can't skip [" + getText() + "] frames.",
"Error",
JOptionPane.ERROR_MESSAGE );
}
}
} );
}
}
@Override
public void frameLocationUpdated( final int location )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
mCurrentPosition.setText( String.valueOf( location ) );
}
} );
}
@Override
public void frameLocationReset()
{
// TODO Auto-generated method stub
}
}

View File

@@ -1,293 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.gui;
import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.source.IControllableFileSource;
import io.github.dsheirer.source.wave.ComplexWaveSource;
import io.github.dsheirer.source.wave.RealWaveSource;
import io.github.dsheirer.util.TimeStamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class Viewer
{
private final static Logger mLog = LoggerFactory.getLogger( Viewer.class );
private JFrame mFrame;
private JDesktopPane mDesktop;
private IControllableFileSource mSource;
public Viewer()
{
initGUI();
}
public void setVisible( boolean visible )
{
mFrame.setVisible( visible );
}
/**
* Initialize the contents of the frame.
*/
private void initGUI()
{
/* Setup main JFrame window */
mFrame = new JFrame();
mFrame.setTitle( "SDRTrunk - Sample File Viewer" );
mFrame.setBounds( 100, 100, 800, 600 );
mFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
/* Multi-window desktop */
mDesktop = new JDesktopPane();
mFrame.add( mDesktop );
/* Menu items */
JMenuBar menuBar = new JMenuBar();
mFrame.setJMenuBar( menuBar );
JMenu fileMenu = new JMenu( "File" );
menuBar.add( fileMenu );
fileMenu.add( new SourceFileItem() );
fileMenu.add( new JSeparator() );
JMenuItem exitMenu = new JMenuItem( "Exit" );
exitMenu.addActionListener( new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
System.exit( 0 );
}
} );
fileMenu.add( exitMenu );
menuBar.add( new ScreenCaptureItem() );
}
private void setSourceFile( File file )
{
mLog.info( "File selected [" + file.getAbsolutePath() + "]");
IControllableFileSource source = null;
/* Attempt to open file as a 1-channel float source */
try
{
source = new RealWaveSource( file );
source.open();
mLog.info( "File opened as float wave file" );
}
catch( Exception e )
{
mLog.error( "Couldn't open file as float single-channel source" );
}
if( source == null )
{
/* Attempt to open file as a 2-channel complex source */
try
{
ComplexWaveSource complex = new ComplexWaveSource( file );
complex.open();
source = complex;
mLog.info( "File opened as complex wave file" );
}
catch( Exception e )
{
mLog.error( "Couldn't open file as float source", e);
}
}
if( source != null )
{
mSource = source;
SourceControllerFrame sourcePanel =
new SourceControllerFrame( source, mDesktop );
sourcePanel.setVisible( true );
mDesktop.add( sourcePanel );
}
}
public static void main( String[] args )
{
final Viewer viewer = new Viewer();
EventQueue.invokeLater( new Runnable()
{
public void run()
{
try
{
viewer.setVisible( true );
}
catch( Exception e )
{
e.printStackTrace();
}
}
} );
}
public class SourceFileItem extends JMenuItem
{
private static final long serialVersionUID = 1L;
public SourceFileItem()
{
super( "Open" );
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
final JFileChooser fc = new JFileChooser();
fc.setFileFilter( new FileFilter()
{
@Override
public boolean accept( File file )
{
return file.isDirectory() ||
file.getName().endsWith( ".wav" );
}
@Override
public String getDescription()
{
return "Float or Complex 16-bit Wave Files";
}
} );
int val = fc.showOpenDialog( mFrame );
if( val == JFileChooser.APPROVE_OPTION )
{
final File file = fc.getSelectedFile();
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
setSourceFile( file );
}
} );
}
}
} );
}
}
public class ScreenCaptureItem extends JMenuItem
{
private static final long serialVersionUID = 1L;
public ScreenCaptureItem()
{
super( "Screen Capture" );
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
Robot robot = new Robot();
final BufferedImage image =
robot.createScreenCapture( mFrame.getBounds() );
SystemProperties props = SystemProperties.getInstance();
Path capturePath = props.getApplicationFolder( "screen_captures" );
if( !Files.exists( capturePath ) )
{
try
{
Files.createDirectory( capturePath );
}
catch ( IOException e )
{
mLog.error( "Couldn't create 'screen_captures' "
+ "subdirectory in the " +
"SDRTrunk application directory", e );
}
}
String filename = TimeStamp.getTimeStamp( "_" ) +
"_screen_capture.png";
final Path captureFile = capturePath.resolve( filename );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
ImageIO.write( image, "png",
captureFile.toFile() );
}
catch ( IOException e )
{
mLog.error( "Couldn't write screen capture to "
+ "file [" + captureFile.toString() + "]", e );
}
}} );
}
catch ( AWTException e )
{
mLog.error( "Exception while taking screen capture", e );
}
}
} );
}
} );
}
}
}

View File

@@ -1,96 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap;
import java.util.ArrayList;
public abstract class Tap
{
protected TapType mType;
protected String mName;
protected int mDelay;
protected ArrayList<TapListener> mListeners = new ArrayList<TapListener>();
/**
* Instrumentation tap. Provides a tap into a data stream or event stream
* within a process, so that registered listeners can be notified every
* time a new data sample is availabe, or an event occurrs.
*
* @param name - displayable name to use for the tap
*
* @param delay - indicates the number of delay units from when the data
* begins the process until this event occurs. When this data or event is
* plotted on a flow graph, the delay value will be used to adjust placement
* on the display to correctly align events.
*/
public Tap( TapType type, String name, int delay )
{
mType = type;
mName = name;
mDelay = delay;
}
public TapType getType()
{
return mType;
}
/**
* Display name for this tap
*/
public String getName()
{
return mName;
}
/**
* Delay for this tap
*/
public int getDelay()
{
return mDelay;
}
/**
* Registers a listener for data or events produced by this tap
*/
public void addListener( TapListener listener )
{
if( !mListeners.contains( listener ) )
{
mListeners.add( listener );
}
}
/**
* Removes the listener from receiving data or events from this tap
*/
public void removeListener( TapListener listener )
{
mListeners.remove( listener );
}
/**
* Number of listeners currently registered on this tap
*/
public int getListenerCount()
{
return mListeners.size();
}
}

View File

@@ -1,35 +0,0 @@
package io.github.dsheirer.instrument.tap;
import java.util.ArrayList;
import java.util.List;
public class TapGroup
{
private String mName;
private List<Tap> mTaps = new ArrayList<>();
public TapGroup( String name )
{
mName = name;
}
public String getName()
{
return mName;
}
public String toString()
{
return getName();
}
public List<Tap> getTaps()
{
return mTaps;
}
public void add( Tap tap )
{
mTaps.add( tap );
}
}

View File

@@ -1,23 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap;
public interface TapListener<T>
{
public void receive( T t );
}

View File

@@ -1,31 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap;
public enum TapType
{
EVENT_SYNC_DETECT,
STREAM_BINARY,
STREAM_COMPLEX,
STREAM_COMPLEX_SAMPLE,
STREAM_DIBIT,
STREAM_EYE_DIAGRAM,
STREAM_FLOAT,
STREAM_QPSK,
STREAM_SYMBOL;
}

View File

@@ -1,131 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap;
import io.github.dsheirer.instrument.gui.SampleModel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observer;
public abstract class TapViewPanel extends JPanel implements Observer
{
private static final long serialVersionUID = 1L;
protected SampleModel<?> mModel;
protected String mLabel;
protected float mVerticalZoom = 1.0f;
public TapViewPanel( SampleModel<?> model, String label )
{
mModel = model;
mModel.addObserver( this );
mLabel = label;
initGui();
}
private void initGui()
{
setBackground( Color.WHITE );
setForeground( Color.BLUE );
setSize( new Dimension( 400, 200 ) );
}
public void reset()
{
mModel.clearSamples();
}
public JMenu getContextMenu()
{
JMenu menu = new JMenu( mLabel );
JMenu verticalMenu = new JMenu( "Vertical Zoom" );
menu.add( verticalMenu );
verticalMenu.add( new VerticalZoomItem( this, "8", 8.0f ) );
verticalMenu.add( new VerticalZoomItem( this, "4", 4.0f ) );
verticalMenu.add( new VerticalZoomItem( this, "2", 2.0f ) );
verticalMenu.add( new VerticalZoomItem( this, "1", 1.0f ) );
verticalMenu.add( new VerticalZoomItem( this, ".5", 0.5f ) );
verticalMenu.add( new VerticalZoomItem( this, ".25", 0.25f ) );
return menu;
}
public SampleModel<?> getModel()
{
return mModel;
}
public int getSampleCount()
{
return getModel().getSampleCount();
}
public void setSampleCount( int sampleCount )
{
getModel().setSampleCount( sampleCount );
}
public float getVerticalZoom()
{
return mVerticalZoom;
}
public void setVerticalZoom( float zoom )
{
mVerticalZoom = zoom;
repaint();
}
public class VerticalZoomItem extends JCheckBoxMenuItem
{
private static final long serialVersionUID = 1L;
private TapViewPanel mPanel;
private float mZoom;
public VerticalZoomItem( TapViewPanel panel, String label, float zoom )
{
super( label );
mPanel = panel;
mZoom = zoom;
if( mPanel.getVerticalZoom() == zoom )
{
setSelected( true );
}
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
mPanel.setVerticalZoom( mZoom );
}
} );
}
}
}

View File

@@ -1,58 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.event;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.dsp.symbol.SyncDetectProvider;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
public class SyncDetectTap extends Tap implements ISyncDetectListener, SyncDetectProvider
{
private ISyncDetectListener mListener;
/**
* Sync detect event tap. Indicates when message sync word has been
* detected within a binary stream of data.
*/
public SyncDetectTap()
{
super(TapType.EVENT_SYNC_DETECT, "Sync Detected", 0);
}
@Override
public void syncDetected()
{
if(mListener != null)
{
mListener.syncDetected();
}
for(TapListener listener : mListeners)
{
listener.receive(getName());
}
}
@Override
public void setSyncDetectListener(ISyncDetectListener listener)
{
mListener = listener;
}
}

View File

@@ -1,40 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
public class AdditiveFloatTap extends FloatTap
{
private float mValue;
public AdditiveFloatTap( String name,
int delay,
float sampleRateRatio,
float addValue )
{
super( name, delay, sampleRateRatio );
mValue = addValue;
}
@Override
public void receive( float sample )
{
super.receive( sample + mValue );
}
}

View File

@@ -1,59 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
import io.github.dsheirer.sample.Listener;
public class BinaryTap extends StreamTap implements Listener<Boolean>
{
private Listener<Boolean> mListener;
public BinaryTap( String name,
int delay,
float sampleRateRatio )
{
super( TapType.STREAM_BINARY, name, delay, sampleRateRatio );
}
@Override
public void receive( Boolean bit )
{
if( mListener != null )
{
mListener.receive( bit );
}
for( TapListener listener: mListeners )
{
listener.receive( bit );
}
}
public void setListener( Listener<Boolean> listener )
{
mListener = listener;
}
public void removeListener( Listener<Boolean> listener )
{
mListener = null;
}
}

View File

@@ -1,156 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Observable;
public class BinaryTapViewPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private Tap mTap;
private List<Boolean> mSamples;
private int mSampleCount;
public BinaryTapViewPanel( BinaryTap tap )
{
super( new SampleModel<Boolean>(), tap.getName() );
mTap = tap;
mTap.addListener( getModel() );
getModel().setSampleCount(
(int)( getModel().getSampleCount() * tap.getSampleRateRatio() ) );
getModel().setDelay( tap.getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<Boolean>)getModel().getSamples();
mSampleCount = getModel().getSampleCount();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int height = getHeight();
int width = getWidth();
g2.setColor( Color.DARK_GRAY );
float middle = (float)height / 2.0f;
g2.drawLine( 0, (int)middle, width, (int)middle );
if( mSamples != null && mSamples.size() > 0 )
{
g2.setColor( getForeground() );
g2.drawString( mLabel, 5 , 15 );
for( int x = 1; x < mSamples.size(); x++ )
{
paintBit( g, x, mSamples.get( x ) );
}
}
g2.dispose();
}
/**
* Paints a polyline representing a boolean value with a 0 or 1 label in
* the middle of it
*
* @param graphics object
* @param index - index of the sample int the sample buffer
* @param value - bit value, 0 or 1
*/
private void paintBit( Graphics graphics, int index, boolean value )
{
Graphics2D g2 = (Graphics2D)graphics;
Path2D.Float polyline =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
float middleY = ( (float)getHeight() / 2.0f );
float indexWidth = (float)( getWidth() ) / (float)mSampleCount;
float startX = (float)index * indexWidth;
float stopX = (float)(index + 1 ) * indexWidth;
float fivePercent = indexWidth * .05f;
float leftX = startX + fivePercent;
float rightX = stopX - fivePercent;
/* Start */
polyline.moveTo( startX, middleY );
/* Left horizonal segment */
polyline.lineTo( leftX, middleY );
float y = ( value ? ( middleY - ( middleY * 0.5f) ) :
( middleY + ( middleY * 0.5f) ) );
/* Left vertical segment */
polyline.lineTo( leftX, y );
/* Middle horizontal segment */
polyline.lineTo( rightX, y );
/* Right vertical segment */
polyline.lineTo( rightX, middleY );
/* Right horizontal segment */
polyline.lineTo( stopX, middleY );
g2.draw( polyline );
/* Draw the bit value label */
String bit = value ? "1" : "0";
FontMetrics fontMetrics = graphics.getFontMetrics( this.getFont() );
Rectangle2D label = fontMetrics.getStringBounds( bit, graphics );
float offsetX = (float)label.getWidth() / 2.0f;
float offsetY = (float)label.getWidth() / 2.0f;
float middleX = startX + ( indexWidth / 2.0f );
graphics.drawString( bit,
(int)( middleX - offsetX ),
(int)( middleY - offsetY ) );
}
}

View File

@@ -1,64 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.sample.complex.ComplexSampleListener;
public class ComplexSampleTap extends StreamTap implements ComplexSampleListener
{
private ComplexSampleListener mListener;
public ComplexSampleTap( String name,
int delay,
float sampleRateRatio )
{
super( TapType.STREAM_COMPLEX_SAMPLE, name, delay, sampleRateRatio );
}
public ComplexSampleTap( TapType tapType, String name, int delay, float sampleRateRatio )
{
super( tapType, name, delay, sampleRateRatio );
}
@Override
public void receive( float inphase, float quadrature )
{
if( mListener != null )
{
mListener.receive( inphase, quadrature );
}
for( TapListener listener: mListeners )
{
listener.receive( new Complex( inphase, quadrature ) );
}
}
public void setListener( ComplexSampleListener listener )
{
mListener = listener;
}
public void removeListener( ComplexSampleListener listener )
{
mListener = null;
}
}

View File

@@ -1,150 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.gui.SDRTrunk;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import io.github.dsheirer.sample.complex.Complex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.List;
import java.util.Observable;
public class ComplexSampleTapViewPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( SDRTrunk.class );
private Tap mTap;
private List<Complex> mSamples;
private int mSampleCount;
public ComplexSampleTapViewPanel( ComplexSampleTap tap )
{
super( new SampleModel<ComplexTap>(), tap.getName() );
setSize( new Dimension( 400, 400 ) );
mTap = tap;
mTap.addListener( getModel() );
mSampleCount = (int)( 2000 * tap.getSampleRateRatio() );
getModel().setSampleCount( mSampleCount );
getModel().setDelay( tap.getDelay() );
mLog.info( "Complex Tap Panel [" + tap.getName() + "] count: " +
getModel().getSampleCount() + " delay:" + getModel().getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<Complex>)getModel().getSamples();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int height = getHeight();
int width = getWidth();
g2.setColor( Color.DARK_GRAY );
float middle = (float)height / 4.0f;
g2.drawLine( 0, (int)middle, width, (int)middle );
g2.drawLine( 0, (int)( 3 * middle ), width, (int)( 3 * middle ) );
if( mSamples != null &&
mSamples.size() > 0 )
{
g2.setColor( getForeground() );
g2.drawString( mLabel, 5 , 15 );
Path2D.Float polylineReal =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
Path2D.Float polylineImag =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
/* Move to the first point */
Point2D.Float firstReal = resolve( 0, mSamples.get( 0 ), Type.REAL );
polylineReal.moveTo( firstReal.x, firstReal.y );
Point2D.Float firstImag = resolve( 0, mSamples.get( 0 ), Type.IMAGINERY );
polylineImag.moveTo( firstImag.x, firstImag.y );
for( int x = 1; x < mSamples.size(); x++ )
{
Point2D.Float pointReal = resolve( x, mSamples.get( x ), Type.REAL );
polylineReal.lineTo( pointReal.x, pointReal.y );
Point2D.Float pointImag = resolve( x, mSamples.get( x ), Type.IMAGINERY );
polylineImag.lineTo( pointImag.x, pointImag.y );
// mLog.debug( "Imag y:" + pointImag.getY() + " height:" + getHeight() );
}
g2.draw( polylineReal );
g2.draw( polylineImag );
}
g2.dispose();
}
private Point2D.Float resolve( int index, Complex sample, Type type )
{
int middle = (int)( getHeight() / 4 );
float y = middle - ( middle * mVerticalZoom * ( type == Type.REAL ?
sample.real() : sample.imaginary()) );
if( type == Type.IMAGINERY )
{
y += ( middle * 2 );
}
/* Clip y to zero as necessary */
y = ( y < 0 ) ? 0 : y;
/* Clip y to max height as necessary */
y = ( y > getHeight() ) ? getHeight() : y;
float indexWidth = (float)getWidth() / (float)mSampleCount;
float x = (float)index * indexWidth;
Point2D.Float point = new Point2D.Float( x, y );
return new Point2D.Float( x , y );
}
public enum Type{ REAL,IMAGINERY };
}

View File

@@ -1,64 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.Complex;
public class ComplexTap extends StreamTap implements Listener<Complex>
{
private Listener<Complex> mListener;
public ComplexTap( String name,
int delay,
float sampleRateRatio )
{
super( TapType.STREAM_COMPLEX, name, delay, sampleRateRatio );
}
public ComplexTap( TapType tapType, String name, int delay, float sampleRateRatio )
{
super( tapType, name, delay, sampleRateRatio );
}
@Override
public void receive( Complex sample )
{
if( mListener != null )
{
mListener.receive( sample );
}
for( TapListener listener: mListeners )
{
listener.receive( sample );
}
}
public void setListener( Listener<Complex> listener )
{
mListener = listener;
}
public void removeListener( Listener<Complex> listener )
{
mListener = null;
}
}

View File

@@ -1,150 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.gui.SDRTrunk;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import io.github.dsheirer.sample.complex.Complex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.List;
import java.util.Observable;
public class ComplexTapViewPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( SDRTrunk.class );
private Tap mTap;
private List<Complex> mSamples;
private int mSampleCount;
public ComplexTapViewPanel( ComplexTap tap )
{
super( new SampleModel<ComplexTap>(), tap.getName() );
setSize( new Dimension( 400, 400 ) );
mTap = tap;
mTap.addListener( getModel() );
mSampleCount = (int)( 2000 * tap.getSampleRateRatio() );
getModel().setSampleCount( mSampleCount );
getModel().setDelay( tap.getDelay() );
mLog.info( "Complex Tap Panel [" + tap.getName() + "] count: " +
getModel().getSampleCount() + " delay:" + getModel().getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<Complex>)getModel().getSamples();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int height = getHeight();
int width = getWidth();
g2.setColor( Color.DARK_GRAY );
float middle = (float)height / 4.0f;
g2.drawLine( 0, (int)middle, width, (int)middle );
g2.drawLine( 0, (int)( 3 * middle ), width, (int)( 3 * middle ) );
if( mSamples != null &&
mSamples.size() > 0 )
{
g2.setColor( getForeground() );
g2.drawString( mLabel, 5 , 15 );
Path2D.Float polylineReal =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
Path2D.Float polylineImag =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
/* Move to the first point */
Point2D.Float firstReal = resolve( 0, mSamples.get( 0 ), Type.REAL );
polylineReal.moveTo( firstReal.x, firstReal.y );
Point2D.Float firstImag = resolve( 0, mSamples.get( 0 ), Type.IMAGINERY );
polylineImag.moveTo( firstImag.x, firstImag.y );
for( int x = 1; x < mSamples.size(); x++ )
{
Point2D.Float pointReal = resolve( x, mSamples.get( x ), Type.REAL );
polylineReal.lineTo( pointReal.x, pointReal.y );
Point2D.Float pointImag = resolve( x, mSamples.get( x ), Type.IMAGINERY );
polylineImag.lineTo( pointImag.x, pointImag.y );
// mLog.debug( "Imag y:" + pointImag.getY() + " height:" + getHeight() );
}
g2.draw( polylineReal );
g2.draw( polylineImag );
}
g2.dispose();
}
private Point2D.Float resolve( int index, Complex sample, Type type )
{
int middle = (int)( getHeight() / 4 );
float y = middle - ( middle * mVerticalZoom * ( type == Type.REAL ?
sample.real() : sample.imaginary()) );
if( type == Type.IMAGINERY )
{
y += ( middle * 2 );
}
/* Clip y to zero as necessary */
y = ( y < 0 ) ? 0 : y;
/* Clip y to max height as necessary */
y = ( y > getHeight() ) ? getHeight() : y;
float indexWidth = (float)getWidth() / (float)mSampleCount;
float x = (float)index * indexWidth;
Point2D.Float point = new Point2D.Float( x, y );
return new Point2D.Float( x , y );
}
public enum Type{ REAL,IMAGINERY };
}

View File

@@ -1,60 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.dsp.symbol.Dibit;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
import io.github.dsheirer.sample.Listener;
public class DibitTap extends StreamTap implements Listener<Dibit>
{
private Listener<Dibit> mListener;
public DibitTap( String name,
int delay,
float sampleRateRatio )
{
super( TapType.STREAM_DIBIT, name, delay, sampleRateRatio );
}
@Override
public void receive( Dibit dibit )
{
if( mListener != null )
{
mListener.receive( dibit );
}
for( TapListener listener: mListeners )
{
listener.receive( dibit );
}
}
public void setListener( Listener<Dibit> listener )
{
mListener = listener;
}
public void removeListener( Listener<Dibit> listener )
{
mListener = null;
}
}

View File

@@ -1,186 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.dsp.symbol.Dibit;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Observable;
public class DibitTapViewPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private Tap mTap;
private List<Dibit> mSamples;
private int mSampleCount;
private int mOffset = 0;
public DibitTapViewPanel( DibitTap tap )
{
super( new SampleModel<Dibit>(), tap.getName() );
mTap = tap;
mTap.addListener( getModel() );
getModel().setSampleCount(
(int)( getModel().getSampleCount() * tap.getSampleRateRatio() ) );
getModel().setDelay( tap.getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<Dibit>)getModel().getSamples();
mSampleCount = getModel().getSampleCount();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int height = getHeight();
int width = getWidth();
g2.setColor( Color.DARK_GRAY );
float middle = (float)height / 2.0f;
g2.drawLine( 0, (int)middle, width, (int)middle );
if( mSamples != null && mSamples.size() > 0 )
{
g2.setColor( getForeground() );
g2.drawString( mLabel, 5 , 15 );
for( int x = 1; x < mSamples.size(); x++ )
{
paintDibit( g, x, mSamples.get( x ) );
}
}
g2.dispose();
}
/**
* Paints a polyline representing a boolean value with a 0 or 1 label in
* the middle of it
*
* @param graphics
* @param index - index of the sample int the sample buffer
* @param value - bit value, 0 or 1
*/
private void paintDibit( Graphics graphics, int index, Dibit value )
{
Graphics2D g2 = (Graphics2D)graphics;
Path2D.Float polyline =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
float middleY = ( (float)getHeight() / 2.0f );
float indexWidth = (float)( getWidth() ) / (float)mSampleCount;
float startX = (float)index * indexWidth;
float stopX = (float)(index + 1 ) * indexWidth;
float fivePercent = indexWidth * .05f;
float leftX = startX + fivePercent;
float rightX = stopX - fivePercent;
/* Start */
polyline.moveTo( startX, middleY );
/* Left horizonal segment */
polyline.lineTo( leftX, middleY );
float y = middleY;
switch( value )
{
case D01_PLUS_3:
y = middleY - ( middleY * 0.75f);
break;
case D00_PLUS_1:
y = middleY - ( middleY * 0.25f);
break;
case D10_MINUS_1:
y = middleY + ( middleY * 0.25f);
break;
case D11_MINUS_3:
y = middleY + ( middleY * 0.75f);
break;
}
/* Left vertical segment */
polyline.lineTo( leftX, y );
/* Middle horizontal segment */
polyline.lineTo( rightX, y );
/* Right vertical segment */
polyline.lineTo( rightX, middleY );
/* Right horizontal segment */
polyline.lineTo( stopX, middleY );
g2.draw( polyline );
/* Draw the bit value label */
String bit = null;
switch( value )
{
case D00_PLUS_1:
bit = "+1";
break;
case D01_PLUS_3:
bit = "+3";
break;
case D10_MINUS_1:
bit = "-1";
break;
case D11_MINUS_3:
bit = "-3";
break;
}
FontMetrics fontMetrics = graphics.getFontMetrics( this.getFont() );
Rectangle2D label = fontMetrics.getStringBounds( bit, graphics );
float offsetX = (float)label.getWidth() / 2.0f;
float offsetY = (float)label.getWidth() / 2.0f;
float middleX = startX + ( indexWidth / 2.0f );
graphics.drawString( bit,
(int)( middleX - offsetX ),
(int)( middleY - offsetY ) );
}
}

View File

@@ -1,46 +0,0 @@
package io.github.dsheirer.instrument.tap.stream;
public class EyeDiagramData
{
private float[] mSamplesInphase;
private float[] mSamplesQuadrature;
private float mLeftPoint;
private float mRightPoint;
private float mError;
public EyeDiagramData( float[] samplesInphase, float[] samplesQuadrature,
float leftPoint, float rightPoint, float error )
{
mSamplesInphase = samplesInphase;
mSamplesQuadrature = samplesQuadrature;
mLeftPoint = leftPoint;
mRightPoint = rightPoint;
mError = error;
}
public float[] getInphaseSamples()
{
return mSamplesInphase;
}
public float[] getQuadratureSamples()
{
return mSamplesQuadrature;
}
public float getLeftPoint()
{
return mLeftPoint;
}
public float getRightPoint()
{
return mRightPoint;
}
public float getError()
{
return mError;
}
}

View File

@@ -1,60 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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.instrument.tap.stream;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
import io.github.dsheirer.sample.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EyeDiagramDataTap extends StreamTap implements Listener<EyeDiagramData>
{
private final static Logger mLog = LoggerFactory.getLogger( EyeDiagramDataTap.class );
private Listener<EyeDiagramData> mListener;
public EyeDiagramDataTap( String name, int delay, float sampleRate )
{
super( TapType.STREAM_EYE_DIAGRAM, name, delay, sampleRate );
}
@Override
public void receive( EyeDiagramData data )
{
if( mListener != null )
{
mListener.receive( data );
}
for( TapListener listener: mListeners )
{
listener.receive( data );
}
}
public void setListener( Listener<EyeDiagramData> listener )
{
mListener = listener;
}
public void removeListener( Listener<EyeDiagramData> listener )
{
mListener = null;
}
}

View File

@@ -1,221 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import io.github.dsheirer.sample.complex.Complex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.util.List;
import java.util.Observable;
public class EyeDiagramDataTapPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( EyeDiagramDataTapPanel.class );
private EyeDiagramDataTap mTap;
private List<EyeDiagramData> mSamples;
public EyeDiagramDataTapPanel( EyeDiagramDataTap tap )
{
super( new SampleModel<EyeDiagramData>(), tap.getName() );
mTap = tap;
mTap.addListener( getModel() );
getModel().setSampleCount( 15 );
getModel().setDelay( tap.getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<EyeDiagramData>)getModel().getSamples();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
float third = getWidth() / 3.0f;
float two_thirds = 2.0f * third;
float halfHeight = getHeight() / 2.0f;
float xAxisIncrement = third / 20.0f;
if( mSamples != null && mSamples.size() > 0 )
{
/* Draw each of the sample sets */
for( int z = 0; z < mSamples.size(); z++ )
{
if( z == mSamples.size() - 1 )
{
g2.setColor( Color.BLUE );
}
else if( z > ( mSamples.size() * .75 ) )
{
g2.setColor( Color.DARK_GRAY );
}
else
{
g2.setColor( Color.LIGHT_GRAY );
}
EyeDiagramData data = mSamples.get( z );
float[] inphaseSamples = data.getInphaseSamples();
float[] quadratureSamples = data.getQuadratureSamples();
/* Draw the sample set containing two symbol periods of data */
if( inphaseSamples.length >= 1 )
{
Path2D.Float iLine = new Path2D.Float( GeneralPath.WIND_EVEN_ODD, 20 );
Path2D.Float qLine = new Path2D.Float( GeneralPath.WIND_EVEN_ODD, 20 );
Path2D.Float mLine = new Path2D.Float( GeneralPath.WIND_EVEN_ODD, 20 );
float xAxis = 0;
iLine.moveTo( xAxis, getSampleHeight( halfHeight, inphaseSamples[ 0 ] ) );
qLine.moveTo( xAxis + third, getSampleHeight( halfHeight, quadratureSamples[ 0 ] ) );
mLine.moveTo( xAxis + ( two_thirds ), getMagnitudeHeight( Complex.magnitude( inphaseSamples[ 0 ], quadratureSamples[ 0 ] ) ) );
for( int x = 1; x < inphaseSamples.length; x++ )
{
xAxis += xAxisIncrement;
iLine.lineTo( xAxis, getSampleHeight( halfHeight, inphaseSamples[ x ] ) );
qLine.lineTo( xAxis + third, getSampleHeight( halfHeight, quadratureSamples[ x ] ) );
mLine.lineTo( xAxis + two_thirds, getMagnitudeHeight( Complex.magnitude( inphaseSamples[ x ], quadratureSamples[ x ] ) ) );
}
g2.draw( iLine );
g2.draw( qLine );
g2.draw( mLine );
/* Left Sample line */
if( z == mSamples.size() - 1 )
{
g2.setColor( Color.GREEN );
}
else
{
g2.setColor( Color.LIGHT_GRAY );
}
xAxis = xAxisIncrement * data.getLeftPoint();
g2.drawLine( (int)xAxis, 5, (int)xAxis, getHeight() - 5 );
g2.drawLine( (int)( xAxis + third ), 5, (int)( xAxis + third ), getHeight() - 5 );
g2.drawLine( (int)( xAxis + two_thirds ), 5, (int)( xAxis + two_thirds ), getHeight() - 5 );
/* Right Sample line */
if( z == mSamples.size() - 1 )
{
g2.setColor( Color.GREEN );
}
else
{
g2.setColor( Color.LIGHT_GRAY );
}
xAxis = xAxisIncrement * data.getRightPoint();
g2.drawLine( (int)xAxis, 5, (int)xAxis, getHeight() - 5 );
g2.drawLine( (int)( xAxis + third ), 5, (int)( xAxis + third ), getHeight() - 5 );
g2.drawLine( (int)( xAxis + two_thirds ), 5, (int)( xAxis + two_thirds ), getHeight() - 5 );
/* Error indicator */
float error = data.getError();
if( z == mSamples.size() - 1 )
{
g2.setColor( Color.BLACK );
float xFrom;
float xTo;
if( error < 0.0f )
{
xFrom = (int)( xAxisIncrement * data.getLeftPoint() );
xTo = xFrom - 25.0f;
}
else
{
xFrom = (int)( xAxisIncrement * data.getRightPoint() );
xTo = xFrom + 25.0f;
}
g2.drawLine( (int)xFrom, (int)halfHeight - 15, (int)xTo, (int)halfHeight );
g2.drawLine( (int)xFrom, (int)halfHeight + 15, (int)xTo, (int)halfHeight );
g2.drawLine( (int)( xFrom + third ), (int)halfHeight - 15, (int)( xTo + third ), (int)halfHeight );
g2.drawLine( (int)( xFrom + third ), (int)halfHeight + 15, (int)( xTo + third ), (int)halfHeight );
g2.drawLine( (int)( xFrom + two_thirds ), (int)halfHeight - 15, (int)( xTo + two_thirds ), (int)halfHeight );
g2.drawLine( (int)( xFrom + two_thirds ), (int)halfHeight + 15, (int)( xTo + two_thirds ), (int)halfHeight );
}
}
}
}
g2.setColor( Color.BLUE );
g2.drawString( "Eye Diagram - I Leg", 5, 15 );
g2.drawString( "Eye Diagram - Q Leg", third, 15 );
g2.drawString( "Eye Diagram - Magnitude", two_thirds, 15 );
/* Horizontal middle line */
g2.setColor( Color.CYAN );
g2.drawLine( 0, (int)halfHeight, getWidth(), (int)halfHeight );
g2.dispose();
}
private float getSampleHeight( float halfHeight, float value )
{
if( value > 1.0 )
{
value = 1.0f;
}
if( value < -1.0 )
{
value = -1.0f;
}
return halfHeight + ( .95f * ( halfHeight * value ) );
}
private float getMagnitudeHeight( float magnitude )
{
if( magnitude > 1.0 )
{
magnitude = 1.0f;
}
return getHeight() - ( getHeight() * magnitude );
}
}

View File

@@ -1,43 +0,0 @@
package io.github.dsheirer.instrument.tap.stream;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.real.RealBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FloatBufferTap extends FloatTap implements Listener<RealBuffer>
{
private final static Logger mLog =
LoggerFactory.getLogger( FloatBufferTap.class );
private Listener<RealBuffer> mRealBufferListener;
public FloatBufferTap( String name, int delay, float sampleRateRatio )
{
super( name, delay, sampleRateRatio );
}
@Override
public void receive( RealBuffer buffer )
{
if( mRealBufferListener != null )
{
mRealBufferListener.receive( buffer );
}
for( float sample: buffer.getSamples() )
{
super.receive( sample );
}
}
public void setListener( Listener<RealBuffer> listener )
{
mRealBufferListener = listener;
}
public void removeListener( Listener<RealBuffer> listener )
{
mRealBufferListener = null;
}
}

View File

@@ -1,58 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
import io.github.dsheirer.sample.real.RealSampleListener;
public class FloatTap extends StreamTap implements RealSampleListener
{
private RealSampleListener mFloatTapListener;
public FloatTap( String name,
int delay,
float sampleRateRatio )
{
super( TapType.STREAM_FLOAT, name, delay, sampleRateRatio );
}
@Override
public void receive( float sample )
{
if( mFloatTapListener != null )
{
mFloatTapListener.receive( sample );
}
for( TapListener listener: mListeners )
{
listener.receive( sample );
}
}
public void setListener( RealSampleListener listener )
{
mFloatTapListener = listener;
}
public void removeListener( RealSampleListener listener )
{
mFloatTapListener = null;
}
}

View File

@@ -1,129 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.List;
import java.util.Observable;
public class FloatTapPhaseViewPanel extends TapViewPanel
{
private final static Logger mLog =
LoggerFactory.getLogger( FloatTapPhaseViewPanel.class );
private static final long serialVersionUID = 1L;
private Tap mTap;
private List<Float> mSamples;
private int mSampleCount;
public FloatTapPhaseViewPanel( FloatTap tap )
{
super( new SampleModel<Float>(), tap.getName() );
mTap = tap;
mTap.addListener( getModel() );
mSampleCount = (int)( 2000 * tap.getSampleRateRatio() );
getModel().setSampleCount( mSampleCount );
getModel().setDelay( tap.getDelay() );
mLog.info( "Float Tap Panel [" + tap.getName() + "] count: " +
getModel().getSampleCount() + " delay:" + getModel().getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<Float>)getModel().getSamples();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int height = getHeight();
int width = getWidth();
g2.setColor( Color.DARK_GRAY );
float middle = (float)height / 2.0f;
g2.drawLine( 0, (int)middle, width, (int)middle );
if( mSamples != null &&
mSamples.size() > 0 )
{
g2.setColor( getForeground() );
g2.drawString( mLabel, 5 , 15 );
Path2D.Float polyline =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
/* Move to the first point */
Point2D.Float first = resolve( 0, mSamples.get( 0 ) );
polyline.moveTo( first.x, first.y );
for( int x = 1; x < mSamples.size(); x++ )
{
Point2D.Float point = resolve( x, mSamples.get( x ) );
polyline.lineTo( point.x, point.y );
}
g2.draw(polyline);
}
g2.dispose();
}
private Point2D.Float resolve( int index, float value )
{
int middle = (int)( getHeight() / 2 );
double scaledValue = Math.asin( value );
float y = middle - (float)( middle * scaledValue * mVerticalZoom );
/* Clip y to zero as necessary */
y = ( y < 0 ) ? 0 : y;
/* Clip y to max height as necessary */
y = ( y > getHeight() ) ? getHeight() : y;
float indexWidth = (float)getWidth() / (float)mSampleCount;
float x = (float)index * indexWidth;
Point2D.Float point = new Point2D.Float( x, y );
return new Point2D.Float( x , y );
}
}

View File

@@ -1,127 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.gui.SDRTrunk;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.List;
import java.util.Observable;
public class FloatTapViewPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( SDRTrunk.class );
private Tap mTap;
private List<Float> mSamples;
private int mSampleCount;
public FloatTapViewPanel( FloatTap tap )
{
super( new SampleModel<Float>(), tap.getName() );
mTap = tap;
mTap.addListener( getModel() );
mSampleCount = (int)( 2000 * tap.getSampleRateRatio() );
getModel().setSampleCount( mSampleCount );
getModel().setDelay( tap.getDelay() );
mLog.info( "Float Tap Panel [" + tap.getName() + "] count: " +
getModel().getSampleCount() + " delay:" + getModel().getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<Float>)getModel().getSamples();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int height = getHeight();
int width = getWidth();
g2.setColor( Color.DARK_GRAY );
float middle = (float)height / 2.0f;
g2.drawLine( 0, (int)middle, width, (int)middle );
if( mSamples != null &&
mSamples.size() > 0 )
{
g2.setColor( getForeground() );
g2.drawString( mLabel, 5 , 15 );
Path2D.Float polyline =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
/* Move to the first point */
Point2D.Float first = resolve( 0, mSamples.get( 0 ) );
polyline.moveTo( first.x, first.y );
for( int x = 1; x < mSamples.size(); x++ )
{
Point2D.Float point = resolve( x, mSamples.get( x ) );
polyline.lineTo( point.x, point.y );
}
g2.draw(polyline);
}
g2.dispose();
}
private Point2D.Float resolve( int index, float value )
{
int middle = (int)( getHeight() / 2 );
float y = middle - ( middle * value * mVerticalZoom );
/* Clip y to zero as necessary */
y = ( y < 0 ) ? 0 : y;
/* Clip y to max height as necessary */
y = ( y > getHeight() ) ? getHeight() : y;
float indexWidth = (float)getWidth() / (float)mSampleCount;
float x = (float)index * indexWidth;
Point2D.Float point = new Point2D.Float( x, y );
return new Point2D.Float( x , y );
}
}

View File

@@ -1,40 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
public class GainFloatTap extends FloatTap
{
private float mGain;
public GainFloatTap( String name,
int delay,
float sampleRateRatio,
float gain )
{
super( name, delay, sampleRateRatio );
mGain = gain;
}
@Override
public void receive( float sample )
{
super.receive( sample * mGain );
}
}

View File

@@ -1,11 +0,0 @@
package io.github.dsheirer.instrument.tap.stream;
import io.github.dsheirer.instrument.tap.TapType;
public class QPSKTap extends ComplexTap
{
public QPSKTap( String name, int delay, float sampleRateRatio )
{
super( TapType.STREAM_QPSK, name, delay, sampleRateRatio );
}
}

View File

@@ -1,157 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.gui.SDRTrunk;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import io.github.dsheirer.sample.complex.Complex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.util.List;
import java.util.Observable;
public class QPSKTapPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( SDRTrunk.class );
private Tap mTap;
private List<Complex> mSamples;
private int mSampleCount;
public QPSKTapPanel( ComplexTap tap )
{
super( new SampleModel<ComplexTap>(), tap.getName() );
mTap = tap;
mTap.addListener( getModel() );
mSampleCount = (int)( 60 * tap.getSampleRateRatio() );
getModel().setSampleCount( mSampleCount );
getModel().setDelay( tap.getDelay() );
mLog.info( "Complex Tap Panel [" + tap.getName() + "] count: " +
getModel().getSampleCount() + " delay:" + getModel().getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<Complex>)getModel().getSamples();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int min = ( getHeight() < getWidth() ? getHeight() : getWidth() );
float middle = (float)min / 2.0f;
g2.setColor( Color.DARK_GRAY );
/* Vertical Line */
g2.drawLine( getWidth() / 2, 5, getWidth() / 2, getHeight() - 5 );
/* Horizontal Line */
g2.drawLine( getWidth() / 2 - (int)( middle ), getHeight() / 2,
getWidth() / 2 + (int)( middle ), getHeight() / 2 );
g2.setColor( Color.CYAN );
/* Crossed Lines */
g2.drawLine( getWidth() / 2 - (int)( middle ), 5,
getWidth() / 2 + (int)( middle ), getHeight() - 5 );
g2.drawLine( getWidth() / 2 + (int)( middle ), 5,
getWidth() / 2 - (int)( middle ), getHeight() - 5 );
if( mSamples != null &&
mSamples.size() > 0 )
{
g2.drawString( mLabel, 5 , 15 );
/* Set color to light gray for oldest 90% of constellations */
g2.setColor( Color.LIGHT_GRAY );
int counter = 0;
int threshold = (int)( mSamples.size() * 0.9f );
for( Complex sample: mSamples )
{
/* Set color to foreground for newest 10% of constellations */
if( counter == threshold )
{
g2.setColor( getForeground() );
}
// float scale;
//
// if( sample.real() != 0 && sample.imaginary() != 0 )
// {
// scale = 1.0f / sample.magnitude();
// }
// else if( sample.real() == 0 )
// {
// scale = 1.0f / sample.imaginary();
// }
// else
// {
// scale = 1.0f / sample.real();
// }
// float x = ( getWidth() / 2 ) +
// ( scale * sample.real() * middle * 0.75f * mVerticalZoom );
float x = ( getWidth() / 2 ) +
( sample.real() * middle * 0.75f * mVerticalZoom );
if( Float.isNaN( x ) )
{
x = getWidth() / 2;
}
// float y = ( getHeight() / 2 ) +
// ( scale * sample.imaginary() * middle * 0.75f * mVerticalZoom );
float y = ( getHeight() / 2 ) +
( sample.imaginary() * middle * 0.75f * mVerticalZoom );
if( Float.isNaN( y ) )
{
y = getHeight() / 2;
}
g2.draw( new Ellipse2D.Float( x, y, 4.0f, 4.0f ) );
counter++;
}
}
g2.dispose();
}
}

View File

@@ -1,41 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.instrument.tap.Tap;
import io.github.dsheirer.instrument.tap.TapType;
public abstract class StreamTap extends Tap
{
protected float mSampleRateRatio;
public StreamTap( TapType type,
String name,
int delay,
float sampleRate )
{
super( type, name, delay );
mSampleRateRatio = sampleRate;
}
public float getSampleRateRatio()
{
return mSampleRateRatio;
}
}

View File

@@ -1,58 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.dsp.symbol.SymbolEvent;
import io.github.dsheirer.instrument.tap.TapListener;
import io.github.dsheirer.instrument.tap.TapType;
import io.github.dsheirer.sample.Listener;
public class SymbolEventTap extends StreamTap implements Listener<SymbolEvent>
{
private Listener<SymbolEvent> mListener;
public SymbolEventTap( String name, int delay, float sampleRate )
{
super( TapType.STREAM_SYMBOL, name, delay, sampleRate );
}
@Override
public void receive( SymbolEvent symbolEvent )
{
if( mListener != null )
{
mListener.receive( symbolEvent );
}
for( TapListener listener: mListeners )
{
listener.receive( symbolEvent );
}
}
public void setListener( Listener<SymbolEvent> listener )
{
mListener = listener;
}
public void removeListener( Listener<SymbolEvent> listener )
{
mListener = null;
}
}

View File

@@ -1,187 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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.instrument.tap.stream;
import io.github.dsheirer.dsp.symbol.SymbolEvent;
import io.github.dsheirer.instrument.gui.SampleModel;
import io.github.dsheirer.instrument.tap.TapViewPanel;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Observable;
public class SymbolEventTapViewPanel extends TapViewPanel
{
private static final long serialVersionUID = 1L;
private SymbolEventTap mTap;
private List<SymbolEvent> mSamples;
private int mSampleCount;
public SymbolEventTapViewPanel( SymbolEventTap tap )
{
super( new SampleModel<SymbolEvent>(), tap.getName() );
mTap = tap;
mTap.addListener( getModel() );
mSampleCount = (int)( getModel().getSampleCount() * tap.getSampleRateRatio() );
getModel().setSampleCount( mSampleCount );
getModel().setDelay( tap.getDelay() );
}
@Override
public void update( Observable arg0, Object arg1 )
{
mSamples = (List<SymbolEvent>)getModel().getSamples();
repaint();
}
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D)g;
int height = getHeight();
int width = getWidth();
g2.setColor( Color.DARK_GRAY );
float middle = (float)height / 2.0f;
g2.drawLine( 0, (int)middle, width, (int)middle );
if( mSamples != null && mSamples.size() > 0 )
{
g2.setColor( getForeground() );
g2.drawString( mLabel, 5 , 15 );
for( int x = 1; x < mSamples.size(); x++ )
{
paint( g, x, mSamples.get( x ) );
}
}
g2.dispose();
}
/**
* Paints a polyline representing a boolean value with a 0 or 1 label in
* the middle of it
*
* @param graphics
* @param index - index of the sample int the sample buffer
* @param value - bit value, 0 or 1
*/
private void paint( Graphics graphics, int index, SymbolEvent symbol )
{
Graphics2D g2 = (Graphics2D)graphics;
g2.setColor( getForeground() );
Path2D.Float polyline =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
float middleY = ( (float)getHeight() / 2.0f );
float indexWidth = (float)( getWidth() ) / (float)mSampleCount;
float startX = (float)index * indexWidth;
float stopX = (float)(index + 1 ) * indexWidth;
float fivePercent = indexWidth * .05f;
float leftX = startX + fivePercent;
float rightX = stopX - fivePercent;
/* Start */
polyline.moveTo( startX, middleY );
/* Left horizonal segment */
polyline.lineTo( leftX, middleY );
float y = ( symbol.getDecision() ? ( middleY - ( middleY * 0.5f) ) :
( middleY + ( middleY * 0.5f) ) );
/* Left vertical segment */
polyline.lineTo( leftX, y );
/* Middle horizontal segment */
polyline.lineTo( rightX, y );
/* Right vertical segment */
polyline.lineTo( rightX, middleY );
/* Right horizontal segment */
polyline.lineTo( stopX, middleY );
g2.draw( polyline );
/* Draw the bit value label */
String bit = symbol.getDecision() ? "1" : "0";
FontMetrics fontMetrics = graphics.getFontMetrics( this.getFont() );
Rectangle2D label = fontMetrics.getStringBounds( bit, graphics );
float offsetX = (float)label.getWidth() / 2.0f;
float offsetY = (float)label.getHeight() / 2.0f;
float middleX = startX + ( indexWidth / 2.0f );
graphics.drawString( bit,
(int)( middleX - offsetX ),
(int)( middleY - ( ( middleY < y ) ? offsetY : -( 2.0f * offsetY ) ) ) );
/* Draw samples */
float sampleWidth = ( rightX - leftX ) / (float)( symbol.getSamplesPerSymbol() + 1 );
g2.setColor( Color.GREEN );
for( int x = 0; x < symbol.getSamplesPerSymbol(); x++ )
{
Path2D.Float line =
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, 2 );
float sampleX = leftX + ( ( x + 1 ) * sampleWidth );
// line.moveTo( sampleX, middleY );
line.moveTo( sampleX, ( symbol.getBitSet().get( x ) ?
middleY - ( middleY * .05f ) :
middleY + ( middleY * .05f ) ) );
float sampleY = ( symbol.getBitSet().get( x ) ?
( middleY - ( middleY * 0.45f ) ) :
( middleY + ( middleY * 0.45f ) ) );
line.lineTo( sampleX, sampleY );
g2.draw( line );
graphics.drawString( symbol.getShift().getLabel(),
(int)( middleX - offsetX ),
(int)( y - ( ( y < middleY ) ? offsetY : -( 2.0f * offsetY ) ) ) );
}
}
}

View File

@@ -16,7 +16,7 @@
package io.github.dsheirer.module.decode.fleetsync2;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.instrument.gui.viewer.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import javafx.beans.property.SimpleIntegerProperty;

View File

@@ -16,7 +16,7 @@
package io.github.dsheirer.module.decode.lj1200;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.instrument.gui.viewer.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import javafx.beans.property.SimpleIntegerProperty;

View File

@@ -16,7 +16,7 @@
package io.github.dsheirer.module.decode.mdc1200;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.instrument.gui.viewer.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import javafx.beans.property.SimpleIntegerProperty;

View File

@@ -16,7 +16,7 @@
package io.github.dsheirer.module.decode.mpt1327;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.instrument.gui.viewer.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import javafx.beans.property.SimpleIntegerProperty;

View File

@@ -1,253 +0,0 @@
/*******************************************************************************
* 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

@@ -1,11 +1,6 @@
package io.github.dsheirer.module.decode.p25;
import io.github.dsheirer.dsp.gain.DirectGainControl;
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.AdditiveFloatTap;
import io.github.dsheirer.instrument.tap.stream.FloatTap;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.real.RealBuffer;
import io.github.dsheirer.sample.real.RealSampleListener;
@@ -13,10 +8,7 @@ import io.github.dsheirer.sample.real.RealSampleProvider;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.SourceEvent;
import java.util.ArrayList;
import java.util.List;
public class C4FMSymbolFilter implements Listener<RealBuffer>, ISourceEventListener, RealSampleProvider, Instrumentable
public class C4FMSymbolFilter implements Listener<RealBuffer>, ISourceEventListener, RealSampleProvider
{
private static final float TAPS[][] =
{
@@ -151,11 +143,6 @@ public class C4FMSymbolFilter implements Listener<RealBuffer>, ISourceEventListe
{0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 1.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f}, // 128/128
};
/* Instrumentation Taps */
private static final String INSTRUMENT_SYMBOL_SPREAD = "Tap Point: Symbol Spread (Goal=2.0)";
private FloatTap mSymbolSpreadTap;
private List<TapGroup> mAvailableTaps;
private static final int NUMBER_FILTER_TAPS = 8;
private static final int NUMBER_FILTER_STEPS = 128;
@@ -379,11 +366,6 @@ public class C4FMSymbolFilter implements Listener<RealBuffer>, ISourceEventListe
500 * (mCoarseFrequencyCorrection > 0 ? 1 : -1);
}
if(mSymbolSpreadTap != null)
{
mSymbolSpreadTap.receive(mSymbolSpread);
}
/* dispatch the interpolated value to the listener */
if(mListener != null)
{
@@ -404,46 +386,6 @@ public class C4FMSymbolFilter implements Listener<RealBuffer>, ISourceEventListe
mListener = null;
}
@Override
public List<TapGroup> getTapGroups()
{
if(mAvailableTaps == null)
{
mAvailableTaps = new ArrayList<>();
/*
* Since the target is 2.0, we subtract 2.0 from the value so that
* a good value is plotted right on the zero center line
*/
TapGroup group = new TapGroup("C4FM Symbol Filter");
group.add(
new AdditiveFloatTap(INSTRUMENT_SYMBOL_SPREAD, 0, 0.1f, -2.0f));
mAvailableTaps.add(group);
}
return mAvailableTaps;
}
@Override
public void registerTap(Tap tap)
{
if(tap.getName().contentEquals(INSTRUMENT_SYMBOL_SPREAD))
{
mSymbolSpreadTap = (FloatTap)tap;
}
}
@Override
public void unregisterTap(Tap tap)
{
if(tap.getName().contentEquals(INSTRUMENT_SYMBOL_SPREAD))
{
mSymbolSpreadTap = null;
}
}
/**
* Broadcasts a frequency change event to the registered listener
*

View File

@@ -16,7 +16,7 @@
package io.github.dsheirer.module.decode.tait;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.instrument.gui.viewer.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import javafx.beans.property.SimpleIntegerProperty;