Merges #34 Major redesign of Tuner, Channel and Alias management.

Changes to model, view and controller components and updates all gui
editors.  Removes the configuration panel and tree and replaces with 3
new panels.  Updates playlist.xml to a new playlist_v2.xml format.
This commit is contained in:
denny
2016-04-01 08:23:49 -04:00
450 changed files with 19560 additions and 22805 deletions

View File

@@ -6,8 +6,8 @@ import sample.complex.ComplexBuffer;
public abstract class ComplexSource extends Source implements Provider<ComplexBuffer>
{
public ComplexSource( String name )
public ComplexSource()
{
super( name, SampleType.COMPLEX );
super( SampleType.COMPLEX );
}
}

View File

@@ -1,46 +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;
import javax.swing.JLabel;
import source.config.SourceConfiguration;
import controller.ResourceManager;
public class EmptySourceEditor extends SourceEditor
{
private static final long serialVersionUID = 1L;
public EmptySourceEditor( ResourceManager resourceManager,
SourceConfiguration config )
{
super( resourceManager, config );
initGUI();
}
public void reset() {}
public void save() {}
private void initGUI()
{
JLabel selectLabel = new JLabel( "Please select a source" );
add( selectLabel );
}
}

View File

@@ -1,12 +0,0 @@
package source;
import sample.Provider;
import sample.SampleType;
public abstract class FloatSource extends Source implements Provider<Float>
{
public FloatSource( String name )
{
super( name, SampleType.REAL );
}
}

View File

@@ -7,8 +7,8 @@ import sample.real.RealBuffer;
public abstract class RealSource extends Source implements Provider<RealBuffer>
{
public RealSource( String name )
public RealSource()
{
super( name, SampleType.REAL );
super( SampleType.REAL );
}
}

View File

@@ -1,28 +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;
import sample.SampleType;
public interface SampleProvider
{
/**
* Real or Complex
*/
public abstract SampleType getSampleType();
}

View File

@@ -17,27 +17,21 @@
******************************************************************************/
package source;
import module.Module;
import sample.SampleType;
/**
* Abstract class to define the minimum functionality of a sample data provider.
*/
public abstract class Source
public abstract class Source extends Module
{
protected String mName;
protected SampleType mSampleType;
public Source( String name, SampleType sampleType )
public Source( SampleType sampleType )
{
mName = name;
mSampleType = sampleType;
}
public String getName()
{
return mName;
}
public abstract int getSampleRate() throws SourceException;
public abstract long getFrequency() throws SourceException;

View File

@@ -1,129 +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;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import net.miginfocom.swing.MigLayout;
import source.config.SourceConfigFactory;
import source.config.SourceConfiguration;
import controller.channel.AbstractChannelEditor;
import controller.channel.ChannelNode;
public class SourceComponentEditor extends AbstractChannelEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<SourceType> mComboSources;
private SourceEditor mEditor;
public SourceComponentEditor( ChannelNode channelNode )
{
super( channelNode );
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][grow]" ) );
mComboSources = new JComboBox<SourceType>();
mComboSources.setModel( new DefaultComboBoxModel<SourceType>( SourceType.values() ) );
mComboSources.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
SourceType selected = mComboSources.getItemAt( mComboSources.getSelectedIndex() );
if( selected != null )
{
SourceConfiguration config;
if( selected == mChannelNode.getChannel()
.getSourceConfiguration().getSourceType() )
{
config = mChannelNode.getChannel()
.getSourceConfiguration();
}
else
{
config = SourceConfigFactory
.getSourceConfiguration( selected );
}
//Remove the existing one
if( mEditor != null )
{
remove( mEditor );
}
//Change to the new one
mEditor = SourceEditorFactory.getPanel(
mChannelNode.getModel().getResourceManager(), config );
//Add it to the jpanel
add( mEditor, "span 2" );
revalidate();
repaint();
}
}
});
add( new JLabel( "Source:" ) );
add( mComboSources, "wrap" );
reset();
}
public SourceEditor getSourceEditor()
{
return mEditor;
}
public void reset()
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run() {
mComboSources.setSelectedItem(
mChannelNode.getChannel()
.getSourceConfiguration().getSourceType() );
mComboSources.requestFocus();
mComboSources.requestFocusInWindow();
}
});
}
@Override
public void save()
{
mEditor.save();
//Let the calling save method send the config change event
mChannelNode.getChannel()
.setSourceConfiguration( mEditor.getConfig(), false );
}
}

View File

@@ -0,0 +1,137 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source;
import gui.editor.Editor;
import gui.editor.EmptyEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import net.miginfocom.swing.MigLayout;
import source.config.SourceConfiguration;
import source.mixer.MixerSourceEditor;
import source.tuner.TunerSourceEditor;
import controller.channel.Channel;
public class SourceConfigurationEditor extends Editor<Channel>
{
private static final long serialVersionUID = 1L;
private JComboBox<SourceType> mComboSources;
private MixerSourceEditor mMixerSourceEditor;
private TunerSourceEditor mTunerSourceEditor;
private Editor<Channel> mCurrentEditor;
public SourceConfigurationEditor( SourceManager sourceManager )
{
mMixerSourceEditor = new MixerSourceEditor( sourceManager );
mMixerSourceEditor.setSaveRequestListener( this );
mTunerSourceEditor = new TunerSourceEditor();
mTunerSourceEditor.setSaveRequestListener( this );
init();
}
public SourceConfiguration getSourceConfiguration()
{
return hasItem() ? getItem().getSourceConfiguration() : null;
}
private void init()
{
setLayout( new MigLayout( "wrap 2", "[][grow,fill]", "[align top][grow]" ) );
mComboSources = new JComboBox<SourceType>();
mComboSources.setModel( new DefaultComboBoxModel<SourceType>( SourceType.getTypes() ) );
mComboSources.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
SourceType selected = (SourceType)mComboSources.getSelectedItem();
switch( selected )
{
case MIXER:
setEditor( mMixerSourceEditor );
break;
case TUNER:
setEditor( mTunerSourceEditor );
break;
default:
setEditor( new EmptyEditor<Channel>() );
break;
}
}
});
add( mComboSources );
mCurrentEditor = mTunerSourceEditor;
add( mCurrentEditor );
}
private void setEditor( Editor<Channel> editor )
{
if( mCurrentEditor != editor )
{
//Set channel to null to force a save prompt as required
mCurrentEditor.setItem( null );
remove( mCurrentEditor );
mCurrentEditor = editor;
mCurrentEditor.setSaveRequestListener( this );
add( mCurrentEditor );
mCurrentEditor.setItem( getItem() );
revalidate();
}
}
@Override
public void save()
{
if( hasItem() )
{
mCurrentEditor.save();
}
}
/**
* Sets the channel configuration. Note: this method must be invoked from
* the swing event dispatch thread.
*/
@Override
public void setItem( Channel channel )
{
super.setItem( channel );
if( hasItem() )
{
mComboSources.setSelectedItem( getItem().getSourceConfiguration().getSourceType() );
repaint();
mCurrentEditor.setItem( channel );
}
}
}

View File

@@ -1,46 +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;
import source.config.SourceConfiguration;
import controller.Editor;
import controller.ResourceManager;
public abstract class SourceEditor extends Editor
{
private static final long serialVersionUID = 1L;
protected ResourceManager mResourceManager;
protected SourceConfiguration mConfig;
public SourceEditor( ResourceManager resourceManager, SourceConfiguration config )
{
mResourceManager = resourceManager;
mConfig = config;
}
public SourceConfiguration getConfig()
{
return mConfig;
}
public ResourceManager getResourceManager()
{
return mResourceManager;
}
}

View File

@@ -1,52 +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;
import source.config.SourceConfiguration;
import source.mixer.MixerEditor;
import source.recording.RecordingEditor;
import source.tuner.TunerEditor;
import controller.ResourceManager;
public class SourceEditorFactory
{
public static SourceEditor getPanel( ResourceManager resourceManager,
SourceConfiguration config )
{
SourceEditor configuredPanel;
switch( config.getSourceType() )
{
case MIXER:
configuredPanel = new MixerEditor( resourceManager, config );
break;
case TUNER:
configuredPanel = new TunerEditor( resourceManager, config );
break;
case RECORDING:
configuredPanel = new RecordingEditor( resourceManager, config );
break;
case NONE:
default:
configuredPanel = new EmptySourceEditor( resourceManager, config );
break;
}
return configuredPanel;
}
}

View File

@@ -17,27 +17,48 @@
******************************************************************************/
package source;
import settings.SettingsManager;
import source.config.SourceConfigTuner;
import source.config.SourceConfiguration;
import source.mixer.MixerManager;
import controller.ResourceManager;
import source.recording.RecordingSourceManager;
import source.tuner.TunerManager;
import source.tuner.TunerModel;
import controller.ThreadPoolManager;
public class SourceManager {
/**
* NOTE: each source will auto-start once a listener registers on it to
* receive samples and should auto-stop once a listener de-registers
*
* Each channel object will handle the starting and stopping of each channel
* processing chain.
*
* Source Manager will reach out to the MixerManager or the TunerManager
* to get source objects to pass off to the channel object, as requested.
*/
private ResourceManager mResourceManager;
public class SourceManager
{
private MixerManager mMixerManager;
private RecordingSourceManager mRecordingSourceManager;
private TunerManager mTunerManager;
private TunerModel mTunerModel;
public SourceManager( ResourceManager resourceManager )
public SourceManager( TunerModel tunerModel,
SettingsManager settingsManager,
ThreadPoolManager threadPoolManager )
{
mResourceManager = resourceManager;
mTunerModel = tunerModel;
mMixerManager = new MixerManager();
mRecordingSourceManager = new RecordingSourceManager( settingsManager );
mTunerManager = new TunerManager( mMixerManager, tunerModel, threadPoolManager );
//TODO: change mixer & recording managers to be models and hand them
//in via the constructor. Perform loading outside of this class.
}
public MixerManager getMixerManager()
{
return mMixerManager;
}
public RecordingSourceManager getRecordingSourceManager()
{
return mRecordingSourceManager;
}
public TunerManager getTunerManager()
{
return mTunerManager;
}
public Source getSource( SourceConfiguration config, int bandwidth )
@@ -48,14 +69,13 @@ public class SourceManager {
switch( config.getSourceType() )
{
case MIXER:
retVal = MixerManager.getInstance().getSource( config );
retVal = mMixerManager.getSource( config );
break;
case TUNER:
retVal = mResourceManager.getTunerManager().getSource( config, bandwidth );
retVal = mTunerModel.getSource( (SourceConfigTuner)config, bandwidth );
break;
case RECORDING:
retVal = mResourceManager.getRecordingSourceManager()
.getSource( config, bandwidth );
retVal = mRecordingSourceManager.getSource( config, bandwidth );
case NONE:
default:
break;

View File

@@ -17,10 +17,11 @@
******************************************************************************/
package source;
public enum SourceType
{
NONE( "No Source" ),
MIXER( "Mixer/Sound Card" ),
MIXER( "Sound Card" ),
TUNER( "Tuner" ),
RECORDING( "IQ Recording" );
@@ -31,6 +32,15 @@ public enum SourceType
mDisplayString = displayString;
}
public static SourceType[] getTypes()
{
SourceType[] types = new SourceType[ 2 ];
types[ 0 ] = SourceType.TUNER;
types[ 1 ] = SourceType.MIXER;
return types;
}
public String getDisplayString()
{
return mDisplayString;

View File

@@ -23,24 +23,20 @@ public class SourceConfigFactory
{
public static SourceConfiguration getDefaultSourceConfiguration()
{
return getSourceConfiguration( SourceType.NONE );
return getSourceConfiguration( SourceType.TUNER );
}
public static SourceConfiguration
getSourceConfiguration( SourceType source )
public static SourceConfiguration getSourceConfiguration( SourceType source )
{
SourceConfiguration retVal;
switch( source )
{
case MIXER:
retVal = new SourceConfigMixer();
break;
case TUNER:
retVal = new SourceConfigTuner();
break;
case RECORDING:
retVal = new SourceConfigRecording();
case MIXER:
retVal = new SourceConfigMixer();
break;
case NONE:
default:
@@ -50,4 +46,39 @@ public class SourceConfigFactory
return retVal;
}
/**
* Creates a copy of the configuration
*/
public static SourceConfiguration copy( SourceConfiguration config )
{
if( config != null )
{
switch( config.getSourceType() )
{
case MIXER:
SourceConfigMixer originalMixer = (SourceConfigMixer)config;
SourceConfigMixer copyMixer = new SourceConfigMixer();
copyMixer.setChannel( originalMixer.getChannel() );
copyMixer.setMixer( originalMixer.getMixer() );
return copyMixer;
case RECORDING:
SourceConfigRecording originalRec = (SourceConfigRecording)config;
SourceConfigRecording copyRec = new SourceConfigRecording();
copyRec.setFrequency( originalRec.getFrequency() );
copyRec.setRecordingAlias( originalRec.getRecordingAlias() );
return copyRec;
case TUNER:
SourceConfigTuner originalTuner = (SourceConfigTuner)config;
SourceConfigTuner copyTuner = new SourceConfigTuner();
copyTuner.setFrequency( originalTuner.getFrequency() );
return copyTuner;
case NONE:
default:
return new SourceConfigNone();
}
}
return null;
}
}

View File

@@ -42,6 +42,7 @@ public class SourceConfigMixer extends SourceConfiguration
{
StringBuilder sb = new StringBuilder();
sb.append( "Mixer: " );
sb.append( mMixer );
sb.append( "-" );
sb.append( mChannel.toString() );

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ public class SourceConfigTuner extends SourceConfiguration
private static DecimalFormat sFORMAT = new DecimalFormat( "0.00000" );
private long mFrequency = 0;
private int mBandwidth = 15000;
private int mBandwidth = 12500;
public SourceConfigTuner()
{

View File

@@ -1,158 +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.mixer;
import java.util.EnumSet;
import javax.sound.sampled.Mixer;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import source.SourceEditor;
import source.config.SourceConfigMixer;
import source.config.SourceConfiguration;
import source.mixer.MixerManager.InputMixerConfiguration;
import controller.ResourceManager;
public class MixerEditor extends SourceEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<InputMixerConfiguration> mComboMixers;
private JComboBox<MixerChannel>mComboChannels;
protected Mixer.Info mSelectedMixer = null;
public MixerEditor( ResourceManager resourceManager,
SourceConfiguration config )
{
super( resourceManager, config );
initGUI();
}
private void initGUI()
{
JLabel mixerLabel = new JLabel( "Mixer:" );
add( mixerLabel, "align right" );
mComboMixers = new JComboBox<InputMixerConfiguration>();
add( mComboMixers, "wrap" );
resetMixers();
JLabel channelLabel = new JLabel( "Channel:" );
add( channelLabel, "align right" );
mComboChannels = new JComboBox<MixerChannel>();
add( mComboChannels, "wrap" );
resetChannels();
}
public void reset()
{
resetMixers();
resetChannels();
}
public void save()
{
SourceConfigMixer config = (SourceConfigMixer)mConfig;
InputMixerConfiguration selectedMixer =
mComboMixers.getItemAt( mComboMixers.getSelectedIndex() );
if( selectedMixer != null )
{
config.setMixer( selectedMixer.getMixerName() );
}
MixerChannel channel = mComboChannels.getItemAt(
mComboChannels.getSelectedIndex() );
if( channel != null )
{
if( config.getChannel() != channel )
{
config.setChannel( channel );
}
}
}
private void resetMixers()
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
InputMixerConfiguration[] mixers = MixerManager.getInstance().getInputMixers();
mComboMixers.setModel(
new DefaultComboBoxModel<InputMixerConfiguration>( mixers ) );
SourceConfigMixer config = (SourceConfigMixer)mConfig;
String mixer = config.getMixer();
if( mixer != null )
{
mComboMixers.setSelectedItem( mixer );
}
else
{
//Mixer either hasn't been set yet, or it was set to a
//mixer that is no longer available. Set the mixer to the
//first item, and then store the value
if( mixers.length > 0 )
{
mComboMixers.setSelectedIndex( 0 );
InputMixerConfiguration selectedMixer =
(InputMixerConfiguration)mComboMixers.getSelectedItem();
config.setMixer( selectedMixer.getMixerName() );
}
}
}
});
}
private void resetChannels()
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
EnumSet<MixerChannel> channels = MixerChannel.getTargetChannels();
mComboChannels.setModel( new DefaultComboBoxModel<MixerChannel>(
channels.toArray( new MixerChannel[ channels.size() ] ) ) );
MixerChannel channel = ((SourceConfigMixer)mConfig).getChannel();
mComboChannels.setSelectedItem( channel );
}
});
}
}

View File

@@ -19,6 +19,7 @@ package source.mixer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
@@ -49,27 +50,15 @@ public class MixerManager
private final static Logger mLog =
LoggerFactory.getLogger( MixerManager.class );
private static MixerManager sInstance = null;
private List<InputMixerConfiguration> mInputMixers = new ArrayList<>();
private List<MixerChannelConfiguration> mOutputMixers = new ArrayList<>();
private HashMap<String,MixerTunerDataLine> mMixerTuners = new HashMap<>();
private MixerManager()
public MixerManager()
{
loadMixers();
}
public static MixerManager getInstance()
{
if( sInstance == null )
{
sInstance = new MixerManager();
}
return sInstance;
}
public RealMixerSource getSource( SourceConfiguration config )
{
RealMixerSource retVal = null;
@@ -108,7 +97,6 @@ public class MixerManager
{
return new RealMixerSource( dataLine,
AudioFormats.PCM_SIGNED_48KHZ_16BITS_MONO,
mixerName,
new ShortAdapter() );
}
}
@@ -137,7 +125,7 @@ public class MixerManager
{
return new RealMixerSource( dataLine,
AudioFormats.PCM_SIGNED_48KHZ_16BITS_STEREO,
mixerName, new ChannelShortAdapter(
new ChannelShortAdapter(
mixerConfig.getChannel() ) );
}
}
@@ -181,7 +169,14 @@ public class MixerManager
public Collection<MixerTunerDataLine> getMixerTunerDataLines()
{
return mMixerTuners.values();
if( mMixerTuners.isEmpty() )
{
return Collections.emptyList();
}
else
{
return mMixerTuners.values();
}
}
private void loadMixers()

View File

@@ -0,0 +1,177 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.mixer;
import gui.editor.Editor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EnumSet;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import net.miginfocom.swing.MigLayout;
import source.SourceManager;
import source.config.SourceConfigMixer;
import source.config.SourceConfiguration;
import source.mixer.MixerManager.InputMixerConfiguration;
import controller.channel.Channel;
public class MixerSourceEditor extends Editor<Channel>
{
private static final long serialVersionUID = 1L;
private JComboBox<InputMixerConfiguration> mComboMixers;
private JComboBox<MixerChannel>mComboChannels;
private SourceManager mSourceManager;
public MixerSourceEditor( SourceManager sourceManager )
{
mSourceManager = sourceManager;
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", "" ) );
mComboMixers = new JComboBox<InputMixerConfiguration>();
InputMixerConfiguration[] inputMixers = mSourceManager.getMixerManager().getInputMixers();
mComboMixers.setModel( new DefaultComboBoxModel<InputMixerConfiguration>( inputMixers ) );
mComboMixers.setEnabled( false );
mComboMixers.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
InputMixerConfiguration selected = (InputMixerConfiguration)mComboMixers.getSelectedItem();
EnumSet<MixerChannel> channels = selected.getChannels();
mComboChannels.setModel( new DefaultComboBoxModel<MixerChannel>(
channels.toArray( new MixerChannel[ channels.size() ] ) ) );
repaint();
setModified( true );
}
} );
add( new JLabel( "Mixer:" ) );
add( mComboMixers );
mComboChannels = new JComboBox<MixerChannel>();
InputMixerConfiguration selected = (InputMixerConfiguration)mComboMixers.getSelectedItem();
if( selected != null )
{
EnumSet<MixerChannel> channels = selected.getChannels();
mComboChannels.setModel( new DefaultComboBoxModel<MixerChannel>(
channels.toArray( new MixerChannel[ channels.size() ] ) ) );
}
mComboChannels.setEnabled( false );
mComboChannels.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Channel:" ) );
add( mComboChannels );
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
mComboMixers.setEnabled( true );
mComboChannels.setEnabled( true );
SourceConfiguration config = item.getSourceConfiguration();
if( config instanceof SourceConfigMixer )
{
SourceConfigMixer mixer = (SourceConfigMixer)config;
for( InputMixerConfiguration inputMixer: mSourceManager.getMixerManager().getInputMixers() )
{
if( inputMixer.getMixerName().equalsIgnoreCase( mixer.getMixer() ) )
{
mComboMixers.setSelectedItem( inputMixer );
for( MixerChannel channel: inputMixer.getChannels() )
{
if( channel.getLabel() != null && mixer.getChannel() != null )
{
if( channel.getLabel().equalsIgnoreCase( mixer.getChannel().getLabel() ) )
{
mComboChannels.setSelectedItem( channel );
}
}
}
continue;
}
}
setModified( false );
}
else
{
setModified( true );
}
}
else
{
mComboMixers.setEnabled( false );
mComboChannels.setEnabled( false );
setModified( false );
}
}
public void save()
{
if( hasItem() && isModified() )
{
SourceConfigMixer config = new SourceConfigMixer();
InputMixerConfiguration selected =
(InputMixerConfiguration)mComboMixers.getSelectedItem();
config.setMixer( selected.getMixerName() );
MixerChannel channel = (MixerChannel)mComboChannels.getSelectedItem();
config.setChannel( channel );
getItem().setSourceConfiguration( config );
}
setModified( false );
}
}

View File

@@ -19,6 +19,7 @@ package source.mixer;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.sound.sampled.AudioFormat;
@@ -29,12 +30,12 @@ import javax.sound.sampled.TargetDataLine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dsp.gain.AutomaticGainControl;
import sample.Listener;
import sample.adapter.ISampleAdapter;
import sample.real.RealBuffer;
import source.RealSource;
import source.SourceException;
import dsp.gain.AutomaticGainControl;
public class RealMixerSource extends RealSource
{
@@ -72,18 +73,30 @@ public class RealMixerSource extends RealSource
* the left/right stereo channels are inverted.
*/
public RealMixerSource( TargetDataLine targetDataLine,
AudioFormat format,
String name,
ISampleAdapter sampleAdapter )
AudioFormat format,
ISampleAdapter sampleAdapter )
{
super( name );
mTargetDataLine = targetDataLine;
mAudioFormat = format;
mSampleAdapter = sampleAdapter;
}
public void setListener( Listener<RealBuffer> listener )
@Override
public void reset()
{
}
@Override
public void start( ScheduledExecutorService executor )
{
}
@Override
public void stop()
{
}
public void setListener( Listener<RealBuffer> listener )
{
mSampleListeners.add( listener );
@@ -92,7 +105,7 @@ public class RealMixerSource extends RealSource
{
Thread thread = new Thread( mBufferReader );
thread.setDaemon( true );
thread.setName( getName() + " Sample Reader" );
thread.setName( "Sample Reader" );
thread.start();
}
}

View File

@@ -4,32 +4,34 @@ import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.RejectedExecutionException;
import settings.SettingsManager;
import source.SourceException;
import source.tuner.ITunerChannelProvider;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelProvider;
import source.tuner.TunerChannelSource;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import controller.ResourceManager;
import controller.ThreadPoolManager;
import source.tuner.frequency.IFrequencyChangeProcessor;
public class Recording implements Comparable<Recording>,
FrequencyChangeListener,
TunerChannelProvider
IFrequencyChangeProcessor,
ITunerChannelProvider
{
private ResourceManager mResourceManager;
private RecordingConfiguration mConfiguration;
private ArrayList<TunerChannelSource> mTunerChannels =
new ArrayList<TunerChannelSource>();
@SuppressWarnings( "unused" )
private long mCenterFrequency;
public Recording( ResourceManager resourceManager,
@SuppressWarnings( "unused" )
private SettingsManager mSettingsManager;
public Recording( SettingsManager settingsManager,
RecordingConfiguration configuration )
{
mResourceManager = resourceManager;
mSettingsManager = settingsManager;
mConfiguration = configuration;
mCenterFrequency = mConfiguration.getCenterFrequency();
}
@@ -37,7 +39,7 @@ public class Recording implements Comparable<Recording>,
public void setAlias( String alias )
{
mConfiguration.setAlias( alias );
mResourceManager.getSettingsManager().save();
// mSettingsManager.save();
}
public void setRecordingFile( File file ) throws SourceException
@@ -50,7 +52,7 @@ public class Recording implements Comparable<Recording>,
}
mConfiguration.setFilePath( file.getAbsolutePath() );
mResourceManager.getSettingsManager().save();
// mSettingsManager.save();
}
/**
@@ -89,13 +91,13 @@ public class Recording implements Comparable<Recording>,
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
if( event.getEvent() == Event.FREQUENCY_CHANGE_NOTIFICATION )
if( event.getEvent() == Event.NOTIFICATION_FREQUENCY_CHANGE )
{
long frequency = event.getValue().longValue();
mConfiguration.setCenterFrequency( frequency );
mResourceManager.getSettingsManager().save();
// mSettingsManager.save();
mCenterFrequency = frequency;

View File

@@ -1,120 +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.recording;
import gui.control.JFrequencyControl;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import source.SourceEditor;
import source.config.SourceConfigRecording;
import source.config.SourceConfigTuner;
import source.config.SourceConfiguration;
import controller.ResourceManager;
public class RecordingEditor extends SourceEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<Recording> mComboRecordings;
private JFrequencyControl mFrequencyControl;
public RecordingEditor( ResourceManager resourceManager,
SourceConfiguration config )
{
super( resourceManager, config );
initGUI();
}
public void reset()
{
mFrequencyControl.setFrequency(
((SourceConfigTuner)mConfig).getFrequency(), false );
}
public void save()
{
SourceConfigRecording config = (SourceConfigRecording)mConfig;
Recording selected = (Recording)mComboRecordings.getSelectedItem();
if( selected != null )
{
config.setRecordingAlias( selected
.getRecordingConfiguration().getAlias() );
}
config.setFrequency( mFrequencyControl.getFrequency() );
}
private void initGUI()
{
add( new JLabel( "Recording" ) );
mComboRecordings = new JComboBox<Recording>();
add( mComboRecordings, "wrap" );
mFrequencyControl = new JFrequencyControl();
mFrequencyControl.setFrequency(
((SourceConfigRecording)mConfig).getFrequency(), false );
add( mFrequencyControl, "span" );
resetRecordings();
}
private void resetRecordings()
{
SwingUtilities.invokeLater( new Runnable()
{
@Override
public void run()
{
List<Recording> recordings = getResourceManager()
.getRecordingSourceManager().getRecordings();
mComboRecordings.setModel(
new DefaultComboBoxModel<Recording>(
recordings.toArray( new Recording[ recordings.size()] ) ) );
SourceConfigRecording config = (SourceConfigRecording)mConfig;
String recordingAlias = config.getRecordingAlias();
if( recordingAlias != null )
{
Recording selected = mResourceManager
.getRecordingSourceManager()
.getRecordingFromAlias( recordingAlias );
if( selected != null )
{
mComboRecordings.setSelectedItem( selected );
}
}
}
});
}
}

View File

@@ -1,130 +0,0 @@
package source.recording;
import gui.control.JFrequencyControl;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
public class RecordingEditorPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private RecordingNode mRecordingNode;
private JTextField mRecordingAlias;
private JLabel mFilePathLabel;
public RecordingEditorPanel( RecordingNode recordingNode )
{
mRecordingNode = recordingNode;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][][][][grow]" ) );
add( new JLabel( "I/Q Recording" ), "span,align left" );
add( new JLabel( "Alias:" ) );
mRecordingAlias = new JTextField( mRecordingNode.getRecording()
.getRecordingConfiguration().getAlias() );
mRecordingAlias.addFocusListener( new FocusListener()
{
@Override
public void focusLost( FocusEvent arg0 )
{
String alias = mRecordingAlias.getText();
if( alias != null )
{
mRecordingNode.getRecording().setAlias( alias );
}
}
@Override
public void focusGained( FocusEvent arg0 ) {}
} );
add( mRecordingAlias, "wrap" );
JButton mFileSelectionButton = new JButton( "File ..." );
mFileSelectionButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
if( mRecordingNode.getRecording().hasChannels() )
{
JOptionPane.showMessageDialog( RecordingEditorPanel.this,
"This recording is currently in replay. Please "
+ "disable any channels that are using this "
+ "recording before changing the recording file." );
}
else
{
final JFileChooser fc = new JFileChooser();
int returnVal = fc.showOpenDialog( RecordingEditorPanel.this );
if ( returnVal == JFileChooser.APPROVE_OPTION )
{
File file = fc.getSelectedFile();
if( file != null && file.exists() )
{
mRecordingNode.getRecording()
.getRecordingConfiguration()
.setFilePath( file.getAbsolutePath() );
if( mFilePathLabel != null )
{
mFilePathLabel.setText( file.getName() );
}
}
}
}
}
} );
add( mFileSelectionButton );
String filePath = mRecordingNode.getRecording()
.getRecordingConfiguration().getFilePath();
if( filePath != null )
{
mFilePathLabel = new JLabel( filePath );
}
else
{
mFilePathLabel = new JLabel( "Please select a recording" );
}
add( mFilePathLabel, "wrap" );
add( new JLabel( "Center Frequency:" ), "span,align left" );
JFrequencyControl frequencyControl = new JFrequencyControl(
mRecordingNode.getRecording().getRecordingConfiguration()
.getCenterFrequency() );
frequencyControl.addListener( mRecordingNode.getRecording() );
add( frequencyControl, "span,align left" );
}
}

View File

@@ -1,91 +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.recording;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import controller.BaseNode;
public class RecordingGroupNode extends BaseNode
{
private static final long serialVersionUID = 1L;
public RecordingGroupNode()
{
super( null );
}
public String toString()
{
return "Recordings [" + this.getChildCount() + "]";
}
public JPopupMenu getContextMenu()
{
JPopupMenu menu = new JPopupMenu();
JMenuItem addRecordingItem = new JMenuItem( "Add Recording" );
addRecordingItem.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
RecordingConfiguration config = new RecordingConfiguration();
getModel().getResourceManager().getSettingsManager()
.addRecordingConfiguration( config );
Recording recording = getModel().getResourceManager()
.getRecordingSourceManager().addRecording( config );
RecordingNode node = new RecordingNode( recording );
getModel().addNode( node, RecordingGroupNode.this, 0 );
sort();
node.show();
}
} );
menu.add( addRecordingItem );
return menu;
}
public void loadRecordings()
{
List<Recording> recordings = getModel().getResourceManager()
.getRecordingSourceManager().getRecordings();
for( Recording recording: recordings )
{
RecordingNode node = new RecordingNode( recording );
getModel().addNode( node, this, 0 );
}
sort();
}
}

View File

@@ -1,79 +0,0 @@
package source.recording;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import controller.BaseNode;
public class RecordingNode extends BaseNode
{
private static final long serialVersionUID = 1L;
private JPanel mEditor;
public RecordingNode( Recording recording )
{
super( recording );
}
public Recording getRecording()
{
return (Recording)getUserObject();
}
public String toString()
{
return getRecording().toString();
}
@Override
public JPanel getEditor()
{
if( mEditor == null )
{
mEditor = new RecordingEditorPanel( this );
}
return mEditor;
}
public JPopupMenu getContextMenu()
{
JPopupMenu menu = new JPopupMenu();
JMenuItem deleteItem = new JMenuItem( "Delete" );
deleteItem.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
if( getRecording().hasChannels() )
{
JOptionPane.showMessageDialog( getModel().getTree(),
"Can't delete recording - currently in use. Please"
+ " disable any channel(s) that are using this "
+ "recording before deleting it",
"Can't delete recording",
JOptionPane.ERROR_MESSAGE );
}
else
{
getModel().getResourceManager().getRecordingSourceManager()
.removeRecording( getRecording() );
getModel().removeNodeFromParent( RecordingNode.this );
}
}
} );
menu.add( deleteItem );
return menu;
}
}

View File

@@ -31,21 +31,19 @@ import source.config.SourceConfigRecording;
import source.config.SourceConfiguration;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelSource;
import controller.ResourceManager;
public class RecordingSourceManager
{
private final static Logger mLog =
LoggerFactory.getLogger( RecordingSourceManager.class );
private ResourceManager mResourceManager;
private ArrayList<Recording> mRecordings = new ArrayList<Recording>();
public RecordingSourceManager( ResourceManager resourceManager )
private SettingsManager mSettingsManager;
public RecordingSourceManager( SettingsManager settingsManager )
{
mResourceManager = resourceManager;
mSettingsManager = settingsManager;
loadRecordings();
}
@@ -114,7 +112,7 @@ public class RecordingSourceManager
public Recording addRecording( RecordingConfiguration config )
{
Recording recording = new Recording( mResourceManager, config );
Recording recording = new Recording( mSettingsManager, config );
mRecordings.add( recording );
@@ -124,7 +122,7 @@ public class RecordingSourceManager
public void removeRecording( Recording recording )
{
/* Remove the config from the settings manager */
mResourceManager.getSettingsManager().removeRecordingConfiguration(
mSettingsManager.removeRecordingConfiguration(
recording.getRecordingConfiguration() );
mRecordings.remove( recording );
@@ -132,24 +130,17 @@ public class RecordingSourceManager
private void loadRecordings()
{
if( mResourceManager != null )
{
SettingsManager settingsManager = mResourceManager.getSettingsManager();
if( settingsManager != null )
{
ArrayList<RecordingConfiguration> recordingConfigurations =
settingsManager.getRecordingConfigurations();
List<RecordingConfiguration> recordingConfigurations =
mSettingsManager.getRecordingConfigurations();
mLog.info( "discovered [" + recordingConfigurations.size() + "] recording configurations" );
for( RecordingConfiguration config: recordingConfigurations )
{
Recording recording = new Recording( mResourceManager, config );
mRecordings.add( recording );
}
}
}
}
mLog.info( "RecordingSourceManager - discovered [" +
recordingConfigurations.size() + "] recording configurations" );
for( RecordingConfiguration config: recordingConfigurations )
{
Recording recording = new Recording( mSettingsManager, config );
mRecordings.add( recording );
}
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,19 +17,28 @@
******************************************************************************/
package source.tuner;
import controller.BaseNode;
import java.util.concurrent.RejectedExecutionException;
public class TunerGroupNode extends BaseNode
import source.SourceException;
public interface ITunerChannelProvider
{
private static final long serialVersionUID = 1L;
/**
* Returns a tuner frequency channel source, tuned to the correct frequency
*
* @param frequency - desired frequency
*
* @return - source for 48k sample rate
*/
public abstract TunerChannelSource getChannel( TunerChannel channel )
throws RejectedExecutionException, SourceException;
public TunerGroupNode()
{
super( null );
}
public String toString()
{
return "Tuners [" + this.getChildCount() + "]";
}
/**
* Releases the tuned channel resources
*
* @param channel - previously obtained tuner channel
*/
public abstract void releaseChannel( TunerChannelSource source );
}

View File

@@ -46,11 +46,12 @@ public abstract class MixerTuner extends Tuner implements Listener<ComplexBuffer
* to support tuning.
*/
public MixerTuner( String name,
TunerController tunerController,
MixerTunerType mixerTunerType,
TargetDataLine targetDataLine,
ISampleAdapter sampleAdapter )
{
super( name );
super( name, tunerController );
mMixerTunerType = mixerTunerType;
@@ -61,11 +62,13 @@ public abstract class MixerTuner extends Tuner implements Listener<ComplexBuffer
(Listener<ComplexBuffer>)this );
}
public MixerTuner( String name,
public MixerTuner( String name,
TunerController tunerController,
MixerTunerDataLine mixerTuner,
ISampleAdapter sampleAdapter )
{
this( name,
tunerController,
mixerTuner.getMixerTunerType(),
mixerTuner.getTargetDataLine(),
sampleAdapter );

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,47 +17,70 @@
******************************************************************************/
package source.tuner;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.JPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.complex.ComplexBuffer;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeBroadcaster;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.FrequencyChangeListener;
import controller.ResourceManager;
import source.tuner.frequency.IFrequencyChangeProcessor;
/**
* Tuner - provides tuner channel sources, representing a channel frequency
*/
public abstract class Tuner implements FrequencyChangeBroadcaster,
FrequencyChangeListener,
TunerChannelProvider
public abstract class Tuner implements ITunerChannelProvider
{
private final static Logger mLog = LoggerFactory.getLogger( Tuner.class );
private String mName;
private TunerController mTunerController;
/**
* Sample Listeners - these will typically be the DFT processor for spectral
* display, or it will be one or more tuner channel sources
*/
protected CopyOnWriteArrayList<Listener<ComplexBuffer>>
mSampleListeners = new CopyOnWriteArrayList<Listener<ComplexBuffer>>();
protected List<Listener<ComplexBuffer>> mSampleListeners =
new CopyOnWriteArrayList<>();
protected CopyOnWriteArrayList<FrequencyChangeListener>
mFrequencyChangeListeners = new CopyOnWriteArrayList<FrequencyChangeListener>();
public Tuner( String name )
protected List<Listener<TunerEvent>> mTunerChangeListeners =
new ArrayList<>();
public Tuner( String name, TunerController tunerController )
{
mName = name;
mTunerController = tunerController;
//Rebroadcast frequency and sample rate change events as tuner events
mTunerController.addListener( new IFrequencyChangeProcessor()
{
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
switch( event.getEvent() )
{
case NOTIFICATION_FREQUENCY_CHANGE:
broadcast( new TunerEvent( Tuner.this,
source.tuner.TunerEvent.Event.FREQUENCY ));
break;
case NOTIFICATION_SAMPLE_RATE_CHANGE:
broadcast( new TunerEvent( Tuner.this,
source.tuner.TunerEvent.Event.SAMPLE_RATE ));
break;
default:
break;
}
}
} );
}
public TunerController getTunerController()
{
return mTunerController;
}
public String toString()
@@ -68,7 +91,6 @@ public abstract class Tuner implements FrequencyChangeBroadcaster,
public void dispose()
{
mSampleListeners.clear();
mFrequencyChangeListeners.clear();
}
public void setName( String name )
@@ -76,18 +98,6 @@ public abstract class Tuner implements FrequencyChangeBroadcaster,
mName = name;
}
/**
* Return an editor panel for the tuner
*/
public abstract JPanel getEditor( ResourceManager resourceManager );
/**
* Applies the settings from a saved tuner configuration setting object
*/
public abstract void apply( TunerConfiguration config )
throws SourceException;
/**
* Unique identifier for this tuner, used to lookup a tuner configuration
* from the settings manager.
@@ -118,23 +128,11 @@ public abstract class Tuner implements FrequencyChangeBroadcaster,
return mName;
}
/**
* Sample rate of complex data coming from the Tuner
* @return
*/
public abstract int getSampleRate();
/**
* Sample size in bits
*/
public abstract double getSampleSize();
/**
* Tuner Local Oscillator Frequency
* @return - frequency in Hertz
*/
public abstract long getFrequency() throws SourceException;
/**
* Returns a tuner frequency channel source, tuned to the correct frequency
*
@@ -186,67 +184,30 @@ public abstract class Tuner implements FrequencyChangeBroadcaster,
}
}
/**
* Adds the frequency change listener to receive frequency and/or bandwidth
* change events
*/
public void addListener( FrequencyChangeListener listener )
{
mFrequencyChangeListeners.add( listener );
}
/**
* Registers the listener
*/
public void addTunerChangeListener( Listener<TunerEvent> listener )
{
mTunerChangeListeners.add( listener );
}
/**
* Removes the frequency change listener
* Removes the registered listener
*/
public void removeListener( FrequencyChangeListener listener )
public void removeTunerChangeListener( Listener<TunerEvent> listener )
{
mFrequencyChangeListeners.remove( listener );
mTunerChangeListeners.remove( listener );
}
/**
* Broadcasts a frequency change event to all registered listeners
* Broadcasts the tuner change event
*/
public void broadcastFrequencyChange( long frequency )
public void broadcast( TunerEvent event )
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.FREQUENCY_CHANGE_NOTIFICATION, frequency ) );
}
/**
* Broadcasts a sample rate change event to all registered listeners
*/
public void broadcastSampleRateChange( int sampleRate )
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.SAMPLE_RATE_CHANGE_NOTIFICATION, sampleRate ) );
}
/**
* Broadcasts actual sample rate change event to all registered listeners
*/
public void broadcastActualSampleRateChange( int actualSampleRate )
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.SAMPLE_RATE_CHANGE_NOTIFICATION, actualSampleRate ) );
}
/**
* Broadcasts a frequency change event to all registered listeners
*/
public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event )
{
for( FrequencyChangeListener listener: mFrequencyChangeListeners )
for( Listener<TunerEvent> listener: mTunerChangeListeners )
{
listener.frequencyChanged( event );
listener.receive( event );
}
}
/**
* Frequency change listener method. We receive change events from the
* controller and rebroadcast them to all registered listeners.
*/
public void frequencyChanged( FrequencyChangeEvent event )
{
broadcastFrequencyChangeEvent( event );
}
}

