Changed FrequencyChangeListener interface to an event so that I could describe what event was causing the frequency change and to broadcast frequency and sample rate error values.

R820T - added a couple more sample rate settings to the enum and modified the periodic sample rate info logger.
This commit is contained in:
dennis.sheirer
2014-09-27 09:46:18 +00:00
parent e441ebf0c9
commit 550aed79d4
28 changed files with 600 additions and 500 deletions

View File

@@ -46,6 +46,7 @@ import source.FloatSource;
import source.Source; import source.Source;
import source.SourceException; import source.SourceException;
import source.config.SourceConfigMixer; import source.config.SourceConfigMixer;
import source.tuner.FrequencyChangeListener;
import source.tuner.Tuner; import source.tuner.Tuner;
import source.tuner.TunerChannelSource; import source.tuner.TunerChannelSource;
import alias.AliasList; import alias.AliasList;
@@ -61,7 +62,6 @@ import controller.state.ChannelState.State;
import decode.Decoder; import decode.Decoder;
import decode.DecoderFactory; import decode.DecoderFactory;
import dsp.afc.AutomaticFrequencyControl; import dsp.afc.AutomaticFrequencyControl;
import dsp.afc.FrequencyErrorListener;
import eventlog.EventLogType; import eventlog.EventLogType;
import eventlog.EventLogger; import eventlog.EventLogger;
@@ -403,16 +403,15 @@ public class ProcessingChain implements Listener<Message>
mAFC = null; mAFC = null;
} }
if( mSource instanceof FrequencyErrorListener && if( mSource instanceof TunerChannelSource &&
mChannel.getDecodeConfiguration().isAFCEnabled() ) mChannel.getDecodeConfiguration().isAFCEnabled() )
{ {
FrequencyErrorListener listener = TunerChannelSource tcs = (TunerChannelSource)mSource;
(FrequencyErrorListener)mSource;
mAFC = new AutomaticFrequencyControl( listener ); mAFC = new AutomaticFrequencyControl( tcs );
/* Register AFC to receive frequency change events */ /* Register AFC to receive frequency change events */
listener.addListener( mAFC ); tcs.addListener( mAFC );
/* Add AFC as listener to the decoder */ /* Add AFC as listener to the decoder */
mDecoder.addUnfilteredFloatListener( mAFC ); mDecoder.addUnfilteredFloatListener( mAFC );

View File

@@ -1,7 +1,9 @@
package dsp.afc; package dsp.afc;
import sample.Listener; import sample.Listener;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.FrequencyChangeEvent.Attribute;
import buffer.FloatAveragingBuffer; import buffer.FloatAveragingBuffer;
public class AutomaticFrequencyControl implements Listener<Float>, public class AutomaticFrequencyControl implements Listener<Float>,
@@ -22,15 +24,14 @@ public class AutomaticFrequencyControl implements Listener<Float>,
private int mSkipThreshold = 4; private int mSkipThreshold = 4;
private int mErrorCorrection = 0; private int mErrorCorrection = 0;
private long mCurrentFrequency; private long mCurrentFrequency;
private int mCurrentSampleRate; private FrequencyChangeListener mListener;
private FrequencyErrorListener mListener;
public enum Mode public enum Mode
{ {
NORMAL,FAST; NORMAL,FAST;
} }
public AutomaticFrequencyControl( FrequencyErrorListener listener ) public AutomaticFrequencyControl( FrequencyChangeListener listener )
{ {
mListener = listener; mListener = listener;
} }
@@ -57,7 +58,9 @@ public class AutomaticFrequencyControl implements Listener<Float>,
{ {
if( mListener != null ) if( mListener != null )
{ {
mListener.setError( mErrorCorrection ); mListener.frequencyChanged(
new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR,
mErrorCorrection ) );
} }
} }
@@ -156,14 +159,23 @@ public class AutomaticFrequencyControl implements Listener<Float>,
} }
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
if( mCurrentFrequency != frequency || mCurrentSampleRate != bandwidth ) switch( event.getAttribute() )
{ {
mCurrentFrequency = frequency; case FREQUENCY:
mCurrentSampleRate = bandwidth; int frequency = (int)event.getValue();
reset(); if( mCurrentFrequency != frequency )
{
mCurrentFrequency = frequency;
reset();
}
case SAMPLE_RATE_ERROR:
break;
default:
break;
} }
} }
} }

View File

@@ -1,10 +0,0 @@
package dsp.afc;
import source.tuner.FrequencyChangeListener;
public interface FrequencyErrorListener
{
public void setError( int error );
public void addListener( FrequencyChangeListener listener );
}

View File

@@ -406,7 +406,15 @@ public class FilterFactory
int decimate = (int)( sampleRate / decimatedRate ); int decimate = (int)( sampleRate / decimatedRate );
filters[ 0 ] = new ComplexCICDecimate( decimate, 2, decimatedRate ); // if( decimate < 25 )
// {
filters[ 0 ] = new ComplexCICDecimate( decimate, 1, decimatedRate );
// }
// else
// {
// filters[ 0 ] = new ComplexCICDecimate( decimate, 3, decimatedRate );
// }
// int finalStopFrequency = decimatedRate - passFrequency; // int finalStopFrequency = decimatedRate - passFrequency;
// //

View File

