/*******************************************************************************
* 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.frequency;
import java.util.ArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.InvalidFrequencyException;
import source.Source;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeEvent.Event;
public class FrequencyController
{
private final static Logger mLog = LoggerFactory.getLogger( FrequencyController.class );
private Tunable mTunable;
private long mFrequency = 101100000;
private long mTunedFrequency = 101100000;
private long mMinimumFrequency;
private long mMaximumFrequency;
private double mFrequencyCorrection = 0d;
private int mSampleRate = 0;
private ArrayList<IFrequencyChangeProcessor> mProcessors = new ArrayList<>();
public FrequencyController( Tunable tunable,
long minFrequency,
long maxFrequency,
double frequencyCorrection )
{
mTunable = tunable;
mMinimumFrequency = minFrequency;
mMaximumFrequency = maxFrequency;
mFrequencyCorrection = frequencyCorrection;
}
/**
* Get bandwidth/sample rate in hertz
*/
public int getBandwidth()
{
return mSampleRate;
}
/**
* Set sample rate in hertz
*/
public void setSampleRate( int sampleRate ) throws SourceException
{
mSampleRate = sampleRate;
broadcastSampleRateChange();
}
/**
* Get frequency in hertz
*/
public long getFrequency()
{
return mFrequency;
}
/**
* Set frequency
* @param frequency in hertz
* @throws SourceException if tunable doesn't support tuning a corrected
* version of the requested frequency
*/
public void setFrequency( long frequency ) throws SourceException
{
setFrequency( frequency, true );
}
/**
* Set frequency with optional broadcast of frequency change event. This
* method supports changing the frequency correction value without
* broadcasting a frequency change event.
*/
private void setFrequency( long frequency, boolean broadcastChange ) throws SourceException
{
long tunedFrequency = getTunedFrequency( frequency );
if( tunedFrequency < mMinimumFrequency )
{
throw new InvalidFrequencyException( "Requested frequency not valid", frequency, mMinimumFrequency );
}
if( tunedFrequency > mMaximumFrequency )
{
throw new InvalidFrequencyException( "Requested frequency not valid", frequency, mMaximumFrequency );
}
mFrequency = frequency;
mTunedFrequency = tunedFrequency;
if( mTunable != null )
{
mTunable.setTunedFrequency( mTunedFrequency );
}
/* Broadcast to all listeners that the frequency has changed */
if( broadcastChange )
{
broadcastFrequencyChange();
}
}
public long getTunedFrequency()
{
return mTunedFrequency;
}
public long getMinimumFrequency()
{
return mMinimumFrequency;
}
public long getMaximumFrequency()
{
return mMaximumFrequency;
}
/**
* Calculate the tuned frequency by adding frequency correction to the
* corrected frequency.
* @param correctedFrequency
*/
private long getTunedFrequency( long correctedFrequency )
{
return (long)( (double)correctedFrequency /
( 1.0 + ( mFrequencyCorrection / 1000000.0 ) ) );
}
/**
* Calculate the corrected frequency by subtracting frequency correction
* from the tuned frequency.
* @param tunedFrequency
*/
@SuppressWarnings("unused")
private long getCorrectedFrequency( long tunedFrequency )
{
return (long)( (double)tunedFrequency /
( 1.0 - ( mFrequencyCorrection / 1000000.0 ) ) );
}
public double getFrequencyCorrection()
{
return mFrequencyCorrection;
}
public void setFrequencyCorrection( double correction ) throws SourceException
{
mFrequencyCorrection = correction;
if( mFrequency > 0 )
{
setFrequency( mFrequency, true );
}
broadcastFrequencyErrorChange();
}
/**
* Adds listener to receive frequency change events
*/
//TODO: rename this to addFrequencyChangeProcessor()
public void addListener( IFrequencyChangeProcessor processor )
{
if( !mProcessors.contains( processor ) )
{
mProcessors.add( processor );
}
}
/**
* Removes listener from receiving frequency change events
*/
public void removeFrequencyChangeProcessor( IFrequencyChangeProcessor processor )
{
mProcessors.remove( processor );
}
/**
* Broadcasts a change/update to the current (uncorrected) frequency or the
* bandwidth/sample rate value.
*/
protected void broadcastFrequencyChange() throws SourceException
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CHANGE, mFrequency ) );
}
/**
* Broadcast a frequency error/correction value change
*/
protected void broadcastFrequencyErrorChange() throws SourceException
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CORRECTION_CHANGE, mFrequencyCorrection ) );
}
/**
* Broadcasts a sample rate change
*/
protected void broadcastSampleRateChange() throws SourceException
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.NOTIFICATION_SAMPLE_RATE_CHANGE, mSampleRate ) );
}
public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event ) throws SourceException
{
for( IFrequencyChangeProcessor processor: mProcessors )
{
processor.frequencyChanged( event );
}
}
public interface Tunable
{
/**
* Gets the tuned frequency of the device
*/
public long getTunedFrequency() throws SourceException;
/**
* Sets the tuned frequency of the device
*/
public void setTunedFrequency( long frequency ) throws SourceException;
/**
* Gets the current bandwidth setting of the device
*/
public int getCurrentSampleRate() throws SourceException;
}
}