View File

@@ -97,13 +97,13 @@ public class TunerChannel implements Comparable<TunerChannel>
}
@Override
public int compareTo( TunerChannel otherTunerChannel )
public int compareTo( TunerChannel otherLock )
{
if( this.equals( otherTunerChannel ) )
if( this.equals( otherLock ) )
{
return 0;
}
else if( mFrequency < otherTunerChannel.getFrequency() )
else if( mFrequency < otherLock.getFrequency() )
{
return -1;
}

View File

@@ -3,7 +3,6 @@ package source.tuner;
import java.util.concurrent.RejectedExecutionException;
import source.SourceException;
import controller.ThreadPoolManager;
public interface TunerChannelProvider
{

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,15 +37,14 @@ import source.ComplexSource;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.frequency.IFrequencyChangeProcessor;
import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType;
import dsp.filter.cic.ComplexPrimeCICDecimate;
import dsp.mixer.Oscillator;
public class TunerChannelSource extends ComplexSource
implements FrequencyChangeListener,
Listener<ComplexBuffer>
implements IFrequencyChangeProcessor, Listener<ComplexBuffer>
{
private final static Logger mLog =
LoggerFactory.getLogger( TunerChannelSource.class );
@@ -60,7 +59,7 @@ public class TunerChannelSource extends ComplexSource
private Oscillator mMixer;
private ComplexPrimeCICDecimate mDecimationFilter;
private Listener<ComplexBuffer> mListener;
private FrequencyChangeListener mFrequencyChangeListener;
private IFrequencyChangeProcessor mFrequencyChangeProcessor;
private ScheduledFuture<?> mTaskHandle;
private long mTunerFrequency = 0;
@@ -69,82 +68,122 @@ public class TunerChannelSource extends ComplexSource
private DecimationProcessor mDecimationProcessor = new DecimationProcessor();
private AtomicBoolean mRunning = new AtomicBoolean();
private boolean mExpended = false;
/**
* Provides a Digital Drop Channel (DDC) to decimate the IQ output from a
* tuner down to a 48 kHz IQ channel rate.
*
* Note: this class can only be used once (started and stopped) and a new
* tuner channel source must be requested from the tuner once this object
* has been stopped. This is because channels are managed dynamically and
* center tuned frequency may have changed since this source was obtained
* and thus the tuner might no longer be able to source this channel once it
* has been stopped.
*
* @param threadPoolManager to use for decimation processing task
* @param tuner to obtain wideband IQ samples from
* @param tunerChannel specifying the center frequency for the DDC
* @throws RejectedExecutionException if the thread pool manager cannot
* accept the decimation processing task
* @throws SourceException if the tuner has an issue providing IQ samples
*/
public TunerChannelSource( Tuner tuner, TunerChannel tunerChannel )
throws RejectedExecutionException, SourceException
throws RejectedExecutionException, SourceException
{
super( "Tuner Channel Source" );
mTuner = tuner;
mTuner.addListener( (FrequencyChangeListener)this );
mTuner.getTunerController().addListener( (IFrequencyChangeProcessor)this );
mTunerChannel = tunerChannel;
mTunerFrequency = mTuner.getFrequency();
mTunerFrequency = mTuner.getTunerController().getFrequency();
/* Setup the frequency translator to the current source frequency */
long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency();
mMixer = new Oscillator( frequencyOffset, mTuner.getSampleRate() );
mMixer = new Oscillator( frequencyOffset,
mTuner.getTunerController().getSampleRate() );
/* Fire a sample rate change event to setup the decimation chain */
frequencyChanged( new FrequencyChangeEvent(
Event.SAMPLE_RATE_CHANGE_NOTIFICATION, mTuner.getSampleRate() ) );
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
mTuner.getTunerController().getSampleRate() ) );
}
public void start( ScheduledExecutorService scheduledExecutorService )
{
/* Schedule the decimation task to run every 10 ms (100 iterations/second) */
mTaskHandle = scheduledExecutorService.scheduleAtFixedRate(
mDecimationProcessor, 0, 10, TimeUnit.MILLISECONDS );
/* Finally, register to receive samples from the tuner */
mTuner.addListener( (Listener<ComplexBuffer>)this );
}
@Override
public void start( ScheduledExecutorService executor )
{
if( mExpended )
{
throw new IllegalStateException( "Attempt to re-start an expended "
+ "tuner channel source. TunerChannelSource objects can only "
+ "be used once. " );
}
if( mRunning.compareAndSet( false, true ))
{
/* Schedule the decimation task to run every 10 ms (100 iterations/second) */
mTaskHandle = executor.scheduleAtFixedRate( mDecimationProcessor,
0, 10, TimeUnit.MILLISECONDS );
/* Finally, register to receive samples from the tuner */
mTuner.addListener( (Listener<ComplexBuffer>)this );
}
else
{
mLog.warn( "Attempt to start() and already running tuner channel source was ignored" );
}
}
@Override
public void reset()
{
}
@Override
public void stop()
{
if( mRunning.compareAndSet( true, false ))
{
mTuner.releaseChannel( this );
mDecimationProcessor.shutdown();
if( mTaskHandle != null )
{
mTaskHandle.cancel( true );
mTaskHandle = null;
}
mBuffer.clear();
mExpended = true;
}
else
{
mLog.warn( "Attempt to stop() and already stopped tuner channel source was ignored" );
}
}
@Override
public void dispose()
{
/* Tell the tuner to release/unregister our resources */
mTuner.removeListener( (FrequencyChangeListener)this );
mTuner.releaseChannel( this );
mTuner = null;
mTunerChannel = null;
/* Flag the decimation processor to shutdown */
if( mDecimationProcessor != null )
{
mDecimationProcessor.dispose();
}
if( !mRunning.get() )
{
/* Tell the tuner to release/unregister our resources */
mTuner.getTunerController().removeListener( this );
mTuner = null;
mTunerChannel = null;
mBuffer = null;
mFrequencyChangeProcessor = null;
mListener = null;
mMixer = null;
mDecimationFilter.dispose();
mDecimationFilter = null;
}
}
/**
* Cleanup method to allow the decimation processor to perform final cleanup
* once it gracefully shuts itself down
*/
private void cleanup()
{
if( mTaskHandle != null )
{
mTaskHandle.cancel( true );
mTaskHandle = null;
}
synchronized( mBuffer )
{
mBuffer.clear();
mBuffer = null;
}
mFrequencyChangeListener = null;
mListener = null;
mMixer = null;
mDecimationFilter.dispose();
mDecimationFilter = null;
}
public Tuner getTuner()
{
return mTuner;
@@ -158,24 +197,21 @@ public class TunerChannelSource extends ComplexSource
@Override
public void receive( ComplexBuffer buffer )
{
synchronized( mBuffer )
if( mRunning.get() )
{
if( mBuffer != null )
{
mBuffer.add( buffer );
}
mBuffer.add( buffer );
}
}
public void setFrequencyChangeListener( FrequencyChangeListener listener )
public void setFrequencyChangeListener( IFrequencyChangeProcessor processor )
{
mFrequencyChangeListener = listener;
mFrequencyChangeProcessor = processor;
}
@Override
public void setListener( Listener<ComplexBuffer> listener )
{
/* Get a pointer to the listener so that if we have to change the
/* Save a pointer to the listener so that if we have to change the
* decimation filter, we can re-add the listener */
mListener = listener;
@@ -196,31 +232,31 @@ public class TunerChannelSource extends ComplexSource
public void frequencyChanged( FrequencyChangeEvent event )
{
// Echo the event to the registered event listener
if( mFrequencyChangeListener != null )
if( mFrequencyChangeProcessor != null )
{
mFrequencyChangeListener.frequencyChanged( event );
mFrequencyChangeProcessor.frequencyChanged( event );
}
switch( event.getEvent() )
{
case FREQUENCY_CHANGE_NOTIFICATION:
case NOTIFICATION_FREQUENCY_CHANGE:
mTunerFrequency = event.getValue().longValue();
updateMixerFrequencyOffset();
break;
case CHANNEL_FREQUENCY_CORRECTION_CHANGE_REQUEST:
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
mChannelFrequencyCorrection = event.getValue().intValue();
updateMixerFrequencyOffset();
if( mFrequencyChangeListener != null )
if( mFrequencyChangeProcessor != null )
{
mFrequencyChangeListener.frequencyChanged(
mFrequencyChangeProcessor.frequencyChanged(
new FrequencyChangeEvent(
Event.CHANNEL_FREQUENCY_CORRECTION_CHANGE_NOTIFICATION,
Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
mChannelFrequencyCorrection ) );
}
break;
case SAMPLE_RATE_CHANGE_NOTIFICATION:
case NOTIFICATION_SAMPLE_RATE_CHANGE:
int sampleRate = event.getValue().intValue();
if( mTunerSampleRate != sampleRate )
@@ -276,12 +312,12 @@ public class TunerChannelSource extends ComplexSource
*/
public class DecimationProcessor implements Runnable
{
private AtomicBoolean mDispose = new AtomicBoolean( false );
private boolean mProcessing = true;
private List<ComplexBuffer> mSampleBuffers = new ArrayList<ComplexBuffer>();
public void dispose()
public void shutdown()
{
mDispose.set( true );
mProcessing = false;
}
@Override
@@ -292,64 +328,69 @@ public class TunerChannelSource extends ComplexSource
* run the program out of memory */
try
{
if( mBuffer != null )
if( mProcessing )
{
mBuffer.drainTo( mSampleBuffers, 8 );
for( Buffer buffer: mSampleBuffers )
{
/* Check to see if we've been shutdown */
if( mDispose.get() )
// long start = System.currentTimeMillis();
mBuffer.drainTo( mSampleBuffers, 8 );
for( Buffer buffer: mSampleBuffers )
{
cleanup();
return;
}
else
{
float[] samples = buffer.getSamples();
/* We make a copy of the buffer so that we don't affect
* anyone else that is using the same buffer, like other
* channels or the spectral display */
float[] translated = new float[ samples.length ];
/* Perform frequency translation */
for( int x = 0; x < samples.length; x += 2 )
/* Check to see if we've been shutdown */
if( !mProcessing )
{
mMixer.rotate();
mBuffer.clear();
return;
}
else
{
float[] samples = buffer.getSamples();
/* We make a copy of the buffer so that we don't affect
* anyone else that is using the same buffer, like other
* channels or the spectral display */
float[] translated = new float[ samples.length ];
translated[ x ] = Complex.multiplyInphase(
samples[ x ], samples[ x + 1 ], mMixer.inphase(), mMixer.quadrature() );
translated[ x + 1 ] = Complex.multiplyQuadrature(
/* Perform frequency translation */
for( int x = 0; x < samples.length; x += 2 )
{
mMixer.rotate();
translated[ x ] = Complex.multiplyInphase(
samples[ x ], samples[ x + 1 ], mMixer.inphase(), mMixer.quadrature() );
}
if( mDecimationFilter != null )
{
mDecimationFilter.receive( new ComplexBuffer( translated ) );
translated[ x + 1 ] = Complex.multiplyQuadrature(
samples[ x ], samples[ x + 1 ], mMixer.inphase(), mMixer.quadrature() );
}
if( mProcessing && mDecimationFilter != null )
{
mDecimationFilter.receive( new ComplexBuffer( translated ) );
}
}
}
// mLog.debug( "Processed [" + mSampleBuffers.size() + "] in " + ( System.currentTimeMillis() - start ) );
mSampleBuffers.clear();
}
mSampleBuffers.clear();
}
}
catch( Exception e )
{
/* Only log the stack trace if we've haven't been shutdown and
* this is a true error */
if( !mDispose.get() )
/* Only log the stack trace if we're still processing */
if( mProcessing )
{
mLog.error( "Error encountered during decimation process", e );
}
}
/* Check to see if we've been shutdown */
if( mDispose.get() )
if( !mProcessing )
{
mBuffer.clear();
mSampleBuffers.clear();
cleanup();
}
}
}

View File

@@ -21,7 +21,7 @@ import javax.usb.UsbDeviceDescriptor;
public enum TunerClass
{
AIRSPY( TunerType.AIRSPY_R820T, "1D50", "60A1", "Airspy.com", "Airspy" ),
AIRSPY( TunerType.AIRSPY_R820T, "1D50", "60A1", "Airspy", "Airspy" ),
GENERIC_2832( TunerType.RTL2832_VARIOUS, "0BDA", "2832", "RTL2832", "SDR" ),
GENERIC_2838( TunerType.RTL2832_VARIOUS, "0BDA", "2838", "RTL2832", "SDR" ),
COMPRO_VIDEOMATE_U620F( TunerType.ELONICS_E4000, "185B", "0620", "Compro", "Videomate U620F" ),

View File

@@ -1,64 +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 javax.xml.bind.annotation.XmlAttribute;
public class TunerConfigurationAssignment
{
private TunerType mTunerType;
private String mUniqueID;
private String mTunerConfigurationName;
public TunerConfigurationAssignment()
{
}
@XmlAttribute( name = "type" )
public TunerType getTunerType()
{
return mTunerType;
}
public void setTunerType( TunerType tunerType )
{
mTunerType = tunerType;
}
@XmlAttribute( name = "id" )
public String getUniqueID()
{
return mUniqueID;
}
public void setUniqueID( String uniqueID )
{
mUniqueID = uniqueID;
}
@XmlAttribute( name = "configuration_name" )
public String getTunerConfigurationName()
{
return mTunerConfigurationName;
}
public void setTunerConfigurationName( String tunerConfigurationName )
{
mTunerConfigurationName = tunerConfigurationName;
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,12 +25,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.FrequencyController;
import source.tuner.frequency.FrequencyController.Tunable;
import controller.ThreadPoolManager;
import source.tuner.frequency.IFrequencyChangeProcessor;
public abstract class TunerController implements Tunable
public abstract class TunerController implements Tunable, IFrequencyChangeProcessor
{
private final static Logger mLog =
LoggerFactory.getLogger( TunerController.class );
@@ -72,8 +74,27 @@ public abstract class TunerController implements Tunable
*/
public abstract void apply( TunerConfiguration config )
throws SourceException;
public int getBandwidth()
/**
* Responds to requests to set the frequency
*/
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
if( event.getEvent() == Event.REQUEST_FREQUENCY_CHANGE )
{
try
{
setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
mLog.error( "Error setting frequency from external controller", e );
}
}
}
public int getBandwidth()
{
return mFrequencyController.getBandwidth();
}
@@ -98,6 +119,11 @@ public abstract class TunerController implements Tunable
{
return mFrequencyController.getFrequency();
}
public int getSampleRate()
{
return mFrequencyController.getBandwidth();
}
public double getFrequencyCorrection()
{
@@ -221,6 +247,11 @@ public abstract class TunerController implements Tunable
return source;
}
public int getChannelCount()
{
return mTunedChannels.size();
}
/**
* Indicates if the tuner's LO frequency must be updated in order to
@@ -358,16 +389,16 @@ public abstract class TunerController implements Tunable
* Note: this is normally used by the Tuner. Any additional listeners can
* be registered on the tuner.
*/
public void addListener( FrequencyChangeListener listener )
public void addListener( IFrequencyChangeProcessor processor )
{
mFrequencyController.addListener( listener );
mFrequencyController.addListener( processor );
}
/**
* Removes the frequency change listener
*/
public void removeListener( FrequencyChangeListener listener )
public void removeListener( IFrequencyChangeProcessor processor )
{
mFrequencyController.removeListener( listener );
mFrequencyController.removeFrequencyChangeProcessor( processor );
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,45 +15,342 @@
* 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 gui.control.JFrequencyControl;
import source.SourceEditor;
import source.config.SourceConfigTuner;
import source.config.SourceConfiguration;
import controller.ResourceManager;
import gui.editor.Editor;
import gui.editor.EmptyEditor;
public class TunerEditor extends SourceEditor
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableRowSorter;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.configuration.TunerConfigurationFactory;
import source.tuner.configuration.TunerConfigurationModel;
import com.jidesoft.swing.JideSplitPane;
public class TunerEditor extends Editor<Tuner>
{
private static final long serialVersionUID = 1L;
private JFrequencyControl mFrequencyControl;
public TunerEditor( ResourceManager resourceManager,
SourceConfiguration config )
{
super( resourceManager, config );
initGUI();
}
private static final long serialVersionUID = 1L;
public void reset()
private final static Logger mLog = LoggerFactory.getLogger( TunerEditor.class );
private TunerConfigurationModel mTunerConfigurationModel;
private JTable mTunerConfigurationTable;
private TableRowSorter<TunerConfigurationModel> mRowSorter;
private JFrequencyControl mFrequencyControl = new JFrequencyControl();
private JLabel mSelectedTunerType = new JLabel( "No Tuner Selected" );
private JButton mNewConfigurationButton = new JButton( "New" );
private JButton mDeleteConfigurationButton = new JButton( "Delete" );
private JButton mAssignConfigurationButton = new JButton( "Assign" );
private JScrollPane mEditorScroller;
private Editor<TunerConfiguration> mEditor = new EmptyEditor<>( "a tuner" );
private JideSplitPane mEditorSplitPane = new JideSplitPane();
public TunerEditor( TunerConfigurationModel tunerConfigurationModel )
{
mFrequencyControl.setFrequency(
((SourceConfigTuner)mConfig).getFrequency(), false );
mTunerConfigurationModel = tunerConfigurationModel;
init();
}
public void init()
{
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill]" ) );
JPanel listPanel = new JPanel();
listPanel.setLayout( new MigLayout( "fill,wrap 3", "[grow,fill]", "[][][][grow,fill][]" ) );
listPanel.add( mSelectedTunerType, "span" );
mFrequencyControl.setEnabled( false );
listPanel.add( mFrequencyControl, "span" );
mRowSorter = new TableRowSorter<>( mTunerConfigurationModel );
mTunerConfigurationTable = new JTable( mTunerConfigurationModel );
mTunerConfigurationTable.setRowSorter( mRowSorter );
mTunerConfigurationTable.setEnabled( false );
mTunerConfigurationTable.getSelectionModel().addListSelectionListener( new ListSelectionListener()
{
@Override
public void valueChanged( ListSelectionEvent event )
{
if( !event.getValueIsAdjusting() )
{
int row = mTunerConfigurationTable.getSelectedRow();
if( row >= 0 )
{
int modelRow = mTunerConfigurationTable.convertRowIndexToModel( row );
if( modelRow >= 0 )
{
setTunerConfiguration( mTunerConfigurationModel.getTunerConfiguration( modelRow ) );
}
}
}
}
} );
JScrollPane tableScroller = new JScrollPane( mTunerConfigurationTable );
tableScroller.setHorizontalScrollBarPolicy(
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
listPanel.add( new JLabel( "Tuner Configurations" ), "span" );
listPanel.add( tableScroller, "span" );
mNewConfigurationButton.setEnabled( false );
mNewConfigurationButton.setToolTipText( "Create a new configuration for the currently selected tuner" );
mNewConfigurationButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
Tuner tuner = getItem();
String name = mTunerConfigurationModel
.getDistinctName( tuner.getTunerType(), tuner.getUniqueID() );
TunerConfiguration config = TunerConfigurationFactory
.getTunerConfiguration( tuner.getTunerType(),
tuner.getUniqueID(), name );
mTunerConfigurationModel.addTunerConfiguration( config );
}
} );
listPanel.add( mNewConfigurationButton );
mDeleteConfigurationButton.setEnabled( false );
mDeleteConfigurationButton.setToolTipText( "Deletes the currently selected tuner" );
mDeleteConfigurationButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
int choice = JOptionPane.showConfirmDialog( TunerEditor.this,
"Do you want to delete this tuner configuration?",
"Delete Tuner Configuration?", JOptionPane.YES_NO_OPTION );
if( choice == JOptionPane.YES_OPTION )
{
TunerConfiguration selected = getSelectedTunerConfiguration();
mTunerConfigurationModel.removeTunerConfiguration( selected );
mTunerConfigurationTable.setRowSelectionInterval( 0, 0 );
}
}
} );
listPanel.add( mDeleteConfigurationButton );
mAssignConfigurationButton.setEnabled( false );
mAssignConfigurationButton.setToolTipText( "Assigns to the currently selected tuner configuration to the selected tuner" );
mAssignConfigurationButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
TunerConfiguration selected = getSelectedTunerConfiguration();
mTunerConfigurationModel.assignTunerConfiguration( selected );
setTunerConfiguration( getSelectedTunerConfiguration() );
}
} );
listPanel.add( mAssignConfigurationButton );
//Set preferred size on both scrollers to same width, so they split the space
listPanel.setPreferredSize( new Dimension( 100, 80 ) );
JScrollPane listScroller = new JScrollPane( listPanel );
listScroller.setPreferredSize( new Dimension( 100, 80 ) );
mEditorScroller = new JScrollPane( mEditor );
mEditorScroller.setPreferredSize( new Dimension( 100, 80 ) );
mEditorSplitPane = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
mEditorSplitPane.add( listScroller );
mEditorSplitPane.add( mEditorScroller );
add( mEditorSplitPane );
}
private TunerConfiguration getSelectedTunerConfiguration()
{
int tableRow = mTunerConfigurationTable.getSelectedRow();
if( tableRow >= 0 )
{
int modelRow = mTunerConfigurationTable.convertRowIndexToModel( tableRow );
if( modelRow >= 0 )
{
return mTunerConfigurationModel.getTunerConfiguration( modelRow );
}
}
return null;
}
@Override
public void save()
{
((SourceConfigTuner)mConfig).setFrequency( mFrequencyControl.getFrequency() );
//Unused
}
@Override
public void setItem( Tuner tuner )
{
//Cleanup previously selected tuner
if( hasItem() )
{
Tuner previous = getItem();
previous.getTunerController().removeListener( mFrequencyControl );
mFrequencyControl.removeListener( previous.getTunerController() );
}
super.setItem( tuner );
if( hasItem() )
{
mSelectedTunerType.setText( tuner.getName() );
mFrequencyControl.setEnabled( true );
mTunerConfigurationTable.setEnabled( true );
mNewConfigurationButton.setEnabled( true );
//Change to an editor for this config's tuner type
mEditor = TunerConfigurationFactory.getEditor( getItem(), mTunerConfigurationModel );
mRowSorter.setRowFilter( new ConfigurationRowFilter( tuner.getTunerType(),
tuner.getUniqueID() ) );
TunerConfiguration assigned = mTunerConfigurationModel
.getTunerConfiguration( tuner.getTunerType(), tuner.getUniqueID() );
int modelIndex = mTunerConfigurationModel.getRowIndex( assigned );
if( modelIndex >= 0 )
{
int viewIndex = mTunerConfigurationTable
.convertRowIndexToView( modelIndex );
if( viewIndex >= 0 )
{
mTunerConfigurationTable
.setRowSelectionInterval( viewIndex, viewIndex );
}
}
//Link frequency control to the tuner
mFrequencyControl.addListener( tuner.getTunerController() );
//Link tuner to frequency control
tuner.getTunerController().addListener( mFrequencyControl );
//Set the displayed frequency without adjusting the tuner's frequency
mFrequencyControl.setFrequency(
tuner.getTunerController().getFrequency(), false );
}
else
{
mSelectedTunerType.setText( "No Tuner Selected" );
mFrequencyControl.setEnabled( false );
mTunerConfigurationTable.setEnabled( false );
mNewConfigurationButton.setEnabled( false );
mRowSorter.setRowFilter( null );
mEditor = new EmptyEditor<TunerConfiguration>();
}
//Swap out the editor
int split = mEditorSplitPane.getDividerLocation( 0 );
mEditorSplitPane.remove( mEditorScroller );
mEditorScroller = new JScrollPane( mEditor );
mEditorSplitPane.add( mEditorScroller );
mEditorSplitPane.setDividerLocation( 0, split );
}
private void initGUI()
private void setTunerConfiguration( TunerConfiguration config )
{
mFrequencyControl = new JFrequencyControl();
if( config != null )
{
if( !config.isAssigned() )
{
if( !mAssignConfigurationButton.isEnabled() )
{
mAssignConfigurationButton.setEnabled( true );
}
if( !mDeleteConfigurationButton.isEnabled() )
{
mDeleteConfigurationButton.setEnabled( true );
}
}
else
{
if( mAssignConfigurationButton.isEnabled() )
{
mAssignConfigurationButton.setEnabled( false );
}
if( mDeleteConfigurationButton.isEnabled() )
{
mDeleteConfigurationButton.setEnabled( false );
}
}
}
else
{
if( mDeleteConfigurationButton.isEnabled() )
{
mDeleteConfigurationButton.setEnabled( false );
}
if( mAssignConfigurationButton.isEnabled() )
{
mAssignConfigurationButton.setEnabled( false );
}
}
mFrequencyControl.setFrequency(
((SourceConfigTuner)mConfig).getFrequency(), false );
add( mFrequencyControl );
mEditor.setItem( config );
}
public class ConfigurationRowFilter extends RowFilter<TunerConfigurationModel,Integer>
{
private TunerType mTunerType;
private String mUniqueID;
public ConfigurationRowFilter( TunerType type, String uniqueID )
{
mTunerType = type;
mUniqueID = uniqueID;
}
@Override
public boolean include( javax.swing.RowFilter.Entry<? extends TunerConfigurationModel,
? extends Integer> entry )
{
TunerConfiguration config = entry.getModel()
.getTunerConfiguration( entry.getIdentifier() );
return config != null &&
config.getTunerType() == mTunerType &&
config.getUniqueID() != null &&
config.getUniqueID().contentEquals( mUniqueID );
}
}
}

View File

@@ -0,0 +1,34 @@
package source.tuner;
public class TunerEvent
{
private Tuner mTuner;
private Event mEvent;
public TunerEvent( Tuner tuner, Event event )
{
mTuner = tuner;
mEvent = event;
}
public Tuner getTuner()
{
return mTuner;
}
public Event getEvent()
{
return mEvent;
}
public enum Event
{
ADD,
REMOVE,
CHANNEL_COUNT,
FREQUENCY,
SAMPLE_RATE,
REQUEST_MAIN_SPECTRAL_DISPLAY,
REQUEST_NEW_SPECTRAL_DISPLAY;
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,11 +17,7 @@
******************************************************************************/
package source.tuner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,10 +26,7 @@ import org.usb4java.DeviceDescriptor;
import org.usb4java.DeviceList;
import org.usb4java.LibUsb;
import source.Source;
import source.SourceException;
import source.config.SourceConfigTuner;
import source.config.SourceConfiguration;
import source.mixer.MixerManager;
import source.tuner.airspy.AirspyTuner;
import source.tuner.airspy.AirspyTunerController;
@@ -46,22 +39,24 @@ import source.tuner.rtl.RTL2832Tuner;
import source.tuner.rtl.RTL2832TunerController;
import source.tuner.rtl.e4k.E4KTunerController;
import source.tuner.rtl.r820t.R820TTunerController;
import controller.ResourceManager;
import controller.ThreadPoolManager;
public class TunerManager
{
private final static Logger mLog =
LoggerFactory.getLogger( TunerManager.class );
private ResourceManager mResourceManager;
private ArrayList<Tuner> mTuners = new ArrayList<Tuner>();
private MixerManager mMixerManager;
private TunerModel mTunerModel;
private ThreadPoolManager mThreadPoolManager;
public TunerManager( ResourceManager resourceManager )
public TunerManager( MixerManager mixerManager,
TunerModel tunerModel,
ThreadPoolManager threadPoolManager )
{
mResourceManager = resourceManager;
/* initialize mixers */
MixerManager.getInstance();
mMixerManager = mixerManager;
mTunerModel = tunerModel;
mThreadPoolManager = threadPoolManager;
initTuners();
}
@@ -74,57 +69,6 @@ public class TunerManager
LibUsb.exit( null );
}
/**
* Iterates current tuners to get a tuner channel source for the frequency
* specified in the channel config's source config object
*/
public Source getSource( SourceConfiguration config, int bandwidth )
{
TunerChannelSource retVal = null;
if( config instanceof SourceConfigTuner )
{
SourceConfigTuner tunerConfig = (SourceConfigTuner)config;
TunerChannel tunerChannel = tunerConfig.getTunerChannel();
tunerChannel.setBandwidth( bandwidth );
Iterator<Tuner> it = mTuners.iterator();
Tuner tuner;
while( it.hasNext() && retVal == null )
{
tuner = it.next();
try
{
retVal = tuner.getChannel( tunerChannel );
}
catch ( RejectedExecutionException ree )
{
mLog.error( "couldn't provide tuner channel source", ree );
}
catch ( SourceException e )
{
mLog.error( "error obtaining channel from tuner [" +
tuner.getName() + "]", e );
}
}
}
return retVal;
}
/**
* Get list of current tuners
*/
public List<Tuner> getTuners()
{
return mTuners;
}
/**
* Loads all USB tuners and USB/Mixer tuner devices
*/
@@ -182,9 +126,19 @@ public class TunerManager
if( status.isLoaded() )
{
Tuner tuner = status.getTuner();
sb.append( "] LOADED: " );
sb.append( tuner.toString() );
mTuners.add( tuner );
try
{
mTunerModel.addTuner( tuner );
sb.append( "] LOADED: " );
sb.append( tuner.toString() );
}
catch( Exception e )
{
sb.append( "] NOT LOADED: " );
sb.append( status.getInfo() );
sb.append( " Error:" + e.getMessage() );
}
}
else
{
@@ -261,19 +215,12 @@ public class TunerManager
try
{
AirspyTunerController airspyController =
new AirspyTunerController( device, mResourceManager.getThreadPoolManager() );
new AirspyTunerController( device, mThreadPoolManager );
airspyController.init();
AirspyTuner tuner = new AirspyTuner( airspyController );
TunerConfiguration config = getTunerConfiguration( tuner );
if( config != null )
{
tuner.apply( config );
}
return new TunerInitStatus( tuner, "LOADED" );
}
catch( SourceException se )
@@ -292,11 +239,6 @@ public class TunerManager
{
return new TunerInitStatus( null, "Ettus B100 tuner not currently "
+ "supported" );
// case ETTUS_USRP_B100:
// mTuners.add( new B100Tuner( device ) );
// status = sLOADED;
// reason = null;
// break;
}
private TunerInitStatus initFuncubeProTuner( Device device,
@@ -319,13 +261,6 @@ public class TunerManager
FCDTuner tuner =
new FCDTuner( dataline, controller );
TunerConfiguration config = getTunerConfiguration( tuner );
if( config != null )
{
tuner.apply( config );
}
return new TunerInitStatus( tuner, "LOADED" );
}
catch ( SourceException e )
@@ -364,13 +299,6 @@ public class TunerManager
FCDTuner tuner =
new FCDTuner( dataline, controller );
TunerConfiguration config = getTunerConfiguration( tuner );
if( config != null )
{
tuner.apply( config );
}
return new TunerInitStatus( tuner, "LOADED" );
}
catch ( SourceException e )
@@ -397,19 +325,12 @@ public class TunerManager
{
HackRFTunerController hackRFController =
new HackRFTunerController( device, descriptor,
mResourceManager.getThreadPoolManager() );
mThreadPoolManager );
hackRFController.init();
HackRFTuner tuner = new HackRFTuner( hackRFController );
TunerConfiguration config = getTunerConfiguration( tuner );
if( config != null )
{
tuner.apply( config );
}
return new TunerInitStatus( tuner, "LOADED" );
}
catch( SourceException se )
@@ -449,21 +370,13 @@ public class TunerManager
{
E4KTunerController controller =
new E4KTunerController( device, deviceDescriptor,
mResourceManager.getThreadPoolManager() );
mThreadPoolManager );
controller.init();
RTL2832Tuner rtlTuner =
new RTL2832Tuner( tunerClass, controller );
TunerConfiguration config =
getTunerConfiguration( rtlTuner );
if( config != null )
{
rtlTuner.apply( config );
}
return new TunerInitStatus( rtlTuner, "LOADED" );
}
catch( SourceException se )
@@ -476,21 +389,13 @@ public class TunerManager
{
R820TTunerController controller =
new R820TTunerController( device, deviceDescriptor,
mResourceManager.getThreadPoolManager() );
mThreadPoolManager );
controller.init();
RTL2832Tuner rtlTuner =
new RTL2832Tuner( tunerClass, controller );
TunerConfiguration config =
getTunerConfiguration( rtlTuner );
if( config != null )
{
rtlTuner.apply( config );
}
return new TunerInitStatus( rtlTuner, "LOADED" );
}
catch( SourceException se )
@@ -513,55 +418,6 @@ public class TunerManager
return new TunerInitStatus( null, reason );
}
/**
* Get a stored tuner configuration or create a default tuner configuration
* for the tuner type, connected at the address.
*
* Note: a named tuner configuration will be stored for for each tuner type
* and address combination.
* @param type - tuner type
* @param address - current usb address/port
* @return - stored tuner configuration or default configuration
*/
private TunerConfiguration getTunerConfiguration( Tuner tuner )
{
TunerConfigurationAssignment selected = mResourceManager
.getSettingsManager().getSelectedTunerConfiguration(
tuner.getTunerType(), tuner.getUniqueID() );
ArrayList<TunerConfiguration> configs = mResourceManager
.getSettingsManager().getTunerConfigurations( tuner.getTunerType() );
TunerConfiguration config = null;
if( selected != null )
{
for( TunerConfiguration tunerConfig: configs )
{
if( tunerConfig.getName().contentEquals( selected.getTunerConfigurationName() ) )
{
config = tunerConfig;
}
}
}
//If we're still null at this point, create a default config
if( config == null )
{
String name = "Default-" + tuner.getUniqueID();
config = mResourceManager.getSettingsManager()
.addNewTunerConfiguration( tuner.getTunerType(), name );
}
//Persist the config as the selected tuner configuration. The method
//auto-saves the setting
mResourceManager.getSettingsManager().setSelectedTunerConfiguration(
tuner.getTunerType(), tuner.getUniqueID(), config );
return config;
}
/**
* Gets the first tuner mixer dataline that corresponds to the tuner class.
@@ -577,7 +433,7 @@ public class TunerManager
private MixerTunerDataLine getMixerTunerDataLine( TunerType tunerClass )
{
Collection<MixerTunerDataLine> datalines =
MixerManager.getInstance().getMixerTunerDataLines();
mMixerManager.getMixerTunerDataLines();
for( MixerTunerDataLine mixerTDL: datalines )
{

View File

@@ -0,0 +1,297 @@
package source.tuner;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.table.AbstractTableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import source.Source;
import source.SourceException;
import source.config.SourceConfigTuner;
import source.tuner.TunerEvent.Event;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.configuration.TunerConfigurationModel;
public class TunerModel extends AbstractTableModel implements Listener<TunerEvent>
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( TunerModel.class );
public static final int TUNER_TYPE = 0;
public static final int TUNER_ID = 1;
public static final int SAMPLE_RATE = 2;
public static final int FREQUENCY = 3;
public static final int CHANNEL_COUNT = 4;
public static final int SPECTRAL_DISPLAY_MAIN = 5;
public static final int SPECTRAL_DISPLAY_NEW = 6;
private static final String MHZ = " MHz";
private static final String[] COLUMNS =
{ "Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Spectral", "Display" };
private List<Tuner> mTuners = new ArrayList<>();
private List<Listener<TunerEvent>> mTunerEventListeners = new ArrayList<>();
private DecimalFormat mFrequencyFormat = new DecimalFormat( "0.00000" );
private DecimalFormat mSampleRateFormat = new DecimalFormat( "0.000" );
private TunerConfigurationModel mTunerConfigurationModel;
public TunerModel( TunerConfigurationModel tunerConfigurationModel )
{
mTunerConfigurationModel = tunerConfigurationModel;
}
public TunerConfigurationModel getTunerConfigurationModel()
{
return mTunerConfigurationModel;
}
/**
* List of Tuners currently in the model
*/
public List<Tuner> getTuners()
{
return mTuners;
}
public Tuner getTuner( int index )
{
if( index < mTuners.size() )
{
return mTuners.get( index );
}
return null;
}
public void addTuners( List<Tuner> Tuners )
{
for( Tuner tuner: Tuners )
{
addTuner( tuner );
}
}
/**
* Adds the Tuner to this model
*/
public void addTuner( Tuner tuner )
{
if( !mTuners.contains( tuner ) )
{
//Get the tuner configuration and apply it to the tuner - this
//call should always produce a tuner configuration
TunerConfiguration config = mTunerConfigurationModel
.getTunerConfiguration( tuner.getTunerType(), tuner.getUniqueID() );
try
{
tuner.getTunerController().apply( config );
mTuners.add( tuner );
int index = mTuners.indexOf( tuner );
fireTableRowsInserted( index, index );
tuner.addTunerChangeListener( this );
}
catch( SourceException se )
{
mLog.error( "Couldn't apply tuner configuration to tuner - ["
+ tuner.getTunerType().name() + "] with id ["
+ tuner.getUniqueID() + "] - tuner will not be included" );
}
}
}
/**
* Removes the Tuner from this model
*/
public void removeTuner( Tuner tuner )
{
if( mTuners.contains( tuner ) )
{
tuner.removeTunerChangeListener( this );
int index = mTuners.indexOf( tuner );
mTuners.remove( tuner );
fireTableRowsDeleted( index, index );
}
}
public void addListener( Listener<TunerEvent> listener )
{
mTunerEventListeners.add( listener );
}
public void removeListener( Listener<TunerEvent> listener )
{
mTunerEventListeners.remove( listener );
}
public void broadcast( TunerEvent event )
{
for( Listener<TunerEvent> listener: mTunerEventListeners )
{
listener.receive( event );
}
}
/**
* Requests to display the first tuner in this model. Invoke this method
* after all listeners have registered and tuners have been added to this
* model, in order to inform the primary display to use the first tuner.
*/
public void requestFirstTunerDisplay()
{
if( mTuners.size() > 0 )
{
broadcast( new TunerEvent( mTuners.get( 0 ),
Event.REQUEST_MAIN_SPECTRAL_DISPLAY ) );
}
}
@Override
public void receive( TunerEvent event )
{
if( event.getTuner() != null )
{
int index = mTuners.indexOf( event.getTuner() );
if( index >= 0 )
{
switch( event.getEvent() )
{
case CHANNEL_COUNT:
fireTableCellUpdated( index, CHANNEL_COUNT );
break;
case FREQUENCY:
fireTableCellUpdated( index, FREQUENCY );
break;
case SAMPLE_RATE:
fireTableCellUpdated( index, SAMPLE_RATE );
break;
case REQUEST_MAIN_SPECTRAL_DISPLAY:
fireTableCellUpdated( index, SPECTRAL_DISPLAY_MAIN );
default:
break;
}
}
}
broadcast( event );
}
@Override
public int getRowCount()
{
return mTuners.size();
}
@Override
public int getColumnCount()
{
return COLUMNS.length;
}
@Override
public Object getValueAt( int rowIndex, int columnIndex )
{
if( rowIndex < mTuners.size() )
{
Tuner tuner = mTuners.get( rowIndex );
switch( columnIndex )
{
case TUNER_TYPE:
return tuner.getTunerType().getLabel();
case TUNER_ID:
return tuner.getUniqueID();
case SAMPLE_RATE:
int sampleRate = tuner.getTunerController().getSampleRate();
return mSampleRateFormat.format( sampleRate / 1E6D ) + MHZ;
case FREQUENCY:
try
{
long frequency = tuner.getTunerController().getFrequency();
return mFrequencyFormat.format( frequency / 1E6D ) + MHZ;
}
catch( Exception e )
{
return 0;
}
case CHANNEL_COUNT:
return tuner.getTunerController().getChannelCount();
case SPECTRAL_DISPLAY_MAIN:
return "Main";
case SPECTRAL_DISPLAY_NEW:
return "New";
default:
break;
}
}
return null;
}
@Override
public String getColumnName( int columnIndex )
{
return COLUMNS[ columnIndex ];
}
/**
* Iterates current tuners to get a tuner channel source for the frequency
* specified in the channel config's source config object.
*
* Returns null if no tuner can source the channel
*/
public Source getSource( SourceConfigTuner config, int bandwidth )
{
TunerChannelSource retVal = null;
TunerChannel tunerChannel = config.getTunerChannel();
tunerChannel.setBandwidth( bandwidth );
Iterator<Tuner> it = mTuners.iterator();
Tuner tuner;
while( it.hasNext() && retVal == null )
{
tuner = it.next();
try
{
retVal = tuner.getChannel( tunerChannel );
}
catch ( RejectedExecutionException ree )
{
mLog.error( "couldn't provide tuner channel source", ree );
}
catch ( SourceException e )
{
mLog.error( "error obtaining channel from tuner [" +
tuner.getName() + "]", e );
}
}
return retVal;
}
}