@@ -43,7 +43,9 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.FrequencyChangeEvent.Attribute;
public class JFrequencyControl extends JPanel implements FrequencyChangeListener public class JFrequencyControl extends JPanel implements FrequencyChangeListener
{ {
@@ -132,9 +134,12 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener
* rebroadcast this event, just set the control to indicate the new frequency. * rebroadcast this event, just set the control to indicate the new frequency.
*/ */
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
setFrequency( frequency, false ); if( event.getAttribute() == Attribute.FREQUENCY )
{
setFrequency( (int)event.getValue(), false );
}
} }
/** /**
@@ -174,9 +179,12 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener
Iterator<FrequencyChangeListener> it = mListeners.iterator(); Iterator<FrequencyChangeListener> it = mListeners.iterator();
FrequencyChangeEvent event =
new FrequencyChangeEvent( Attribute.FREQUENCY, mFrequency );
while( it.hasNext() ) while( it.hasNext() )
{ {
it.next().frequencyChanged( mFrequency, -1 ); it.next().frequencyChanged( event );
} }
} }

View File

@@ -1,114 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package sample.complex;
import gui.SDRTrunk;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import source.tuner.FrequencyChangeListener;
import buffer.FloatAveragingBuffer;
public class ComplexSampleRateCounter implements Listener<ComplexSample>,
ComplexSampleListListener,
FrequencyChangeListener
{
private final static Logger mLog =
LoggerFactory.getLogger( ComplexSampleRateCounter.class );
private int mCounter;
private int mAverageCounter;
private int mExpectedSampleRate;
private long mLastRun = 0;
private int mBufferSize = 100;
private FloatAveragingBuffer mAveragingBuffer;
public ComplexSampleRateCounter( int expectedSampleRate, int bufferSize )
{
mExpectedSampleRate = expectedSampleRate;
mBufferSize = bufferSize;
mAveragingBuffer = new FloatAveragingBuffer( mBufferSize );
mLastRun = System.currentTimeMillis();
mLog.info( "Complex Sample Rate Counter started ...." );
}
@Override
public void receive( ComplexSample sample )
{
mCounter++;
if( mCounter >= mExpectedSampleRate )
{
mCounter = 0;
long now = System.currentTimeMillis();
long elapsed = now - mLastRun;
mLastRun = now;
float average = (float)mExpectedSampleRate * 1000.0f / (float)elapsed;
float runningAverage = mAveragingBuffer.get( average );
mAverageCounter++;
mLog.info( "Complex Sample Rate Avg " + mAverageCounter +
" current [" + elapsed + " ms/" + average +
" hz] average [" + runningAverage + " hz] expected [" +
mExpectedSampleRate + " hz] over [" +
mBufferSize + "] buffer length" );
}
}
@Override
public void receive( List<ComplexSample> samples )
{
mCounter += samples.size();
if( mCounter >= mExpectedSampleRate )
{
mCounter -= mExpectedSampleRate;
long now = System.currentTimeMillis();
long elapsed = now - mLastRun;
mLastRun = now;
float average = (float)mExpectedSampleRate * 1000.0f / (float)elapsed;
float runningAverage = mAveragingBuffer.get( average );
mAverageCounter++;
mLog.info( "Complex Sample Rate Avg " + mAverageCounter +
" current [" + elapsed + " ms/" + average +
" hz] average [" + runningAverage + " hz] expected [" +
mExpectedSampleRate + " hz] over [" +
mBufferSize + "] buffer length" );
}
}
@Override
public void frequencyChanged( long frequency, int bandwidth )
{
mExpectedSampleRate = bandwidth;
}
}

View File

@@ -5,10 +5,12 @@ import java.util.ArrayList;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.TunerChannel; import source.tuner.TunerChannel;
import source.tuner.TunerChannelProvider; import source.tuner.TunerChannelProvider;
import source.tuner.TunerChannelSource; import source.tuner.TunerChannelSource;
import source.tuner.FrequencyChangeEvent.Attribute;
import controller.ResourceManager; import controller.ResourceManager;
import controller.ThreadPoolManager; import controller.ThreadPoolManager;
@@ -86,16 +88,22 @@ public class Recording implements Comparable<Recording>,
} }
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
mConfiguration.setCenterFrequency( frequency ); if( event.getAttribute() == Attribute.FREQUENCY )
mResourceManager.getSettingsManager().save();
mCenterFrequency = frequency;
for( TunerChannelSource channel: mTunerChannels )
{ {
channel.frequencyChanged( frequency, bandwidth ); int frequency = (int)event.getValue();
mConfiguration.setCenterFrequency( frequency );
mResourceManager.getSettingsManager().save();
mCenterFrequency = frequency;
for( TunerChannelSource channel: mTunerChannels )
{
channel.frequencyChanged( event );
}
} }
} }

View File

@@ -0,0 +1,34 @@
package source.tuner;
public class FrequencyChangeEvent
{
public enum Attribute
{
SAMPLE_RATE_ERROR,
BANDWIDTH,
FREQUENCY,
FREQUENCY_ERROR,
SAMPLE_RATE;
}
private Attribute mAttribute;
private long mValue;
public FrequencyChangeEvent( Attribute attribute, long value )
{
mAttribute = attribute;
mValue = value;
}
public Attribute getAttribute()
{
return mAttribute;
}
public long getValue()
{
return mValue;
}
}

View File

@@ -18,8 +18,8 @@
package source.tuner; package source.tuner;
/** /**
* Interface for broadcasting changes to frequency and/or bandwidth/sample rate * Interface for broadcasting changes to frequency, bandwidth, sample rate,
* to all registered listeners. * and actual sample rate values to all registered listeners.
* *
* Note: broadcasted frequency should be the uncorrected, or displayable * Note: broadcasted frequency should be the uncorrected, or displayable
* frequency value. All frequency correction aspects should be handled within * frequency value. All frequency correction aspects should be handled within
@@ -27,12 +27,5 @@ package source.tuner;
*/ */
public interface FrequencyChangeListener public interface FrequencyChangeListener
{ {
/** public void frequencyChanged( FrequencyChangeEvent event );
* Broadcasts a change to the (uncorrected) frequency and/or bandwidth
* or sample rate.
*
* @param frequency - uncorrected frequency in hertz
* @param bandwidth - bandwidth in hertz
*/
public void frequencyChanged( long frequency, int bandwidth );
} }

View File

