mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 09:07:27 -05:00
#108 [WIP] Created new ThreadPool class with a static ScheduledThreadExecutor that is now shared by all components. Removed ThreadPoolManager from all classes. Consolidating into 1 pool seems to have reduced CPU usage by ~15-20%. Overall memory usage is also reduced.
This commit is contained in:
@@ -1,22 +1,38 @@
|
||||
/*******************************************************************************
|
||||
* 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 <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package source.tuner;
|
||||
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import dsp.mixer.Oscillator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Buffer;
|
||||
import sample.Listener;
|
||||
import sample.complex.Complex;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ComplexSource;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
@@ -26,371 +42,351 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sample.Buffer;
|
||||
import sample.Listener;
|
||||
import sample.complex.Complex;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ComplexSource;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import dsp.mixer.Oscillator;
|
||||
|
||||
public class TunerChannelSource extends ComplexSource
|
||||
implements IFrequencyChangeProcessor, Listener<ComplexBuffer>
|
||||
implements IFrequencyChangeProcessor, Listener<ComplexBuffer>
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( TunerChannelSource.class );
|
||||
|
||||
private static int CHANNEL_RATE = 48000;
|
||||
private static int CHANNEL_PASS_FREQUENCY = 12000;
|
||||
|
||||
private LinkedTransferQueue<ComplexBuffer> mBuffer =
|
||||
new LinkedTransferQueue<ComplexBuffer>();
|
||||
private Tuner mTuner;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Oscillator mMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private IFrequencyChangeProcessor mFrequencyChangeProcessor;
|
||||
private ScheduledFuture<?> mTaskHandle;
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger(TunerChannelSource.class);
|
||||
|
||||
private long mTunerFrequency = 0;
|
||||
private int mTunerSampleRate;
|
||||
private int mChannelFrequencyCorrection = 0;
|
||||
|
||||
private DecimationProcessor mDecimationProcessor = new DecimationProcessor();
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private boolean mExpended = false;
|
||||
|
||||
/**
|
||||
* Provides a Digital Drop Channel (DDC) to decimate the IQ output from a
|
||||
* tuner down to a 48 kHz IQ channel rate.
|
||||
*
|
||||
* Note: this class can only be used once (started and stopped) and a new
|
||||
* tuner channel source must be requested from the tuner once this object
|
||||
* has been stopped. This is because channels are managed dynamically and
|
||||
* center tuned frequency may have changed since this source was obtained
|
||||
* 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
|
||||
private static int CHANNEL_RATE = 48000;
|
||||
private static int CHANNEL_PASS_FREQUENCY = 12000;
|
||||
|
||||
private LinkedTransferQueue<ComplexBuffer> mBuffer =
|
||||
new LinkedTransferQueue<ComplexBuffer>();
|
||||
private Tuner mTuner;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Oscillator mMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private IFrequencyChangeProcessor mFrequencyChangeProcessor;
|
||||
private ScheduledFuture<?> mTaskHandle;
|
||||
|
||||
private long mTunerFrequency = 0;
|
||||
private int mTunerSampleRate;
|
||||
private int mChannelFrequencyCorrection = 0;
|
||||
|
||||
private DecimationProcessor mDecimationProcessor = new DecimationProcessor();
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private boolean mExpended = false;
|
||||
|
||||
/**
|
||||
* Provides a Digital Drop Channel (DDC) to decimate the IQ output from a
|
||||
* tuner down to a 48 kHz IQ channel rate.
|
||||
*
|
||||
* Note: this class can only be used once (started and stopped) and a new
|
||||
* tuner channel source must be requested from the tuner once this object
|
||||
* has been stopped. This is because channels are managed dynamically and
|
||||
* center tuned frequency may have changed since this source was obtained
|
||||
* 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
|
||||
{
|
||||
mTuner = tuner;
|
||||
mTuner.getTunerController().addListener( (IFrequencyChangeProcessor)this );
|
||||
|
||||
mTunerChannel = tunerChannel;
|
||||
mTuner = tuner;
|
||||
mTuner.getTunerController().addListener((IFrequencyChangeProcessor) this);
|
||||
|
||||
mTunerChannel = tunerChannel;
|
||||
|
||||
mTunerFrequency = mTuner.getTunerController().getFrequency();
|
||||
|
||||
mTunerFrequency = mTuner.getTunerController().getFrequency();
|
||||
|
||||
/* Setup the frequency translator to the current source frequency */
|
||||
long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency();
|
||||
|
||||
mMixer = new Oscillator( frequencyOffset,
|
||||
mTuner.getTunerController().getSampleRate() );
|
||||
long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency();
|
||||
|
||||
mMixer = new Oscillator(frequencyOffset,
|
||||
mTuner.getTunerController().getSampleRate());
|
||||
|
||||
/* Fire a sample rate change event to setup the decimation chain */
|
||||
frequencyChanged( new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
mTuner.getTunerController().getSampleRate() ) );
|
||||
frequencyChanged(new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
mTuner.getTunerController().getSampleRate()));
|
||||
}
|
||||
|
||||
|
||||
public void start( ScheduledExecutorService executor )
|
||||
{
|
||||
if( mExpended )
|
||||
{
|
||||
throw new IllegalStateException( "Attempt to re-start an expended "
|
||||
+ "tuner channel source. TunerChannelSource objects can only "
|
||||
+ "be used once. " );
|
||||
}
|
||||
|
||||
if( mRunning.compareAndSet( false, true ))
|
||||
{
|
||||
|
||||
|
||||
public void start(ScheduledExecutorService executor)
|
||||
{
|
||||
if(mExpended)
|
||||
{
|
||||
throw new IllegalStateException("Attempt to re-start an expended "
|
||||
+ "tuner channel source. TunerChannelSource objects can only "
|
||||
+ "be used once. ");
|
||||
}
|
||||
|
||||
if(mRunning.compareAndSet(false, true))
|
||||
{
|
||||
/* Schedule the decimation task to run every 10 ms (100 iterations/second) */
|
||||
mTaskHandle = executor.scheduleAtFixedRate( mDecimationProcessor,
|
||||
0, 10, TimeUnit.MILLISECONDS );
|
||||
mTaskHandle = executor.scheduleAtFixedRate(mDecimationProcessor,
|
||||
0, 10, TimeUnit.MILLISECONDS);
|
||||
|
||||
/* Finally, register to receive samples from the tuner */
|
||||
mTuner.addListener( (Listener<ComplexBuffer>)this );
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn( "Attempt to start() and already running tuner channel source was ignored" );
|
||||
}
|
||||
}
|
||||
mTuner.addListener((Listener<ComplexBuffer>) this);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Attempt to start() and already running tuner channel source was ignored");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if( mRunning.compareAndSet( true, false ))
|
||||
{
|
||||
mTuner.releaseChannel( this );
|
||||
mDecimationProcessor.shutdown();
|
||||
|
||||
if( mTaskHandle != null )
|
||||
{
|
||||
mTaskHandle.cancel( true );
|
||||
mTaskHandle = null;
|
||||
}
|
||||
|
||||
mBuffer.clear();
|
||||
|
||||
mExpended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn( "Attempt to stop() and already stopped tuner channel source was ignored" );
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(mRunning.compareAndSet(true, false))
|
||||
{
|
||||
mTuner.releaseChannel(this);
|
||||
mDecimationProcessor.shutdown();
|
||||
|
||||
if(mTaskHandle != null)
|
||||
{
|
||||
mTaskHandle.cancel(true);
|
||||
mTaskHandle = null;
|
||||
}
|
||||
|
||||
mBuffer.clear();
|
||||
|
||||
mExpended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Attempt to stop() and already stopped tuner channel source was ignored");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
if( !mRunning.get() )
|
||||
{
|
||||
if(!mRunning.get())
|
||||
{
|
||||
/* Tell the tuner to release/unregister our resources */
|
||||
mTuner.getTunerController().removeListener( this );
|
||||
mTuner = null;
|
||||
mTunerChannel = null;
|
||||
mBuffer = null;
|
||||
mFrequencyChangeProcessor = null;
|
||||
mListener = null;
|
||||
mMixer = null;
|
||||
mDecimationFilter.dispose();
|
||||
mDecimationFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Tuner getTuner()
|
||||
{
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( ComplexBuffer buffer )
|
||||
{
|
||||
if( mRunning.get() )
|
||||
{
|
||||
mBuffer.add( buffer );
|
||||
}
|
||||
mTuner.getTunerController().removeListener(this);
|
||||
// mTuner = null;
|
||||
// mTunerChannel = null;
|
||||
// mBuffer = null;
|
||||
// mFrequencyChangeProcessor = null;
|
||||
// mListener = null;
|
||||
// mMixer = null;
|
||||
// mDecimationFilter.dispose();
|
||||
// mDecimationFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFrequencyChangeListener( IFrequencyChangeProcessor processor )
|
||||
public Tuner getTuner()
|
||||
{
|
||||
mFrequencyChangeProcessor = processor;
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(ComplexBuffer buffer)
|
||||
{
|
||||
if(mRunning.get())
|
||||
{
|
||||
mBuffer.add(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFrequencyChangeListener(IFrequencyChangeProcessor processor)
|
||||
{
|
||||
mFrequencyChangeProcessor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
/* Save a pointer to the listener so that if we have to change the
|
||||
* decimation filter, we can re-add the listener */
|
||||
mListener = listener;
|
||||
|
||||
mDecimationFilter.setListener( listener );
|
||||
}
|
||||
mListener = listener;
|
||||
|
||||
@Override
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
mDecimationFilter.removeListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for frequency change events received from the tuner and channel
|
||||
* frequency correction events received from the channel consumer/listener
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event ) throws SourceException
|
||||
{
|
||||
// Echo the event to the registered event listener
|
||||
if( mFrequencyChangeProcessor != null )
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged( event );
|
||||
}
|
||||
|
||||
switch( event.getEvent() )
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
mTunerFrequency = event.getValue().longValue();
|
||||
updateMixerFrequencyOffset();
|
||||
break;
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
mChannelFrequencyCorrection = event.getValue().intValue();
|
||||
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
if( mFrequencyChangeProcessor != null )
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(
|
||||
new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
mChannelFrequencyCorrection ) );
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
int sampleRate = event.getValue().intValue();
|
||||
|
||||
if( mTunerSampleRate != sampleRate )
|
||||
{
|
||||
mMixer.setSampleRate( sampleRate );
|
||||
|
||||
/* Get new decimation filter */
|
||||
mDecimationFilter = FilterFactory
|
||||
.getDecimationFilter( sampleRate,
|
||||
CHANNEL_RATE,
|
||||
1, //Order
|
||||
CHANNEL_PASS_FREQUENCY,
|
||||
60, //dB attenuation
|
||||
WindowType.HAMMING );
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilter.setListener( mListener );
|
||||
|
||||
mTunerSampleRate = sampleRate;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mDecimationFilter.setListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the local mixer frequency offset from the tuned frequency,
|
||||
* channel's requested frequency, and channel frequency correction.
|
||||
*/
|
||||
private void updateMixerFrequencyOffset()
|
||||
{
|
||||
long offset = mTunerFrequency -
|
||||
mTunerChannel.getFrequency() -
|
||||
mChannelFrequencyCorrection;
|
||||
@Override
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mDecimationFilter.removeListener();
|
||||
}
|
||||
|
||||
mMixer.setFrequency( offset );
|
||||
}
|
||||
/**
|
||||
* Handler for frequency change events received from the tuner and channel
|
||||
* frequency correction events received from the channel consumer/listener
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event) throws SourceException
|
||||
{
|
||||
// Echo the event to the registered event listener
|
||||
if(mFrequencyChangeProcessor != null)
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(event);
|
||||
}
|
||||
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
mTunerFrequency = event.getValue().longValue();
|
||||
updateMixerFrequencyOffset();
|
||||
break;
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
mChannelFrequencyCorrection = event.getValue().intValue();
|
||||
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
if(mFrequencyChangeProcessor != null)
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(
|
||||
new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
mChannelFrequencyCorrection));
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
int sampleRate = event.getValue().intValue();
|
||||
|
||||
if(mTunerSampleRate != sampleRate)
|
||||
{
|
||||
mMixer.setSampleRate(sampleRate);
|
||||
|
||||
/* Get new decimation filter */
|
||||
mDecimationFilter = FilterFactory
|
||||
.getDecimationFilter(sampleRate,
|
||||
CHANNEL_RATE,
|
||||
1, //Order
|
||||
CHANNEL_PASS_FREQUENCY,
|
||||
60, //dB attenuation
|
||||
WindowType.HAMMING);
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilter.setListener(mListener);
|
||||
|
||||
mTunerSampleRate = sampleRate;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the local mixer frequency offset from the tuned frequency,
|
||||
* channel's requested frequency, and channel frequency correction.
|
||||
*/
|
||||
private void updateMixerFrequencyOffset()
|
||||
{
|
||||
long offset = mTunerFrequency -
|
||||
mTunerChannel.getFrequency() -
|
||||
mChannelFrequencyCorrection;
|
||||
|
||||
mMixer.setFrequency(offset);
|
||||
}
|
||||
|
||||
public int getSampleRate() throws SourceException
|
||||
{
|
||||
return CHANNEL_RATE;
|
||||
return CHANNEL_RATE;
|
||||
}
|
||||
|
||||
public long getFrequency() throws SourceException
|
||||
{
|
||||
return mTunerChannel.getFrequency();
|
||||
return mTunerChannel.getFrequency();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decimates an inbound buffer of I/Q samples from the source down to the
|
||||
* standard 48000 channel sample rate
|
||||
*/
|
||||
public class DecimationProcessor implements Runnable
|
||||
{
|
||||
private boolean mProcessing = true;
|
||||
private List<ComplexBuffer> mSampleBuffers = new ArrayList<ComplexBuffer>();
|
||||
public class DecimationProcessor implements Runnable
|
||||
{
|
||||
private boolean mProcessing = true;
|
||||
private List<ComplexBuffer> mSampleBuffers = new ArrayList<ComplexBuffer>();
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
mProcessing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown()
|
||||
{
|
||||
mProcessing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
/* General exception handler so that any errors won't kill the
|
||||
* decimation thread and cause the input buffers to fill up and
|
||||
* run the program out of memory */
|
||||
try
|
||||
{
|
||||
if( mProcessing )
|
||||
{
|
||||
{
|
||||
// long start = System.currentTimeMillis();
|
||||
|
||||
mBuffer.drainTo( mSampleBuffers, 8 );
|
||||
|
||||
for( Buffer buffer: mSampleBuffers )
|
||||
{
|
||||
try
|
||||
{
|
||||
if(mProcessing)
|
||||
{
|
||||
{
|
||||
mBuffer.drainTo(mSampleBuffers, 8);
|
||||
|
||||
for(Buffer buffer : mSampleBuffers)
|
||||
{
|
||||
/* Check to see if we've been shutdown */
|
||||
if( !mProcessing )
|
||||
{
|
||||
mBuffer.clear();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
float[] samples = buffer.getSamples();
|
||||
if(!mProcessing)
|
||||
{
|
||||
mBuffer.clear();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
float[] samples = buffer.getSamples();
|
||||
|
||||
/* We make a copy of the buffer so that we don't affect
|
||||
* anyone else that is using the same buffer, like other
|
||||
* channels or the spectral display */
|
||||
float[] translated = new float[ samples.length ];
|
||||
float[] translated = new float[samples.length];
|
||||
|
||||
/* Perform frequency translation */
|
||||
for( int x = 0; x < samples.length; x += 2 )
|
||||
{
|
||||
mMixer.rotate();
|
||||
|
||||
translated[ x ] = Complex.multiplyInphase(
|
||||
samples[ x ], samples[ x + 1 ], mMixer.inphase(), mMixer.quadrature() );
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
mMixer.rotate();
|
||||
|
||||
translated[ x + 1 ] = Complex.multiplyQuadrature(
|
||||
samples[ x ], samples[ x + 1 ], mMixer.inphase(), mMixer.quadrature() );
|
||||
}
|
||||
|
||||
if( mProcessing && mDecimationFilter != null )
|
||||
{
|
||||
mDecimationFilter.receive( new ComplexBuffer( translated ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mLog.debug( "Processed [" + mSampleBuffers.size() + "] in " + ( System.currentTimeMillis() - start ) );
|
||||
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
translated[x] = Complex.multiplyInphase(
|
||||
samples[x], samples[x + 1], mMixer.inphase(), mMixer.quadrature());
|
||||
|
||||
translated[x + 1] = Complex.multiplyQuadrature(
|
||||
samples[x], samples[x + 1], mMixer.inphase(), mMixer.quadrature());
|
||||
}
|
||||
|
||||
if(mProcessing)
|
||||
{
|
||||
final ComplexPrimeCICDecimate filter = mDecimationFilter;
|
||||
filter.receive(new ComplexBuffer(translated));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
/* Only log the stack trace if we're still processing */
|
||||
if( mProcessing )
|
||||
{
|
||||
mLog.error( "Error encountered during decimation process", e );
|
||||
}
|
||||
}
|
||||
if(mProcessing)
|
||||
{
|
||||
mLog.error("Error encountered during decimation process", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if we've been shutdown */
|
||||
if( !mProcessing )
|
||||
{
|
||||
mBuffer.clear();
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
if(!mProcessing)
|
||||
{
|
||||
mBuffer.clear();
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* 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 <http://www.gnu.org/licenses/>
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package source.tuner;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.Device;
|
||||
import org.usb4java.DeviceDescriptor;
|
||||
import org.usb4java.DeviceList;
|
||||
import org.usb4java.LibUsb;
|
||||
|
||||
import source.SourceException;
|
||||
import source.mixer.MixerManager;
|
||||
import source.tuner.airspy.AirspyTuner;
|
||||
@@ -39,437 +37,424 @@ import source.tuner.rtl.RTL2832Tuner;
|
||||
import source.tuner.rtl.RTL2832TunerController;
|
||||
import source.tuner.rtl.e4k.E4KTunerController;
|
||||
import source.tuner.rtl.r820t.R820TTunerController;
|
||||
import controller.ThreadPoolManager;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class TunerManager
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( TunerManager.class );
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger(TunerManager.class);
|
||||
|
||||
private MixerManager mMixerManager;
|
||||
private TunerModel mTunerModel;
|
||||
|
||||
public TunerManager(MixerManager mixerManager, TunerModel tunerModel)
|
||||
{
|
||||
mMixerManager = mixerManager;
|
||||
mTunerModel = tunerModel;
|
||||
|
||||
initTuners();
|
||||
}
|
||||
|
||||
private MixerManager mMixerManager;
|
||||
private TunerModel mTunerModel;
|
||||
private ThreadPoolManager mThreadPoolManager;
|
||||
|
||||
public TunerManager( MixerManager mixerManager,
|
||||
TunerModel tunerModel,
|
||||
ThreadPoolManager threadPoolManager )
|
||||
{
|
||||
mMixerManager = mixerManager;
|
||||
mTunerModel = tunerModel;
|
||||
mThreadPoolManager = threadPoolManager;
|
||||
|
||||
initTuners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs cleanup of USB related issues
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
LibUsb.exit( null );
|
||||
LibUsb.exit(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all USB tuners and USB/Mixer tuner devices
|
||||
*/
|
||||
private void initTuners()
|
||||
{
|
||||
DeviceList deviceList = new DeviceList();
|
||||
private void initTuners()
|
||||
{
|
||||
DeviceList deviceList = new DeviceList();
|
||||
|
||||
int result = LibUsb.init( null );
|
||||
int result = LibUsb.init(null);
|
||||
|
||||
if( result != LibUsb.SUCCESS )
|
||||
{
|
||||
mLog.error( "unable to initialize libusb [" +
|
||||
LibUsb.errorName( result ) + "]" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.info( "LibUSB API Version: " + LibUsb.getApiVersion() );
|
||||
mLog.info( "LibUSB Version: " + LibUsb.getVersion() );
|
||||
|
||||
result = LibUsb.getDeviceList( null, deviceList );
|
||||
|
||||
if( result < 0 )
|
||||
{
|
||||
mLog.error( "unable to get device list from libusb [" + result + " / " +
|
||||
LibUsb.errorName( result ) + "]" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.info( "discovered [" + result + "] attached USB devices" );
|
||||
}
|
||||
}
|
||||
if(result != LibUsb.SUCCESS)
|
||||
{
|
||||
mLog.error("unable to initialize libusb [" +
|
||||
LibUsb.errorName(result) + "]");
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.info("LibUSB API Version: " + LibUsb.getApiVersion());
|
||||
mLog.info("LibUSB Version: " + LibUsb.getVersion());
|
||||
|
||||
for( Device device: deviceList )
|
||||
{
|
||||
DeviceDescriptor descriptor = new DeviceDescriptor();
|
||||
|
||||
result = LibUsb.getDeviceDescriptor( device, descriptor );
|
||||
|
||||
if( result != LibUsb.SUCCESS )
|
||||
{
|
||||
mLog.error( "unable to read device descriptor [" +
|
||||
LibUsb.errorName( result ) + "]" );
|
||||
}
|
||||
else
|
||||
{
|
||||
TunerInitStatus status = initTuner( device, descriptor );
|
||||
result = LibUsb.getDeviceList(null, deviceList);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "usb device [" );
|
||||
sb.append( String.format( "%04X", descriptor.idVendor() ) );
|
||||
sb.append( ":" );
|
||||
sb.append( String.format( "%04X", descriptor.idProduct() ) );
|
||||
|
||||
if( status.isLoaded() )
|
||||
{
|
||||
Tuner tuner = status.getTuner();
|
||||
|
||||
try
|
||||
{
|
||||
mTunerModel.addTuner( tuner );
|
||||
sb.append( "] LOADED: " );
|
||||
sb.append( tuner.toString() );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
sb.append( "] NOT LOADED: " );
|
||||
sb.append( status.getInfo() );
|
||||
sb.append( " Error:" + e.getMessage() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "] NOT LOADED: " );
|
||||
sb.append( status.getInfo() );
|
||||
}
|
||||
|
||||
mLog.info( sb.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
LibUsb.freeDeviceList( deviceList, true );
|
||||
}
|
||||
|
||||
private TunerInitStatus initTuner( Device device,
|
||||
DeviceDescriptor descriptor )
|
||||
{
|
||||
if( device != null && descriptor != null )
|
||||
{
|
||||
TunerClass tunerClass = TunerClass.valueOf( descriptor.idVendor(),
|
||||
descriptor.idProduct() );
|
||||
|
||||
switch( tunerClass )
|
||||
{
|
||||
case AIRSPY:
|
||||
return initAirspyTuner( device, descriptor );
|
||||
case ETTUS_USRP_B100:
|
||||
return initEttusB100Tuner( device, descriptor );
|
||||
case FUNCUBE_DONGLE_PRO:
|
||||
return initFuncubeProTuner( device, descriptor );
|
||||
case FUNCUBE_DONGLE_PRO_PLUS:
|
||||
return initFuncubeProPlusTuner( device, descriptor );
|
||||
case HACKRF_ONE:
|
||||
case RAD1O:
|
||||
return initHackRFTuner( device, descriptor );
|
||||
case COMPRO_VIDEOMATE_U620F:
|
||||
case COMPRO_VIDEOMATE_U650F:
|
||||
case COMPRO_VIDEOMATE_U680F:
|
||||
case GENERIC_2832:
|
||||
case GENERIC_2838:
|
||||
case DEXATEK_5217_DVBT:
|
||||
case DEXATEK_DIGIVOX_MINI_II_REV3:
|
||||
case DEXATEK_LOGILINK_VG002A:
|
||||
case GIGABYTE_GTU7300:
|
||||
case GTEK_T803:
|
||||
case LIFEVIEW_LV5T_DELUXE:
|
||||
case MYGICA_TD312:
|
||||
case PEAK_102569AGPK:
|
||||
case PROLECTRIX_DV107669:
|
||||
case SVEON_STV20:
|
||||
case TERRATEC_CINERGY_T_REV1:
|
||||
case TERRATEC_CINERGY_T_REV3:
|
||||
case TERRATEC_NOXON_REV1_B3:
|
||||
case TERRATEC_NOXON_REV1_B4:
|
||||
case TERRATEC_NOXON_REV1_B7:
|
||||
case TERRATEC_NOXON_REV1_C6:
|
||||
case TERRATEC_NOXON_REV2:
|
||||
case TERRATEC_T_STICK_PLUS:
|
||||
case TWINTECH_UT40:
|
||||
case ZAAPA_ZTMINDVBZP:
|
||||
return initRTL2832Tuner( tunerClass, device, descriptor );
|
||||
case UNKNOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new TunerInitStatus( null, "Unknown Device" );
|
||||
}
|
||||
|
||||
private TunerInitStatus initAirspyTuner( Device device,
|
||||
DeviceDescriptor descriptor )
|
||||
{
|
||||
try
|
||||
{
|
||||
AirspyTunerController airspyController =
|
||||
new AirspyTunerController( device, mThreadPoolManager );
|
||||
|
||||
airspyController.init();
|
||||
|
||||
AirspyTuner tuner = new AirspyTuner( airspyController );
|
||||
|
||||
return new TunerInitStatus( tuner, "LOADED" );
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
mLog.error( "couldn't construct Airspy controller/tuner", se );
|
||||
|
||||
return new TunerInitStatus( null,
|
||||
"error constructing Airspy tuner controller" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private TunerInitStatus initEttusB100Tuner( Device device,
|
||||
DeviceDescriptor descriptor )
|
||||
{
|
||||
return new TunerInitStatus( null, "Ettus B100 tuner not currently "
|
||||
+ "supported" );
|
||||
}
|
||||
|
||||
private TunerInitStatus initFuncubeProTuner( Device device,
|
||||
DeviceDescriptor descriptor )
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(
|
||||
TunerClass.FUNCUBE_DONGLE_PRO.getTunerType() );
|
||||
|
||||
if( dataline != null )
|
||||
{
|
||||
FCD1TunerController controller =
|
||||
new FCD1TunerController( device, descriptor );
|
||||
|
||||
try
|
||||
if(result < 0)
|
||||
{
|
||||
controller.init();
|
||||
|
||||
FCDTuner tuner =
|
||||
new FCDTuner( dataline, controller );
|
||||
|
||||
return new TunerInitStatus( tuner, "LOADED" );
|
||||
mLog.error("unable to get device list from libusb [" + result + " / " +
|
||||
LibUsb.errorName(result) + "]");
|
||||
}
|
||||
catch ( SourceException e )
|
||||
else
|
||||
{
|
||||
mLog.error( "couldn't load funcube dongle pro tuner", e );
|
||||
|
||||
reason = "error during initialization - " + e.getLocalizedMessage();
|
||||
mLog.info("discovered [" + result + "] attached USB devices");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = "couldn't find matching mixer dataline";
|
||||
}
|
||||
}
|
||||
|
||||
return new TunerInitStatus( null, "Funcube Dongle Pro tuner not "
|
||||
+ "loaded - " + reason );
|
||||
}
|
||||
for(Device device : deviceList)
|
||||
{
|
||||
DeviceDescriptor descriptor = new DeviceDescriptor();
|
||||
|
||||
private TunerInitStatus initFuncubeProPlusTuner( Device device,
|
||||
DeviceDescriptor descriptor )
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(
|
||||
TunerClass.FUNCUBE_DONGLE_PRO_PLUS.getTunerType() );
|
||||
|
||||
if( dataline != null )
|
||||
{
|
||||
FCD2TunerController controller =
|
||||
new FCD2TunerController( device, descriptor );
|
||||
result = LibUsb.getDeviceDescriptor(device, descriptor);
|
||||
|
||||
try
|
||||
if(result != LibUsb.SUCCESS)
|
||||
{
|
||||
controller.init();
|
||||
|
||||
FCDTuner tuner =
|
||||
new FCDTuner( dataline, controller );
|
||||
|
||||
return new TunerInitStatus( tuner, "LOADED" );
|
||||
mLog.error("unable to read device descriptor [" +
|
||||
LibUsb.errorName(result) + "]");
|
||||
}
|
||||
catch ( SourceException e )
|
||||
else
|
||||
{
|
||||
mLog.error( "couldn't load funcube dongle pro plus tuner", e );
|
||||
|
||||
reason = "error during initialization - " +
|
||||
e.getLocalizedMessage();
|
||||
TunerInitStatus status = initTuner(device, descriptor);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("usb device [");
|
||||
sb.append(String.format("%04X", descriptor.idVendor()));
|
||||
sb.append(":");
|
||||
sb.append(String.format("%04X", descriptor.idProduct()));
|
||||
|
||||
if(status.isLoaded())
|
||||
{
|
||||
Tuner tuner = status.getTuner();
|
||||
|
||||
try
|
||||
{
|
||||
mTunerModel.addTuner(tuner);
|
||||
sb.append("] LOADED: ");
|
||||
sb.append(tuner.toString());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
sb.append("] NOT LOADED: ");
|
||||
sb.append(status.getInfo());
|
||||
sb.append(" Error:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("] NOT LOADED: ");
|
||||
sb.append(status.getInfo());
|
||||
}
|
||||
|
||||
mLog.info(sb.toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = "couldn't find matching mixer dataline";
|
||||
}
|
||||
}
|
||||
|
||||
return new TunerInitStatus( null, "Funcube Dongle Pro tuner not "
|
||||
+ "loaded - " + reason );
|
||||
}
|
||||
LibUsb.freeDeviceList(deviceList, true);
|
||||
}
|
||||
|
||||
private TunerInitStatus initHackRFTuner( Device device,
|
||||
DeviceDescriptor descriptor )
|
||||
{
|
||||
try
|
||||
{
|
||||
HackRFTunerController hackRFController =
|
||||
new HackRFTunerController( device, descriptor,
|
||||
mThreadPoolManager );
|
||||
|
||||
hackRFController.init();
|
||||
|
||||
HackRFTuner tuner = new HackRFTuner( hackRFController );
|
||||
|
||||
return new TunerInitStatus( tuner, "LOADED" );
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
mLog.error( "couldn't construct HackRF controller/tuner", se );
|
||||
|
||||
return new TunerInitStatus( null,
|
||||
"error constructing HackRF tuner controller" );
|
||||
}
|
||||
}
|
||||
private TunerInitStatus initTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
{
|
||||
if(device != null && descriptor != null)
|
||||
{
|
||||
TunerClass tunerClass = TunerClass.valueOf(descriptor.idVendor(),
|
||||
descriptor.idProduct());
|
||||
|
||||
private TunerInitStatus initRTL2832Tuner( TunerClass tunerClass,
|
||||
Device device,
|
||||
DeviceDescriptor deviceDescriptor )
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
switch(tunerClass)
|
||||
{
|
||||
case AIRSPY:
|
||||
return initAirspyTuner(device, descriptor);
|
||||
case ETTUS_USRP_B100:
|
||||
return initEttusB100Tuner(device, descriptor);
|
||||
case FUNCUBE_DONGLE_PRO:
|
||||
return initFuncubeProTuner(device, descriptor);
|
||||
case FUNCUBE_DONGLE_PRO_PLUS:
|
||||
return initFuncubeProPlusTuner(device, descriptor);
|
||||
case HACKRF_ONE:
|
||||
case RAD1O:
|
||||
return initHackRFTuner(device, descriptor);
|
||||
case COMPRO_VIDEOMATE_U620F:
|
||||
case COMPRO_VIDEOMATE_U650F:
|
||||
case COMPRO_VIDEOMATE_U680F:
|
||||
case GENERIC_2832:
|
||||
case GENERIC_2838:
|
||||
case DEXATEK_5217_DVBT:
|
||||
case DEXATEK_DIGIVOX_MINI_II_REV3:
|
||||
case DEXATEK_LOGILINK_VG002A:
|
||||
case GIGABYTE_GTU7300:
|
||||
case GTEK_T803:
|
||||
case LIFEVIEW_LV5T_DELUXE:
|
||||
case MYGICA_TD312:
|
||||
case PEAK_102569AGPK:
|
||||
case PROLECTRIX_DV107669:
|
||||
case SVEON_STV20:
|
||||
case TERRATEC_CINERGY_T_REV1:
|
||||
case TERRATEC_CINERGY_T_REV3:
|
||||
case TERRATEC_NOXON_REV1_B3:
|
||||
case TERRATEC_NOXON_REV1_B4:
|
||||
case TERRATEC_NOXON_REV1_B7:
|
||||
case TERRATEC_NOXON_REV1_C6:
|
||||
case TERRATEC_NOXON_REV2:
|
||||
case TERRATEC_T_STICK_PLUS:
|
||||
case TWINTECH_UT40:
|
||||
case ZAAPA_ZTMINDVBZP:
|
||||
return initRTL2832Tuner(tunerClass, device, descriptor);
|
||||
case UNKNOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TunerType tunerType = tunerClass.getTunerType();
|
||||
|
||||
if( tunerType == TunerType.RTL2832_VARIOUS )
|
||||
{
|
||||
try
|
||||
{
|
||||
tunerType = RTL2832TunerController.identifyTunerType( device );
|
||||
}
|
||||
catch( SourceException e )
|
||||
{
|
||||
mLog.error( "couldn't determine RTL2832 tuner type", e );
|
||||
tunerType = TunerType.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
switch( tunerType )
|
||||
{
|
||||
case ELONICS_E4000:
|
||||
try
|
||||
{
|
||||
E4KTunerController controller =
|
||||
new E4KTunerController( device, deviceDescriptor,
|
||||
mThreadPoolManager );
|
||||
|
||||
controller.init();
|
||||
|
||||
RTL2832Tuner rtlTuner =
|
||||
new RTL2832Tuner( tunerClass, controller );
|
||||
|
||||
return new TunerInitStatus( rtlTuner, "LOADED" );
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
return new TunerInitStatus( null, "Error constructing E4K tuner "
|
||||
+ "controller - " + se.getLocalizedMessage() );
|
||||
}
|
||||
case RAFAELMICRO_R820T:
|
||||
try
|
||||
{
|
||||
R820TTunerController controller =
|
||||
new R820TTunerController( device, deviceDescriptor,
|
||||
mThreadPoolManager );
|
||||
|
||||
controller.init();
|
||||
|
||||
RTL2832Tuner rtlTuner =
|
||||
new RTL2832Tuner( tunerClass, controller );
|
||||
|
||||
return new TunerInitStatus( rtlTuner, "LOADED" );
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
mLog.error( "error constructing tuner", se );
|
||||
|
||||
return new TunerInitStatus( null, "Error constructing R820T "
|
||||
+ "tuner controller - " + se.getLocalizedMessage() );
|
||||
}
|
||||
case FITIPOWER_FC0012:
|
||||
case FITIPOWER_FC0013:
|
||||
case RAFAELMICRO_R828D:
|
||||
case UNKNOWN:
|
||||
default:
|
||||
reason = "SDRTRunk doesn't currently support RTL2832 "
|
||||
+ "Dongle with [" + tunerType.toString() +
|
||||
"] tuner for tuner class[" + tunerClass.toString() + "]";
|
||||
break;
|
||||
}
|
||||
|
||||
return new TunerInitStatus( null, reason );
|
||||
}
|
||||
return new TunerInitStatus(null, "Unknown Device");
|
||||
}
|
||||
|
||||
private TunerInitStatus initAirspyTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
{
|
||||
try
|
||||
{
|
||||
AirspyTunerController airspyController = new AirspyTunerController(device);
|
||||
|
||||
airspyController.init();
|
||||
|
||||
AirspyTuner tuner = new AirspyTuner(airspyController);
|
||||
|
||||
return new TunerInitStatus(tuner, "LOADED");
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("couldn't construct Airspy controller/tuner", se);
|
||||
|
||||
return new TunerInitStatus(null,
|
||||
"error constructing Airspy tuner controller");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private TunerInitStatus initEttusB100Tuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
{
|
||||
return new TunerInitStatus(null, "Ettus B100 tuner not currently "
|
||||
+ "supported");
|
||||
}
|
||||
|
||||
private TunerInitStatus initFuncubeProTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(
|
||||
TunerClass.FUNCUBE_DONGLE_PRO.getTunerType());
|
||||
|
||||
if(dataline != null)
|
||||
{
|
||||
FCD1TunerController controller =
|
||||
new FCD1TunerController(device, descriptor);
|
||||
|
||||
try
|
||||
{
|
||||
controller.init();
|
||||
|
||||
FCDTuner tuner =
|
||||
new FCDTuner(dataline, controller);
|
||||
|
||||
return new TunerInitStatus(tuner, "LOADED");
|
||||
}
|
||||
catch(SourceException e)
|
||||
{
|
||||
mLog.error("couldn't load funcube dongle pro tuner", e);
|
||||
|
||||
reason = "error during initialization - " + e.getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = "couldn't find matching mixer dataline";
|
||||
}
|
||||
|
||||
return new TunerInitStatus(null, "Funcube Dongle Pro tuner not "
|
||||
+ "loaded - " + reason);
|
||||
}
|
||||
|
||||
private TunerInitStatus initFuncubeProPlusTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(
|
||||
TunerClass.FUNCUBE_DONGLE_PRO_PLUS.getTunerType());
|
||||
|
||||
if(dataline != null)
|
||||
{
|
||||
FCD2TunerController controller =
|
||||
new FCD2TunerController(device, descriptor);
|
||||
|
||||
try
|
||||
{
|
||||
controller.init();
|
||||
|
||||
FCDTuner tuner =
|
||||
new FCDTuner(dataline, controller);
|
||||
|
||||
return new TunerInitStatus(tuner, "LOADED");
|
||||
}
|
||||
catch(SourceException e)
|
||||
{
|
||||
mLog.error("couldn't load funcube dongle pro plus tuner", e);
|
||||
|
||||
reason = "error during initialization - " +
|
||||
e.getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = "couldn't find matching mixer dataline";
|
||||
}
|
||||
|
||||
return new TunerInitStatus(null, "Funcube Dongle Pro tuner not "
|
||||
+ "loaded - " + reason);
|
||||
}
|
||||
|
||||
private TunerInitStatus initHackRFTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
{
|
||||
try
|
||||
{
|
||||
HackRFTunerController hackRFController = new HackRFTunerController(device, descriptor);
|
||||
|
||||
hackRFController.init();
|
||||
|
||||
HackRFTuner tuner = new HackRFTuner(hackRFController);
|
||||
|
||||
return new TunerInitStatus(tuner, "LOADED");
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("couldn't construct HackRF controller/tuner", se);
|
||||
|
||||
return new TunerInitStatus(null,
|
||||
"error constructing HackRF tuner controller");
|
||||
}
|
||||
}
|
||||
|
||||
private TunerInitStatus initRTL2832Tuner(TunerClass tunerClass,
|
||||
Device device,
|
||||
DeviceDescriptor deviceDescriptor)
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
|
||||
TunerType tunerType = tunerClass.getTunerType();
|
||||
|
||||
if(tunerType == TunerType.RTL2832_VARIOUS)
|
||||
{
|
||||
try
|
||||
{
|
||||
tunerType = RTL2832TunerController.identifyTunerType(device);
|
||||
}
|
||||
catch(SourceException e)
|
||||
{
|
||||
mLog.error("couldn't determine RTL2832 tuner type", e);
|
||||
tunerType = TunerType.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
switch(tunerType)
|
||||
{
|
||||
case ELONICS_E4000:
|
||||
try
|
||||
{
|
||||
E4KTunerController controller = new E4KTunerController(device, deviceDescriptor);
|
||||
|
||||
controller.init();
|
||||
|
||||
RTL2832Tuner rtlTuner = new RTL2832Tuner(tunerClass, controller);
|
||||
|
||||
return new TunerInitStatus(rtlTuner, "LOADED");
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
return new TunerInitStatus(null, "Error constructing E4K tuner controller - " +
|
||||
se.getLocalizedMessage());
|
||||
}
|
||||
case RAFAELMICRO_R820T:
|
||||
try
|
||||
{
|
||||
R820TTunerController controller = new R820TTunerController(device, deviceDescriptor);
|
||||
|
||||
controller.init();
|
||||
|
||||
RTL2832Tuner rtlTuner = new RTL2832Tuner(tunerClass, controller);
|
||||
|
||||
return new TunerInitStatus(rtlTuner, "LOADED");
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("error constructing tuner", se);
|
||||
|
||||
return new TunerInitStatus(null, "Error constructing R820T "
|
||||
+ "tuner controller - " + se.getLocalizedMessage());
|
||||
}
|
||||
case FITIPOWER_FC0012:
|
||||
case FITIPOWER_FC0013:
|
||||
case RAFAELMICRO_R828D:
|
||||
case UNKNOWN:
|
||||
default:
|
||||
reason = "SDRTRunk doesn't currently support RTL2832 "
|
||||
+ "Dongle with [" + tunerType.toString() +
|
||||
"] tuner for tuner class[" + tunerClass.toString() + "]";
|
||||
break;
|
||||
}
|
||||
|
||||
return new TunerInitStatus(null, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first tuner mixer dataline that corresponds to the tuner class.
|
||||
*
|
||||
*
|
||||
* Note: this method is not currently able to align multiple tuner mixer
|
||||
* data lines of the same tuner type. If you have multiple Funcube Dongle
|
||||
* tuners of the same TYPE, there is no guarantee that you will get the
|
||||
* tuners of the same TYPE, there is no guarantee that you will get the
|
||||
* correct mixer.
|
||||
*
|
||||
*
|
||||
* @param tunerClass
|
||||
* @return
|
||||
*/
|
||||
private MixerTunerDataLine getMixerTunerDataLine( TunerType tunerClass )
|
||||
private MixerTunerDataLine getMixerTunerDataLine(TunerType tunerClass)
|
||||
{
|
||||
Collection<MixerTunerDataLine> datalines =
|
||||
mMixerManager.getMixerTunerDataLines();
|
||||
Collection<MixerTunerDataLine> datalines =
|
||||
mMixerManager.getMixerTunerDataLines();
|
||||
|
||||
for( MixerTunerDataLine mixerTDL: datalines )
|
||||
{
|
||||
if( mixerTDL.getMixerTunerType().getTunerClass() == tunerClass )
|
||||
{
|
||||
return mixerTDL;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
for(MixerTunerDataLine mixerTDL : datalines)
|
||||
{
|
||||
if(mixerTDL.getMixerTunerType().getTunerClass() == tunerClass)
|
||||
{
|
||||
return mixerTDL;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public class TunerInitStatus
|
||||
{
|
||||
private Tuner mTuner;
|
||||
private String mInfo;
|
||||
|
||||
public TunerInitStatus( Tuner tuner, String info )
|
||||
{
|
||||
mTuner = tuner;
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
public Tuner getTuner()
|
||||
{
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
public String getInfo()
|
||||
{
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
public boolean isLoaded()
|
||||
{
|
||||
return mTuner != null;
|
||||
}
|
||||
private Tuner mTuner;
|
||||
private String mInfo;
|
||||
|
||||
public TunerInitStatus(Tuner tuner, String info)
|
||||
{
|
||||
mTuner = tuner;
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
public Tuner getTuner()
|
||||
{
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
public String getInfo()
|
||||
{
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
public boolean isLoaded()
|
||||
{
|
||||
return mTuner != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user