View File

@@ -1,156 +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 java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeListener;
import spectrum.SpectrumFrame;
import controller.BaseNode;
import controller.ResourceManager;
public class TunerNode extends BaseNode implements FrequencyChangeListener
{
private final static Logger mLog =
LoggerFactory.getLogger( TunerNode.class );
private static final long serialVersionUID = 1L;
private static DecimalFormat FREQUENCY_FORMAT = new DecimalFormat( "0.00000" );
private static DecimalFormat SAMPLE_RATE_FORMAT = new DecimalFormat( "0.000" );
private long mFrequency;
private int mSampleRate;
public TunerNode( Tuner tuner )
{
super( tuner ); //does this make it a super tuner?
tuner.addListener( this );
try
{
mFrequency = tuner.getFrequency();
mSampleRate = tuner.getSampleRate();
}
catch ( SourceException e )
{
mLog.error( "TunerNode - error reading frequency and sample rate "
+ "from tuner", e );
}
}
@Override
public JPanel getEditor()
{
return getTuner().getEditor( getModel().getResourceManager() );
}
public Tuner getTuner()
{
return (Tuner)getUserObject();
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append( getTuner().getName() );
sb.append( " " );
sb.append( FREQUENCY_FORMAT.format( (double)mFrequency / 1E6d ) );
sb.append( " [" );
sb.append( SAMPLE_RATE_FORMAT.format( (double)mSampleRate / 1E6d ) );
sb.append( "] MHz" );
return sb.toString();
}
public JPopupMenu getContextMenu()
{
JPopupMenu retVal = new JPopupMenu();
JMenuItem showSpectrumItem = new JMenuItem( "Show in Main Spectrum" );
showSpectrumItem.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
getModel().fireTunerSelectedEvent( getTuner() );
}
} );
retVal.add( showSpectrumItem );
JMenuItem newSpectrumItem = new JMenuItem( "New Spectrum Window" );
newSpectrumItem.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
ResourceManager rm = getModel().getResourceManager();
SpectrumFrame frame = new SpectrumFrame( rm.getChannelManager(),
rm.getController(), rm.getPlaylistManager(),
rm.getSettingsManager(), getTuner() );
}
} );
retVal.add( newSpectrumItem );
return retVal;
}
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
switch( event.getEvent() )
{
case FREQUENCY_CHANGE_NOTIFICATION:
long frequency = event.getValue().longValue();
if( mFrequency != frequency )
{
mFrequency = frequency;
getModel().nodeChanged( TunerNode.this );
}
break;
case SAMPLE_RATE_CHANGE_NOTIFICATION:
int sampleRate = event.getValue().intValue();
if( mSampleRate != sampleRate )
{
mSampleRate = sampleRate;
getModel().nodeChanged( TunerNode.this );
}
break;
default:
break;
}
}
}

View File

@@ -1,23 +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;
public interface TunerSelectionListener
{
public void tunerSelected( Tuner tuner );
}

View File

@@ -0,0 +1,95 @@
/*******************************************************************************
* 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 gui.control.JFrequencyControl;
import gui.editor.Editor;
import net.miginfocom.swing.MigLayout;
import source.config.SourceConfigTuner;
import source.config.SourceConfiguration;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.IFrequencyChangeProcessor;
import controller.channel.Channel;
public class TunerSourceEditor extends Editor<Channel>
{
private static final long serialVersionUID = 1L;
private JFrequencyControl mFrequencyControl;
public TunerSourceEditor()
{
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0", "[left]", "" ) );
mFrequencyControl = new JFrequencyControl();
mFrequencyControl.setEnabled( false );
mFrequencyControl.addListener( new IFrequencyChangeProcessor()
{
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
setModified( true );
}
} );
add( mFrequencyControl );
}
public void save()
{
if( hasItem() && isModified() )
{
SourceConfigTuner config = new SourceConfigTuner();
config.setFrequency( mFrequencyControl.getFrequency() );
getItem().setSourceConfiguration( config );
}
setModified( false );
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
SourceConfiguration config = getItem().getSourceConfiguration();
mFrequencyControl.setEnabled( true );
if( config instanceof SourceConfigTuner )
{
mFrequencyControl.setFrequency( ((SourceConfigTuner)config).getFrequency(), false );
setModified( false );
}
else
{
mFrequencyControl.setFrequency( 101000000, false );
setModified( true );
}
}
else
{
mFrequencyControl.setEnabled( false );
setModified( false );
}
}
}

View File

@@ -0,0 +1,55 @@
package source.tuner;
import java.awt.EventQueue;
import sample.Listener;
import settings.SettingsManager;
import spectrum.SpectralDisplayPanel;
import spectrum.SpectrumFrame;
import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
public class TunerSpectralDisplayManager implements Listener<TunerEvent>
{
private SpectralDisplayPanel mSpectralDisplayPanel;
private ChannelModel mChannelModel;
private ChannelProcessingManager mChannelProcessingManager;
private SettingsManager mSettingsManager;
public TunerSpectralDisplayManager( SpectralDisplayPanel panel,
ChannelModel channelModel,
ChannelProcessingManager channelProcessingManager,
SettingsManager settingsManager )
{
mSpectralDisplayPanel = panel;
mChannelModel = channelModel;
mChannelProcessingManager = channelProcessingManager;
mSettingsManager = settingsManager;
}
@Override
public void receive( TunerEvent event )
{
switch( event.getEvent() )
{
case REQUEST_MAIN_SPECTRAL_DISPLAY:
mSpectralDisplayPanel.showTuner( event.getTuner() );
break;
case REQUEST_NEW_SPECTRAL_DISPLAY:
final SpectrumFrame frame = new SpectrumFrame( mChannelModel,
mChannelProcessingManager, mSettingsManager, event.getTuner() );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
frame.setVisible( true );
}
} );
break;
default:
break;
}
}
}

View File

@@ -19,7 +19,7 @@ package source.tuner;
public enum TunerType
{
AIRSPY_R820T( "R820T" ),
AIRSPY_R820T( "Airspy R820T" ),
ELONICS_E4000( "E4000" ),
ETTUS_WBX( "WBX" ),
ETTUS_VARIOUS( "Ettus Tuner" ),

View File

@@ -0,0 +1,178 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableRowSorter;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.tuner.TunerEvent.Event;
import com.jidesoft.swing.JideSplitPane;
public class TunerViewPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( TunerViewPanel.class );
private TunerModel mTunerModel;
private JTable mTunerTable;
private TableRowSorter<TunerModel> mRowSorter;
private JideSplitPane mSplitPane;
private TunerEditor mTunerEditor;
public TunerViewPanel( TunerModel tunerModel )
{
mTunerModel = tunerModel;
mTunerEditor = new TunerEditor( mTunerModel.getTunerConfigurationModel() );
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0", "[fill,grow]", "[fill,grow]" ) );
mRowSorter = new TableRowSorter<>( mTunerModel );
List<RowSorter.SortKey> sortKeys = new ArrayList<>();
sortKeys.add( new RowSorter.SortKey( TunerModel.TUNER_TYPE, SortOrder.ASCENDING ) );
sortKeys.add( new RowSorter.SortKey( TunerModel.TUNER_ID, SortOrder.ASCENDING ) );
mRowSorter.setSortKeys( sortKeys );
mTunerTable = new JTable( mTunerModel );
mTunerTable.setRowSorter( mRowSorter );
mTunerTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
mTunerTable.getSelectionModel().addListSelectionListener( new ListSelectionListener()
{
@Override
public void valueChanged( ListSelectionEvent event )
{
if( !event.getValueIsAdjusting() )
{
int row = mTunerTable.getSelectedRow();
int modelRow = mTunerTable.convertRowIndexToModel( row );
mTunerEditor.setItem( mTunerModel.getTuner( modelRow ) );
}
}
} );
mTunerTable.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
int column = mTunerTable.columnAtPoint( e.getPoint() );
if( column == TunerModel.SPECTRAL_DISPLAY_MAIN )
{
int tableRow = mTunerTable.rowAtPoint( e.getPoint() );
int modelRow = mTunerTable.convertRowIndexToModel( tableRow );
Tuner tuner = mTunerModel.getTuner( modelRow );
if( tuner != null )
{
mTunerModel.broadcast( new TunerEvent( tuner,
Event.REQUEST_MAIN_SPECTRAL_DISPLAY ) );
}
}
else if( column == TunerModel.SPECTRAL_DISPLAY_NEW )
{
int tableRow = mTunerTable.rowAtPoint( e.getPoint() );
int modelRow = mTunerTable.convertRowIndexToModel( tableRow );
Tuner tuner = mTunerModel.getTuner( modelRow );
if( tuner != null )
{
mTunerModel.broadcast( new TunerEvent( tuner,
Event.REQUEST_NEW_SPECTRAL_DISPLAY ) );
}
}
}
} );
TableCellRenderer renderer = new LinkCellRenderer();
mTunerTable.getColumnModel().getColumn( 5 ).setCellRenderer( renderer );
mTunerTable.getColumnModel().getColumn( 6 ).setCellRenderer( renderer );
JScrollPane listScroller = new JScrollPane( mTunerTable );
listScroller.setPreferredSize( new Dimension( 400, 20 ) );
JScrollPane editorScroller = new JScrollPane( mTunerEditor );
editorScroller.setPreferredSize( new Dimension( 400, 80 ) );
mSplitPane = new JideSplitPane();
mSplitPane.setOrientation( JideSplitPane.VERTICAL_SPLIT );
mSplitPane.add( listScroller );
mSplitPane.add( editorScroller );
add( mSplitPane );
}
public class LinkCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent( JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column )
{
JLabel label = (JLabel)super.getTableCellRendererComponent( table,
value, isSelected, hasFocus, row, column );
label.setForeground( Color.BLUE.brighter() );
if( column == TunerModel.SPECTRAL_DISPLAY_MAIN )
{
label.setToolTipText( "Show this tuner in the main spectral display" );
}
else if( column == TunerModel.SPECTRAL_DISPLAY_NEW )
{
label.setToolTipText( "Show this tuner in a new spectral display" );
}
return label;
}
}
}

View File

@@ -1,77 +0,0 @@
package source.tuner.airspy;
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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/>
******************************************************************************/
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class AirspyInformationPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private AirspyTunerController mController;
/**
* Displays Airspy firmware, serial number and part identifier
*/
public AirspyInformationPanel( AirspyTunerController controller )
{
mController = controller;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2",
"[right,grow][grow]",
"[][][][][grow]" ) );
AirspyDeviceInformation info = mController.getDeviceInfo();
add( new JLabel( "Serial:" ) );
add( new JLabel( info.getSerialNumber() ) );
add( new JLabel( "Firmware:" ) );
//Split the firmware on spaces and use first value -- expose full
//string in a tool tip
String[] firmware = info.getVersion().split( " " );
JLabel firmwareLabel;
if( firmware.length > 1 )
{
firmwareLabel = new JLabel( firmware[ 0 ] );
}
else
{
firmwareLabel = new JLabel( info.getVersion() );
}
firmwareLabel.setToolTipText( info.getVersion() );
add( firmwareLabel );
add( new JLabel( "Part:" ) );
add( new JLabel( info.getPartNumber() ) );
add( new JLabel( "Board ID:" ) );
add( new JLabel( info.getBoardID().getLabel() ) );
}
}

View File

@@ -18,15 +18,10 @@ package source.tuner.airspy;
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.adapter.ISampleAdapter;
public class AirspySampleAdapter implements ISampleAdapter
{
private final static Logger mLog = LoggerFactory.getLogger( AirspySampleAdapter.class );
private static final float SCALE_SIGNED_12_BIT_TO_FLOAT = 1.0f / 2048.0f;
private boolean mSamplePacking = false;

View File

@@ -19,8 +19,6 @@ package source.tuner.airspy;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.JPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,44 +29,22 @@ import source.tuner.Tuner;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelSource;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerEvent;
import source.tuner.TunerType;
import source.tuner.airspy.AirspyTunerController.BoardID;
import controller.ResourceManager;
import controller.ThreadPoolManager;
public class AirspyTuner extends Tuner
{
private final static Logger mLog = LoggerFactory.getLogger( AirspyTuner.class );
AirspyTunerController mController;
public AirspyTuner( AirspyTunerController controller )
{
super( "Airspy" );
mController = controller;
/* Register for frequency/sample rate changes so that we can rebroadcast
* to any registered listeners */
mController.addListener( this );
}
@Override
public JPanel getEditor( ResourceManager resourceManager )
{
return new AirspyTunerEditorPanel( this, resourceManager );
super( "Airspy " + controller.getDeviceInfo().getSerialNumber(), controller );
}
public AirspyTunerController getController()
{
return mController;
}
@Override
public void apply( TunerConfiguration config ) throws SourceException
{
mController.apply( config );
return (AirspyTunerController)getTunerController();
}
@Override
@@ -76,11 +52,11 @@ public class AirspyTuner extends Tuner
{
try
{
return mController.getDeviceInfo().getSerialNumber();
return getController().getDeviceInfo().getSerialNumber();
}
catch( Exception e )
{
mLog.error( "error gettting serial number", e );
mLog.error( "error getting serial number", e );
}
return BoardID.AIRSPY.getLabel();
@@ -98,35 +74,12 @@ public class AirspyTuner extends Tuner
return TunerType.AIRSPY_R820T;
}
@Override
public int getSampleRate()
{
int rate = 0;
try
{
rate = mController.getCurrentSampleRate();
}
catch ( SourceException e )
{
mLog.error( "Error while getting sample rate from controller", e );
}
return rate;
}
@Override
public double getSampleSize()
{
return 13.0;
}
@Override
public long getFrequency() throws SourceException
{
return mController.getFrequency();
}
@Override
public TunerChannelSource getChannel( TunerChannel channel )
throws RejectedExecutionException, SourceException
@@ -138,9 +91,16 @@ public class AirspyTuner extends Tuner
//Consider implementing a fractional resampler to get a correct 48 kHz
//output sample rate
return mController.getChannel( this, channel );
}
TunerChannelSource source = getController().getChannel( this, channel );
if( source != null )
{
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
}
return source;
}
@Override
public void releaseChannel( TunerChannelSource source )
{
@@ -150,19 +110,19 @@ public class AirspyTuner extends Tuner
/* Tell the controller to release the channel and cleanup */
if( source != null )
{
mController.releaseChannel( source );
getController().releaseChannel( source );
}
}
@Override
public void addListener( Listener<ComplexBuffer> listener )
{
mController.addListener( listener );
getController().addListener( listener );
}
@Override
public void removeListener( Listener<ComplexBuffer> listener )
{
mController.removeListener( listener );
getController().removeListener( listener );
}
}

View File

@@ -19,9 +19,9 @@ package source.tuner.airspy;
import javax.xml.bind.annotation.XmlAttribute;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.airspy.AirspyTunerController.Gain;
import source.tuner.configuration.TunerConfiguration;
public class AirspyTunerConfiguration extends TunerConfiguration
{
@@ -30,6 +30,7 @@ public class AirspyTunerConfiguration extends TunerConfiguration
private int mIFGain = AirspyTunerController.IF_GAIN_DEFAULT;
private int mMixerGain = AirspyTunerController.MIXER_GAIN_DEFAULT;
private int mLNAGain = AirspyTunerController.LNA_GAIN_DEFAULT;
private double mFrequencyCorrection = 0.0d;
private boolean mMixerAGC = false;
private boolean mLNAAGC = false;
@@ -39,12 +40,11 @@ public class AirspyTunerConfiguration extends TunerConfiguration
*/
public AirspyTunerConfiguration()
{
this( "Default" );
}
public AirspyTunerConfiguration( String name )
public AirspyTunerConfiguration( String uniqueID, String name )
{
super( name );
super( uniqueID, name );
}
@Override
@@ -129,4 +129,16 @@ public class AirspyTunerConfiguration extends TunerConfiguration
{
mLNAAGC = enabled;
}
@XmlAttribute( name = "frequency_correction" )
public double getFrequencyCorrection()
{
return mFrequencyCorrection;
}
public void setFrequencyCorrection( double value )
{
mFrequencyCorrection = value;
}
}

View File