@@ -20,6 +20,7 @@ package source.tuner;
import java.util.ArrayList; import java.util.ArrayList;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent.Attribute;
public class FrequencyController public class FrequencyController
{ {
@@ -29,7 +30,7 @@ public class FrequencyController
private long mMinimumFrequency; private long mMinimumFrequency;
private long mMaximumFrequency; private long mMaximumFrequency;
private double mFrequencyCorrection = 0d; private double mFrequencyCorrection = 0d;
private int mBandwidth = 0; private int mSampleRate = 0;
private ArrayList<FrequencyChangeListener> mListeners = private ArrayList<FrequencyChangeListener> mListeners =
new ArrayList<FrequencyChangeListener>(); new ArrayList<FrequencyChangeListener>();
@@ -50,17 +51,17 @@ public class FrequencyController
*/ */
public int getBandwidth() public int getBandwidth()
{ {
return mBandwidth; return mSampleRate;
} }
/** /**
* Set bandwidth/sample rate in hertz * Set sample rate in hertz
*/ */
public void setBandwidth( int bandwidth ) public void setSampleRate( int sampleRate )
{ {
mBandwidth = bandwidth; mSampleRate = sampleRate;
broadcastFrequencyChange(); broadcastSampleRateChange();
} }
/** /**
@@ -193,12 +194,28 @@ public class FrequencyController
* bandwidth/sample rate value. * bandwidth/sample rate value.
*/ */
protected void broadcastFrequencyChange() protected void broadcastFrequencyChange()
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Attribute.FREQUENCY, mFrequency ) );
}
/**
* Broadcasts a sample rate change
*/
protected void broadcastSampleRateChange()
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Attribute.SAMPLE_RATE, mSampleRate ) );
}
public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event )
{ {
for( FrequencyChangeListener listener: mListeners ) for( FrequencyChangeListener listener: mListeners )
{ {
listener.frequencyChanged( mFrequency, mBandwidth ); listener.frequencyChanged( event );
} }
} }
public interface Tunable public interface Tunable
{ {

View File

@@ -1,127 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner;
import sample.Listener;
import sample.complex.ComplexSample;
import sample.complex.ComplexSampleUtils;
import util.Oscillator;
public class NumericallyControlledOscillator implements Listener<ComplexSample>,
FrequencyChangeListener
{
private long mFrequency;
private int mSampleRate;
private Oscillator mSineWaveGenerator;
private Listener<ComplexSample> mListener;
/**
* Translates (shifts) frequency spectrum up or down, depending on the sign
* of the frequency argument, by mixing received complex samples with a
* generated sine wave of the frequency argument. Positive frequency shifts
* the received spectrum higher in frequency. Negative frequency shifts the
* received spectrum lower in frequency. In both cases, spectrum that is
* shifted outside of the sampling bandwidth will wrap around, due to the
* nature of quadrature sampling.
*/
public NumericallyControlledOscillator( long frequencyShift, int sampleRate )
{
mFrequency = frequencyShift;
mSampleRate = sampleRate;
int defaultMixingSignalGain = 10;
mSineWaveGenerator = new Oscillator( mFrequency, mSampleRate );
}
/**
* Listener method for this class to receive samples from a Complex Sample
* Provider. This method multiplies the incoming sample by the generated
* mixing frequency to translate (ie shift +/-) the incoming signal, and
* then send the translated signal on to all registered listeners
*/
@Override
public void receive( ComplexSample sample )
{
if( mListener != null )
{
mListener.receive( ComplexSampleUtils.multiply( sample,
mSineWaveGenerator.nextComplex() ) );
}
}
@Override
public void frequencyChanged( long frequency, int bandwidth )
{
if( frequency != mFrequency )
{
setFrequency( frequency );
}
if( bandwidth != mSampleRate )
{
setSampleRate( bandwidth );
}
}
/**
* Changes the frequency value and resets the sine wave generator, so that
* all subsequent samples will be output at the new translated frequency
* @param frequency - hertz
*/
public void setFrequency( long frequency )
{
mFrequency = frequency;
mSineWaveGenerator.setFrequency( frequency );
}
/**
* Current frequency shift setting
* @return - frequency - hertz
*/
public long getFrequency()
{
return mFrequency;
}
/**
* Changes the sample rate, so that all new input/output values will be
* translated at the new sample rate
* @param sampleRate - hertz
*/
public void setSampleRate( int sampleRate )
{
mSampleRate = sampleRate;
mSineWaveGenerator.setSampleRate( sampleRate );
}
/**
* Add listener to receive frequency translated complex samples
*/
public void setListener( Listener<ComplexSample> listener )
{
mListener = listener;
}
/**
* Remove listener from receiving frequency translated complex samples.
*/
public void clearListener()
{
mListener = null;
}
}

View File

@@ -24,6 +24,7 @@ import javax.swing.JPanel;
import sample.Listener; import sample.Listener;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent.Attribute;
import controller.ResourceManager; import controller.ResourceManager;
import controller.ThreadPoolManager; import controller.ThreadPoolManager;
@@ -172,11 +173,38 @@ public abstract class Tuner implements FrequencyChangeBroadcaster,
/** /**
* Broadcasts a frequency change event to all registered listeners * Broadcasts a frequency change event to all registered listeners
*/ */
public void broadcastFrequencyChange( long frequency, int bandwidth ) public void broadcastFrequencyChange( long frequency )
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Attribute.FREQUENCY, frequency ) );
}
/**
* Broadcasts a sample rate change event to all registered listeners
*/
public void broadcastSampleRateChange( int sampleRate )
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Attribute.SAMPLE_RATE, sampleRate ) );
}
/**
* Broadcasts actual sample rate change event to all registered listeners
*/
public void broadcastActualSampleRateChange( int actualSampleRate )
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Attribute.SAMPLE_RATE, actualSampleRate ) );
}
/**
* Broadcasts a frequency change event to all registered listeners
*/
public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event )
{ {
for( FrequencyChangeListener listener: mFrequencyChangeListeners ) for( FrequencyChangeListener listener: mFrequencyChangeListeners )
{ {
listener.frequencyChanged( frequency, bandwidth ); listener.frequencyChanged( event );
} }
} }
@@ -184,8 +212,19 @@ public abstract class Tuner implements FrequencyChangeBroadcaster,
* Frequency change listener method. We receive change events from the * Frequency change listener method. We receive change events from the
* controller and rebroadcast them to all registered listeners. * controller and rebroadcast them to all registered listeners.
*/ */
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
broadcastFrequencyChange( frequency, bandwidth ); broadcastFrequencyChangeEvent( event );
} }
// /**
// * Broadcasts a frequency change event to all registered listeners
// */
// public void broadcastBandwidthChange( int bandwidth )
// {
// broadcastFrequencyChangeEvent(
// new FrequencyChangeEvent( Attribute.BANDWIDTH, bandwidth ) );
// }
//
} }

View File

