diff --git a/src/audio/AudioModule.java b/src/audio/AudioModule.java index 58b0be0f..f1cdf38f 100644 --- a/src/audio/AudioModule.java +++ b/src/audio/AudioModule.java @@ -117,7 +117,7 @@ public class AudioModule extends Module implements IAudioPacketProvider, IFilter } @Override - public void start(ScheduledExecutorService executor) + public void start() { /* No start operations provided */ } diff --git a/src/channel/state/AlwaysUnsquelchedDecoderState.java b/src/channel/state/AlwaysUnsquelchedDecoderState.java index ef6a0db0..b2a67cc9 100644 --- a/src/channel/state/AlwaysUnsquelchedDecoderState.java +++ b/src/channel/state/AlwaysUnsquelchedDecoderState.java @@ -47,11 +47,6 @@ public class AlwaysUnsquelchedDecoderState extends DecoderState mChannelName = channelName; } - @Override - public void init() - { - } - @Override public void reset() { @@ -94,14 +89,9 @@ public class AlwaysUnsquelchedDecoderState extends DecoderState } @Override - public void start(ScheduledExecutorService executor) + public void start() { broadcast(new AttributeChangeRequest(Attribute.PRIMARY_ADDRESS_TO, mChannelName)); broadcast(new DecoderStateEvent(this, Event.ALWAYS_UNSQUELCH, State.IDLE)); } - - @Override - public void stop() - { - } } diff --git a/src/channel/state/ChannelState.java b/src/channel/state/ChannelState.java index 01fc6175..3bb4d00b 100644 --- a/src/channel/state/ChannelState.java +++ b/src/channel/state/ChannelState.java @@ -20,8 +20,8 @@ package channel.state; import audio.squelch.ISquelchStateProvider; import audio.squelch.SquelchState; -import channel.heartbeat.Heartbeat; -import channel.heartbeat.IHeartbeatListener; +import source.heartbeat.Heartbeat; +import source.heartbeat.IHeartbeatListener; import channel.metadata.Attribute; import channel.metadata.AttributeChangeRequest; import channel.metadata.IAttributeChangeRequestListener; @@ -124,7 +124,7 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder } @Override - public void start(ScheduledExecutorService executor) + public void start() { mMutableMetadata.receive(new AttributeChangeRequest(Attribute.CHANNEL_STATE, mState)); diff --git a/src/channel/state/DecoderState.java b/src/channel/state/DecoderState.java index 4e68bb8f..707f0241 100644 --- a/src/channel/state/DecoderState.java +++ b/src/channel/state/DecoderState.java @@ -71,7 +71,20 @@ public abstract class DecoderState extends Module implements ActivitySummaryProv /** * Allow the decoder to perform any setup actions */ - public abstract void init(); + public void init() + { + + } + + @Override + public void start() + { + } + + @Override + public void stop() + { + } /** * Implements the IDecoderStateEventListener interface to receive state diff --git a/src/channel/traffic/TrafficChannelManager.java b/src/channel/traffic/TrafficChannelManager.java index d7fac5a2..f01bc492 100644 --- a/src/channel/traffic/TrafficChannelManager.java +++ b/src/channel/traffic/TrafficChannelManager.java @@ -36,7 +36,7 @@ import org.slf4j.LoggerFactory; import record.config.RecordConfiguration; import sample.Listener; import source.config.SourceConfigTuner; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; import java.util.ArrayList; import java.util.List; @@ -330,7 +330,7 @@ public class TrafficChannelManager extends Module implements ICallEventProvider, } @Override - public void start(ScheduledExecutorService executor) + public void start() { } diff --git a/src/controller/channel/Channel.java b/src/controller/channel/Channel.java index b3e49224..c099b517 100644 --- a/src/controller/channel/Channel.java +++ b/src/controller/channel/Channel.java @@ -33,7 +33,7 @@ import source.config.SourceConfigFactory; import source.config.SourceConfigRecording; import source.config.SourceConfigTuner; import source.config.SourceConfiguration; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; import source.SourceEvent; import source.SourceEvent.Event; diff --git a/src/dsp/filter/channelizer/ChannelCalculator.java b/src/dsp/filter/channelizer/ChannelCalculator.java index bf98e1ea..0f80483b 100644 --- a/src/dsp/filter/channelizer/ChannelCalculator.java +++ b/src/dsp/filter/channelizer/ChannelCalculator.java @@ -20,7 +20,7 @@ package dsp.filter.channelizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; import java.text.DecimalFormat; import java.util.ArrayList; diff --git a/src/dsp/filter/channelizer/ChannelizerViewer.java b/src/dsp/filter/channelizer/ChannelizerViewer.java index 8afc76b6..91db8580 100644 --- a/src/dsp/filter/channelizer/ChannelizerViewer.java +++ b/src/dsp/filter/channelizer/ChannelizerViewer.java @@ -28,7 +28,8 @@ import settings.SettingsManager; import source.ISourceEventProcessor; import source.SourceEvent; import source.SourceException; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; import source.tuner.configuration.TunerConfigurationModel; import source.tuner.test.TestTuner; import spectrum.DFTProcessor; @@ -70,12 +71,12 @@ public class ChannelizerViewer extends JFrame { mTestTuner = new TestTuner(); - mChannelCount = mTestTuner.getSampleRate() / CHANNEL_BANDWIDTH; + mChannelCount = mTestTuner.getTunerController().getSampleRate() / CHANNEL_BANDWIDTH; mChannelsPerRow = channelsPerRow; mToneFrequency = mTestTuner.getTunerController().getFrequency() + 19200; - mTestTuner.setToneFrequency(mToneFrequency); + mTestTuner.getTunerController().setToneFrequency(mToneFrequency); init(); } @@ -108,10 +109,11 @@ public class ChannelizerViewer extends JFrame { if(mPrimarySpectrumPanel == null) { - mPrimarySpectrumPanel = new PrimarySpectrumPanel(mSettingsManager, mTestTuner.getSampleRate()); + mPrimarySpectrumPanel = new PrimarySpectrumPanel(mSettingsManager, + mTestTuner.getTunerController().getSampleRate()); mPrimarySpectrumPanel.setPreferredSize(new Dimension(1000, 200)); mPrimarySpectrumPanel.setDFTSize(mMainPanelDFTSize); - mTestTuner.addListener(mPrimarySpectrumPanel); + mTestTuner.getSourceManager().addComplexBufferListener(mPrimarySpectrumPanel); } return mPrimarySpectrumPanel; @@ -125,7 +127,7 @@ public class ChannelizerViewer extends JFrame mControlPanel.setLayout(new MigLayout("insets 0 0 0 0", "", "")); mControlPanel.add(new JLabel("Tone:"), "align left"); - int maximumFrequencyOffset = mTestTuner.getSampleRate() / 2; + int maximumFrequencyOffset = mTestTuner.getTunerController().getSampleRate() / 2; long minimumFrequency = mTestTuner.getTunerController().getFrequency() - maximumFrequencyOffset; long maximumFrequency = mTestTuner.getTunerController().getFrequency() + maximumFrequencyOffset; @@ -138,7 +140,7 @@ public class ChannelizerViewer extends JFrame public void stateChanged(ChangeEvent e) { int toneFrequency = model.getNumber().intValue(); - mTestTuner.setToneFrequency(toneFrequency); + mTestTuner.getTunerController().setToneFrequency(toneFrequency); } }); @@ -147,9 +149,9 @@ public class ChannelizerViewer extends JFrame mControlPanel.add(spinner); mControlPanel.add(new JLabel("Hz")); - mControlPanel.add(new JLabel("Sample Rate: " + mTestTuner.getSampleRate() + " Hz"), "push,align right"); + mControlPanel.add(new JLabel("Sample Rate: " + mTestTuner.getTunerController().getSampleRate() + " Hz"), "push,align right"); - mControlPanel.add(new JLabel("Max: " + (mTestTuner.getSampleRate() / 2) + " Hz"), "push,align right"); + mControlPanel.add(new JLabel("Max: " + (mTestTuner.getTunerController().getSampleRate() / 2) + " Hz"), "push,align right"); mControlPanel.add(new JLabel("Channels: " + mChannelCount), "push,align right"); } @@ -183,7 +185,7 @@ public class ChannelizerViewer extends JFrame { setLayout(new MigLayout("insets 0 0 0 0", "fill", "fill")); - long spectralBandwidth = mTestTuner.getSampleRate(); + long spectralBandwidth = mTestTuner.getTunerController().getSampleRate(); long halfSpectralBandwidth = spectralBandwidth / 2; int channelToLog = -1; @@ -248,7 +250,7 @@ public class ChannelizerViewer extends JFrame public class ChannelPanel extends JPanel implements Listener, ISourceEventProcessor { - private PolyphaseChannelSource mSource; + private TunerChannelSource mSource; private DFTProcessor mDFTProcessor = new DFTProcessor(SampleType.COMPLEX); private ComplexDecibelConverter mComplexDecibelConverter = new ComplexDecibelConverter(); private SpectrumPanel mSpectrumPanel; @@ -268,7 +270,7 @@ public class ChannelizerViewer extends JFrame mFrequency = frequency; TunerChannel tunerChannel = new TunerChannel(frequency, bandwidth); - mSource = (PolyphaseChannelSource)mTestTuner.getChannelSource(tunerChannel); + mSource = mTestTuner.getSourceManager().getSource(tunerChannel); if(mSource != null) { @@ -288,7 +290,8 @@ public class ChannelizerViewer extends JFrame { mSource.setListener(mDFTProcessor); } - mSource.start(ThreadPool.SCHEDULED); + + mSource.start(); } else { @@ -296,7 +299,7 @@ public class ChannelizerViewer extends JFrame } } - public PolyphaseChannelSource getSource() + public TunerChannelSource getSource() { return mSource; } diff --git a/src/dsp/filter/channelizer/PolyphaseChannelManager.java b/src/dsp/filter/channelizer/PolyphaseChannelManager.java index b82b212d..aa95a3c3 100644 --- a/src/dsp/filter/channelizer/PolyphaseChannelManager.java +++ b/src/dsp/filter/channelizer/PolyphaseChannelManager.java @@ -25,11 +25,11 @@ import dsp.filter.design.FilterDesignException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sample.Listener; +import sample.complex.IComplexBufferProvider; import source.Source; import source.SourceEvent; import source.SourceException; -import source.tuner.Tuner; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -42,7 +42,7 @@ public class PolyphaseChannelManager implements Listener private static final int CHANNEL_SAMPLE_RATE = (int)(CHANNEL_BANDWIDTH * CHANNEL_OVERSAMPLING); private static final int POLYPHASE_FILTER_TAPS_PER_CHANNEL = 17; - private Tuner mTuner; + private IComplexBufferProvider mComplexBufferProvider; private List mChannelSources = new CopyOnWriteArrayList<>(); private ChannelCalculator mChannelCalculator; private ComplexPolyphaseChannelizerM2 mPolyphaseChannelizer; @@ -57,27 +57,29 @@ public class PolyphaseChannelManager implements Listener * active DDC polyphase channel sources accordingly. This class also monitors source event requests and * notifications received from active DDC polyphase channel sources to adjust sample streams as required. * - * @param tuner providing complex sample buffers + * Note: add this channel manager as a source event listener to the complex buffer provider to ensure this manager + * adapts to changes in source frequency and sample rate. + * + * @param complexBufferProvider that supports register/deregister of this channel manager + * @param frequency of the provided complex buffer samples + * @param sampleRate of the provided complex buffer samples */ - public PolyphaseChannelManager(Tuner tuner) + public PolyphaseChannelManager(IComplexBufferProvider complexBufferProvider, long frequency, int sampleRate) { - if(tuner == null) + if(complexBufferProvider == null) { - throw new IllegalArgumentException("Tuner argument cannot be null"); + throw new IllegalArgumentException("Complex buffer provider argument cannot be null"); } - mTuner = tuner; + mComplexBufferProvider = complexBufferProvider; - int sampleRate = mTuner.getTunerController().getSampleRate(); - - //Ensure that tuner sample rate is a multiple of channel sample rate since polyphase channelizer is M2 + //Ensure that sample rate is a multiple of channel sample rate since polyphase channelizer is M2 if(sampleRate % (CHANNEL_SAMPLE_RATE) != 0) { throw new IllegalArgumentException("Tuner sample rate [" + sampleRate + "] must be an even multiple of " + CHANNEL_SAMPLE_RATE + " Hz"); } - long frequency = mTuner.getTunerController().getFrequency(); int channelCount = sampleRate / CHANNEL_BANDWIDTH; mChannelCalculator = new ChannelCalculator(sampleRate, channelCount, frequency, CHANNEL_OVERSAMPLING); @@ -85,9 +87,6 @@ public class PolyphaseChannelManager implements Listener mBufferProcessor = new ScheduledBufferProcessor(500, 100, 50, 50); updateChannelizer(sampleRate, null); - - mTuner.addSourceEventListener(this); - } /** @@ -159,7 +158,7 @@ public class PolyphaseChannelManager implements Listener if(mPolyphaseChannelizer.getRegisteredChannelCount() == 1) { - mTuner.addListener(mBufferProcessor); + mComplexBufferProvider.addComplexBufferListener(mBufferProcessor); mBufferProcessor.start(); } } @@ -179,7 +178,7 @@ public class PolyphaseChannelManager implements Listener if(mPolyphaseChannelizer.getRegisteredChannelCount() == 0) { - mTuner.removeListener(mBufferProcessor); + mComplexBufferProvider.removeComplexBufferListener(mBufferProcessor); mBufferProcessor.stop(); } } diff --git a/src/dsp/filter/channelizer/PolyphaseChannelSource.java b/src/dsp/filter/channelizer/PolyphaseChannelSource.java index 89a7e0df..20e789fb 100644 --- a/src/dsp/filter/channelizer/PolyphaseChannelSource.java +++ b/src/dsp/filter/channelizer/PolyphaseChannelSource.java @@ -18,7 +18,7 @@ ******************************************************************************/ package dsp.filter.channelizer; -import channel.heartbeat.Heartbeat; +import source.heartbeat.Heartbeat; import dsp.filter.channelizer.output.IPolyphaseChannelOutputProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,12 +27,10 @@ import sample.complex.ComplexBuffer; import sample.complex.ComplexToComplexBufferAssembler; import source.ComplexSource; import source.ISourceEventProcessor; -import source.Source; import source.SourceEvent; import source.SourceException; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; -import java.util.Arrays; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; diff --git a/src/module/Module.java b/src/module/Module.java index a46b3e9c..e7d1fcc4 100644 --- a/src/module/Module.java +++ b/src/module/Module.java @@ -59,9 +59,9 @@ public abstract class Module public abstract void reset(); /** - * Start processing. Provides an executor to use for scheduling tasks + * Start processing. */ - public abstract void start( ScheduledExecutorService executor ); + public abstract void start(); /** * Stop processing diff --git a/src/module/ProcessingChain.java b/src/module/ProcessingChain.java index 6736aece..516d71c8 100644 --- a/src/module/ProcessingChain.java +++ b/src/module/ProcessingChain.java @@ -24,9 +24,9 @@ import audio.IAudioPacketProvider; import audio.squelch.ISquelchStateListener; import audio.squelch.ISquelchStateProvider; import audio.squelch.SquelchState; -import channel.heartbeat.Heartbeat; -import channel.heartbeat.IHeartbeatListener; -import channel.heartbeat.IHeartbeatProvider; +import source.heartbeat.Heartbeat; +import source.heartbeat.IHeartbeatListener; +import source.heartbeat.IHeartbeatProvider; import channel.metadata.AttributeChangeRequest; import channel.metadata.IAttributeChangeRequestListener; import channel.metadata.IAttributeChangeRequestProvider; @@ -454,7 +454,7 @@ public class ProcessingChain implements IChannelEventListener if(module instanceof IHeartbeatProvider) { - ((IHeartbeatProvider)module).setHeartbeatListener(mHeartbeatBroadcaster); + ((IHeartbeatProvider)module).getHeartbeatManager().addHeartbeatListener(mHeartbeatBroadcaster); } if(module instanceof IMessageProvider) @@ -521,7 +521,7 @@ public class ProcessingChain implements IChannelEventListener if(module instanceof IHeartbeatProvider) { - ((IHeartbeatProvider)module).removeHeartbeatListener(); + ((IHeartbeatProvider)module).getHeartbeatManager().removeHeartbeatListener(mHeartbeatBroadcaster); } if(module instanceof IMessageProvider) @@ -595,7 +595,7 @@ public class ProcessingChain implements IChannelEventListener { try { - module.start(ThreadPool.SCHEDULED); + module.start(); } catch(Exception e) { diff --git a/src/module/decode/Decoder.java b/src/module/decode/Decoder.java index cc6880a7..3a029035 100644 --- a/src/module/decode/Decoder.java +++ b/src/module/decode/Decoder.java @@ -1,19 +1,20 @@ /******************************************************************************* - * SDR Trunk - * Copyright (C) 2014-2016 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 + * 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 + * ******************************************************************************/ package module.decode; @@ -22,8 +23,7 @@ import message.Message; import module.Module; import sample.Listener; -public abstract class Decoder extends Module - implements IMessageProvider, Listener +public abstract class Decoder extends Module implements IMessageProvider, Listener { /* This has to be a broadcaster in order for references to persist */ protected Listener mMessageListener; @@ -82,4 +82,19 @@ public abstract class Decoder extends Module { broadcast( message ); } + + @Override + public void reset() + { + } + + @Override + public void start() + { + } + + @Override + public void stop() + { + } } diff --git a/src/module/decode/fleetsync2/Fleetsync2Decoder.java b/src/module/decode/fleetsync2/Fleetsync2Decoder.java index 5b18628b..c27d4a97 100644 --- a/src/module/decode/fleetsync2/Fleetsync2Decoder.java +++ b/src/module/decode/fleetsync2/Fleetsync2Decoder.java @@ -174,19 +174,4 @@ public class Fleetsync2Decoder extends Decoder implements IFilteredRealBufferLis { return mDecimationFilter; } - - @Override - public void reset() - { - } - - @Override - public void start( ScheduledExecutorService executor ) - { - } - - @Override - public void stop() - { - } } diff --git a/src/module/decode/fleetsync2/Fleetsync2DecoderState.java b/src/module/decode/fleetsync2/Fleetsync2DecoderState.java index e3aa69ec..d72346e1 100644 --- a/src/module/decode/fleetsync2/Fleetsync2DecoderState.java +++ b/src/module/decode/fleetsync2/Fleetsync2DecoderState.java @@ -63,27 +63,12 @@ public class Fleetsync2DecoderState extends DecoderState return DecoderType.FLEETSYNC2; } - @Override - public void start(ScheduledExecutorService executor) - { - } - - @Override - public void stop() - { - } - @Override public void dispose() { super.dispose(); } - @Override - public void init() - { - } - /** * Resets the overall decoder state and clears any accumulated event details */ diff --git a/src/module/decode/lj1200/LJ1200Decoder.java b/src/module/decode/lj1200/LJ1200Decoder.java index 3e12b544..2e936984 100644 --- a/src/module/decode/lj1200/LJ1200Decoder.java +++ b/src/module/decode/lj1200/LJ1200Decoder.java @@ -192,19 +192,4 @@ public class LJ1200Decoder extends Decoder implements IFilteredRealBufferListene { return mDecimationFilter; } - - @Override - public void reset() - { - } - - @Override - public void start( ScheduledExecutorService executor ) - { - } - - @Override - public void stop() - { - } } diff --git a/src/module/decode/lj1200/LJ1200DecoderState.java b/src/module/decode/lj1200/LJ1200DecoderState.java index 5382f034..a5cac1b8 100644 --- a/src/module/decode/lj1200/LJ1200DecoderState.java +++ b/src/module/decode/lj1200/LJ1200DecoderState.java @@ -63,16 +63,6 @@ public class LJ1200DecoderState extends DecoderState return DecoderType.LJ_1200; } - @Override - public void start(ScheduledExecutorService executor) - { - } - - @Override - public void stop() - { - } - @Override public void receive(Message message) { @@ -125,12 +115,6 @@ public class LJ1200DecoderState extends DecoderState return sb.toString(); } - @Override - public void init() - { - /* No initialization steps */ - } - @Override public void receiveDecoderStateEvent(DecoderStateEvent event) { diff --git a/src/module/decode/ltrnet/LTRNetDecoder.java b/src/module/decode/ltrnet/LTRNetDecoder.java index 5e1eecff..bf1fbcd4 100644 --- a/src/module/decode/ltrnet/LTRNetDecoder.java +++ b/src/module/decode/ltrnet/LTRNetDecoder.java @@ -120,14 +120,4 @@ public class LTRNetDecoder extends Decoder { mLTRMessageFramer.reset(); } - - @Override - public void start( ScheduledExecutorService executor ) - { - } - - @Override - public void stop() - { - } } diff --git a/src/module/decode/ltrnet/LTRNetDecoderState.java b/src/module/decode/ltrnet/LTRNetDecoderState.java index e643b558..544302bc 100644 --- a/src/module/decode/ltrnet/LTRNetDecoderState.java +++ b/src/module/decode/ltrnet/LTRNetDecoderState.java @@ -765,12 +765,6 @@ public class LTRNetDecoderState extends DecoderState } } - @Override - public void init() - { - /* No initialization steps required */ - } - @Override public void receiveDecoderStateEvent(DecoderStateEvent event) { @@ -786,14 +780,4 @@ public class LTRNetDecoderState extends DecoderState break; } } - - @Override - public void start(ScheduledExecutorService executor) - { - } - - @Override - public void stop() - { - } } diff --git a/src/module/decode/ltrstandard/LTRStandardDecoder.java b/src/module/decode/ltrstandard/LTRStandardDecoder.java index 06f0a927..40b355c5 100644 --- a/src/module/decode/ltrstandard/LTRStandardDecoder.java +++ b/src/module/decode/ltrstandard/LTRStandardDecoder.java @@ -84,14 +84,4 @@ public class LTRStandardDecoder extends Decoder implements IUnFilteredRealBuffer { mLTRMessageFramer.reset(); } - - @Override - public void start( ScheduledExecutorService executor ) - { - } - - @Override - public void stop() - { - } } diff --git a/src/module/decode/ltrstandard/LTRStandardDecoderState.java b/src/module/decode/ltrstandard/LTRStandardDecoderState.java index a826ceeb..1693b2b6 100644 --- a/src/module/decode/ltrstandard/LTRStandardDecoderState.java +++ b/src/module/decode/ltrstandard/LTRStandardDecoderState.java @@ -76,18 +76,6 @@ public class LTRStandardDecoderState extends DecoderState return DecoderType.LTR_STANDARD; } - @Override - public void start(ScheduledExecutorService executor) - { - // TODO Auto-generated method stub - - } - - @Override - public void stop() - { - } - @Override public void receive(Message message) { @@ -257,11 +245,6 @@ public class LTRStandardDecoderState extends DecoderState } } - @Override - public void init() - { - } - @Override public void receiveDecoderStateEvent(DecoderStateEvent event) { diff --git a/src/module/decode/mdc1200/MDCDecoder.java b/src/module/decode/mdc1200/MDCDecoder.java index 89f04afc..2bd89fba 100644 --- a/src/module/decode/mdc1200/MDCDecoder.java +++ b/src/module/decode/mdc1200/MDCDecoder.java @@ -202,25 +202,4 @@ public class MDCDecoder extends Decoder implements IFilteredRealBufferListener, { return mDecimationFilter; } - - @Override - public void reset() - { - // TODO Auto-generated method stub - - } - - @Override - public void start( ScheduledExecutorService executor ) - { - // TODO Auto-generated method stub - - } - - @Override - public void stop() - { - // TODO Auto-generated method stub - - } } diff --git a/src/module/decode/mdc1200/MDCDecoderState.java b/src/module/decode/mdc1200/MDCDecoderState.java index eecd0de9..a70c8f0f 100644 --- a/src/module/decode/mdc1200/MDCDecoderState.java +++ b/src/module/decode/mdc1200/MDCDecoderState.java @@ -59,16 +59,6 @@ public class MDCDecoderState extends DecoderState return DecoderType.MDC1200; } - @Override - public void start(ScheduledExecutorService executor) - { - } - - @Override - public void stop() - { - } - @Override public void reset() { @@ -245,12 +235,6 @@ public class MDCDecoderState extends DecoderState return sb.toString(); } - @Override - public void init() - { - /* No initialization required */ - } - /** * Responds to reset events issued by the channel state */ diff --git a/src/module/decode/mpt1327/MPT1327Decoder.java b/src/module/decode/mpt1327/MPT1327Decoder.java index 15163f11..228f8dc9 100644 --- a/src/module/decode/mpt1327/MPT1327Decoder.java +++ b/src/module/decode/mpt1327/MPT1327Decoder.java @@ -297,16 +297,4 @@ public class MPT1327Decoder extends Decoder implements IFilteredRealBufferListen mControlMessageFramer.reset(); mTrafficMessageFramer.reset(); } - - @Override - public void start(ScheduledExecutorService executor) - { - // TODO Auto-generated method stub - } - - @Override - public void stop() - { - // TODO Auto-generated method stub - } } diff --git a/src/module/decode/mpt1327/MPT1327DecoderState.java b/src/module/decode/mpt1327/MPT1327DecoderState.java index a70b96fa..940e1496 100644 --- a/src/module/decode/mpt1327/MPT1327DecoderState.java +++ b/src/module/decode/mpt1327/MPT1327DecoderState.java @@ -87,16 +87,6 @@ public class MPT1327DecoderState extends DecoderState return DecoderType.MPT1327; } - @Override - public void start(ScheduledExecutorService executor) - { - } - - @Override - public void stop() - { - } - public ChannelType getChannelType() { return mChannelType; @@ -501,12 +491,6 @@ public class MPT1327DecoderState extends DecoderState return sb.toString(); } - @Override - public void init() - { - /* No initialization required */ - } - @Override public void receiveDecoderStateEvent(DecoderStateEvent event) { diff --git a/src/module/decode/p25/P25DecoderState.java b/src/module/decode/p25/P25DecoderState.java index 5072bc31..2a84255b 100644 --- a/src/module/decode/p25/P25DecoderState.java +++ b/src/module/decode/p25/P25DecoderState.java @@ -221,11 +221,6 @@ public class P25DecoderState extends DecoderState return DecoderType.P25_PHASE1; } - @Override - public void stop() - { - } - /** * Performs a full reset to prepare this object for reuse on a new channel */ @@ -257,14 +252,6 @@ public class P25DecoderState extends DecoderState mCurrentCallEvent = null; } - /** - * Performs any initialization operations to prepare for use - */ - @Override - public void init() - { - } - /** * Indicates if there a call event exists for the specified channel and * from and to talkgroup identifiers. @@ -3624,7 +3611,7 @@ public class P25DecoderState extends DecoderState } @Override - public void start(ScheduledExecutorService executor) + public void start() { //Change the default (45-second) traffic channel timeout to 1 second if(mChannelType == ChannelType.TRAFFIC) diff --git a/src/module/decode/p25/P25_C4FMDecoder.java b/src/module/decode/p25/P25_C4FMDecoder.java index cbae323d..3dc771fc 100644 --- a/src/module/decode/p25/P25_C4FMDecoder.java +++ b/src/module/decode/p25/P25_C4FMDecoder.java @@ -194,27 +194,6 @@ public class P25_C4FMDecoder extends P25Decoder implements IFilteredRealBufferLi } } - @Override - public void reset() - { - // TODO Auto-generated method stub - - } - - @Override - public void start( ScheduledExecutorService executor ) - { - // TODO Auto-generated method stub - - } - - @Override - public void stop() - { - // TODO Auto-generated method stub - - } - @Override public void setSourceEventListener(Listener listener ) { diff --git a/src/module/decode/p25/P25_LSMDecoder.java b/src/module/decode/p25/P25_LSMDecoder.java index 3e30e9ae..d461cfd0 100644 --- a/src/module/decode/p25/P25_LSMDecoder.java +++ b/src/module/decode/p25/P25_LSMDecoder.java @@ -237,25 +237,4 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener tap.getName() ); } } - - @Override - public void reset() - { - // TODO Auto-generated method stub - - } - - @Override - public void start( ScheduledExecutorService executor ) - { - // TODO Auto-generated method stub - - } - - @Override - public void stop() - { - // TODO Auto-generated method stub - - } } diff --git a/src/module/decode/p25/audio/P25AudioModule.java b/src/module/decode/p25/audio/P25AudioModule.java index d6aa4c9f..c49dd2f4 100644 --- a/src/module/decode/p25/audio/P25AudioModule.java +++ b/src/module/decode/p25/audio/P25AudioModule.java @@ -71,7 +71,7 @@ public class P25AudioModule extends Module implements Listener, IAudioP } @Override - public void start(ScheduledExecutorService executor) + public void start() { } diff --git a/src/module/decode/passport/PassportDecoder.java b/src/module/decode/passport/PassportDecoder.java index 859e7c9d..1c298888 100644 --- a/src/module/decode/passport/PassportDecoder.java +++ b/src/module/decode/passport/PassportDecoder.java @@ -109,14 +109,4 @@ public class PassportDecoder extends Decoder { mPassportMessageFramer.reset(); } - - @Override - public void start( ScheduledExecutorService executor ) - { - } - - @Override - public void stop() - { - } } diff --git a/src/module/decode/passport/PassportDecoderState.java b/src/module/decode/passport/PassportDecoderState.java index ee5370e7..c98ef2c6 100644 --- a/src/module/decode/passport/PassportDecoderState.java +++ b/src/module/decode/passport/PassportDecoderState.java @@ -78,21 +78,6 @@ public class PassportDecoderState extends DecoderState return DecoderType.PASSPORT; } - @Override - public void start(ScheduledExecutorService executor) - { - } - - @Override - public void init() - { - } - - @Override - public void stop() - { - } - private void logTalkgroup(String talkgroup) { if(mTalkgroupsFirstHeard.contains(talkgroup)) diff --git a/src/module/decode/tait/Tait1200Decoder.java b/src/module/decode/tait/Tait1200Decoder.java index 97b9b788..917a2192 100644 --- a/src/module/decode/tait/Tait1200Decoder.java +++ b/src/module/decode/tait/Tait1200Decoder.java @@ -190,25 +190,4 @@ public class Tait1200Decoder extends Decoder implements IFilteredRealBufferListe { return DecoderType.TAIT_1200; } - - @Override - public void reset() - { - // TODO Auto-generated method stub - - } - - @Override - public void start( ScheduledExecutorService executor ) - { - // TODO Auto-generated method stub - - } - - @Override - public void stop() - { - // TODO Auto-generated method stub - - } } diff --git a/src/module/decode/tait/Tait1200DecoderState.java b/src/module/decode/tait/Tait1200DecoderState.java index b18ccb24..d8750b52 100644 --- a/src/module/decode/tait/Tait1200DecoderState.java +++ b/src/module/decode/tait/Tait1200DecoderState.java @@ -65,16 +65,6 @@ public class Tait1200DecoderState extends DecoderState return DecoderType.TAIT_1200; } - @Override - public void start(ScheduledExecutorService executor) - { - } - - @Override - public void stop() - { - } - @Override public void reset() { @@ -176,12 +166,6 @@ public class Tait1200DecoderState extends DecoderState return sb.toString(); } - @Override - public void init() - { - /* No initialization required */ - } - /** * Responds to reset events issued by the channel state */ diff --git a/src/module/demodulate/am/AMDemodulatorModule.java b/src/module/demodulate/am/AMDemodulatorModule.java index 374491aa..9c9f1ace 100644 --- a/src/module/demodulate/am/AMDemodulatorModule.java +++ b/src/module/demodulate/am/AMDemodulatorModule.java @@ -1,124 +1,110 @@ /******************************************************************************* * SDR Trunk * Copyright (C) 2014,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 ******************************************************************************/ package module.demodulate.am; -import java.util.concurrent.ScheduledExecutorService; - -import module.Module; -import sample.Listener; -import sample.complex.ComplexBuffer; -import sample.complex.IComplexBufferListener; -import sample.real.IFilteredRealBufferProvider; -import sample.real.RealBuffer; import dsp.am.AMDemodulator_CB; import dsp.filter.FilterFactory; import dsp.filter.Window.WindowType; import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB; import dsp.filter.fir.real.RealFIRFilter_RB_RB; import dsp.gain.AutomaticGainControl_RB; +import module.Module; +import sample.Listener; +import sample.complex.ComplexBuffer; +import sample.complex.IComplexBufferListener; +import sample.real.IFilteredRealBufferProvider; +import sample.real.RealBuffer; -public class AMDemodulatorModule extends Module - implements IComplexBufferListener, IFilteredRealBufferProvider +public class AMDemodulatorModule extends Module + implements IComplexBufferListener, IFilteredRealBufferProvider { - private static final int SAMPLE_RATE = 48000; - - private ComplexFIRFilter_CB_CB mIQFilter; - private AMDemodulator_CB mDemodulator; - private RealFIRFilter_RB_RB mLowPassFilter; + private static final int SAMPLE_RATE = 48000; + + private ComplexFIRFilter_CB_CB mIQFilter; + private AMDemodulator_CB mDemodulator; + private RealFIRFilter_RB_RB mLowPassFilter; private AutomaticGainControl_RB mAGC; - /** - * FM Demodulator with integrated DC removal and automatic frequency - * correction control. - * - * @param pass - pass frequency for IQ filtering prior to demodulation. This - * frequency should be half of the signal bandwidth since the filter will - * be applied against each of the inphase and quadrature signals and the - * combined pass bandwidth will be twice this value. - * - * @param stop - stop frequency for IQ filtering prior to demodulation. - * - * @param maxFrequencyCorrection - defines the maximum frequency +/- that - * the correction controller can adjust from the center tuned frequency. - * Set this value to 0 for no frequency correction control. - */ - public AMDemodulatorModule() - { - mIQFilter = new ComplexFIRFilter_CB_CB( FilterFactory.getLowPass( - SAMPLE_RATE, 5000, 73, WindowType.HAMMING ), 1.0f ); - - mDemodulator = new AMDemodulator_CB( 500.0f ); - mIQFilter.setListener( mDemodulator ); + /** + * AM Demodulator Module + */ + public AMDemodulatorModule() + { + mIQFilter = new ComplexFIRFilter_CB_CB(FilterFactory.getLowPass( + SAMPLE_RATE, 5000, 73, WindowType.HAMMING), 1.0f); - mLowPassFilter = new RealFIRFilter_RB_RB( - FilterFactory.getLowPass( 48000, 3000, 31, WindowType.COSINE ), 1.0f ); - mDemodulator.setListener( mLowPassFilter ); - - mAGC = new AutomaticGainControl_RB(); - mLowPassFilter.setListener( mAGC ); - } + mDemodulator = new AMDemodulator_CB(500.0f); + mIQFilter.setListener(mDemodulator); - @Override - public Listener getComplexBufferListener() - { - return mIQFilter; - } + mLowPassFilter = new RealFIRFilter_RB_RB( + FilterFactory.getLowPass(48000, 3000, 31, WindowType.COSINE), 1.0f); + mDemodulator.setListener(mLowPassFilter); - @Override - public void dispose() - { - mIQFilter.dispose(); - mIQFilter = null; - - mDemodulator.dispose(); - mDemodulator = null; - - mLowPassFilter.dispose(); - mLowPassFilter = null; - - mAGC.dispose(); - mAGC = null; - } + mAGC = new AutomaticGainControl_RB(); + mLowPassFilter.setListener(mAGC); + } - @Override - public void reset() - { - } + @Override + public Listener getComplexBufferListener() + { + return mIQFilter; + } - @Override - public void setFilteredRealBufferListener( Listener listener ) - { - mAGC.setListener( listener ); - } + @Override + public void dispose() + { + mIQFilter.dispose(); + mIQFilter = null; - @Override - public void removeFilteredRealBufferListener() - { - mAGC.removeListener(); - } + mDemodulator.dispose(); + mDemodulator = null; - @Override - public void start( ScheduledExecutorService executor ) - { - } + mLowPassFilter.dispose(); + mLowPassFilter = null; - @Override - public void stop() - { - } + mAGC.dispose(); + mAGC = null; + } + + @Override + public void reset() + { + } + + @Override + public void setFilteredRealBufferListener(Listener listener) + { + mAGC.setListener(listener); + } + + @Override + public void removeFilteredRealBufferListener() + { + mAGC.removeListener(); + } + + @Override + public void start() + { + } + + @Override + public void stop() + { + } } diff --git a/src/module/demodulate/audio/DemodulatedAudioFilterModule.java b/src/module/demodulate/audio/DemodulatedAudioFilterModule.java index a28ff3fd..fa73f27d 100644 --- a/src/module/demodulate/audio/DemodulatedAudioFilterModule.java +++ b/src/module/demodulate/audio/DemodulatedAudioFilterModule.java @@ -97,7 +97,7 @@ public class DemodulatedAudioFilterModule extends Module implements IUnFilteredR } @Override - public void start(ScheduledExecutorService executor) + public void start() { } diff --git a/src/module/demodulate/fm/FMDemodulatorModule.java b/src/module/demodulate/fm/FMDemodulatorModule.java index 8b7646de..d3278e68 100644 --- a/src/module/demodulate/fm/FMDemodulatorModule.java +++ b/src/module/demodulate/fm/FMDemodulatorModule.java @@ -104,7 +104,7 @@ public class FMDemodulatorModule extends Module implements IComplexBufferListene } @Override - public void start(ScheduledExecutorService executor) + public void start() { } diff --git a/src/module/log/EventLogger.java b/src/module/log/EventLogger.java index b6d800f5..dcd90caa 100644 --- a/src/module/log/EventLogger.java +++ b/src/module/log/EventLogger.java @@ -65,7 +65,7 @@ public abstract class EventLogger extends Module public abstract String getHeader(); @Override - public void start(ScheduledExecutorService executor) + public void start() { if(mLogFile == null) { diff --git a/src/record/AudioRecorder.java b/src/record/AudioRecorder.java index 15723eba..3c1b7f64 100644 --- a/src/record/AudioRecorder.java +++ b/src/record/AudioRecorder.java @@ -25,6 +25,7 @@ import module.Module; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sample.Listener; +import util.ThreadPool; import java.io.FileOutputStream; import java.io.IOException; @@ -196,7 +197,7 @@ public abstract class AudioRecorder extends Module implements Listener ******************************************************************************/ package record.wave; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.sound.sampled.AudioFormat; - import module.Module; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sample.Buffer; import sample.ConversionUtils; import sample.Listener; import sample.complex.ComplexBuffer; import sample.complex.IComplexBufferListener; +import util.ThreadPool; import util.TimeStamp; +import javax.sound.sampled.AudioFormat; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + /** * WAVE audio recorder module for recording complex (I&Q) samples to a wave file */ -public class ComplexBufferWaveRecorder extends Module - implements IComplexBufferListener, Listener +public class ComplexBufferWaveRecorder extends Module + implements IComplexBufferListener, Listener { - private final static Logger mLog = - LoggerFactory.getLogger( ComplexBufferWaveRecorder.class ); + private final static Logger mLog = + LoggerFactory.getLogger(ComplexBufferWaveRecorder.class); private WaveWriter mWriter; private String mFilePrefix; private Path mFile; - private AudioFormat mAudioFormat; - - private BufferProcessor mBufferProcessor; - private ScheduledFuture mProcessorHandle; - private LinkedBlockingQueue mBuffers = new LinkedBlockingQueue<>( 500 ); - - private AtomicBoolean mRunning = new AtomicBoolean(); - - public ComplexBufferWaveRecorder( int sampleRate, String filePrefix ) - { - mAudioFormat = new AudioFormat( sampleRate, //SampleRate - 16, //Sample Size - 2, //Channels - true, //Signed - false ); //Little Endian + private AudioFormat mAudioFormat; - mFilePrefix = filePrefix; - } + private BufferProcessor mBufferProcessor; + private ScheduledFuture mProcessorHandle; + private LinkedBlockingQueue mBuffers = new LinkedBlockingQueue<>(500); - public Path getFile() - { - return mFile; - } - - public void start( ScheduledExecutorService executor ) - { - if( mRunning.compareAndSet( false, true ) ) - { - if( mBufferProcessor == null ) - { - mBufferProcessor = new BufferProcessor(); - } + private AtomicBoolean mRunning = new AtomicBoolean(); - try - { - StringBuilder sb = new StringBuilder(); - sb.append( mFilePrefix ); - sb.append( "_" ); - sb.append( TimeStamp.getTimeStamp( "_" ) ); - sb.append( ".wav" ); - - mFile = Paths.get( sb.toString() ); + public ComplexBufferWaveRecorder(int sampleRate, String filePrefix) + { + mAudioFormat = new AudioFormat(sampleRate, //SampleRate + 16, //Sample Size + 2, //Channels + true, //Signed + false); //Little Endian - mWriter = new WaveWriter( mAudioFormat, mFile ); + mFilePrefix = filePrefix; + } + + public Path getFile() + { + return mFile; + } + + public void start() + { + if(mRunning.compareAndSet(false, true)) + { + if(mBufferProcessor == null) + { + mBufferProcessor = new BufferProcessor(); + } + + try + { + StringBuilder sb = new StringBuilder(); + sb.append(mFilePrefix); + sb.append("_"); + sb.append(TimeStamp.getTimeStamp("_")); + sb.append(".wav"); + + mFile = Paths.get(sb.toString()); + + mWriter = new WaveWriter(mAudioFormat, mFile); /* Schedule the processor to run every 500 milliseconds */ - mProcessorHandle = executor.scheduleAtFixedRate( - mBufferProcessor, 0, 500, TimeUnit.MILLISECONDS ); - } - catch( IOException io ) - { - mLog.error( "Error starting complex baseband recorder", io ); - } - } - } - - public void stop() - { - if( mRunning.compareAndSet( true, false ) ) - { - receive( new PoisonPill() ); - } - } - - @Override - public void receive( ComplexBuffer buffer ) - { - if( mRunning.get() ) - { - boolean success = mBuffers.offer( buffer ); - - if( !success ) - { - mLog.error( "recorder buffer overflow - purging [" + - mFile.toFile().getAbsolutePath() + "]" ); - - mBuffers.clear(); - } - } - } - - @Override - public Listener getComplexBufferListener() - { - return this; - } - - @Override - public void dispose() - { - stop(); - } - - @Override - public void reset() - { - } - - public class BufferProcessor implements Runnable - { - public void run() - { - try - { - Buffer buffer = mBuffers.poll(); - - while( buffer != null ) - { - if( buffer instanceof PoisonPill ) - { - buffer = null; - - mBuffers.clear(); - - if( mWriter != null ) - { - try - { - mWriter.close(); - mWriter = null; - } - catch( IOException io ) - { - mLog.error( "Error stopping complex wave recorder [" + - getFile() + "]", io ); - } - } - - mFile = null; - - if( mProcessorHandle != null ) - { - mProcessorHandle.cancel( true ); - } - - mProcessorHandle = null; - } - else - { - mWriter.write( ConversionUtils.convertToSigned16BitSamples( buffer ) ); - buffer = mBuffers.poll(); - } - } + mProcessorHandle = ThreadPool.SCHEDULED.scheduleAtFixedRate( + mBufferProcessor, 0, 500, TimeUnit.MILLISECONDS); } - catch ( IOException ioe ) - { - /* Stop this module if/when we get an IO exception */ - mBuffers.clear(); - stop(); - - mLog.error( "IOException while trying to write to the wave " - + "writer", ioe ); - } - } + catch(IOException io) + { + mLog.error("Error starting complex baseband recorder", io); + } + } } - /** - * This is used as a sentinel value to signal the buffer processor to end - */ - public class PoisonPill extends ComplexBuffer - { - public PoisonPill() - { - super( new float[ 1 ] ); - } - } + public void stop() + { + if(mRunning.compareAndSet(true, false)) + { + receive(new PoisonPill()); + } + } + + @Override + public void receive(ComplexBuffer buffer) + { + if(mRunning.get()) + { + boolean success = mBuffers.offer(buffer); + + if(!success) + { + mLog.error("recorder buffer overflow - purging [" + + mFile.toFile().getAbsolutePath() + "]"); + + mBuffers.clear(); + } + } + } + + @Override + public Listener getComplexBufferListener() + { + return this; + } + + @Override + public void dispose() + { + stop(); + } + + @Override + public void reset() + { + } + + public class BufferProcessor implements Runnable + { + public void run() + { + try + { + Buffer buffer = mBuffers.poll(); + + while(buffer != null) + { + if(buffer instanceof PoisonPill) + { + buffer = null; + + mBuffers.clear(); + + if(mWriter != null) + { + try + { + mWriter.close(); + mWriter = null; + } + catch(IOException io) + { + mLog.error("Error stopping complex wave recorder [" + + getFile() + "]", io); + } + } + + mFile = null; + + if(mProcessorHandle != null) + { + mProcessorHandle.cancel(true); + } + + mProcessorHandle = null; + } + else + { + mWriter.write(ConversionUtils.convertToSigned16BitSamples(buffer)); + buffer = mBuffers.poll(); + } + } + } + catch(IOException ioe) + { + /* Stop this module if/when we get an IO exception */ + mBuffers.clear(); + stop(); + + mLog.error("IOException while trying to write to the wave " + + "writer", ioe); + } + } + } + + /** + * This is used as a sentinel value to signal the buffer processor to end + */ + public class PoisonPill extends ComplexBuffer + { + public PoisonPill() + { + super(new float[1]); + } + } } diff --git a/src/record/wave/RealBufferWaveRecorder.java b/src/record/wave/RealBufferWaveRecorder.java index 763c9ded..d006fe4a 100644 --- a/src/record/wave/RealBufferWaveRecorder.java +++ b/src/record/wave/RealBufferWaveRecorder.java @@ -25,6 +25,7 @@ import sample.ConversionUtils; import sample.Listener; import sample.real.IFilteredRealBufferListener; import sample.real.RealBuffer; +import util.ThreadPool; import util.TimeStamp; import javax.sound.sampled.AudioFormat; @@ -89,7 +90,7 @@ public class RealBufferWaveRecorder extends Module return mFile; } - public void start(ScheduledExecutorService executor) + public void start() { if(mRunning.compareAndSet(false, true)) { @@ -111,7 +112,7 @@ public class RealBufferWaveRecorder extends Module mWriter = new WaveWriter(mAudioFormat, mFile); /* Schedule the processor to run every 500 milliseconds */ - mProcessorHandle = executor.scheduleAtFixedRate(mBufferProcessor, 0, 500, TimeUnit.MILLISECONDS); + mProcessorHandle = ThreadPool.SCHEDULED.scheduleAtFixedRate(mBufferProcessor, 0, 500, TimeUnit.MILLISECONDS); } catch(IOException io) { diff --git a/src/sample/OverflowableTransferQueue.java b/src/sample/OverflowableTransferQueue.java index f37314a4..193ef811 100644 --- a/src/sample/OverflowableTransferQueue.java +++ b/src/sample/OverflowableTransferQueue.java @@ -21,7 +21,6 @@ package sample; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sample.real.IOverflowListener; -import source.tuner.TunerChannelSource; import java.util.Collection; import java.util.concurrent.LinkedTransferQueue; diff --git a/src/sample/complex/IComplexBufferProvider.java b/src/sample/complex/IComplexBufferProvider.java new file mode 100644 index 00000000..480cede0 --- /dev/null +++ b/src/sample/complex/IComplexBufferProvider.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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 + * + ******************************************************************************/ +package sample.complex; + +import sample.Listener; + +public interface IComplexBufferProvider +{ + /** + * Adds the listener to receive complex buffer samples + */ + void addComplexBufferListener(Listener listener); + + /** + * Removes the listener from receiving complex buffer samples + */ + void removeComplexBufferListener(Listener listener); + + /** + * Indicates if there are any complex buffer listeners registered + */ + boolean hasComplexBufferListeners(); +} diff --git a/src/source/Source.java b/src/source/Source.java index 1518279d..9304ddbe 100644 --- a/src/source/Source.java +++ b/src/source/Source.java @@ -18,7 +18,8 @@ ******************************************************************************/ package source; -import channel.heartbeat.IHeartbeatProvider; +import source.heartbeat.HeartbeatManager; +import source.heartbeat.IHeartbeatProvider; import module.Module; import sample.SampleType; import sample.real.IOverflowListener; @@ -28,6 +29,17 @@ import sample.real.IOverflowListener; */ public abstract class Source extends Module implements ISourceEventListener, ISourceEventProvider, IHeartbeatProvider { + private HeartbeatManager mHeartbeatManager = new HeartbeatManager(); + + /** + * Heartbeat manager for this source + */ + public HeartbeatManager getHeartbeatManager() + { + return mHeartbeatManager; + } + + protected IOverflowListener mOverflowListener; /** diff --git a/src/source/SourceEvent.java b/src/source/SourceEvent.java index 5a9dd3b7..074eee9a 100644 --- a/src/source/SourceEvent.java +++ b/src/source/SourceEvent.java @@ -31,6 +31,7 @@ public class SourceEvent REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, REQUEST_FREQUENCY_CHANGE, + REQUEST_SOURCE_DISPOSE, REQUEST_START_SAMPLE_STREAM, REQUEST_STOP_SAMPLE_STREAM; } @@ -189,4 +190,13 @@ public class SourceEvent { return new SourceEvent(Event.REQUEST_STOP_SAMPLE_STREAM, source); } + + /** + * Creates a request to dispose of the source. This is normally used for TunerChannelSource to notify the + * parent source manager that the channel is no longer needed + */ + public static SourceEvent sourceDisposeRequest(Source source) + { + return new SourceEvent(Event.REQUEST_SOURCE_DISPOSE, source); + } } diff --git a/src/source/config/SourceConfigRecording.java b/src/source/config/SourceConfigRecording.java index f1b7c1c3..d92b4fe5 100644 --- a/src/source/config/SourceConfigRecording.java +++ b/src/source/config/SourceConfigRecording.java @@ -19,7 +19,7 @@ package source.config; import source.SourceType; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; import javax.xml.bind.annotation.XmlAttribute; diff --git a/src/source/config/SourceConfigTuner.java b/src/source/config/SourceConfigTuner.java index 2f31457d..8fe54732 100644 --- a/src/source/config/SourceConfigTuner.java +++ b/src/source/config/SourceConfigTuner.java @@ -19,7 +19,7 @@ package source.config; import source.SourceType; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; import javax.xml.bind.annotation.XmlAttribute; import java.text.DecimalFormat; diff --git a/src/channel/heartbeat/Heartbeat.java b/src/source/heartbeat/Heartbeat.java similarity index 97% rename from src/channel/heartbeat/Heartbeat.java rename to src/source/heartbeat/Heartbeat.java index 4799754e..993d51ee 100644 --- a/src/channel/heartbeat/Heartbeat.java +++ b/src/source/heartbeat/Heartbeat.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package channel.heartbeat; +package source.heartbeat; public class Heartbeat { diff --git a/src/source/heartbeat/HeartbeatManager.java b/src/source/heartbeat/HeartbeatManager.java new file mode 100644 index 00000000..d35188e3 --- /dev/null +++ b/src/source/heartbeat/HeartbeatManager.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * 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 + * + ******************************************************************************/ +package source.heartbeat; + +import sample.Broadcaster; +import sample.Listener; + +public class HeartbeatManager +{ + private static final Heartbeat HEARTBEAT = new Heartbeat(); + private Broadcaster mHeartbeatBroadcaster = new Broadcaster<>(); + + public HeartbeatManager() + { + } + + /** + * Sends a heartbeat to all registered listeners + */ + public void broadcast() + { + mHeartbeatBroadcaster.broadcast(HEARTBEAT); + } + + /** + * Adds the listener to receive heartbeats + */ + public void addHeartbeatListener(Listener listener) + { + mHeartbeatBroadcaster.addListener(listener); + } + + /** + * Removes the listener from receiving heartbeats + * @param listener + */ + public void removeHeartbeatListener(Listener listener) + { + mHeartbeatBroadcaster.removeListener(listener); + } + +} diff --git a/src/channel/heartbeat/IHeartbeatListener.java b/src/source/heartbeat/IHeartbeatListener.java similarity index 97% rename from src/channel/heartbeat/IHeartbeatListener.java rename to src/source/heartbeat/IHeartbeatListener.java index 904d0501..296860a7 100644 --- a/src/channel/heartbeat/IHeartbeatListener.java +++ b/src/source/heartbeat/IHeartbeatListener.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package channel.heartbeat; +package source.heartbeat; import sample.Listener; diff --git a/src/channel/heartbeat/IHeartbeatProvider.java b/src/source/heartbeat/IHeartbeatProvider.java similarity index 84% rename from src/channel/heartbeat/IHeartbeatProvider.java rename to src/source/heartbeat/IHeartbeatProvider.java index 3583cd42..9941b716 100644 --- a/src/channel/heartbeat/IHeartbeatProvider.java +++ b/src/source/heartbeat/IHeartbeatProvider.java @@ -16,13 +16,9 @@ * along with this program. If not, see * ******************************************************************************/ -package channel.heartbeat; - -import sample.Listener; +package source.heartbeat; public interface IHeartbeatProvider { - public void setHeartbeatListener(Listener listener); - - public void removeHeartbeatListener(); + public HeartbeatManager getHeartbeatManager(); } diff --git a/src/source/mixer/RealMixerSource.java b/src/source/mixer/RealMixerSource.java index 408f04ea..e8558429 100644 --- a/src/source/mixer/RealMixerSource.java +++ b/src/source/mixer/RealMixerSource.java @@ -17,8 +17,7 @@ ******************************************************************************/ package source.mixer; -import channel.heartbeat.Heartbeat; -import dsp.gain.AutomaticGainControl; +import source.heartbeat.Heartbeat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sample.Listener; diff --git a/src/source/recording/Recording.java b/src/source/recording/Recording.java index a89f77eb..938dc6a6 100644 --- a/src/source/recording/Recording.java +++ b/src/source/recording/Recording.java @@ -7,8 +7,8 @@ import java.util.concurrent.RejectedExecutionException; import settings.SettingsManager; import source.SourceException; import source.tuner.ITunerChannelProvider; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; import source.SourceEvent; import source.SourceEvent.Event; import source.ISourceEventProcessor; diff --git a/src/source/recording/RecordingSourceManager.java b/src/source/recording/RecordingSourceManager.java index 4a47c660..d5fb4a69 100644 --- a/src/source/recording/RecordingSourceManager.java +++ b/src/source/recording/RecordingSourceManager.java @@ -29,8 +29,8 @@ import source.Source; import source.SourceException; import source.config.SourceConfigRecording; import source.config.SourceConfiguration; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; public class RecordingSourceManager { diff --git a/src/source/tuner/ITunerChannelProvider.java b/src/source/tuner/ITunerChannelProvider.java index b3a69a63..17558dbc 100644 --- a/src/source/tuner/ITunerChannelProvider.java +++ b/src/source/tuner/ITunerChannelProvider.java @@ -20,6 +20,8 @@ package source.tuner; import java.util.concurrent.RejectedExecutionException; import source.SourceException; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; public interface ITunerChannelProvider { @@ -30,7 +32,7 @@ public interface ITunerChannelProvider * * @return - source for 48k sample rate */ - public abstract TunerChannelSource getChannel( TunerChannel channel ) + public abstract TunerChannelSource getChannel(TunerChannel channel ) throws RejectedExecutionException, SourceException; /** diff --git a/src/source/tuner/MixerTuner.java b/src/source/tuner/MixerTuner.java deleted file mode 100644 index c873aa8c..00000000 --- a/src/source/tuner/MixerTuner.java +++ /dev/null @@ -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 - ******************************************************************************/ -package source.tuner; - -import java.util.ArrayList; - -import javax.sound.sampled.TargetDataLine; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sample.Listener; -import sample.adapter.ISampleAdapter; -import sample.complex.ComplexBuffer; -import sample.complex.ComplexSampleListListener; -import source.mixer.ComplexMixer; - -public abstract class MixerTuner extends Tuner implements Listener -{ - private final static Logger mLog = - LoggerFactory.getLogger( MixerTuner.class ); - - protected MixerTunerType mMixerTunerType; - protected ComplexMixer mComplexMixer; - protected ArrayList mListeners = - new ArrayList(); - - /** - * Wrapper class to add basic Tuner functionality to the ComplexMixer. - * Subclasses should couple this functionality with a tuner controller class - * to support tuning. - */ - public MixerTuner( String name, - TunerController tunerController, - MixerTunerType mixerTunerType, - TargetDataLine targetDataLine, - ISampleAdapter sampleAdapter ) - { - super( name, tunerController ); - - mMixerTunerType = mixerTunerType; - - mComplexMixer = new ComplexMixer( targetDataLine, - mMixerTunerType.getAudioFormat(), - name, - sampleAdapter, - (Listener)this ); - } - - public MixerTuner( String name, - TunerController tunerController, - MixerTunerDataLine mixerTuner, - ISampleAdapter sampleAdapter ) - { - this( name, - tunerController, - mixerTuner.getMixerTunerType(), - mixerTuner.getTargetDataLine(), - sampleAdapter ); - } - - public void dispose() - { - mComplexMixer.stop(); - - super.dispose(); - } - - public MixerTunerType getMixerTunerType() - { - return mMixerTunerType; - } - - public TargetDataLine getTargetDataLine() - { - return mComplexMixer.getTargetDataLine(); - } - - /** - * Dispatches the received complex buffers from the mComplexMixer to all - * listeners registered on the parent Tuner class - */ - @Override - public void receive( ComplexBuffer buffer ) - { - super.broadcast( buffer ); - } - - /** - * Overrides the parent Tuner class listener management method to allow - * starting the buffer processing thread - */ - @Override - public void addListener( Listener listener ) - { - super.addListener( listener ); - - /* We can call start multiple times -- it ignores additional requests */ - mComplexMixer.start(); - } - - /** - * Overrides the parent Tuner class listener management method to allow - * stopping the buffer processing thread when there are no more listeners - */ - @Override - public void removeListener( Listener listener ) - { - super.removeListener( listener ); - - if( !hasListeners() ) - { - mComplexMixer.stop(); - } - } -} diff --git a/src/source/tuner/Tuner.java b/src/source/tuner/Tuner.java index aac3297e..13370fb3 100644 --- a/src/source/tuner/Tuner.java +++ b/src/source/tuner/Tuner.java @@ -23,9 +23,12 @@ import org.slf4j.LoggerFactory; import sample.Broadcaster; import sample.Listener; import sample.complex.ComplexBuffer; +import sample.complex.IComplexBufferProvider; import source.ISourceEventProcessor; import source.SourceEvent; import source.SourceException; +import source.tuner.manager.AbstractSourceManager; +import source.tuner.manager.TunerSourceManager; import java.util.ArrayList; import java.util.List; @@ -35,21 +38,27 @@ import java.util.concurrent.RejectedExecutionException; /** * Tuner - provides tuner channel sources, representing a channel frequency */ -public abstract class Tuner implements ITunerChannelProvider +public abstract class Tuner { private final static Logger mLog = LoggerFactory.getLogger(Tuner.class); - private String mName; + protected Broadcaster mTunerEventBroadcaster = new Broadcaster<>(); private TunerController mTunerController; - private Broadcaster mSampleBroadcaster = new Broadcaster<>(); - protected List> mTunerChangeListeners = new ArrayList<>(); - protected Broadcaster mSourceEventBroadcaster = new Broadcaster<>(); + private String mName; + private AbstractSourceManager mTunerSourceManager; + /** + * Abstract tuner class. + * @param name of the tuner + * @param tunerController for the tuner + */ public Tuner(String name, TunerController tunerController) { mName = name; mTunerController = tunerController; + mTunerSourceManager = new TunerSourceManager(mTunerController); + //Rebroadcast frequency and sample rate change events as tuner events mTunerController.addListener(new ISourceEventProcessor() { @@ -59,12 +68,10 @@ public abstract class Tuner implements ITunerChannelProvider switch(event.getEvent()) { case NOTIFICATION_FREQUENCY_CHANGE: - broadcast(new TunerEvent(Tuner.this, - source.tuner.TunerEvent.Event.FREQUENCY)); + broadcast(new TunerEvent(Tuner.this, source.tuner.TunerEvent.Event.FREQUENCY)); break; case NOTIFICATION_SAMPLE_RATE_CHANGE: - broadcast(new TunerEvent(Tuner.this, - source.tuner.TunerEvent.Event.SAMPLE_RATE)); + broadcast(new TunerEvent(Tuner.this, source.tuner.TunerEvent.Event.SAMPLE_RATE)); break; default: break; @@ -73,6 +80,14 @@ public abstract class Tuner implements ITunerChannelProvider }); } + /** + * Source Manager. Provides access to registering for complex buffer samples and source event notifications. + */ + public AbstractSourceManager getSourceManager() + { + return mTunerSourceManager; + } + public TunerController getTunerController() { return mTunerController; @@ -85,7 +100,6 @@ public abstract class Tuner implements ITunerChannelProvider public void dispose() { - mSampleBroadcaster.clear(); } public void setName(String name) @@ -129,93 +143,12 @@ public abstract class Tuner implements ITunerChannelProvider */ public abstract double getSampleSize(); - /** - * Returns a tuner frequency channel source, tuned to the correct frequency - * - * Note: ensure the concrete implementation registers the returned - * tuner channel source as a listener on the tuner, to receive frequency - * change events. - * - * @param channel - desired frequency and bandwidth - * @return - source for 48k sample rate - */ - public abstract TunerChannelSource getChannel(TunerChannel channel) - throws RejectedExecutionException, SourceException; - - /** - * Releases the tuned channel resources - * - * Note: ensure the concrete implementation unregisters the tuner channel - * source from the tuner as a frequency change listener - * - * @param source - previously obtained tuner channel - */ - public abstract void releaseChannel(TunerChannelSource source); - - /** - * Registers the listener to receive complex float sample arrays - */ - public void addListener(Listener listener) - { - mSampleBroadcaster.addListener(listener); - } - - /** - * Removes the registered listener - */ - public void removeListener(Listener listener) - { - mSampleBroadcaster.removeListener(listener); - } - - /** - * Number of registered complex sample buffer listeners - */ - public int getListenerCount() - { - return mSampleBroadcaster.getListenerCount(); - } - - /** - * Provides access to the internal sample broadcaster for sub-class use (ie protected). - */ - protected Broadcaster getSampleBroadcaster() - { - return mSampleBroadcaster; - } - - /** - * Indicates if the listener is currently registered with this tuner - * @param listener of complex buffer samples - * @return true if the listener is registered - */ - public boolean hasListener(Listener listener) - { - return mSampleBroadcaster.hasListener(listener); - } - - /** - * Indicates if this tuner has any complex buffer listeners registered - */ - public boolean hasListeners() - { - return mSampleBroadcaster.hasListeners(); - } - - /** - * Broadcasts the samples to all registered listeners - */ - public void broadcast(ComplexBuffer sampleBuffer) - { - mSampleBroadcaster.broadcast(sampleBuffer); - } - /** * Registers the listener */ public void addTunerChangeListener(Listener listener) { - mTunerChangeListeners.add(listener); + mTunerEventBroadcaster.addListener(listener); } /** @@ -223,7 +156,7 @@ public abstract class Tuner implements ITunerChannelProvider */ public void removeTunerChangeListener(Listener listener) { - mTunerChangeListeners.remove(listener); + mTunerEventBroadcaster.removeListener(listener); } /** @@ -231,36 +164,6 @@ public abstract class Tuner implements ITunerChannelProvider */ public void broadcast(TunerEvent tunerEvent) { - for(Listener listener : mTunerChangeListeners) - { - listener.receive(tunerEvent); - } - - //Re-broadcast frequency and sample rate change events as source events - switch(tunerEvent.getEvent()) - { - case FREQUENCY: - mSourceEventBroadcaster.broadcast(SourceEvent.frequencyChange(getTunerController().getFrequency())); - break; - case SAMPLE_RATE: - mSourceEventBroadcaster.broadcast(SourceEvent.sampleRateChange(getTunerController().getSampleRate())); - break; - } - } - - /** - * Adds the listener to receive source events - */ - public void addSourceEventListener(Listener listener) - { - mSourceEventBroadcaster.addListener(listener); - } - - /** - * Removes the listener from receiving source events - */ - public void removeSourceEventListener(Listener listener) - { - mSourceEventBroadcaster.removeListener(listener); + mTunerEventBroadcaster.broadcast(tunerEvent); } } diff --git a/src/source/tuner/TunerChannelProvider.java b/src/source/tuner/TunerChannelProvider.java deleted file mode 100644 index 8f53f144..00000000 --- a/src/source/tuner/TunerChannelProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -package source.tuner; - -import java.util.concurrent.RejectedExecutionException; - -import source.SourceException; - -public interface TunerChannelProvider -{ - /** - * Returns a tuner frequency channel source, tuned to the correct frequency - * - * @param frequency - desired frequency - * - * @return - source for 48k sample rate - */ - public abstract TunerChannelSource getChannel( TunerChannel channel ) - throws RejectedExecutionException, SourceException; - - /** - * Releases the tuned channel resources - * - * @param channel - previously obtained tuner channel - */ - public abstract void releaseChannel( TunerChannelSource source ); - - -} diff --git a/src/source/tuner/TunerController.java b/src/source/tuner/TunerController.java index 8fd2cc54..50c4a98c 100644 --- a/src/source/tuner/TunerController.java +++ b/src/source/tuner/TunerController.java @@ -19,10 +19,16 @@ package source.tuner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sample.Broadcaster; +import sample.Listener; +import sample.complex.ComplexBuffer; +import sample.complex.IComplexBufferProvider; import source.ISourceEventProcessor; import source.SourceEvent; import source.SourceEvent.Event; import source.SourceException; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; import source.tuner.configuration.TunerConfiguration; import source.tuner.frequency.FrequencyController; import source.tuner.frequency.FrequencyController.Tunable; @@ -31,9 +37,11 @@ import java.util.SortedSet; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.RejectedExecutionException; -public abstract class TunerController implements Tunable, ISourceEventProcessor +public abstract class TunerController implements Tunable, ISourceEventProcessor, + IComplexBufferProvider, Listener { private final static Logger mLog = LoggerFactory.getLogger(TunerController.class); + protected Broadcaster mSampleBroadcaster = new Broadcaster<>(); /* List of currently tuned channels being served to demod channels */ private SortedSet mTunedChannels = new ConcurrentSkipListSet<>(); @@ -102,6 +110,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor return mFrequencyController.getFrequency(); } + @Override + public boolean canTune(long frequency) + { + return mFrequencyController.canTune(frequency); + } + public int getSampleRate() { return mFrequencyController.getSampleRate(); @@ -369,4 +383,48 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor { mFrequencyController.removeFrequencyChangeProcessor(processor); } + + /** + * Adds the listener to receive complex buffer samples + */ + @Override + public void addComplexBufferListener(Listener listener) + { + mSampleBroadcaster.addListener(listener); + } + + /** + * Removes the listener from receiving complex buffer samples + */ + @Override + public void removeComplexBufferListener(Listener listener) + { + mSampleBroadcaster.removeListener(listener); + } + + /** + * Indicates if there are any complex buffer listeners registered on this controller + */ + @Override + public boolean hasComplexBufferListeners() + { + return mSampleBroadcaster.hasListeners(); + } + + /** + * Broadcasts the buffer to any registered listeners + */ + protected void broadcast(ComplexBuffer complexBuffer) + { + mSampleBroadcaster.broadcast(complexBuffer); + } + + /** + * Implements the Listener interface to receive and distribute complex buffers from subclass implementations + */ + @Override + public void receive(ComplexBuffer complexBuffer) + { + broadcast(complexBuffer); + } } diff --git a/src/source/tuner/TunerManager.java b/src/source/tuner/TunerManager.java index b5181c26..12d228aa 100644 --- a/src/source/tuner/TunerManager.java +++ b/src/source/tuner/TunerManager.java @@ -246,25 +246,21 @@ public class TunerManager + "supported"); } - private TunerInitStatus initFuncubeProTuner(Device device, - DeviceDescriptor descriptor) + private TunerInitStatus initFuncubeProTuner(Device device, DeviceDescriptor descriptor) { String reason = "NOT LOADED"; - MixerTunerDataLine dataline = getMixerTunerDataLine( - TunerClass.FUNCUBE_DONGLE_PRO.getTunerType()); + MixerTunerDataLine dataline = getMixerTunerDataLine(TunerClass.FUNCUBE_DONGLE_PRO.getTunerType()); if(dataline != null) { - FCD1TunerController controller = - new FCD1TunerController(device, descriptor); + FCD1TunerController controller = new FCD1TunerController(dataline, device, descriptor); try { controller.init(); - FCDTuner tuner = - new FCDTuner(dataline, controller); + FCDTuner tuner = new FCDTuner(controller); return new TunerInitStatus(tuner, "LOADED"); } @@ -284,25 +280,21 @@ public class TunerManager + "loaded - " + reason); } - private TunerInitStatus initFuncubeProPlusTuner(Device device, - DeviceDescriptor descriptor) + private TunerInitStatus initFuncubeProPlusTuner(Device device, DeviceDescriptor descriptor) { String reason = "NOT LOADED"; - MixerTunerDataLine dataline = getMixerTunerDataLine( - TunerClass.FUNCUBE_DONGLE_PRO_PLUS.getTunerType()); + MixerTunerDataLine dataline = getMixerTunerDataLine(TunerClass.FUNCUBE_DONGLE_PRO_PLUS.getTunerType()); if(dataline != null) { - FCD2TunerController controller = - new FCD2TunerController(device, descriptor); + FCD2TunerController controller = new FCD2TunerController(dataline, device, descriptor); try { controller.init(); - FCDTuner tuner = - new FCDTuner(dataline, controller); + FCDTuner tuner = new FCDTuner(controller); return new TunerInitStatus(tuner, "LOADED"); } @@ -323,8 +315,7 @@ public class TunerManager + "loaded - " + reason); } - private TunerInitStatus initHackRFTuner(Device device, - DeviceDescriptor descriptor) + private TunerInitStatus initHackRFTuner(Device device, DeviceDescriptor descriptor) { try { diff --git a/src/source/tuner/TunerModel.java b/src/source/tuner/TunerModel.java index 09a74804..9680d732 100644 --- a/src/source/tuner/TunerModel.java +++ b/src/source/tuner/TunerModel.java @@ -1,298 +1,292 @@ package source.tuner; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.RejectedExecutionException; - -import javax.swing.table.AbstractTableModel; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sample.Listener; import source.Source; import source.SourceException; import source.config.SourceConfigTuner; import source.tuner.TunerEvent.Event; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; import source.tuner.configuration.TunerConfiguration; import source.tuner.configuration.TunerConfigurationModel; +import javax.swing.table.AbstractTableModel; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + public class TunerModel extends AbstractTableModel implements Listener { - private static final long serialVersionUID = 1L; - - private final static Logger mLog = LoggerFactory.getLogger( TunerModel.class ); + private static final long serialVersionUID = 1L; - public static final int TUNER_TYPE = 0; - public static final int TUNER_ID = 1; - public static final int SAMPLE_RATE = 2; - public static final int FREQUENCY = 3; - public static final int CHANNEL_COUNT = 4; - public static final int SPECTRAL_DISPLAY_MAIN = 5; - public static final int SPECTRAL_DISPLAY_NEW = 6; - - private static final String MHZ = " MHz"; - private static final String[] COLUMNS = - { "Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Spectral", "Display" }; - - private List mTuners = new ArrayList<>(); - private List> mTunerEventListeners = new ArrayList<>(); - private DecimalFormat mFrequencyFormat = new DecimalFormat( "0.00000" ); - private DecimalFormat mSampleRateFormat = new DecimalFormat( "0.000" ); - - private TunerConfigurationModel mTunerConfigurationModel; + private final static Logger mLog = LoggerFactory.getLogger(TunerModel.class); - public TunerModel( TunerConfigurationModel tunerConfigurationModel ) - { - mTunerConfigurationModel = tunerConfigurationModel; - } - - public TunerConfigurationModel getTunerConfigurationModel() - { - return mTunerConfigurationModel; - } + public static final int TUNER_TYPE = 0; + public static final int TUNER_ID = 1; + public static final int SAMPLE_RATE = 2; + public static final int FREQUENCY = 3; + public static final int CHANNEL_COUNT = 4; + public static final int SPECTRAL_DISPLAY_MAIN = 5; + public static final int SPECTRAL_DISPLAY_NEW = 6; - /** - * List of Tuners currently in the model - */ - public List getTuners() - { - return mTuners; - } - - public Tuner getTuner( int index ) - { - if( index < mTuners.size() ) - { - return mTuners.get( index ); - } - - return null; - } + private static final String MHZ = " MHz"; + private static final String[] COLUMNS = + {"Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Spectral", "Display"}; - public void addTuners( List Tuners ) - { - for( Tuner tuner: Tuners ) - { - addTuner( tuner ); - } - } + private List mTuners = new ArrayList<>(); + private List> mTunerEventListeners = new ArrayList<>(); + private DecimalFormat mFrequencyFormat = new DecimalFormat("0.00000"); + private DecimalFormat mSampleRateFormat = new DecimalFormat("0.000"); - /** - * Adds the Tuner to this model - */ - public void addTuner( Tuner tuner ) - { - if( !mTuners.contains( tuner ) ) - { - //Get the tuner configuration and apply it to the tuner - this - //call should always produce a tuner configuration - TunerConfiguration config = mTunerConfigurationModel - .getTunerConfiguration( tuner.getTunerType(), tuner.getUniqueID() ); - - try - { - tuner.getTunerController().apply( config ); - - mTuners.add( tuner ); - - int index = mTuners.indexOf( tuner ); - - fireTableRowsInserted( index, index ); - - tuner.addTunerChangeListener( this ); - } - catch( SourceException se ) - { - mLog.error( "Couldn't apply tuner configuration to tuner - [" - + tuner.getTunerType().name() + "] with id [" - + tuner.getUniqueID() + "] - tuner will not be included" ); - } - - } - } + private TunerConfigurationModel mTunerConfigurationModel; - /** - * Removes the Tuner from this model - */ - public void removeTuner( Tuner tuner ) - { - if( mTuners.contains( tuner ) ) - { - tuner.removeTunerChangeListener( this ); - - int index = mTuners.indexOf( tuner ); - - mTuners.remove( tuner ); - - fireTableRowsDeleted( index, index ); - } - } - - public void addListener( Listener listener ) - { - mTunerEventListeners.add( listener ); - } + public TunerModel(TunerConfigurationModel tunerConfigurationModel) + { + mTunerConfigurationModel = tunerConfigurationModel; + } - public void removeListener( Listener listener ) - { - mTunerEventListeners.remove( listener ); - } + public TunerConfigurationModel getTunerConfigurationModel() + { + return mTunerConfigurationModel; + } - public void broadcast( TunerEvent event ) - { - for( Listener listener: mTunerEventListeners ) - { - listener.receive( event ); - } - } + /** + * List of Tuners currently in the model + */ + public List getTuners() + { + return mTuners; + } - /** - * Requests to display the first tuner in this model. Invoke this method - * after all listeners have registered and tuners have been added to this - * model, in order to inform the primary display to use the first tuner. - */ - public void requestFirstTunerDisplay() - { - if( mTuners.size() > 0 ) - { - broadcast( new TunerEvent( mTuners.get( 0 ), - Event.REQUEST_MAIN_SPECTRAL_DISPLAY ) ); - } - } - - @Override - public void receive( TunerEvent event ) - { - if( event.getTuner() != null ) - { - int index = mTuners.indexOf( event.getTuner() ); - - if( index >= 0 ) - { - switch( event.getEvent() ) - { - case CHANNEL_COUNT: - fireTableCellUpdated( index, CHANNEL_COUNT ); - break; - case FREQUENCY: - fireTableCellUpdated( index, FREQUENCY ); - mTunerConfigurationModel.tunerFrequencyChanged( event.getTuner() ); - break; - case SAMPLE_RATE: - fireTableCellUpdated( index, SAMPLE_RATE ); - break; - case REQUEST_MAIN_SPECTRAL_DISPLAY: - fireTableCellUpdated( index, SPECTRAL_DISPLAY_MAIN ); - default: - break; - } - } - } - - broadcast( event ); - } + public Tuner getTuner(int index) + { + if(index < mTuners.size()) + { + return mTuners.get(index); + } - @Override - public int getRowCount() - { - return mTuners.size(); - } + return null; + } - @Override - public int getColumnCount() - { - return COLUMNS.length; - } + public void addTuners(List Tuners) + { + for(Tuner tuner : Tuners) + { + addTuner(tuner); + } + } - @Override - public Object getValueAt( int rowIndex, int columnIndex ) - { - if( rowIndex < mTuners.size() ) - { - Tuner tuner = mTuners.get( rowIndex ); + /** + * Adds the Tuner to this model + */ + public void addTuner(Tuner tuner) + { + if(!mTuners.contains(tuner)) + { + //Get the tuner configuration and apply it to the tuner - this + //call should always produce a tuner configuration + TunerConfiguration config = mTunerConfigurationModel + .getTunerConfiguration(tuner.getTunerType(), tuner.getUniqueID()); - switch( columnIndex ) - { - case TUNER_TYPE: - return tuner.getTunerType().getLabel(); - case TUNER_ID: - return tuner.getUniqueID(); - case SAMPLE_RATE: - int sampleRate = tuner.getTunerController().getSampleRate(); + try + { + tuner.getTunerController().apply(config); - return mSampleRateFormat.format( sampleRate / 1E6D ) + MHZ; - case FREQUENCY: - try - { - long frequency = tuner.getTunerController().getFrequency(); - - return mFrequencyFormat.format( frequency / 1E6D ) + MHZ; - } - catch( Exception e ) - { - return 0; - } - case CHANNEL_COUNT: - return tuner.getTunerController().getChannelCount(); - case SPECTRAL_DISPLAY_MAIN: - return "Main"; - case SPECTRAL_DISPLAY_NEW: - return "New"; - default: - break; - } - } + mTuners.add(tuner); + + int index = mTuners.indexOf(tuner); + + fireTableRowsInserted(index, index); + + tuner.addTunerChangeListener(this); + } + catch(SourceException se) + { + mLog.error("Couldn't apply tuner configuration to tuner - [" + + tuner.getTunerType().name() + "] with id [" + + tuner.getUniqueID() + "] - tuner will not be included"); + } + + } + } + + /** + * Removes the Tuner from this model + */ + public void removeTuner(Tuner tuner) + { + if(mTuners.contains(tuner)) + { + tuner.removeTunerChangeListener(this); + + int index = mTuners.indexOf(tuner); + + mTuners.remove(tuner); + + fireTableRowsDeleted(index, index); + } + } + + public void addListener(Listener listener) + { + mTunerEventListeners.add(listener); + } + + public void removeListener(Listener listener) + { + mTunerEventListeners.remove(listener); + } + + public void broadcast(TunerEvent event) + { + for(Listener listener : mTunerEventListeners) + { + listener.receive(event); + } + } + + /** + * Requests to display the first tuner in this model. Invoke this method + * after all listeners have registered and tuners have been added to this + * model, in order to inform the primary display to use the first tuner. + */ + public void requestFirstTunerDisplay() + { + if(mTuners.size() > 0) + { + broadcast(new TunerEvent(mTuners.get(0), + Event.REQUEST_MAIN_SPECTRAL_DISPLAY)); + } + } + + @Override + public void receive(TunerEvent event) + { + if(event.getTuner() != null) + { + int index = mTuners.indexOf(event.getTuner()); + + if(index >= 0) + { + switch(event.getEvent()) + { + case CHANNEL_COUNT: + fireTableCellUpdated(index, CHANNEL_COUNT); + break; + case FREQUENCY: + fireTableCellUpdated(index, FREQUENCY); + mTunerConfigurationModel.tunerFrequencyChanged(event.getTuner()); + break; + case SAMPLE_RATE: + fireTableCellUpdated(index, SAMPLE_RATE); + break; + case REQUEST_MAIN_SPECTRAL_DISPLAY: + fireTableCellUpdated(index, SPECTRAL_DISPLAY_MAIN); + default: + break; + } + } + } + + broadcast(event); + } + + @Override + public int getRowCount() + { + return mTuners.size(); + } + + @Override + public int getColumnCount() + { + return COLUMNS.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) + { + if(rowIndex < mTuners.size()) + { + Tuner tuner = mTuners.get(rowIndex); + + switch(columnIndex) + { + case TUNER_TYPE: + return tuner.getTunerType().getLabel(); + case TUNER_ID: + return tuner.getUniqueID(); + case SAMPLE_RATE: + int sampleRate = tuner.getTunerController().getSampleRate(); + + return mSampleRateFormat.format(sampleRate / 1E6D) + MHZ; + case FREQUENCY: + try + { + long frequency = tuner.getTunerController().getFrequency(); + + return mFrequencyFormat.format(frequency / 1E6D) + MHZ; + } + catch(Exception e) + { + return 0; + } + case CHANNEL_COUNT: + return tuner.getTunerController().getChannelCount(); + case SPECTRAL_DISPLAY_MAIN: + return "Main"; + case SPECTRAL_DISPLAY_NEW: + return "New"; + default: + break; + } + } + + return null; + } + + @Override + public String getColumnName(int columnIndex) + { + return COLUMNS[columnIndex]; + } - return null; - } - - @Override - public String getColumnName( int columnIndex ) - { - return COLUMNS[ columnIndex ]; - } - /** * Iterates current tuners to get a tuner channel source for the frequency * specified in the channel config's source config object. - * + * * Returns null if no tuner can source the channel */ - public Source getSource( SourceConfigTuner config, int bandwidth ) + public Source getSource(SourceConfigTuner config, int bandwidth) { - TunerChannelSource retVal = null; - - TunerChannel tunerChannel = config.getTunerChannel(); - - tunerChannel.setBandwidth( bandwidth ); - - Iterator it = mTuners.iterator(); - - Tuner tuner; - - while( it.hasNext() && retVal == null ) - { - tuner = it.next(); - - try + TunerChannelSource retVal = null; + + TunerChannel tunerChannel = config.getTunerChannel(); + + tunerChannel.setBandwidth(bandwidth); + + Iterator it = mTuners.iterator(); + + Tuner tuner; + + while(it.hasNext() && retVal == null) + { + tuner = it.next(); + + try { - retVal = tuner.getChannel( tunerChannel ); + retVal = tuner.getSourceManager().getSource(tunerChannel); } - catch ( RejectedExecutionException ree ) - { - mLog.error( "couldn't provide tuner channel source", ree ); - } - catch ( SourceException e ) + catch(Exception e) { - mLog.error( "error obtaining channel from tuner [" + - tuner.getName() + "]", e ); + mLog.error("Error obtaining channel source from tuner [" + tuner.getName() + "]", e); } - } - - return retVal; + } + + return retVal; } - + } diff --git a/src/source/tuner/airspy/AirspyTuner.java b/src/source/tuner/airspy/AirspyTuner.java index 48c06d3b..649a4eae 100644 --- a/src/source/tuner/airspy/AirspyTuner.java +++ b/src/source/tuner/airspy/AirspyTuner.java @@ -17,19 +17,11 @@ ******************************************************************************/ package source.tuner.airspy; -import java.util.concurrent.RejectedExecutionException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sample.Listener; -import sample.complex.ComplexBuffer; -import source.SourceException; import source.tuner.Tuner; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; import source.tuner.TunerClass; -import source.tuner.TunerEvent; import source.tuner.TunerType; import source.tuner.airspy.AirspyTunerController.BoardID; @@ -79,50 +71,4 @@ public class AirspyTuner extends Tuner { return 13.0; } - - @Override - public TunerChannelSource getChannel( TunerChannel channel ) - throws RejectedExecutionException, SourceException - { - //TODO: this channel has a decimated sample rate of: - // 10.0 MSps = 10,000,000 / 208 = 48076.923 - // 5.0 MSps = 5,000,000 / 104 = 48076.923 - // 2.5 MSps = 2,500,000 / 52 = 48076.923 - //Consider implementing a fractional resampler to get a correct 48 kHz - //output sample rate - - TunerChannelSource source = getController().getChannel( this, channel ); - - if( source != null ) - { - broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) ); - } - - return source; - } - - @Override - public void releaseChannel( TunerChannelSource source ) - { - /* Unregister for receiving samples */ - removeListener( (Listener)source ); - - /* Tell the controller to release the channel and cleanup */ - if( source != null ) - { - getController().releaseChannel( source ); - } - } - - @Override - public void addListener( Listener listener ) - { - getController().addListener( listener ); - } - - @Override - public void removeListener( Listener listener ) - { - getController().removeListener( listener ); - } } diff --git a/src/source/tuner/airspy/AirspyTunerController.java b/src/source/tuner/airspy/AirspyTunerController.java index f8362bf6..490cd231 100644 --- a/src/source/tuner/airspy/AirspyTunerController.java +++ b/src/source/tuner/airspy/AirspyTunerController.java @@ -1,7 +1,5 @@ package source.tuner.airspy; -import dsp.filter.dc.DCRemovalFilter_RB; -import dsp.filter.hilbert.HilbertTransform; import org.apache.commons.io.EndianUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -9,16 +7,11 @@ import org.usb4java.Device; import org.usb4java.DeviceHandle; import org.usb4java.LibUsb; import org.usb4java.LibUsbException; -import org.usb4java.Transfer; -import org.usb4java.TransferCallback; -import sample.Broadcaster; -import sample.Listener; -import sample.complex.ComplexBuffer; import source.SourceException; import source.tuner.TunerController; import source.tuner.configuration.TunerConfiguration; import source.tuner.usb.USBTransferProcessor; -import util.ThreadPool; +import source.tuner.usb.USBTunerController; import javax.usb.UsbException; import java.nio.ByteBuffer; @@ -27,10 +20,6 @@ import java.text.DecimalFormat; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -import java.util.concurrent.LinkedTransferQueue; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; /** * SDR Trunk @@ -72,7 +61,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * POSSIBILITY OF SUCH DAMAGE. */ -public class AirspyTunerController extends TunerController +public class AirspyTunerController extends USBTunerController { public static final Gain LINEARITY_GAIN_DEFAULT = Gain.LINEARITY_14; public static final Gain SENSITIVITY_GAIN_DEFAULT = Gain.SENSITIVITY_10; @@ -193,6 +182,14 @@ public class AirspyTunerController extends TunerController USB_TRANSFER_BUFFER_SIZE); } + + @Override + protected USBTransferProcessor getUSBTransferProcessor() + { + return mUSBTransferProcessor; + } + + /** * Claims the USB interface. If another application currently has * the interface claimed, the USB_FORCE_CLAIM_INTERFACE setting @@ -1193,34 +1190,4 @@ public class AirspyTunerController extends TunerController return mValue; } } - - /** - * Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started. - */ - public void addListener(Listener listener) - { - if(mUSBTransferProcessor != null) - { - mUSBTransferProcessor.addListener(listener); - } - else - { - mLog.error("Couldn't add IQ buffer listener to Airspy tuner - processor is null"); - } - } - - /** - * Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners. - */ - public void removeListener(Listener listener) - { - if(mUSBTransferProcessor != null) - { - mUSBTransferProcessor.removeListener(listener); - } - else - { - mLog.error("Couldn't remove IQ buffer listener from Airspy tuner - processor is null"); - } - } } diff --git a/src/source/tuner/TunerChannelSource.java b/src/source/tuner/channel/DecimatingTunerChannelSource.java similarity index 89% rename from src/source/tuner/TunerChannelSource.java rename to src/source/tuner/channel/DecimatingTunerChannelSource.java index a41b22de..134601b1 100644 --- a/src/source/tuner/TunerChannelSource.java +++ b/src/source/tuner/channel/DecimatingTunerChannelSource.java @@ -16,12 +16,10 @@ * along with this program. If not, see * ******************************************************************************/ -package source.tuner; +package source.tuner.channel; -import channel.heartbeat.Heartbeat; -import channel.heartbeat.IHeartbeatProvider; import dsp.filter.FilterFactory; -import dsp.filter.Window.WindowType; +import dsp.filter.Window; import dsp.filter.cic.ComplexPrimeCICDecimate; import dsp.mixer.Oscillator; import org.slf4j.Logger; @@ -32,12 +30,13 @@ import sample.OverflowableTransferQueue; import sample.complex.Complex; import sample.complex.ComplexBuffer; import sample.real.IOverflowListener; -import source.ComplexSource; -import source.SourceException; import source.ISourceEventListener; -import source.ISourceEventProvider; -import source.SourceEvent; import source.ISourceEventProcessor; +import source.ISourceEventProvider; +import source.Source; +import source.SourceEvent; +import source.SourceException; +import source.tuner.Tuner; import java.util.ArrayList; import java.util.List; @@ -47,9 +46,9 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -public class TunerChannelSource extends ComplexSource implements ISourceEventProcessor, Listener +public class DecimatingTunerChannelSource extends TunerChannelSource { - private final static Logger mLog = LoggerFactory.getLogger(TunerChannelSource.class); + private final static Logger mLog = LoggerFactory.getLogger(DecimatingTunerChannelSource.class); //Maximum number of filled buffers for the blocking queue private static final int BUFFER_MAX_CAPACITY = 300; @@ -59,17 +58,14 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro private static int CHANNEL_RATE = 48000; private static int CHANNEL_PASS_FREQUENCY = 12000; - private static final Heartbeat HEARTBEAT = new Heartbeat(); private OverflowableTransferQueue mBuffer; - private Tuner mTuner; private TunerChannel mTunerChannel; private Oscillator mMixer; private ComplexPrimeCICDecimate mDecimationFilter; private Listener mListener; private ISourceEventProcessor mFrequencyChangeProcessor; - private Listener mHeartbeatListener; private DownstreamProcessor mDownstreamFrequencyEventProcessor = new DownstreamProcessor(); private ScheduledFuture mTaskHandle; @@ -93,28 +89,50 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro * and thus the tuner might no longer be able to source this channel once it * has been stopped. * - * @param tuner to obtain wideband IQ samples from * @param tunerChannel specifying the center frequency for the DDC * @throws RejectedExecutionException if the thread pool manager cannot * accept the decimation processing task * @throws SourceException if the tuner has an issue providing IQ samples */ - public TunerChannelSource(Tuner tuner, TunerChannel tunerChannel) throws RejectedExecutionException, SourceException + public DecimatingTunerChannelSource(Listener listener, TunerChannel tunerChannel, int inputSampleRate, + long frequency) { - mTuner = tuner; + super(listener, tunerChannel); + mTunerChannel = tunerChannel; - mTuner.getTunerController().addListener((ISourceEventProcessor) this); - mTunerFrequency = mTuner.getTunerController().getFrequency(); + mTunerFrequency = frequency; mBuffer = new OverflowableTransferQueue<>(BUFFER_MAX_CAPACITY, BUFFER_OVERFLOW_RESET_THRESHOLD); /* Setup the frequency translator to the current source frequency */ long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency(); - mMixer = new Oscillator(frequencyOffset, mTuner.getTunerController().getSampleRate()); + mMixer = new Oscillator(frequencyOffset, inputSampleRate); /* Fire a sample rate change event to setup the decimation chain */ - process(SourceEvent.sampleRateChange(mTuner.getTunerController().getSampleRate())); + try + { + process(SourceEvent.sampleRateChange(inputSampleRate)); + } + catch(SourceException se) + { + mLog.error("Error", se); + } + + } + + /** + * Changes the frequency correction value and broadcasts the change to the registered downstream listener. + * @param correction current frequency correction value. + */ + private void setFrequencyCorrection(int correction) + { + mChannelFrequencyCorrection = correction; + + updateMixerFrequencyOffset(); + + mDownstreamFrequencyEventProcessor.broadcast( + SourceEvent.channelFrequencyCorrectionChange(mChannelFrequencyCorrection)); } /** @@ -145,7 +163,7 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro mTaskHandle = executor.scheduleAtFixedRate(mDecimationProcessor, 0, 9, TimeUnit.MILLISECONDS); /* Finally, register to receive samples from the tuner */ - mTuner.addListener((Listener) this); + mSourceEventListener.receive(SourceEvent.startSampleStream(this)); } else { @@ -163,7 +181,7 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro { if(mRunning.compareAndSet(true, false)) { - mTuner.releaseChannel(this); + mSourceEventListener.receive(SourceEvent.stopSampleStream(this)); mDecimationProcessor.shutdown(); if(mTaskHandle != null) @@ -186,30 +204,6 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro @Override public void dispose() { - if(!mRunning.get()) - { - /* Tell the tuner to release/unregister our resources */ - mTuner.getTunerController().removeListener(this); - } - } - - /** - * Changes the frequency correction value and broadcasts the change to the registered downstream listener. - * @param correction current frequency correction value. - */ - private void setFrequencyCorrection(int correction) - { - mChannelFrequencyCorrection = correction; - - updateMixerFrequencyOffset(); - - mDownstreamFrequencyEventProcessor.broadcast( - SourceEvent.channelFrequencyCorrectionChange(mChannelFrequencyCorrection)); - } - - public Tuner getTuner() - { - return mTuner; } public TunerChannel getTunerChannel() @@ -234,7 +228,7 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro @Override public void setListener(Listener listener) { - /* Save a pointer to the listener so that if we have to change the + /* Save a pointer to the listener so that if we have to change the * decimation filter, we can re-add the listener */ mListener = listener; @@ -290,7 +284,7 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro /* Get new decimation filter */ mDecimationFilter = FilterFactory.getDecimationFilter(sampleRate, CHANNEL_RATE, 1, - CHANNEL_PASS_FREQUENCY, 60, WindowType.HAMMING); + CHANNEL_PASS_FREQUENCY, 60, Window.WindowType.HAMMING); /* re-add the original output listener */ mDecimationFilter.setListener(mListener); @@ -336,7 +330,7 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro /** * Implements ISourceEventProvider to remove the frequency change listener from receiving down-stream frequency * change events. - */ + */ @Override public void removeSourceEventListener() { @@ -354,25 +348,6 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro return mDownstreamFrequencyEventProcessor.getSourceEventListener(); } - /** - * Registers the listener to receive heartbeats from this source. - * @param listener to receive heartbeats - */ - @Override - public void setHeartbeatListener(Listener listener) - { - mHeartbeatListener = listener; - } - - /** - * Removes the currently registered heartbeat listener - */ - @Override - public void removeHeartbeatListener() - { - mHeartbeatListener = null; - } - /** * Managers frequency change requests and notifications from/to any downstream component. Downstream * components are those that receive samples from this tuner channel source. These downstream components will be @@ -500,10 +475,7 @@ public class TunerChannelSource extends ComplexSource implements ISourceEventPro { //Send a heartbeat every time this runs to allow downstream components to perform periodic //state monitoring functions on this thread - if(mHeartbeatListener != null) - { - mHeartbeatListener.receive(HEARTBEAT); - } + getHeartbeatManager().broadcast(); mBuffer.drainTo(mSampleBuffers, 20); diff --git a/src/source/tuner/TunerChannel.java b/src/source/tuner/channel/TunerChannel.java similarity index 98% rename from src/source/tuner/TunerChannel.java rename to src/source/tuner/channel/TunerChannel.java index f2b383b3..0fa851a0 100644 --- a/src/source/tuner/TunerChannel.java +++ b/src/source/tuner/channel/TunerChannel.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package source.tuner; +package source.tuner.channel; public class TunerChannel implements Comparable { diff --git a/src/source/tuner/channel/TunerChannelProvider.java b/src/source/tuner/channel/TunerChannelProvider.java new file mode 100644 index 00000000..56b85aa1 --- /dev/null +++ b/src/source/tuner/channel/TunerChannelProvider.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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 + * + ******************************************************************************/ +package source.tuner.channel; + +import java.util.concurrent.RejectedExecutionException; + +import source.SourceException; + +public interface TunerChannelProvider +{ + /** + * Returns a tuner frequency channel source, tuned to the correct frequency + * + * @param frequency - desired frequency + * + * @return - source for 48k sample rate + */ + public abstract TunerChannelSource getChannel( TunerChannel channel ) + throws RejectedExecutionException, SourceException; + + /** + * Releases the tuned channel resources + * + * @param channel - previously obtained tuner channel + */ + public abstract void releaseChannel( TunerChannelSource source ); + + +} diff --git a/src/source/tuner/channel/TunerChannelSource.java b/src/source/tuner/channel/TunerChannelSource.java new file mode 100644 index 00000000..54a2bdc3 --- /dev/null +++ b/src/source/tuner/channel/TunerChannelSource.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * 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 + * + ******************************************************************************/ +package source.tuner.channel; + +import dsp.filter.FilterFactory; +import dsp.filter.Window.WindowType; +import dsp.filter.cic.ComplexPrimeCICDecimate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sample.Buffer; +import sample.Listener; +import sample.complex.Complex; +import sample.complex.ComplexBuffer; +import sample.real.IOverflowListener; +import source.ComplexSource; +import source.SourceException; +import source.ISourceEventListener; +import source.ISourceEventProvider; +import source.SourceEvent; +import source.ISourceEventProcessor; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public abstract class TunerChannelSource extends ComplexSource implements ISourceEventProcessor, Listener +{ + private final static Logger mLog = LoggerFactory.getLogger(TunerChannelSource.class); + private TunerChannel mTunerChannel; + protected Listener mSourceEventListener; + + /** + * Requirements: + * 1. Provide complex buffer samples + * 2. Fetch complex buffer samples from subclass implementations (for distribution) + * 3. Provide heartbeat at each interval + * 4. Provide start/stop running + * 5. Provide support for downstream consumer source events (delegate to the sub class) + * 6. Support buffer overflow listeners + * + * @param sourceEventListener to receive source dispose request + * @param tunerChannel + */ + public TunerChannelSource(Listener sourceEventListener, TunerChannel tunerChannel) + { + mSourceEventListener = sourceEventListener; + } + + /** + * Tuner channel for this tuner channel source + */ + public TunerChannel getTunerChannel() + { + return mTunerChannel; + } + + /** + * Starts this tuner channel source producing sample stream. + */ + public void start() + { + if(mSourceEventListener != null) + { + mSourceEventListener.receive(SourceEvent.startSampleStream(this)); + } + + //TODO: broadcast center frequency and sample rate to downstream listeners. + } + + /** + * Stops this tuner channel source from producing a sample stream. Note: tuner channel sources are one-time usage + * only. Invoking this method will also tell the source manager to dispose of this source. + */ + public void stop() + { + if(mSourceEventListener != null) + { + mSourceEventListener.receive(SourceEvent.stopSampleStream(this)); + mSourceEventListener.receive(SourceEvent.sourceDisposeRequest(this)); + } + } + + @Override + public void reset() + { + //Reset is not valid for a tuner channel source - ignored + } +} diff --git a/src/source/tuner/ettus/B100Tuner.java b/src/source/tuner/ettus/B100Tuner.java deleted file mode 100644 index be5271f8..00000000 --- a/src/source/tuner/ettus/B100Tuner.java +++ /dev/null @@ -1,83 +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 - ******************************************************************************/ -package source.tuner.ettus; - -import java.util.concurrent.RejectedExecutionException; - -import source.SourceException; -import source.tuner.Tuner; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; -import source.tuner.TunerClass; -import source.tuner.TunerType; -import source.tuner.usb.USBTunerDevice; - -public class B100Tuner extends Tuner -{ - public B100Tuner( USBTunerDevice device ) - { - //TODO: this should extend a USBTuner class, so that we can push the - //complex sample listener and the frequency change listener up to that class - - super( "Ettus B100 with WBX Tuner", null ); - } - - public void dispose() - { - - } - - @Override - public TunerClass getTunerClass() - { - return TunerClass.ETTUS_USRP_B100; - } - - @Override - public TunerType getTunerType() - { - return TunerType.ETTUS_WBX; - } - - @Override - public double getSampleSize() - { - return 16.0; - } - - @Override - public TunerChannelSource getChannel( TunerChannel channel ) - throws RejectedExecutionException, SourceException - { - //TODO: pass this call to the tuner controller - return null; - } - - @Override - public void releaseChannel( TunerChannelSource source ) - { - //TODO: pass this call to the tuner controller - } - - @Override - public String getUniqueID() - { - // TODO Auto-generated method stub - return null; - } -} diff --git a/src/source/tuner/ettus/B100TunerEditorPanel.java b/src/source/tuner/ettus/B100TunerEditorPanel.java deleted file mode 100644 index ed30ed68..00000000 --- a/src/source/tuner/ettus/B100TunerEditorPanel.java +++ /dev/null @@ -1,44 +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 - ******************************************************************************/ -package source.tuner.ettus; - -import javax.swing.BorderFactory; -import javax.swing.JLabel; -import javax.swing.JPanel; - -import net.miginfocom.swing.MigLayout; -import settings.SettingsManager; - -public class B100TunerEditorPanel extends JPanel -{ - private static final long serialVersionUID = 1L; - - public B100TunerEditorPanel( B100Tuner tuner, SettingsManager settingsManager ) - { - init(); - } - - private void init() - { - setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) ); - - setBorder( BorderFactory.createTitledBorder( "Ettus B100 Tuner" ) ); - - add( new JLabel( "Note: SDRTrunk can only recognize the B100 at this time. It cannot use this tuner") ); - } -} diff --git a/src/source/tuner/fcd/FCDTuner.java b/src/source/tuner/fcd/FCDTuner.java index 9c32abfd..18c89fc6 100644 --- a/src/source/tuner/fcd/FCDTuner.java +++ b/src/source/tuner/fcd/FCDTuner.java @@ -17,35 +17,19 @@ ******************************************************************************/ package source.tuner.fcd; -import java.util.concurrent.RejectedExecutionException; - -import sample.Listener; -import sample.adapter.ShortAdapter; -import sample.complex.ComplexBuffer; -import source.SourceException; -import source.tuner.MixerTuner; -import source.tuner.MixerTunerDataLine; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; +import source.tuner.Tuner; import source.tuner.TunerClass; -import source.tuner.TunerEvent; import source.tuner.TunerType; -public class FCDTuner extends MixerTuner +public class FCDTuner extends Tuner { - public FCDTuner( MixerTunerDataLine mixerTDL, - FCDTunerController controller ) + public FCDTuner(FCDTunerController controller) { - super( controller.getConfiguration().toString(), - controller, - mixerTDL, - new ShortAdapter() ); + super( controller.getConfiguration().toString(), controller); } public void dispose() { - //TODO: release the mixer tuner data line as well - getController().dispose(); } @@ -77,36 +61,4 @@ public class FCDTuner extends MixerTuner { return 16.0; } - - @Override - public TunerChannelSource getChannel( TunerChannel tunerChannel ) - throws RejectedExecutionException, SourceException - { - TunerChannelSource source = getController().getChannel( this, tunerChannel ); - - if( source != null ) - { - broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) ); - } - - return source; - } - - /** - * Releases the tuned channel so that the tuner controller can tune to - * other frequencies as needed. - */ - @Override - public void releaseChannel( TunerChannelSource source ) - { - if( source != null ) - { - /* Unregister for receiving samples */ - removeListener( (Listener)source ); - - /* Tell the controller to release the channel and cleanup */ - /* This will release the channel as a frequency change listener */ - getController().releaseChannel( source ); - } - } } diff --git a/src/source/tuner/fcd/FCDTunerController.java b/src/source/tuner/fcd/FCDTunerController.java index f8dae0e8..3b907683 100644 --- a/src/source/tuner/fcd/FCDTunerController.java +++ b/src/source/tuner/fcd/FCDTunerController.java @@ -25,13 +25,19 @@ import org.usb4java.DeviceDescriptor; import org.usb4java.DeviceHandle; import org.usb4java.LibUsb; import org.usb4java.LibUsbException; +import sample.Listener; +import sample.adapter.ShortAdapter; +import sample.complex.ComplexBuffer; import source.SourceException; +import source.mixer.ComplexMixer; +import source.tuner.MixerTunerDataLine; import source.tuner.TunerClass; import source.tuner.TunerController; import source.tuner.TunerType; import source.tuner.configuration.TunerConfiguration; import source.tuner.fcd.proV1.FCD1TunerController.Block; +import javax.sound.sampled.AudioFormat; import javax.usb.UsbClaimException; import javax.usb.UsbException; import java.nio.ByteBuffer; @@ -54,6 +60,8 @@ public abstract class FCDTunerController extends TunerController private DeviceHandle mDeviceHandle; private FCDConfiguration mConfiguration = new FCDConfiguration(); + protected ComplexMixer mComplexMixer; + /** * Generic FCD tuner controller - contains functionality common across both @@ -64,11 +72,8 @@ public abstract class FCDTunerController extends TunerController * @param minTunableFrequency * @param maxTunableFrequency */ - public FCDTunerController(Device device, - DeviceDescriptor descriptor, - int sampleRate, - int minTunableFrequency, - int maxTunableFrequency) + public FCDTunerController(MixerTunerDataLine mixerTDL, Device device, DeviceDescriptor descriptor, String tunerName, + int minTunableFrequency, int maxTunableFrequency, AudioFormat audioFormat) { super(minTunableFrequency, maxTunableFrequency, DC_SPIKE_AVOID_BUFFER, USABLE_BANDWIDTH_PERCENT); mDevice = device; @@ -76,11 +81,45 @@ public abstract class FCDTunerController extends TunerController try { - mFrequencyController.setSampleRate(sampleRate); + mFrequencyController.setSampleRate((int)audioFormat.getSampleRate()); } catch(SourceException se) { - mLog.error("Error setting sample rate to [" + sampleRate + "]", se); + mLog.error("Error setting sample rate to [" + audioFormat.getSampleRate() + "]", se); + } + + mComplexMixer = new ComplexMixer( mixerTDL.getTargetDataLine(), audioFormat, tunerName, new ShortAdapter(), + mSampleBroadcaster); + } + + /** + * Overrides the super class functionality to auto-start the complex mixer and provide samples to listeners + */ + @Override + public void addComplexBufferListener(Listener listener) + { + boolean hasExistingListeners = hasComplexBufferListeners(); + + super.addComplexBufferListener(listener); + + if(!hasExistingListeners) + { + mComplexMixer.start(); + } + } + + /** + * Overrides the super class functionality to auto-stop the complex mixer and stop sample stream when there are no + * more registered listeners + */ + @Override + public void removeComplexBufferListener(Listener listener) + { + super.removeComplexBufferListener(listener); + + if(!hasComplexBufferListeners()) + { + mComplexMixer.stop(); } } diff --git a/src/source/tuner/fcd/proV1/FCD1TunerController.java b/src/source/tuner/fcd/proV1/FCD1TunerController.java index 9df0590e..143f820f 100644 --- a/src/source/tuner/fcd/proV1/FCD1TunerController.java +++ b/src/source/tuner/fcd/proV1/FCD1TunerController.java @@ -1,34 +1,28 @@ /******************************************************************************* * 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 ******************************************************************************/ package source.tuner.fcd.proV1; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import javax.usb.UsbClaimException; -import javax.usb.UsbException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.usb4java.Device; import org.usb4java.DeviceDescriptor; - import source.SourceException; +import source.tuner.MixerTunerDataLine; import source.tuner.MixerTunerType; import source.tuner.TunerClass; import source.tuner.TunerType; @@ -36,377 +30,381 @@ import source.tuner.configuration.TunerConfiguration; import source.tuner.fcd.FCDCommand; import source.tuner.fcd.FCDTunerController; +import javax.usb.UsbClaimException; +import javax.usb.UsbException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + public class FCD1TunerController extends FCDTunerController { - private final static Logger mLog = - LoggerFactory.getLogger( FCD1TunerController.class ); + private final static Logger mLog = LoggerFactory.getLogger(FCD1TunerController.class); - public static final int sMINIMUM_TUNABLE_FREQUENCY = 64000000; - public static final int sMAXIMUM_TUNABLE_FREQUENCY = 1700000000; - public static final int sSAMPLE_RATE = 96000; - - private double mDCCorrectionInPhase = 0.0; - private double mDCCorrectionQuadrature = 0.0; - private double mPhaseCorrection = 0.0; - private double mGainCorrection = 0.0; - private LNAGain mLNAGain; - private LNAEnhance mLNAEnhance; - private MixerGain mMixerGain; - private FCD1TunerConfiguration mTunerConfiguration; - private FCD1TunerEditor mEditor; + public static final int MINIMUM_TUNABLE_FREQUENCY = 64000000; + public static final int MAXIMUM_TUNABLE_FREQUENCY = 1700000000; + public static final int SAMPLE_RATE = 96000; - public FCD1TunerController( Device device, DeviceDescriptor descriptor ) - { - super( device, - descriptor, - (int)MixerTunerType.FUNCUBE_DONGLE_PRO.getAudioFormat().getSampleRate(), - sMINIMUM_TUNABLE_FREQUENCY, - sMAXIMUM_TUNABLE_FREQUENCY ); - } - - public void init() throws SourceException - { - super.init(); - - mFrequencyController.setSampleRate( sSAMPLE_RATE ); - - try - { - setFCDMode( Mode.APPLICATION ); - getPhaseAndGainCorrection(); - getDCIQCorrection(); - getLNAGainSetting(); - getLNAEnhanceSetting(); - getMixerGainSetting(); - - send( FCDCommand.APP_SET_MIXER_GAIN, 1l ); - } - catch( Exception e ) - { - e.printStackTrace(); - - throw new SourceException( "FCDTunerController error " + - "during construction", e ); - } - } - - public int getCurrentSampleRate() - { - return sSAMPLE_RATE; - } + private double mDCCorrectionInPhase = 0.0; + private double mDCCorrectionQuadrature = 0.0; + private double mPhaseCorrection = 0.0; + private double mGainCorrection = 0.0; + private LNAGain mLNAGain; + private LNAEnhance mLNAEnhance; + private MixerGain mMixerGain; + private FCD1TunerConfiguration mTunerConfiguration; + private FCD1TunerEditor mEditor; - @Override + public FCD1TunerController(MixerTunerDataLine mixerTDL, Device device, DeviceDescriptor descriptor) + { + super(mixerTDL, device, descriptor, MixerTunerType.FUNCUBE_DONGLE_PRO.getDisplayString(), MINIMUM_TUNABLE_FREQUENCY, + MAXIMUM_TUNABLE_FREQUENCY, MixerTunerType.FUNCUBE_DONGLE_PRO.getAudioFormat()); + } + + public void init() throws SourceException + { + super.init(); + + mFrequencyController.setSampleRate(SAMPLE_RATE); + + try + { + setFCDMode(Mode.APPLICATION); + getPhaseAndGainCorrection(); + getDCIQCorrection(); + getLNAGainSetting(); + getLNAEnhanceSetting(); + getMixerGainSetting(); + + send(FCDCommand.APP_SET_MIXER_GAIN, 1l); + } + catch(Exception e) + { + e.printStackTrace(); + + throw new SourceException("FCDTunerController error " + + "during construction", e); + } + } + + public int getCurrentSampleRate() + { + return SAMPLE_RATE; + } + + @Override public TunerClass getTunerClass() { - return TunerClass.FUNCUBE_DONGLE_PRO; + return TunerClass.FUNCUBE_DONGLE_PRO; } - @Override + @Override public TunerType getTunerType() { - return TunerType.FUNCUBE_DONGLE_PRO; + return TunerType.FUNCUBE_DONGLE_PRO; } - /** - * Get the tuner configuration - * - * @return current config or null if one hasn't been applied yet - */ - public FCD1TunerConfiguration getTunerConfiguration() - { - return mTunerConfiguration; - } - - @Override - public void apply( TunerConfiguration tunerConfig ) - throws SourceException + /** + * Get the tuner configuration + * + * @return current config or null if one hasn't been applied yet + */ + public FCD1TunerConfiguration getTunerConfiguration() { - FCD1TunerConfiguration config = (FCD1TunerConfiguration)tunerConfig; - - try - { - setFrequencyCorrection( config.getFrequencyCorrection() ); - setLNAGain( config.getLNAGain() ); - setLNAEnhance( config.getLNAEnhance() ); - setMixerGain( config.getMixerGain() ); - setDCCorrectionInPhase( config.getInphaseDCCorrection() ); - setDCCorrectionQuadrature( config.getQuadratureDCCorrection() ); - setGainCorrection( config.getGainCorrection() ); - setPhaseCorrection( config.getPhaseCorrection() ); - - //If we get to here without exception, store this config - mTunerConfiguration = config; - } - catch( Exception e) - { - //Re-cast any usb exceptions as source exceptions - throw new SourceException( "FCD 1 Controller encountered an " - + "exception while applying tuner config - " + - e.getLocalizedMessage() ); - } - - try - { - setFrequency( config.getFrequency() ); - } - catch( SourceException se ) - { - //Do nothing, we couldn't set the frequency - } - } + return mTunerConfiguration; + } - /** - * Gets the current LNA Gain value from the controller and stores it - */ - private void getLNAGainSetting() throws UsbClaimException, UsbException - { - ByteBuffer buffer = send( FCDCommand.APP_GET_LNA_GAIN ); - - buffer.order( ByteOrder.LITTLE_ENDIAN ); - - int gain = buffer.getInt( 2 ); + @Override + public void apply(TunerConfiguration tunerConfig) + throws SourceException + { + FCD1TunerConfiguration config = (FCD1TunerConfiguration)tunerConfig; - mLNAGain = LNAGain.valueOf( gain ); - } - - /** - * @return - current lna gain setting - */ - public LNAGain getLNAGain() - { - return mLNAGain; - } + try + { + setFrequencyCorrection(config.getFrequencyCorrection()); + setLNAGain(config.getLNAGain()); + setLNAEnhance(config.getLNAEnhance()); + setMixerGain(config.getMixerGain()); + setDCCorrectionInPhase(config.getInphaseDCCorrection()); + setDCCorrectionQuadrature(config.getQuadratureDCCorrection()); + setGainCorrection(config.getGainCorrection()); + setPhaseCorrection(config.getPhaseCorrection()); - /** - * Sets lna gain for the controller - * @param gain - * @throws UsbException - * @throws UsbClaimException - */ - public void setLNAGain( LNAGain gain ) - throws UsbException, UsbClaimException - { - send( FCDCommand.APP_SET_LNA_GAIN, gain.getSetting() ); - } - - /** - * @return - current phase correction setting - */ - public double getPhaseCorrection() - { - return mPhaseCorrection; - } + //If we get to here without exception, store this config + mTunerConfiguration = config; + } + catch(Exception e) + { + //Re-cast any usb exceptions as source exceptions + throw new SourceException("FCD 1 Controller encountered an " + + "exception while applying tuner config - " + + e.getLocalizedMessage()); + } - /** - * Sets the phase correction - * @param value - new phase correction - * @throws IllegalArgumentException for value outside limits (0.0 <> 1.0) - * @throws UsbClaimException - if cannot claim the FCD HID controller - * @throws UsbException - if there was a usb error - */ - public void setPhaseCorrection( double value ) - throws UsbClaimException, UsbException - { - if( value < -1.0 || value > 1.0 ) - { - throw new IllegalArgumentException( "Phase correction value [" + - value + "] outside limits ( -1.0 <> 1.0 )" ); - } - - mPhaseCorrection = value; - setPhaseAndGainCorrection(); - } + try + { + setFrequency(config.getFrequency()); + } + catch(SourceException se) + { + //Do nothing, we couldn't set the frequency + } + } - /** - * @return current gain correction setting - */ - public double getGainCorrection() - { - return mGainCorrection; - } + /** + * Gets the current LNA Gain value from the controller and stores it + */ + private void getLNAGainSetting() throws UsbClaimException, UsbException + { + ByteBuffer buffer = send(FCDCommand.APP_GET_LNA_GAIN); - /** - * - * @param value - gain correction value - * @throws IllegalArgumentException for value outside limits (0.0 <> 1.0) - * @throws UsbClaimException - if cannot claim the FCD HID controller - * @throws UsbException - if there was a usb error - */ - public void setGainCorrection( double value ) - throws UsbClaimException, UsbException - { - if( value < -1.0 || value > 1.0 ) - { - throw new IllegalArgumentException( "Gain correction value [" + - value + "] outside limits ( -1.0 <> 1.0 )" ); - } - - mGainCorrection = value; - setPhaseAndGainCorrection(); - } - - /** - * Sends the phase and gain correction values to FCD. - * - * The interface expects an argument with the SIGNED phase value in the first - * 16 bits and the UNSIGNED gain value in the second 16 bits, both in - * big-endian format. Since we're sending the argument in java little endian - * format, we place the phase in the high-order bits and the gain in the - * low-order bits, so that the send(command) function will reorder the bytes - * into big endian format, and place the arguments correctly. - * - * Gain correction values range -1.0 to 0.0 to 1.0 and applied to the dongle - * as values 0 to 65534 - * - * Phase correction values range -1.0 to 0.0 to 1.0 and applied to the - * dongle as signed values -32768 to 32767 - */ - private void setPhaseAndGainCorrection() throws UsbClaimException, - UsbException - { - //UNSIGNED short gain value - masked into a long to avoid sign-extension - long gain = (long)( ( 1.0 + mGainCorrection ) * Short.MAX_VALUE ); - - //Left shift gain to place value in upper 16 bits - long longGain = Long.rotateLeft( ( 0xFFFF & gain ), 16 ); + buffer.order(ByteOrder.LITTLE_ENDIAN); - //SIGNED short phase value - short phase = (short)( mPhaseCorrection * Short.MAX_VALUE ); + int gain = buffer.getInt(2); - //Merge the results - long correction = longGain | phase; + mLNAGain = LNAGain.valueOf(gain); + } - send( FCDCommand.APP_SET_IQ_CORRECTION, correction ); - } + /** + * @return - current lna gain setting + */ + public LNAGain getLNAGain() + { + return mLNAGain; + } - /** - * Retrieves the stored phase and gain correction values from the FCD. - * - * Note: testing shows that when the dongle is unplugged, any stored phase - * and gain correction values are reset. Reading the dongle after a fresh - * plugin shows the values reset. - * - * @throws UsbClaimException - * @throws UsbException - */ - private void getPhaseAndGainCorrection() throws UsbClaimException, - UsbException - { - ByteBuffer buffer = send( FCDCommand.APP_GET_IQ_CORRECTION ); - - buffer.order( ByteOrder.LITTLE_ENDIAN ); - - int correction = buffer.getInt( 2 ); - - /** - * Gain: mask the upper 16 phase bits and right shift to get the - * unsigned short value and then divide by 32768 to get the double - * value. We place the unsigned short value in an int to avoid sign - * issues. - */ - int gain = (int)( Long.rotateRight( correction & 0xFFFF0000, 16 ) ); + /** + * Sets lna gain for the controller + * + * @param gain + * @throws UsbException + * @throws UsbClaimException + */ + public void setLNAGain(LNAGain gain) + throws UsbException, UsbClaimException + { + send(FCDCommand.APP_SET_LNA_GAIN, gain.getSetting()); + } - mGainCorrection = ( (double)gain / (double)Short.MAX_VALUE ) - 1.0; + /** + * @return - current phase correction setting + */ + public double getPhaseCorrection() + { + return mPhaseCorrection; + } - /** - * Phase: mask the lower 16 bits and divide by 32768 to get the double - * value - */ - short phase = (short)( correction & 0x0000FFFF ); - - mPhaseCorrection = ( (double)phase / (double)Short.MAX_VALUE ); - } - - /** - * @return current DC correction for the I (inphase) component - */ - public double getDCCorrectionInPhase() - { - return mDCCorrectionInPhase; - } + /** + * Sets the phase correction + * + * @param value - new phase correction + * @throws IllegalArgumentException for value outside limits (0.0 <> 1.0) + * @throws UsbClaimException - if cannot claim the FCD HID controller + * @throws UsbException - if there was a usb error + */ + public void setPhaseCorrection(double value) + throws UsbClaimException, UsbException + { + if(value < -1.0 || value > 1.0) + { + throw new IllegalArgumentException("Phase correction value [" + + value + "] outside limits ( -1.0 <> 1.0 )"); + } - /** - * Sets DC correction for the I (inphase) component and sends the new value - * to the FCD controller - * @param value - new DC correction value for the inphase component - * @throws IllegalArgumentException for values outside limits (-1.0 <> 1.0) - * @throws UsbClaimException - if cannot claim the FCD HID controller - * @throws UsbException - if there was a usb error - */ - public void setDCCorrectionInPhase( double value ) - throws UsbClaimException, UsbException - { - if( value < -1.0 || value > 1.0 ) - { - throw new IllegalArgumentException( "DC inphase correction value " - + "[" + value + "] outside limits ( 0.0 <> 1.0 )" ); - } - - mDCCorrectionInPhase = value; - setDCIQCorrection(); - } + mPhaseCorrection = value; + setPhaseAndGainCorrection(); + } - /** - * @return current DC correction for the Q (quadrature) component - */ - public double getDCCorrectionQuadrature() - { - return mDCCorrectionQuadrature; - } + /** + * @return current gain correction setting + */ + public double getGainCorrection() + { + return mGainCorrection; + } - /** - * Sets the DC correction for the Q (quadrature) component and send the - * new value to the FCD controller - * @param value - new DC correction value for the quadrature component - * @throws IllegalArgumentException for values outside limits (-1.0 <> 1.0) - * @throws UsbClaimException - if cannot claim the FCD HID controller - * @throws UsbException - if there was a usb error - */ - public void setDCCorrectionQuadrature( double value ) - throws UsbClaimException, UsbException - { - if( value < -1.0 || value > 1.0 ) - { - throw new IllegalArgumentException( "DC quadrature correction " - + "value [" + value + "] outside limits ( 0.0 <> 1.0 )" ); - } - - mDCCorrectionQuadrature = value; - setDCIQCorrection(); - } + /** + * @param value - gain correction value + * @throws IllegalArgumentException for value outside limits (0.0 <> 1.0) + * @throws UsbClaimException - if cannot claim the FCD HID controller + * @throws UsbException - if there was a usb error + */ + public void setGainCorrection(double value) + throws UsbClaimException, UsbException + { + if(value < -1.0 || value > 1.0) + { + throw new IllegalArgumentException("Gain correction value [" + + value + "] outside limits ( -1.0 <> 1.0 )"); + } - /** - * Sends the I/Q DC offset correction values to FCD. - * - * The interface expects an argument with the signed inphase value in the - * first 16 bits and the signed quadrature value in the second 16 bits, - * both in big-endian format. - * - * Since we're sending the argument in java little endian format, we place - * the quadrature in the high-order bits and the inphase in the low-order - * bits, so that the send(command) function will reorder the bytes into big - * endian format, and place the arguments correctly. - * - * Both Inphase and Quadrature correction values range -1.0 to 0.0 to 1.0 - * and are applied to the dongle as signed short values -32768 to 0 to 32767 - */ - private void setDCIQCorrection() throws UsbClaimException, UsbException - { - //I & Q DC offset correction values are signed short values - short inphase = (short)( mDCCorrectionInPhase * Short.MAX_VALUE ); - short quadrature = (short)( mDCCorrectionQuadrature * Short.MAX_VALUE ); + mGainCorrection = value; + setPhaseAndGainCorrection(); + } + + /** + * Sends the phase and gain correction values to FCD. + * + * The interface expects an argument with the SIGNED phase value in the first + * 16 bits and the UNSIGNED gain value in the second 16 bits, both in + * big-endian format. Since we're sending the argument in java little endian + * format, we place the phase in the high-order bits and the gain in the + * low-order bits, so that the send(command) function will reorder the bytes + * into big endian format, and place the arguments correctly. + * + * Gain correction values range -1.0 to 0.0 to 1.0 and applied to the dongle + * as values 0 to 65534 + * + * Phase correction values range -1.0 to 0.0 to 1.0 and applied to the + * dongle as signed values -32768 to 32767 + */ + private void setPhaseAndGainCorrection() throws UsbClaimException, + UsbException + { + //UNSIGNED short gain value - masked into a long to avoid sign-extension + long gain = (long)((1.0 + mGainCorrection) * Short.MAX_VALUE); + + //Left shift gain to place value in upper 16 bits + long longGain = Long.rotateLeft((0xFFFF & gain), 16); + + //SIGNED short phase value + short phase = (short)(mPhaseCorrection * Short.MAX_VALUE); + + //Merge the results + long correction = longGain | phase; + + send(FCDCommand.APP_SET_IQ_CORRECTION, correction); + } + + /** + * Retrieves the stored phase and gain correction values from the FCD. + * + * Note: testing shows that when the dongle is unplugged, any stored phase + * and gain correction values are reset. Reading the dongle after a fresh + * plugin shows the values reset. + * + * @throws UsbClaimException + * @throws UsbException + */ + private void getPhaseAndGainCorrection() throws UsbClaimException, + UsbException + { + ByteBuffer buffer = send(FCDCommand.APP_GET_IQ_CORRECTION); + + buffer.order(ByteOrder.LITTLE_ENDIAN); + + int correction = buffer.getInt(2); + + /** + * Gain: mask the upper 16 phase bits and right shift to get the + * unsigned short value and then divide by 32768 to get the double + * value. We place the unsigned short value in an int to avoid sign + * issues. + */ + int gain = (int)(Long.rotateRight(correction & 0xFFFF0000, 16)); + + mGainCorrection = ((double)gain / (double)Short.MAX_VALUE) - 1.0; + + /** + * Phase: mask the lower 16 bits and divide by 32768 to get the double + * value + */ + short phase = (short)(correction & 0x0000FFFF); + + mPhaseCorrection = ((double)phase / (double)Short.MAX_VALUE); + } + + /** + * @return current DC correction for the I (inphase) component + */ + public double getDCCorrectionInPhase() + { + return mDCCorrectionInPhase; + } + + /** + * Sets DC correction for the I (inphase) component and sends the new value + * to the FCD controller + * + * @param value - new DC correction value for the inphase component + * @throws IllegalArgumentException for values outside limits (-1.0 <> 1.0) + * @throws UsbClaimException - if cannot claim the FCD HID controller + * @throws UsbException - if there was a usb error + */ + public void setDCCorrectionInPhase(double value) + throws UsbClaimException, UsbException + { + if(value < -1.0 || value > 1.0) + { + throw new IllegalArgumentException("DC inphase correction value " + + "[" + value + "] outside limits ( 0.0 <> 1.0 )"); + } + + mDCCorrectionInPhase = value; + setDCIQCorrection(); + } + + /** + * @return current DC correction for the Q (quadrature) component + */ + public double getDCCorrectionQuadrature() + { + return mDCCorrectionQuadrature; + } + + /** + * Sets the DC correction for the Q (quadrature) component and send the + * new value to the FCD controller + * + * @param value - new DC correction value for the quadrature component + * @throws IllegalArgumentException for values outside limits (-1.0 <> 1.0) + * @throws UsbClaimException - if cannot claim the FCD HID controller + * @throws UsbException - if there was a usb error + */ + public void setDCCorrectionQuadrature(double value) + throws UsbClaimException, UsbException + { + if(value < -1.0 || value > 1.0) + { + throw new IllegalArgumentException("DC quadrature correction " + + "value [" + value + "] outside limits ( 0.0 <> 1.0 )"); + } + + mDCCorrectionQuadrature = value; + setDCIQCorrection(); + } + + /** + * Sends the I/Q DC offset correction values to FCD. + * + * The interface expects an argument with the signed inphase value in the + * first 16 bits and the signed quadrature value in the second 16 bits, + * both in big-endian format. + * + * Since we're sending the argument in java little endian format, we place + * the quadrature in the high-order bits and the inphase in the low-order + * bits, so that the send(command) function will reorder the bytes into big + * endian format, and place the arguments correctly. + * + * Both Inphase and Quadrature correction values range -1.0 to 0.0 to 1.0 + * and are applied to the dongle as signed short values -32768 to 0 to 32767 + */ + private void setDCIQCorrection() throws UsbClaimException, UsbException + { + //I & Q DC offset correction values are signed short values + short inphase = (short)(mDCCorrectionInPhase * Short.MAX_VALUE); + short quadrature = (short)(mDCCorrectionQuadrature * Short.MAX_VALUE); + + //Mask the shorts into longs to preserve the sign bit and prepare + //for merging to a single 32-bit value + long maskedInphase = inphase & 0x0000FFFF; + long maskedQuadrature = quadrature & 0x0000FFFF; + + //Left shift quadrature to place value in upper 16 bits + long shiftedQuadrature = Long.rotateLeft(maskedQuadrature, 16); + + //Merge the results + long correction = shiftedQuadrature | maskedInphase; - //Mask the shorts into longs to preserve the sign bit and prepare - //for merging to a single 32-bit value - long maskedInphase = inphase & 0x0000FFFF; - long maskedQuadrature = quadrature & 0x0000FFFF; - - //Left shift quadrature to place value in upper 16 bits - long shiftedQuadrature = Long.rotateLeft( maskedQuadrature, 16 ); - - //Merge the results - long correction = shiftedQuadrature | maskedInphase; - // Log.info( "FCD1: setting iq correction," + // " inphase:" + inphase + // " masked inphase:" + maskedInphase + @@ -415,305 +413,305 @@ public class FCD1TunerController extends FCDTunerController // " shifted quadrature:" + shiftedQuadrature + // " correction:" + correction ); - send( FCDCommand.APP_SET_DC_CORRECTION, correction ); - } - - private void getDCIQCorrection() throws UsbClaimException, - UsbException - { - ByteBuffer buffer = send( FCDCommand.APP_GET_DC_CORRECTION ); - - buffer.order( ByteOrder.LITTLE_ENDIAN ); - - int correction = buffer.getInt( 2 ); + send(FCDCommand.APP_SET_DC_CORRECTION, correction); + } - /** - * Quadrature: mask the upper 16 bits and divide by 32768 to get the - * stored quadrature value. Cast the 16-bit value to a short to get - * the signed short value - */ - long shiftedQuadrature = correction & 0xFFFF0000; - long quadrature = Long.rotateRight( shiftedQuadrature, 16 ); + private void getDCIQCorrection() throws UsbClaimException, + UsbException + { + ByteBuffer buffer = send(FCDCommand.APP_GET_DC_CORRECTION); - mDCCorrectionQuadrature = ( (short)quadrature / (double)Short.MAX_VALUE ); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + int correction = buffer.getInt(2); + + /** + * Quadrature: mask the upper 16 bits and divide by 32768 to get the + * stored quadrature value. Cast the 16-bit value to a short to get + * the signed short value + */ + long shiftedQuadrature = correction & 0xFFFF0000; + long quadrature = Long.rotateRight(shiftedQuadrature, 16); + + mDCCorrectionQuadrature = ((short)quadrature / (double)Short.MAX_VALUE); + + /** + * InPhase: mask the lower 16 bits to get the short + * value and then divide by 32768 to get the stored inphase value. + * Cast the 16-bit value to a short to get the signed short value + */ + long inphase = correction & 0x0000FFFF; + mDCCorrectionInPhase = ((short)inphase / (double)Short.MAX_VALUE); - /** - * InPhase: mask the lower 16 bits to get the short - * value and then divide by 32768 to get the stored inphase value. - * Cast the 16-bit value to a short to get the signed short value - */ - long inphase = correction & 0x0000FFFF; - mDCCorrectionInPhase = ( (short)inphase / (double)Short.MAX_VALUE ); - // Log.info( "FCD1:" + // " correction:" + correction + // " Q:" + quadrature + // " I:" + inphase + // " QCorr:" + mDCCorrectionQuadrature + // " ICorr:" + mDCCorrectionInPhase ); - } - - private void getLNAEnhanceSetting() throws UsbClaimException, UsbException - { - ByteBuffer buffer = send( FCDCommand.APP_GET_LNA_ENHANCE ); - - buffer.order( ByteOrder.LITTLE_ENDIAN ); - - int enhance = buffer.getInt( 2 ); - - mLNAEnhance = LNAEnhance.valueOf( enhance ); - } - - public LNAEnhance getLNAEnhance() - { - return mLNAEnhance; - } - - public void setLNAEnhance( LNAEnhance enhance ) - throws UsbClaimException, UsbException - { - send( FCDCommand.APP_SET_LNA_ENHANCE, enhance.getSetting() ); - } - - private void getMixerGainSetting() throws UsbClaimException, UsbException - { - ByteBuffer buffer = send( FCDCommand.APP_GET_MIXER_GAIN ); - - buffer.order( ByteOrder.LITTLE_ENDIAN ); - - int gain = buffer.getInt( 2 ); - - mMixerGain = MixerGain.valueOf( gain ); - } - - public MixerGain getMixerGain() - { - return mMixerGain; - } - - public void setMixerGain( MixerGain gain ) throws UsbClaimException, UsbException - { - send( FCDCommand.APP_SET_MIXER_GAIN, gain.getSetting() ); - } - - public enum Block - { - CELLULAR_BAND_BLOCKED( "Blocked" ), - NO_BAND_BLOCK( "Unblocked" ), - UNKNOWN( "Unknown" ); - - private String mLabel; - - private Block( String label ) - { - mLabel = label; - } - - public String getLabel() - { - return mLabel; - } - - public static Block getBlock( String block ) - { - Block retVal = UNKNOWN; - - if( block.equalsIgnoreCase( "No blk" ) ) - { - retVal = NO_BAND_BLOCK; - } - else if( block.equalsIgnoreCase( "Cell blk" ) ) - { - retVal = CELLULAR_BAND_BLOCKED; - } - - return retVal; - } - } - - /** - * LNA Gain values suppported by the FCD Pro 1.0 - */ - public enum LNAGain - { - LNA_GAIN_MINUS_5_0( 0, "-5.0 dB" ), - LNA_GAIN_MINUS_2_5( 1, "-2.5 dB" ), - LNA_GAIN_PLUS_0_0( 4, "0.0 dB" ), - LNA_GAIN_PLUS_2_5( 5, "2.5 dB" ), - LNA_GAIN_PLUS_5_0( 6, "5.0 dB" ), - LNA_GAIN_PLUS_7_5( 7, "7.5 dB" ), - LNA_GAIN_PLUS_10_0( 8, "10.0 dB" ), - LNA_GAIN_PLUS_12_5( 9, "12.5 dB" ), - LNA_GAIN_PLUS_15_0( 10, "15.0 dB" ), - LNA_GAIN_PLUS_17_5( 11, "17.5 dB" ), - LNA_GAIN_PLUS_20_0( 12, "20.0 dB" ), - LNA_GAIN_PLUS_25_0( 13, "25.0 dB" ), - LNA_GAIN_PLUS_30_0( 14, "30.0 dB" ); - - private int mSetting; - private String mLabel; - - private LNAGain( int setting, String label ) - { - mSetting = setting; - mLabel = label; - } - - public static LNAGain valueOf( int setting ) - { - switch( setting ) - { - case 0: - return LNA_GAIN_MINUS_5_0; - case 1: - return LNA_GAIN_MINUS_2_5; - case 4: - return LNA_GAIN_PLUS_0_0; - case 5: - return LNA_GAIN_PLUS_2_5; - case 6: - return LNA_GAIN_PLUS_5_0; - case 7: - return LNA_GAIN_PLUS_7_5; - case 8: - return LNA_GAIN_PLUS_10_0; - case 9: - return LNA_GAIN_PLUS_12_5; - case 10: - return LNA_GAIN_PLUS_15_0; - case 11: - return LNA_GAIN_PLUS_17_5; - case 12: - return LNA_GAIN_PLUS_20_0; - case 13: - return LNA_GAIN_PLUS_25_0; - case 14: - return LNA_GAIN_PLUS_30_0; - default: - throw new IllegalArgumentException( "FCD 1.0 Tuner " - + "Controller - unrecognized LNA gain setting " - + "value [" + setting + "]" ); - } - } - - public int getSetting() - { - return mSetting; - } - - public String getLabel() - { - return mLabel; - } - - public String toString() - { - return getLabel(); - } } - /** - * LNA Enhance values suppported by the FCD Pro 1.0 - */ - public enum LNAEnhance + private void getLNAEnhanceSetting() throws UsbClaimException, UsbException { - LNA_ENHANCE_OFF( 0, "Off" ), - LNA_ENHANCE_0( 1, "0" ), - LNA_ENHANCE_1( 3, "1" ), - LNA_ENHANCE_2( 5, "2" ), - LNA_ENHANCE_3( 7, "3" ); - - private int mSetting; - private String mLabel; - - private LNAEnhance( int setting, String label ) - { - mSetting = setting; - mLabel = label; - } - - public static LNAEnhance valueOf( int setting ) - { - switch( setting ) - { - case 0: - return LNA_ENHANCE_OFF; - case 1: - return LNA_ENHANCE_0; - case 3: - return LNA_ENHANCE_1; - case 5: - return LNA_ENHANCE_2; - case 7: - return LNA_ENHANCE_3; - default: - throw new IllegalArgumentException( "FCD 1.0 Tuner " - + "Controller - unrecognized LNA enhance setting " - + "value [" + setting + "]" ); - } - } - - public int getSetting() - { - return mSetting; - } - - public String getLabel() - { - return mLabel; - } - - public String toString() - { - return getLabel(); - } + ByteBuffer buffer = send(FCDCommand.APP_GET_LNA_ENHANCE); + + buffer.order(ByteOrder.LITTLE_ENDIAN); + + int enhance = buffer.getInt(2); + + mLNAEnhance = LNAEnhance.valueOf(enhance); } - /** - * Mixer Gain values suppported by the FCD Pro 1.0 - */ - public enum MixerGain + public LNAEnhance getLNAEnhance() { - MIXER_GAIN_PLUS_4_0( 0, "4.0 dB" ), - MIXER_GAIN_PLUS_12_0( 1, "12.0 dB" ); - - private int mSetting; - private String mLabel; - - private MixerGain( int setting, String label ) - { - mSetting = setting; - mLabel = label; - } - - public static MixerGain valueOf( int setting ) - { - switch( setting ) - { - case 0: - return MIXER_GAIN_PLUS_4_0; - case 1: - return MIXER_GAIN_PLUS_12_0; - default: - throw new IllegalArgumentException( "FCD 1.0 Tuner " - + "Controller - unrecognized mixer gain setting " - + "value [" + setting + "]" ); - } - } - - public int getSetting() - { - return mSetting; - } - - public String getLabel() - { - return mLabel; - } - - public String toString() - { - return getLabel(); - } + return mLNAEnhance; + } + + public void setLNAEnhance(LNAEnhance enhance) + throws UsbClaimException, UsbException + { + send(FCDCommand.APP_SET_LNA_ENHANCE, enhance.getSetting()); + } + + private void getMixerGainSetting() throws UsbClaimException, UsbException + { + ByteBuffer buffer = send(FCDCommand.APP_GET_MIXER_GAIN); + + buffer.order(ByteOrder.LITTLE_ENDIAN); + + int gain = buffer.getInt(2); + + mMixerGain = MixerGain.valueOf(gain); + } + + public MixerGain getMixerGain() + { + return mMixerGain; + } + + public void setMixerGain(MixerGain gain) throws UsbClaimException, UsbException + { + send(FCDCommand.APP_SET_MIXER_GAIN, gain.getSetting()); + } + + public enum Block + { + CELLULAR_BAND_BLOCKED("Blocked"), + NO_BAND_BLOCK("Unblocked"), + UNKNOWN("Unknown"); + + private String mLabel; + + private Block(String label) + { + mLabel = label; + } + + public String getLabel() + { + return mLabel; + } + + public static Block getBlock(String block) + { + Block retVal = UNKNOWN; + + if(block.equalsIgnoreCase("No blk")) + { + retVal = NO_BAND_BLOCK; + } + else if(block.equalsIgnoreCase("Cell blk")) + { + retVal = CELLULAR_BAND_BLOCKED; + } + + return retVal; + } + } + + /** + * LNA Gain values suppported by the FCD Pro 1.0 + */ + public enum LNAGain + { + LNA_GAIN_MINUS_5_0(0, "-5.0 dB"), + LNA_GAIN_MINUS_2_5(1, "-2.5 dB"), + LNA_GAIN_PLUS_0_0(4, "0.0 dB"), + LNA_GAIN_PLUS_2_5(5, "2.5 dB"), + LNA_GAIN_PLUS_5_0(6, "5.0 dB"), + LNA_GAIN_PLUS_7_5(7, "7.5 dB"), + LNA_GAIN_PLUS_10_0(8, "10.0 dB"), + LNA_GAIN_PLUS_12_5(9, "12.5 dB"), + LNA_GAIN_PLUS_15_0(10, "15.0 dB"), + LNA_GAIN_PLUS_17_5(11, "17.5 dB"), + LNA_GAIN_PLUS_20_0(12, "20.0 dB"), + LNA_GAIN_PLUS_25_0(13, "25.0 dB"), + LNA_GAIN_PLUS_30_0(14, "30.0 dB"); + + private int mSetting; + private String mLabel; + + private LNAGain(int setting, String label) + { + mSetting = setting; + mLabel = label; + } + + public static LNAGain valueOf(int setting) + { + switch(setting) + { + case 0: + return LNA_GAIN_MINUS_5_0; + case 1: + return LNA_GAIN_MINUS_2_5; + case 4: + return LNA_GAIN_PLUS_0_0; + case 5: + return LNA_GAIN_PLUS_2_5; + case 6: + return LNA_GAIN_PLUS_5_0; + case 7: + return LNA_GAIN_PLUS_7_5; + case 8: + return LNA_GAIN_PLUS_10_0; + case 9: + return LNA_GAIN_PLUS_12_5; + case 10: + return LNA_GAIN_PLUS_15_0; + case 11: + return LNA_GAIN_PLUS_17_5; + case 12: + return LNA_GAIN_PLUS_20_0; + case 13: + return LNA_GAIN_PLUS_25_0; + case 14: + return LNA_GAIN_PLUS_30_0; + default: + throw new IllegalArgumentException("FCD 1.0 Tuner " + + "Controller - unrecognized LNA gain setting " + + "value [" + setting + "]"); + } + } + + public int getSetting() + { + return mSetting; + } + + public String getLabel() + { + return mLabel; + } + + public String toString() + { + return getLabel(); + } + } + + /** + * LNA Enhance values suppported by the FCD Pro 1.0 + */ + public enum LNAEnhance + { + LNA_ENHANCE_OFF(0, "Off"), + LNA_ENHANCE_0(1, "0"), + LNA_ENHANCE_1(3, "1"), + LNA_ENHANCE_2(5, "2"), + LNA_ENHANCE_3(7, "3"); + + private int mSetting; + private String mLabel; + + private LNAEnhance(int setting, String label) + { + mSetting = setting; + mLabel = label; + } + + public static LNAEnhance valueOf(int setting) + { + switch(setting) + { + case 0: + return LNA_ENHANCE_OFF; + case 1: + return LNA_ENHANCE_0; + case 3: + return LNA_ENHANCE_1; + case 5: + return LNA_ENHANCE_2; + case 7: + return LNA_ENHANCE_3; + default: + throw new IllegalArgumentException("FCD 1.0 Tuner " + + "Controller - unrecognized LNA enhance setting " + + "value [" + setting + "]"); + } + } + + public int getSetting() + { + return mSetting; + } + + public String getLabel() + { + return mLabel; + } + + public String toString() + { + return getLabel(); + } + } + + /** + * Mixer Gain values suppported by the FCD Pro 1.0 + */ + public enum MixerGain + { + MIXER_GAIN_PLUS_4_0(0, "4.0 dB"), + MIXER_GAIN_PLUS_12_0(1, "12.0 dB"); + + private int mSetting; + private String mLabel; + + private MixerGain(int setting, String label) + { + mSetting = setting; + mLabel = label; + } + + public static MixerGain valueOf(int setting) + { + switch(setting) + { + case 0: + return MIXER_GAIN_PLUS_4_0; + case 1: + return MIXER_GAIN_PLUS_12_0; + default: + throw new IllegalArgumentException("FCD 1.0 Tuner " + + "Controller - unrecognized mixer gain setting " + + "value [" + setting + "]"); + } + } + + public int getSetting() + { + return mSetting; + } + + public String getLabel() + { + return mLabel; + } + + public String toString() + { + return getLabel(); + } } } diff --git a/src/source/tuner/fcd/proplusV2/FCD2TunerController.java b/src/source/tuner/fcd/proplusV2/FCD2TunerController.java index f2173ceb..f6c39834 100644 --- a/src/source/tuner/fcd/proplusV2/FCD2TunerController.java +++ b/src/source/tuner/fcd/proplusV2/FCD2TunerController.java @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import org.usb4java.Device; import org.usb4java.DeviceDescriptor; import source.SourceException; +import source.tuner.MixerTunerDataLine; import source.tuner.MixerTunerType; import source.tuner.TunerClass; import source.tuner.TunerType; @@ -41,11 +42,10 @@ public class FCD2TunerController extends FCDTunerController public static final int MAXIMUM_TUNABLE_FREQUENCY = 2050000000; public static final int SAMPLE_RATE = 192000; - public FCD2TunerController(Device device, DeviceDescriptor descriptor) + public FCD2TunerController(MixerTunerDataLine mixerTDL, Device device, DeviceDescriptor descriptor) { - super(device, descriptor, - (int)MixerTunerType.FUNCUBE_DONGLE_PRO_PLUS.getAudioFormat().getSampleRate(), - MINIMUM_TUNABLE_FREQUENCY, MAXIMUM_TUNABLE_FREQUENCY); + super(mixerTDL, device, descriptor, MixerTunerType.FUNCUBE_DONGLE_PRO_PLUS.getDisplayString(), + MINIMUM_TUNABLE_FREQUENCY, MAXIMUM_TUNABLE_FREQUENCY, MixerTunerType.FUNCUBE_DONGLE_PRO.getAudioFormat()); } public void init() throws SourceException diff --git a/src/source/tuner/frequency/DCTrackingSourceControl.java b/src/source/tuner/frequency/DCTrackingSourceControl.java index 09b48831..de042699 100644 --- a/src/source/tuner/frequency/DCTrackingSourceControl.java +++ b/src/source/tuner/frequency/DCTrackingSourceControl.java @@ -113,7 +113,7 @@ public class DCTrackingSourceControl extends Module } @Override - public void start(ScheduledExecutorService executor) + public void start() { } diff --git a/src/source/tuner/frequency/FrequencyController.java b/src/source/tuner/frequency/FrequencyController.java index 7403ad64..86723b10 100644 --- a/src/source/tuner/frequency/FrequencyController.java +++ b/src/source/tuner/frequency/FrequencyController.java @@ -95,6 +95,16 @@ public class FrequencyController setFrequency(frequency, true); } + /** + * Indicates if the specified frequency can be tuned (ie is within min/max frequency) by this controller. + * @param frequency to evaluate + * @return true if the frequency falls within the tuning range of this controller + */ + public boolean canTune(long frequency) + { + return getMinimumFrequency() <= frequency && frequency <= getMaximumFrequency(); + } + /** * Set frequency with optional broadcast of frequency change event. This * method supports changing the frequency correction value without @@ -257,5 +267,10 @@ public class FrequencyController * Gets the current bandwidth setting of the device */ public int getCurrentSampleRate() throws SourceException; + + /** + * Indicates if this tunable can tune the frequency + */ + public boolean canTune(long frequency); } } diff --git a/src/source/tuner/hackrf/HackRFTuner.java b/src/source/tuner/hackrf/HackRFTuner.java index 2194a7de..fa0ff210 100644 --- a/src/source/tuner/hackrf/HackRFTuner.java +++ b/src/source/tuner/hackrf/HackRFTuner.java @@ -17,19 +17,12 @@ ******************************************************************************/ package source.tuner.hackrf; -import java.util.concurrent.RejectedExecutionException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sample.Listener; -import sample.complex.ComplexBuffer; import source.SourceException; import source.tuner.Tuner; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; import source.tuner.TunerClass; -import source.tuner.TunerEvent; import source.tuner.TunerType; import source.tuner.hackrf.HackRFTunerController.BoardID; @@ -49,7 +42,6 @@ public class HackRFTuner extends Tuner public void dispose() { - //TODO: dispose of something here } @Override @@ -70,33 +62,6 @@ public class HackRFTuner extends Tuner return 11.0; } - @Override - public TunerChannelSource getChannel( TunerChannel channel ) - throws RejectedExecutionException, SourceException - { - TunerChannelSource source = getController().getChannel( this, channel ); - - if( source != null ) - { - broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) ); - } - - return source; - } - - @Override - public void releaseChannel( TunerChannelSource source ) - { - /* Unregister for receiving samples */ - removeListener( (Listener)source ); - - /* Tell the controller to release the channel and cleanup */ - if( source != null ) - { - getController().releaseChannel( source ); - } - } - @Override public String getUniqueID() { @@ -111,16 +76,4 @@ public class HackRFTuner extends Tuner return BoardID.HACKRF_ONE.getLabel(); } - - @Override - public void addListener( Listener listener ) - { - getController().addListener( listener ); - } - - @Override - public void removeListener( Listener listener ) - { - getController().removeListener( listener ); - } } diff --git a/src/source/tuner/hackrf/HackRFTunerController.java b/src/source/tuner/hackrf/HackRFTunerController.java index 1741bfaf..812f37f5 100644 --- a/src/source/tuner/hackrf/HackRFTunerController.java +++ b/src/source/tuner/hackrf/HackRFTunerController.java @@ -69,6 +69,7 @@ import source.SourceException; import source.tuner.TunerController; import source.tuner.configuration.TunerConfiguration; import source.tuner.usb.USBTransferProcessor; +import source.tuner.usb.USBTunerController; import javax.usb.UsbException; import java.nio.ByteBuffer; @@ -76,7 +77,7 @@ import java.nio.ByteOrder; import java.util.Arrays; import java.util.concurrent.LinkedTransferQueue; -public class HackRFTunerController extends TunerController +public class HackRFTunerController extends USBTunerController { private final static Logger mLog = LoggerFactory.getLogger(HackRFTunerController.class); @@ -160,6 +161,12 @@ public class HackRFTunerController extends TunerController mUSBTransferProcessor = new USBTransferProcessor(name, mDeviceHandle, mSampleAdapter, USB_TRANSFER_BUFFER_SIZE); } + @Override + protected USBTransferProcessor getUSBTransferProcessor() + { + return mUSBTransferProcessor; + } + /** * Claims the USB interface. If another application currently has * the interface claimed, the USB_FORCE_CLAIM_INTERFACE setting @@ -874,23 +881,4 @@ public class HackRFTunerController extends TunerController return sb.toString(); } } - - /** - * Adds a sample listener. If the buffer processing thread is - * not currently running, starts it running in a new thread. - */ - public void addListener(Listener listener) - { - mUSBTransferProcessor.addListener(listener); - } - - /** - * Removes the sample listener. If this is the last registered listener, - * shuts down the buffer processing thread. - */ - public void removeListener(Listener listener) - { - mUSBTransferProcessor.removeListener(listener); - } - } diff --git a/src/source/tuner/manager/AbstractSourceManager.java b/src/source/tuner/manager/AbstractSourceManager.java new file mode 100644 index 00000000..9c373d2d --- /dev/null +++ b/src/source/tuner/manager/AbstractSourceManager.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * 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 + * + ******************************************************************************/ +package source.tuner.manager; + +import sample.Broadcaster; +import sample.Listener; +import sample.complex.ComplexBuffer; +import sample.complex.IComplexBufferProvider; +import source.SourceEvent; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; + +import java.util.List; + +/** + * Interface to define the functionality of a source manager for handling tuner channel management, complex buffer + * listeners, and source event listeners. + */ +public abstract class AbstractSourceManager implements IComplexBufferProvider, Listener +{ + protected Broadcaster mComplexBufferBroadcaster = new Broadcaster<>(); + + /** + * Indicates if this source manager can tune (ie provide a source for) the specified tuner channel + */ + public abstract boolean canTune(TunerChannel tunerChannel); + + /** + * List of tuner channels being sourced by this source manager + */ + public abstract List getChannels(); + + /** + * Obtains a source for the tuner channel or returns null if the channel cannot be sourced by this tuner. + * Note: use the canTune() method to check if a tuner channel can be sourced/tuned prior to accessing this method. + * + * @param tunerChannel for requested source + * @return tuner channel source or null + */ + public abstract TunerChannelSource getSource(TunerChannel tunerChannel); + + + /** + * Releases the source and all related resources + */ + public abstract void releaseSource(TunerChannelSource source); + + /** + * Adds the listener to receive source events from this source manager + * + * @param sourceEventListener to add + */ + public abstract void addSourceEventListener(Listener sourceEventListener); + + /** + * Removes the listener from receiving source events from this source manager + * @param sourceEventListener to remove + */ + public abstract void removeSourceEventListener(Listener sourceEventListener); + + /** + * Adds the listener to receive complex buffer samples + */ + @Override + public void addComplexBufferListener(Listener listener) + { + mComplexBufferBroadcaster.addListener(listener); + } + + /** + * Removes the listener from receiving complex buffer samples + */ + @Override + public void removeComplexBufferListener(Listener listener) + { + mComplexBufferBroadcaster.removeListener(listener); + } + + /** + * Indicates if there are any complex buffer listeners registered with this source manager + */ + @Override + public boolean hasComplexBufferListeners() + { + return mComplexBufferBroadcaster.hasListeners(); + } + + /** + * Broadcasts the buffer to any registered listeners + */ + protected void broadcast(ComplexBuffer complexBuffer) + { + mComplexBufferBroadcaster.broadcast(complexBuffer); + } +} diff --git a/src/source/tuner/manager/TunerSourceManager.java b/src/source/tuner/manager/TunerSourceManager.java new file mode 100644 index 00000000..fb6856bd --- /dev/null +++ b/src/source/tuner/manager/TunerSourceManager.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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 + * + ******************************************************************************/ +package source.tuner.manager; + +import dsp.filter.channelizer.PolyphaseChannelManager; +import sample.Listener; +import source.SourceEvent; +import source.tuner.channel.TunerChannel; +import source.tuner.channel.TunerChannelSource; +import source.tuner.TunerController; + +import java.util.List; + +public class TunerSourceManager extends AbstractSourceManager +{ + private PolyphaseChannelManager mPolyphaseChannelManager; + private TunerController mTunerController; + + public TunerSourceManager(TunerController tunerController) + { + mTunerController = tunerController; + } + + //TODO: broadcast a tuner event each time we add a new channel to the polyphase manager + + @Override + public boolean canTune(TunerChannel tunerChannel) + { + return false; + } + + @Override + public List getChannels() + { + return null; + } + + @Override + public TunerChannelSource getSource(TunerChannel tunerChannel) + { + return null; + } + + @Override + public void releaseSource(TunerChannelSource source) + { + + } + + @Override + public void addSourceEventListener(Listener sourceEventListener) + { + + } + + @Override + public void removeSourceEventListener(Listener sourceEventListener) + { + + } + + @Override + public void receive(SourceEvent sourceEvent) + { + + } +} diff --git a/src/source/tuner/rtl/RTL2832Tuner.java b/src/source/tuner/rtl/RTL2832Tuner.java index 20b746ea..dceece1c 100644 --- a/src/source/tuner/rtl/RTL2832Tuner.java +++ b/src/source/tuner/rtl/RTL2832Tuner.java @@ -1,161 +1,75 @@ /******************************************************************************* * SDR Trunk * Copyright (C) 2014-2016 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 ******************************************************************************/ package source.tuner.rtl; -import java.util.concurrent.RejectedExecutionException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.usb4java.LibUsbException; - -import sample.Listener; -import sample.complex.ComplexBuffer; import source.SourceException; import source.tuner.Tuner; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; import source.tuner.TunerClass; -import source.tuner.TunerEvent; import source.tuner.TunerType; -import source.tuner.rtl.RTL2832TunerController.SampleRate; public class RTL2832Tuner extends Tuner { - private final static Logger mLog = - LoggerFactory.getLogger( RTL2832Tuner.class ); + private final static Logger mLog = LoggerFactory.getLogger(RTL2832Tuner.class); - private TunerClass mTunerClass; + private TunerClass mTunerClass; - public RTL2832Tuner( TunerClass tunerClass, - RTL2832TunerController controller ) - throws SourceException - { - super( tunerClass.getVendorDeviceLabel() + "/" + - controller.getTunerType().getLabel() + " " + - controller.getUniqueID(), controller ); - - mTunerClass = tunerClass; - } - - public void dispose() - { - //TODO: dispose of something here - } - - public RTL2832TunerController getController() - { - return (RTL2832TunerController)getTunerController(); - } + public RTL2832Tuner(TunerClass tunerClass, RTL2832TunerController controller) throws SourceException + { + super(tunerClass.getVendorDeviceLabel() + "/" + controller.getTunerType().getLabel() + " " + + controller.getUniqueID(), controller); - @Override + mTunerClass = tunerClass; + } + + public void dispose() + { + } + + public RTL2832TunerController getController() + { + return (RTL2832TunerController)getTunerController(); + } + + @Override public String getUniqueID() { - return getController().getUniqueID(); + return getController().getUniqueID(); } - @Override + @Override public TunerClass getTunerClass() { - return mTunerClass; + return mTunerClass; } - @Override + @Override public TunerType getTunerType() { - return getController().getTunerType(); + return getController().getTunerType(); } - - public void setSampleRate( SampleRate sampleRate ) throws SourceException - { - try - { - getController().setSampleRate( sampleRate ); - } - catch( LibUsbException e ) - { - throw new SourceException( "RTL2832 Tuner - error setting " - + "sample rate", e ); - } - } - - @Override - public double getSampleSize() - { - //Note: although sample size is 8, we set it to 11 to align with the - //actual noise floor. - return 11.0; - } - public void setFrequency( int frequency ) throws SourceException - { - getController().setFrequency( frequency ); - } - - @Override - public TunerChannelSource getChannel( TunerChannel channel ) - throws RejectedExecutionException, - SourceException - { - TunerChannelSource source = null; - - try - { - source = getController().getChannel( this, channel ); - - if( source != null ) - { - broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) ); - } - } - catch( Exception e ) - { - mLog.error( "couldn't provide source channel", e ); - } - - return source; - } - - /** - * Releases the tuned channel so that the tuner controller can tune to - * other frequencies as needed. - */ - @Override - public void releaseChannel( TunerChannelSource source ) + @Override + public double getSampleSize() { - /* Unregister for receiving samples */ - removeListener( (Listener)source ); - - /* Tell the controller to release the channel and cleanup */ - if( source != null ) - { - getController().releaseChannel( source ); - } + //Note: although sample size is 8, we set it to 11 to align with the + //actual noise floor. + return 11.0; } - - @Override - public void addListener( Listener listener ) - { - getController().addListener( listener ); - } - - @Override - public void removeListener( Listener listener ) - { - getController().removeListener( listener ); - } } diff --git a/src/source/tuner/rtl/RTL2832TunerController.java b/src/source/tuner/rtl/RTL2832TunerController.java index 7666890b..6102f951 100644 --- a/src/source/tuner/rtl/RTL2832TunerController.java +++ b/src/source/tuner/rtl/RTL2832TunerController.java @@ -38,6 +38,7 @@ import source.tuner.TunerController; import source.tuner.TunerManager; import source.tuner.TunerType; import source.tuner.usb.USBTransferProcessor; +import source.tuner.usb.USBTunerController; import javax.usb.UsbDisconnectedException; import javax.usb.UsbException; @@ -47,7 +48,7 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; -public abstract class RTL2832TunerController extends TunerController +public abstract class RTL2832TunerController extends USBTunerController { private final static Logger mLog = LoggerFactory.getLogger(RTL2832TunerController.class); @@ -163,6 +164,12 @@ public abstract class RTL2832TunerController extends TunerController USB_TRANSFER_BUFFER_SIZE); } + @Override + protected USBTransferProcessor getUSBTransferProcessor() + { + return mUSBTransferProcessor; + } + /** * Claims the USB interface. Attempts to detach the active kernel driver * if one is currently attached. @@ -449,7 +456,7 @@ public abstract class RTL2832TunerController extends TunerController { if(mUSBTransferProcessor != null) { - mUSBTransferProcessor.removeAllListeners(); + mUSBTransferProcessor.removeListener(); TunerManager.LIBUSB_TRANSFER_PROCESSOR.unregisterTransferProcessor(mUSBTransferProcessor); } @@ -1490,20 +1497,33 @@ public abstract class RTL2832TunerController extends TunerController } /** - * Adds a sample listener. If the USB transfer processor is not currently running, it will auto-start + * Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started. */ - public void addListener(Listener listener) + @Override + public void addComplexBufferListener(Listener listener) { - mUSBTransferProcessor.addListener(listener); + boolean hasExistingListeners = hasComplexBufferListeners(); + + super.addComplexBufferListener(listener); + + if(!hasExistingListeners) + { + mUSBTransferProcessor.setListener(this); + } } /** - * Removes the sample listener. If this is the last registered listener, the USB transfer processor will - * halt buffer processing + * Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners. */ - public void removeListener(Listener listener) + @Override + public void removeComplexBufferListener(Listener listener) { - mUSBTransferProcessor.removeListener(listener); + super.removeComplexBufferListener(listener); + + if(!hasComplexBufferListeners()) + { + mUSBTransferProcessor.removeListener(); + } } /** diff --git a/src/source/tuner/test/TestTuner.java b/src/source/tuner/test/TestTuner.java index 476c6174..f43e646b 100644 --- a/src/source/tuner/test/TestTuner.java +++ b/src/source/tuner/test/TestTuner.java @@ -18,21 +18,12 @@ ******************************************************************************/ package source.tuner.test; -import dsp.filter.channelizer.PolyphaseChannelManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sample.Listener; -import sample.complex.ComplexBuffer; -import source.Source; -import source.SourceException; import source.tuner.Tuner; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; import source.tuner.TunerClass; import source.tuner.TunerType; -import java.util.concurrent.RejectedExecutionException; - /** * Testing tuner that implements an internal oscillator to output a unity gain tone at a specified frequency offset * from a configurable center tune frequency and sample rate @@ -43,13 +34,9 @@ public class TestTuner extends Tuner private static int mInstanceCounter = 1; private final int mInstanceID = mInstanceCounter++; - private PolyphaseChannelManager mPolyphaseChannelManager; - public TestTuner() { super("Test Tuner", new TestTunerController()); - - mPolyphaseChannelManager = new PolyphaseChannelManager(this); } /** @@ -58,41 +45,11 @@ public class TestTuner extends Tuner * Note: this is a temporary method until the tuner controller interface can be updated with the start(listener) * and stop() methods. */ - private TestTunerController getTestTunerController() + public TestTunerController getTunerController() { return (TestTunerController)getTunerController(); } - /** - * Sets the center tuned frequency for this tuner - * @param frequency - * @throws SourceException - */ - public void setFrequency(long frequency) throws SourceException - { - getTunerController().setFrequency(frequency); - } - - public void setToneFrequency(long frequency) - { - getTestTunerController().setToneFrequency(frequency); - } - - public long getToneFrequency() - { - return getTestTunerController().getToneFrequency(); - } - - public void setSampleRate(int sampleRate) throws SourceException - { - getTestTunerController().setSampleRate(sampleRate); - } - - public int getSampleRate() - { - return getTestTunerController().getSampleRate(); - } - @Override public String getUniqueID() { @@ -116,62 +73,4 @@ public class TestTuner extends Tuner { return 16.0; } - - /** - * Creates a polyphase channel source. The provided channel is a one-use channel that can be commanded to start - * and stop processing via the source event interface. Once stopped, the channel is deregistered from this tuner - * and is no longer usable -- a new channel source must be requested from the tuner. - * - * @param tunerChannel identifying the channel center frequency and bandwidth - * @return channel source or null if the channel source cannot be provided by this tuner - */ - public Source getChannelSource(TunerChannel tunerChannel) - { - return mPolyphaseChannelManager.getChannel(tunerChannel); - } - - @Override - public TunerChannelSource getChannel(TunerChannel channel) throws RejectedExecutionException, SourceException - { - mLog.error("This method is deprecated in this test tuner implementation"); - throw new IllegalStateException("Method deprecated - this test tuner cannot provide a TunerChannelSource"); - } - - @Override - public void releaseChannel(TunerChannelSource source) - { - mLog.error("This method is deprecated in this test tuner implementation"); - } - - /** - * Adds the listener to receive complex sample buffers and auto-starts the sample stream if this is the first - * registered listener. - */ - @Override - public void addListener(Listener listener) - { - boolean isRunning = hasListeners(); - - super.addListener(listener); - - if(!isRunning) - { - getTestTunerController().start(getSampleBroadcaster()); - } - } - - /** - * Removes the listener from receiving complex sample buffers and auto-stops the sample stream when there are - * no more listeners. - */ - @Override - public void removeListener(Listener listener) - { - super.removeListener(listener); - - if(!hasListeners()) - { - getTestTunerController().stop(); - } - } } diff --git a/src/source/tuner/test/TestTunerController.java b/src/source/tuner/test/TestTunerController.java index b09f630b..5664d9d0 100644 --- a/src/source/tuner/test/TestTunerController.java +++ b/src/source/tuner/test/TestTunerController.java @@ -70,18 +70,28 @@ public class TestTunerController extends TunerController * Starts the tuner controller producing samples that will be delivered to the specified listener */ public void start(Listener listener) + { + } + + @Override + public void addComplexBufferListener(Listener listener) { mSampleGenerator.setListener(listener); mSampleGenerator.start(); } + @Override + public void removeComplexBufferListener(Listener listener) + { + mSampleGenerator.stop(); + mSampleGenerator.setListener(null); + } + /** * Stops the tuner controller sample generator and deregisters the listener */ public void stop() { - mSampleGenerator.stop(); - mSampleGenerator.setListener(null); } @Override diff --git a/src/source/tuner/usb/USBTransferProcessor.java b/src/source/tuner/usb/USBTransferProcessor.java index 7052db0c..60d6642a 100644 --- a/src/source/tuner/usb/USBTransferProcessor.java +++ b/src/source/tuner/usb/USBTransferProcessor.java @@ -70,10 +70,10 @@ public class USBTransferProcessor implements TransferCallback //Byte array transfer buffers size in bytes private int mBufferSize; - private Broadcaster mComplexBufferBroadcaster = new Broadcaster<>(); private OverflowableTransferQueue mFilledBuffers; private LinkedTransferQueue mAvailableTransfers = new LinkedTransferQueue<>(); private LinkedTransferQueue mTransfersInProgress = new LinkedTransferQueue<>(); + private Listener mComplexBufferListener; private AtomicBoolean mRunning = new AtomicBoolean(); @@ -234,36 +234,26 @@ public class USBTransferProcessor implements TransferCallback } /** - * Indicates if there are complex buffer listeners registered with this processor + * Sets the listener and auto-starts the buffer processor */ - public boolean hasListeners() + public void setListener(Listener listener) { - return mComplexBufferBroadcaster.hasListeners(); - } - - public void addListener(Listener listener) - { - mComplexBufferBroadcaster.addListener(listener); - + mComplexBufferListener = listener; start(); } - public void removeListener(Listener listener) + /** + * Auto-stops the buffer processor and removes the listener + */ + public void removeListener() { - mComplexBufferBroadcaster.removeListener(listener); - - if(!hasListeners()) + if(mComplexBufferListener != null) { stop(); + mComplexBufferListener = null; } } - public void removeAllListeners() - { - mComplexBufferBroadcaster.clear(); - stop(); - } - /** * Prepares (allocates) a set of transfer buffers for use in transferring data from the USB device via the bulk * interface. Since we're using direct allocation (native), buffers are retained and reused across multiple @@ -425,7 +415,10 @@ public class USBTransferProcessor implements TransferCallback { float[] complexSamples = mSampleAdapter.convert(buffer); - mComplexBufferBroadcaster.broadcast(new ComplexBuffer(complexSamples)); + if(mComplexBufferListener != null) + { + mComplexBufferListener.receive(new ComplexBuffer(complexSamples)); + } } } catch(Exception e) diff --git a/src/source/tuner/usb/USBTunerController.java b/src/source/tuner/usb/USBTunerController.java new file mode 100644 index 00000000..f731783b --- /dev/null +++ b/src/source/tuner/usb/USBTunerController.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * 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 + * + ******************************************************************************/ +package source.tuner.usb; + +import sample.Listener; +import sample.complex.ComplexBuffer; +import source.tuner.TunerController; + +public abstract class USBTunerController extends TunerController +{ + /** + * USB tuner controller class. Provides auto-start and auto-stop function when complex buffer listeners are added + * or removed from this tuner controller. + * + * @param minimumFrequency minimum uncorrected tunable frequency + * @param maximumFrequency maximum uncorrected tunable frequency + * @param middleUnusable is the +/- value center DC spike to avoid for channels + * @param usableBandwidth percentage of usable bandwidth relative to space at the extreme ends of the spectrum + */ + public USBTunerController(long minimumFrequency, long maximumFrequency, int middleUnusable, double usableBandwidth) + { + super(minimumFrequency, maximumFrequency, middleUnusable, usableBandwidth); + } + + protected abstract USBTransferProcessor getUSBTransferProcessor(); + + /** + * Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started. + */ + @Override + public void addComplexBufferListener(Listener listener) + { + boolean hasExistingListeners = hasComplexBufferListeners(); + + super.addComplexBufferListener(listener); + + if(!hasExistingListeners) + { + getUSBTransferProcessor().setListener(this); + } + } + + /** + * Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners. + */ + @Override + public void removeComplexBufferListener(Listener listener) + { + super.removeComplexBufferListener(listener); + + if(!hasComplexBufferListeners()) + { + getUSBTransferProcessor().removeListener(); + } + } +} diff --git a/src/source/wave/ComplexWaveSource.java b/src/source/wave/ComplexWaveSource.java index 9ec77f2a..f7d0c601 100644 --- a/src/source/wave/ComplexWaveSource.java +++ b/src/source/wave/ComplexWaveSource.java @@ -18,7 +18,7 @@ ******************************************************************************/ package source.wave; -import channel.heartbeat.Heartbeat; +import source.heartbeat.Heartbeat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sample.ConversionUtils; diff --git a/src/source/wave/RealWaveSource.java b/src/source/wave/RealWaveSource.java index 3545efc2..f64eef05 100644 --- a/src/source/wave/RealWaveSource.java +++ b/src/source/wave/RealWaveSource.java @@ -17,7 +17,7 @@ ******************************************************************************/ package source.wave; -import channel.heartbeat.Heartbeat; +import source.heartbeat.Heartbeat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sample.ConversionUtils; diff --git a/src/spectrum/OverlayPanel.java b/src/spectrum/OverlayPanel.java index d78101e2..dc211bae 100644 --- a/src/spectrum/OverlayPanel.java +++ b/src/spectrum/OverlayPanel.java @@ -30,7 +30,7 @@ import settings.ColorSetting.ColorSettingName; import settings.Setting; import settings.SettingChangeListener; import settings.SettingsManager; -import source.tuner.TunerChannel; +import source.tuner.channel.TunerChannel; import source.SourceEvent; import source.ISourceEventProcessor; diff --git a/src/spectrum/SpectralDisplayPanel.java b/src/spectrum/SpectralDisplayPanel.java index 9c871aea..c050e27c 100644 --- a/src/spectrum/SpectralDisplayPanel.java +++ b/src/spectrum/SpectralDisplayPanel.java @@ -424,7 +424,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener)mDFTProcessor); + mTuner.getSourceManager().addComplexBufferListener(mDFTProcessor); mSpectrumPanel.setSampleSize(mTuner.getSampleSize());