@@ -1,705 +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.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 source.tuner.airspy.AirspyTunerController.Gain;
import source.tuner.airspy.AirspyTunerController.GainMode;
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<AirspyTunerConfiguration> mComboConfigurations;
private JTextField mName;
private JComboBox<AirspySampleRate> mSampleRateCombo;
private JComboBox<GainMode> 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;
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<AirspyTunerConfiguration>();
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<AirspySampleRate> rates = mController.getSampleRates();
mSampleRateCombo = new JComboBox<AirspySampleRate>(
new DefaultComboBoxModel<AirspySampleRate>( 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();
}
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" );
add( new JSeparator(), "span,growx,push" );
/**
* Gain Mode
*/
add( new JLabel( "Gain Mode:" ) );
mGainModeCombo = new JComboBox<AirspyTunerController.GainMode>( 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
*/
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,
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();
mIFGainValueLabel.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" );
/**
* Mixer Gain
*/
mMixerGainLabel = new JLabel( "Mixer Gain" );
add( mMixerGainLabel );
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" );
mMixerGainValueLabel = new JLabel( String.valueOf( mSelectedConfig.getMixerGain() ) );
add( mMixerGainValueLabel, "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();
mMixerGainValueLabel.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" );
/**
* LNA Gain
*/
mLNAGainLabel = new JLabel( "LNA Gain" );
add( mLNAGainLabel );
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" );
mLNAGainValueLabel = new JLabel( String.valueOf( mSelectedConfig.getLNAGain() ) );
add( mLNAGainValueLabel, "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();
mLNAGainValueLabel.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" );
//Set the enabled state of each of the gain controls
updateGainComponents( (GainMode)mGainModeCombo.getSelectedItem() );
/**
* 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 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
* @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 );
}
mIFGain.setValue( mSelectedConfig.getIFGain() );
mMixerGain.setValue( mSelectedConfig.getMixerGain() );
mLNAGain.setValue( mSelectedConfig.getLNAGain() );
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 );
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<AirspyTunerConfiguration> getModel()
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.AIRSPY_R820T );
DefaultComboBoxModel<AirspyTunerConfiguration> model =
new DefaultComboBoxModel<AirspyTunerConfiguration>();
for( TunerConfiguration config: configs )
{
model.addElement( (AirspyTunerConfiguration)config );
}
return model;
}
/**
* Retrieves a specific (named) tuner configuration
*/
private AirspyTunerConfiguration getNamedConfiguration( String name )
{
ArrayList<TunerConfiguration> 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();
}
}

View File

@@ -6,7 +6,6 @@ import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -28,8 +27,8 @@ import sample.Broadcaster;
import sample.Listener;
import sample.complex.ComplexBuffer;
import source.SourceException;
import source.tuner.TunerConfiguration;
import source.tuner.TunerController;
import source.tuner.configuration.TunerConfiguration;
import controller.ThreadPoolManager;
import controller.ThreadPoolManager.ThreadType;
import dsp.filter.dc.DCRemovalFilter_RB;
@@ -262,30 +261,31 @@ public class AirspyTunerController extends TunerController
}
}
public static String getTransferStatus( int status )
{
switch( status )
{
case 0:
return "TRANSFER COMPLETED (0)";
case 1:
return "TRANSFER ERROR (1)";
case 2:
return "TRANSFER TIMED OUT (2)";
case 3:
return "TRANSFER CANCELLED (3)";
case 4:
return "TRANSFER STALL (4)";
case 5:
return "TRANSFER NO DEVICE (5)";
case 6:
return "TRANSFER OVERFLOW (6)";
default:
return "UNKNOWN TRANSFER STATUS (" + status + ")";
}
}
public static String getTransferStatus( int status )
{
switch( status )
{
case 0:
return "TRANSFER COMPLETED (0)";
case 1:
return "TRANSFER ERROR (1)";
case 2:
return "TRANSFER TIMED OUT (2)";
case 3:
return "TRANSFER CANCELLED (3)";
case 4:
return "TRANSFER STALL (4)";
case 5:
return "TRANSFER NO DEVICE (5)";
case 6:
return "TRANSFER OVERFLOW (6)";
default:
return "UNKNOWN TRANSFER STATUS (" + status + ")";
}
}
@Override
@Override
public void apply( TunerConfiguration config ) throws SourceException
{
if( config instanceof AirspyTunerConfiguration )
@@ -426,7 +426,7 @@ public class AirspyTunerController extends TunerController
/**
* Airspy sample rate object that matches the current sample rate setting.
*/
public AirspySampleRate getSampleRate()
public AirspySampleRate getAirspySampleRate()
{
return getSampleRate( mSampleRate );
}
@@ -1215,8 +1215,8 @@ public class AirspyTunerController extends TunerController
*/
public void addListener( Listener<ComplexBuffer> listener )
{
synchronized( mComplexBufferBroadcaster )
{
synchronized ( mComplexBufferBroadcaster )
{
mComplexBufferBroadcaster.addListener( listener );
if( mBufferProcessor == null || !mBufferProcessor.isRunning() )
@@ -1229,7 +1229,7 @@ public class AirspyTunerController extends TunerController
thread.start();
}
}
}
}
/**
@@ -1238,15 +1238,15 @@ public class AirspyTunerController extends TunerController
*/
public void removeListener( Listener<ComplexBuffer> listener )
{
synchronized( mComplexBufferBroadcaster )
{
synchronized ( mComplexBufferBroadcaster )
{
mComplexBufferBroadcaster.removeListener( listener );
if( !mComplexBufferBroadcaster.hasListeners() )
{
mBufferProcessor.stop();
}
}
}
}
/**
@@ -1273,31 +1273,31 @@ public class AirspyTunerController extends TunerController
ThreadType.SOURCE_SAMPLE_PROCESSING, new BufferDispatcher(),
20, TimeUnit.MILLISECONDS );
mLibUsbHandlerStatus = ByteBuffer.allocateDirect( 4 );
mLibUsbHandlerStatus = ByteBuffer.allocateDirect( 4 );
List<Transfer> transfers = new ArrayList<>();
mCancel = false;
while( mRunning.get() )
while( mRunning.get() )
{
mAvailableTransfers.drainTo( transfers );
for( Transfer transfer: transfers )
{
int result = LibUsb.submitTransfer( transfer );
if( result == LibUsb.SUCCESS )
{
mTransfersInProgress.add( transfer );
}
mAvailableTransfers.drainTo( transfers );
for( Transfer transfer: transfers )
{
int result = LibUsb.submitTransfer( transfer );
if( result == LibUsb.SUCCESS )
{
mTransfersInProgress.add( transfer );
}
else
{
mLog.error( "error submitting transfer [" +
LibUsb.errorName( result ) + "]" );
}
}
mLog.error( "error submitting transfer [" +
LibUsb.errorName( result ) + "]" );
}
}
int result = LibUsb.handleEventsTimeoutCompleted(
null, USB_TIMEOUT_MS, mLibUsbHandlerStatus.asIntBuffer() );
@@ -1310,20 +1310,20 @@ public class AirspyTunerController extends TunerController
mLibUsbHandlerStatus.rewind();
}
if( mCancel )
{
for( Transfer transfer: mTransfersInProgress )
{
LibUsb.cancelTransfer( transfer );
}
int result = LibUsb.handleEventsTimeoutCompleted( null,
USB_TIMEOUT_MS, mLibUsbHandlerStatus.asIntBuffer() );
if( mCancel )
{
for( Transfer transfer: mTransfersInProgress )
{
LibUsb.cancelTransfer( transfer );
}
int result = LibUsb.handleEventsTimeoutCompleted( null,
USB_TIMEOUT_MS, mLibUsbHandlerStatus.asIntBuffer() );
if( result != LibUsb.SUCCESS )
{
mLog.error( "error handling events for libusb" );
mLog.error( "error handling events for libusb during cancel" );
}
mLibUsbHandlerStatus.rewind();

View File

@@ -0,0 +1,770 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner.airspy;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import java.util.List;
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.JSeparator;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
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.airspy.AirspyTunerController.Gain;
import source.tuner.airspy.AirspyTunerController.GainMode;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.configuration.TunerConfigurationEditor;
import source.tuner.configuration.TunerConfigurationEvent;
import source.tuner.configuration.TunerConfigurationModel;
import source.tuner.configuration.TunerConfigurationEvent.Event;
public class AirspyTunerEditor extends TunerConfigurationEditor
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( AirspyTunerEditor.class );
private JTextField mConfigurationName;
private JButton mTunerInfo;
private JComboBox<AirspySampleRate> mSampleRateCombo;
private JSpinner mFrequencyCorrection;
private JComboBox<GainMode> mGainModeCombo;
private JSlider mMasterGain;
private JLabel mMasterGainValueLabel;
private JSlider mIFGain;
private JLabel mIFGainValueLabel;
private JSlider mLNAGain;
private JLabel mLNAGainValueLabel;
private JSlider mMixerGain;
private JLabel mMixerGainValueLabel;
private JCheckBox mLNAAGC;
private JCheckBox mMixerAGC;
private AirspyTunerController mController;
private boolean mLoading;
public AirspyTunerEditor( TunerConfigurationModel tunerConfigurationModel,
AirspyTuner tuner )
{
super( tunerConfigurationModel );
mController = tuner.getController();
init();
}
private AirspyTunerConfiguration getConfiguration()
{
if( hasItem() )
{
return (AirspyTunerConfiguration)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
"[][][][][][grow]" ) );
add( new JLabel( "Airspy Tuner Configuration" ), "span,align center" );
mConfigurationName = new JTextField();
mConfigurationName.setEnabled( false );
mConfigurationName.addFocusListener( new FocusListener()
{
@Override
public void focusLost( FocusEvent e )
{
save();
}
@Override
public void focusGained( FocusEvent e ) {}
} );
add( new JLabel( "Name:" ) );
add( mConfigurationName, "span 2" );
mTunerInfo = new JButton( "Tuner Info" );
mTunerInfo.setEnabled( false );
mTunerInfo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
JOptionPane.showMessageDialog( AirspyTunerEditor.this, getTunerInfo(),
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( mTunerInfo );
/**
* Sample Rate
*/
add( new JLabel( "Sample Rate:" ) );
List<AirspySampleRate> rates = mController.getSampleRates();
mSampleRateCombo = new JComboBox<AirspySampleRate>(
new DefaultComboBoxModel<AirspySampleRate>( rates.toArray(
new AirspySampleRate[ rates.size() ] ) ) );
mSampleRateCombo.setEnabled( false );
mSampleRateCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
AirspySampleRate rate = (AirspySampleRate)mSampleRateCombo.getSelectedItem();
try
{
mController.setSampleRate( rate );
save();
}
catch ( LibUsbException | UsbException e1 )
{
JOptionPane.showMessageDialog( AirspyTunerEditor.this,
"Couldn't set sample rate to " + rate.getLabel() );
mLog.error( "Error setting airspy sample rate", e1 );
}
}
} );
add( mSampleRateCombo );
/**
* Frequency Correction
*/
SpinnerModel model =
new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
mFrequencyCorrection.setEnabled( false );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
final double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
try
{
mController.setFrequencyCorrection( value );
}
catch ( SourceException e1 )
{
mLog.error( "Error setting frequency correction value", e1 );
}
save();
}
} );
add( new JLabel( "PPM:" ) );
add( mFrequencyCorrection );
add( new JSeparator(), "span,growx,push" );
/**
* Gain Mode
*/
add( new JLabel( "Gain Mode:" ) );
mGainModeCombo = new JComboBox<AirspyTunerController.GainMode>( GainMode.values() );
mGainModeCombo.setEnabled( false );
mGainModeCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
GainMode mode = (GainMode)mGainModeCombo.getSelectedItem();
updateGainComponents( mode );
if( hasItem() )
{
AirspyTunerConfiguration airspy = getConfiguration();
Gain gain = airspy.getGain();
if( mode == GainMode.CUSTOM )
{
mIFGain.setValue( airspy.getIFGain() );
mMixerGain.setValue( airspy.getMixerGain() );
mMixerAGC.setSelected( airspy.isMixerAGC() );
mLNAGain.setValue( airspy.getLNAGain() );
mLNAAGC.setSelected( airspy.isLNAAGC() );
}
else
{
mMixerAGC.setSelected( false );
mLNAAGC.setSelected( false );
mMasterGain.setValue( gain.getValue() );
mIFGain.setValue( gain.getIF() );
mMixerGain.setValue( gain.getMixer() );
mLNAGain.setValue( gain.getLNA() );
}
}
save();
}
} );
add( mGainModeCombo, "wrap" );
/**
* Gain
*/
add( new JLabel( "Master:" ) );
mMasterGain = new JSlider( JSlider.HORIZONTAL,
AirspyTunerController.GAIN_MIN,
AirspyTunerController.GAIN_MAX,
AirspyTunerController.GAIN_MIN );
mMasterGain.setMajorTickSpacing( 1 );
mMasterGain.setPaintTicks( true );
mMasterGain.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent event )
{
GainMode mode = (GainMode)mGainModeCombo.getSelectedItem();
int value = mMasterGain.getValue();
Gain gain = Gain.getGain( mode, value );
try
{
mController.setGain( gain );
save();
mMasterGainValueLabel.setText( String.valueOf( gain.getValue() ) );
}
catch ( Exception e )
{
mLog.error( "Couldn't set airspy gain to:" + gain.name(), e );
JOptionPane.showMessageDialog( mMasterGain, "Couldn't set gain value to " +
gain.getValue() );
}
}
} );
add( mMasterGain, "span 2" );
mMasterGainValueLabel = new JLabel( "0" );
add( mMasterGainValueLabel );
add( new JLabel( "IF:" ) );
mIFGain = new JSlider( JSlider.HORIZONTAL,
AirspyTunerController.IF_GAIN_MIN,
AirspyTunerController.IF_GAIN_MAX,
AirspyTunerController.IF_GAIN_MIN );
mIFGain.setMajorTickSpacing( 1 );
mIFGain.setPaintTicks( true );
mIFGain.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent event )
{
int gain = mIFGain.getValue();
try
{
mController.setIFGain( gain );
save();
mIFGainValueLabel.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 );
}
}
} );
add( mIFGain, "span 2" );
mIFGainValueLabel = new JLabel( "0" );
add( mIFGainValueLabel );
/**
* Mixer Gain
*/
add( new JLabel( "Mixer:" ) );
mMixerGain = new JSlider( JSlider.HORIZONTAL,
AirspyTunerController.MIXER_GAIN_MIN,
AirspyTunerController.MIXER_GAIN_MAX,
AirspyTunerController.MIXER_GAIN_MIN );
mMixerGain.setMajorTickSpacing( 1 );
mMixerGain.setPaintTicks( true );
mMixerGain.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent event )
{
int gain = mMixerGain.getValue();
try
{
mController.setMixerGain( gain );
save();
mMixerGainValueLabel.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 );
}
}
} );
add( mMixerGain, "span 2" );
mMixerGainValueLabel = new JLabel( "0" );
add( mMixerGainValueLabel );
add( new JLabel( "LNA:" ) );
mLNAGain = new JSlider( JSlider.HORIZONTAL,
AirspyTunerController.LNA_GAIN_MIN,
AirspyTunerController.LNA_GAIN_MAX,
AirspyTunerController.LNA_GAIN_MIN );
mLNAGain.setMajorTickSpacing( 1 );
mLNAGain.setPaintTicks( true );
mLNAGain.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent event )
{
int gain = mLNAGain.getValue();
try
{
mController.setLNAGain( gain );
save();
mLNAGainValueLabel.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 );
}
}
} );
add( mLNAGain, "span 2" );
mLNAGainValueLabel = new JLabel( "0" );
add( mLNAGainValueLabel );
mMixerAGC = new JCheckBox( "Mixer AGC" );
mMixerAGC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
try
{
mController.setMixerAGC( mMixerAGC.isSelected() );
mMixerGain.setEnabled( !mMixerAGC.isSelected() );
save();
}
catch ( Exception e1 )
{
mLog.error( "Error setting Mixer AGC Enabled" );
}
}
} );
add( mMixerAGC, "span 2,center" );
mLNAAGC = new JCheckBox( "LNA AGC" );
mLNAAGC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
try
{
mController.setLNAAGC( mLNAAGC.isSelected() );
mLNAGain.setEnabled( !mLNAAGC.isSelected() );
save();
}
catch ( Exception e1 )
{
mLog.error( "Error setting LNA AGC Enabled" );
}
}
} );
add( mLNAAGC, "span 2,center" );
}
/**
* Updates the enabled state of each of the gain controls according to the
* specified gain mode. The master gain control is enabled for linearity
* and sensitivity and the individual gain controls are disabled, and
* vice-versa for custom mode.
*/
private void updateGainComponents( GainMode mode )
{
switch( mode )
{
case LINEARITY:
if( !mMasterGain.isEnabled() )
{
mMasterGain.setEnabled( true );
mMasterGainValueLabel.setEnabled( true );
}
if( mIFGain.isEnabled() )
{
mIFGain.setEnabled( false );
mIFGainValueLabel.setEnabled( false );
}
if( mLNAGain.isEnabled() )
{
mLNAAGC.setEnabled( false );
mLNAGainValueLabel.setEnabled( false );
mLNAGain.setEnabled( false );
}
if( mMixerGain.isEnabled() )
{
mMixerGainValueLabel.setEnabled( false );
mMixerAGC.setEnabled( false );
mMixerGain.setEnabled( false );
}
break;
case SENSITIVITY:
if( !mMasterGain.isEnabled() )
{
mMasterGain.setEnabled( true );
mMasterGainValueLabel.setEnabled( true );
}
if( mIFGain.isEnabled() )
{
mIFGain.setEnabled( false );
mIFGainValueLabel.setEnabled( false );
}
if( mLNAGain.isEnabled() )
{
mLNAAGC.setEnabled( false );
mLNAGainValueLabel.setEnabled( false );
mLNAGain.setEnabled( false );
}
if( mMixerGain.isEnabled() )
{
mMixerGainValueLabel.setEnabled( false );
mMixerAGC.setEnabled( false );
mMixerGain.setEnabled( false );
}
break;
case CUSTOM:
if( mMasterGain.isEnabled() )
{
mMasterGain.setEnabled( false );
mMasterGainValueLabel.setEnabled( false );
}
if( !mIFGain.isEnabled() )
{
mIFGain.setEnabled( true );
mIFGainValueLabel.setEnabled( true );
}
if( !mLNAGain.isEnabled() )
{
mLNAAGC.setEnabled( true );
mLNAGainValueLabel.setEnabled( true );
mLNAGain.setEnabled( true );
}
if( !mMixerGain.isEnabled() )
{
mMixerGainValueLabel.setEnabled( true );
mMixerAGC.setEnabled( true );
mMixerGain.setEnabled( true );
}
default:
break;
}
}
@Override
public void save()
{
if( hasItem() && !mLoading )
{
AirspyTunerConfiguration config = getConfiguration();
config.setName( mConfigurationName.getText() );
config.setSampleRate( ((AirspySampleRate)mSampleRateCombo.getSelectedItem()).getRate() );
double value = ((SpinnerNumberModel)mFrequencyCorrection.getModel()).getNumber().doubleValue();
config.setFrequencyCorrection( value );
Gain gain = Gain.getGain( (GainMode)mGainModeCombo.getSelectedItem(), mMasterGain.getValue() );
config.setGain( gain );
config.setIFGain( mIFGain.getValue() );
config.setMixerGain( mMixerGain.getValue() );
config.setLNAGain( mLNAGain.getValue() );
config.setMixerAGC( mMixerAGC.isSelected() );
config.setLNAAGC( mLNAAGC.isSelected() );
getTunerConfigurationModel().broadcast( new TunerConfigurationEvent( config, Event.CHANGE ) );
}
}
private AirspySampleRate fromValue( int value )
{
List<AirspySampleRate> rates = mController.getSampleRates();
for( AirspySampleRate rate: rates )
{
if( rate.getRate() == value )
{
return rate;
}
}
if( rates.size() > 0 )
{
return rates.get( 0 );
}
return null;
}
/**
* Sets all controls to the argument enabled state
*/
private void setControlsEnabled( boolean enabled )
{
if( mConfigurationName.isEnabled() != enabled )
{
mConfigurationName.setEnabled( enabled );
}
if( mTunerInfo.isEnabled() != enabled )
{
mTunerInfo.setEnabled( enabled );
}
if( mSampleRateCombo.isEnabled() != enabled )
{
mSampleRateCombo.setEnabled( enabled );
}
if( mFrequencyCorrection.isEnabled() != enabled )
{
mFrequencyCorrection.setEnabled( enabled );
}
if( mGainModeCombo.isEnabled() != enabled )
{
mGainModeCombo.setEnabled( enabled );
}
if( mMasterGain.isEnabled() != enabled )
{
mMasterGain.setEnabled( enabled );
}
if( mIFGain.isEnabled() != enabled )
{
mIFGain.setEnabled( enabled );
}
if( mMixerGain.isEnabled() != enabled )
{
mMixerGain.setEnabled( enabled );
}
if( mMixerAGC.isEnabled() != enabled )
{
mMixerAGC.setEnabled( enabled );
}
if( mLNAGain.isEnabled() != enabled )
{
mLNAGain.setEnabled( enabled );
}
if( mLNAAGC.isEnabled() != enabled )
{
mLNAAGC.setEnabled( enabled );
}
}
/**
* Applies the tuner configuration to the editor. If the configuration is assigned to the
* currently selected tuner, then the settings are applied.
*/
@Override
public void setItem( TunerConfiguration config )
{
super.setItem( config );
mLoading = true;
if( hasItem() && getItem().isAssigned() )
{
AirspyTunerConfiguration airspy = getConfiguration();
setControlsEnabled( true );
mConfigurationName.setText( airspy.getName() );
AirspySampleRate rate = fromValue( airspy.getSampleRate() );
if( rate != null )
{
mSampleRateCombo.setSelectedItem( rate );
}
mFrequencyCorrection.setValue( airspy.getFrequencyCorrection() );
GainMode mode = Gain.getGainMode( airspy.getGain() );
//This will set the master, IF, Mixer, LNA and AGC controls
mGainModeCombo.setSelectedItem( mode );
if( mode == GainMode.CUSTOM )
{
mMasterGain.setValue( airspy.getGain().getValue() );
mIFGain.setValue( airspy.getIFGain() );
if( airspy.isMixerAGC() )
{
mMixerAGC.setSelected( airspy.isMixerAGC() );
mMixerGain.setEnabled( false );
}
else
{
mMixerGain.setValue( airspy.getMixerGain() );
}
if( airspy.isLNAAGC() )
{
mLNAAGC.setSelected( airspy.isLNAAGC() );
mLNAGain.setEnabled( false );
}
else
{
mLNAGain.setValue( airspy.getLNAGain() );
}
}
else
{
mMixerAGC.setSelected( false );
mLNAAGC.setSelected( false );
Gain gain = airspy.getGain();
mMasterGain.setValue( gain.getValue() );
mIFGain.setValue( gain.getIF() );
mMixerGain.setValue( gain.getMixer() );
mLNAGain.setValue( gain.getLNA() );
}
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( hasItem() ? getItem().getName() : "" );
}
mLoading = false;
}
private String getTunerInfo()
{
StringBuilder sb = new StringBuilder();
AirspyDeviceInformation info = mController.getDeviceInfo();
sb.append( "<html><h3>Airspy Tuner</h3>" );
sb.append( "<b>Serial: </b>" );
sb.append( info.getSerialNumber() );
sb.append( "<br>" );
sb.append( "<b>Firmware: </b>" );
String[] firmware = info.getVersion().split( " " );
sb.append( firmware.length > 1 ? firmware[ 0 ] : info.getVersion() );
sb.append( "<br>" );
sb.append( "<b>Part: </b>" );
sb.append( info.getPartNumber() );
sb.append( "<br>" );
sb.append( "<b>Board ID: </b>" );
sb.append( info.getBoardID().getLabel() );
sb.append( "<br>" );
return sb.toString();
}
}

View File

@@ -1,113 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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.airspy;
import gui.control.JFrequencyControl;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.FrequencyChangeListener;
import com.jidesoft.swing.JideTabbedPane;
import controller.ResourceManager;
public class AirspyTunerEditorPanel extends JPanel
implements FrequencyChangeListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( AirspyTunerEditorPanel.class );
private JFrequencyControl mFrequencyControl;
private AirspyTuner mTuner;
private AirspyTunerController mController;
private ResourceManager mResourceManager;
public AirspyTunerEditorPanel( AirspyTuner tuner,
ResourceManager resourceManager )
{
mTuner = tuner;
mController = mTuner.getController();
mResourceManager = resourceManager;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2",
"[right,grow][grow]",
"[][][][][][grow]" ) );
add( new JLabel( "Airspy Tuner" ), "span,align center" );
mFrequencyControl = new JFrequencyControl();
mFrequencyControl.addListener( this );
/* Add frequency control as frequency change listener. This creates a
* feedback loop, so the control does not rebroadcast the event */
mTuner.addListener( mFrequencyControl );
mFrequencyControl.setFrequency( mController.getFrequency(), false );
add( mFrequencyControl, "span,align center" );
JideTabbedPane tabs = new JideTabbedPane();
tabs.setFont( this.getFont() );
tabs.setForeground( Color.BLACK );
add( tabs, "span,grow,push" );
tabs.add( "Config", new AirspyTunerConfigurationPanel(
mResourceManager, mTuner.getController() ) );
tabs.add( "Info", new AirspyInformationPanel( mTuner.getController() ) );
}
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
if( event.getEvent() == Event.FREQUENCY_CHANGE_NOTIFICATION )
{
try
{
mController.setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
mLog.error( "error setting frequency [" +
event.getValue().longValue() + "]", e );
}
}
}
}

View File

@@ -15,11 +15,13 @@
* 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;
package source.tuner.configuration;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import source.tuner.TunerType;
/**
* Abstract class to hold a named configuration for a specific type of tuner
*/
@@ -27,13 +29,23 @@ import javax.xml.bind.annotation.XmlType;
public abstract class TunerConfiguration
{
protected String mName;
protected String mUniqueID;
protected boolean mAssigned;
/**
* Default constructor to support JAXB
*/
public TunerConfiguration()
{
this( "Unknown" );
}
/**
* Normal constructor
*/
public TunerConfiguration( String uniqueID, String name )
{
mUniqueID = uniqueID;
mName = name;
}
public String toString()
@@ -41,14 +53,6 @@ public abstract class TunerConfiguration
return mName;
}
/**
* Normal constructor
*/
public TunerConfiguration( String name )
{
mName = name;
}
@XmlAttribute( name = "name" )
public String getName()
{
@@ -59,6 +63,28 @@ public abstract class TunerConfiguration
{
mName = name;
}
@XmlAttribute( name = "unique_id" )
public String getUniqueID()
{
return mUniqueID;
}
public void setUniqueID( String id )
{
mUniqueID = id;;
}
@XmlAttribute( name = "assigned" )
public boolean isAssigned()
{
return mAssigned;
}
public void setAssigned( boolean assigned )
{
mAssigned = assigned;
}
@XmlAttribute( name = "tuner_type" )
public abstract TunerType getTunerType();

View File

@@ -0,0 +1,20 @@
package source.tuner.configuration;
import gui.editor.Editor;
public abstract class TunerConfigurationEditor extends Editor<TunerConfiguration>
{
private static final long serialVersionUID = 1L;
private TunerConfigurationModel mTunerConfigurationModel;
public TunerConfigurationEditor( TunerConfigurationModel model )
{
mTunerConfigurationModel = model;
}
public TunerConfigurationModel getTunerConfigurationModel()
{
return mTunerConfigurationModel;
}
}

View File

@@ -0,0 +1,30 @@
package source.tuner.configuration;
public class TunerConfigurationEvent
{
private TunerConfiguration mTunerConfiguration;
private Event mEvent;
public TunerConfigurationEvent( TunerConfiguration configuration, Event event )
{
mTunerConfiguration = configuration;
mEvent = event;
}
public TunerConfiguration getConfiguration()
{
return mTunerConfiguration;
}
public Event getEvent()
{
return mEvent;
}
public enum Event
{
ADD,
REMOVE,
CHANGE;
}
}

View File

@@ -0,0 +1,94 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner.configuration;
import gui.editor.Editor;
import source.tuner.Tuner;
import source.tuner.TunerType;
import source.tuner.airspy.AirspyTuner;
import source.tuner.airspy.AirspyTunerConfiguration;
import source.tuner.airspy.AirspyTunerEditor;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.proV1.FCD1TunerConfiguration;
import source.tuner.fcd.proV1.FCD1TunerEditor;
import source.tuner.fcd.proplusV2.FCD2TunerConfiguration;
import source.tuner.fcd.proplusV2.FCD2TunerEditor;
import source.tuner.hackrf.HackRFTuner;
import source.tuner.hackrf.HackRFTunerConfiguration;
import source.tuner.hackrf.HackRFTunerEditor;
import source.tuner.rtl.RTL2832Tuner;
import source.tuner.rtl.e4k.E4KTunerConfiguration;
import source.tuner.rtl.e4k.E4KTunerEditor;
import source.tuner.rtl.r820t.R820TTunerConfiguration;
import source.tuner.rtl.r820t.R820TTunerEditor;
public class TunerConfigurationFactory
{
/**
* Creates a tuner configuration for the specified tuner type, unique ID and name
*/
public static TunerConfiguration getTunerConfiguration( TunerType type, String uniqueID,
String name )
{
switch( type )
{
case AIRSPY_R820T:
return new AirspyTunerConfiguration( uniqueID, name );
case ELONICS_E4000:
return new E4KTunerConfiguration( uniqueID, name );
case FUNCUBE_DONGLE_PRO:
return new FCD1TunerConfiguration( uniqueID, name );
case FUNCUBE_DONGLE_PRO_PLUS:
return new FCD2TunerConfiguration( uniqueID, name );
case HACKRF:
return new HackRFTunerConfiguration( uniqueID, name );
case RAFAELMICRO_R820T:
return new R820TTunerConfiguration( uniqueID, name );
default:
throw new IllegalArgumentException( "Unrecognized tuner type ["
+ type.name() + "] - can't create named [" + name + "] tuner"
+ " configuration" );
}
}
/**
* Creates a tuner editor gui for the specified tuner
*/
public static Editor<TunerConfiguration> getEditor( Tuner tuner, TunerConfigurationModel model )
{
switch( tuner.getTunerType() )
{
case AIRSPY_R820T:
return new AirspyTunerEditor( model, (AirspyTuner)tuner );
case ELONICS_E4000:
return new E4KTunerEditor( model, (RTL2832Tuner)tuner );
case FUNCUBE_DONGLE_PRO:
return new FCD1TunerEditor( model, (FCDTuner)tuner );
case FUNCUBE_DONGLE_PRO_PLUS:
return new FCD2TunerEditor( model, (FCDTuner)tuner );
case HACKRF:
return new HackRFTunerEditor( model, (HackRFTuner)tuner );
case RAFAELMICRO_R820T:
return new R820TTunerEditor( model, (RTL2832Tuner)tuner );
case UNKNOWN:
default:
throw new IllegalArgumentException( "Unrecognized Tuner: " + tuner.getName() );
}
}
}

View File

@@ -0,0 +1,371 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner.configuration;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfigurationEvent.Event;
public class TunerConfigurationModel extends AbstractTableModel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( TunerConfigurationModel.class );
public static final int TUNER_TYPE = 0;
public static final int CONFIGURATION_NAME = 1;
public static final int ASSIGNED = 2;
private static final String[] COLUMN_HEADERS = { "Tuner Type", "Name", "Assigned" };
private List<Listener<TunerConfigurationEvent>> mConfigurationChangeListeners =
new ArrayList<>();
private List<TunerConfiguration> mTunerConfigurations = new ArrayList<>();
/**
* Table model for managing tuner configurations. Provides tuner configuration events to
* registered listeners
*/
public TunerConfigurationModel()
{
}
/**
* Adds the list of tuner configurations to the model
*/
public void addTunerConfigurations( List<TunerConfiguration> configs )
{
for( TunerConfiguration config: configs )
{
addTunerConfiguration( config );
}
}
/**
* Returns of list of tuner configurations from the model
*/
public List<TunerConfiguration> getTunerConfigurations()
{
return mTunerConfigurations;
}
/**
* Adds the tuner configuration to the model firing a table model row add
* event and broadcasting a tuner configuration event.
*/
public void addTunerConfiguration( TunerConfiguration config )
{
if( !mTunerConfigurations.contains( config ) &&
config.getUniqueID() != null &&
config.getName() != null )
{
mTunerConfigurations.add( config );
int index = mTunerConfigurations.indexOf( config );
fireTableRowsInserted( index, index );
broadcast( new TunerConfigurationEvent( config, Event.ADD ) );
}
}
/**
* Removes the tuner configuration from the model firing a table model row
* delete event and broadcasting a tuner configuration event.
*/
public void removeTunerConfiguration( TunerConfiguration config )
{
if( mTunerConfigurations.contains( config ) )
{
int index = mTunerConfigurations.indexOf( config );
mTunerConfigurations.remove( config );
fireTableRowsDeleted( index, index );
broadcast( new TunerConfigurationEvent( config, Event.REMOVE ) );
}
}
/**
* Removes all tuner configurations and assignments from the model and
* fires a table clear event and broadcasts a tuner configuration event for
* each row removed.
*/
public void clear()
{
for( TunerConfiguration config: mTunerConfigurations )
{
broadcast( new TunerConfigurationEvent( config, Event.REMOVE ) );
}
int size = mTunerConfigurations.size();
mTunerConfigurations.clear();
fireTableRowsDeleted( 0, size - 1 );
}
/**
* Registers a tuner configuration event listener
*/
public void addListener( Listener<TunerConfigurationEvent> listener )
{
mConfigurationChangeListeners.add( listener );
}
/**
* Removes the tuner configuration event listener
*/
public void removeListener( Listener<TunerConfigurationEvent> listener )
{
mConfigurationChangeListeners.remove( listener );
}
/**
* Broadcasts a tuner configuration event
*/
public void broadcast( TunerConfigurationEvent event )
{
for( Listener<TunerConfigurationEvent> listener: mConfigurationChangeListeners )
{
listener.receive( event );
}
}
/**
* Designates the configuration argument as the currently assigned configuration and unassigns
* any other configurations with the same tuner type and unique ID.
*/
public void assignTunerConfiguration( TunerConfiguration configToAssign )
{
if( configToAssign != null )
{
List<TunerConfiguration> configs =
getTunerConfigurations( configToAssign.getTunerType(), configToAssign.getUniqueID() );
for( TunerConfiguration config: configs )
{
if( config.isAssigned() )
{
config.setAssigned( false );
int index = mTunerConfigurations.indexOf( config );
fireTableCellUpdated( index, ASSIGNED );
broadcast( new TunerConfigurationEvent( config, Event.CHANGE ) );
}
}
configToAssign.setAssigned( true );
int index = mTunerConfigurations.indexOf( configToAssign );
fireTableCellUpdated( index, ASSIGNED );
broadcast( new TunerConfigurationEvent( configToAssign, Event.CHANGE ) );
}
}
/**
* Returns the tuner configuration that is assigned to the tuner with the
* tuner type and uniqueID, or selects the first existing configuration that
* matches the tuner type and unique ID and assigns it, or creates a new
* tuner configuration and assigns it to the tuner.
*
* This method will always return a tuner configuration that is assigned to
* the tuner type and unique ID.
*/
public TunerConfiguration getTunerConfiguration( TunerType type, String uniqueID )
{
List<TunerConfiguration> configs = getTunerConfigurations( type, uniqueID );
for( TunerConfiguration config: configs )
{
if( config.isAssigned() &&
config.getUniqueID() != null &&
config.getUniqueID().contentEquals( uniqueID ) )
{
return config;
}
}
//Reuse an existing configuration to assign
if( !configs.isEmpty() )
{
configs.get( 0 ).setAssigned( true );
return configs.get( 0 );
}
String name = getDistinctName( type, uniqueID );
//We didn't find the config so create a new one and assign it
TunerConfiguration config = TunerConfigurationFactory
.getTunerConfiguration( type, uniqueID, name );
config.setAssigned( true );
addTunerConfiguration( config );
return config;
}
/**
* Indicates if a configuration exists in this model matching the tuner type
* and unique ID and name.
*/
public boolean hasTunerConfiguration( TunerType type, String uniqueID, String name )
{
for( TunerConfiguration config: mTunerConfigurations )
{
if( config.getTunerType() == type &&
config.getUniqueID() != null &&
config.getUniqueID().contentEquals( uniqueID ) &&
config.getName() != null &&
config.getName().contentEquals( name ) )
{
return true;
}
}
return false;
}
/**
* Creates a configuration name for the tuner configuration that is distinct
* among the existing tuner configurations of the same type and uniqueID
*/
public String getDistinctName( TunerType type, String uniqueID )
{
int counter = 0;
String name = "New";
while( hasTunerConfiguration( type, uniqueID, name ) )
{
counter++;
name = "New (" + counter + ")";
}
return name;
}
/**
* Returns all tuner configurations for the specified tuner type
*/
public List<TunerConfiguration> getTunerConfigurations( TunerType type, String uniqueID )
{
List<TunerConfiguration> configs = new ArrayList<>();
for( TunerConfiguration config: mTunerConfigurations )
{
if( config.getTunerType() == type &&
config.getUniqueID() != null &&
config.getUniqueID().contentEquals( uniqueID ) )
{
configs.add( config );
}
}
return configs;
}
/**
* Column names for the table model
*/
@Override
public String getColumnName( int column )
{
return COLUMN_HEADERS[ column ];
}
/**
* Tuner configuration model row count
*/
@Override
public int getRowCount()
{
return mTunerConfigurations.size();
}
/**
* Tuner configuration model column count
*/
@Override
public int getColumnCount()
{
return COLUMN_HEADERS.length;
}
/**
* Returns the row index for the specified configuration or -1
*/
public int getRowIndex( TunerConfiguration configuration )
{
if( mTunerConfigurations.contains( configuration ) )
{
return mTunerConfigurations.indexOf( configuration );
}
return -1;
}
/**
* Returns the configuration at the specified index or null
*/
public TunerConfiguration getTunerConfiguration( int index )
{
if( index >= 0 && index < mTunerConfigurations.size() )
{
return mTunerConfigurations.get( index );
}
return null;
}
/**
* Returns the value at the indicated table cell
*/
@Override
public Object getValueAt( int row, int column )
{
if( row >= 0 && row < mTunerConfigurations.size() )
{
TunerConfiguration config = mTunerConfigurations.get( row );
switch( column )
{
case TUNER_TYPE:
return config.getTunerType().getLabel();
case CONFIGURATION_NAME:
return config.getName();
case ASSIGNED:
return config.isAssigned() ? "*" : null;
default:
break;
}
}
return null;
}
}

View File