@@ -29,17 +29,16 @@ import sample.complex.ComplexSample;
import sample.complex.ComplexSampleAssembler; import sample.complex.ComplexSampleAssembler;
import source.ComplexSource; import source.ComplexSource;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent.Attribute;
import util.Oscillator; import util.Oscillator;
import controller.ThreadPoolManager; import controller.ThreadPoolManager;
import controller.ThreadPoolManager.ThreadType; import controller.ThreadPoolManager.ThreadType;
import dsp.afc.FrequencyErrorListener;
import dsp.filter.ComplexFilter; import dsp.filter.ComplexFilter;
import dsp.filter.FilterFactory; import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType; import dsp.filter.Window.WindowType;
public class TunerChannelSource extends ComplexSource public class TunerChannelSource extends ComplexSource
implements FrequencyChangeListener, implements FrequencyChangeListener,
FrequencyErrorListener,
Listener<Float[]> Listener<Float[]>
{ {
private static int sCHANNEL_RATE = 48000; private static int sCHANNEL_RATE = 48000;
@@ -64,32 +63,34 @@ public class TunerChannelSource extends ComplexSource
public TunerChannelSource( ThreadPoolManager threadPoolManager, public TunerChannelSource( ThreadPoolManager threadPoolManager,
Tuner tuner, Tuner tuner,
TunerChannel tunerChannel ) TunerChannel tunerChannel )
throws RejectedExecutionException throws RejectedExecutionException, SourceException
{ {
super( "Tuner Channel Source" ); super( "Tuner Channel Source" );
mThreadPoolManager = threadPoolManager; mThreadPoolManager = threadPoolManager;
/* Schedule the decimation task to run 20 times a second */
mTaskHandle = mThreadPoolManager.schedule( ThreadType.DECIMATION,
new DecimationProcessor(), 50, TimeUnit.MILLISECONDS );
mTuner = tuner; mTuner = tuner;
mTuner.addListener( (FrequencyChangeListener)this ); mTuner.addListener( (FrequencyChangeListener)this );
mTunerChannel = tunerChannel; mTunerChannel = tunerChannel;
mTunerFrequency = mTuner.getFrequency();
/* Setup the frequency translator to the current source frequency */ /* Setup the frequency translator to the current source frequency */
try long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency();
{
frequencyChanged( mTuner.getFrequency(), mTuner.getSampleRate() ); mSineWaveGenerator = new Oscillator( frequencyOffset, mTuner.getSampleRate() );
}
catch ( SourceException e )
{
e.printStackTrace();
}
/* Finally, register to receive samples from the tuner */ /* Fire a sample rate change event to get the decimation chain setup */
frequencyChanged( new FrequencyChangeEvent(
Attribute.SAMPLE_RATE, mTuner.getSampleRate() ) );
/* Schedule the decimation task to run 20 times a second */
mTaskHandle = mThreadPoolManager.schedule( ThreadType.DECIMATION,
new DecimationProcessor(), 50, TimeUnit.MILLISECONDS );
/* Finally, register to receive samples from the tuner */
mTuner.addListener( (Listener<Float[]>)this ); mTuner.addListener( (Listener<Float[]>)this );
} }
@@ -156,60 +157,73 @@ public class TunerChannelSource extends ComplexSource
} }
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
/* Send change to Automatic Frequency Control */ /* Send change to Automatic Frequency Control if it exists */
if( mFrequencyChangeListener != null ) if( mFrequencyChangeListener != null )
{ {
mFrequencyChangeListener.frequencyChanged( frequency, bandwidth ); mFrequencyChangeListener.frequencyChanged( event );
} }
long frequencyOffset = frequency -
mTunerChannel.getFrequency() -
mTunerFrequencyError;
if( mSineWaveGenerator == null ) switch( event.getAttribute() )
{ {
mSineWaveGenerator = new Oscillator( frequencyOffset, bandwidth ); case SAMPLE_RATE_ERROR:
} break;
else case SAMPLE_RATE:
{ int sampleRate = (int)event.getValue();
mSineWaveGenerator.setFrequency( frequencyOffset );
} if( mTunerSampleRate != sampleRate )
{
/* Clear the buffer for the frequency to take immediate effect */ /* Set the oscillator to the new frequency */
// mBuffer.clear(); mSineWaveGenerator.setSampleRate( sampleRate );
mTunerFrequency = frequency; /* Get new decimation filters */
mDecimationFilters = FilterFactory
/* Bandwidth/Sample rate change */ .getDecimationFilters( sampleRate,
if( bandwidth != mTunerSampleRate )
{
/* Get the original decimation filter output listener */
// Listener<ComplexSample> listener = null;
/* Get new decimation filters */
mDecimationFilters = FilterFactory
.getDecimationFilters( bandwidth,
sCHANNEL_RATE, sCHANNEL_RATE,
sCHANNEL_PASS_FREQUENCY, sCHANNEL_PASS_FREQUENCY,
48, //dB attenuation 48, //dB attenuation
WindowType.HAMMING ); WindowType.HAMMING );
/* wire the filters together */ /* wire the filters together */
if( mDecimationFilters.length > 1 ) if( mDecimationFilters.length > 1 )
{ {
for( int x = 1; x < mDecimationFilters.length; x++ ) for( int x = 1; x < mDecimationFilters.length; x++ )
{ {
mDecimationFilters[ x - 1 ].setListener( mDecimationFilters[ x ] ); mDecimationFilters[ x - 1 ]
} .setListener( mDecimationFilters[ x ] );
} }
}
/* re-add the original output listener */
mDecimationFilters[ mDecimationFilters.length - 1 ] /* re-add the original output listener */
.setListener( mBufferAssembler ); mDecimationFilters[ mDecimationFilters.length - 1 ]
.setListener( mBufferAssembler );
mTunerSampleRate = bandwidth; mTunerSampleRate = sampleRate;
}
break;
case FREQUENCY_ERROR:
mTunerFrequencyError = (int)event.getValue();
long frequencyErrorOffset = mTunerFrequency -
mTunerChannel.getFrequency() -
mTunerFrequencyError;
mSineWaveGenerator.setFrequency( frequencyErrorOffset );
break;
case FREQUENCY:
int frequency = (int)event.getValue();
/* If the frequency is updated, the AFC will also get reset, so
* we don't include the frequency error value here */
long frequencyOffset = frequency - mTunerChannel.getFrequency();
mSineWaveGenerator.setFrequency( frequencyOffset );
mTunerFrequency = frequency;
break;
default:
break;
} }
} }
@@ -264,20 +278,6 @@ public class TunerChannelSource extends ComplexSource
} }
} }
/**
* Automatic Frequency Control
*/
@Override
public void setError( int error )
{
if( mTunerFrequencyError != error )
{
mTunerFrequencyError = error;
frequencyChanged( mTunerFrequency, mTunerSampleRate );
}
}
@Override
public void addListener( FrequencyChangeListener listener ) public void addListener( FrequencyChangeListener listener )
{ {
mFrequencyChangeListener = listener; mFrequencyChangeListener = listener;

View File

@@ -167,7 +167,8 @@ public abstract class TunerController implements Tunable
updateLOFrequency(); updateLOFrequency();
source = new TunerChannelSource( threadPoolManager, tuner, tunerChannel ); source = new TunerChannelSource( threadPoolManager,
tuner, tunerChannel );
} }
return source; return source;

View File

@@ -42,7 +42,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener
private static DecimalFormat SAMPLE_RATE_FORMAT = new DecimalFormat( "0.000" ); private static DecimalFormat SAMPLE_RATE_FORMAT = new DecimalFormat( "0.000" );
private long mFrequency; private long mFrequency;
private int mBandwidth; private int mSampleRate;
public TunerNode( Tuner tuner ) public TunerNode( Tuner tuner )
{ {
@@ -53,7 +53,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener
try try
{ {
mFrequency = tuner.getFrequency(); mFrequency = tuner.getFrequency();
mBandwidth = tuner.getSampleRate(); mSampleRate = tuner.getSampleRate();
} }
catch ( SourceException e ) catch ( SourceException e )
{ {
@@ -82,7 +82,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener
sb.append( " " ); sb.append( " " );
sb.append( FREQUENCY_FORMAT.format( (double)mFrequency / 1E6d ) ); sb.append( FREQUENCY_FORMAT.format( (double)mFrequency / 1E6d ) );
sb.append( " [" ); sb.append( " [" );
sb.append( SAMPLE_RATE_FORMAT.format( (double)mBandwidth / 1E6d ) ); sb.append( SAMPLE_RATE_FORMAT.format( (double)mSampleRate / 1E6d ) );
sb.append( "] MHz" ); sb.append( "] MHz" );
return sb.toString(); return sb.toString();
@@ -122,11 +122,29 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener
} }
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
mFrequency = frequency; switch( event.getAttribute() )
mBandwidth = bandwidth; {
case FREQUENCY:
getModel().nodeChanged( TunerNode.this ); int frequency = (int)event.getValue();
if( mFrequency != frequency )
{
mFrequency = frequency;
getModel().nodeChanged( TunerNode.this );
}
case SAMPLE_RATE:
int sampleRate = (int)event.getValue();
if( mSampleRate != sampleRate )
{
mSampleRate = sampleRate;
getModel().nodeChanged( TunerNode.this );
}
break;
default:
break;
}
} }
} }

