/******************************************************************************* * SDR Trunk * Copyright (C) 2014 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ package source.tuner.airspy; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.util.ArrayList; import java.util.List; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.usb.UsbException; import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.usb4java.LibUsbException; import source.SourceException; import source.tuner.TunerConfiguration; import source.tuner.TunerConfigurationAssignment; import source.tuner.TunerType; import controller.ResourceManager; public class AirspyTunerConfigurationPanel extends JPanel { private final static Logger mLog = LoggerFactory.getLogger( AirspyTunerConfigurationPanel.class ); private static final long serialVersionUID = 1L; private ResourceManager mResourceManager; private AirspyTunerController mController; private AirspyTunerConfiguration mSelectedConfig; private JButton mNewConfiguration; private JButton mDeleteConfiguration; private JComboBox mComboConfigurations; private JTextField mName; private JComboBox mSampleRateCombo; private JComboBox mDecimationCombo; private JLabel mEffectiveRate; private JLabel mIFGainLabel; private JSlider mIFGain; private JLabel mLNAGainLabel; private JSlider mLNAGain; private JLabel mMixerGainLabel; private JSlider mMixerGain; private JCheckBox mMixerAGC; private JCheckBox mLNAAGC; public AirspyTunerConfigurationPanel( ResourceManager resourceManager, AirspyTunerController controller ) { mResourceManager = resourceManager; mController = controller; init(); } /** * Initializes the gui components */ private void init() { setLayout( new MigLayout( "fill,wrap 4", "[left][grow][grow][right]", "[][][][][][][grow]" ) ); /** * Tuner configuration selector */ mComboConfigurations = new JComboBox(); mComboConfigurations.setModel( getModel() ); /* Determine which tuner configuration should be selected/displayed */ TunerConfigurationAssignment savedConfig = null; String serial = null; serial = mController.getDeviceInfo().getSerialNumber(); if( serial != null ) { savedConfig = mResourceManager .getSettingsManager().getSelectedTunerConfiguration( TunerType.AIRSPY_R820T, serial ); } if( savedConfig != null ) { mSelectedConfig = getNamedConfiguration( savedConfig.getTunerConfigurationName() ); } /* If we couldn't determine the saved/selected config, use the first one */ if( mSelectedConfig == null ) { mSelectedConfig = mComboConfigurations.getItemAt( 0 ); //Store this config as the default for this tuner at this address if( serial != null ) { mResourceManager.getSettingsManager() .setSelectedTunerConfiguration( TunerType.AIRSPY_R820T, serial, mSelectedConfig ); } } mComboConfigurations.setSelectedItem( mSelectedConfig ); mComboConfigurations.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { AirspyTunerConfiguration selected = (AirspyTunerConfiguration)mComboConfigurations .getItemAt( mComboConfigurations.getSelectedIndex() ); if( selected != null ) { update( selected ); } } }); add( new JLabel( "Config:" ) ); add( mComboConfigurations, "span,growx,push" ); add( new JSeparator(), "span,growx,push" ); /** * Tuner Configuration Name */ mName = new JTextField(); mName.setText( mSelectedConfig.getName() ); mName.addFocusListener( new FocusListener() { @Override public void focusLost( FocusEvent e ) { mSelectedConfig.setName( mName.getText() ); save(); } @Override public void focusGained( FocusEvent e ) {} } ); add( new JLabel( "Name:" ) ); add( mName, "span,growx,push" ); /** * Sample Rate */ add( new JLabel( "Sample Rate:" ) ); List rates = mController.getSampleRates(); mSampleRateCombo = new JComboBox( new DefaultComboBoxModel( rates.toArray( new AirspySampleRate[ rates.size() ] ) ) ); mSampleRateCombo.setSelectedItem( mController.getSampleRate() ); mSampleRateCombo.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { AirspySampleRate rate = (AirspySampleRate)mSampleRateCombo.getSelectedItem(); try { mController.setSampleRate( rate ); mSelectedConfig.setSampleRate( rate.getRate() ); save(); mEffectiveRate.setText( rate.getLabel() ); } catch ( LibUsbException | UsbException e1 ) { JOptionPane.showMessageDialog( AirspyTunerConfigurationPanel.this, "Couldn't set sample rate to " + rate.getLabel() ); mLog.error( "Error setting airspy sample rate", e1 ); } } } ); 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" ); /** * IF/VGA Gain */ add( new JLabel( "IF Gain" ) ); add( new JLabel( "" ), "span 2" ); mIFGainLabel = new JLabel( String.valueOf( mSelectedConfig.getIFGain() ) ); add( mIFGainLabel, "wrap" ); mIFGain = new JSlider( JSlider.HORIZONTAL, AirspyTunerController.IF_GAIN_MIN, AirspyTunerController.IF_GAIN_MAX, mSelectedConfig.getIFGain() ); mIFGain.setMajorTickSpacing( 1 ); mIFGain.setPaintTicks( true ); mIFGain.addChangeListener( new ChangeListener() { @Override public void stateChanged( ChangeEvent event ) { int gain = mIFGain.getValue(); try { mController.setIFGain( gain ); mSelectedConfig.setIFGain( gain ); save(); mIFGainLabel.setText( String.valueOf( gain ) ); } catch ( Exception e ) { mLog.error( "Couldn't set airspy IF gain to:" + gain, e ); JOptionPane.showMessageDialog( mIFGain, "Couldn't set IF gain value to " + gain ); mIFGain.setValue( mSelectedConfig.getIFGain() ); } } } ); add( mIFGain, "span,grow" ); add( new JLabel( "Mixer Gain" ) ); mMixerAGC = new JCheckBox( "AGC" ); mMixerAGC.setSelected( mSelectedConfig.isMixerAGC() ); mMixerAGC.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { try { mController.setMixerAGC( !mSelectedConfig.isMixerAGC() ); mSelectedConfig.setMixerAGC( !mSelectedConfig.isMixerAGC() ); save(); } catch ( Exception e1 ) { mLog.error( "Error setting Mixer AGC Enabled:" + !mSelectedConfig.isMixerAGC() ); mMixerAGC.setSelected( mSelectedConfig.isMixerAGC() ); } } } ); add( mMixerAGC, "span 2,center" ); mMixerGainLabel = new JLabel( String.valueOf( mSelectedConfig.getMixerGain() ) ); add( mMixerGainLabel, "wrap" ); mMixerGain = new JSlider( JSlider.HORIZONTAL, AirspyTunerController.MIXER_GAIN_MIN, AirspyTunerController.MIXER_GAIN_MAX, mSelectedConfig.getMixerGain() ); mMixerGain.setMajorTickSpacing( 1 ); mMixerGain.setPaintTicks( true ); mMixerGain.addChangeListener( new ChangeListener() { @Override public void stateChanged( ChangeEvent event ) { int gain = mMixerGain.getValue(); try { mController.setMixerGain( gain ); mSelectedConfig.setMixerGain( gain ); save(); mMixerGainLabel.setText( String.valueOf( gain ) ); } catch ( Exception e ) { mLog.error( "Couldn't set airspy Mixer gain to:" + gain, e ); JOptionPane.showMessageDialog( mIFGain, "Couldn't set Mixer gain value to " + gain ); mMixerGain.setValue( mSelectedConfig.getMixerGain() ); } } } ); add( mMixerGain, "span,grow" ); add( new JLabel( "LNA Gain" ) ); mLNAAGC = new JCheckBox( "AGC" ); mLNAAGC.setSelected( mSelectedConfig.isLNAAGC() ); mLNAAGC.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { try { mController.setLNAAGC( !mSelectedConfig.isLNAAGC() ); mSelectedConfig.setLNAAGC( !mSelectedConfig.isLNAAGC() ); save(); } catch ( Exception e1 ) { mLog.error( "Error setting LNA AGC Enabled:" + !mSelectedConfig.isLNAAGC() ); mLNAAGC.setSelected( mSelectedConfig.isLNAAGC() ); } } } ); add( mLNAAGC, "span 2,center" ); mLNAGainLabel = new JLabel( String.valueOf( mSelectedConfig.getLNAGain() ) ); add( mLNAGainLabel, "wrap" ); mLNAGain = new JSlider( JSlider.HORIZONTAL, AirspyTunerController.LNA_GAIN_MIN, AirspyTunerController.LNA_GAIN_MAX, mSelectedConfig.getLNAGain() ); mLNAGain.setMajorTickSpacing( 1 ); mLNAGain.setPaintTicks( true ); mLNAGain.addChangeListener( new ChangeListener() { @Override public void stateChanged( ChangeEvent event ) { int gain = mLNAGain.getValue(); try { mController.setLNAGain( gain ); mSelectedConfig.setLNAGain( gain ); save(); mLNAGainLabel.setText( String.valueOf( gain ) ); } catch ( Exception e ) { mLog.error( "Couldn't set airspy LNA gain to:" + gain, e ); JOptionPane.showMessageDialog( mIFGain, "Couldn't set LNA gain value to " + gain ); mLNAGain.setValue( mSelectedConfig.getLNAGain() ); } } } ); add( mLNAGain, "span,grow" ); /** * Create a new configuration */ mNewConfiguration = new JButton( "New" ); mNewConfiguration.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { TunerConfiguration config = mResourceManager.getSettingsManager() .addNewTunerConfiguration( TunerType.AIRSPY_R820T, "New Configuration" ); mComboConfigurations.setModel( getModel() ); mComboConfigurations.setSelectedItem( config ); repaint(); } } ); add( mNewConfiguration, "span 2,growx,push" ); /** * Delete the currently selected configuration */ mDeleteConfiguration = new JButton( "Delete" ); mDeleteConfiguration.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { AirspyTunerConfiguration selected = (AirspyTunerConfiguration)mComboConfigurations .getItemAt( mComboConfigurations.getSelectedIndex() ); if( selected != null ) { int n = JOptionPane.showConfirmDialog( AirspyTunerConfigurationPanel.this, "Are you sure you want to delete '" + selected.getName() + "'?", "Are you sure?", JOptionPane.YES_NO_OPTION ); if( n == JOptionPane.YES_OPTION ) { mResourceManager.getSettingsManager() .deleteTunerConfiguration( selected ); mComboConfigurations.setModel( getModel() ); mComboConfigurations.setSelectedIndex( 0 ); repaint(); } } } } ); add( mDeleteConfiguration, "span 2,growx,push" ); } /** * Updates gui controls with the values from the tuner configuration * @param config - tuner configuration */ private void update( AirspyTunerConfiguration config ) { mSelectedConfig = config; try { mController.apply( config ); mName.setText( config.getName() ); AirspySampleRate rate = mController.getSampleRate( mSelectedConfig.getSampleRate() ); if( rate != null ) { mSampleRateCombo.setSelectedItem( rate ); } //TODO: set decimation and effective rate here mIFGain.setValue( mSelectedConfig.getIFGain() ); mMixerGain.setValue( mSelectedConfig.getMixerGain() ); mLNAGain.setValue( mSelectedConfig.getLNAGain() ); mMixerAGC.setSelected( mSelectedConfig.isMixerAGC() ); mLNAAGC.setSelected( mSelectedConfig.isLNAAGC() ); mResourceManager.getSettingsManager().setSelectedTunerConfiguration( TunerType.AIRSPY_R820T, mController.getDeviceInfo().getSerialNumber(), config ); save(); } catch ( /*UsbException |*/ SourceException e1 ) { JOptionPane.showMessageDialog( AirspyTunerConfigurationPanel.this, "Airspy Tuner Controller - couldn't " + "apply the tuner configuration settings - " + e1.getLocalizedMessage() ); mLog.error( "Airspy Tuner Controller - couldn't apply " + "config [" + config.getName() + "]", e1 ); } } /** * Constructs a combo box model for the tuner configuration combo component * by assembling a list of the tuner configurations appropriate for this * specific tuner */ private ComboBoxModel getModel() { ArrayList configs = mResourceManager.getSettingsManager() .getTunerConfigurations( TunerType.AIRSPY_R820T ); DefaultComboBoxModel model = new DefaultComboBoxModel(); for( TunerConfiguration config: configs ) { model.addElement( (AirspyTunerConfiguration)config ); } return model; } /** * Retrieves a specific (named) tuner configuration */ private AirspyTunerConfiguration getNamedConfiguration( String name ) { ArrayList configs = mResourceManager.getSettingsManager() .getTunerConfigurations( TunerType.AIRSPY_R820T ); for( TunerConfiguration config: configs ) { if( config.getName().contentEquals( name ) ) { return (AirspyTunerConfiguration)config; } } return null; } /** * Saves current tuner configuration settings */ private void save() { mResourceManager.getSettingsManager().save(); } }