@@ -19,36 +19,22 @@ package source.tuner.ettus;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.JPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.Tuner;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelSource;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.usb.USBTunerDevice;
import controller.ResourceManager;
import controller.ThreadPoolManager;
public class B100Tuner extends Tuner
{
private final static Logger mLog = LoggerFactory.getLogger( B100Tuner.class );
private USBTunerDevice mDevice;
public B100Tuner( USBTunerDevice device )
{
//TODO: this should extend a USBTuner class, so that we can push the
//complex sample listener and the frequency change listener up to that class
super( "Ettus B100 with WBX Tuner" );
mDevice = device;
super( "Ettus B100 with WBX Tuner", null );
}
public void dispose()
@@ -68,36 +54,12 @@ public class B100Tuner extends Tuner
return TunerType.ETTUS_WBX;
}
@Override
public JPanel getEditor( ResourceManager resourceManager )
{
return new B100TunerEditorPanel( this, resourceManager );
}
@Override
public void apply( TunerConfiguration config ) throws SourceException
{
mLog.error( "B100 Tuner - can't apply tuner configuration" );
}
@Override
public int getSampleRate()
{
return 0;
}
@Override
public double getSampleSize()
{
return 16.0;
}
@Override
public long getFrequency() throws SourceException
{
return 0;
}
@Override
public TunerChannelSource getChannel( TunerChannel channel )
throws RejectedExecutionException, SourceException
@@ -105,7 +67,7 @@ public class B100Tuner extends Tuner
//TODO: pass this call to the tuner controller
return null;
}
@Override
public void releaseChannel( TunerChannelSource source )
{

View File

@@ -22,20 +22,14 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import controller.ResourceManager;
import settings.SettingsManager;
public class B100TunerEditorPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private B100Tuner mTuner;
private ResourceManager mResourceManager;
public B100TunerEditorPanel( B100Tuner tuner, ResourceManager resourceManager )
public B100TunerEditorPanel( B100Tuner tuner, SettingsManager settingsManager )
{
mTuner = tuner;
mResourceManager = resourceManager;
init();
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,8 +19,6 @@ package source.tuner.fcd;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.JPanel;
import sample.Listener;
import sample.adapter.ShortAdapter;
import sample.complex.ComplexBuffer;
@@ -30,75 +28,50 @@ import source.tuner.MixerTunerDataLine;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelSource;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerEvent;
import source.tuner.TunerType;
import source.tuner.frequency.FrequencyChangeListener;
import controller.ResourceManager;
import controller.ThreadPoolManager;
public class FCDTuner extends MixerTuner
{
private FCDTunerController mController;
public FCDTuner( MixerTunerDataLine mixerTDL,
FCDTunerController controller )
{
super( controller.getConfiguration().toString(),
super( controller.getConfiguration().toString(),
controller,
mixerTDL,
new ShortAdapter() );
mController = controller;
mController.addListener( (FrequencyChangeListener)this );
}
public void dispose()
{
//TODO: release the mixer tuner data line as well
mController.dispose();
getController().dispose();
}
public FCDTunerController getController()
{
return mController;
return (FCDTunerController)getTunerController();
}
@Override
public TunerClass getTunerClass()
{
return mController.getTunerClass();
return getController().getTunerClass();
}
@Override
public TunerType getTunerType()
{
return mController.getTunerType();
return getController().getTunerType();
}
@Override
public String getUniqueID()
{
return mController.getUSBAddress();
return getController().getUSBAddress();
}
@Override
public JPanel getEditor( ResourceManager resourceManager )
{
return mController.getEditor( this, resourceManager );
}
@Override
public void apply( TunerConfiguration config )throws SourceException
{
mController.apply( config );
}
@Override
public int getSampleRate()
{
return (int)mMixerTunerType.getAudioFormat().getSampleRate();
}
@Override
public double getSampleSize()
{
@@ -106,16 +79,17 @@ public class FCDTuner extends MixerTuner
}
@Override
public long getFrequency() throws SourceException
{
return mController.getFrequency();
}
@Override
public TunerChannelSource getChannel( TunerChannel tunerChannel )
public TunerChannelSource getChannel( TunerChannel tunerChannel )
throws RejectedExecutionException, SourceException
{
return mController.getChannel( this, tunerChannel );
TunerChannelSource source = getController().getChannel( this, tunerChannel );
if( source != null )
{
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
}
return source;
}
/**
@@ -132,7 +106,7 @@ public class FCDTuner extends MixerTuner
/* Tell the controller to release the channel and cleanup */
/* This will release the channel as a frequency change listener */
mController.releaseChannel( source );
getController().releaseChannel( source );
}
}
}

View File

@@ -21,7 +21,6 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.swing.JPanel;
import javax.usb.UsbClaimException;
import javax.usb.UsbException;
@@ -35,11 +34,10 @@ import org.usb4java.LibUsbException;
import source.SourceException;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerController;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.fcd.proV1.FCD1TunerController.Block;
import controller.ResourceManager;
public abstract class FCDTunerController extends TunerController
{
@@ -70,6 +68,7 @@ public abstract class FCDTunerController extends TunerController
*/
public FCDTunerController( Device device,
DeviceDescriptor descriptor,
int sampleRate,
int minTunableFrequency,
int maxTunableFrequency )
{
@@ -77,7 +76,7 @@ public abstract class FCDTunerController extends TunerController
maxTunableFrequency,
DC_SPIKE_AVOID_BUFFER,
USABLE_BANDWIDTH_PERCENT );
mFrequencyController.setSampleRate( sampleRate );
mDevice = device;
mDeviceDescriptor = descriptor;
}
@@ -146,23 +145,10 @@ public abstract class FCDTunerController extends TunerController
*/
public abstract TunerType getTunerType();
/**
* Editor panel (GUI) component.
*/
public abstract JPanel getEditor( FCDTuner tuner,
ResourceManager resourceManager );
/**
* Applies the settings in the tuner configuration
*/
public abstract void apply( TunerConfiguration config )
throws SourceException;
/**
* Returns the currently applied tuner configuration or null if one hasn't
* yet been applied
*/
public abstract TunerConfiguration getTunerConfiguration();
public abstract void apply( TunerConfiguration config ) throws SourceException;
/**
* USB address (bus/port)

View File

@@ -1,49 +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.fcd;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class FCDTunerDetailsPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public FCDTunerDetailsPanel( FCDTunerController controller )
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][][grow]" ) );
add( new JLabel( "USB ID:" ) );
add( new JLabel( controller.getUSBID() ) );
add( new JLabel( "USB Address:" ) );
add( new JLabel( controller.getUSBAddress() ) );
add( new JLabel( "USB Speed:" ) );
add( new JLabel( controller.getUSBSpeed() ) );
add( new JLabel( "Cellular Band:" ) );
add( new JLabel( controller.getConfiguration().getBandBlocking()
.getLabel() ) );
add( new JLabel( "Firmware:" ) );
add( new JLabel( controller.getConfiguration().getFirmware() ) );
}
}

View File

@@ -19,8 +19,8 @@ package source.tuner.fcd.proV1;
import javax.xml.bind.annotation.XmlAttribute;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.fcd.proV1.FCD1TunerController.LNAEnhance;
import source.tuner.fcd.proV1.FCD1TunerController.LNAGain;
import source.tuner.fcd.proV1.FCD1TunerController.MixerGain;
@@ -42,12 +42,11 @@ public class FCD1TunerConfiguration extends TunerConfiguration
*/
public FCD1TunerConfiguration()
{
this( "Default" );
}
public FCD1TunerConfiguration( String name )
public FCD1TunerConfiguration( String uniqueID, String name )
{
super( name );
super( uniqueID, name );
}
@Override
@@ -56,6 +55,7 @@ public class FCD1TunerConfiguration extends TunerConfiguration
return TunerType.FUNCUBE_DONGLE_PRO;
}
@XmlAttribute( name = "lna_gain" )
public LNAGain getLNAGain()
{
return mLNAGain;
@@ -66,12 +66,12 @@ public class FCD1TunerConfiguration extends TunerConfiguration
mLNAGain = gain;
}
@XmlAttribute( name = "lna_gain" )
public LNAEnhance getLNAEnhance()
{
return mLNAEnhance;
}
@XmlAttribute( name = "lna_enhance" )
public void setLNAEnhance( LNAEnhance enhance )
{
mLNAEnhance = enhance;

View File

@@ -1,663 +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.fcd.proV1;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.usb.UsbClaimException;
import javax.usb.UsbException;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.fcd.proV1.FCD1TunerController.LNAEnhance;
import source.tuner.fcd.proV1.FCD1TunerController.LNAGain;
import source.tuner.fcd.proV1.FCD1TunerController.MixerGain;
import com.jidesoft.swing.JideTabbedPane;
import controller.ResourceManager;
public class FCD1TunerConfigurationPanel extends JPanel
{
private final static Logger mLog =
LoggerFactory.getLogger( FCD1TunerConfigurationPanel.class );
private static final long serialVersionUID = 1L;
private ResourceManager mResourceManager;
private FCD1TunerController mController;
private FCD1TunerConfiguration mSelectedConfig;
private JButton mNewConfiguration;
private JButton mDeleteConfiguration;
private JComboBox<FCD1TunerConfiguration> mComboConfigurations;
private JComboBox<LNAGain> mComboLNAGain;
private JComboBox<LNAEnhance> mComboLNAEnhance;
private JComboBox<MixerGain> mComboMixerGain;
private JTextField mName;
private JSpinner mCorrectionFrequency;
private CorrectionSpinner mCorrectionDCI;
private CorrectionSpinner mCorrectionDCQ;
private CorrectionSpinner mCorrectionGain;
private CorrectionSpinner mCorrectionPhase;
public FCD1TunerConfigurationPanel( ResourceManager resourceManager,
FCD1TunerController controller )
{
mResourceManager = resourceManager;
mController = controller;
mSelectedConfig = controller.getTunerConfiguration();
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][grow]" ) );
/**
* Tuner configurations combo
*/
mComboConfigurations = new JComboBox<FCD1TunerConfiguration>();
mComboConfigurations.setToolTipText( "Select a tuner configuration. "
+ "Create a separate tuner configuration for each of your "
+ "funcube dongles by using the NEW button and typing a "
+ "descriptive name" );
mComboConfigurations.setModel( getModel() );
mComboConfigurations.setSelectedItem( mSelectedConfig );
mComboConfigurations.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
FCD1TunerConfiguration selected =
(FCD1TunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
update( selected );
}
}
});
add( new JLabel( "Config:" ) );
add( mComboConfigurations, "growx,push" );
/**
* Tuner Configuration - Name
*/
mName = new JTextField( mSelectedConfig.getName() );
mName.setToolTipText( "Name for the selected tuner configuration" );
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, "growx,push" );
JideTabbedPane tabs = new JideTabbedPane();
tabs.setFont( this.getFont() );
tabs.setForeground( Color.BLACK );
add( tabs, "span,grow,push" );
JPanel gainPanel = new JPanel();
gainPanel.setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][grow]" ) );
/**
* LNA Gain
*/
mComboLNAGain = new JComboBox<LNAGain>( LNAGain.values() );
mComboLNAGain.setToolTipText( "Adjust the low noise amplifier gain "
+ "setting. Default value is 20db" );
mComboLNAGain.setSelectedItem( mSelectedConfig.getLNAGain() );
mComboLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
LNAGain gain = (LNAGain)mComboLNAGain.getSelectedItem();
mSelectedConfig.setLNAGain( gain );
try
{
mController.setLNAGain( gain );
}
catch ( UsbClaimException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - cannot claim FCD "
+ "Controller to apply LNA gain [" + gain.toString() + "]" );
mLog.error( "FuncubeDonglePro Controller - usb claim "
+ "exception while applying LNA gain value [" +
gain.toString() + "]", e1 );
}
catch ( UsbException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - FCD Controller "
+ "cannot apply LNA gain [" + gain.toString() + "]" );
mLog.error( "FuncubeDonglePro Controller - "
+ "exception while applying LNA gain value [" +
gain.toString() + "]", e1 );
}
save();
}
} );
gainPanel.add( new JLabel( "LNA:" ) );
gainPanel.add( mComboLNAGain, "growx,push" );
/**
* LNA Enhance
*/
mComboLNAEnhance = new JComboBox<LNAEnhance>( LNAEnhance.values() );
mComboLNAEnhance.setToolTipText( "Adjust the LNA enhance setting. "
+ "Default value is OFF" );
mComboLNAEnhance.setSelectedItem( mSelectedConfig.getLNAEnhance() );
mComboLNAEnhance.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
LNAEnhance enhance = (LNAEnhance)mComboLNAEnhance.getSelectedItem();
mSelectedConfig.setLNAEnhance( enhance );
try
{
mController.setLNAEnhance( enhance );
}
catch ( UsbClaimException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - cannot claim FCD "
+ "Controller to apply LNA enhance [" + enhance.toString() + "]" );
mLog.error( "FuncubeDonglePro Controller - usb claim "
+ "exception while applying LNA enhance value [" +
enhance.toString() + "]", e1 );
}
catch ( UsbException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - FCD Controller "
+ "cannot apply LNA enhance [" + enhance.toString() + "]" );
mLog.error( "FuncubeDonglePro Controller - "
+ "exception while applying LNA enhance value [" +
enhance.toString() + "]", e1 );
}
save();
}
} );
gainPanel.add( new JLabel( "LNA Enhance:" ) );
gainPanel.add( mComboLNAEnhance, "growx,push" );
/**
* Mixer Gain
*/
mComboMixerGain = new JComboBox<MixerGain>( MixerGain.values() );
mComboMixerGain.setToolTipText( "Adjust mixer gain setting" );
mComboMixerGain.setSelectedItem( mSelectedConfig.getMixerGain() );
mComboMixerGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
MixerGain gain = (MixerGain)mComboMixerGain.getSelectedItem();
mSelectedConfig.setMixerGain( gain );
try
{
mController.setMixerGain( gain );
}
catch ( UsbClaimException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - cannot claim FCD "
+ "Controller to apply Mixer gain [" + gain.toString() + "]" );
mLog.error( "FuncubeDonglePro Controller - usb claim "
+ "exception while applying Mixer gain value [" +
gain.toString() + "]", e1 );
}
catch ( UsbException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - FCD Controller "
+ "cannot apply Mixer gain [" + gain.toString() + "]" );
mLog.error( "FuncubeDonglePro Controller - "
+ "exception while applying Mixer gain value [" +
gain.toString() + "]", e1 );
}
save();
}
} );
gainPanel.add( new JLabel( "Mixer:" ) );
gainPanel.add( mComboMixerGain, "growx,push" );
tabs.add( "Gain", gainPanel );
JPanel correctionPanel = new JPanel();
correctionPanel.setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][][grow]" ) );
/**
* Frequency Correction
*/
SpinnerModel model =
new SpinnerNumberModel( 0.0, -1000.0, 1000.0, 0.1 ); //initial,min,max,step
mCorrectionFrequency = new JSpinner( model );
mCorrectionFrequency.setToolTipText( "Frequency Correction: adjust "
+ "value +/- to align the displayed frequency label with the "
+ "actual signals" );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mCorrectionFrequency.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mCorrectionFrequency.setValue( mSelectedConfig.getFrequencyCorrection() );
mCorrectionFrequency.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
double value = ((SpinnerNumberModel)mCorrectionFrequency
.getModel()).getNumber().doubleValue();
try
{
mSelectedConfig.setFrequencyCorrection( value );
mController.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - couldn't "
+ "apply frequency correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "FuncubeDonglePro Controller - couldn't apply "
+ "frequency correction value: " + value, e1 );
}
}
} );
correctionPanel.add( new JLabel( "Frequency PPM:" ) );
correctionPanel.add( mCorrectionFrequency, "growx,push" );
/**
* Inphase DC Correction
*/
mCorrectionDCI = new CorrectionSpinner( Correction.DC_INPHASE,
mSelectedConfig.getInphaseDCCorrection(), 0.00001, 5 );
mCorrectionDCI.setToolTipText( "DC Bias Correction/Inphase "
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
correctionPanel.add( new JLabel( "DC Inphase:" ) );
correctionPanel.add( mCorrectionDCI, "growx,push" );
/**
* Quadrature DC Correction
*/
mCorrectionDCQ = new CorrectionSpinner( Correction.DC_QUADRATURE,
mSelectedConfig.getQuadratureDCCorrection(), 0.00001, 5 );
mCorrectionDCQ.setToolTipText( "DC Bias Correction/Quadrature "
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
correctionPanel.add( new JLabel( "DC Quadrature:" ) );
correctionPanel.add( mCorrectionDCQ, "growx,push" );
/**
* Gain Correction
*/
mCorrectionGain = new CorrectionSpinner( Correction.GAIN,
mSelectedConfig.getGainCorrection(), 0.00001, 5 );
mCorrectionGain.setToolTipText( "Gain Correction: valid values are "
+ "-1.0 to 1.0 (default: 0.0)" );
correctionPanel.add( new JLabel( "Gain:" ) );
correctionPanel.add( mCorrectionGain, "growx,push" );
/**
* Phase Correction
*/
mCorrectionPhase = new CorrectionSpinner( Correction.PHASE,
mSelectedConfig.getPhaseCorrection(), 0.00001, 5 );
mCorrectionPhase.setToolTipText( "Phase Correction: valid values are "
+ "-1.0 to 1.0 (default: 0.0)" );
correctionPanel.add( new JLabel( "Phase:" ) );
correctionPanel.add( mCorrectionPhase, "growx,push" );
tabs.add( "Correction", correctionPanel );
/**
* Create a new configuration
*/
mNewConfiguration = new JButton( "New" );
mNewConfiguration.setToolTipText( "Create a new tuner configuration "
+ "for each of your dongles to keep track of the specific "
+ "settings for each dongle" );
mNewConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
TunerConfiguration config =
mResourceManager.getSettingsManager()
.addNewTunerConfiguration(
TunerType.FUNCUBE_DONGLE_PRO,
"New Configuration" );
mComboConfigurations.setModel( getModel() );
mComboConfigurations.setSelectedItem( config );
repaint();
}
} );
add( mNewConfiguration, "growx,push" );
/**
* Delete the currently selected configuration
*/
mDeleteConfiguration = new JButton( "Delete" );
mDeleteConfiguration.setToolTipText( "Deletes the currently selected "
+ "tuner configuration. Note: the DEFAULT tuner "
+ "configuration will be recreated if you delete it, "
+ "after you restart the application" );
mDeleteConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
FCD1TunerConfiguration selected =
(FCD1TunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
int n = JOptionPane.showConfirmDialog(
FCD1TunerConfigurationPanel.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, "growx,push" );
}
private void update( FCD1TunerConfiguration config )
{
mSelectedConfig = config;
try
{
mController.apply( config );
mName.setText( config.getName() );
mComboLNAGain.setSelectedItem( mSelectedConfig.getLNAGain() );
mComboLNAEnhance.setSelectedItem( mSelectedConfig.getLNAEnhance() );
mComboMixerGain.setSelectedItem( mSelectedConfig.getMixerGain() );
mCorrectionFrequency.setValue( config.getFrequencyCorrection() );
mCorrectionDCI.setValue( config.getInphaseDCCorrection() );
mCorrectionDCQ.setValue( config.getQuadratureDCCorrection() );
mCorrectionGain.setValue( config.getGainCorrection() );
mCorrectionPhase.setValue( config.getPhaseCorrection() );
mResourceManager.getSettingsManager()
.setSelectedTunerConfiguration(
TunerType.FUNCUBE_DONGLE_PRO,
mController.getUSBAddress(), config );
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - couldn't "
+ "apply the tuner configuration settings - " +
e1.getLocalizedMessage() );
mLog.error( "FuncubeDonglePro Controller - couldn't apply "
+ "config [" + config.getName() + "]", e1 );
}
}
private ComboBoxModel<FCD1TunerConfiguration> getModel()
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.FUNCUBE_DONGLE_PRO );
DefaultComboBoxModel<FCD1TunerConfiguration> model =
new DefaultComboBoxModel<FCD1TunerConfiguration>();
for( TunerConfiguration config: configs )
{
model.addElement( (FCD1TunerConfiguration)config );
}
return model;
}
@SuppressWarnings( "unused" )
private FCD1TunerConfiguration getNamedConfiguration( String name )
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.FUNCUBE_DONGLE_PRO );
for( TunerConfiguration config: configs )
{
if( config.getName().contentEquals( name ) )
{
return (FCD1TunerConfiguration)config;
}
}
return null;
}
private void save()
{
mResourceManager.getSettingsManager().save();
}
public enum Correction { GAIN, PHASE, DC_INPHASE, DC_QUADRATURE };
public class CorrectionSpinner extends JSpinner
{
private static final long serialVersionUID = 1L;
private static final double sMIN_VALUE = -1.0d;
private static final double sMAX_VALUE = 1.0d;
private Correction mCorrectionComponent;
public CorrectionSpinner( Correction component,
double initialValue,
double step,
int decimalPlaces )
{
mCorrectionComponent = component;
SpinnerModel model = new SpinnerNumberModel( initialValue,
sMIN_VALUE, sMAX_VALUE, step );
setModel( model );
JSpinner.NumberEditor editor = (JSpinner.NumberEditor)getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( decimalPlaces );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
double value =
((SpinnerNumberModel)getModel()).getNumber().doubleValue();
try
{
switch( mCorrectionComponent )
{
case DC_INPHASE:
mSelectedConfig.setInphaseDCCorrection( value );
mController.setDCCorrectionInPhase( value );
break;
case DC_QUADRATURE:
mSelectedConfig.setQuadratureDCCorrection( value );
mController.setDCCorrectionQuadrature( value );
break;
case GAIN:
mSelectedConfig.setGainCorrection( value );
mController.setGainCorrection( value );
break;
case PHASE:
mSelectedConfig.setPhaseCorrection( value );
mController.setPhaseCorrection( value );
break;
}
//Save the change(s) to the selected tuner config
save();
}
catch ( UsbClaimException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - cannot claim FCD "
+ "Controller to apply "
+ mCorrectionComponent.toString() +
" correction value [" + value + "]" );
mLog.error( "FuncubeDonglePro Controller - usb claim "
+ "exception while applying "
+ mCorrectionComponent.toString()
+ " correction value [" + value + "]", e1 );
}
catch ( UsbException e1 )
{
JOptionPane.showMessageDialog(
FCD1TunerConfigurationPanel.this,
"FCD Pro Tuner Controller - USB error from FCD "
+ "Controller while applying "
+ mCorrectionComponent.toString() +
" correction value [" + value + "]" );
mLog.error( "FuncubeDonglePro Controller - usb "
+ "exception while applying "
+ mCorrectionComponent.toString()
+ " correction value [" + value + "]", e1 );
}
}
} );
}
}
}

View File

@@ -20,7 +20,6 @@ package source.tuner.fcd.proV1;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.swing.JPanel;
import javax.usb.UsbClaimException;
import javax.usb.UsbException;
@@ -30,13 +29,12 @@ import org.usb4java.Device;
import org.usb4java.DeviceDescriptor;
import source.SourceException;
import source.tuner.MixerTunerType;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.fcd.FCDCommand;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerController;
import controller.ResourceManager;
public class FCD1TunerController extends FCDTunerController
{
@@ -55,12 +53,13 @@ public class FCD1TunerController extends FCDTunerController
private LNAEnhance mLNAEnhance;
private MixerGain mMixerGain;
private FCD1TunerConfiguration mTunerConfiguration;
private FCD1TunerEditorPanel mEditor;
private FCD1TunerEditor mEditor;
public FCD1TunerController( Device device, DeviceDescriptor descriptor )
{
super( device,
descriptor,
descriptor,
(int)MixerTunerType.FUNCUBE_DONGLE_PRO.getAudioFormat().getSampleRate(),
sMINIMUM_TUNABLE_FREQUENCY,
sMAXIMUM_TUNABLE_FREQUENCY );
}
@@ -147,17 +146,6 @@ public class FCD1TunerController extends FCDTunerController
}
}
@Override
public JPanel getEditor( FCDTuner tuner, ResourceManager resourceManager )
{
if( mEditor == null )
{
mEditor = new FCD1TunerEditorPanel( tuner, resourceManager );
}
return mEditor;
}
/**
* Gets the current LNA Gain value from the controller and stores it
*/

View File

@@ -0,0 +1,528 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner.fcd.proV1;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.configuration.TunerConfigurationEditor;
import source.tuner.configuration.TunerConfigurationEvent;
import source.tuner.configuration.TunerConfigurationEvent.Event;
import source.tuner.configuration.TunerConfigurationModel;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.proV1.FCD1TunerController.LNAEnhance;
import source.tuner.fcd.proV1.FCD1TunerController.LNAGain;
import source.tuner.fcd.proV1.FCD1TunerController.MixerGain;
public class FCD1TunerEditor extends TunerConfigurationEditor
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( FCD1TunerEditor.class );
private JTextField mConfigurationName;
private JButton mTunerInfo;
private JSpinner mFrequencyCorrection;
private JComboBox<LNAGain> mComboLNAGain;
private JComboBox<LNAEnhance> mComboLNAEnhance;
private JComboBox<MixerGain> mComboMixerGain;
private CorrectionSpinner mCorrectionDCI;
private CorrectionSpinner mCorrectionDCQ;
private CorrectionSpinner mCorrectionGain;
private CorrectionSpinner mCorrectionPhase;
private boolean mLoading;
private FCD1TunerController mController;
public FCD1TunerEditor( TunerConfigurationModel tunerConfigurationModel, FCDTuner tuner )
{
super( tunerConfigurationModel );
mController = (FCD1TunerController)tuner.getController();
init();
}
private FCD1TunerConfiguration getConfiguration()
{
if( hasItem() )
{
return (FCD1TunerConfiguration)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
"[][][][][][][][][][][][grow]" ) );
add( new JLabel( "FCD Pro Tuner Configuration" ), "span,align center" );
mConfigurationName = new JTextField();
mConfigurationName.setEnabled( false );
mConfigurationName.addFocusListener( new FocusListener()
{
@Override
public void focusLost( FocusEvent e )
{
save();
}
@Override
public void focusGained( FocusEvent e ) {}
} );
add( new JLabel( "Name:" ) );
add( mConfigurationName, "span 2" );
mTunerInfo = new JButton( "Tuner Info" );
mTunerInfo.setEnabled( false );
mTunerInfo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
JOptionPane.showMessageDialog( FCD1TunerEditor.this, getTunerInfo(),
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( mTunerInfo );
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
mFrequencyCorrection.setEnabled( false );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
try
{
mController.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner "
+ "Controller - couldn't apply frequency correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "FuncubeDonglePro Controller - couldn't apply "
+ "frequency correction value: " + value, e1 );
}
}
} );
add( new JLabel( "PPM:" ) );
add( mFrequencyCorrection, "wrap" );
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
add( new JLabel( "Gain" ), "span,align center" );
mComboLNAGain = new JComboBox<LNAGain>( LNAGain.values() );
mComboLNAGain.setEnabled( false );
mComboLNAGain.setToolTipText( "Adjust the low noise amplifier gain setting." );
mComboLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
LNAGain gain = (LNAGain)mComboLNAGain.getSelectedItem();
try
{
mController.setLNAGain( gain );
save();
}
catch ( Exception e )
{
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner Controller"
+ " - error setting LNA gain [" + gain.toString() + "]" );
mLog.error( "FuncubeDonglePro Controller - error setting gain [" + gain.toString() + "]", e );
}
}
} );
add( new JLabel( "LNA:" ) );
add( mComboLNAGain );
/**
* LNA Enhance
*/
mComboLNAEnhance = new JComboBox<LNAEnhance>( LNAEnhance.values() );
mComboLNAEnhance.setToolTipText( "Adjust the LNA enhance setting. Default value is OFF" );
mComboLNAEnhance.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
LNAEnhance enhance = (LNAEnhance)mComboLNAEnhance.getSelectedItem();
try
{
mController.setLNAEnhance( enhance );
save();
}
catch ( Exception e1 )
{
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner"
+ " error setting LNA enhance gain [" + enhance.toString() + "]" );
mLog.error( "FCDPro - error setting LNA enhance [" + enhance.toString() + "]", e1 );
}
}
} );
add( new JLabel( "Enhance:" ) );
add( mComboLNAEnhance );
/**
* Mixer Gain
*/
mComboMixerGain = new JComboBox<MixerGain>( MixerGain.values() );
mComboMixerGain.setToolTipText( "Adjust mixer gain setting" );
mComboMixerGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
MixerGain gain = (MixerGain)mComboMixerGain.getSelectedItem();
try
{
mController.setMixerGain( gain );
save();
}
catch ( Exception e1 )
{
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCDPro - error setting"
+ " mixer gain [" + gain.toString() + "]" );
mLog.error( "FCDPro - error setting mixer gain [" + gain.toString() + "]", e1 );
}
}
} );
add( new JLabel( "Mixer:" ) );
add( mComboMixerGain, "wrap" );
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
add( new JLabel( "Correction" ), "span,align center" );
/**
* Inphase DC Correction
*/
mCorrectionDCI = new CorrectionSpinner( Correction.DC_INPHASE, 0.0, 0.00001, 5 );
mCorrectionDCI.setEnabled( false );
mCorrectionDCI.setToolTipText( "DC Bias Correction/Inphase "
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
add( new JLabel( "DC Inphase:" ) );
add( mCorrectionDCI );
/**
* Quadrature DC Correction
*/
mCorrectionDCQ = new CorrectionSpinner( Correction.DC_QUADRATURE, 0.0, 0.00001, 5 );
mCorrectionDCQ.setToolTipText( "DC Bias Correction/Quadrature "
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
add( new JLabel( "DC Quadrature:" ) );
add( mCorrectionDCQ );
/**
* Gain Correction
*/
mCorrectionGain = new CorrectionSpinner( Correction.GAIN, 0.0, 0.00001, 5 );
mCorrectionGain.setToolTipText( "Gain Correction: valid values are "
+ "-1.0 to 1.0 (default: 0.0)" );
add( new JLabel( "Gain:" ) );
add( mCorrectionGain );
/**
* Phase Correction
*/
mCorrectionPhase = new CorrectionSpinner( Correction.PHASE, 0.0, 0.00001, 5 );
mCorrectionPhase.setToolTipText( "Phase Correction: valid values are "
+ "-1.0 to 1.0 (default: 0.0)" );
add( new JLabel( "Phase:" ) );
add( mCorrectionPhase );
}
/**
* Sets each of the tuner configuration controls to the enabled argument state
*/
private void setControlsEnabled( boolean enabled )
{
if( mConfigurationName.isEnabled() != enabled )
{
mConfigurationName.setEnabled( enabled );
}
if( mTunerInfo.isEnabled() != enabled )
{
mTunerInfo.setEnabled( enabled );
}
if( mFrequencyCorrection.isEnabled() != enabled )
{
mFrequencyCorrection.setEnabled( enabled );
}
if( mComboLNAEnhance.isEnabled() != enabled )
{
mComboLNAEnhance.setEnabled( enabled );
}
if( mComboLNAGain.isEnabled() != enabled )
{
mComboLNAGain.setEnabled( enabled );
}
if( mComboMixerGain.isEnabled() != enabled )
{
mComboMixerGain.setEnabled( enabled );
}
if( mCorrectionDCI.isEnabled() != enabled )
{
mCorrectionDCI.setEnabled( enabled );
}
if( mCorrectionDCQ.isEnabled() != enabled )
{
mCorrectionDCQ.setEnabled( enabled );
}
if( mCorrectionGain.isEnabled() != enabled )
{
mCorrectionGain.setEnabled( enabled );
}
if( mCorrectionPhase.isEnabled() != enabled )
{
mCorrectionPhase.setEnabled( enabled );
}
}
private String getTunerInfo()
{
StringBuilder sb = new StringBuilder();
sb.append( "<html><h3>Funcube Dongle Pro Tuner</h3>" );
sb.append( "<b>USB ID: </b>" );
sb.append( mController.getUSBID() );
sb.append( "<br>" );
sb.append( "<b>USB Address: </b>" );
sb.append( mController.getUSBAddress() );
sb.append( "<br>" );
sb.append( "<b>USB Speed: </b>" );
sb.append( mController.getUSBSpeed() );
sb.append( "<br>" );
sb.append( "<b>Cellular Band: </b>" );
sb.append( mController.getConfiguration().getBandBlocking() );
sb.append( "<br>" );
sb.append( "<b>Firmware: </b>" );
sb.append( mController.getConfiguration().getFirmware() );
sb.append( "<br>" );
return sb.toString();
}
@Override
public void save()
{
if( hasItem() && !mLoading )
{
FCD1TunerConfiguration config = getConfiguration();
config.setName( mConfigurationName.getText() );
double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
config.setFrequencyCorrection( value );
config.setLNAEnhance( (LNAEnhance)mComboLNAEnhance.getSelectedItem() );
config.setLNAGain( (LNAGain)mComboLNAGain.getSelectedItem() );
config.setMixerGain( (MixerGain)mComboMixerGain.getSelectedItem() );
double dci = ((SpinnerNumberModel)mCorrectionDCI.getModel()).getNumber().doubleValue();
config.setInphaseDCCorrection( dci );
double dcq = ((SpinnerNumberModel)mCorrectionDCQ.getModel()).getNumber().doubleValue();
config.setQuadratureDCCorrection( dcq );
double gain = ((SpinnerNumberModel)mCorrectionGain.getModel()).getNumber().doubleValue();
config.setGainCorrection( gain );
double phase = ((SpinnerNumberModel)mCorrectionPhase.getModel()).getNumber().doubleValue();
config.setPhaseCorrection( phase );
getTunerConfigurationModel().broadcast( new TunerConfigurationEvent( getConfiguration(), Event.CHANGE ) );
}
}
@Override
public void setItem( TunerConfiguration tunerConfiguration )
{
super.setItem( tunerConfiguration );
//Toggle loading so that we don't fire a change event and schedule a settings file save
mLoading = true;
if( hasItem() )
{
FCD1TunerConfiguration config = getConfiguration();
if( tunerConfiguration.isAssigned() )
{
setControlsEnabled( true );
mConfigurationName.setText( config.getName() );
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
mComboLNAEnhance.setSelectedItem( config.getLNAEnhance() );
mComboLNAGain.setSelectedItem( config.getLNAGain() );
mComboMixerGain.setSelectedItem( config.getMixerGain() );
mCorrectionDCI.setValue( config.getInphaseDCCorrection() );
mCorrectionDCQ.setValue( config.getQuadratureDCCorrection() );
mCorrectionGain.setValue( config.getGainCorrection() );
mCorrectionPhase.setValue( config.getPhaseCorrection() );
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( config.getName() );
}
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( "" );
}
mLoading = false;
}
public enum Correction { GAIN, PHASE, DC_INPHASE, DC_QUADRATURE };
public class CorrectionSpinner extends JSpinner
{
private static final long serialVersionUID = 1L;
private static final double MIN_VALUE = -1.0d;
private static final double MAX_VALUE = 1.0d;
private Correction mCorrectionComponent;
public CorrectionSpinner( Correction component, double initialValue, double step, int decimalPlaces )
{
mCorrectionComponent = component;
SpinnerModel model = new SpinnerNumberModel( initialValue, MIN_VALUE, MAX_VALUE, step );
setModel( model );
JSpinner.NumberEditor editor = (JSpinner.NumberEditor)getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( decimalPlaces );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
double value =
((SpinnerNumberModel)getModel()).getNumber().doubleValue();
try
{
switch( mCorrectionComponent )
{
case DC_INPHASE:
mController.setDCCorrectionInPhase( value );
break;
case DC_QUADRATURE:
mController.setDCCorrectionQuadrature( value );
break;
case GAIN:
mController.setGainCorrection( value );
break;
case PHASE:
mController.setPhaseCorrection( value );
break;
}
save();
}
catch ( Exception e1 )
{
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCDPro - error "
+ "applying " + mCorrectionComponent.toString() + " correction value ["
+ value + "]" );
mLog.error( "FCDPro - error applying "+ mCorrectionComponent.toString()
+ " correction value [" + value + "]", e1 );
}
}
} );
}
}
}

View File

@@ -1,111 +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.fcd.proV1;
import gui.control.JFrequencyControl;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerDetailsPanel;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import com.jidesoft.swing.JideTabbedPane;
import controller.ResourceManager;
public class FCD1TunerEditorPanel extends JPanel implements FrequencyChangeListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( FCD1TunerEditorPanel.class );
private FCDTuner mTuner;
private FCD1TunerController mController;
private ResourceManager mResourceManager;
private JFrequencyControl mFrequencyControl;
public FCD1TunerEditorPanel( FCDTuner tuner, ResourceManager resourceManager )
{
mTuner = tuner;
mController = (FCD1TunerController)mTuner.getController();
mResourceManager = resourceManager;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2", "[grow,right][grow]", "[][][grow]" ) );
add( new JLabel( "Funcube Dongle Pro Tuner" ), "span, align center" );
mFrequencyControl = new JFrequencyControl();
mFrequencyControl.addListener( this );
/* Add frequency control as listener to tuner to get frequency changes
* that are invoked elsewhere, to keep the control in sync with the
* frequency */
mTuner.addListener( mFrequencyControl );
mFrequencyControl.setFrequency( mController.getFrequency(), false );
add( mFrequencyControl, "span,align center" );
JideTabbedPane tabs = new JideTabbedPane();
tabs.setFont( this.getFont() );
tabs.setForeground( Color.BLACK );
tabs.add( "Configuration", new FCD1TunerConfigurationPanel(
mResourceManager, mController ) );
tabs.add( "Info", new FCDTunerDetailsPanel( mController ) );
add( tabs, "span,push,grow" );
}
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
if( event.getEvent() == Event.FREQUENCY_CHANGE_NOTIFICATION )
{
try
{
mController.setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
mLog.error( "FCTProController - error setting frequency [" +
event.getValue().longValue() + "]", e );
}
}
}
}

View File