View File

@@ -60,7 +60,7 @@ public class FCD1TunerController extends FCDTunerController
sMINIMUM_TUNABLE_FREQUENCY, sMINIMUM_TUNABLE_FREQUENCY,
sMAXIMUM_TUNABLE_FREQUENCY ); sMAXIMUM_TUNABLE_FREQUENCY );
mFrequencyController.setBandwidth( sSAMPLE_RATE ); mFrequencyController.setSampleRate( sSAMPLE_RATE );
try try
{ {

View File

@@ -30,6 +30,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeEvent.Attribute;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.fcd.FCDTuner; import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerDetailsPanel; import source.tuner.fcd.FCDTunerDetailsPanel;
@@ -91,17 +93,19 @@ public class FCD1TunerEditorPanel extends JPanel implements FrequencyChangeListe
} }
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
//Disregard the bandwidth value, which shouldn't be changing if( event.getAttribute() == Attribute.FREQUENCY )
try {
{ try
mController.setFrequency( frequency ); {
} mController.setFrequency( event.getValue() );
catch ( SourceException e ) }
{ catch ( SourceException e )
mLog.error( "FCTProController - error setting frequency [" + {
frequency + "]", e ); mLog.error( "FCTProController - error setting frequency [" +
} event.getValue() + "]", e );
}
}
} }
} }

View File

@@ -53,7 +53,7 @@ public class FCD2TunerController extends FCDTunerController
sMINIMUM_TUNABLE_FREQUENCY, sMINIMUM_TUNABLE_FREQUENCY,
sMAXIMUM_TUNABLE_FREQUENCY ); sMAXIMUM_TUNABLE_FREQUENCY );
mFrequencyController.setBandwidth( sSAMPLE_RATE ); mFrequencyController.setSampleRate( sSAMPLE_RATE );
try try
{ {

View File

@@ -30,6 +30,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeEvent.Attribute;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.fcd.FCDTuner; import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerDetailsPanel; import source.tuner.fcd.FCDTunerDetailsPanel;
@@ -90,17 +92,20 @@ public class FCD2TunerEditorPanel extends JPanel implements FrequencyChangeListe
} }
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
//Disregard the bandwidth, which shouldn't be changing if( event.getAttribute() == Attribute.FREQUENCY )
try {
{ //Disregard the bandwidth, which shouldn't be changing
mController.setFrequency( frequency ); try
} {
catch ( SourceException e ) mController.setFrequency( event.getValue() );
{ }
mLog.error( "FCTProController - error setting frequency [" + catch ( SourceException e )
frequency + "]", e ); {
} mLog.error( "FCDProController - error setting frequency [" +
event.getValue() + "]", e );
}
}
} }
} }

View File

