diff --git a/src/source/tuner/airspy/AirspyTuner.java b/src/source/tuner/airspy/AirspyTuner.java index a424d98f..36df0315 100644 --- a/src/source/tuner/airspy/AirspyTuner.java +++ b/src/source/tuner/airspy/AirspyTuner.java @@ -118,7 +118,7 @@ public class AirspyTuner extends Tuner @Override public double getSampleSize() { - return 12.0; + return 13.0; } @Override diff --git a/src/source/tuner/airspy/AirspyTunerConfiguration.java b/src/source/tuner/airspy/AirspyTunerConfiguration.java index b21c0dd6..52a3a818 100644 --- a/src/source/tuner/airspy/AirspyTunerConfiguration.java +++ b/src/source/tuner/airspy/AirspyTunerConfiguration.java @@ -21,10 +21,12 @@ import javax.xml.bind.annotation.XmlAttribute; import source.tuner.TunerConfiguration; import source.tuner.TunerType; +import source.tuner.airspy.AirspyTunerController.Gain; public class AirspyTunerConfiguration extends TunerConfiguration { private int mSampleRate = AirspyTunerController.DEFAULT_SAMPLE_RATE.getRate(); + private Gain mGain = AirspyTunerController.LINEARITY_GAIN_DEFAULT; private int mIFGain = AirspyTunerController.IF_GAIN_DEFAULT; private int mMixerGain = AirspyTunerController.MIXER_GAIN_DEFAULT; private int mLNAGain = AirspyTunerController.LNA_GAIN_DEFAULT; @@ -62,6 +64,17 @@ public class AirspyTunerConfiguration extends TunerConfiguration mSampleRate = sampleRate; } + @XmlAttribute( name = "gain" ) + public Gain getGain() + { + return mGain; + } + + public void setGain( Gain gain ) + { + mGain = gain; + } + @XmlAttribute( name = "if_gain" ) public int getIFGain() { diff --git a/src/source/tuner/airspy/AirspyTunerConfigurationPanel.java b/src/source/tuner/airspy/AirspyTunerConfigurationPanel.java index 36faa33b..e2d31475 100644 --- a/src/source/tuner/airspy/AirspyTunerConfigurationPanel.java +++ b/src/source/tuner/airspy/AirspyTunerConfigurationPanel.java @@ -49,6 +49,8 @@ import source.SourceException; import source.tuner.TunerConfiguration; import source.tuner.TunerConfigurationAssignment; import source.tuner.TunerType; +import source.tuner.airspy.AirspyTunerController.Gain; +import source.tuner.airspy.AirspyTunerController.GainMode; import controller.ResourceManager; public class AirspyTunerConfigurationPanel extends JPanel @@ -69,18 +71,28 @@ public class AirspyTunerConfigurationPanel extends JPanel private JTextField mName; private JComboBox mSampleRateCombo; - private JComboBox mDecimationCombo; - private JLabel mEffectiveRate; + private JComboBox mGainModeCombo; + private JLabel mGainLabel; + private JLabel mGainFillerLabel; + private JLabel mGainValueLabel; + private JSlider mGain; + private JLabel mIFGainLabel; + private JLabel mIFGainFillerLabel; + private JLabel mIFGainValueLabel; private JSlider mIFGain; + private JLabel mLNAGainLabel; + private JCheckBox mLNAAGC; + private JLabel mLNAGainValueLabel; private JSlider mLNAGain; + + private JLabel mMixerGainValueLabel; + private JCheckBox mMixerAGC; private JLabel mMixerGainLabel; private JSlider mMixerGain; - private JCheckBox mMixerAGC; - private JCheckBox mLNAAGC; public AirspyTunerConfigurationPanel( ResourceManager resourceManager, AirspyTunerController controller ) @@ -210,8 +222,6 @@ public class AirspyTunerConfigurationPanel extends JPanel mController.setSampleRate( rate ); mSelectedConfig.setSampleRate( rate.getRate() ); save(); - - mEffectiveRate.setText( rate.getLabel() ); } catch ( LibUsbException | UsbException e1 ) { @@ -225,31 +235,102 @@ public class AirspyTunerConfigurationPanel extends JPanel add( mSampleRateCombo, "span 3,growx" ); - /** - * Decimation - */ - add( new JLabel( "Decimation:" ) ); - mDecimationCombo = new JComboBox(); - add( mDecimationCombo, "span 3,growx" ); - mDecimationCombo.setEnabled( false ); - - /** - * Effective Rate - */ - add( new JLabel( "Effective Rate:" ) ); - mEffectiveRate = new JLabel( "10,000,000" ); - add( mEffectiveRate, "span 3,growx" ); - add( new JSeparator(), "span,growx,push" ); + /** + * Gain Mode + */ + add( new JLabel( "Gain Mode:" ) ); + mGainModeCombo = new JComboBox( GainMode.values() ); + mGainModeCombo.setSelectedItem( Gain.getGainMode( mSelectedConfig.getGain() ) ); + mGainModeCombo.addActionListener( new ActionListener() + { + @Override + public void actionPerformed( ActionEvent e ) + { + GainMode mode = (GainMode)mGainModeCombo.getSelectedItem(); + updateGainComponents( mode ); + + switch( mode ) + { + case LINEARITY: + mGain.setValue( AirspyTunerController.LINEARITY_GAIN_DEFAULT.getValue() ); + mSelectedConfig.setGain( AirspyTunerController.LINEARITY_GAIN_DEFAULT ); + break; + case SENSITIVITY: + mGain.setValue( AirspyTunerController.SENSITIVITY_GAIN_DEFAULT.getValue() ); + mSelectedConfig.setGain( AirspyTunerController.SENSITIVITY_GAIN_DEFAULT ); + break; + case CUSTOM: + default: + mLNAGain.setValue( mSelectedConfig.getLNAGain() ); + mMixerGain.setValue( mSelectedConfig.getMixerGain() ); + mIFGain.setValue( mSelectedConfig.getIFGain() ); + mSelectedConfig.setGain( Gain.CUSTOM ); + break; + } + + save(); + } + } ); + + add( mGainModeCombo, "wrap" ); + + /** + * Gain + */ + mGainLabel = new JLabel( "Gain" ); + add( mGainLabel ); + mGainFillerLabel = new JLabel( "" ); + add( mGainFillerLabel, "span 2" ); + mGainValueLabel = new JLabel( String.valueOf( mSelectedConfig.getGain().getValue() ) ); + add( mGainValueLabel, "wrap" ); + mGain = new JSlider( JSlider.HORIZONTAL, + AirspyTunerController.GAIN_MIN, + AirspyTunerController.GAIN_MAX, + mSelectedConfig.getGain().getValue() ); + mGain.setMajorTickSpacing( 1 ); + mGain.setPaintTicks( true ); + + mGain.addChangeListener( new ChangeListener() + { + @Override + public void stateChanged( ChangeEvent event ) + { + GainMode mode = (GainMode)mGainModeCombo.getSelectedItem(); + int value = mGain.getValue(); + Gain gain = Gain.getGain( mode, value ); + + try + { + mController.setGain( gain ); + mSelectedConfig.setGain( gain ); + save(); + mGainValueLabel.setText( String.valueOf( gain.getValue() ) ); + } + catch ( Exception e ) + { + mLog.error( "Couldn't set airspy gain to:" + gain.name(), e ); + + JOptionPane.showMessageDialog( mGain, + "Couldn't set gain value to " + gain.getValue() ); + + mGain.setValue( mSelectedConfig.getGain().getValue() ); + } + } + } ); + + add( mGain, "span,grow" ); + /** * IF/VGA Gain */ - add( new JLabel( "IF Gain" ) ); - add( new JLabel( "" ), "span 2" ); - - mIFGainLabel = new JLabel( String.valueOf( mSelectedConfig.getIFGain() ) ); - add( mIFGainLabel, "wrap" ); + mIFGainLabel = new JLabel( "IF Gain" ); + add( mIFGainLabel ); + mIFGainFillerLabel = new JLabel( "" ); + add( mIFGainFillerLabel, "span 2" ); + mIFGainValueLabel = new JLabel( String.valueOf( mSelectedConfig.getIFGain() ) ); + add( mIFGainValueLabel, "wrap" ); mIFGain = new JSlider( JSlider.HORIZONTAL, AirspyTunerController.IF_GAIN_MIN, @@ -271,7 +352,7 @@ public class AirspyTunerConfigurationPanel extends JPanel mController.setIFGain( gain ); mSelectedConfig.setIFGain( gain ); save(); - mIFGainLabel.setText( String.valueOf( gain ) ); + mIFGainValueLabel.setText( String.valueOf( gain ) ); } catch ( Exception e ) { @@ -287,12 +368,14 @@ public class AirspyTunerConfigurationPanel extends JPanel add( mIFGain, "span,grow" ); - add( new JLabel( "Mixer Gain" ) ); + /** + * Mixer Gain + */ + mMixerGainLabel = new JLabel( "Mixer Gain" ); + add( mMixerGainLabel ); mMixerAGC = new JCheckBox( "AGC" ); - mMixerAGC.setSelected( mSelectedConfig.isMixerAGC() ); - mMixerAGC.addActionListener( new ActionListener() { @Override @@ -315,8 +398,8 @@ public class AirspyTunerConfigurationPanel extends JPanel add( mMixerAGC, "span 2,center" ); - mMixerGainLabel = new JLabel( String.valueOf( mSelectedConfig.getMixerGain() ) ); - add( mMixerGainLabel, "wrap" ); + mMixerGainValueLabel = new JLabel( String.valueOf( mSelectedConfig.getMixerGain() ) ); + add( mMixerGainValueLabel, "wrap" ); mMixerGain = new JSlider( JSlider.HORIZONTAL, AirspyTunerController.MIXER_GAIN_MIN, @@ -338,7 +421,7 @@ public class AirspyTunerConfigurationPanel extends JPanel mController.setMixerGain( gain ); mSelectedConfig.setMixerGain( gain ); save(); - mMixerGainLabel.setText( String.valueOf( gain ) ); + mMixerGainValueLabel.setText( String.valueOf( gain ) ); } catch ( Exception e ) { @@ -352,13 +435,15 @@ public class AirspyTunerConfigurationPanel extends JPanel } ); add( mMixerGain, "span,grow" ); - - add( new JLabel( "LNA Gain" ) ); + + /** + * LNA Gain + */ + mLNAGainLabel = new JLabel( "LNA Gain" ); + add( mLNAGainLabel ); mLNAAGC = new JCheckBox( "AGC" ); - mLNAAGC.setSelected( mSelectedConfig.isLNAAGC() ); - mLNAAGC.addActionListener( new ActionListener() { @Override @@ -381,8 +466,8 @@ public class AirspyTunerConfigurationPanel extends JPanel add( mLNAAGC, "span 2,center" ); - mLNAGainLabel = new JLabel( String.valueOf( mSelectedConfig.getLNAGain() ) ); - add( mLNAGainLabel, "wrap" ); + mLNAGainValueLabel = new JLabel( String.valueOf( mSelectedConfig.getLNAGain() ) ); + add( mLNAGainValueLabel, "wrap" ); mLNAGain = new JSlider( JSlider.HORIZONTAL, AirspyTunerController.LNA_GAIN_MIN, @@ -404,7 +489,7 @@ public class AirspyTunerConfigurationPanel extends JPanel mController.setLNAGain( gain ); mSelectedConfig.setLNAGain( gain ); save(); - mLNAGainLabel.setText( String.valueOf( gain ) ); + mLNAGainValueLabel.setText( String.valueOf( gain ) ); } catch ( Exception e ) { @@ -418,6 +503,9 @@ public class AirspyTunerConfigurationPanel extends JPanel } ); add( mLNAGain, "span,grow" ); + + //Set the enabled state of each of the gain controls + updateGainComponents( (GainMode)mGainModeCombo.getSelectedItem() ); /** * Create a new configuration @@ -485,6 +573,34 @@ public class AirspyTunerConfigurationPanel extends JPanel add( mDeleteConfiguration, "span 2,growx,push" ); } + + /** + * Updates the enabled state of each of the gain controls according to the + * specified gain mode. The overall gain controls are enabled for linearity + * and sensitivity and the individual gain controls are disabled, and + * vice-versa for custom mode. + */ + private void updateGainComponents( GainMode mode ) + { + boolean isCustom = ( mode == GainMode.CUSTOM ); + + mGainLabel.setEnabled( !isCustom ); + mGainFillerLabel.setEnabled( !isCustom ); + mGainValueLabel.setEnabled( !isCustom ); + mGain.setEnabled( !isCustom ); + mIFGainLabel.setEnabled( isCustom ); + mIFGainFillerLabel.setEnabled( isCustom ); + mIFGainValueLabel.setEnabled( isCustom ); + mIFGain.setEnabled( isCustom ); + mLNAGainLabel.setEnabled( isCustom ); + mLNAAGC.setEnabled( isCustom ); + mLNAGainValueLabel.setEnabled( isCustom ); + mLNAGain.setEnabled( isCustom ); + mMixerGainValueLabel.setEnabled( isCustom ); + mMixerAGC.setEnabled( isCustom ); + mMixerGainLabel.setEnabled( isCustom ); + mMixerGain.setEnabled( isCustom ); + } /** * Updates gui controls with the values from the tuner configuration @@ -507,9 +623,7 @@ public class AirspyTunerConfigurationPanel extends JPanel { mSampleRateCombo.setSelectedItem( rate ); } - - //TODO: set decimation and effective rate here - + mIFGain.setValue( mSelectedConfig.getIFGain() ); mMixerGain.setValue( mSelectedConfig.getMixerGain() ); mLNAGain.setValue( mSelectedConfig.getLNAGain() ); @@ -517,6 +631,10 @@ public class AirspyTunerConfigurationPanel extends JPanel mMixerAGC.setSelected( mSelectedConfig.isMixerAGC() ); mLNAAGC.setSelected( mSelectedConfig.isLNAAGC() ); + Gain gain = mSelectedConfig.getGain(); + mGainModeCombo.setSelectedItem( Gain.getGainMode( gain ) ); + mGain.setValue( gain.getValue() ); + mResourceManager.getSettingsManager().setSelectedTunerConfiguration( TunerType.AIRSPY_R820T, mController.getDeviceInfo().getSerialNumber(), config ); diff --git a/src/source/tuner/airspy/AirspyTunerController.java b/src/source/tuner/airspy/AirspyTunerController.java index 9c8b9a1f..755465d0 100644 --- a/src/source/tuner/airspy/AirspyTunerController.java +++ b/src/source/tuner/airspy/AirspyTunerController.java @@ -4,11 +4,10 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedTransferQueue; -import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -29,9 +28,6 @@ import sample.Broadcaster; import sample.Listener; import sample.complex.ComplexBuffer; import source.SourceException; -import source.tuner.Tuner; -import source.tuner.TunerChannel; -import source.tuner.TunerChannelSource; import source.tuner.TunerConfiguration; import source.tuner.TunerController; import controller.ThreadPoolManager; @@ -81,15 +77,19 @@ import dsp.filter.hilbert.HilbertTransform; public class AirspyTunerController extends TunerController { + public static final Gain LINEARITY_GAIN_DEFAULT = Gain.LINEARITY_14; + public static final Gain SENSITIVITY_GAIN_DEFAULT = Gain.SENSITIVITY_10; + public static final int GAIN_MIN = 1; + public static final int GAIN_MAX = 22; public static final int LNA_GAIN_MIN = 0; public static final int LNA_GAIN_MAX = 14; - public static final int LNA_GAIN_DEFAULT = 1; + public static final int LNA_GAIN_DEFAULT = 7; public static final int MIXER_GAIN_MIN = 0; public static final int MIXER_GAIN_MAX = 15; - public static final int MIXER_GAIN_DEFAULT = 5; + public static final int MIXER_GAIN_DEFAULT = 9; public static final int IF_GAIN_MIN = 0; public static final int IF_GAIN_MAX = 15; - public static final int IF_GAIN_DEFAULT = 5; + public static final int IF_GAIN_DEFAULT = 9; public static final long FREQUENCY_MIN = 24000000l; public static final long FREQUENCY_MAX = 1800000000l; public static final long FREQUENCY_DEFAULT = 101100000; @@ -296,6 +296,11 @@ public class AirspyTunerController extends TunerController setMixerAGC( airspy.isMixerAGC() ); setLNAAGC( airspy.isLNAAGC() ); + + //Set the gain mode last, so custom values are already set, and + //linearity and sensitivity modes will automatically override + //the custom values. + setGain( airspy.getGain() ); } catch( Exception e ) { @@ -482,6 +487,18 @@ public class AirspyTunerController extends TunerController throw new UsbException( "Couldnt set LNA AGC enabled: " + enabled ); } } + + public void setGain( Gain gain ) throws UsbException + { + if( gain != Gain.CUSTOM ) + { + setMixerAGC( false ); + setLNAAGC( false ); + setLNAGain( gain.getLNA() ); + setMixerGain( gain.getMixer() ); + setIFGain( gain.getIF() ); + } + } /** * Sets LNA gain @@ -829,6 +846,155 @@ public class AirspyTunerController extends TunerController LibUsb.ERROR_NO_DEVICE ); } } + + public enum GainMode + { + LINEARITY, + SENSITIVITY, + CUSTOM; + } + + public enum Gain + { + LINEARITY_1( 1, 4, 0, 0 ), + LINEARITY_2( 2, 5, 0, 0 ), + LINEARITY_3( 3, 6, 1, 0 ), + LINEARITY_4( 4, 7, 1, 0 ), + LINEARITY_5( 5, 8, 1, 0 ), + LINEARITY_6( 6, 9, 1, 0 ), + LINEARITY_7( 7, 10, 2, 0 ), + LINEARITY_8( 8, 10, 2, 1 ), + LINEARITY_9( 9, 10, 0, 3 ), + LINEARITY_10( 10, 10, 0, 5 ), + LINEARITY_11( 11, 10, 1, 6 ), + LINEARITY_12( 12, 10, 0, 8 ), + LINEARITY_13( 13, 10, 0, 9 ), + LINEARITY_14( 14, 10, 5, 8 ), + LINEARITY_15( 15, 10, 6, 9 ), + LINEARITY_16( 16, 11, 6, 9 ), + LINEARITY_17( 17, 11, 7, 10 ), + LINEARITY_18( 18, 11, 8, 12 ), + LINEARITY_19( 19, 11, 9, 13 ), + LINEARITY_20( 20, 11, 11, 14 ), + LINEARITY_21( 21, 12, 12, 14 ), + LINEARITY_22( 22, 13, 12, 14 ), + SENSITIVITY_1( 1, 4, 0, 0 ), + SENSITIVITY_2( 2, 4, 0, 1 ), + SENSITIVITY_3( 3, 4, 0, 2 ), + SENSITIVITY_4( 4, 4, 0, 3 ), + SENSITIVITY_5( 5, 4, 1, 5 ), + SENSITIVITY_6( 6, 4, 2, 6 ), + SENSITIVITY_7( 7, 4, 2, 7 ), + SENSITIVITY_8( 8, 4, 3, 8 ), + SENSITIVITY_9( 9, 4, 4, 9 ), + SENSITIVITY_10( 10, 5, 4, 9 ), + SENSITIVITY_11( 11, 5, 4, 12 ), + SENSITIVITY_12( 12, 5, 7, 12 ), + SENSITIVITY_13( 13, 5, 8, 13 ), + SENSITIVITY_14( 14, 5, 9, 14 ), + SENSITIVITY_15( 15, 6, 9, 14 ), + SENSITIVITY_16( 16, 7, 10, 14 ), + SENSITIVITY_17( 17, 8, 10, 14 ), + SENSITIVITY_18( 18, 9, 11, 14 ), + SENSITIVITY_19( 19, 10, 12, 14 ), + SENSITIVITY_20( 20, 11, 12, 14 ), + SENSITIVITY_21( 21, 12, 12, 14 ), + SENSITIVITY_22( 22, 13, 12, 14 ), + CUSTOM( 1, 0, 0, 0 ); + + private int mValue; + private int mIF; + private int mMixer; + private int mLNA; + + private Gain( int value, int ifGain, int mixer, int lna ) + { + mValue = value; + mIF = ifGain; + mMixer = mixer; + mLNA = lna; + } + + public int getValue() + { + return mValue; + } + + public int getIF() + { + return mIF; + } + + public int getMixer() + { + return mMixer; + } + + public int getLNA() + { + return mLNA; + } + + public static Gain getGain( GainMode mode, int value ) + { + assert( GAIN_MIN <= value && value <= GAIN_MAX ); + + switch( mode ) + { + case LINEARITY: + for( Gain gain: getLinearityGains() ) + { + if( gain.getValue() == value ) + { + return gain; + } + } + return LINEARITY_GAIN_DEFAULT; + case SENSITIVITY: + for( Gain gain: getSensitivityGains() ) + { + if( gain.getValue() == value ) + { + return gain; + } + } + return SENSITIVITY_GAIN_DEFAULT; + case CUSTOM: + default: + return Gain.CUSTOM; + } + } + + public static GainMode getGainMode( Gain gain ) + { + if( gain == CUSTOM ) + { + return GainMode.CUSTOM; + } + else if( getLinearityGains().contains( gain ) ) + { + return GainMode.LINEARITY; + } + else if( getSensitivityGains().contains( gain ) ) + { + return GainMode.SENSITIVITY; + } + + return GainMode.CUSTOM; + } + + public static EnumSet getLinearityGains() + { + return EnumSet.range( LINEARITY_1, LINEARITY_22 ); + } + + public static EnumSet getSensitivityGains() + { + return EnumSet.range( SENSITIVITY_1, SENSITIVITY_22 ); + } + } + + /** * Airspy Board Identifier