@@ -19,8 +19,8 @@ package source.tuner.fcd.proplusV2;
import javax.xml.bind.annotation.XmlAttribute;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
public class FCD2TunerConfiguration extends TunerConfiguration
{
@@ -33,12 +33,11 @@ public class FCD2TunerConfiguration extends TunerConfiguration
*/
public FCD2TunerConfiguration()
{
this( "Default" );
}
public FCD2TunerConfiguration( String name )
public FCD2TunerConfiguration( String uniqueID, String name )
{
super( name );
super( uniqueID, name );
}
@Override

View File

@@ -1,380 +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.fcd.proplusV2;
import java.awt.ComponentOrientation;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
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.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.TunerConfiguration;
import source.tuner.TunerConfigurationAssignment;
import source.tuner.TunerType;
import controller.ResourceManager;
public class FCD2TunerConfigurationPanel extends JPanel
{
private final static Logger mLog =
LoggerFactory.getLogger( FCD2TunerConfigurationPanel.class );
private static final long serialVersionUID = 1L;
private ResourceManager mResourceManager;
private FCD2TunerController mController;
private FCD2TunerConfiguration mSelectedConfig;
private JButton mNewConfiguration;
private JButton mDeleteConfiguration;
private JComboBox<FCD2TunerConfiguration> mComboConfigurations;
private JTextField mName;
private JCheckBox mLNAGain;
private JCheckBox mMixerGain;
private JSpinner mFrequencyCorrection;
public FCD2TunerConfigurationPanel( ResourceManager resourceManager,
FCD2TunerController controller )
{
mResourceManager = resourceManager;
mController = controller;
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][][grow]" ) );
mComboConfigurations = new JComboBox<FCD2TunerConfiguration>();
mComboConfigurations.setModel( getModel() );
mComboConfigurations.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
FCD2TunerConfiguration selected =
(FCD2TunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
update( selected );
}
}
});
add( new JLabel( "Config:" ) );
add( mComboConfigurations, "growx,push" );
mName = new JTextField();
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, "growx,push" );
/**
* Frequency Correction
*/
SpinnerModel model =
new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
try
{
mController.setFrequencyCorrection( value );
mSelectedConfig.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog(
FCD2TunerConfigurationPanel.this,
"FCD Pro Plus Tuner Controller - couldn't "
+ "apply frequency correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "FuncubeDongleProPlus Controller - couldn't apply "
+ "frequency correction value: " + value, e1 );
}
}
} );
add( new JLabel( "Correction PPM:" ) );
add( mFrequencyCorrection, "growx,push" );
/**
* LNA Gain
*/
mLNAGain = new JCheckBox( "LNA Gain:" );
mLNAGain.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
mLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
mSelectedConfig.setGainLNA( mLNAGain.isSelected() );
save();
update( mSelectedConfig );
}
} );
add( mLNAGain );
/**
* Mixer Gain
*/
mMixerGain = new JCheckBox( "Mixer Gain:" );
mMixerGain.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
mMixerGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
mSelectedConfig.setGainMixer( mMixerGain.isSelected() );
save();
update( mSelectedConfig );
}
} );
add( mMixerGain );
/**
* Lookup the save config and apply that config to update all of the
* controls
*/
TunerConfigurationAssignment savedConfig = mResourceManager
.getSettingsManager().getSelectedTunerConfiguration(
TunerType.FUNCUBE_DONGLE_PRO_PLUS,
mController.getUSBAddress() );
if( savedConfig != null )
{
mSelectedConfig = getNamedConfiguration(
savedConfig.getTunerConfigurationName() );
}
if( mSelectedConfig == null )
{
mSelectedConfig = mComboConfigurations.getItemAt( 0 );
//Store this config as the default for this tuner at this address
mResourceManager.getSettingsManager()
.setSelectedTunerConfiguration(
TunerType.FUNCUBE_DONGLE_PRO_PLUS,
mController.getUSBAddress(), mSelectedConfig );
}
mComboConfigurations.setSelectedItem( mSelectedConfig );
/**
* Create a new configuration
*/
mNewConfiguration = new JButton( "New" );
mNewConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
TunerConfiguration config =
mResourceManager.getSettingsManager()
.addNewTunerConfiguration(
TunerType.FUNCUBE_DONGLE_PRO_PLUS,
"New Configuration" );
mComboConfigurations.setModel( getModel() );
mComboConfigurations.setSelectedItem( config );
repaint();
}
} );
add( mNewConfiguration, "growx,push" );
/**
* Delete the currently selected configuration
*/
mDeleteConfiguration = new JButton( "Delete" );
mDeleteConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
FCD2TunerConfiguration selected =
(FCD2TunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
int n = JOptionPane.showConfirmDialog(
FCD2TunerConfigurationPanel.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, "growx,push" );
}
private void update( FCD2TunerConfiguration config )
{
mSelectedConfig = config;
try
{
mController.apply( config );
mName.setText( config.getName() );
mLNAGain.setSelected( config.getGainLNA() );
mMixerGain.setSelected( config.getGainMixer() );
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
mResourceManager.getSettingsManager().setSelectedTunerConfiguration(
TunerType.FUNCUBE_DONGLE_PRO_PLUS,
mController.getUSBAddress(), config );
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog(
FCD2TunerConfigurationPanel.this,
"FCD Pro Plus Tuner Controller - couldn't "
+ "apply the tuner configuration settings - " +
e1.getLocalizedMessage() );
mLog.error( "FuncubeDongleProPlus Controller - couldn't apply "
+ "config [" + config.getName() + "]", e1 );
}
}
private ComboBoxModel<FCD2TunerConfiguration> getModel()
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.FUNCUBE_DONGLE_PRO_PLUS );
DefaultComboBoxModel<FCD2TunerConfiguration> model =
new DefaultComboBoxModel<FCD2TunerConfiguration>();
for( TunerConfiguration config: configs )
{
model.addElement( (FCD2TunerConfiguration)config );
}
return model;
}
private FCD2TunerConfiguration getNamedConfiguration( String name )
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.FUNCUBE_DONGLE_PRO_PLUS );
for( TunerConfiguration config: configs )
{
if( config.getName().contentEquals( name ) )
{
return (FCD2TunerConfiguration)config;
}
}
return null;
}
private void save()
{
mResourceManager.getSettingsManager().save();
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,47 +20,39 @@ package source.tuner.fcd.proplusV2;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.swing.JPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.usb4java.Device;
import org.usb4java.DeviceDescriptor;
import source.SourceException;
import source.tuner.MixerTunerType;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.fcd.FCDCommand;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerController;
import controller.ResourceManager;
public class FCD2TunerController extends FCDTunerController
{
private final static Logger mLog =
LoggerFactory.getLogger( FCD2TunerController.class );
private final static Logger mLog = LoggerFactory.getLogger( FCD2TunerController.class );
public static final int sMINIMUM_TUNABLE_FREQUENCY = 150000;
public static final int sMAXIMUM_TUNABLE_FREQUENCY = 2050000000;
public static final int sSAMPLE_RATE = 192000;
private FCD2TunerConfiguration mTunerConfiguration;
private FCD2TunerEditorPanel mEditor;
public static final int MINIMUM_TUNABLE_FREQUENCY = 150000;
public static final int MAXIMUM_TUNABLE_FREQUENCY = 2050000000;
public static final int SAMPLE_RATE = 192000;
public FCD2TunerController( Device device, DeviceDescriptor descriptor )
{
super( device,
descriptor,
sMINIMUM_TUNABLE_FREQUENCY,
sMAXIMUM_TUNABLE_FREQUENCY );
super( device, descriptor,
(int)MixerTunerType.FUNCUBE_DONGLE_PRO_PLUS.getAudioFormat().getSampleRate(),
MINIMUM_TUNABLE_FREQUENCY, MAXIMUM_TUNABLE_FREQUENCY );
}
public void init() throws SourceException
{
super.init();
mFrequencyController.setSampleRate( sSAMPLE_RATE );
mFrequencyController.setSampleRate( SAMPLE_RATE );
try
{
@@ -74,7 +66,7 @@ public class FCD2TunerController extends FCDTunerController
public int getCurrentSampleRate()
{
return sSAMPLE_RATE;
return SAMPLE_RATE;
}
@Override
@@ -88,71 +80,44 @@ public class FCD2TunerController extends FCDTunerController
{
return TunerType.FUNCUBE_DONGLE_PRO_PLUS;
}
public JPanel getEditor( FCDTuner tuner, ResourceManager resourceManager )
{
if( mEditor == null )
{
mEditor = new FCD2TunerEditorPanel( tuner, resourceManager );
}
return mEditor;
}
public void setLNAGain( boolean enabled ) throws SourceException
{
try
{
send( FCDCommand.APP_SET_LNA_GAIN, enabled ? 1 : 0 );
}
catch ( Exception e )
{
throw new SourceException( "error while setting LNA Gain", e );
}
}
public void setMixerGain( boolean enabled ) throws SourceException
{
try
{
send( FCDCommand.APP_SET_MIXER_GAIN, enabled ? 1 : 0 );
}
catch ( Exception e )
{
throw new SourceException( "error while setting Mixer Gain", e );
}
}
@Override
public void apply( TunerConfiguration config ) throws SourceException
{
if( config instanceof FCD2TunerConfiguration )
{
FCD2TunerConfiguration plusConfig =
(FCD2TunerConfiguration)config;
FCD2TunerConfiguration fcd2 = (FCD2TunerConfiguration)config;
setFrequencyCorrection( plusConfig.getFrequencyCorrection() );
try
{
if( plusConfig.getGainLNA() )
{
send( FCDCommand.APP_SET_LNA_GAIN, 1 );
}
else
{
send( FCDCommand.APP_SET_LNA_GAIN, 0 );
}
}
catch ( Exception e )
{
throw new SourceException( "error while setting LNA Gain", e );
}
try
{
if( plusConfig.getGainMixer() )
{
send( FCDCommand.APP_SET_MIXER_GAIN, 1 );
}
else
{
send( FCDCommand.APP_SET_MIXER_GAIN, 0 );
}
}
catch ( Exception e )
{
throw new SourceException( "error while setting Mixer Gain", e );
}
mTunerConfiguration = plusConfig;
setFrequencyCorrection( fcd2.getFrequencyCorrection() );
setLNAGain( fcd2.getGainLNA() );
setMixerGain( fcd2.getGainMixer() );
}
}
@Override
public TunerConfiguration getTunerConfiguration()
{
return mTunerConfiguration;
}
public int getDCCorrection()
{
int dcCorrection = -999;

View File

@@ -0,0 +1,328 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner.fcd.proplusV2;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.configuration.TunerConfigurationEditor;
import source.tuner.configuration.TunerConfigurationEvent;
import source.tuner.configuration.TunerConfigurationEvent.Event;
import source.tuner.configuration.TunerConfigurationModel;
import source.tuner.fcd.FCDTuner;
public class FCD2TunerEditor extends TunerConfigurationEditor
{
private final static Logger mLog = LoggerFactory.getLogger( FCD2TunerEditor.class );
private static final long serialVersionUID = 1L;
private JTextField mConfigurationName;
private JButton mTunerInfo;
private JSpinner mFrequencyCorrection;
private JCheckBox mLNAGain;
private JCheckBox mMixerGain;
private boolean mLoading;
private FCD2TunerController mController;
public FCD2TunerEditor( TunerConfigurationModel tunerConfigurationModel, FCDTuner tuner )
{
super( tunerConfigurationModel );
mController = (FCD2TunerController)tuner.getController();
init();
}
private FCD2TunerConfiguration getConfiguration()
{
if( hasItem() )
{
return (FCD2TunerConfiguration)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
"[][][][][][grow]" ) );
add( new JLabel( "FCD Pro+ Tuner Configuration" ), "span,align center" );
mConfigurationName = new JTextField();
mConfigurationName.setEnabled( false );
mConfigurationName.addFocusListener( new FocusListener()
{
@Override
public void focusLost( FocusEvent e )
{
save();
}
@Override
public void focusGained( FocusEvent e ) {}
} );
add( new JLabel( "Name:" ) );
add( mConfigurationName, "span 2" );
mTunerInfo = new JButton( "Tuner Info" );
mTunerInfo.setEnabled( false );
mTunerInfo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
JOptionPane.showMessageDialog( FCD2TunerEditor.this, getTunerInfo(),
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( mTunerInfo );
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
mFrequencyCorrection.setEnabled( false );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
try
{
mController.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog( FCD2TunerEditor.this, "FCD Pro Plus Tuner "
+ "Controller - couldn't apply frequency correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "FuncubeDongleProPlus Controller - couldn't apply "
+ "frequency correction value: " + value, e1 );
}
}
} );
add( new JLabel( "PPM:" ) );
add( mFrequencyCorrection, "wrap" );
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
mLNAGain = new JCheckBox( "LNA Gain" );
mLNAGain.setEnabled( false );
mLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent event )
{
try
{
mController.setLNAGain( mLNAGain.isSelected() );
save();
}
catch( SourceException e )
{
mLog.error( "Couldn't set LNA gain for FCD2", e );
}
}
} );
add( new JLabel( "" ) );
add( mLNAGain );
/**
* Mixer Gain
*/
mMixerGain = new JCheckBox( "Mixer Gain" );
mMixerGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent event )
{
try
{
mController.setMixerGain( mMixerGain.isSelected() );
save();
}
catch( SourceException e )
{
mLog.error( "Couldn't set mixer gain for FCD2", e );
}
}
} );
add( new JLabel( "" ) );
add( mMixerGain );
}
/**
* Sets each of the tuner configuration controls to the enabled argument state
*/
private void setControlsEnabled( boolean enabled )
{
if( mConfigurationName.isEnabled() != enabled )
{
mConfigurationName.setEnabled( enabled );
}
if( mTunerInfo.isEnabled() != enabled )
{
mTunerInfo.setEnabled( enabled );
}
if( mFrequencyCorrection.isEnabled() != enabled )
{
mFrequencyCorrection.setEnabled( enabled );
}
if( mLNAGain.isEnabled() != enabled )
{
mLNAGain.setEnabled( enabled );
}
if( mMixerGain.isEnabled() != enabled )
{
mMixerGain.setEnabled( enabled );
}
}
private String getTunerInfo()
{
StringBuilder sb = new StringBuilder();
sb.append( "<html><h3>Funcube Dongle Pro Plus Tuner</h3>" );
sb.append( "<b>USB ID: </b>" );
sb.append( mController.getUSBID() );
sb.append( "<br>" );
sb.append( "<b>USB Address: </b>" );
sb.append( mController.getUSBAddress() );
sb.append( "<br>" );
sb.append( "<b>USB Speed: </b>" );
sb.append( mController.getUSBSpeed() );
sb.append( "<br>" );
sb.append( "<b>Cellular Band: </b>" );
sb.append( mController.getConfiguration().getBandBlocking() );
sb.append( "<br>" );
sb.append( "<b>Firmware: </b>" );
sb.append( mController.getConfiguration().getFirmware() );
sb.append( "<br>" );
return sb.toString();
}
@Override
public void save()
{
if( hasItem() && !mLoading )
{
FCD2TunerConfiguration config = getConfiguration();
config.setName( mConfigurationName.getText() );
double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
config.setFrequencyCorrection( value );
config.setGainLNA( mLNAGain.isSelected() );
config.setGainMixer( mMixerGain.isSelected() );
getTunerConfigurationModel().broadcast(
new TunerConfigurationEvent( getConfiguration(), Event.CHANGE ) );
}
}
@Override
public void setItem( TunerConfiguration tunerConfiguration )
{
super.setItem( tunerConfiguration );
//Toggle loading so that we don't fire a change event and schedule a settings file save
mLoading = true;
if( hasItem() )
{
FCD2TunerConfiguration config = getConfiguration();
if( tunerConfiguration.isAssigned() )
{
setControlsEnabled( true );
mConfigurationName.setText( config.getName() );
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
mLNAGain.setSelected( config.getGainLNA() );
mMixerGain.setSelected( config.getGainMixer() );
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( config.getName() );
}
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( "" );
}
mLoading = false;
}
}

View File

@@ -1,111 +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.fcd.proplusV2;
import gui.control.JFrequencyControl;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerDetailsPanel;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import com.jidesoft.swing.JideTabbedPane;
import controller.ResourceManager;
public class FCD2TunerEditorPanel extends JPanel implements FrequencyChangeListener
{
private final static Logger mLog =
LoggerFactory.getLogger( FCD2TunerEditorPanel.class );
private static final long serialVersionUID = 1L;
private FCDTuner mTuner;
private FCD2TunerController mController;
private ResourceManager mResourceManager;
private JFrequencyControl mFrequencyControl;
public FCD2TunerEditorPanel( FCDTuner tuner, ResourceManager resourceManager )
{
mTuner = tuner;
mController = (FCD2TunerController)mTuner.getController();
mResourceManager = resourceManager;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][grow]" ) );
add( new JLabel( "Funcube Dongle Pro Plus Tuner" ), "span,align center" );
mFrequencyControl = new JFrequencyControl();
mFrequencyControl.addListener( this );
/* Add frequency control as frequency change listener. This creates a
* feedback loop, so the control does not rebroadcast the event */
mTuner.addListener( mFrequencyControl );
mFrequencyControl.setFrequency( mController.getFrequency(), false );
add( mFrequencyControl, "span,align center" );
JideTabbedPane tabs = new JideTabbedPane();
tabs.setFont( this.getFont() );
tabs.setForeground( Color.BLACK );
tabs.add( "Configuration", new FCD2TunerConfigurationPanel(
mResourceManager, mController ) );
tabs.add( "Info", new FCDTunerDetailsPanel( mController ) );
add( tabs, "span,grow,push" );
}
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
if( event.getEvent() == Event.FREQUENCY_CHANGE_NOTIFICATION )
{
//Disregard the bandwidth, which shouldn't be changing
try
{
mController.setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
mLog.error( "FCDProController - error setting frequency [" +
event.getValue().longValue() + "]", e );
}
}
}
}

View File

@@ -1,181 +0,0 @@
package source.tuner.frequency;
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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/>
******************************************************************************/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.real.RealSampleListener;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import buffer.FloatAveragingBuffer;
public class AutomaticFrequencyControl_R extends FrequencyCorrectionControl
implements RealSampleListener
{
private final static Logger mLog =
LoggerFactory.getLogger( AutomaticFrequencyControl_R.class );
private static float LARGE_ERROR = 0.300f;
private static float MEDIUM_ERROR = 0.150f;
private static float SMALL_ERROR = 0.030f;
private static float FINE_ERROR = 0.015f;
private static int LARGE_FREQUENCY_CORRECTION = 1500; //Hertz
private static int MEDIUM_FREQUENCY_CORRECTION = 500;
private static int SMALL_FREQUENCY_CORRECTION = 100;
private static int FINE_FREQUENCY_CORRECTION = 50;
private static int SAMPLE_THRESHOLD = 15000;
private Mode mMode = Mode.FAST;
private FloatAveragingBuffer mBuffer =
new FloatAveragingBuffer( SAMPLE_THRESHOLD );
private int mSampleCounter = 0;
private int mSkipCounter = 0;
private int mSkipThreshold = 4;
private int mErrorCorrection = 0;
public enum Mode
{
NORMAL,FAST;
}
/**
* Automatic Frequency Control. Monitors DC bias present in an FM
* demodulated audio stream and issues automatic frequency corrections to
* maintain the DC bias close to zero.
*
* @param maximum - maximum allowable (+/-) frequency correction value.
*/
public AutomaticFrequencyControl_R( int maximum )
{
super( maximum );
}
public void dispose()
{
super.dispose();
mBuffer = null;
}
/**
* Resets the error correction value to zero and broadcasts a change event
*/
public void reset()
{
mErrorCorrection = 0;
mMode = Mode.FAST;
dispatch();
}
/**
* Broadcasts a frequency correction change event to the registered listener
*/
private void dispatch()
{
if( mListener != null )
{
mListener.frequencyChanged(
new FrequencyChangeEvent( Event.CHANNEL_FREQUENCY_CORRECTION_CHANGE_NOTIFICATION,
mErrorCorrection ) );
}
}
@Override
public void receive( float sample )
{
if( mMode == Mode.FAST )
{
float average = mBuffer.get( sample );
mSampleCounter++;
if( mSampleCounter >= SAMPLE_THRESHOLD )
{
mSampleCounter = 0;
update( average );
}
}
else
{
mSkipCounter++;
if( mSkipCounter >= mSkipThreshold )
{
mSkipCounter = 0;
float average = mBuffer.get( sample );
mSampleCounter++;
if( mSampleCounter >= SAMPLE_THRESHOLD )
{
mSampleCounter = 0;
update( average );
}
}
}
}
private void update( float average )
{
mMode = Mode.NORMAL;
if( average > LARGE_ERROR )
{
adjust( -LARGE_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average > MEDIUM_ERROR )
{
adjust( -MEDIUM_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average > SMALL_ERROR )
{
adjust( -SMALL_FREQUENCY_CORRECTION );
}
else if( average > FINE_ERROR )
{
adjust( -FINE_FREQUENCY_CORRECTION );
}
else if( average < -LARGE_ERROR )
{
adjust( LARGE_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average < -MEDIUM_ERROR )
{
adjust( MEDIUM_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average < -SMALL_ERROR )
{
adjust( SMALL_FREQUENCY_CORRECTION );
}
else if( average < -FINE_ERROR )
{
adjust( FINE_FREQUENCY_CORRECTION );
}
}
}

View File

@@ -1,197 +0,0 @@
package source.tuner.frequency;
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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/>
******************************************************************************/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.real.RealBuffer;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import buffer.FloatAveragingBuffer;
public class AutomaticFrequencyControl_RB extends FrequencyCorrectionControl
implements Listener<RealBuffer>
{
private final static Logger mLog =
LoggerFactory.getLogger( AutomaticFrequencyControl_RB.class );
private static float LARGE_ERROR = 0.300f;
private static float MEDIUM_ERROR = 0.150f;
private static float SMALL_ERROR = 0.030f;
private static float FINE_ERROR = 0.015f;
private static int LARGE_FREQUENCY_CORRECTION = 1500; //Hertz
private static int MEDIUM_FREQUENCY_CORRECTION = 500;
private static int SMALL_FREQUENCY_CORRECTION = 100;
private static int FINE_FREQUENCY_CORRECTION = 50;
private static int SAMPLE_THRESHOLD = 15000;
private Mode mMode = Mode.FAST;
private FloatAveragingBuffer mBuffer =
new FloatAveragingBuffer( SAMPLE_THRESHOLD );
private int mSampleCounter = 0;
private int mSkipCounter = 0;
private int mSkipThreshold = 4;
private int mErrorCorrection = 0;
public enum Mode
{
NORMAL,FAST;
}
/**
* Automatic Frequency Control. Monitors DC bias present in an FM
* demodulated audio stream and issues automatic frequency corrections to
* maintain the DC bias close to zero.
*
* @param maximum - maximum allowable (+/-) frequency correction value.
*/
public AutomaticFrequencyControl_RB( int maximum )
{
super( maximum );
}
public void dispose()
{
super.dispose();
mBuffer = null;
}
/**
* Resets the error correction value to zero and broadcasts a change event
*/
public void reset()
{
super.reset();
mMode = Mode.FAST;
dispatch();
}
/**
* Broadcasts a frequency correction change event to the registered listener
*/
private void dispatch()
{
if( mListener != null )
{
mListener.frequencyChanged(
new FrequencyChangeEvent( Event.CHANNEL_FREQUENCY_CORRECTION_CHANGE_NOTIFICATION,
mErrorCorrection ) );
}
}
@Override
public void receive( RealBuffer t )
{
float average = 0.0f;
for( float sample: t.getSamples() )
{
average = mBuffer.get( sample );
}
//TODO: fix this
// update( average );
}
public void receive( float sample )
{
if( mMode == Mode.FAST )
{
float average = mBuffer.get( sample );
mSampleCounter++;
if( mSampleCounter >= SAMPLE_THRESHOLD )
{
mSampleCounter = 0;
update( average );
}
}
else
{
mSkipCounter++;
if( mSkipCounter >= mSkipThreshold )
{
mSkipCounter = 0;
float average = mBuffer.get( sample );
mSampleCounter++;
if( mSampleCounter >= SAMPLE_THRESHOLD )
{
mSampleCounter = 0;
update( average );
}
}
}
}
private void update( float average )
{
mMode = Mode.NORMAL;
if( average > LARGE_ERROR )
{
adjust( -LARGE_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average > MEDIUM_ERROR )
{
adjust( -MEDIUM_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average > SMALL_ERROR )
{
adjust( -SMALL_FREQUENCY_CORRECTION );
}
else if( average > FINE_ERROR )
{
adjust( -FINE_FREQUENCY_CORRECTION );
}
else if( average < -LARGE_ERROR )
{
adjust( LARGE_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average < -MEDIUM_ERROR )
{
adjust( MEDIUM_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average < -SMALL_ERROR )
{
adjust( SMALL_FREQUENCY_CORRECTION );
}
else if( average < -FINE_ERROR )
{
adjust( FINE_FREQUENCY_CORRECTION );
}
}
}

View File

@@ -0,0 +1,128 @@
package source.tuner.frequency;
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
import java.util.concurrent.ScheduledExecutorService;
import module.Module;
import sample.Listener;
import sample.real.RealBuffer;
import source.tuner.frequency.FrequencyChangeEvent.Event;
public class DCTrackingFrequencyControl extends Module
implements Listener<RealBuffer>, IFrequencyChangeProvider
{
private static float COARSE_THRESHOLD = 0.1f;
private static float LOOP_GAIN = 0.1f;
private static float COARSE_GAIN = 1000.0f;
private static float FINE_GAIN = 100.0f;
private int mErrorCorrection = 0;
private int mMaximumFrequencyCorrection = 0;
private Listener<FrequencyChangeEvent> mListener;
/**
* DC offset Automatic Frequency Control. Monitors DC bias present in an FM
* demodulated audio stream and issues automatic frequency corrections to
* maintain the DC bias close to zero.
*
* @param maximum - maximum allowable (+/-) frequency correction value.
*/
public DCTrackingFrequencyControl( int maximum )
{
mMaximumFrequencyCorrection = maximum;
}
public void dispose()
{
mListener = null;
}
@Override
public void receive( RealBuffer buffer )
{
double sum = 0.0d;
for( float sample: buffer.getSamples() )
{
sum += sample;
}
float mean = (float)( sum / (double)buffer.getSamples().length );
float adjustment = 0.0f;
if( mean > COARSE_THRESHOLD || mean < - COARSE_THRESHOLD )
{
adjustment = mean * COARSE_GAIN;
}
else
{
adjustment = mean * FINE_GAIN;
}
setErrorCorrection( mErrorCorrection + (int)( (float)adjustment * LOOP_GAIN ) );
}
private void setErrorCorrection( int correction )
{
if( mListener != null )
{
if( correction > mMaximumFrequencyCorrection )
{
correction = mMaximumFrequencyCorrection;
}
else if( correction < -mMaximumFrequencyCorrection )
{
correction = -mMaximumFrequencyCorrection;
}
if( correction != mErrorCorrection )
{
mListener.receive( new FrequencyChangeEvent(
Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, correction ) );
}
}
}
@Override
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
{
mListener = listener;
}
@Override
public void removeFrequencyChangeListener()
{
mListener = null;
}
@Override
public void start( ScheduledExecutorService executor )
{
}
@Override
public void stop()
{
}
@Override
public void reset()
{
setErrorCorrection( 0 );
}
}

View File

@@ -1,26 +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.frequency;
public interface FrequencyChangeBroadcaster
{
public abstract void addListener( FrequencyChangeListener listener );
public abstract void removeListener( FrequencyChangeListener listener );
}

View File

@@ -4,11 +4,13 @@ public class FrequencyChangeEvent
{
public enum Event
{
FREQUENCY_CHANGE_NOTIFICATION,
FREQUENCY_CORRECTION_CHANGE_NOTIFICATION,
CHANNEL_FREQUENCY_CORRECTION_CHANGE_NOTIFICATION,
CHANNEL_FREQUENCY_CORRECTION_CHANGE_REQUEST,
SAMPLE_RATE_CHANGE_NOTIFICATION;
NOTIFICATION_FREQUENCY_CHANGE,
NOTIFICATION_FREQUENCY_CORRECTION_CHANGE,
NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
NOTIFICATION_SAMPLE_RATE_CHANGE,
REQUEST_FREQUENCY_CHANGE,
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE;
}
private Event mEvent;

View File

@@ -0,0 +1,32 @@
package source.tuner.frequency;
import sample.Listener;
public class FrequencyChangeProcessorWrapper
implements IFrequencyChangeListener, Listener<FrequencyChangeEvent>
{
private IFrequencyChangeProcessor mProcessor;
/**
* Provides IFrequencyChangeListener wrapper for an IFrequencyChangeProcessor
*/
public FrequencyChangeProcessorWrapper( IFrequencyChangeProcessor handler )
{
mProcessor = handler;
}
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
return this;
}
@Override
public void receive( FrequencyChangeEvent event )
{
if( mProcessor != null )
{
mProcessor.frequencyChanged( event );
}
}
}

View File

@@ -37,8 +37,7 @@ public class FrequencyController
private double mFrequencyCorrection = 0d;
private int mSampleRate = 0;
private ArrayList<FrequencyChangeListener> mListeners =
new ArrayList<FrequencyChangeListener>();
private ArrayList<IFrequencyChangeProcessor> mProcessors = new ArrayList<>();
public FrequencyController( Tunable tunable,
long minFrequency,
@@ -181,20 +180,21 @@ public class FrequencyController
/**
* Adds listener to receive frequency change events
*/
public void addListener( FrequencyChangeListener listener )
//TODO: rename this to addFrequencyChangeProcessor()
public void addListener( IFrequencyChangeProcessor processor )
{
if( !mListeners.contains( listener ) )
if( !mProcessors.contains( processor ) )
{
mListeners.add( listener );
mProcessors.add( processor );
}
}
/**
* Removes listener from receiving frequency change events
*/
public void removeListener( FrequencyChangeListener listener )
public void removeFrequencyChangeProcessor( IFrequencyChangeProcessor processor )
{
mListeners.remove( listener );
mProcessors.remove( processor );
}
@@ -205,7 +205,7 @@ public class FrequencyController
protected void broadcastFrequencyChange()
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.FREQUENCY_CHANGE_NOTIFICATION, mFrequency ) );
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CHANGE, mFrequency ) );
}
/**
@@ -214,7 +214,7 @@ public class FrequencyController
protected void broadcastFrequencyErrorChange()
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.FREQUENCY_CORRECTION_CHANGE_NOTIFICATION, mFrequencyCorrection ) );
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CORRECTION_CHANGE, mFrequencyCorrection ) );
}
/**
@@ -223,14 +223,14 @@ public class FrequencyController
protected void broadcastSampleRateChange()
{
broadcastFrequencyChangeEvent(
new FrequencyChangeEvent( Event.SAMPLE_RATE_CHANGE_NOTIFICATION, mSampleRate ) );
new FrequencyChangeEvent( Event.NOTIFICATION_SAMPLE_RATE_CHANGE, mSampleRate ) );
}
public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event )
{
for( FrequencyChangeListener listener: mListeners )
for( IFrequencyChangeProcessor processor: mProcessors )
{
listener.frequencyChanged( event );
processor.frequencyChanged( event );
}
}

View File

@@ -1,161 +0,0 @@
package source.tuner.frequency;
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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/>
******************************************************************************/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.tuner.frequency.FrequencyChangeEvent.Event;
/**
* Frequency control for providing frequency error correction to a tuned channel
*/
public class FrequencyCorrectionControl implements FrequencyChangeListener
{
private final static Logger mLog =
LoggerFactory.getLogger( FrequencyCorrectionControl.class );
protected FrequencyChangeListener mListener;
protected FrequencyCorrectionResetListener mResetListener;
protected int mChannelFrequencyCorrection = 0;
private int mMaximumCorrection = 3000;
/**
* Frequency correction controller.
*
* @param maximum - defines the maximum +/- allowable frequency correction
* value
*/
public FrequencyCorrectionControl( int maximum )
{
mMaximumCorrection = maximum;
}
/**
* Cleanup
*/
public void dispose()
{
mListener = null;
mResetListener = null;
}
/**
* Registers a listener to receive frequency correction events
*/
public void setFrequencyChangeListener( FrequencyChangeListener listener )
{
mListener = listener;
}
/**
* Registers a listener to receive frequency correction resets
*/
public void setListener( FrequencyCorrectionResetListener listener )
{
mResetListener = listener;
}
/**
* Listener for source frequency or frequency offset value changes to
* reset this frequency controller value to zero.
*/
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
Event attribute = event.getEvent();
switch( attribute )
{
//Direct the listener to reset when frequency correction (PPM) or
//sample rate changes
case FREQUENCY_CORRECTION_CHANGE_NOTIFICATION:
case SAMPLE_RATE_CHANGE_NOTIFICATION:
reset();
break;
default:
break;
}
}
/**
* Resets frequency correction value to zero and notifies any reset
* listeners
*/
public void reset()
{
if( mResetListener != null )
{
mResetListener.resetFrequencyCorrection();
}
}
/**
* Sets frequency correction to the specified value and broadcasts a change
* request
*/
public void setFrequencyCorrection( int correction )
{
mChannelFrequencyCorrection = correction;
/* Limit frequency correction to +/- max correction value */
if( mChannelFrequencyCorrection > mMaximumCorrection )
{
mChannelFrequencyCorrection = mMaximumCorrection;
}
else if( mChannelFrequencyCorrection < -mMaximumCorrection )
{
mChannelFrequencyCorrection = -mMaximumCorrection;
}
/* Broadcast a change request */
if( mListener != null )
{
mListener.frequencyChanged( new FrequencyChangeEvent(
Event.CHANNEL_FREQUENCY_CORRECTION_CHANGE_REQUEST,
mChannelFrequencyCorrection ) );
}
}
/**
* Increments the frequency error correction value by the specified adjustment
*/
public void adjust( int adjustment )
{
setFrequencyCorrection( getErrorCorrection() + adjustment );
}
/**
* Current frequency error correction value
* @return
*/
public int getErrorCorrection()
{
return mChannelFrequencyCorrection;
}
/**
* Listener interface to be notified when this control is reset to a zero
* frequency correction value
*/
public interface FrequencyCorrectionResetListener
{
public void resetFrequencyCorrection();
}
}

View File

@@ -17,6 +17,8 @@
******************************************************************************/
package source.tuner.frequency;
import sample.Listener;
/**
* Interface for broadcasting changes to frequency, bandwidth, sample rate,
@@ -26,7 +28,7 @@ package source.tuner.frequency;
* frequency value. All frequency correction aspects should be handled within
* the device that implements the tuning of the frequency.
*/
public interface FrequencyChangeListener
public interface IFrequencyChangeListener
{
public void frequencyChanged( FrequencyChangeEvent event );
public Listener<FrequencyChangeEvent> getFrequencyChangeListener();
}

View File

@@ -0,0 +1,6 @@
package source.tuner.frequency;
public interface IFrequencyChangeProcessor
{
public void frequencyChanged( FrequencyChangeEvent event );
}

View File

@@ -0,0 +1,9 @@
package source.tuner.frequency;
import sample.Listener;
public interface IFrequencyChangeProvider
{
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener );
public void removeFrequencyChangeListener();
}

View File

@@ -1,8 +0,0 @@
package source.tuner.frequency;
public interface IFrequencyCorrectionController
{
public boolean hasFrequencyCorrectionControl();
public FrequencyCorrectionControl getFrequencyCorrectionControl();
}

View File

@@ -1,104 +0,0 @@
package source.tuner.hackrf;
/*******************************************************************************
* 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/>
******************************************************************************/
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.tuner.hackrf.HackRFTunerController.Serial;
public class HackRFInformationPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( HackRFInformationPanel.class );
private HackRFTunerController mController;
/**
* Displays HackRF firmware, serial number and part identifier
*/
public HackRFInformationPanel( HackRFTunerController controller )
{
mController = controller;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2",
"[right,grow][grow]",
"[][][][grow]" ) );
Serial serial = null;
try
{
serial = mController.getSerial();
}
catch( Exception e )
{
mLog.error( "couldn't read HackRF serial number", e );
}
if( serial != null )
{
add( new JLabel( "Serial:" ) );
add( new JLabel( serial.getSerialNumber() ) );
add( new JLabel( "Part:" ) );
add( new JLabel( serial.getPartID() ) );
}
else
{
add( new JLabel( "Serial:" ) );
add( new JLabel( "Unknown" ) );
add( new JLabel( "Part:" ) );
add( new JLabel( "Unknown" ) );
}
String firmware = null;
try
{
firmware = mController.getFirmwareVersion();
}
catch( Exception e )
{
mLog.error( "couldn't read HackRF firmware version", e );
}
add( new JLabel( "Firmware:" ) );
if( firmware != null )
{
add( new JLabel( firmware ) );
}
else
{
add( new JLabel( "Unknown" ) );
}
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,8 +19,6 @@ package source.tuner.hackrf;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.JPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,26 +29,22 @@ import source.tuner.Tuner;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelSource;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerEvent;
import source.tuner.TunerType;
import source.tuner.hackrf.HackRFTunerController.BoardID;
import controller.ResourceManager;
import controller.ThreadPoolManager;
public class HackRFTuner extends Tuner
{
private final static Logger mLog = LoggerFactory.getLogger( HackRFTuner.class );
private HackRFTunerController mController;
public HackRFTuner( HackRFTunerController controller ) throws SourceException
{
super( "HackRF" );
mController = controller;
/* Register for frequency/sample rate changes */
mController.addListener( this );
super( "HackRF", controller );
}
public HackRFTunerController getController()
{
return (HackRFTunerController)getTunerController();
}
public void dispose()
@@ -58,11 +52,6 @@ public class HackRFTuner extends Tuner
//TODO: dispose of something here
}
public HackRFTunerController getController()
{
return mController;
}
@Override
public TunerClass getTunerClass()
{
@@ -75,41 +64,24 @@ public class HackRFTuner extends Tuner
return TunerType.HACKRF;
}
@Override
public JPanel getEditor( ResourceManager resourceManager )
{
return new HackRFTunerEditorPanel( this, resourceManager );
}
@Override
public void apply( TunerConfiguration config ) throws SourceException
{
mController.apply( config );
}
@Override
public int getSampleRate()
{
return mController.getSampleRate();
}
@Override
public double getSampleSize()
{
return 11.0;
}
@Override
public long getFrequency() throws SourceException
{
return mController.getFrequency();
}
@Override
public TunerChannelSource getChannel( TunerChannel channel )
throws RejectedExecutionException, SourceException
{
return mController.getChannel( this, channel );
TunerChannelSource source = getController().getChannel( this, channel );
if( source != null )
{
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
}
return source;
}
@Override
@@ -121,7 +93,7 @@ public class HackRFTuner extends Tuner
/* Tell the controller to release the channel and cleanup */
if( source != null )
{
mController.releaseChannel( source );
getController().releaseChannel( source );
}
}
@@ -130,7 +102,7 @@ public class HackRFTuner extends Tuner
{
try
{
return mController.getSerial().getSerialNumber();
return getController().getSerial().getSerialNumber();
}
catch( Exception e )
{
@@ -143,12 +115,12 @@ public class HackRFTuner extends Tuner
@Override
public void addListener( Listener<ComplexBuffer> listener )
{
mController.addListener( listener );
getController().addListener( listener );
}
@Override
public void removeListener( Listener<ComplexBuffer> listener )
{
mController.removeListener( listener );
getController().removeListener( listener );
}
}

View File

@@ -20,8 +20,8 @@ package source.tuner.hackrf;
import javax.xml.bind.annotation.XmlAttribute;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.hackrf.HackRFTunerController.HackRFLNAGain;
import source.tuner.hackrf.HackRFTunerController.HackRFSampleRate;
import source.tuner.hackrf.HackRFTunerController.HackRFVGAGain;
@@ -39,12 +39,11 @@ public class HackRFTunerConfiguration extends TunerConfiguration
*/
public HackRFTunerConfiguration()
{
this( "Default" );
}
public HackRFTunerConfiguration( String name )
public HackRFTunerConfiguration( String uniqueID, String name )
{
super( name );
super( uniqueID, name );
}
@Override

View File

@@ -1,562 +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.hackrf;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
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 source.SourceException;
import source.tuner.TunerConfiguration;
import source.tuner.TunerConfigurationAssignment;
import source.tuner.TunerType;
import source.tuner.hackrf.HackRFTunerController.HackRFLNAGain;
import source.tuner.hackrf.HackRFTunerController.HackRFSampleRate;
import source.tuner.hackrf.HackRFTunerController.HackRFVGAGain;
import controller.ResourceManager;
public class HackRFTunerConfigurationPanel extends JPanel
{
private final static Logger mLog =
LoggerFactory.getLogger( HackRFTunerConfigurationPanel.class );
private static final long serialVersionUID = 1L;
private ResourceManager mResourceManager;
private HackRFTunerController mController;
private HackRFTunerConfiguration mSelectedConfig;
private JButton mNewConfiguration;
private JButton mDeleteConfiguration;
private JComboBox<HackRFTunerConfiguration> mComboConfigurations;
private JTextField mName;
private JSpinner mFrequencyCorrection;
private JToggleButton mAmplifier;
private JComboBox<HackRFLNAGain> mComboLNAGain;
private JComboBox<HackRFVGAGain> mComboVGAGain;
private JComboBox<HackRFSampleRate> mComboSampleRate;
public HackRFTunerConfigurationPanel( ResourceManager resourceManager,
HackRFTunerController controller )
{
mResourceManager = resourceManager;
mController = controller;
init();
}
/**
* Initializes the gui components
*/
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[grow,right][grow]", "[][][][][][][grow]" ) );
/**
* Tuner configuration selector
*/
mComboConfigurations = new JComboBox<HackRFTunerConfiguration>();
mComboConfigurations.setModel( getModel() );
/* Determine which tuner configuration should be selected/displayed */
TunerConfigurationAssignment savedConfig = null;
String serial = null;
try
{
serial = mController.getSerial().getSerialNumber();
}
catch ( UsbException e2 )
{
mLog.error( "couldn't read hackrf serial number", e2 );
}
if( serial != null )
{
savedConfig = mResourceManager
.getSettingsManager().getSelectedTunerConfiguration(
TunerType.HACKRF, 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.HACKRF,
serial, mSelectedConfig );
}
}
mComboConfigurations.setSelectedItem( mSelectedConfig );
mComboConfigurations.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
HackRFTunerConfiguration selected =
(HackRFTunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
update( selected );
}
}
});
add( new JLabel( "Config:" ) );
add( mComboConfigurations, "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, "growx,push" );
/**
* Frequency Correction
*/
SpinnerModel model =
new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.setValue( mSelectedConfig.getFrequencyCorrection() );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
final double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
mController.setFrequencyCorrection( value );
mSelectedConfig.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog(
HackRFTunerConfigurationPanel.this,
"HackRF Tuner Controller - couldn't apply "
+ "frequency correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply "
+ "frequency correction value: " + value, e1 );
}
}
} );
}
} );
add( new JLabel( "Correction PPM:" ) );
add( mFrequencyCorrection, "growx,push" );
/**
* Sample Rate
*/
mComboSampleRate = new JComboBox<>( HackRFSampleRate.values() );
mComboSampleRate.setSelectedItem( mSelectedConfig.getSampleRate() );
mComboSampleRate.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
HackRFSampleRate sampleRate =
(HackRFSampleRate)mComboSampleRate.getSelectedItem();
try
{
mController.setSampleRate( sampleRate );
mSelectedConfig.setSampleRate( sampleRate );
save();
}
catch ( UsbException e2 )
{
JOptionPane.showMessageDialog(
HackRFTunerConfigurationPanel.this,
"HackRF Tuner Controller - couldn't apply the sample "
+ "rate setting [" + sampleRate.getLabel() + "] " +
e2.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply sample "
+ "rate setting [" + sampleRate.getLabel() + "]", e );
}
}
} );
add( new JLabel( "Sample Rate:" ) );
add( mComboSampleRate, "growx,push" );
/**
* Gain Controls
*/
JPanel gainPanel = new JPanel();
gainPanel.setLayout( new MigLayout( "",
"[][right][grow,fill][right][grow,fill]", "[grow,fill]" ) );
gainPanel.setBorder( BorderFactory.createTitledBorder( "Gain" ) );
/* Amplifier */
mAmplifier = new JToggleButton( "Amp" );
mAmplifier.setSelected( mSelectedConfig.getAmplifierEnabled() );
mAmplifier.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
mController.setAmplifierEnabled( mAmplifier.isSelected() );
mSelectedConfig.setAmplifierEnabled( mAmplifier.isSelected() );
save();
}
catch ( UsbException e )
{
mLog.error( "couldn't enable/disable amplifier", e );
mAmplifier.setEnabled( !mAmplifier.isSelected() );
JOptionPane.showMessageDialog(
HackRFTunerConfigurationPanel.this,
"Couldn't change amplifier setting",
"Error changing amplifier setting",
JOptionPane.ERROR_MESSAGE );
}
}
} );
gainPanel.add( mAmplifier );
/* LNA Gain Control */
mComboLNAGain = new JComboBox<HackRFLNAGain>( HackRFLNAGain.values() );
mComboLNAGain.setSelectedItem( mSelectedConfig.getLNAGain() );
mComboLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
HackRFLNAGain lnaGain =
(HackRFLNAGain)mComboLNAGain.getSelectedItem();
if ( lnaGain == null )
{
lnaGain = HackRFLNAGain.GAIN_0;
}
if( mComboLNAGain.isEnabled() )
{
mController.setLNAGain( lnaGain );
}
mSelectedConfig.setLNAGain( lnaGain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog(
HackRFTunerConfigurationPanel.this,
"HackRF Tuner Controller - couldn't apply the LNA "
+ "gain setting - " + e.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply LNA "
+ "gain setting - ", e );
}
}
} );
mComboLNAGain.setToolTipText( "<html>LNA Gain. Adjust to set "
+ "the IF gain</html>" );
gainPanel.add( new JLabel( "LNA" ) );
gainPanel.add( mComboLNAGain );
/* VGA Gain Control */
mComboVGAGain = new JComboBox<HackRFVGAGain>( HackRFVGAGain.values() );
mComboVGAGain.setSelectedItem( mSelectedConfig.getVGAGain() );
mComboVGAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
HackRFVGAGain vgaGain = (HackRFVGAGain)mComboVGAGain.getSelectedItem();
if( vgaGain == null )
{
vgaGain = HackRFVGAGain.GAIN_4;
}
if( mComboVGAGain.isEnabled() )
{
mController.setVGAGain( vgaGain );
}
mSelectedConfig.setVGAGain( vgaGain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog(
HackRFTunerConfigurationPanel.this,
"HackRF Tuner Controller - couldn't apply the VGA "
+ "gain setting - " + e.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply VGA "
+ "gain setting", e );
}
}
} );
mComboVGAGain.setToolTipText( "<html>VGA Gain. Adjust to set the "
+ "baseband gain</html>" );
gainPanel.add( new JLabel( "VGA" ) );
gainPanel.add( mComboVGAGain, "wrap" );
add( gainPanel, "span,growx" );
/**
* Create a new configuration
*/
mNewConfiguration = new JButton( "New" );
mNewConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
TunerConfiguration config =
mResourceManager.getSettingsManager()
.addNewTunerConfiguration(
TunerType.HACKRF,
"New Configuration" );
mComboConfigurations.setModel( getModel() );
mComboConfigurations.setSelectedItem( config );
repaint();
}
} );
add( mNewConfiguration, "growx,push" );
/**
* Delete the currently selected configuration
*/
mDeleteConfiguration = new JButton( "Delete" );
mDeleteConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
HackRFTunerConfiguration selected =
(HackRFTunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
int n = JOptionPane.showConfirmDialog(
HackRFTunerConfigurationPanel.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, "growx,push,wrap" );
}
/**
* Updates gui controls with the values from the tuner configuration
* @param config - tuner configuration
*/
private void update( HackRFTunerConfiguration config )
{
mSelectedConfig = config;
try
{
mController.apply( config );
mName.setText( config.getName() );
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
mComboLNAGain.setSelectedItem( mSelectedConfig.getLNAGain() );
mComboVGAGain.setSelectedItem( mSelectedConfig.getVGAGain() );
mComboSampleRate.setSelectedItem( mSelectedConfig.getSampleRate() );
mResourceManager.getSettingsManager().setSelectedTunerConfiguration(
TunerType.HACKRF, mController.getSerial().getSerialNumber(), config );
}
catch ( UsbException | SourceException e1 )
{
JOptionPane.showMessageDialog(
HackRFTunerConfigurationPanel.this,
"HackRF Tuner Controller - couldn't "
+ "apply the tuner configuration settings - " +
e1.getLocalizedMessage() );
mLog.error( "HackRF 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<HackRFTunerConfiguration> getModel()
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.HACKRF );
DefaultComboBoxModel<HackRFTunerConfiguration> model =
new DefaultComboBoxModel<HackRFTunerConfiguration>();
for( TunerConfiguration config: configs )
{
model.addElement( (HackRFTunerConfiguration)config );
}
return model;
}
/**
* Retrieves a specific (named) tuner configuration
*/
private HackRFTunerConfiguration getNamedConfiguration( String name )
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.HACKRF );
for( TunerConfiguration config: configs )
{
if( config.getName().contentEquals( name ) )
{
return (HackRFTunerConfiguration)config;
}
}
return null;
}
/**
* Saves current tuner configuration settings
*/
private void save()
{
mResourceManager.getSettingsManager().save();
}
}