@@ -60,10 +60,13 @@ import org.usb4java.LibUsb;
import sample.Listener; import sample.Listener;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeEvent.Attribute;
import source.tuner.TunerController; import source.tuner.TunerController;
import source.tuner.TunerType; import source.tuner.TunerType;
import source.tuner.usb.USBTunerDevice; import source.tuner.usb.USBTunerDevice;
import util.TimeStamp; import util.TimeStamp;
import buffer.FloatAveragingBuffer;
import controller.ResourceManager; import controller.ResourceManager;
public abstract class RTL2832TunerController extends TunerController public abstract class RTL2832TunerController extends TunerController
@@ -85,7 +88,6 @@ public abstract class RTL2832TunerController extends TunerController
(byte)( LibUsb.ENDPOINT_OUT | LibUsb.REQUEST_TYPE_VENDOR ); (byte)( LibUsb.ENDPOINT_OUT | LibUsb.REQUEST_TYPE_VENDOR );
public final static byte sREQUEST_ZERO = (byte)0; public final static byte sREQUEST_ZERO = (byte)0;
public final static int sUSB_IRP_DATA_SIZE = 65536;
public final static int sUSB_IRP_POOL_SIZE = 10; public final static int sUSB_IRP_POOL_SIZE = 10;
public final static byte EEPROM_ADDRESS = (byte)0xA0; public final static byte EEPROM_ADDRESS = (byte)0xA0;
@@ -135,7 +137,9 @@ public abstract class RTL2832TunerController extends TunerController
}; };
private static final DecimalFormat mDecimalFormatter = private static final DecimalFormat mDecimalFormatter =
new DecimalFormat( "###,###,###.#" ); new DecimalFormat( "###,###,###.0" );
private static final DecimalFormat mPercentFormatter =
new DecimalFormat( "###.00" );
private USBTunerDevice mUSBTunerDevice; private USBTunerDevice mUSBTunerDevice;
protected UsbDevice mUSBDevice; protected UsbDevice mUSBDevice;
@@ -163,6 +167,9 @@ public abstract class RTL2832TunerController extends TunerController
private int mSampleRateAverageCount; private int mSampleRateAverageCount;
protected int mOscillatorFrequency = 28800000; //28.8 MHz protected int mOscillatorFrequency = 28800000; //28.8 MHz
private SampleRateMonitor mSampleRateMonitor;
public int mBufferSize = 16384;
/** /**
* Abstract tuner controller device. Use the static getTunerClass() method * Abstract tuner controller device. Use the static getTunerClass() method
* to determine the tuner type, and construct the corresponding child * to determine the tuner type, and construct the corresponding child
@@ -1163,7 +1170,17 @@ public abstract class RTL2832TunerController extends TunerController
mSampleRate = sampleRate; mSampleRate = sampleRate;
mFrequencyController.setBandwidth( sampleRate.getRate() ); /**
* Adjust the size of the byte array buffers sent over the USB bus
*/
mBufferSize = mSampleRate.getBufferSize();
mFrequencyController.setSampleRate( sampleRate.getRate() );
if( mSampleRateMonitor != null )
{
mSampleRateMonitor.setSampleRate( mSampleRate.getRate() );
}
} }
public void setSampleRateFrequencyCorrection( int ppm ) public void setSampleRateFrequencyCorrection( int ppm )
@@ -1392,34 +1409,37 @@ public abstract class RTL2832TunerController extends TunerController
public enum SampleRate public enum SampleRate
{ {
/* Note: sample rates below 1.0MHz are subject to aliasing */ /* Note: sample rates below 1.0MHz are subject to aliasing */
RATE_0_240MHZ( 0x0DFC, 0x0000, 240000, "0.240 MHz" ), RATE_0_240MHZ( 0x0DFC, 0x0000, 240000, "0.240 MHz", 16384 ),
RATE_0_288MHZ( 0x08FC, 0x0000, 288000, "0.288 MHz" ), RATE_0_288MHZ( 0x08FC, 0x0000, 288000, "0.288 MHz", 16384 ),
RATE_0_912MHZ( 0x07E6, 0x0000, 912000, "0.912 MHz" ), RATE_0_912MHZ( 0x07E4, 0x0000, 912000, "0.912 MHz", 32768 ),
RATE_0_960MHZ( 0x077A, 0x0000, 960000, "0.960 MHz" ), RATE_0_960MHZ( 0x0778, 0x0000, 960000, "0.960 MHz", 32768 ),
RATE_1_200MHZ( 0x05F4, 0x0000, 1200000, "1.200 MHz" ), RATE_1_200MHZ( 0x05F4, 0x0000, 1200000, "1.200 MHz", 65536 ),
RATE_1_440MHZ( 0x0500, 0x0000, 1440000, "1.440 MHz" ), RATE_1_440MHZ( 0x04FC, 0x0000, 1440000, "1.440 MHz", 65536 ),
RATE_1_680MHZ( 0x044A, 0x0000, 1680000, "1.680 MHz" ), RATE_1_680MHZ( 0x0448, 0x0000, 1680000, "1.680 MHz", 65536 ),
RATE_1_824MHZ( 0x03F3, 0x0000, 1824000, "1.824 MHz" ), RATE_1_824MHZ( 0x03F0, 0x0000, 1824000, "1.824 MHz", 65536 ),
RATE_2_016MHZ( 0x038F, 0x0000, 2016000, "2.016 MHz" ); RATE_2_016MHZ( 0x038C, 0x0000, 2016000, "2.016 MHz", 131072 ),
RATE_2_208MHZ( 0x0340, 0x0000, 2208000, "2.208 MHz", 131072 ),
/* Note: usb4java library buffer processing scheme doesn't seem capable RATE_2_400MHZ( 0x02FC, 0x0000, 2400000, "2.400 MHz", 131072 ),
* of supporting these rates */ RATE_2_640MHZ( 0x02B4, 0x8000, 2640000, "2.640 MHz", 262144 ),
//RATE_2_400MHZ( 0x0300, 0x0000, 2400000, "2.400 MHz" ), RATE_2_880MHZ( 0x027C, 0x0000, 2880000, "2.880 MHz", 262144 );
//RATE_2_880MHZ( 0x0280, 0x0000, 2880000, "2.880 MHz" ),
//RATE_3_072MHZ( 0x0258, 0x0000, 3072000, "3.072 MHz" ),
//RATE_3_216MHZ( 0x023D, 0x0000, 3216000, "3.216 MHz" );
private int mRatioHigh; private int mRatioHigh;
private int mRatioLow; private int mRatioLow;
private int mRate; private int mRate;
private String mLabel; private String mLabel;
private int mBufferSize;
private SampleRate( int ratioHigh, int ratioLow, int rate, String label ) private SampleRate( int ratioHigh,
int ratioLow,
int rate,
String label,
int bufferSize )
{ {
mRatioHigh = ratioHigh; mRatioHigh = ratioHigh;
mRatioLow = ratioLow; mRatioLow = ratioLow;
mRate = rate; mRate = rate;
mLabel = label; mLabel = label;
mBufferSize = bufferSize;
} }
public int getRatioHighBits() public int getRatioHighBits()
@@ -1447,6 +1467,11 @@ public abstract class RTL2832TunerController extends TunerController
return mLabel; return mLabel;
} }
public int getBufferSize()
{
return mBufferSize;
}
/** /**
* Returns the sample rate that is equal to the argument or the next * Returns the sample rate that is equal to the argument or the next
* higher sample rate * higher sample rate
@@ -1545,7 +1570,7 @@ public abstract class RTL2832TunerController extends TunerController
for( int x = 0; x < sUSB_IRP_POOL_SIZE; x++ ) for( int x = 0; x < sUSB_IRP_POOL_SIZE; x++ )
{ {
UsbIrp irp = mUSBPipe.createUsbIrp(); UsbIrp irp = mUSBPipe.createUsbIrp();
irp.setData( new byte[ sUSB_IRP_DATA_SIZE ] ); irp.setData( new byte[ mBufferSize ] );
irps.add( irp ); irps.add( irp );
} }
@@ -1566,12 +1591,15 @@ public abstract class RTL2832TunerController extends TunerController
if( mUSBPipe.isOpen() ) if( mUSBPipe.isOpen() )
{ {
mSampleDispatcherTask = mExecutor mSampleDispatcherTask = mExecutor
.scheduleAtFixedRate( new BufferDispatcher(), .scheduleAtFixedRate( new BufferDispatcher(),
0, 20, TimeUnit.MILLISECONDS ); 0, 20, TimeUnit.MILLISECONDS );
mSampleRateMonitor =
new SampleRateMonitor( mSampleRate.getRate() );
mSampleRateCounterTask = mExecutor mSampleRateCounterTask = mExecutor
.scheduleAtFixedRate( new SampleRateMonitor(), .scheduleAtFixedRate( mSampleRateMonitor,
60, 60, TimeUnit.SECONDS ); 10, 10, TimeUnit.SECONDS );
mUSBPipe.asyncSubmit( irps ); mUSBPipe.asyncSubmit( irps );
} }
@@ -1645,7 +1673,7 @@ public abstract class RTL2832TunerController extends TunerController
{ {
try try
{ {
mUSBPipe.asyncSubmit( new byte[ sUSB_IRP_DATA_SIZE ] ); mUSBPipe.asyncSubmit( new byte[ mBufferSize ] );
} }
catch ( UsbNotActiveException | UsbNotOpenException catch ( UsbNotActiveException | UsbNotOpenException
| IllegalArgumentException | UsbDisconnectedException | IllegalArgumentException | UsbDisconnectedException
@@ -1707,37 +1735,103 @@ public abstract class RTL2832TunerController extends TunerController
*/ */
public class SampleRateMonitor implements Runnable public class SampleRateMonitor implements Runnable
{ {
private static final int BUFFER_SIZE = 5;
private int mTargetSampleRate;
private int mSampleRateMinimum;
private int mSampleRateMaximum;
private int mNewTargetSampleRate;
private FloatAveragingBuffer mRateErrorBuffer =
new FloatAveragingBuffer( BUFFER_SIZE );
private AtomicBoolean mRateChanged = new AtomicBoolean();
public SampleRateMonitor( int sampleRate )
{
setTargetRate( sampleRate );
}
public void setSampleRate( int sampleRate )
{
mNewTargetSampleRate = sampleRate;
mRateChanged.set( true );
}
private void setTargetRate( int rate )
{
mTargetSampleRate = rate;
mSampleRateMinimum = (int)( (float)mTargetSampleRate * 0.95f );
mSampleRateMaximum = (int)( (float)mTargetSampleRate * 1.05f );
for( int x = 0; x < BUFFER_SIZE; x++ )
{
mRateErrorBuffer.get( 0 );
}
}
@Override @Override
public void run() public void run()
{ {
int count = mSampleCounter.getAndSet( 0 ); if( mRateChanged.compareAndSet( true, false ) )
double rate = (double)count / 120.0d;
mSampleRateAverageSum += rate;
mSampleRateAverageCount++;
double average = mSampleRateAverageSum / (double)mSampleRateAverageCount;
StringBuilder sb = new StringBuilder();
sb.append( TimeStamp.getTimeStamp( " " ) );
sb.append( " RTL-2832 [" );
if( mDescriptor != null )
{ {
sb.append( mDescriptor.getSerial() ); setTargetRate( mNewTargetSampleRate );
/* Reset the sample counter */
mSampleCounter.set( 0 );
mLog.info( "monitor reset for new sample rate [" + mTargetSampleRate + "]" );
System.out.println( "monitor reset for new sample rate [" + mTargetSampleRate + "]" );
} }
else else
{ {
sb.append( "DESCRIPTOR IS NULL" ); int count = mSampleCounter.getAndSet( 0 );
float current = (float)count / 20.0f;
/**
* Only accept values +/- 5% of target rate
*/
float average;
if( mSampleRateMinimum < current && current < mSampleRateMaximum )
{
average = mRateErrorBuffer.get( (float)mTargetSampleRate - current );
/* broadcast an actual sample rate update */
if( mFrequencyController != null )
{
mFrequencyController.broadcastFrequencyChangeEvent(
new FrequencyChangeEvent(
Attribute.SAMPLE_RATE_ERROR, (int)average ) );
}
}
else
{
average = mTargetSampleRate;
}
StringBuilder sb = new StringBuilder();
sb.append( TimeStamp.getTimeStamp( " " ) );
sb.append( " RTL-2832 [" );
if( mDescriptor != null )
{
sb.append( mDescriptor.getSerial() );
}
else
{
sb.append( "DESCRIPTOR IS NULL" );
}
sb.append( "] sample rate current [" );
sb.append( mDecimalFormatter.format( current ) );
sb.append( " Hz " );
sb.append( mPercentFormatter.format( 100.0f * ( current / (float)mTargetSampleRate ) ) );
sb.append( "% ] average error [" );
sb.append( average );
sb.append( " Hz ] target " );
sb.append( mTargetSampleRate );
System.out.println( sb.toString() );
mLog.info( sb.toString() );
} }
sb.append( "] Sample Rate - current: " );
sb.append( mDecimalFormatter.format( rate ) );
sb.append( "\taverage: " );
sb.append( mDecimalFormatter.format( average ) );
sb.append( " count:" );
sb.append( mSampleRateAverageCount );
mLog.info( sb.toString() );
} }
} }