View File

@@ -1,4 +1,3 @@
package source.tuner.hackrf;
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
@@ -52,12 +51,13 @@ package source.tuner.hackrf;
* 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.hackrf;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -81,8 +81,8 @@ import sample.Listener;
import sample.adapter.ByteSampleAdapter;
import sample.complex.ComplexBuffer;
import source.SourceException;
import source.tuner.TunerConfiguration;
import source.tuner.TunerController;
import source.tuner.configuration.TunerConfiguration;
import controller.ThreadPoolManager;
import controller.ThreadPoolManager.ThreadType;
@@ -92,7 +92,7 @@ public class HackRFTunerController extends TunerController
private final static Logger mLog =
LoggerFactory.getLogger( HackRFTunerController.class );
public final static long USB_TIMEOUT_MS = 1000000l; //uSeconds
public final static long USB_TIMEOUT_US = 1000000l; //uSeconds
public static final byte USB_ENDPOINT = (byte)0x81;
public static final byte USB_INTERFACE = (byte)0x0;
@@ -395,7 +395,7 @@ public class HackRFTunerController extends TunerController
(short)value,
(short)index,
buffer,
USB_TIMEOUT_MS );
USB_TIMEOUT_US );
if( transferred < 0 )
{
@@ -468,7 +468,7 @@ public class HackRFTunerController extends TunerController
(short)value,
(short)index,
buffer,
USB_TIMEOUT_MS );
USB_TIMEOUT_US );
if( transferred < 0 )
{
@@ -887,8 +887,8 @@ public class HackRFTunerController extends TunerController
*/
public void addListener( Listener<ComplexBuffer> listener )
{
synchronized( mComplexBufferBroadcaster )
{
synchronized ( mComplexBufferBroadcaster )
{
mComplexBufferBroadcaster.addListener( listener );
if( mBufferProcessor == null || !mBufferProcessor.isRunning() )
@@ -901,7 +901,7 @@ public class HackRFTunerController extends TunerController
thread.start();
}
}
}
}
/**
@@ -910,15 +910,15 @@ public class HackRFTunerController extends TunerController
*/
public void removeListener( Listener<ComplexBuffer> listener )
{
synchronized( mComplexBufferBroadcaster )
{
synchronized ( mComplexBufferBroadcaster )
{
mComplexBufferBroadcaster.removeListener( listener );
if( !mComplexBufferBroadcaster.hasListeners() )
{
mBufferProcessor.stop();
}
}
}
}
/**
@@ -928,12 +928,12 @@ public class HackRFTunerController extends TunerController
public class BufferProcessor implements Runnable, TransferCallback
{
private ScheduledFuture<?> mSampleDispatcherTask;
private AtomicBoolean mRunning = new AtomicBoolean();
private LinkedTransferQueue<Transfer> mAvailableTransfers;
private LinkedTransferQueue<Transfer> mTransfersInProgress = new LinkedTransferQueue<>();
private AtomicBoolean mRunning = new AtomicBoolean();
private ByteBuffer mLibUsbHandlerStatus;
private boolean mCancel = false;
@Override
public void run()
{
@@ -955,23 +955,23 @@ public class HackRFTunerController extends TunerController
{
mAvailableTransfers.drainTo( transfers );
for( Transfer transfer: transfers )
{
int result = LibUsb.submitTransfer( transfer );
if( result == LibUsb.SUCCESS )
{
mTransfersInProgress.add( transfer );
}
else
{
mLog.error( "error submitting transfer [" +
LibUsb.errorName( result ) + "]" );
}
}
for( Transfer transfer: transfers )
{
int result = LibUsb.submitTransfer( transfer );
if( result == LibUsb.SUCCESS )
{
mTransfersInProgress.add( transfer );
}
else
{
mLog.error( "error submitting transfer [" +
LibUsb.errorName( result ) + "]" );
}
}
int result = LibUsb.handleEventsTimeoutCompleted(
null, USB_TIMEOUT_MS, mLibUsbHandlerStatus.asIntBuffer() );
null, USB_TIMEOUT_US, mLibUsbHandlerStatus.asIntBuffer() );
if( result != LibUsb.SUCCESS )
{
@@ -990,16 +990,16 @@ public class HackRFTunerController extends TunerController
LibUsb.cancelTransfer( transfer );
}
int result = LibUsb.handleEventsTimeoutCompleted(
null, USB_TIMEOUT_MS, mLibUsbHandlerStatus.asIntBuffer() );
int result = LibUsb.handleEventsTimeoutCompleted( null,
USB_TIMEOUT_US, mLibUsbHandlerStatus.asIntBuffer() );
if( result != LibUsb.SUCCESS )
{
mLog.error( "error cancelling transfers in progress" );
}
mLibUsbHandlerStatus.rewind();
}
{
mLog.error( "error cancelling transfers in progress" );
}
mLibUsbHandlerStatus.rewind();
}
}
}
@@ -1089,7 +1089,7 @@ public class HackRFTunerController extends TunerController
ByteBuffer.allocateDirect( mBufferSize );
LibUsb.fillBulkTransfer( transfer, mDeviceHandle,USB_ENDPOINT,
buffer, BufferProcessor.this, "Buffer", USB_TIMEOUT_MS );
buffer, BufferProcessor.this, "Buffer", USB_TIMEOUT_US );
mAvailableTransfers.add( transfer );
}

View File

@@ -0,0 +1,464 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner.hackrf;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
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 source.SourceException;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.configuration.TunerConfigurationEditor;
import source.tuner.configuration.TunerConfigurationEvent;
import source.tuner.configuration.TunerConfigurationEvent.Event;
import source.tuner.configuration.TunerConfigurationModel;
import source.tuner.hackrf.HackRFTunerController.BoardID;
import source.tuner.hackrf.HackRFTunerController.HackRFLNAGain;
import source.tuner.hackrf.HackRFTunerController.HackRFSampleRate;
import source.tuner.hackrf.HackRFTunerController.HackRFVGAGain;
import source.tuner.hackrf.HackRFTunerController.Serial;
public class HackRFTunerEditor extends TunerConfigurationEditor
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( HackRFTunerEditor.class );
private JTextField mConfigurationName;
private JButton mTunerInfo;
private JComboBox<HackRFSampleRate> mComboSampleRate;
private JSpinner mFrequencyCorrection;
private JToggleButton mAmplifier;
private JComboBox<HackRFLNAGain> mComboLNAGain;
private JComboBox<HackRFVGAGain> mComboVGAGain;
private boolean mLoading;
private HackRFTunerController mController;
public HackRFTunerEditor( TunerConfigurationModel tunerConfigurationModel, HackRFTuner tuner )
{
super( tunerConfigurationModel );
mController = tuner.getController();
init();
}
private HackRFTunerConfiguration getConfiguration()
{
if( hasItem() )
{
return (HackRFTunerConfiguration)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
"[][][][][][][grow]" ) );
add( new JLabel( "HackRF Tuner Configuration" ), "span,align center" );
mConfigurationName = new JTextField();
mConfigurationName.setEnabled( false );
mConfigurationName.addFocusListener( new FocusListener()
{
@Override
public void focusLost( FocusEvent e )
{
save();
}
@Override
public void focusGained( FocusEvent e ) {}
} );
add( new JLabel( "Name:" ) );
add( mConfigurationName, "span 2" );
mTunerInfo = new JButton( "Tuner Info" );
mTunerInfo.setEnabled( false );
mTunerInfo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
JOptionPane.showMessageDialog( HackRFTunerEditor.this, getTunerInfo(),
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( mTunerInfo );
mComboSampleRate = new JComboBox<>( HackRFSampleRate.values() );
mComboSampleRate.setEnabled( false );
mComboSampleRate.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
HackRFSampleRate sampleRate =
(HackRFSampleRate)mComboSampleRate.getSelectedItem();
try
{
mController.setSampleRate( sampleRate );
save();
}
catch ( UsbException e2 )
{
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
+ " - couldn't apply the sample rate setting [" + sampleRate.getLabel() +
"] " + e2.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply sample rate setting [" +
sampleRate.getLabel() + "]", e );
}
}
} );
add( new JLabel( "Sample Rate:" ) );
add( mComboSampleRate );
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
mFrequencyCorrection.setEnabled( false );
JSpinner.NumberEditor editor = (JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
final double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
try
{
mController.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
+ " - couldn't apply frequency correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply frequency correction "
+ "value: " + value, e1 );
}
}
} );
add( new JLabel( "PPM:" ) );
add( mFrequencyCorrection );
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
add( new JLabel( "Gain" ) );
add( new JLabel( "" ), "span 2" ); //filler
mAmplifier = new JToggleButton( "Amplifier" );
mAmplifier.setEnabled( false );
mAmplifier.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
mController.setAmplifierEnabled( mAmplifier.isSelected() );
save();
}
catch ( UsbException e )
{
mLog.error( "couldn't enable/disable amplifier", e );
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "Couldn't change amplifier setting",
"Error changing amplifier setting", JOptionPane.ERROR_MESSAGE );
}
}
} );
add( mAmplifier );
mComboLNAGain = new JComboBox<HackRFLNAGain>( HackRFLNAGain.values() );
mComboLNAGain.setEnabled( false );
mComboLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
HackRFLNAGain lnaGain = (HackRFLNAGain)mComboLNAGain.getSelectedItem();
if ( lnaGain == null )
{
lnaGain = HackRFLNAGain.GAIN_0;
}
mController.setLNAGain( lnaGain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
+ " - couldn't apply the LNA gain setting - " + e.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply LNA gain setting - ", e );
}
}
} );
mComboLNAGain.setToolTipText( "<html>LNA Gain. Adjust to set the IF gain</html>" );
add( new JLabel( "LNA:" ) );
add( mComboLNAGain );
mComboVGAGain = new JComboBox<HackRFVGAGain>( HackRFVGAGain.values() );
mComboVGAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
HackRFVGAGain vgaGain = (HackRFVGAGain)mComboVGAGain.getSelectedItem();
if( vgaGain == null )
{
vgaGain = HackRFVGAGain.GAIN_4;
}
mController.setVGAGain( vgaGain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
+ " - couldn't apply the VGA gain setting - " + e.getLocalizedMessage() );
mLog.error( "HackRF Tuner Controller - couldn't apply VGA gain setting", e );
}
}
} );
mComboVGAGain.setToolTipText( "<html>VGA Gain. Adjust to set the baseband gain</html>" );
add( new JLabel( "VGA:" ) );
add( mComboVGAGain );
}
/**
* Sets each of the tuner configuration controls to the enabled argument state
*/
private void setControlsEnabled( boolean enabled )
{
if( mConfigurationName.isEnabled() != enabled )
{
mConfigurationName.setEnabled( enabled );
}
if( mTunerInfo.isEnabled() != enabled )
{
mTunerInfo.setEnabled( enabled );
}
if( mFrequencyCorrection.isEnabled() != enabled )
{
mFrequencyCorrection.setEnabled( enabled );
}
if( mComboSampleRate.isEnabled() != enabled )
{
mComboSampleRate.setEnabled( enabled );
}
if( mAmplifier.isEnabled() != enabled )
{
mAmplifier.setEnabled( enabled );
}
if( mComboLNAGain.isEnabled() != enabled )
{
mComboLNAGain.setEnabled( enabled );
}
if( mComboVGAGain.isEnabled() != enabled )
{
mComboVGAGain.setEnabled( enabled );
}
}
private String getTunerInfo()
{
BoardID board = BoardID.INVALID;
try
{
board = mController.getBoardID();
}
catch ( UsbException e )
{
mLog.error( "couldn't read HackRF board identifier", e );
}
StringBuilder sb = new StringBuilder();
sb.append( "<html><h3>HackRF Tuner</h3>" );
sb.append( "<b>Board: </b>" );
sb.append( board.getLabel() );
sb.append( "<br>" );
Serial serial = null;
try
{
serial = mController.getSerial();
}
catch( Exception e )
{
mLog.error( "couldn't read HackRF serial number", e );
}
if( serial != null )
{
sb.append( "<b>Serial: </b>" );
sb.append( serial.getSerialNumber() );
sb.append( "<br>" );
sb.append( "<b>Part: </b>" );
sb.append( serial.getPartID() );
sb.append( "<br>" );
}
else
{
sb.append( "<b>Serial: Unknown</b><br>" );
sb.append( "<b>Part: Unknown</b><br>" );
}
String firmware = null;
try
{
firmware = mController.getFirmwareVersion();
}
catch( Exception e )
{
mLog.error( "couldn't read HackRF firmware version", e );
}
if( firmware != null )
{
sb.append( "<b>Firmware: </b>" );
sb.append( firmware );
sb.append( "<br>" );
}
else
{
sb.append( "<b>Firmware: Unknown</b><br>" );
}
return sb.toString();
}
@Override
public void setItem( TunerConfiguration tunerConfiguration )
{
super.setItem( tunerConfiguration );
//Toggle loading so that we don't fire a change event and schedule a settings file save
mLoading = true;
if( hasItem() )
{
HackRFTunerConfiguration config = getConfiguration();
if( tunerConfiguration.isAssigned() )
{
setControlsEnabled( true );
mConfigurationName.setText( config.getName() );
mComboSampleRate.setSelectedItem( config.getSampleRate() );
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
mAmplifier.setSelected( config.getAmplifierEnabled() );
mComboLNAGain.setSelectedItem( config.getLNAGain() );
mComboVGAGain.setSelectedItem( config.getVGAGain() );
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( config.getName() );
}
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( "" );
}
mLoading = false;
}
@Override
public void save()
{
if( hasItem() && !mLoading )
{
HackRFTunerConfiguration config = getConfiguration();
config.setName( mConfigurationName.getText() );
double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
config.setFrequencyCorrection( value );
config.setSampleRate( (HackRFSampleRate)mComboSampleRate.getSelectedItem() );
config.setAmplifierEnabled( mAmplifier.isSelected() );
config.setLNAGain( (HackRFLNAGain)mComboLNAGain.getSelectedItem() );
config.setVGAGain( (HackRFVGAGain)mComboVGAGain.getSelectedItem() );
getTunerConfigurationModel().broadcast(
new TunerConfigurationEvent( getConfiguration(), Event.CHANGE ) );
}
}
}

View File

@@ -1,125 +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.hackrf;
import gui.control.JFrequencyControl;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.usb.UsbException;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.hackrf.HackRFTunerController.BoardID;
import com.jidesoft.swing.JideTabbedPane;
import controller.ResourceManager;
public class HackRFTunerEditorPanel extends JPanel
implements FrequencyChangeListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( HackRFTunerEditorPanel.class );
private JFrequencyControl mFrequencyControl;
private HackRFTuner mTuner;
private HackRFTunerController mController;
private ResourceManager mResourceManager;
public HackRFTunerEditorPanel( HackRFTuner tuner,
ResourceManager resourceManager )
{
mTuner = tuner;
mController = mTuner.getController();
mResourceManager = resourceManager;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2",
"[right,grow][grow]",
"[][][][][][grow]" ) );
BoardID board = BoardID.INVALID;
try
{
board = mTuner.getController().getBoardID();
}
catch ( UsbException e )
{
mLog.error( "couldn't read HackRF board identifier", e );
}
add( new JLabel( board.getLabel() ), "span,align center" );
mFrequencyControl = new JFrequencyControl();
mFrequencyControl.addListener( this );
/* Add frequency control as frequency change listener. This creates a
* feedback loop, so the control does not rebroadcast the event */
mTuner.addListener( mFrequencyControl );
mFrequencyControl.setFrequency( mController.getFrequency(), false );
add( mFrequencyControl, "span,align center" );
JideTabbedPane tabs = new JideTabbedPane();
tabs.setFont( this.getFont() );
tabs.setForeground( Color.BLACK );
add( tabs, "span,grow,push" );
tabs.add( "Config", new HackRFTunerConfigurationPanel(
mResourceManager, mTuner.getController() ) );
tabs.add( "Info", new HackRFInformationPanel( mTuner.getController() ) );
}
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
if( event.getEvent() == Event.FREQUENCY_CHANGE_NOTIFICATION )
{
try
{
mController.setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
mLog.error( "error setting frequency [" + event.getValue().longValue() + "]", e );
}
}
}
}

View File

@@ -1,76 +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.rtl;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import source.tuner.rtl.RTL2832TunerController.Descriptor;
public class RTL2832InfoPanel extends JPanel
{
RTL2832TunerController mController;
public RTL2832InfoPanel( RTL2832TunerController controller )
{
mController = controller;
init();
}
public void dispose()
{
mController = null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][][][][grow]" ) );
Descriptor descriptor = mController.getDescriptor();
add( new JLabel( "RTL-2832 EEPROM Descriptor" ), "span,align center" );
if( descriptor == null )
{
add( new JLabel( "No descriptor" ), "wrap" ) ;
}
else
{
add( new JLabel( "USB ID:" ) ) ;
add( new JLabel( descriptor.getVendorID() + ":" +
descriptor.getProductID() ), "wrap" ) ;
add( new JLabel( "Vendor:" ) ) ;
add( new JLabel( descriptor.getVendorLabel() ), "wrap" ) ;
add( new JLabel( "Product:" ) ) ;
add( new JLabel( descriptor.getProductLabel() ), "wrap" ) ;
add( new JLabel( "Serial:" ) ) ;
add( new JLabel( descriptor.getSerial() ), "wrap" ) ;
add( new JLabel( "IR Enabled:" ) ) ;
add( new JLabel( ( descriptor.irEnabled() ? "Yes" : "No" ) ), "wrap" ) ;
add( new JLabel( "Remote Wake:" ) ) ;
add( new JLabel( ( descriptor.remoteWakeupEnabled() ? "Yes" : "No" ) ), "wrap" ) ;
}
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,8 +19,6 @@ package source.tuner.rtl;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.JPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.usb4java.LibUsbException;
@@ -32,11 +30,9 @@ import source.tuner.Tuner;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelSource;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerEvent;
import source.tuner.TunerType;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.rtl.RTL2832TunerController.SampleRate;
import controller.ResourceManager;
public class RTL2832Tuner extends Tuner
{
@@ -44,19 +40,16 @@ public class RTL2832Tuner extends Tuner
LoggerFactory.getLogger( RTL2832Tuner.class );
private TunerClass mTunerClass;
protected RTL2832TunerController mController;
public RTL2832Tuner( TunerClass tunerClass,
RTL2832TunerController controller )
throws SourceException
{
super( tunerClass.getVendorDeviceLabel() + "/" +
controller.getTunerType().getLabel() + " #" +
controller.getUniqueID() );
controller.getTunerType().getLabel() + " " +
controller.getUniqueID(), controller );
mTunerClass = tunerClass;
mController = controller;
mController.addListener( (FrequencyChangeListener)this );
}
public void dispose()
@@ -66,13 +59,13 @@ public class RTL2832Tuner extends Tuner
public RTL2832TunerController getController()
{
return mController;
return (RTL2832TunerController)getTunerController();
}
@Override
public String getUniqueID()
{
return mController.getUniqueID();
return getController().getUniqueID();
}
@Override
@@ -84,41 +77,14 @@ public class RTL2832Tuner extends Tuner
@Override
public TunerType getTunerType()
{
return mController.getTunerType();
}
@Override
public JPanel getEditor( ResourceManager resourceManager )
{
return mController.getEditor( resourceManager );
}
@Override
public void apply( TunerConfiguration config ) throws SourceException
{
mController.apply( config );
}
@Override
public int getSampleRate()
{
try
{
return mController.getCurrentSampleRate();
}
catch( SourceException e )
{
mLog.error( "RTL2832 Tuner - couldn't get sample rate", e );
}
return 0;
return getController().getTunerType();
}
public void setSampleRate( SampleRate sampleRate ) throws SourceException
{
try
{
mController.setSampleRate( sampleRate );
getController().setSampleRate( sampleRate );
}
catch( LibUsbException e )
{
@@ -135,26 +101,26 @@ public class RTL2832Tuner extends Tuner
return 11.0;
}
@Override
public long getFrequency() throws SourceException
{
return mController.getFrequency();
}
public void setFrequency( int frequency ) throws SourceException
{
mController.setFrequency( frequency );
getController().setFrequency( frequency );
}
@Override
public TunerChannelSource getChannel( TunerChannel channel )
throws RejectedExecutionException, SourceException
throws RejectedExecutionException,
SourceException
{
TunerChannelSource source = null;
try
{
source = mController.getChannel( this, channel );
source = getController().getChannel( this, channel );
if( source != null )
{
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
}
}
catch( Exception e )
{
@@ -163,6 +129,7 @@ public class RTL2832Tuner extends Tuner
return source;
}
/**
* Releases the tuned channel so that the tuner controller can tune to
* other frequencies as needed.
@@ -176,19 +143,19 @@ public class RTL2832Tuner extends Tuner
/* Tell the controller to release the channel and cleanup */
if( source != null )
{
mController.releaseChannel( source );
getController().releaseChannel( source );
}
}
@Override
public void addListener( Listener<ComplexBuffer> listener )
{
mController.addListener( listener );
getController().addListener( listener );
}
@Override
public void removeListener( Listener<ComplexBuffer> listener )
{
mController.removeListener( listener );
getController().removeListener( listener );
}
}

View File

@@ -34,7 +34,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.JPanel;
import javax.usb.UsbDisconnectedException;
import javax.usb.UsbException;
@@ -56,7 +55,6 @@ import source.SourceException;
import source.tuner.TunerController;
import source.tuner.TunerType;
import buffer.FloatAveragingBuffer;
import controller.ResourceManager;
import controller.ThreadPoolManager;
import controller.ThreadPoolManager.ThreadType;
@@ -113,8 +111,6 @@ public abstract class RTL2832TunerController extends TunerController
private SampleRateMonitor mSampleRateMonitor;
private AtomicInteger mSampleCounter = new AtomicInteger();
private double mSampleRateAverageSum;
private int mSampleRateAverageCount;
private static final DecimalFormat mDecimalFormatter =
new DecimalFormat( "###,###,###.0" );
private static final DecimalFormat mPercentFormatter =
@@ -149,6 +145,7 @@ public abstract class RTL2832TunerController extends TunerController
mDevice = device;
mDeviceDescriptor = deviceDescriptor;
}
public void init() throws SourceException
{
@@ -362,8 +359,6 @@ public abstract class RTL2832TunerController extends TunerController
}
}
public abstract JPanel getEditor( ResourceManager resourceManager );
public abstract void setSampleRateFilters( int sampleRate )
throws SourceException;
@@ -977,7 +972,7 @@ public abstract class RTL2832TunerController extends TunerController
return mSampleRate.getRate();
}
public int getSampleRate() throws SourceException
public int getSampleRateFromTuner() throws SourceException
{
try
{
@@ -1426,17 +1421,17 @@ public abstract class RTL2832TunerController extends TunerController
{
mLog.error( "NPE! = tpm null: " + ( mThreadPoolManager == null ), npe );
}
mLibUsbHandlerStatus = ByteBuffer.allocateDirect( 4 );
List<Transfer> transfers = new ArrayList<>();
mCancel = false;
while( mRunning.get() )
while( mRunning.get() )
{
mAvailableTransfers.drainTo( transfers );
for( Transfer transfer: transfers )
{
int result = LibUsb.submitTransfer( transfer );
@@ -1453,7 +1448,7 @@ public abstract class RTL2832TunerController extends TunerController
}
int result = LibUsb.handleEventsTimeoutCompleted(
null, TIMEOUT_US, mLibUsbHandlerStatus.asIntBuffer() );
null, TIMEOUT_US, mLibUsbHandlerStatus.asIntBuffer() );
if( result != LibUsb.SUCCESS )
{
@@ -1472,21 +1467,17 @@ public abstract class RTL2832TunerController extends TunerController
LibUsb.cancelTransfer( transfer );
}
int result = LibUsb.handleEventsTimeoutCompleted(
null, TIMEOUT_US, mLibUsbHandlerStatus.asIntBuffer() );
if( result != LibUsb.SUCCESS )
{
mLog.error( "error handling events for libusb" );
}
mLibUsbHandlerStatus.rewind();
int result = LibUsb.handleEventsTimeoutCompleted( null,
TIMEOUT_US, mLibUsbHandlerStatus.asIntBuffer() );
if( result != LibUsb.SUCCESS )
{
mLog.error( "error handling events for libusb during cancel" );
}
mLibUsbHandlerStatus.rewind();
}
}
else
{
mLog.error( "Couldn't start buffer processor - already running!" );
}
}
/**
@@ -1516,7 +1507,7 @@ public abstract class RTL2832TunerController extends TunerController
}
@Override
public void processTransfer( Transfer transfer )
public void processTransfer( Transfer transfer )
{
mTransfersInProgress.remove( transfer );
@@ -1636,6 +1627,79 @@ public abstract class RTL2832TunerController extends TunerController
}
}
public class USBEventHandlingThread implements Runnable
{
/** If thread should abort. */
private volatile boolean mAbort;
/**
* Aborts the event handling thread.
*/
public void abort()
{
mAbort = true;
}
@Override
public void run()
{
while ( !mAbort )
{
int result = LibUsb.handleEventsTimeout( null, 1000 );
if ( result != LibUsb.SUCCESS )
{
mAbort = true;
mLog.error( "error handling usb events [" +
LibUsb.errorName( result ) + "]" );
throw new LibUsbException("Unable to handle USB "
+ "events", result );
}
}
}
}
public enum TunerTypeCheck
{
E4K( 0xC8, 0x02, 0x40 ),
FC0012( 0xC6, 0x00, 0xA1 ),
FC0013( 0xC6, 0x00, 0xA3 ),
FC2580( 0xAC, 0x01, 0x56 ),
R820T( 0x34, 0x00, 0x69 ),
R828D( 0x74, 0x00, 0x69 );
private int mI2CAddress;
private int mCheckAddress;
private int mCheckValue;
private TunerTypeCheck( int i2c, int address, int value )
{
mI2CAddress = i2c;
mCheckAddress = address;
mCheckValue = value;
}
public byte getI2CAddress()
{
return (byte)mI2CAddress;
}
public byte getCheckAddress()
{
return (byte)mCheckAddress;
}
public byte getCheckValue()
{
return (byte)mCheckValue;
}
}
/**
* Averages the sample rate over a 10-second period. The count is for the
* number of bytes received from the tuner. There are two bytes for each
@@ -1730,7 +1794,6 @@ public abstract class RTL2832TunerController extends TunerController
}
}
}
/**
* RTL2832 EEPROM byte array descriptor parsing class
*/
@@ -1901,74 +1964,4 @@ public abstract class RTL2832TunerController extends TunerController
}
}
public class USBEventHandlingThread implements Runnable
{
/** If thread should abort. */
private volatile boolean mAbort;
/**
* Aborts the event handling thread.
*/
public void abort()
{
mAbort = true;
}
@Override
public void run()
{
while ( !mAbort )
{
int result = LibUsb.handleEventsTimeout( null, 1000 );
if ( result != LibUsb.SUCCESS )
{
mAbort = true;
mLog.error( "error handling usb events [" +
LibUsb.errorName( result ) + "]" );
throw new LibUsbException("Unable to handle USB "
+ "events", result );
}
}
}
}
public enum TunerTypeCheck
{
E4K( 0xC8, 0x02, 0x40 ),
FC0012( 0xC6, 0x00, 0xA1 ),
FC0013( 0xC6, 0x00, 0xA3 ),
FC2580( 0xAC, 0x01, 0x56 ),
R820T( 0x34, 0x00, 0x69 ),
R828D( 0x74, 0x00, 0x69 );
private int mI2CAddress;
private int mCheckAddress;
private int mCheckValue;
private TunerTypeCheck( int i2c, int address, int value )
{
mI2CAddress = i2c;
mCheckAddress = address;
mCheckValue = value;
}
public byte getI2CAddress()
{
return (byte)mI2CAddress;
}
public byte getCheckAddress()
{
return (byte)mCheckAddress;
}
public byte getCheckValue()
{
return (byte)mCheckValue;
}
}
}