View File

@@ -31,7 +31,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.FrequencyChangeEvent.Attribute;
import source.tuner.rtl.RTL2832InfoPanel; import source.tuner.rtl.RTL2832InfoPanel;
import com.jidesoft.swing.JideTabbedPane; import com.jidesoft.swing.JideTabbedPane;
@@ -94,23 +96,28 @@ public class E4KTunerEditorPanel extends JPanel implements FrequencyChangeListen
* apply end-user requested frequency changes against the tuner * apply end-user requested frequency changes against the tuner
*/ */
@Override @Override
public void frequencyChanged( final long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
EventQueue.invokeLater( new Runnable() if( event.getAttribute() == Attribute.FREQUENCY )
{ {
@Override final int frequency = (int)event.getValue();
public void run()
{ EventQueue.invokeLater( new Runnable()
try {
{ @Override
mController.setFrequency( frequency ); public void run()
} {
catch ( SourceException e ) try
{ {
mLog.error( "E4KTunerController - error setting frequency [" + mController.setFrequency( frequency );
frequency + "]", e ); }
} catch ( SourceException e )
} {
} ); mLog.error( "E4KTunerController - error setting frequency [" +
frequency + "]", e );
}
}
} );
}
} }
} }

View File

@@ -77,6 +77,7 @@ public class R820TTunerConfigurationPanel extends JPanel
private JTextField mName; private JTextField mName;
private JSpinner mFrequencyCorrection; private JSpinner mFrequencyCorrection;
private JSpinner mSampleRateCorrection;
private JComboBox<R820TGain> mComboMasterGain; private JComboBox<R820TGain> mComboMasterGain;
private JComboBox<R820TMixerGain> mComboMixerGain; private JComboBox<R820TMixerGain> mComboMixerGain;
private JComboBox<R820TLNAGain> mComboLNAGain; private JComboBox<R820TLNAGain> mComboLNAGain;
@@ -268,6 +269,65 @@ public class R820TTunerConfigurationPanel extends JPanel
add( new JLabel( "Sample Rate:" ) ); add( new JLabel( "Sample Rate:" ) );
add( mComboSampleRate, "growx,push" ); add( mComboSampleRate, "growx,push" );
/**
* Sample Rate Correction
*/
SpinnerModel sampleRateCorrectionModel =
new SpinnerNumberModel( 0, //initial value
-32768, //min
32767, //max
1 ); //step
mSampleRateCorrection = new JSpinner( sampleRateCorrectionModel );
JSpinner.NumberEditor sampleRateCorrectionEditor =
(JSpinner.NumberEditor)mSampleRateCorrection.getEditor();
DecimalFormat sampleRateCorrectionFormat =
sampleRateCorrectionEditor.getFormat();
sampleRateCorrectionFormat.setMinimumFractionDigits( 0 );
sampleRateCorrectionEditor.getTextField()
.setHorizontalAlignment( SwingConstants.CENTER );
mSampleRateCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
final int value = ((SpinnerNumberModel)mSampleRateCorrection
.getModel()).getNumber().intValue();
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
mController.setSampleRateFrequencyCorrection( value );
}
catch ( SourceException | UsbException e1 )
{
JOptionPane.showMessageDialog(
R820TTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't apply "
+ "sample rate correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply "
+ "sample rate correction value: " + value +
e1.getLocalizedMessage() );
}
}
} );
}
} );
add( mSampleRateCorrection );
add( new JLabel( "Sample Rate Correction (ppm)" ), "grow,push" );
/** /**
* Gain Controls * Gain Controls
*/ */

View File