View File

@@ -1,28 +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.rtl;
public enum RTL2832TunerType
{
E4000,
FC0012,
FC0013,
R820T,
R828D,
UNKNOWN;
}

View File

@@ -19,8 +19,8 @@ package source.tuner.rtl.e4k;
import javax.xml.bind.annotation.XmlAttribute;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.rtl.RTL2832TunerController.SampleRate;
import source.tuner.rtl.e4k.E4KTunerController.E4KEnhanceGain;
import source.tuner.rtl.e4k.E4KTunerController.E4KGain;
@@ -29,24 +29,23 @@ import source.tuner.rtl.e4k.E4KTunerController.E4KMixerGain;
public class E4KTunerConfiguration extends TunerConfiguration
{
private E4KGain mMasterGain = E4KGain.AUTOMATIC;
private E4KMixerGain mMixerGain = E4KMixerGain.AUTOMATIC;
private E4KLNAGain mLNAGain = E4KLNAGain.AUTOMATIC;
private E4KEnhanceGain mEnhanceGain = E4KEnhanceGain.AUTOMATIC;
private double mFrequencyCorrection = 8.9d;
private SampleRate mSampleRate = SampleRate.RATE_1_920MHZ;
private E4KGain mMasterGain = E4KGain.MANUAL;
private E4KMixerGain mMixerGain = E4KMixerGain.GAIN_4;
private E4KLNAGain mLNAGain = E4KLNAGain.GAIN_PLUS_200;
private E4KEnhanceGain mEnhanceGain = E4KEnhanceGain.GAIN_3;
private double mFrequencyCorrection = 0.0d;
private SampleRate mSampleRate = SampleRate.RATE_2_400MHZ;
/**
* Default constructor for JAXB
*/
public E4KTunerConfiguration()
{
this( "Default" );
}
public E4KTunerConfiguration( String name )
public E4KTunerConfiguration( String uniqueID, String name )
{
super( name );
super( uniqueID, name );
}
@Override

View File

@@ -1,691 +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.rtl.e4k;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
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 source.tuner.rtl.RTL2832TunerController.SampleRate;
import source.tuner.rtl.e4k.E4KTunerController.E4KEnhanceGain;
import source.tuner.rtl.e4k.E4KTunerController.E4KGain;
import source.tuner.rtl.e4k.E4KTunerController.E4KLNAGain;
import source.tuner.rtl.e4k.E4KTunerController.E4KMixerGain;
import controller.ResourceManager;
public class E4KTunerConfigurationPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( E4KTunerConfigurationPanel.class );
private ResourceManager mResourceManager;
private E4KTunerController mController;
private E4KTunerConfiguration mSelectedConfig;
private JButton mNewConfiguration;
private JButton mDeleteConfiguration;
private JComboBox<E4KTunerConfiguration> mComboConfigurations;
private JTextField mName;
private JSpinner mFrequencyCorrection;
private JSpinner mSampleRateCorrection;
private JComboBox<E4KGain> mComboMasterGain;
private JComboBox<E4KMixerGain> mComboMixerGain;
private JComboBox<E4KLNAGain> mComboLNAGain;
private JComboBox<E4KEnhanceGain> mComboEnhanceGain;
private JComboBox<SampleRate> mComboSampleRate;
public E4KTunerConfigurationPanel( ResourceManager resourceManager,
E4KTunerController controller )
{
mResourceManager = resourceManager;
mController = controller;
init();
}
/**
* Initializes the gui components
*/
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[grow,right][grow]", "[][][][][][][grow]" ) );
/**
* Tuner configuration selector
*/
mComboConfigurations = new JComboBox<E4KTunerConfiguration>();
mComboConfigurations.setModel( getModel() );
/* Determine which tuner configuration should be selected/displayed */
TunerConfigurationAssignment savedConfig = mResourceManager
.getSettingsManager().getSelectedTunerConfiguration(
TunerType.ELONICS_E4000, mController.getUniqueID() );
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
mResourceManager.getSettingsManager()
.setSelectedTunerConfiguration(
TunerType.ELONICS_E4000,
mController.getUniqueID(), mSelectedConfig );
}
mComboConfigurations.setSelectedItem( mSelectedConfig );
mComboConfigurations.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
E4KTunerConfiguration selected =
(E4KTunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
update( selected );
}
}
});
add( new JLabel( "Config:" ) );
add( mComboConfigurations, "growx,push" );
/**
* Tuner Configuration Name
*/
add( new JLabel( "Name:" ) );
mName = new JTextField();
mName.setText( mSelectedConfig.getName() );
mName.addFocusListener( new FocusListener()
{
@Override
public void focusLost( FocusEvent e )
{
/* Update the config name */
mSelectedConfig.setName( mName.getText() );
/* Reset this named config as the assigned config for this
* tuner */
mResourceManager.getSettingsManager()
.setSelectedTunerConfiguration(
TunerType.ELONICS_E4000,
mController.getUniqueID(), mSelectedConfig );
save();
}
@Override
public void focusGained( FocusEvent e ) {}
} );
add( mName, "growx,push" );
/**
* Frequency Correction
*/
SpinnerModel model =
new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.setValue( mSelectedConfig.getFrequencyCorrection() );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
final double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
mController.setFrequencyCorrection( value );
mSelectedConfig.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog(
E4KTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't apply "
+ "frequency correction value: " + value +
e1.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply "
+ "frequency correction value: " + value, e1 );
}
}
} );
}
} );
add( new JLabel( "Correction PPM:" ) );
add( mFrequencyCorrection, "growx,push" );
/**
* Sample Rate
*/
mComboSampleRate = new JComboBox<>( SampleRate.values() );
mComboSampleRate.setSelectedItem( mSelectedConfig.getSampleRate() );
mComboSampleRate.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
SampleRate sampleRate =
(SampleRate)mComboSampleRate.getSelectedItem();
try
{
mController.setSampleRate( sampleRate );
mSelectedConfig.setSampleRate( sampleRate );
save();
}
catch ( SourceException | LibUsbException eSampleRate )
{
JOptionPane.showMessageDialog(
E4KTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't apply the sample "
+ "rate setting [" + sampleRate.getLabel() + "] " +
eSampleRate.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply sample "
+ "rate setting [" + sampleRate.getLabel() + "]",
eSampleRate );
}
}
} );
add( new JLabel( "Sample Rate:" ) );
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(
// E4KTunerConfigurationPanel.this,
// "E4K Tuner Controller - couldn't apply "
// + "sample rate correction value: " + value +
// e1.getLocalizedMessage() );
//
// Log.error( "E4K Tuner Controller - couldn't apply "
// + "sample rate correction value: " + value +
// e1.getLocalizedMessage() );
// }
// }
// } );
// }
// } );
//
// add( mSampleRateCorrection );
// add( new JLabel( "Sample Rate Correction (ppm)" ), "wrap" );
/**
* Gain Controls
*/
JPanel gainPanel = new JPanel();
gainPanel.setLayout( new MigLayout( "fill", "[right][left][right][left]", "" ) );
gainPanel.setBorder( BorderFactory.createTitledBorder( "Gain" ) );
/* Master Gain Control */
mComboMasterGain = new JComboBox<E4KGain>( E4KGain.values() );
mComboMasterGain.setSelectedItem( mSelectedConfig.getMasterGain() );
mComboMasterGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
E4KGain gain = (E4KGain)mComboMasterGain.getSelectedItem();
mController.setGain( (E4KGain)mComboMasterGain.getSelectedItem(), true );
if( gain == E4KGain.MANUAL )
{
mComboMixerGain.setSelectedItem(
mController.getMixerGain( true ) );
mComboMixerGain.setEnabled( true );
mComboLNAGain.setSelectedItem(
mController.getLNAGain( true ) );
mComboLNAGain.setEnabled( true );
mComboEnhanceGain.setEnabled( true );
mComboEnhanceGain.setSelectedItem(
mController.getEnhanceGain( true ) );
}
else
{
mComboMixerGain.setEnabled( false );
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
mComboLNAGain.setEnabled( false );
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
mComboEnhanceGain.setEnabled( false );
mComboEnhanceGain.setSelectedItem( gain.getEnhanceGain() );
}
mSelectedConfig.setMasterGain( gain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog(
E4KTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't apply the gain "
+ "setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply "
+ "gain setting", e );
}
}
} );
mComboMasterGain.setToolTipText( "<html>Select <b>AUTOMATIC</b> for auto "
+ "gain, <b>MANUAL</b> to enable<br> independent control of "
+ "<i>Mixer</i>, <i>LNA</i> and <i>Enhance</i> gain<br>"
+ "settings, or one of the individual gain settings for<br>"
+ "semi-manual gain control</html>" );
gainPanel.add( new JLabel( "Master" ) );
gainPanel.add( mComboMasterGain );
/* Mixer Gain Control */
mComboMixerGain = new JComboBox<E4KMixerGain>( E4KMixerGain.values() );
mComboMixerGain.setSelectedItem( mSelectedConfig.getMixerGain() );
mComboMixerGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
E4KMixerGain mixerGain =
(E4KMixerGain)mComboMixerGain.getSelectedItem();
if( mComboMixerGain.isEnabled() )
{
mController.setMixerGain( mixerGain, true );
}
mSelectedConfig.setMixerGain( mixerGain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog(
E4KTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't apply the mixer "
+ "gain setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply mixer "
+ "gain setting", e );
}
}
} );
}
} );
mComboMixerGain.setToolTipText( "<html>Mixer Gain. Set master gain "
+ "to <b>MASTER</b> to enable adjustment</html>" );
mComboMixerGain.setEnabled( false );
gainPanel.add( new JLabel( "Mixer" ) );
gainPanel.add( mComboMixerGain, "wrap" );
/* LNA Gain Control */
mComboLNAGain = new JComboBox<E4KLNAGain>( E4KLNAGain.values() );
mComboLNAGain.setSelectedItem( mSelectedConfig.getLNAGain() );
mComboLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
E4KLNAGain lnaGain = (E4KLNAGain)mComboLNAGain.getSelectedItem();
if( mComboLNAGain.isEnabled() )
{
mController.setLNAGain( lnaGain, true );
}
mSelectedConfig.setLNAGain( lnaGain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog(
E4KTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't apply the LNA "
+ "gain setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply LNA "
+ "gain setting - ", e );
}
}
} );
mComboLNAGain.setToolTipText( "<html>LNA Gain. Set master gain "
+ "to <b>MANUAL</b> to enable adjustment</html>" );
mComboLNAGain.setEnabled( false );
gainPanel.add( new JLabel( "LNA" ) );
gainPanel.add( mComboLNAGain );
/* Enhance Gain Control */
mComboEnhanceGain = new JComboBox<E4KEnhanceGain>( E4KEnhanceGain.values() );
mComboEnhanceGain.setSelectedItem( mSelectedConfig.getEnhanceGain() );
mComboEnhanceGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
E4KEnhanceGain enhanceGain =
(E4KEnhanceGain)mComboEnhanceGain.getSelectedItem();
if( mComboEnhanceGain.isEnabled() )
{
mController.setEnhanceGain( enhanceGain, true );
}
mSelectedConfig.setEnhanceGain( enhanceGain );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog(
E4KTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't apply the enhance "
+ "gain setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply enhance "
+ "gain setting", e );
}
}
} );
mComboEnhanceGain.setToolTipText( "<html>Enhance Gain. Set master gain "
+ "to <b>MANUAL</b> to enable adjustment</html>" );
mComboEnhanceGain.setEnabled( false );
gainPanel.add( new JLabel( "Enhance" ) );
gainPanel.add( mComboEnhanceGain, "wrap" );
add( gainPanel, "span,grow,push" );
/**
* Create a new configuration
*/
mNewConfiguration = new JButton( "New" );
mNewConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
TunerConfiguration config =
mResourceManager.getSettingsManager()
.addNewTunerConfiguration(
TunerType.ELONICS_E4000,
"New Configuration" );
mComboConfigurations.setModel( getModel() );
mComboConfigurations.setSelectedItem( config );
repaint();
}
} );
add( mNewConfiguration, "growx,push" );
/**
* Delete the currently selected configuration
*/
mDeleteConfiguration = new JButton( "Delete" );
mDeleteConfiguration.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
E4KTunerConfiguration selected =
(E4KTunerConfiguration)mComboConfigurations
.getItemAt( mComboConfigurations.getSelectedIndex() );
if( selected != null )
{
int n = JOptionPane.showConfirmDialog(
E4KTunerConfigurationPanel.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, "growx,push,wrap" );
}
/**
* Updates gui controls with the values from the tuner configuration
* @param config - tuner configuration
*/
private void update( E4KTunerConfiguration config )
{
mSelectedConfig = config;
try
{
mController.apply( config );
mName.setText( config.getName() );
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
mComboMixerGain.setSelectedItem( mSelectedConfig.getMixerGain() );
mComboLNAGain.setSelectedItem( mSelectedConfig.getLNAGain() );
mComboEnhanceGain.setSelectedItem( mSelectedConfig.getEnhanceGain() );
/* Apply master gain last so that the Mixer, LNA, and Enhance gain
* settings are updated with the master setting where necessary */
mComboMasterGain.setSelectedItem( mSelectedConfig.getMasterGain() );
mComboSampleRate.setSelectedItem( mSelectedConfig.getSampleRate() );
mResourceManager.getSettingsManager().setSelectedTunerConfiguration(
TunerType.ELONICS_E4000, mController.getUniqueID(), config );
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog(
E4KTunerConfigurationPanel.this,
"E4K Tuner Controller - couldn't "
+ "apply the tuner configuration settings - " +
e1.getLocalizedMessage() );
mLog.error( "E4K 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<E4KTunerConfiguration> getModel()
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.ELONICS_E4000 );
DefaultComboBoxModel<E4KTunerConfiguration> model =
new DefaultComboBoxModel<E4KTunerConfiguration>();
for( TunerConfiguration config: configs )
{
model.addElement( (E4KTunerConfiguration)config );
}
return model;
}
/**
* Retrieves a specific (named) tuner configuration
*/
private E4KTunerConfiguration getNamedConfiguration( String name )
{
ArrayList<TunerConfiguration> configs =
mResourceManager.getSettingsManager()
.getTunerConfigurations( TunerType.ELONICS_E4000 );
for( TunerConfiguration config: configs )
{
if( config.getName().contentEquals( name ) )
{
return (E4KTunerConfiguration)config;
}
}
return null;
}
/**
* Saves current tuner configuration settings
*/
private void save()
{
mResourceManager.getSettingsManager().save();
}
}

View File

@@ -19,7 +19,6 @@ package source.tuner.rtl.e4k;
import java.util.Arrays;
import javax.swing.JPanel;
import javax.usb.UsbException;
import org.slf4j.Logger;
@@ -31,10 +30,9 @@ import org.usb4java.LibUsb;
import org.usb4java.LibUsbException;
import source.SourceException;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
import source.tuner.configuration.TunerConfiguration;
import source.tuner.rtl.RTL2832TunerController;
import controller.ResourceManager;
import controller.ThreadPoolManager;
public class E4KTunerController extends RTL2832TunerController
@@ -110,8 +108,6 @@ public class E4KTunerController extends RTL2832TunerController
public static final byte CHFCALIB_CMD = (byte)0x01;
private E4KTunerEditorPanel mEditor;
public E4KTunerController( Device device,
DeviceDescriptor deviceDescriptor,
ThreadPoolManager threadPoolManager )
@@ -252,16 +248,6 @@ public class E4KTunerController extends RTL2832TunerController
}
}
public JPanel getEditor( ResourceManager resourceManager )
{
if( mEditor == null )
{
mEditor = new E4KTunerEditorPanel( this, resourceManager );
}
return mEditor;
}
/**
* Sets the IF filters (mixer, channel and RC) to the correct filter setting
* for the selected bandwidth/sample rate
@@ -1070,7 +1056,7 @@ public class E4KTunerController extends RTL2832TunerController
(byte)( ( temp & ~mask ) | ( value & mask ) ),
controlI2CRepeater );
int temp2 = readE4KRegister( register, controlI2CRepeater );
readE4KRegister( register, controlI2CRepeater );
}
}

View File

@@ -0,0 +1,499 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package source.tuner.rtl.e4k;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
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.configuration.TunerConfiguration;
import source.tuner.configuration.TunerConfigurationEditor;
import source.tuner.configuration.TunerConfigurationEvent;
import source.tuner.configuration.TunerConfigurationModel;
import source.tuner.rtl.RTL2832Tuner;
import source.tuner.rtl.RTL2832TunerController.Descriptor;
import source.tuner.rtl.RTL2832TunerController.SampleRate;
import source.tuner.rtl.e4k.E4KTunerController.E4KEnhanceGain;
import source.tuner.rtl.e4k.E4KTunerController.E4KGain;
import source.tuner.rtl.e4k.E4KTunerController.E4KLNAGain;
import source.tuner.rtl.e4k.E4KTunerController.E4KMixerGain;
public class E4KTunerEditor extends TunerConfigurationEditor
{
private final static Logger mLog = LoggerFactory.getLogger( E4KTunerEditor.class );
private static final long serialVersionUID = 1L;
private JTextField mConfigurationName;
private JButton mTunerInfo;
private JComboBox<SampleRate> mComboSampleRate;
private JSpinner mFrequencyCorrection;
private JComboBox<E4KGain> mComboMasterGain;
private JComboBox<E4KMixerGain> mComboMixerGain;
private JComboBox<E4KLNAGain> mComboLNAGain;
private JComboBox<E4KEnhanceGain> mComboEnhanceGain;
private E4KTunerController mController;
private boolean mLoading;
public E4KTunerEditor( TunerConfigurationModel tunerConfigurationModel, RTL2832Tuner tuner )
{
super( tunerConfigurationModel );
mController = (E4KTunerController)tuner.getController();
init();
}
private E4KTunerConfiguration getConfiguration()
{
if( hasItem() )
{
return (E4KTunerConfiguration)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
"[][][][][][][][grow]" ) );
add( new JLabel( "E4000 Tuner Configuration" ), "span,align center" );
/**
* Tuner Configuration Name
*/
add( new JLabel( "Name:" ) );
mConfigurationName = new JTextField();
mConfigurationName.setEnabled( false );
mConfigurationName.addFocusListener( new FocusListener()
{
@Override
public void focusLost( FocusEvent e )
{
save();
}
@Override
public void focusGained( FocusEvent e ) {}
} );
add( mConfigurationName, "span 2" );
mTunerInfo = new JButton( "Tuner Info" );
mTunerInfo.setEnabled( false );
mTunerInfo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
JOptionPane.showMessageDialog( E4KTunerEditor.this, getTunerInfo(),
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( mTunerInfo );
mComboSampleRate = new JComboBox<>( SampleRate.values() );
mComboSampleRate.setEnabled( false );
mComboSampleRate.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
SampleRate sampleRate = (SampleRate)mComboSampleRate.getSelectedItem();
try
{
mController.setSampleRate( sampleRate );
save();
}
catch ( SourceException | LibUsbException eSampleRate )
{
JOptionPane.showMessageDialog( E4KTunerEditor.this,
"E4K Tuner Controller - couldn't apply the sample rate setting [" +
sampleRate.getLabel() + "] " + eSampleRate.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply sample rate setting [" +
sampleRate.getLabel() + "]", eSampleRate );
}
}
} );
add( new JLabel( "Sample Rate:" ) );
add( mComboSampleRate );
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
-1000.0, //min
1000.0, //max
0.1 ); //step
mFrequencyCorrection = new JSpinner( model );
mFrequencyCorrection.setEnabled( false );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits( 1 );
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mFrequencyCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
final double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
try
{
mController.setFrequencyCorrection( value );
save();
}
catch ( SourceException e1 )
{
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
+ "couldn't apply frequency correction value: " + value + e1.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply frequency correction value:"
+ value, e1 );
}
}
} );
add( new JLabel( "PPM:" ) );
add( mFrequencyCorrection );
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
add( new JLabel( "Gain" ), "wrap" );
mComboMasterGain = new JComboBox<E4KGain>( E4KGain.values() );
mComboMasterGain.setEnabled( false );
mComboMasterGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
E4KGain gain = (E4KGain)mComboMasterGain.getSelectedItem();
mController.setGain( (E4KGain)mComboMasterGain.getSelectedItem(), true );
if( gain == E4KGain.MANUAL )
{
mComboMixerGain.setSelectedItem( mController.getMixerGain( true ) );
mComboMixerGain.setEnabled( true );
mComboLNAGain.setSelectedItem( mController.getLNAGain( true ) );
mComboLNAGain.setEnabled( true );
mComboEnhanceGain.setSelectedItem( mController.getEnhanceGain( true ) );
mComboEnhanceGain.setEnabled( true );
}
else
{
mComboMixerGain.setEnabled( false );
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
mComboLNAGain.setEnabled( false );
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
mComboEnhanceGain.setEnabled( false );
mComboEnhanceGain.setSelectedItem( gain.getEnhanceGain() );
}
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
+ "couldn't apply the gain setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply gain setting", e );
}
}
} );
mComboMasterGain.setToolTipText( "<html>Select <b>AUTOMATIC</b> for auto "
+ "gain, <b>MANUAL</b> to enable<br> independent control of "
+ "<i>Mixer</i>, <i>LNA</i> and <i>Enhance</i> gain<br>"
+ "settings, or one of the individual gain settings for<br>"
+ "semi-manual gain control</html>" );
add( new JLabel( "Master:" ) );
add( mComboMasterGain );
mComboMixerGain = new JComboBox<E4KMixerGain>( E4KMixerGain.values() );
mComboMixerGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
E4KMixerGain mixerGain = (E4KMixerGain)mComboMixerGain.getSelectedItem();
mController.setMixerGain( mixerGain, true );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
+ "couldn't apply the mixer gain setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply mixer gain setting", e );
}
}
} );
mComboMixerGain.setToolTipText( "<html>Mixer Gain. Set master gain "
+ "to <b>MASTER</b> to enable adjustment</html>" );
mComboMixerGain.setEnabled( false );
add( new JLabel( "Mixer:" ) );
add( mComboMixerGain );
mComboLNAGain = new JComboBox<E4KLNAGain>( E4KLNAGain.values() );
mComboLNAGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
E4KLNAGain lnaGain = (E4KLNAGain)mComboLNAGain.getSelectedItem();
mController.setLNAGain( lnaGain, true );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
+ "couldn't apply the LNA gain setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply LNA gain setting - ", e );
}
}
} );
mComboLNAGain.setToolTipText( "<html>LNA Gain. Set master gain "
+ "to <b>MANUAL</b> to enable adjustment</html>" );
mComboLNAGain.setEnabled( false );
add( new JLabel( "LNA:" ) );
add( mComboLNAGain );
mComboEnhanceGain = new JComboBox<E4KEnhanceGain>( E4KEnhanceGain.values() );
mComboEnhanceGain.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
try
{
E4KEnhanceGain enhance = (E4KEnhanceGain)mComboEnhanceGain.getSelectedItem();
mController.setEnhanceGain( enhance, true );
save();
}
catch ( UsbException e )
{
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
+ "couldn't apply the enhance gain setting - " + e.getLocalizedMessage() );
mLog.error( "E4K Tuner Controller - couldn't apply enhance gain setting", e );
}
}
} );
mComboEnhanceGain.setToolTipText( "<html>Enhance Gain. Set master gain "
+ "to <b>MANUAL</b> to enable adjustment</html>" );
mComboEnhanceGain.setEnabled( false );
add( new JLabel( "Enhance:" ) );
add( mComboEnhanceGain );
}
/**
* Sets each of the tuner configuration controls to the enabled argument state
*/
private void setControlsEnabled( boolean enabled )
{
if( mConfigurationName.isEnabled() != enabled )
{
mConfigurationName.setEnabled( enabled );
}
if( mTunerInfo.isEnabled() != enabled )
{
mTunerInfo.setEnabled( enabled );
}
if( mFrequencyCorrection.isEnabled() != enabled )
{
mFrequencyCorrection.setEnabled( enabled );
}
if( mComboSampleRate.isEnabled() != enabled )
{
mComboSampleRate.setEnabled( enabled );
}
if( mComboMasterGain.isEnabled() != enabled )
{
mComboMasterGain.setEnabled( enabled );
}
if( mComboMixerGain.isEnabled() != enabled )
{
mComboMixerGain.setEnabled( enabled );
}
if( mComboLNAGain.isEnabled() != enabled )
{
mComboLNAGain.setEnabled( enabled );
}
if( mComboEnhanceGain.isEnabled() != enabled )
{
mComboEnhanceGain.setEnabled( enabled );
}
}
private String getTunerInfo()
{
StringBuilder sb = new StringBuilder();
Descriptor descriptor = mController.getDescriptor();
sb.append( "<html><h3>RTL-2832 with E4000 Tuner</h3>" );
if( descriptor == null )
{
sb.append( "No EEPROM Descriptor Available" );
}
else
{
sb.append( "<b>USB ID: </b>" );
sb.append( descriptor.getVendorID() );
sb.append( ":" );
sb.append( descriptor.getProductID() );
sb.append( "<br>" );
sb.append( "<b>Vendor: </b>" );
sb.append( descriptor.getVendorLabel() );
sb.append( "<br>" );
sb.append( "<b>Product: </b>" );
sb.append( descriptor.getProductLabel() );
sb.append( "<br>" );
sb.append( "<b>Serial: </b>" );
sb.append( descriptor.getSerial() );
sb.append( "<br>" );
sb.append( "<b>IR Enabled: </b>" );
sb.append( descriptor.irEnabled() );
sb.append( "<br>" );
sb.append( "<b>Remote Wake: </b>" );
sb.append( descriptor.remoteWakeupEnabled() );
sb.append( "<br>" );
}
return sb.toString();
}
@Override
public void save()
{
if( hasItem() && !mLoading )
{
E4KTunerConfiguration config = getConfiguration();
config.setName( mConfigurationName.getText() );
config.setSampleRate( (SampleRate)mComboSampleRate.getSelectedItem() );
double value = ((SpinnerNumberModel)mFrequencyCorrection
.getModel()).getNumber().doubleValue();
config.setFrequencyCorrection( value );
config.setMasterGain( (E4KGain)mComboMasterGain.getSelectedItem() );
config.setMixerGain( (E4KMixerGain)mComboMixerGain.getSelectedItem() );
config.setLNAGain( (E4KLNAGain)mComboLNAGain.getSelectedItem() );
config.setEnhanceGain( (E4KEnhanceGain)mComboEnhanceGain.getSelectedItem() );
getTunerConfigurationModel().broadcast( new TunerConfigurationEvent(
getConfiguration(), TunerConfigurationEvent.Event.CHANGE ) );
}
}
@Override
public void setItem( TunerConfiguration tunerConfiguration )
{
super.setItem( tunerConfiguration );
//Toggle loading so that we don't fire a change event and schedule a settings file save
mLoading = true;
if( hasItem() )
{
E4KTunerConfiguration config = getConfiguration();
if( tunerConfiguration.isAssigned() )
{
setControlsEnabled( true );
mConfigurationName.setText( config.getName() );
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
mComboSampleRate.setSelectedItem( config.getSampleRate() );
mComboMasterGain.setSelectedItem( config.getMasterGain() );
mComboMixerGain.setSelectedItem( config.getMixerGain() );
mComboLNAGain.setSelectedItem( config.getLNAGain() );
mComboEnhanceGain.setSelectedItem( config.getEnhanceGain() );
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( config.getName() );
}
}
else
{
setControlsEnabled( false );
mConfigurationName.setText( "" );
}
mLoading = false;
}
}

View File

@@ -1,123 +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.rtl.e4k;
import gui.control.JFrequencyControl;
import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.rtl.RTL2832InfoPanel;
import com.jidesoft.swing.JideTabbedPane;
import controller.ResourceManager;
public class E4KTunerEditorPanel extends JPanel implements FrequencyChangeListener
{
private final static Logger mLog =
LoggerFactory.getLogger( E4KTunerEditorPanel.class );
private static final long serialVersionUID = 1L;
private E4KTunerController mController;
private ResourceManager mResourceManager;
private JFrequencyControl mFrequencyControl;
public E4KTunerEditorPanel( E4KTunerController controller,
ResourceManager resourceManager )
{
mController = controller;
mResourceManager = resourceManager;
initGUI();
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][grow]", "[][][grow]" ) );
add( new JLabel( "RTL2832 with E4000 Tuner" ), "span 2, align center, wrap" );
mFrequencyControl = new JFrequencyControl();
mFrequencyControl.addListener( this );
/* Add frequency control as listener on the controller, to maintain
* sync with the tuned frequency value */
mController.addListener( mFrequencyControl );
mFrequencyControl.setFrequency( mController.getFrequency(), false );
add( mFrequencyControl, "span 2, align center, wrap" );
JideTabbedPane tabs = new JideTabbedPane();
tabs.setFont( this.getFont() );
tabs.setForeground( Color.BLACK );
tabs.addTab( "Configuration",
new E4KTunerConfigurationPanel( mResourceManager, mController ) );
tabs.addTab( "Info", new RTL2832InfoPanel( mController ) );
add( tabs, "grow,push,span" );
}
/**
* Frequency change listener for the frequency control gui component to
* apply end-user requested frequency changes against the tuner
*/
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
if( event.getEvent() == Event.FREQUENCY_CHANGE_NOTIFICATION )
{
final long frequency = event.getValue().longValue();
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
try
{
mController.setFrequency( frequency );
}
catch ( SourceException e )
{
mLog.error( "E4KTunerController - error setting frequency [" +
frequency + "]", e );
}
}
} );
}
}
}

Some files were not shown because too many files have changed in this diff Show More