@@ -31,7 +31,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.FrequencyChangeEvent.Attribute;
import source.tuner.rtl.RTL2832InfoPanel; import source.tuner.rtl.RTL2832InfoPanel;
import com.jidesoft.swing.JideTabbedPane; import com.jidesoft.swing.JideTabbedPane;
@@ -93,23 +95,28 @@ public class R820TTunerEditorPanel extends JPanel implements FrequencyChangeList
* apply end-user requested frequency changes against the tuner * apply end-user requested frequency changes against the tuner
*/ */
@Override @Override
public void frequencyChanged( final long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
EventQueue.invokeLater( new Runnable() if( event.getAttribute() == Attribute.FREQUENCY )
{ {
@Override final int frequency = (int)event.getValue();
public void run()
{ EventQueue.invokeLater( new Runnable()
try {
{ @Override
mController.setFrequency( frequency ); public void run()
} {
catch ( SourceException e ) try
{ {
mLog.error( "R820T Tuner Controller - error setting frequency [" + mController.setFrequency( frequency );
frequency + "]", e ); }
} catch ( SourceException e )
} {
} ); mLog.error( "R820T Tuner Controller - error setting frequency [" +
frequency + "]", e );
}
}
} );
}
} }
} }

View File

@@ -23,6 +23,8 @@ import settings.Setting;
import settings.SettingChangeListener; import settings.SettingChangeListener;
import settings.SettingsManager; import settings.SettingsManager;
import source.Source.SampleType; import source.Source.SampleType;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeEvent.Attribute;
import spectrum.converter.DFTResultsConverter; import spectrum.converter.DFTResultsConverter;
import spectrum.converter.RealDecibelConverter; import spectrum.converter.RealDecibelConverter;
import spectrum.menu.AmplificationItem; import spectrum.menu.AmplificationItem;
@@ -86,7 +88,8 @@ public class ChannelSpectrumPanel extends JPanel
mDecimatingSampleAssembler = new DecimatingSampleAssembler( mDFTProcessor ); mDecimatingSampleAssembler = new DecimatingSampleAssembler( mDFTProcessor );
/* Set the DFTProcessor to the decimated 24kHz sample rate */ /* Set the DFTProcessor to the decimated 24kHz sample rate */
mDFTProcessor.frequencyChanged( 0, 24000 ); mDFTProcessor.frequencyChanged(
new FrequencyChangeEvent( Attribute.SAMPLE_RATE, 24000 ) );
initGui(); initGui();
} }

View File

@@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory;
import sample.Listener; import sample.Listener;
import source.Source; import source.Source;
import source.Source.SampleType; import source.Source.SampleType;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import spectrum.converter.DFTResultsConverter; import spectrum.converter.DFTResultsConverter;
import dsp.filter.Window; import dsp.filter.Window;
@@ -443,11 +444,19 @@ public class DFTProcessor implements Listener<Float[]>,
} }
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
mSampleRate = bandwidth; switch( event.getAttribute() )
{
calculateConsumptionRate(); case SAMPLE_RATE_ERROR:
break;
case SAMPLE_RATE:
mSampleRate = (int)event.getValue();
calculateConsumptionRate();
break;
default:
break;
}
} }
/** /**

View File

@@ -36,6 +36,7 @@ import settings.ColorSetting;
import settings.ColorSetting.ColorSettingName; import settings.ColorSetting.ColorSettingName;
import settings.Setting; import settings.Setting;
import settings.SettingChangeListener; import settings.SettingChangeListener;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.TunerChannel; import source.tuner.TunerChannel;
import controller.ResourceManager; import controller.ResourceManager;
@@ -523,10 +524,22 @@ public class OverlayPanel extends JPanel
* Frequency change event handler * Frequency change event handler
*/ */
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
mBandwidth = bandwidth; switch( event.getAttribute() )
mFrequency = frequency; {
case SAMPLE_RATE_ERROR:
// System.out.println( "OVerlay panel got a sample rate error update" );
break;
case SAMPLE_RATE:
mBandwidth = (int)event.getValue();
break;
case FREQUENCY:
mFrequency = (int)event.getValue();
break;
default:
break;
}
/** /**
* Reset the visible channel configs list * Reset the visible channel configs list

View File

@@ -55,9 +55,11 @@ import settings.SettingChangeListener;
import settings.SettingsManager; import settings.SettingsManager;
import source.Source.SampleType; import source.Source.SampleType;
import source.SourceException; import source.SourceException;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeListener; import source.tuner.FrequencyChangeListener;
import source.tuner.Tuner; import source.tuner.Tuner;
import source.tuner.TunerSelectionListener; import source.tuner.TunerSelectionListener;
import source.tuner.FrequencyChangeEvent.Attribute;
import spectrum.converter.ComplexDecibelConverter; import spectrum.converter.ComplexDecibelConverter;
import spectrum.converter.DFTResultsConverter; import spectrum.converter.DFTResultsConverter;
import spectrum.menu.AmplificationItem; import spectrum.menu.AmplificationItem;
@@ -340,10 +342,10 @@ public class SpectralDisplayPanel extends JPanel
* Receives frequency change events -- primarily from tuner components. * Receives frequency change events -- primarily from tuner components.
*/ */
@Override @Override
public void frequencyChanged( long frequency, int bandwidth ) public void frequencyChanged( FrequencyChangeEvent event )
{ {
mOverlayPanel.frequencyChanged( frequency, bandwidth ); mOverlayPanel.frequencyChanged( event );
mDFTProcessor.frequencyChanged( frequency, bandwidth ); mDFTProcessor.frequencyChanged( event );
} }
/** /**
@@ -381,11 +383,15 @@ public class SpectralDisplayPanel extends JPanel
//Register the dft processor to receive samples from the tuner //Register the dft processor to receive samples from the tuner
mTuner.addListener( (Listener<Float[]>)mDFTProcessor ); mTuner.addListener( (Listener<Float[]>)mDFTProcessor );
//Fire a frequency change event so that everyone can init //Fire frequency and sample rate change events so that everyone
//can init
try try
{ {
frequencyChanged( mTuner.getFrequency(), frequencyChanged( new FrequencyChangeEvent(
mTuner.getSampleRate() ); Attribute.FREQUENCY, mTuner.getFrequency() ) );
frequencyChanged( new FrequencyChangeEvent(
Attribute.SAMPLE_RATE, mTuner.getSampleRate() ) );
} }
catch ( SourceException e ) catch ( SourceException e )
{ {

View File

@@ -42,6 +42,11 @@ public class Oscillator
update(); update();
} }
public ComplexSample getCurrentAngle()
{
return mCurrentAngle;
}
private void update() private void update()
{ {
float anglePerSample = float anglePerSample =
@@ -64,6 +69,7 @@ public class Oscillator
*/ */
public void setSampleRate( int sampleRate ) public void setSampleRate( int sampleRate )
{ {
System.out.println( "Oscillator - setting sampleRate to:" + sampleRate );
mSampleRate = (double)sampleRate; mSampleRate = (double)sampleRate;
update(); update();
} }