mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
Initial code check in continued
This commit is contained in:
27
src/source/BufferReceiver.java
Normal file
27
src/source/BufferReceiver.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public interface BufferReceiver {
|
||||
|
||||
/**
|
||||
* Method for receiving a buffer of bytes
|
||||
* @param buffer
|
||||
*/
|
||||
public void receive( byte[] buffer );
|
||||
}
|
||||
15
src/source/ComplexSource.java
Normal file
15
src/source/ComplexSource.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package source;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import sample.Provider;
|
||||
import sample.complex.ComplexSample;
|
||||
|
||||
public abstract class ComplexSource extends Source
|
||||
implements Provider<List<ComplexSample>>
|
||||
{
|
||||
public ComplexSource( String name )
|
||||
{
|
||||
super( name, SampleType.COMPLEX );
|
||||
}
|
||||
}
|
||||
44
src/source/EmptySourceEditor.java
Normal file
44
src/source/EmptySourceEditor.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public class EmptySourceEditor extends SourceEditor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public EmptySourceEditor( SourceConfiguration config )
|
||||
{
|
||||
super( config );
|
||||
|
||||
initGUI();
|
||||
}
|
||||
|
||||
public void reset() {}
|
||||
|
||||
public void save() {}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
JLabel selectLabel = new JLabel( "Please select a source" );
|
||||
add( selectLabel );
|
||||
}
|
||||
}
|
||||
12
src/source/FloatArraySource.java
Normal file
12
src/source/FloatArraySource.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package source;
|
||||
|
||||
import sample.Provider;
|
||||
import source.Source.SampleType;
|
||||
|
||||
public abstract class FloatArraySource extends Source implements Provider<Float[]>
|
||||
{
|
||||
public FloatArraySource( String name )
|
||||
{
|
||||
super( name, SampleType.FLOAT );
|
||||
}
|
||||
}
|
||||
11
src/source/FloatSource.java
Normal file
11
src/source/FloatSource.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package source;
|
||||
|
||||
import sample.Provider;
|
||||
|
||||
public abstract class FloatSource extends Source implements Provider<Float>
|
||||
{
|
||||
public FloatSource( String name )
|
||||
{
|
||||
super( name, SampleType.FLOAT );
|
||||
}
|
||||
}
|
||||
28
src/source/SampleProvider.java
Normal file
28
src/source/SampleProvider.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* 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.Source.SampleType;
|
||||
|
||||
public interface SampleProvider
|
||||
{
|
||||
/**
|
||||
* Real or Complex
|
||||
*/
|
||||
public abstract SampleType getSampleType();
|
||||
}
|
||||
56
src/source/Source.java
Normal file
56
src/source/Source.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Abstract class to define the minimum functionality of a sample data provider.
|
||||
*/
|
||||
public abstract class Source
|
||||
{
|
||||
protected String mName;
|
||||
protected SampleType mSampleType;
|
||||
|
||||
public enum SampleType { COMPLEX, FLOAT }
|
||||
|
||||
public Source( String name, SampleType sampleType )
|
||||
{
|
||||
mName = name;
|
||||
mSampleType = sampleType;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public abstract int getSampleRate() throws SourceException;
|
||||
|
||||
public abstract int getFrequency() throws SourceException;
|
||||
|
||||
public abstract void dispose();
|
||||
|
||||
public SampleType getSampleType()
|
||||
{
|
||||
return mSampleType;
|
||||
}
|
||||
|
||||
public void setSampleType( SampleType sampleType )
|
||||
{
|
||||
mSampleType = sampleType;
|
||||
}
|
||||
}
|
||||
119
src/source/SourceComponentEditor.java
Normal file
119
src/source/SourceComponentEditor.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*******************************************************************************
|
||||
* 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.BorderFactory;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JComboBox;
|
||||
|
||||
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 );
|
||||
|
||||
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( config );
|
||||
|
||||
//Add it to the jpanel
|
||||
add( mEditor, "span 2" );
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add( mComboSources, "wrap" );
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
38
src/source/SourceEditor.java
Normal file
38
src/source/SourceEditor.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public abstract class SourceEditor extends Editor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected SourceConfiguration mConfig;
|
||||
|
||||
public SourceEditor( SourceConfiguration config )
|
||||
{
|
||||
mConfig = config;
|
||||
}
|
||||
|
||||
public SourceConfiguration getConfig()
|
||||
{
|
||||
return mConfig;
|
||||
}
|
||||
}
|
||||
46
src/source/SourceEditorFactory.java
Normal file
46
src/source/SourceEditorFactory.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
* 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.tuner.TunerEditor;
|
||||
|
||||
public class SourceEditorFactory
|
||||
{
|
||||
public static SourceEditor getPanel( SourceConfiguration config )
|
||||
{
|
||||
SourceEditor configuredPanel;
|
||||
|
||||
switch( config.getSourceType() )
|
||||
{
|
||||
case MIXER:
|
||||
configuredPanel = new MixerEditor( config );
|
||||
break;
|
||||
case TUNER:
|
||||
configuredPanel = new TunerEditor( config );
|
||||
break;
|
||||
case NONE:
|
||||
default:
|
||||
configuredPanel = new EmptySourceEditor( config );
|
||||
break;
|
||||
}
|
||||
|
||||
return configuredPanel;
|
||||
}
|
||||
}
|
||||
33
src/source/SourceException.java
Normal file
33
src/source/SourceException.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public class SourceException extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SourceException( String message )
|
||||
{
|
||||
this( message, null );
|
||||
}
|
||||
|
||||
public SourceException( String message, Throwable cause )
|
||||
{
|
||||
super( message, cause );
|
||||
}
|
||||
}
|
||||
66
src/source/SourceManager.java
Normal file
66
src/source/SourceManager.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
* 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.mixer.MixerManager;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.ProcessingChain;
|
||||
|
||||
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 SourceManager( ResourceManager resourceManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
}
|
||||
|
||||
public Source getSource( ProcessingChain channel )
|
||||
{
|
||||
Source retVal = null;
|
||||
|
||||
if( channel != null )
|
||||
{
|
||||
switch( channel.getChannel()
|
||||
.getSourceConfiguration().getSourceType() )
|
||||
{
|
||||
case MIXER:
|
||||
retVal = MixerManager.getInstance().getSource( channel );
|
||||
break;
|
||||
case TUNER:
|
||||
retVal = mResourceManager.getTunerManager().getSource( channel );
|
||||
break;
|
||||
case NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
44
src/source/SourceType.java
Normal file
44
src/source/SourceType.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public enum SourceType
|
||||
{
|
||||
NONE( "No Source" ),
|
||||
MIXER( "Mixer/Sound Card" ),
|
||||
TUNER( "Tuner" );
|
||||
// WAVE( "Wave File" );
|
||||
|
||||
private String mDisplayString;
|
||||
|
||||
SourceType( String displayString )
|
||||
{
|
||||
mDisplayString = displayString;
|
||||
}
|
||||
|
||||
public String getDisplayString()
|
||||
{
|
||||
return mDisplayString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return mDisplayString;
|
||||
}
|
||||
}
|
||||
50
src/source/config/SourceConfigFactory.java
Normal file
50
src/source/config/SourceConfigFactory.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* 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.config;
|
||||
|
||||
import source.SourceType;
|
||||
|
||||
public class SourceConfigFactory
|
||||
{
|
||||
public static SourceConfiguration getDefaultSourceConfiguration()
|
||||
{
|
||||
return getSourceConfiguration( SourceType.NONE );
|
||||
}
|
||||
|
||||
public static SourceConfiguration
|
||||
getSourceConfiguration( SourceType source )
|
||||
{
|
||||
SourceConfiguration retVal;
|
||||
|
||||
switch( source )
|
||||
{
|
||||
case MIXER:
|
||||
retVal = new SourceConfigMixer();
|
||||
break;
|
||||
case TUNER:
|
||||
retVal = new SourceConfigTuner();
|
||||
break;
|
||||
case NONE:
|
||||
default:
|
||||
retVal = new SourceConfigNone();
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
73
src/source/config/SourceConfigMixer.java
Normal file
73
src/source/config/SourceConfigMixer.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* 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.config;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import source.SourceType;
|
||||
import source.mixer.MixerChannel;
|
||||
|
||||
public class SourceConfigMixer extends SourceConfiguration
|
||||
{
|
||||
protected String mMixer;
|
||||
protected MixerChannel mChannel = MixerChannel.LEFT; //default
|
||||
|
||||
public SourceConfigMixer()
|
||||
{
|
||||
super( SourceType.MIXER );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return getName();
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( mMixer );
|
||||
sb.append( "-" );
|
||||
sb.append( mChannel.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@XmlAttribute( name= "mixer" )
|
||||
public String getMixer()
|
||||
{
|
||||
return mMixer;
|
||||
}
|
||||
|
||||
public void setMixer( String mixer )
|
||||
{
|
||||
mMixer = mixer;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "channel" )
|
||||
public MixerChannel getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
public void setChannel( MixerChannel channel )
|
||||
{
|
||||
mChannel = channel;
|
||||
}
|
||||
}
|
||||
34
src/source/config/SourceConfigNone.java
Normal file
34
src/source/config/SourceConfigNone.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* 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.config;
|
||||
|
||||
import source.SourceType;
|
||||
|
||||
public class SourceConfigNone extends SourceConfiguration
|
||||
{
|
||||
public SourceConfigNone()
|
||||
{
|
||||
super( SourceType.NONE );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return "No Source";
|
||||
}
|
||||
}
|
||||
53
src/source/config/SourceConfigTuner.java
Normal file
53
src/source/config/SourceConfigTuner.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
* 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.config;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import source.SourceType;
|
||||
|
||||
public class SourceConfigTuner extends SourceConfiguration
|
||||
{
|
||||
private static DecimalFormat sFORMAT = new DecimalFormat( "0.00000" );
|
||||
|
||||
private int mFrequency = 0;
|
||||
|
||||
public SourceConfigTuner()
|
||||
{
|
||||
super( SourceType.TUNER );
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "frequency" )
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency( int frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return sFORMAT.format( (double)mFrequency / 1000000.0d ) + " MHz";
|
||||
}
|
||||
}
|
||||
59
src/source/config/SourceConfiguration.java
Normal file
59
src/source/config/SourceConfiguration.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*******************************************************************************
|
||||
* 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.config;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import source.SourceType;
|
||||
import controller.config.Configuration;
|
||||
|
||||
@XmlSeeAlso( { SourceConfigMixer.class, SourceConfigNone.class,
|
||||
SourceConfigTuner.class } )
|
||||
@XmlRootElement( name = "source_configuration" )
|
||||
public class SourceConfiguration extends Configuration
|
||||
{
|
||||
protected SourceType mSourceType;
|
||||
|
||||
public SourceConfiguration()
|
||||
{
|
||||
this( SourceType.NONE );
|
||||
}
|
||||
|
||||
public SourceConfiguration( SourceType source )
|
||||
{
|
||||
mSourceType = source;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "source_type" )
|
||||
public SourceType getSourceType()
|
||||
{
|
||||
return mSourceType;
|
||||
}
|
||||
|
||||
public void setSourceType( SourceType source )
|
||||
{
|
||||
mSourceType = source;
|
||||
}
|
||||
|
||||
public String getDescription()
|
||||
{
|
||||
return "No Source";
|
||||
}
|
||||
}
|
||||
85
src/source/mixer/ChannelShortAdapter.java
Normal file
85
src/source/mixer/ChannelShortAdapter.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*******************************************************************************
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import source.Source.SampleType;
|
||||
|
||||
/**
|
||||
* Converts 16-bit little endian byte data into an array of floats
|
||||
*/
|
||||
public class ChannelShortAdapter extends SampleAdapter
|
||||
{
|
||||
private ByteOrder mByteOrder = ByteOrder.LITTLE_ENDIAN;
|
||||
private MixerChannel mMixerChannel;
|
||||
|
||||
public ChannelShortAdapter( MixerChannel channel )
|
||||
{
|
||||
/* Only use with LEFT/RIGHT channels */
|
||||
assert( channel != MixerChannel.MONO );
|
||||
|
||||
mMixerChannel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float[] convert( byte[] samples )
|
||||
{
|
||||
Float[] processed = new Float[ samples.length / 4 ];
|
||||
|
||||
int pointer = 0;
|
||||
|
||||
/* Wrap byte array in a byte buffer so we can process them as shorts */
|
||||
ByteBuffer buffer = ByteBuffer.wrap( samples );
|
||||
|
||||
/* Set endian to correct byte ordering */
|
||||
buffer.order( mByteOrder );
|
||||
|
||||
while( buffer.hasRemaining() )
|
||||
{
|
||||
if( mMixerChannel == MixerChannel.LEFT )
|
||||
{
|
||||
processed[ pointer ] = (float)buffer.getShort();
|
||||
|
||||
/* Throw away the right channel */
|
||||
buffer.getShort();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Throw away the left channel */
|
||||
buffer.getShort();
|
||||
|
||||
processed[ pointer ] = (float)buffer.getShort();
|
||||
}
|
||||
|
||||
pointer++;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set byte interpretation to little or big endian. Defaults to LITTLE
|
||||
* endian
|
||||
*/
|
||||
public void setByteOrder( ByteOrder order )
|
||||
{
|
||||
mByteOrder = order;
|
||||
}
|
||||
}
|
||||
23
src/source/mixer/MixerChannel.java
Normal file
23
src/source/mixer/MixerChannel.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public enum MixerChannel
|
||||
{
|
||||
LEFT,RIGHT,MONO;
|
||||
}
|
||||
149
src/source/mixer/MixerEditor.java
Normal file
149
src/source/mixer/MixerEditor.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*******************************************************************************
|
||||
* 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.Set;
|
||||
|
||||
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;
|
||||
|
||||
public class MixerEditor extends SourceEditor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JComboBox<String> mComboMixers;
|
||||
private JComboBox<MixerChannel>mComboChannels;
|
||||
protected Mixer.Info mSelectedMixer = null;
|
||||
|
||||
|
||||
public MixerEditor( SourceConfiguration config )
|
||||
{
|
||||
super( config );
|
||||
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
JLabel mixerLabel = new JLabel( "Mixer:" );
|
||||
add( mixerLabel, "align right" );
|
||||
|
||||
mComboMixers = new JComboBox<String>();
|
||||
|
||||
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;
|
||||
|
||||
String mixer = mComboMixers.getItemAt( mComboMixers.getSelectedIndex() );
|
||||
|
||||
if( mixer != null )
|
||||
{
|
||||
config.setMixer( mixer );
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Set<String> mixers = MixerManager.getInstance().getMixers();
|
||||
String[] mixerStrings = mixers.toArray( new String[ mixers.size() ] );
|
||||
|
||||
mComboMixers.setModel(
|
||||
new DefaultComboBoxModel<String>( mixerStrings ) );
|
||||
|
||||
SourceConfigMixer config = (SourceConfigMixer)mConfig;
|
||||
String mixer = config.getMixer();
|
||||
|
||||
if( mixer != null && mixers.contains( mixer ) )
|
||||
{
|
||||
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.size() > 0 )
|
||||
{
|
||||
mComboMixers.setSelectedIndex( 0 );
|
||||
|
||||
config.setMixer( mComboMixers.getItemAt( 0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void resetChannels()
|
||||
{
|
||||
javax.swing.SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mComboChannels.setModel(
|
||||
new DefaultComboBoxModel<MixerChannel>( MixerChannel.values() ) );
|
||||
|
||||
MixerChannel channel = ((SourceConfigMixer)mConfig).getChannel();
|
||||
|
||||
mComboChannels.setSelectedItem( channel );
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
258
src/source/mixer/MixerManager.java
Normal file
258
src/source/mixer/MixerManager.java
Normal file
@@ -0,0 +1,258 @@
|
||||
/*******************************************************************************
|
||||
* 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.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.Line;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
|
||||
import log.Log;
|
||||
import source.config.SourceConfigMixer;
|
||||
import source.config.SourceConfiguration;
|
||||
import source.tuner.MixerTunerDataLine;
|
||||
import source.tuner.MixerTunerType;
|
||||
import controller.channel.ProcessingChain;
|
||||
|
||||
public class MixerManager
|
||||
{
|
||||
private static MixerManager sInstance = null;
|
||||
|
||||
private HashMap<String,TargetDataLine> mMixerLines =
|
||||
new HashMap<String,TargetDataLine>();
|
||||
|
||||
private HashMap<String,MixerTunerDataLine> mMixerTuners =
|
||||
new HashMap<String,MixerTunerDataLine>();
|
||||
|
||||
public static AudioFormat MONO = new AudioFormat( 48000, //SampleRate
|
||||
16, //Sample Size
|
||||
1, //Channels
|
||||
true, //Signed
|
||||
false ); //Little Endian
|
||||
|
||||
public static AudioFormat STEREO = new AudioFormat( 48000, //SampleRate
|
||||
16, //Sample Size
|
||||
2, //Channels
|
||||
true, //Signed
|
||||
false ); //Little Endian
|
||||
|
||||
private MixerManager()
|
||||
{
|
||||
loadMixers();
|
||||
}
|
||||
|
||||
public static MixerManager getInstance()
|
||||
{
|
||||
if( sInstance == null )
|
||||
{
|
||||
sInstance = new MixerManager();
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public MixerSource getSource( ProcessingChain channel )
|
||||
{
|
||||
MixerSource retVal = null;
|
||||
|
||||
SourceConfiguration config =
|
||||
channel.getChannel().getSourceConfiguration();
|
||||
|
||||
if( config instanceof SourceConfigMixer )
|
||||
{
|
||||
SourceConfigMixer mixerConfig = (SourceConfigMixer)config;
|
||||
|
||||
//Get the name of the requested mixer
|
||||
String mixerName = mixerConfig.getMixer();
|
||||
|
||||
if( mixerName != null )
|
||||
{
|
||||
TargetDataLine tdl = mMixerLines.get( mixerName );
|
||||
|
||||
if( tdl != null )
|
||||
{
|
||||
switch( mixerConfig.getChannel() )
|
||||
{
|
||||
case MONO:
|
||||
retVal = new MixerSource( mMixerLines.get( mixerName ),
|
||||
MONO,
|
||||
mixerName,
|
||||
new ShortAdapter() );
|
||||
break;
|
||||
case LEFT:
|
||||
case RIGHT:
|
||||
retVal = new MixerSource( mMixerLines.get( mixerName ),
|
||||
STEREO,
|
||||
mixerName,
|
||||
new ChannelShortAdapter( mixerConfig.getChannel() ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public Set<String> getMixers()
|
||||
{
|
||||
return mMixerLines.keySet();
|
||||
}
|
||||
|
||||
public Collection<MixerTunerDataLine> getMixerTunerDataLines()
|
||||
{
|
||||
return mMixerTuners.values();
|
||||
}
|
||||
|
||||
private void loadMixers()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "MixerManager - loading system mixer devices\n" );
|
||||
|
||||
for( Mixer.Info mixerInfo: AudioSystem.getMixerInfo() )
|
||||
{
|
||||
//Sort between the mixers and the tuner mixers, and load each
|
||||
MixerTunerType mixerTunerType = MixerTunerType.getMixerTunerType( mixerInfo );
|
||||
|
||||
if( mixerTunerType == MixerTunerType.UNKNOWN )
|
||||
{
|
||||
Mixer mixer = AudioSystem.getMixer( mixerInfo );
|
||||
|
||||
if( mixer != null )
|
||||
{
|
||||
TargetDataLine tdl = getTargetDataLine( mixerInfo, STEREO );
|
||||
|
||||
if( tdl != null )
|
||||
{
|
||||
mMixerLines.put( mixerInfo.getName(), tdl );
|
||||
|
||||
sb.append( "\t[LOADED] Mixer:" + mixerInfo.getName() + "\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "\t[NOT LOADED] Mixer:" + mixerInfo.getName() + " - audio format not supported\n" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "\t[NOT LOADED] Mixer:" + mixerInfo.getName() + " - couldn't get mixer\n" );
|
||||
}
|
||||
}
|
||||
else //Process as a Mixer-based tuner data line
|
||||
{
|
||||
TargetDataLine tdl =
|
||||
getTargetDataLine( mixerInfo,
|
||||
mixerTunerType.getAudioFormat() );
|
||||
|
||||
if( tdl != null )
|
||||
{
|
||||
switch( mixerTunerType )
|
||||
{
|
||||
case FUNCUBE_DONGLE_PRO:
|
||||
case FUNCUBE_DONGLE_PRO_PLUS:
|
||||
mMixerTuners.put( mixerInfo.getName(),
|
||||
new MixerTunerDataLine( tdl, mixerTunerType ) );
|
||||
sb.append( "\t[LOADED] FunCube Dongle Mixer Tuner:" + mixerInfo.getName() + "[" + mixerTunerType.getDisplayString() + "]\n" );
|
||||
break;
|
||||
case UNKNOWN:
|
||||
default:
|
||||
sb.append( "\t[NOT LOADED] Tuner:" + mixerInfo.getName() + " - unrecognized tuner type\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "\t[NOT LOADED] Tuner:" + mixerInfo.getName() + " - couldn't get target data line\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.info( sb.toString() );
|
||||
}
|
||||
|
||||
private TargetDataLine getTargetDataLine( Mixer.Info mixerInfo, AudioFormat format )
|
||||
{
|
||||
TargetDataLine retVal = null;
|
||||
|
||||
Mixer mixer = AudioSystem.getMixer( mixerInfo );
|
||||
|
||||
if( mixer != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
DataLine.Info datalineInfo=
|
||||
new DataLine.Info(TargetDataLine.class, format );
|
||||
|
||||
retVal = (TargetDataLine) mixer.getLine( datalineInfo );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
//Do nothing ... we couldn't get the TDL
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static String getMixerDevices()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for( Mixer.Info mixerInfo: AudioSystem.getMixerInfo() )
|
||||
{
|
||||
sb.append( "\n--------------------------------------------------" );
|
||||
sb.append( "\nMIXER name:" + mixerInfo.getName() +
|
||||
"\n desc:" + mixerInfo.getDescription() +
|
||||
"\n vendor:" + mixerInfo.getVendor() +
|
||||
"\n version:" + mixerInfo.getVersion() +
|
||||
"\n" );
|
||||
|
||||
Mixer mixer = AudioSystem.getMixer( mixerInfo );
|
||||
|
||||
Line.Info[] sourceLines = mixer.getSourceLineInfo();
|
||||
|
||||
for( Line.Info lineInfo: sourceLines )
|
||||
{
|
||||
sb.append( " SOURCE LINE desc:" + lineInfo.toString() +
|
||||
"\n class:" + lineInfo.getClass() +
|
||||
"\n lineclass:" + lineInfo.getLineClass() +
|
||||
"\n" );
|
||||
}
|
||||
|
||||
Line.Info[] targetLines = mixer.getTargetLineInfo();
|
||||
|
||||
for( Line.Info lineInfo: targetLines )
|
||||
{
|
||||
sb.append( " TARGET LINE desc:" + lineInfo.toString() +
|
||||
"\n class:" + lineInfo.getClass() +
|
||||
"\n lineclass:" + lineInfo.getLineClass() +
|
||||
"\n" );
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
274
src/source/mixer/MixerSource.java
Normal file
274
src/source/mixer/MixerSource.java
Normal file
@@ -0,0 +1,274 @@
|
||||
/*******************************************************************************
|
||||
* 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.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
|
||||
import log.Log;
|
||||
import sample.Listener;
|
||||
import source.FloatArraySource;
|
||||
import source.SourceException;
|
||||
|
||||
public class MixerSource extends FloatArraySource
|
||||
{
|
||||
private int mFrequency = 0;
|
||||
private int mBufferSize = 16384;
|
||||
|
||||
private BufferReader mBufferReader = new BufferReader();
|
||||
private TargetDataLine mTargetDataLine;
|
||||
private AudioFormat mAudioFormat;
|
||||
private String mDisplayName;
|
||||
private int mBytesPerFrame = 0;
|
||||
private SampleAdapter mSampleAdapter;
|
||||
|
||||
CopyOnWriteArrayList<Listener<Float[]>> mSampleListeners =
|
||||
new CopyOnWriteArrayList<Listener<Float[]>>();
|
||||
|
||||
/**
|
||||
* Complex Mixer Source - constructs a reader on the mixer/sound card target
|
||||
* data line using the specified audio format (sample size, sample rate )
|
||||
* and broadcasts float[] sample data to all registered listeners. Reads
|
||||
* sample buffers sized to 10% of the sample rate specified in audio format.
|
||||
*
|
||||
* @param targetDataLine - mixer or sound card to be used
|
||||
*
|
||||
* @param format - audio format
|
||||
*
|
||||
* @param name - token name to use for this source
|
||||
*
|
||||
* @param sampleAdapter - adapter to convert byte array data read from the
|
||||
* mixer into float array data. Can optionally invert the channel data if
|
||||
* the left/right stereo channels are inverted.
|
||||
*/
|
||||
public MixerSource( TargetDataLine targetDataLine,
|
||||
AudioFormat format,
|
||||
String name,
|
||||
SampleAdapter sampleAdapter )
|
||||
{
|
||||
super( name );
|
||||
|
||||
mTargetDataLine = targetDataLine;
|
||||
mAudioFormat = format;
|
||||
mSampleAdapter = sampleAdapter;
|
||||
}
|
||||
|
||||
public void setListener( Listener<Float[]> listener )
|
||||
{
|
||||
mSampleListeners.add( listener );
|
||||
|
||||
/* If this is the first listener, start the reader thread */
|
||||
if( !mBufferReader.isRunning() )
|
||||
{
|
||||
Thread thread = new Thread( mBufferReader );
|
||||
thread.setName( getName() + " Sample Reader" );
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener( Listener<Float[]> listener )
|
||||
{
|
||||
mSampleListeners.remove( listener );
|
||||
|
||||
/* If this is the laster listener, stop the reader thread */
|
||||
if( mSampleListeners.isEmpty() )
|
||||
{
|
||||
mBufferReader.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcast( Float[] samples )
|
||||
{
|
||||
Iterator<Listener<Float[]>> it = mSampleListeners.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
{
|
||||
Listener<Float[]> next = it.next();
|
||||
|
||||
/* if this is the last (or only) listener, send him the original
|
||||
* buffer, otherwise send him a copy of the buffer */
|
||||
if( it.hasNext() )
|
||||
{
|
||||
next.receive( Arrays.copyOf( samples, samples.length ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
next.receive( samples );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return mDisplayName;
|
||||
}
|
||||
|
||||
public int getSampleRate()
|
||||
{
|
||||
if( mTargetDataLine != null )
|
||||
{
|
||||
return (int)mTargetDataLine.getFormat().getSampleRate();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frequency of this source. Default is 0.
|
||||
*/
|
||||
public int getFrequency() throws SourceException
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the frequency that will be returned from this source. This may
|
||||
* be useful if you are streaming an external audio source in through the
|
||||
* sound card and you want to specify a frequency for that source
|
||||
*/
|
||||
public void setFrequency( int frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reader thread. Performs blocking read against the mixer target data
|
||||
* line, converts the samples to an array of floats using the specified
|
||||
* adapter. Dispatches float arrays to all registered listeners.
|
||||
*/
|
||||
public class BufferReader implements Runnable
|
||||
{
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if( mRunning.compareAndSet( false, true ) )
|
||||
{
|
||||
if( mTargetDataLine == null )
|
||||
{
|
||||
mRunning.set( false );
|
||||
|
||||
Log.error( "ComplexMixerSource - mixer target data line"
|
||||
+ " is null" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mBytesPerFrame = mAudioFormat.getSampleSizeInBits() / 8;
|
||||
|
||||
if( mBytesPerFrame == AudioSystem.NOT_SPECIFIED )
|
||||
{
|
||||
mBytesPerFrame = 2;
|
||||
}
|
||||
|
||||
/* Set buffer size to 1/10 second of samples */
|
||||
mBufferSize = (int)( mAudioFormat.getSampleRate()
|
||||
* 0.05 ) * mBytesPerFrame;
|
||||
|
||||
/* We'll reuse the same buffer for each read */
|
||||
byte[] buffer = new byte[ mBufferSize ];
|
||||
|
||||
try
|
||||
{
|
||||
mTargetDataLine.open( mAudioFormat );
|
||||
|
||||
mTargetDataLine.start();
|
||||
}
|
||||
catch ( LineUnavailableException e )
|
||||
{
|
||||
Log.error( "ComplexMixerSource - mixer target data line"
|
||||
+ "not available to read data from - " +
|
||||
e.getLocalizedMessage() );
|
||||
|
||||
mRunning.set( false );
|
||||
}
|
||||
|
||||
while( mRunning.get() )
|
||||
{
|
||||
try
|
||||
{
|
||||
/* Blocking read - waits until the buffer fills */
|
||||
mTargetDataLine.read( buffer, 0, buffer.length );
|
||||
|
||||
/* Convert samples to float array */
|
||||
Float[] convertedSamples =
|
||||
mSampleAdapter.convert( buffer );
|
||||
|
||||
/* Dispatch samples to registered listeners */
|
||||
broadcast( convertedSamples );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
Log.error( "ComplexMixerSource - error while reading"
|
||||
+ "from the mixer target data line - " +
|
||||
e.getLocalizedMessage() );
|
||||
|
||||
mRunning.set( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the data line if it is still open */
|
||||
if( mTargetDataLine != null && mTargetDataLine.isOpen() )
|
||||
{
|
||||
mTargetDataLine.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the reader thread
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
if( mRunning.compareAndSet( true, false ) )
|
||||
{
|
||||
mTargetDataLine.stop();
|
||||
mTargetDataLine.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the reader thread is running
|
||||
*/
|
||||
public boolean isRunning()
|
||||
{
|
||||
return mRunning.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
if( mBufferReader != null )
|
||||
{
|
||||
mBufferReader.stop();
|
||||
mSampleListeners.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/source/mixer/SampleAdapter.java
Normal file
29
src/source/mixer/SampleAdapter.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* 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 source.Source.SampleType;
|
||||
|
||||
/*
|
||||
* Adapter to convert byte data received from a data stream into float[]
|
||||
* samples
|
||||
*/
|
||||
public abstract class SampleAdapter
|
||||
{
|
||||
public abstract Float[] convert( byte[] samples );
|
||||
}
|
||||
63
src/source/mixer/ShortAdapter.java
Normal file
63
src/source/mixer/ShortAdapter.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*******************************************************************************
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import source.Source.SampleType;
|
||||
|
||||
/**
|
||||
* Converts 16-bit little endian byte data into an array of floats
|
||||
*/
|
||||
public class ShortAdapter extends SampleAdapter
|
||||
{
|
||||
private ByteOrder mByteOrder = ByteOrder.LITTLE_ENDIAN;
|
||||
|
||||
@Override
|
||||
public Float[] convert( byte[] samples )
|
||||
{
|
||||
Float[] processed = new Float[ samples.length / 2 ];
|
||||
|
||||
int pointer = 0;
|
||||
|
||||
/* Wrap byte array in a byte buffer so we can process them as shorts */
|
||||
ByteBuffer buffer = ByteBuffer.wrap( samples );
|
||||
|
||||
/* Set endian to correct byte ordering */
|
||||
buffer.order( mByteOrder );
|
||||
|
||||
while( buffer.hasRemaining() )
|
||||
{
|
||||
processed[ pointer ] = (float)buffer.getShort();
|
||||
|
||||
pointer++;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set byte interpretation to little or big endian. Defaults to LITTLE
|
||||
* endian
|
||||
*/
|
||||
public void setByteOrder( ByteOrder order )
|
||||
{
|
||||
mByteOrder = order;
|
||||
}
|
||||
}
|
||||
116
src/source/mixer/SystemMixerDevices.java
Normal file
116
src/source/mixer/SystemMixerDevices.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*******************************************************************************
|
||||
* 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.HashMap;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.Line;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
|
||||
/**
|
||||
* THIS CLASS IS SCHEDULED FOR DELETION *****************************
|
||||
*/
|
||||
|
||||
public class SystemMixerDevices {
|
||||
|
||||
/**
|
||||
* Returns a hashmap of mixer names and target data lines that support the
|
||||
* audio format argument
|
||||
*
|
||||
* @param format - requested audio format
|
||||
* @return - mixer target data lines that support the requested audio format
|
||||
*/
|
||||
public static HashMap<String,TargetDataLine> getMixers( AudioFormat format )
|
||||
{
|
||||
HashMap<String,TargetDataLine> retVal = new HashMap<String,TargetDataLine>();
|
||||
|
||||
DataLine.Info datalineInfo=new DataLine.Info(TargetDataLine.class, format );
|
||||
|
||||
for( Mixer.Info mixerInfo: AudioSystem.getMixerInfo() )
|
||||
{
|
||||
Mixer mixer = AudioSystem.getMixer( mixerInfo );
|
||||
|
||||
if( mixer != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
TargetDataLine tdl = (TargetDataLine) mixer.getLine( datalineInfo );
|
||||
|
||||
if( tdl != null )
|
||||
{
|
||||
retVal.put( mixerInfo.getName(), tdl );
|
||||
}
|
||||
}
|
||||
catch( IllegalArgumentException iae )
|
||||
{
|
||||
//Do nothing ... mixer doesn't support the audio format
|
||||
}
|
||||
catch( LineUnavailableException e )
|
||||
{
|
||||
//Do nothing ... mixer doesn't support the audio format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static String getSoundDevices()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for( Mixer.Info mixerInfo: AudioSystem.getMixerInfo() )
|
||||
{
|
||||
sb.append( "\n--------------------------------------------------" );
|
||||
sb.append( "\nMIXER name:" + mixerInfo.getName() +
|
||||
"\n desc:" + mixerInfo.getDescription() +
|
||||
"\n vendor:" + mixerInfo.getVendor() +
|
||||
"\n version:" + mixerInfo.getVersion() +
|
||||
"\n" );
|
||||
|
||||
Mixer mixer = AudioSystem.getMixer( mixerInfo );
|
||||
|
||||
Line.Info[] sourceLines = mixer.getSourceLineInfo();
|
||||
|
||||
for( Line.Info lineInfo: sourceLines )
|
||||
{
|
||||
sb.append( " SOURCE LINE desc:" + lineInfo.toString() +
|
||||
"\n class:" + lineInfo.getClass() +
|
||||
"\n lineclass:" + lineInfo.getLineClass() +
|
||||
"\n" );
|
||||
}
|
||||
|
||||
Line.Info[] targetLines = mixer.getTargetLineInfo();
|
||||
|
||||
for( Line.Info lineInfo: targetLines )
|
||||
{
|
||||
sb.append( " TARGET LINE desc:" + lineInfo.toString() +
|
||||
"\n class:" + lineInfo.getClass() +
|
||||
"\n lineclass:" + lineInfo.getLineClass() +
|
||||
"\n" );
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
152
src/source/tuner/DigitalDropChannel.java
Normal file
152
src/source/tuner/DigitalDropChannel.java
Normal file
@@ -0,0 +1,152 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package source.tuner;
|
||||
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexSample;
|
||||
import dsp.filter.ComplexFilter;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
|
||||
@Deprecated
|
||||
public class DigitalDropChannel implements Listener<ComplexSample>,
|
||||
FrequencyChangeListener
|
||||
{
|
||||
/**
|
||||
* Implements a frequency translating, decimating FIR filter channelizer.
|
||||
*
|
||||
* Uses multiple cascaded half-band low pass filters that each decimate by
|
||||
* two, to achieve an overall power-of-two decimation factor.
|
||||
*
|
||||
* @param decimation - power of 2 decimation factor
|
||||
*
|
||||
* @param frequencyShift +/- frequency shift in hertz
|
||||
*/
|
||||
|
||||
private static int sCHANNEL_RATE = 48000;
|
||||
private static int sCHANNEL_PASS_FREQUENCY = 12500;
|
||||
|
||||
private NumericallyControlledOscillator mFrequencyTranslator;
|
||||
|
||||
private ComplexFilter[] mFilters;
|
||||
|
||||
private Broadcaster<ComplexSample> mComplexSampleBroadcaster =
|
||||
new Broadcaster<ComplexSample>();
|
||||
|
||||
private int mSampleRate;
|
||||
private int mFrequencyShift;
|
||||
|
||||
public DigitalDropChannel( int sampleRate, int frequencyShift )
|
||||
{
|
||||
if( sampleRate % sCHANNEL_RATE != 0 )
|
||||
{
|
||||
throw new IllegalArgumentException( "Sample rate must be an "
|
||||
+ "integer multiple of 48000" );
|
||||
}
|
||||
|
||||
mFrequencyShift = frequencyShift;
|
||||
|
||||
setSampleRate( sampleRate );
|
||||
}
|
||||
|
||||
private void setSampleRate( int sampleRate )
|
||||
{
|
||||
if( sampleRate != mSampleRate )
|
||||
{
|
||||
/* Setup or adjust the frequency translator */
|
||||
if( mFrequencyTranslator == null )
|
||||
{
|
||||
mFrequencyTranslator =
|
||||
new NumericallyControlledOscillator( mFrequencyShift,
|
||||
sampleRate );
|
||||
}
|
||||
else
|
||||
{
|
||||
mFrequencyTranslator.setSampleRate( sampleRate );
|
||||
}
|
||||
|
||||
/* Get new decimation filters */
|
||||
mFilters = FilterFactory
|
||||
.getDecimationFilters( sampleRate,
|
||||
sCHANNEL_RATE,
|
||||
sCHANNEL_PASS_FREQUENCY,
|
||||
48, //dB attenuation
|
||||
WindowType.HAMMING );
|
||||
|
||||
/* wire the first filter stage to the frequency translator */
|
||||
// mFrequencyTranslator.setListener( mFilters[ 0 ] );
|
||||
|
||||
/* wire the remaining filters together */
|
||||
if( mFilters.length > 1 )
|
||||
{
|
||||
for( int x = 1; x < mFilters.length; x++ )
|
||||
{
|
||||
mFilters[ x - 1 ].setListener( mFilters[ x ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the sample broadcaster as a listener to the final filter */
|
||||
// mFilters[ mFilters.length - 1 ].setListener( mComplexSampleBroadcaster );
|
||||
|
||||
mSampleRate = sampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged( int frequency, int bandwidth )
|
||||
{
|
||||
mFrequencyTranslator.setFrequency( frequency );
|
||||
|
||||
if( bandwidth != mSampleRate )
|
||||
{
|
||||
setSampleRate( bandwidth );
|
||||
}
|
||||
}
|
||||
|
||||
public int getFrequencyOffset()
|
||||
{
|
||||
return mFrequencyTranslator.getFrequency();
|
||||
}
|
||||
|
||||
public void addListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
mComplexSampleBroadcaster.addListener( listener );
|
||||
}
|
||||
|
||||
public void removeListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
mComplexSampleBroadcaster.removeListener( listener );
|
||||
}
|
||||
|
||||
public int getListenerCount()
|
||||
{
|
||||
return mComplexSampleBroadcaster.getListenerCount();
|
||||
}
|
||||
|
||||
public void removeListeners()
|
||||
{
|
||||
mComplexSampleBroadcaster.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( ComplexSample sample )
|
||||
{
|
||||
mFrequencyTranslator.receive( sample );
|
||||
}
|
||||
}
|
||||
25
src/source/tuner/FrequencyChangeBroadcaster.java
Normal file
25
src/source/tuner/FrequencyChangeBroadcaster.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* 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 FrequencyChangeBroadcaster
|
||||
{
|
||||
public abstract void addListener( FrequencyChangeListener listener );
|
||||
|
||||
public abstract void removeListener( FrequencyChangeListener listener );
|
||||
}
|
||||
38
src/source/tuner/FrequencyChangeListener.java
Normal file
38
src/source/tuner/FrequencyChangeListener.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Interface for broadcasting changes to frequency and/or bandwidth/sample rate
|
||||
* to all registered listeners.
|
||||
*
|
||||
* Note: broadcasted frequency should be the uncorrected, or displayable
|
||||
* frequency value. All frequency correction aspects should be handled within
|
||||
* the device that implements the tuning of the frequency.
|
||||
*/
|
||||
public interface FrequencyChangeListener
|
||||
{
|
||||
/**
|
||||
* Broadcasts a change to the (uncorrected) frequency and/or bandwidth
|
||||
* or sample rate.
|
||||
*
|
||||
* @param frequency - uncorrected frequency in hertz
|
||||
* @param bandwidth - bandwidth in hertz
|
||||
*/
|
||||
public void frequencyChanged( int frequency, int bandwidth );
|
||||
}
|
||||
220
src/source/tuner/FrequencyController.java
Normal file
220
src/source/tuner/FrequencyController.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.ArrayList;
|
||||
|
||||
import source.SourceException;
|
||||
|
||||
public class FrequencyController
|
||||
{
|
||||
private Tunable mTunable;
|
||||
private int mFrequency = 101100000;
|
||||
private int mTunedFrequency = 101100000;
|
||||
private int mMinimumFrequency;
|
||||
private int mMaximumFrequency;
|
||||
private double mFrequencyCorrection = 0d;
|
||||
private int mBandwidth = 0;
|
||||
|
||||
private ArrayList<FrequencyChangeListener> mListeners =
|
||||
new ArrayList<FrequencyChangeListener>();
|
||||
|
||||
public FrequencyController( Tunable tunable,
|
||||
int minFrequency,
|
||||
int maxFrequency,
|
||||
double frequencyCorrection ) throws SourceException
|
||||
{
|
||||
mTunable = tunable;
|
||||
mMinimumFrequency = minFrequency;
|
||||
mMaximumFrequency = maxFrequency;
|
||||
mFrequencyCorrection = frequencyCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bandwidth/sample rate in hertz
|
||||
*/
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mBandwidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bandwidth/sample rate in hertz
|
||||
*/
|
||||
public void setBandwidth( int bandwidth )
|
||||
{
|
||||
mBandwidth = bandwidth;
|
||||
|
||||
broadcastFrequencyChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get frequency in hertz
|
||||
*/
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set frequency
|
||||
* @param frequency in hertz
|
||||
* @throws SourceException if tunable doesn't support tuning a corrected
|
||||
* version of the requested frequency
|
||||
*/
|
||||
public void setFrequency( int frequency ) throws SourceException
|
||||
{
|
||||
setFrequency( frequency, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set frequency with optional broadcast of frequency change event. This
|
||||
* method supports changing the frequency correction value without
|
||||
* broadcasting a frequency change event.
|
||||
*/
|
||||
private void setFrequency( int frequency, boolean broadcastChange )
|
||||
throws SourceException
|
||||
{
|
||||
int tunedFrequency = getTunedFrequency( frequency );
|
||||
|
||||
if( tunedFrequency < mMinimumFrequency ||
|
||||
tunedFrequency > mMaximumFrequency )
|
||||
{
|
||||
throw new SourceException( "Cannot tune frequency ( requested: " +
|
||||
frequency + " actual:" + tunedFrequency + "]" );
|
||||
}
|
||||
|
||||
mFrequency = frequency;
|
||||
mTunedFrequency = tunedFrequency;
|
||||
|
||||
if( mTunable != null )
|
||||
{
|
||||
mTunable.setTunedFrequency( mTunedFrequency );
|
||||
}
|
||||
|
||||
/* Broadcast to all listeners that the frequency has changed */
|
||||
if( broadcastChange )
|
||||
{
|
||||
broadcastFrequencyChange();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTunedFrequency()
|
||||
{
|
||||
return mTunedFrequency;
|
||||
}
|
||||
|
||||
public int getMinimumFrequency()
|
||||
{
|
||||
return mMinimumFrequency;
|
||||
}
|
||||
|
||||
public int getMaximumFrequency()
|
||||
{
|
||||
return mMaximumFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the tuned frequency by adding frequency correction to the
|
||||
* corrected frequency.
|
||||
* @param correctedFrequency
|
||||
*/
|
||||
private int getTunedFrequency( int correctedFrequency )
|
||||
{
|
||||
return (int)( (double)correctedFrequency /
|
||||
( 1.0 + ( mFrequencyCorrection / 1000000.0 ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the corrected frequency by subtracting frequency correction
|
||||
* from the tuned frequency.
|
||||
* @param tunedFrequency
|
||||
*/
|
||||
private int getCorrectedFrequency( int tunedFrequency )
|
||||
{
|
||||
return (int)( (double)tunedFrequency /
|
||||
( 1.0 - ( mFrequencyCorrection / 1000000.0 ) ) );
|
||||
}
|
||||
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double correction )
|
||||
throws SourceException
|
||||
{
|
||||
mFrequencyCorrection = correction;
|
||||
|
||||
if( mFrequency > 0 )
|
||||
{
|
||||
/* Reset the frequency, but don't broadcast a change */
|
||||
setFrequency( mFrequency, false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds listener to receive frequency change events
|
||||
*/
|
||||
public void addListener( FrequencyChangeListener listener )
|
||||
{
|
||||
if( !mListeners.contains( listener ) )
|
||||
{
|
||||
mListeners.add( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes listener from receiving frequency change events
|
||||
*/
|
||||
public void removeListener( FrequencyChangeListener listener )
|
||||
{
|
||||
mListeners.remove( listener );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Broadcasts a change/update to the current (uncorrected) frequency or the
|
||||
* bandwidth/sample rate value.
|
||||
*/
|
||||
protected void broadcastFrequencyChange()
|
||||
{
|
||||
for( FrequencyChangeListener listener: mListeners )
|
||||
{
|
||||
listener.frequencyChanged( mFrequency, mBandwidth );
|
||||
}
|
||||
}
|
||||
|
||||
public interface Tunable
|
||||
{
|
||||
/**
|
||||
* Gets the tuned frequency of the device
|
||||
*/
|
||||
public int getTunedFrequency() throws SourceException;
|
||||
|
||||
/**
|
||||
* Sets the tuned frequency of the device
|
||||
*/
|
||||
public void setTunedFrequency( int frequency ) throws SourceException;
|
||||
|
||||
/**
|
||||
* Gets the current bandwidth setting of the device
|
||||
*/
|
||||
public int getCurrentSampleRate() throws SourceException;
|
||||
}
|
||||
}
|
||||
98
src/source/tuner/MixerTuner.java
Normal file
98
src/source/tuner/MixerTuner.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.ArrayList;
|
||||
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexSampleListListener;
|
||||
import source.mixer.MixerSource;
|
||||
import source.mixer.SampleAdapter;
|
||||
|
||||
public abstract class MixerTuner extends Tuner
|
||||
{
|
||||
private TargetDataLine mTargetDataLine;
|
||||
protected MixerTunerType mMixerTunerType;
|
||||
protected MixerSource mMixerSource;
|
||||
protected ArrayList<ComplexSampleListListener> mListeners =
|
||||
new ArrayList<ComplexSampleListListener>();
|
||||
|
||||
/**
|
||||
* Provides a wrapper around a MixerSource to treat it like a Tuner that
|
||||
* can provide ComplexSample<Short> samples. Subclasses should couple this
|
||||
* functionality with a tuner control class to allow tuning.
|
||||
*/
|
||||
public MixerTuner( String name,
|
||||
MixerTunerType mixerTunerType,
|
||||
TargetDataLine targetDataLine,
|
||||
SampleAdapter sampleAdapter )
|
||||
{
|
||||
super( name );
|
||||
|
||||
mMixerTunerType = mixerTunerType;
|
||||
|
||||
mTargetDataLine = targetDataLine;
|
||||
|
||||
mMixerSource = new MixerSource( targetDataLine,
|
||||
mMixerTunerType.getAudioFormat(),
|
||||
name,
|
||||
sampleAdapter );
|
||||
}
|
||||
|
||||
public MixerTuner( String name,
|
||||
MixerTunerDataLine mixerTuner,
|
||||
SampleAdapter sampleAdapter )
|
||||
{
|
||||
this( name,
|
||||
mixerTuner.getMixerTunerType(),
|
||||
mixerTuner.getTargetDataLine(),
|
||||
sampleAdapter );
|
||||
}
|
||||
|
||||
public MixerTunerType getMixerTunerType()
|
||||
{
|
||||
return mMixerTunerType;
|
||||
}
|
||||
|
||||
public TargetDataLine getTargetDataLine()
|
||||
{
|
||||
return mTargetDataLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the Tuner listener management methods and allows the
|
||||
* complex mixer source to manage sample listeners
|
||||
*/
|
||||
@Override
|
||||
public void addListener( Listener<Float[]> listener )
|
||||
{
|
||||
mMixerSource.setListener( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the Tuner listener management methods and allows the
|
||||
* complex mixer source to manage sample listeners
|
||||
*/
|
||||
@Override
|
||||
public void removeListener( Listener<Float[]> listener )
|
||||
{
|
||||
mMixerSource.removeListener( listener );
|
||||
}
|
||||
}
|
||||
42
src/source/tuner/MixerTunerDataLine.java
Normal file
42
src/source/tuner/MixerTunerDataLine.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* 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.sound.sampled.TargetDataLine;
|
||||
|
||||
public class MixerTunerDataLine
|
||||
{
|
||||
private TargetDataLine mTargetDataLine;
|
||||
protected MixerTunerType mMixerTunerType;
|
||||
|
||||
public MixerTunerDataLine( TargetDataLine line, MixerTunerType type )
|
||||
{
|
||||
mTargetDataLine = line;
|
||||
mMixerTunerType = type;
|
||||
}
|
||||
|
||||
public TargetDataLine getTargetDataLine()
|
||||
{
|
||||
return mTargetDataLine;
|
||||
}
|
||||
|
||||
public MixerTunerType getMixerTunerType()
|
||||
{
|
||||
return mMixerTunerType;
|
||||
}
|
||||
}
|
||||
117
src/source/tuner/MixerTunerType.java
Normal file
117
src/source/tuner/MixerTunerType.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*******************************************************************************
|
||||
* 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.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.Mixer;
|
||||
|
||||
public enum MixerTunerType
|
||||
{
|
||||
|
||||
FUNCUBE_DONGLE_PRO( TunerType.FUNCUBE_DONGLE_PRO,
|
||||
"V10",
|
||||
"FUNcube Dongle",
|
||||
"FUNcube Dongle Pro V1.0",
|
||||
new AudioFormat( 96000, //SampleRate
|
||||
16, //Sample Size
|
||||
2, //Channels
|
||||
true, //Signed
|
||||
false ) ), //Little Endian )
|
||||
|
||||
FUNCUBE_DONGLE_PRO_PLUS( TunerType.FUNCUBE_DONGLE_PRO_PLUS,
|
||||
"V20",
|
||||
"FUNcube Dongle V2.0",
|
||||
"FUNcube Dongle Pro Plus V2.0",
|
||||
new AudioFormat( 192000, //SampleRate
|
||||
16, //Sample Size
|
||||
2, //Channels
|
||||
true, //Signed
|
||||
false ) ), //Little Endian )
|
||||
|
||||
UNKNOWN( TunerType.UNKNOWN,
|
||||
"UNK",
|
||||
"Unknown",
|
||||
"Unknown Mixer Tuner",
|
||||
new AudioFormat( 48000, //SampleRate
|
||||
16, //Sample Size
|
||||
2, //Channels
|
||||
true, //Signed
|
||||
false ) ); //Little Endian )
|
||||
|
||||
private TunerType mTunerClass;
|
||||
private String mMixerName;
|
||||
private String mPartialDescription;
|
||||
private String mDisplayString;
|
||||
private AudioFormat mAudioFormat;
|
||||
|
||||
MixerTunerType( TunerType tunerClass,
|
||||
String mixerName,
|
||||
String partialDescription,
|
||||
String displayString,
|
||||
AudioFormat format )
|
||||
{
|
||||
mTunerClass = tunerClass;
|
||||
mMixerName = mixerName;
|
||||
mPartialDescription = partialDescription;
|
||||
mDisplayString = displayString;
|
||||
mAudioFormat = format;
|
||||
}
|
||||
|
||||
public TunerType getTunerClass()
|
||||
{
|
||||
return mTunerClass;
|
||||
}
|
||||
|
||||
public String getMixerName()
|
||||
{
|
||||
return mMixerName;
|
||||
}
|
||||
|
||||
public String getPartialDescription()
|
||||
{
|
||||
return mPartialDescription;
|
||||
}
|
||||
|
||||
public String getDisplayString()
|
||||
{
|
||||
return mDisplayString;
|
||||
}
|
||||
|
||||
public AudioFormat getAudioFormat()
|
||||
{
|
||||
return mAudioFormat;
|
||||
}
|
||||
|
||||
public static MixerTunerType getMixerTunerType( Mixer.Info info )
|
||||
{
|
||||
MixerTunerType retVal = UNKNOWN;
|
||||
|
||||
if( info.getName().contains( FUNCUBE_DONGLE_PRO_PLUS.mPartialDescription ) ||
|
||||
info.getDescription().contains( FUNCUBE_DONGLE_PRO_PLUS.mPartialDescription ) )
|
||||
{
|
||||
retVal = FUNCUBE_DONGLE_PRO_PLUS;
|
||||
}
|
||||
else if( info.getName().contains( FUNCUBE_DONGLE_PRO.mPartialDescription ) ||
|
||||
info.getDescription().contains( FUNCUBE_DONGLE_PRO.mPartialDescription ) )
|
||||
{
|
||||
retVal = FUNCUBE_DONGLE_PRO;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
130
src/source/tuner/NumericallyControlledOscillator.java
Normal file
130
src/source/tuner/NumericallyControlledOscillator.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*******************************************************************************
|
||||
* 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 log.Log;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexSample;
|
||||
import sample.complex.ComplexSampleUtils;
|
||||
import util.Oscillator;
|
||||
|
||||
public class NumericallyControlledOscillator implements Listener<ComplexSample>,
|
||||
FrequencyChangeListener
|
||||
{
|
||||
private int mFrequency;
|
||||
private int mSampleRate;
|
||||
private Oscillator mSineWaveGenerator;
|
||||
private Listener<ComplexSample> mListener;
|
||||
/**
|
||||
* Translates (shifts) frequency spectrum up or down, depending on the sign
|
||||
* of the frequency argument, by mixing received complex samples with a
|
||||
* generated sine wave of the frequency argument. Positive frequency shifts
|
||||
* the received spectrum higher in frequency. Negative frequency shifts the
|
||||
* received spectrum lower in frequency. In both cases, spectrum that is
|
||||
* shifted outside of the sampling bandwidth will wrap around, due to the
|
||||
* nature of quadrature sampling.
|
||||
*/
|
||||
public NumericallyControlledOscillator( int frequencyShift, int sampleRate )
|
||||
{
|
||||
mFrequency = frequencyShift;
|
||||
mSampleRate = sampleRate;
|
||||
|
||||
int defaultMixingSignalGain = 10;
|
||||
|
||||
mSineWaveGenerator = new Oscillator( mFrequency, mSampleRate );
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener method for this class to receive samples from a Complex Sample
|
||||
* Provider. This method multiplies the incoming sample by the generated
|
||||
* mixing frequency to translate (ie shift +/-) the incoming signal, and
|
||||
* then send the translated signal on to all registered listeners
|
||||
*/
|
||||
@Override
|
||||
public void receive( ComplexSample sample )
|
||||
{
|
||||
if( mListener != null )
|
||||
{
|
||||
mListener.receive( ComplexSampleUtils.multiply( sample,
|
||||
mSineWaveGenerator.nextComplex() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged( int frequency, int bandwidth )
|
||||
{
|
||||
if( frequency != mFrequency )
|
||||
{
|
||||
setFrequency( frequency );
|
||||
}
|
||||
|
||||
if( bandwidth != mSampleRate )
|
||||
{
|
||||
setSampleRate( bandwidth );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the frequency value and resets the sine wave generator, so that
|
||||
* all subsequent samples will be output at the new translated frequency
|
||||
* @param frequency - hertz
|
||||
*/
|
||||
public void setFrequency( int frequency )
|
||||
{
|
||||
Log.info( "NumericallyControlledOscillator - setting sine wave gen to freq:" + frequency );
|
||||
|
||||
mFrequency = frequency;
|
||||
mSineWaveGenerator.setFrequency( frequency );
|
||||
}
|
||||
|
||||
/**
|
||||
* Current frequency shift setting
|
||||
* @return - frequency - hertz
|
||||
*/
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the sample rate, so that all new input/output values will be
|
||||
* translated at the new sample rate
|
||||
* @param sampleRate - hertz
|
||||
*/
|
||||
public void setSampleRate( int sampleRate )
|
||||
{
|
||||
mSampleRate = sampleRate;
|
||||
mSineWaveGenerator.setSampleRate( sampleRate );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener to receive frequency translated complex samples
|
||||
*/
|
||||
public void setListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove listener from receiving frequency translated complex samples.
|
||||
*/
|
||||
public void clearListener()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
190
src/source/tuner/Tuner.java
Normal file
190
src/source/tuner/Tuner.java
Normal file
@@ -0,0 +1,190 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import sample.Listener;
|
||||
import source.SourceException;
|
||||
import controller.ResourceManager;
|
||||
import controller.ThreadPoolManager;
|
||||
|
||||
/**
|
||||
* Tuner - provides tuner channel sources, representing a channel frequency
|
||||
*/
|
||||
public abstract class Tuner implements FrequencyChangeBroadcaster,
|
||||
FrequencyChangeListener
|
||||
{
|
||||
private String mName;
|
||||
|
||||
protected CopyOnWriteArrayList<Listener<Float[]>>
|
||||
mSampleListeners = new CopyOnWriteArrayList<Listener<Float[]>>();
|
||||
|
||||
protected CopyOnWriteArrayList<FrequencyChangeListener>
|
||||
mFrequencyChangeListeners = new CopyOnWriteArrayList<FrequencyChangeListener>();
|
||||
|
||||
public Tuner( String name )
|
||||
{
|
||||
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.
|
||||
*
|
||||
* @return - unique identifier like a serial number, or a usb bus location
|
||||
* or ip address and port. Return some form of unique identification that
|
||||
* allows this tuner to be identified from among several of the same types
|
||||
* of tuners.
|
||||
*/
|
||||
public abstract String getUniqueID();
|
||||
|
||||
/**
|
||||
* @return - tuner class enum entry
|
||||
*/
|
||||
public abstract TunerClass getTunerClass();
|
||||
|
||||
/**
|
||||
* @return - tuner type enum entry
|
||||
*/
|
||||
public abstract TunerType getTunerType();
|
||||
|
||||
/**
|
||||
* Name of this tuner object
|
||||
* @return - string name of this tuner object
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample rate of complex data coming from the Tuner
|
||||
* @return
|
||||
*/
|
||||
public abstract int getSampleRate();
|
||||
|
||||
/**
|
||||
* Tuner Local Oscillator Frequency
|
||||
* @return - frequency in Hertz
|
||||
*/
|
||||
public abstract int getFrequency() throws SourceException;
|
||||
|
||||
/**
|
||||
* Returns a tuner frequency channel source, tuned to the correct frequency
|
||||
*
|
||||
* Note: ensure the concrete implementation registers the returned
|
||||
* tuner channel source as a listener on the tuner, to receive frequency
|
||||
* change events.
|
||||
*
|
||||
* @param frequency - desired frequency
|
||||
*
|
||||
* @return - source for 48k sample rate
|
||||
*/
|
||||
public abstract TunerChannelSource getChannel( ThreadPoolManager threadPoolManager,
|
||||
TunerChannel channel ) throws RejectedExecutionException, SourceException;
|
||||
|
||||
/**
|
||||
* Releases the tuned channel resources
|
||||
*
|
||||
* Note: ensure the concrete implementation unregisters the tuner channel
|
||||
* source from the tuner as a frequency change listener
|
||||
*
|
||||
* @param channel - previously obtained tuner channel
|
||||
*/
|
||||
public abstract void releaseChannel( TunerChannelSource source );
|
||||
|
||||
/**
|
||||
* Registers the listener to receive complex float sample arrays
|
||||
*/
|
||||
public void addListener( Listener<Float[]> listener )
|
||||
{
|
||||
mSampleListeners.add( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeListener( Listener<Float[]> listener )
|
||||
{
|
||||
mSampleListeners.remove( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the samples to all registered listeners
|
||||
*/
|
||||
public void broadcast( Float[] samples )
|
||||
{
|
||||
for( Listener<Float[]> listener: mSampleListeners )
|
||||
{
|
||||
listener.receive( samples );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the frequency change listener to receive frequency and/or bandwidth
|
||||
* change events
|
||||
*/
|
||||
public void addListener( FrequencyChangeListener listener )
|
||||
{
|
||||
mFrequencyChangeListeners.add( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the frequency change listener
|
||||
*/
|
||||
public void removeListener( FrequencyChangeListener listener )
|
||||
{
|
||||
mFrequencyChangeListeners.remove( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a frequency change event to all registered listeners
|
||||
*/
|
||||
public void broadcastFrequencyChange( int frequency, int bandwidth )
|
||||
{
|
||||
for( FrequencyChangeListener listener: mFrequencyChangeListeners )
|
||||
{
|
||||
listener.frequencyChanged( frequency, bandwidth );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency change listener method. We receive change events from the
|
||||
* controller and rebroadcast them to all registered listeners.
|
||||
*/
|
||||
public void frequencyChanged( int frequency, int bandwidth )
|
||||
{
|
||||
broadcastFrequencyChange( frequency, bandwidth );
|
||||
}
|
||||
}
|
||||
114
src/source/tuner/TunerChannel.java
Normal file
114
src/source/tuner/TunerChannel.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*******************************************************************************
|
||||
* 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 class TunerChannel implements Comparable<TunerChannel>
|
||||
{
|
||||
private Type mType;
|
||||
private int mFrequency;
|
||||
private int mBandwidth;
|
||||
|
||||
public TunerChannel( Type type, int frequency, int bandwidth )
|
||||
{
|
||||
mType = type;
|
||||
mFrequency = frequency;
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public Type getType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
public void setType( Type type )
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency( int frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mBandwidth;
|
||||
}
|
||||
|
||||
public void setBandwidth( int bandwidth )
|
||||
{
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public int getMinFrequency()
|
||||
{
|
||||
return mFrequency - ( mBandwidth / 2 );
|
||||
}
|
||||
|
||||
public int getMaxFrequency()
|
||||
{
|
||||
return mFrequency + ( mBandwidth / 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if any part of this tuner channel is contained within the
|
||||
* minimum and maximum frequency values.
|
||||
*/
|
||||
public boolean isWithin( int minimum, int maximum )
|
||||
{
|
||||
return ( ( minimum <= getMinFrequency() && getMinFrequency() <= maximum ) ||
|
||||
( minimum <= getMaxFrequency() && getMaxFrequency() <= maximum ) );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "Channel: " );
|
||||
sb.append( ( mFrequency - ( mBandwidth / 2 ) ) );
|
||||
sb.append( "-" );
|
||||
sb.append( ( mFrequency + ( mBandwidth / 2 ) ) );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo( TunerChannel otherLock )
|
||||
{
|
||||
if( mFrequency < otherLock.getFrequency() )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
LOCKED, //Use for decoding channels, so that they cannot be tuned out of range
|
||||
TRAFFIC, //Like locked, but for temporary allocated traffic channels
|
||||
TUNABLE; //Tunable -- can be tuned out of range
|
||||
}
|
||||
}
|
||||
273
src/source/tuner/TunerChannelSource.java
Normal file
273
src/source/tuner/TunerChannelSource.java
Normal file
@@ -0,0 +1,273 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import sample.Listener;
|
||||
import sample.Provider;
|
||||
import sample.complex.ComplexSample;
|
||||
import sample.complex.ComplexSampleAssembler;
|
||||
import source.ComplexSource;
|
||||
import source.Source.SampleType;
|
||||
import source.SourceException;
|
||||
import util.Oscillator;
|
||||
import controller.ThreadPoolManager;
|
||||
import controller.ThreadPoolManager.ThreadType;
|
||||
import dsp.filter.ComplexFilter;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
|
||||
public class TunerChannelSource extends ComplexSource
|
||||
implements FrequencyChangeListener,
|
||||
Listener<Float[]>
|
||||
{
|
||||
private static int sCHANNEL_RATE = 48000;
|
||||
private static int sCHANNEL_PASS_FREQUENCY = 12500;
|
||||
|
||||
private LinkedTransferQueue<Float[]> mBuffer =
|
||||
new LinkedTransferQueue<Float[]>();
|
||||
private Tuner mTuner;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Oscillator mSineWaveGenerator;
|
||||
private ComplexFilter[] mDecimationFilters;
|
||||
private DecimationProcessor mDecimationProcessor = new DecimationProcessor();
|
||||
|
||||
private ComplexSampleAssembler mBufferAssembler =
|
||||
new ComplexSampleAssembler( 3000 );
|
||||
private int mTunerFrequency;
|
||||
private int mTunerSampleRate;
|
||||
private ThreadPoolManager mThreadPoolManager;
|
||||
private ScheduledFuture<?> mTaskHandle;
|
||||
|
||||
public TunerChannelSource( ThreadPoolManager threadPoolManager,
|
||||
Tuner tuner,
|
||||
TunerChannel tunerChannel )
|
||||
throws RejectedExecutionException
|
||||
{
|
||||
super( "Tuner Channel Source" );
|
||||
|
||||
mThreadPoolManager = threadPoolManager;
|
||||
|
||||
/* Schedule the decimation task to run 20 times a second */
|
||||
mTaskHandle = mThreadPoolManager.schedule( ThreadType.DECIMATION,
|
||||
new DecimationProcessor(), 50, TimeUnit.MILLISECONDS );
|
||||
|
||||
mTuner = tuner;
|
||||
mTuner.addListener( (FrequencyChangeListener)this );
|
||||
|
||||
mTunerChannel = tunerChannel;
|
||||
|
||||
/* Setup the frequency translator to the current source frequency */
|
||||
try
|
||||
{
|
||||
frequencyChanged( mTuner.getFrequency(), mTuner.getSampleRate() );
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
/* Finally, register to receive samples from the tuner */
|
||||
mTuner.addListener( (Listener<Float[]>)this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
//Tell the tuner to release our resources
|
||||
mTuner.removeListener( (FrequencyChangeListener)this );
|
||||
mTuner.releaseChannel( this );
|
||||
|
||||
if( mTaskHandle != null )
|
||||
{
|
||||
mThreadPoolManager.cancel( mTaskHandle );
|
||||
}
|
||||
|
||||
mBuffer.clear();
|
||||
mBuffer = null;
|
||||
|
||||
for( ComplexFilter filter: mDecimationFilters )
|
||||
{
|
||||
filter.dispose();
|
||||
}
|
||||
|
||||
mBufferAssembler.dispose();
|
||||
|
||||
mTuner = null;
|
||||
|
||||
mTunerChannel = null;
|
||||
|
||||
mTunerChannel = null;
|
||||
mTuner = null;
|
||||
}
|
||||
|
||||
public Tuner getTuner()
|
||||
{
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( Float[] samples )
|
||||
{
|
||||
mBuffer.add( samples );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener( Listener<List<ComplexSample>> listener )
|
||||
{
|
||||
mBufferAssembler.setListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( Listener<List<ComplexSample>> listener )
|
||||
{
|
||||
mBufferAssembler.removeListener( listener );
|
||||
mDecimationFilters[ mDecimationFilters.length - 1 ]
|
||||
.setListener( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged( int frequency, int bandwidth )
|
||||
{
|
||||
|
||||
/* Frequency change */
|
||||
if( frequency != mTunerFrequency )
|
||||
{
|
||||
int frequencyOffset = frequency - mTunerChannel.getFrequency();
|
||||
|
||||
if( mSineWaveGenerator == null )
|
||||
{
|
||||
mSineWaveGenerator =
|
||||
new Oscillator( frequencyOffset, bandwidth );
|
||||
}
|
||||
else
|
||||
{
|
||||
mSineWaveGenerator.setFrequency( frequencyOffset );
|
||||
}
|
||||
|
||||
/* Clear the buffer for the frequency to take immediate effect */
|
||||
mBuffer.clear();
|
||||
|
||||
mTunerFrequency = frequency;
|
||||
}
|
||||
|
||||
/* Bandwidth/Sample rate change */
|
||||
if( bandwidth != mTunerSampleRate )
|
||||
{
|
||||
int frequencyOffset = frequency - mTunerChannel.getFrequency();
|
||||
|
||||
if( mSineWaveGenerator == null )
|
||||
{
|
||||
mSineWaveGenerator =
|
||||
new Oscillator( frequencyOffset, bandwidth );
|
||||
}
|
||||
else
|
||||
{
|
||||
mSineWaveGenerator.setSampleRate( bandwidth );
|
||||
}
|
||||
|
||||
/* Get the original decimation filter output listener */
|
||||
Listener<ComplexSample> listener = null;
|
||||
|
||||
/* Get new decimation filters */
|
||||
mDecimationFilters = FilterFactory
|
||||
.getDecimationFilters( bandwidth,
|
||||
sCHANNEL_RATE,
|
||||
sCHANNEL_PASS_FREQUENCY,
|
||||
48, //dB attenuation
|
||||
WindowType.HAMMING );
|
||||
|
||||
/* wire the filters together */
|
||||
if( mDecimationFilters.length > 1 )
|
||||
{
|
||||
for( int x = 1; x < mDecimationFilters.length; x++ )
|
||||
{
|
||||
mDecimationFilters[ x - 1 ].setListener( mDecimationFilters[ x ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilters[ mDecimationFilters.length - 1 ]
|
||||
.setListener( mBufferAssembler );
|
||||
|
||||
mTunerSampleRate = bandwidth;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSampleRate() throws SourceException
|
||||
{
|
||||
return mTuner.getSampleRate();
|
||||
}
|
||||
|
||||
public int getFrequency() throws SourceException
|
||||
{
|
||||
return mTuner.getFrequency();
|
||||
}
|
||||
|
||||
public class DecimationProcessor implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
List<Float[]> samplesList = new ArrayList<Float[]>();
|
||||
|
||||
if( mBuffer != null )
|
||||
{
|
||||
/* Limit to 10, so that after a garbage collect we don't
|
||||
* induce wild swings as it tries to take tons of samples
|
||||
* and process them, causing delays and buffer refill */
|
||||
mBuffer.drainTo( samplesList, 10 );
|
||||
|
||||
for( Float[] samples: samplesList )
|
||||
{
|
||||
for( int x = 0; x < samples.length; x += 2 )
|
||||
{
|
||||
Float left = samples[ x ];
|
||||
Float right = samples[ x + 1 ];
|
||||
|
||||
if( left != null && right != null )
|
||||
{
|
||||
/* perform frequency translation */
|
||||
ComplexSample translated = ComplexSample.multiply(
|
||||
mSineWaveGenerator.nextComplex(), left, right );
|
||||
|
||||
/* decimate the sample rate */
|
||||
if( mDecimationFilters[ 0 ] != null )
|
||||
{
|
||||
mDecimationFilters[ 0 ].receive( translated );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
samplesList.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
260
src/source/tuner/TunerClass.java
Normal file
260
src/source/tuner/TunerClass.java
Normal file
@@ -0,0 +1,260 @@
|
||||
/*******************************************************************************
|
||||
* 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.usb.UsbDeviceDescriptor;
|
||||
|
||||
public enum TunerClass
|
||||
{
|
||||
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" ),
|
||||
COMPRO_VIDEOMATE_U650F( TunerType.ELONICS_E4000, "185B", "0650", "Compro", "Videomate U620F" ),
|
||||
COMPRO_VIDEOMATE_U680F( TunerType.ELONICS_E4000, "185B", "0680", "Compro", "Videomate U620F" ),
|
||||
DEXATEK_LOGILINK_VG002A( TunerType.FCI_FC2580, "1D19", "1101", "Dexatek", "Logilink VG0002A" ),
|
||||
DEXATEK_DIGIVOX_MINI_II_REV3( TunerType.FCI_FC2580, "1D19", "1102", "Dexatek", "MSI Digivox Mini II v3.0" ),
|
||||
DEXATEK_5217_DVBT( TunerType.FCI_FC2580, "1D19", "1103", "Dexatek", "5217 DVB-T" ),
|
||||
ETTUS_USRP_B100( TunerType.ETTUS_VARIOUS, "2500", "0002", "Ettus Research", "USRP B100" ),
|
||||
FUNCUBE_DONGLE_PRO( TunerType.FUNCUBE_DONGLE_PRO, "04D8", "FB56", "Hamlincrest", "Funcube Dongle Pro" ),
|
||||
FUNCUBE_DONGLE_PRO_PLUS( TunerType.FUNCUBE_DONGLE_PRO_PLUS, "04D8", "FB31", "Hamlincrest", "Funcube Dongle Pro Plus" ),
|
||||
GIGABYTE_GTU7300( TunerType.FITIPOWER_FC0012, "1B80", "D393", "Gigabyte", "GT-U7300" ),
|
||||
GTEK_T803( TunerType.FITIPOWER_FC0012, "1F4D", "B803", "GTek", "T803" ),
|
||||
LIFEVIEW_LV5T_DELUXE( TunerType.FITIPOWER_FC0012, "1F4D", "C803", "Liveview", "LV5T Deluxe" ),
|
||||
MYGICA_TD312( TunerType.FITIPOWER_FC0012, "1F4D", "D286", "MyGica", "TD312" ),
|
||||
PEAK_102569AGPK( TunerType.FITIPOWER_FC0012, "1B80", "D395", "Peak", "102569AGPK" ),
|
||||
PROLECTRIX_DV107669( TunerType.FITIPOWER_FC0012, "1F4D", "D803", "Prolectrix", "DV107669" ),
|
||||
SVEON_STV20( TunerType.FITIPOWER_FC0012, "1B80", "D39D", "Sveon", "STV20 DVB-T USB & FM" ),
|
||||
TERRATEC_CINERGY_T_REV1( TunerType.FITIPOWER_FC0012, "0CCD", "00A9", "Terratec", "Cinergy T R1" ),
|
||||
TERRATEC_CINERGY_T_REV3( TunerType.ELONICS_E4000, "0CCD", "00D3", "Terratec", "Cinergy T R3" ),
|
||||
TERRATEC_NOXON_REV1_B3( TunerType.FITIPOWER_FC0013, "0CCD", "00B3", "Terratec", "NOXON R1 (B3)" ),
|
||||
TERRATEC_NOXON_REV1_B4( TunerType.FITIPOWER_FC0013, "0CCD", "00B4", "Terratec", "NOXON R1 (B4)" ),
|
||||
TERRATEC_NOXON_REV1_B7( TunerType.FITIPOWER_FC0013, "0CCD", "00B7", "Terratec", "NOXON R1 (B7)" ),
|
||||
TERRATEC_NOXON_REV1_C6( TunerType.FITIPOWER_FC0013, "0CCD", "00C6", "Terratec", "NOXON R1 (C6)" ),
|
||||
TERRATEC_NOXON_REV2( TunerType.ELONICS_E4000, "0CCD", "00E0", "Terratec", "NOXON R2" ),
|
||||
TERRATEC_T_STICK_PLUS( TunerType.ELONICS_E4000, "0CCD", "00D7", "Terratec", "T Stick Plus" ),
|
||||
TWINTECH_UT40( TunerType.FITIPOWER_FC0013, "1B80", "D3A4", "Twintech", "UT-40" ),
|
||||
ZAAPA_ZTMINDVBZP( TunerType.FITIPOWER_FC0012, "1B80", "D398", "Zaapa", "ZT-MINDVBZP" ),
|
||||
UNKNOWN( TunerType.UNKNOWN, "0", "0", "Unknown Manufacturer", "Unknown Device" );
|
||||
|
||||
private TunerType mTunerType;
|
||||
private String mVendorID;
|
||||
private String mDeviceID;
|
||||
private String mVendorDescription;
|
||||
private String mDeviceDescription;
|
||||
|
||||
private TunerClass( TunerType tunerType,
|
||||
String vendorID,
|
||||
String deviceID,
|
||||
String vendorDescription,
|
||||
String deviceDescription )
|
||||
{
|
||||
mTunerType = tunerType;
|
||||
mVendorID = vendorID;
|
||||
mDeviceID = deviceID;
|
||||
mVendorDescription = vendorDescription;
|
||||
mDeviceDescription = deviceDescription;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "USB" +
|
||||
" Tuner:" + mTunerType.toString() +
|
||||
" Vendor:" + mVendorDescription +
|
||||
" Device:" + mDeviceDescription +
|
||||
" Address:" + mVendorID + ":" + mDeviceID;
|
||||
}
|
||||
|
||||
public String getVendorDeviceLabel()
|
||||
{
|
||||
return mVendorDescription + " " + mDeviceDescription;
|
||||
}
|
||||
|
||||
public TunerType getTunerClass()
|
||||
{
|
||||
return mTunerType;
|
||||
}
|
||||
|
||||
public static TunerClass valueOf( UsbDeviceDescriptor descriptor )
|
||||
{
|
||||
return valueOf( descriptor.idVendor(), descriptor.idProduct() );
|
||||
}
|
||||
|
||||
public static TunerClass valueOf( short vendor, short product )
|
||||
{
|
||||
TunerClass retVal = TunerClass.UNKNOWN;
|
||||
|
||||
//Cast the short to integer so that we can switch on unsigned numbers
|
||||
int vendorID = vendor & 0xFFFF;
|
||||
int productID = product & 0xFFFF;
|
||||
|
||||
switch( vendorID )
|
||||
{
|
||||
case 1240: //04DA
|
||||
if( productID == 64305 ) //FB31
|
||||
{
|
||||
retVal = FUNCUBE_DONGLE_PRO_PLUS;
|
||||
}
|
||||
else if( productID == 64342 ) //FB56
|
||||
{
|
||||
retVal = FUNCUBE_DONGLE_PRO;
|
||||
}
|
||||
break;
|
||||
case 3034: //0BDA
|
||||
if( productID == 10290 ) //2832
|
||||
{
|
||||
retVal = GENERIC_2832;
|
||||
}
|
||||
else if( productID == 10296 ) //2838
|
||||
{
|
||||
retVal = GENERIC_2838;
|
||||
}
|
||||
break;
|
||||
case 6235: //185B
|
||||
if( productID == 1568 ) //0620
|
||||
{
|
||||
retVal = COMPRO_VIDEOMATE_U620F;
|
||||
}
|
||||
else if( productID == 1616 ) //0650
|
||||
{
|
||||
retVal = COMPRO_VIDEOMATE_U650F;
|
||||
}
|
||||
else if( productID == 1664 ) //0680
|
||||
{
|
||||
retVal = COMPRO_VIDEOMATE_U680F;
|
||||
}
|
||||
break;
|
||||
case 7040: //1B80
|
||||
if( productID == 54163 ) //D393
|
||||
{
|
||||
retVal = GIGABYTE_GTU7300;
|
||||
}
|
||||
else if( productID == 54165 ) //D395
|
||||
{
|
||||
retVal = PEAK_102569AGPK;
|
||||
}
|
||||
else if( productID == 54168 ) //D398
|
||||
{
|
||||
retVal = ZAAPA_ZTMINDVBZP;
|
||||
}
|
||||
else if( productID == 54173 ) //D39D
|
||||
{
|
||||
retVal = SVEON_STV20;
|
||||
}
|
||||
else if( productID == 54180 ) //D3A4
|
||||
{
|
||||
retVal = TWINTECH_UT40;
|
||||
}
|
||||
break;
|
||||
case 7449: //1D19
|
||||
if( productID == 4353 ) //1101
|
||||
{
|
||||
retVal = DEXATEK_LOGILINK_VG002A;
|
||||
}
|
||||
else if( productID == 4354 ) //1102
|
||||
{
|
||||
retVal = DEXATEK_DIGIVOX_MINI_II_REV3;
|
||||
}
|
||||
else if( productID == 4355 ) //1103
|
||||
{
|
||||
retVal = DEXATEK_5217_DVBT;
|
||||
}
|
||||
break;
|
||||
case 8013: //1F4D
|
||||
if( productID == 47107 ) //B803
|
||||
{
|
||||
retVal = GTEK_T803;
|
||||
}
|
||||
else if( productID == 51203 ) //C803
|
||||
{
|
||||
retVal = LIFEVIEW_LV5T_DELUXE;
|
||||
}
|
||||
else if( productID == 53894 ) //D286
|
||||
{
|
||||
retVal = MYGICA_TD312;
|
||||
}
|
||||
else if( productID == 55299 ) //D803
|
||||
{
|
||||
retVal = PROLECTRIX_DV107669;
|
||||
}
|
||||
break;
|
||||
case 3277: //0CCD
|
||||
if( productID == 169 ) //00A9
|
||||
{
|
||||
retVal = TERRATEC_CINERGY_T_REV1;
|
||||
}
|
||||
else if( productID == 179 ) //00B3
|
||||
{
|
||||
retVal = TERRATEC_NOXON_REV1_B3;
|
||||
}
|
||||
else if( productID == 180 ) //00B4
|
||||
{
|
||||
retVal = TERRATEC_NOXON_REV1_B4;
|
||||
}
|
||||
else if( productID == 181 ) //00B5
|
||||
{
|
||||
retVal = TERRATEC_NOXON_REV1_B7;
|
||||
}
|
||||
else if( productID == 198 ) //00C6
|
||||
{
|
||||
retVal = TERRATEC_NOXON_REV1_C6;
|
||||
}
|
||||
else if( productID == 211 ) //00D3
|
||||
{
|
||||
retVal = TERRATEC_CINERGY_T_REV3;
|
||||
}
|
||||
else if( productID == 215 ) //00D7
|
||||
{
|
||||
retVal = TERRATEC_T_STICK_PLUS;
|
||||
}
|
||||
else if( productID == 224) //00E0
|
||||
{
|
||||
retVal = TERRATEC_NOXON_REV2;
|
||||
}
|
||||
break;
|
||||
case 9472: //2500
|
||||
if( productID == 2 ) //0002
|
||||
{
|
||||
retVal = ETTUS_USRP_B100;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public String getVendorID()
|
||||
{
|
||||
return mVendorID;
|
||||
}
|
||||
|
||||
public String getDeviceID()
|
||||
{
|
||||
return mDeviceID;
|
||||
}
|
||||
|
||||
public String getVendorDescription()
|
||||
{
|
||||
return mVendorDescription;
|
||||
}
|
||||
|
||||
public String getDeviceDescription()
|
||||
{
|
||||
return mDeviceDescription;
|
||||
}
|
||||
}
|
||||
65
src/source/tuner/TunerConfiguration.java
Normal file
65
src/source/tuner/TunerConfiguration.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* Abstract class to hold a named configuration for a specific type of tuner
|
||||
*/
|
||||
@XmlType( name = "tuner_configuration" )
|
||||
public abstract class TunerConfiguration
|
||||
{
|
||||
protected String mName;
|
||||
|
||||
/**
|
||||
* Default constructor to support JAXB
|
||||
*/
|
||||
public TunerConfiguration()
|
||||
{
|
||||
this( "Unknown" );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normal constructor
|
||||
*/
|
||||
public TunerConfiguration( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "name" )
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "tuner_type" )
|
||||
public abstract TunerType getTunerType();
|
||||
}
|
||||
64
src/source/tuner/TunerConfigurationAssignment.java
Normal file
64
src/source/tuner/TunerConfigurationAssignment.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
250
src/source/tuner/TunerController.java
Normal file
250
src/source/tuner/TunerController.java
Normal file
@@ -0,0 +1,250 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import log.Log;
|
||||
import source.SourceException;
|
||||
import source.tuner.FrequencyController.Tunable;
|
||||
import controller.ThreadPoolManager;
|
||||
|
||||
public abstract class TunerController implements Tunable
|
||||
{
|
||||
/* List of currently tuned channels being served to demod channels */
|
||||
protected ArrayList<TunerChannel> mTunedChannels =
|
||||
new ArrayList<TunerChannel>();
|
||||
|
||||
protected FrequencyController mFrequencyController;
|
||||
|
||||
/**
|
||||
* Abstract tuner controller class. The tuner controller manages frequency
|
||||
* bandwidth and currently tuned channels that are being fed samples from
|
||||
* the tuner.
|
||||
*
|
||||
* @param minimumFrequency - minimum uncorrected tunable frequency
|
||||
* @param maximumFrequency - maximum uncorrected tunable frequency
|
||||
* @throws SourceException - for any issues related to constructing the
|
||||
* class, tuning a frequency, or setting the bandwidth
|
||||
*/
|
||||
public TunerController( int minimumFrequency, int maximumFrequency )
|
||||
throws SourceException
|
||||
{
|
||||
mFrequencyController = new FrequencyController( this,
|
||||
minimumFrequency,
|
||||
maximumFrequency,
|
||||
0.0d );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the settings in the tuner configuration
|
||||
*/
|
||||
public abstract void apply( TunerConfiguration config )
|
||||
throws SourceException;
|
||||
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mFrequencyController.getBandwidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the center frequency of the local oscillator.
|
||||
*
|
||||
* @param frequency in hertz
|
||||
* @throws SourceException - if the tuner has any issues
|
||||
*/
|
||||
public void setFrequency( int frequency ) throws SourceException
|
||||
{
|
||||
mFrequencyController.setFrequency( frequency );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the center frequency of the local oscillator
|
||||
*
|
||||
* @return frequency in hertz
|
||||
*/
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequencyController.getFrequency();
|
||||
}
|
||||
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyController.getFrequencyCorrection();
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double correction ) throws SourceException
|
||||
{
|
||||
mFrequencyController.setFrequencyCorrection( correction );
|
||||
}
|
||||
|
||||
public int getMinFrequency()
|
||||
{
|
||||
return mFrequencyController.getMinimumFrequency();
|
||||
}
|
||||
|
||||
public int getMaxFrequency()
|
||||
{
|
||||
return mFrequencyController.getMaximumFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the tuner can accomodate this new channel frequency and
|
||||
* bandwidth, along with all of the existing tuned channels currently in
|
||||
* place.
|
||||
*/
|
||||
public boolean canTuneChannel( TunerChannel channel )
|
||||
{
|
||||
//Make sure we're within the tunable frequency range of this tuner
|
||||
if( getMinFrequency() < channel.getMinFrequency() &&
|
||||
getMaxFrequency() > channel.getMaxFrequency() )
|
||||
{
|
||||
//If this is the first lock, then we're good
|
||||
if( mTunedChannels.isEmpty() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Sort the existing locks and get the min/max locked frequencies
|
||||
Collections.sort( mTunedChannels );
|
||||
|
||||
int minLockedFrequency = mTunedChannels.get( 0 ).getMinFrequency();
|
||||
int maxLockedFrequency = mTunedChannels
|
||||
.get( mTunedChannels.size() - 1 ).getMaxFrequency();
|
||||
|
||||
//Requested channel is higher than min locked frequency
|
||||
if( minLockedFrequency <= channel.getMinFrequency() &&
|
||||
( channel.getMaxFrequency() - minLockedFrequency ) <= getBandwidth() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//Requested channel is lower than the max locked frequency
|
||||
else if( channel.getMaxFrequency() <= maxLockedFrequency &&
|
||||
( maxLockedFrequency - channel.getMinFrequency() ) <= getBandwidth() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public TunerChannelSource getChannel( ThreadPoolManager threadPoolManager,
|
||||
Tuner tuner, TunerChannel tunerChannel )
|
||||
throws RejectedExecutionException,
|
||||
SourceException
|
||||
{
|
||||
TunerChannelSource source = null;
|
||||
|
||||
if( canTuneChannel( tunerChannel ) )
|
||||
{
|
||||
mTunedChannels.add( tunerChannel );
|
||||
|
||||
updateLOFrequency();
|
||||
|
||||
source = new TunerChannelSource( threadPoolManager, tuner, tunerChannel );
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
public void releaseChannel( TunerChannelSource tunerChannelSource )
|
||||
{
|
||||
if( tunerChannelSource != null )
|
||||
{
|
||||
mTunedChannels.remove( tunerChannelSource.getTunerChannel() );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( "Tuner Controller - couldn't find the tuned channel "
|
||||
+ "to release it" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Local Oscillator frequency to the middle of the currently
|
||||
* locked frequency range, adjusting the left/right of a channel, if the
|
||||
* middle falls within the locked range of any of the channels. Note: this
|
||||
* will fail to set the correct frequency if multiple overlapping channel
|
||||
* bandwidths are locked in the exact middle of the total locked channel
|
||||
* frequency range.
|
||||
*
|
||||
* @throws SourceException
|
||||
*/
|
||||
public void updateLOFrequency() throws SourceException
|
||||
{
|
||||
Collections.sort( mTunedChannels );
|
||||
|
||||
int minLockedFrequency = mTunedChannels.get( 0 ).getMinFrequency();
|
||||
int maxLockedFrequency = mTunedChannels
|
||||
.get( mTunedChannels.size() - 1 ).getMaxFrequency();
|
||||
|
||||
int middle = minLockedFrequency +
|
||||
( ( maxLockedFrequency - minLockedFrequency ) / 2 );
|
||||
int middleMin = middle - 10000;
|
||||
int middleMax = middle + 10000;
|
||||
|
||||
Iterator<TunerChannel> it = mTunedChannels.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
{
|
||||
TunerChannel lock = it.next();
|
||||
|
||||
//If a locked channel overlaps our middle frequency lockout, adjust to
|
||||
//the left or the right of that channel, whichever is closer
|
||||
if( lock.getMinFrequency() < middleMax && middleMin < lock.getMaxFrequency() )
|
||||
{
|
||||
if( middleMax - lock.getMinFrequency() < lock.getMaxFrequency() - middleMin )
|
||||
{
|
||||
middle = lock.getMinFrequency() - 10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
middle = lock.getMaxFrequency() + 10000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mFrequencyController.setFrequency( middle );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener to be notified any time that the tuner changes frequency
|
||||
* or bandwidth/sample rate.
|
||||
*
|
||||
* Note: this is normally used by the Tuner. Any additional listeners can
|
||||
* be registered on the tuner.
|
||||
*/
|
||||
public void addListener( FrequencyChangeListener listener )
|
||||
{
|
||||
mFrequencyController.addListener( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the frequency change listener
|
||||
*/
|
||||
public void removeListener( FrequencyChangeListener listener )
|
||||
{
|
||||
mFrequencyController.removeListener( listener );
|
||||
}
|
||||
}
|
||||
57
src/source/tuner/TunerEditor.java
Normal file
57
src/source/tuner/TunerEditor.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
* 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 source.SourceEditor;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.config.SourceConfiguration;
|
||||
|
||||
public class TunerEditor extends SourceEditor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JFrequencyControl mFrequencyControl;
|
||||
|
||||
public TunerEditor( SourceConfiguration config )
|
||||
{
|
||||
super( config );
|
||||
|
||||
initGUI();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
mFrequencyControl.setFrequency(
|
||||
((SourceConfigTuner)mConfig).getFrequency(), false );
|
||||
}
|
||||
|
||||
public void save()
|
||||
{
|
||||
((SourceConfigTuner)mConfig).setFrequency( mFrequencyControl.getFrequency() );
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
mFrequencyControl = new JFrequencyControl();
|
||||
|
||||
mFrequencyControl.setFrequency(
|
||||
((SourceConfigTuner)mConfig).getFrequency(), false );
|
||||
|
||||
add( mFrequencyControl );
|
||||
}
|
||||
}
|
||||
35
src/source/tuner/TunerGroupNode.java
Normal file
35
src/source/tuner/TunerGroupNode.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.BaseNode;
|
||||
|
||||
public class TunerGroupNode extends BaseNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public TunerGroupNode()
|
||||
{
|
||||
super( null );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Tuners [" + this.getChildCount() + "]";
|
||||
}
|
||||
}
|
||||
547
src/source/tuner/TunerManager.java
Normal file
547
src/source/tuner/TunerManager.java
Normal file
@@ -0,0 +1,547 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import javax.usb.UsbDevice;
|
||||
import javax.usb.UsbException;
|
||||
import javax.usb.UsbHostManager;
|
||||
import javax.usb.UsbHub;
|
||||
import javax.usb.UsbServices;
|
||||
|
||||
import log.Log;
|
||||
|
||||
import org.usb4java.Context;
|
||||
import org.usb4java.DeviceList;
|
||||
import org.usb4java.LibUsb;
|
||||
import org.usb4java.LibUsbException;
|
||||
|
||||
import source.Source;
|
||||
import source.SourceException;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.mixer.MixerManager;
|
||||
import source.tuner.ettus.B100Tuner;
|
||||
import source.tuner.fcd.FCDTuner;
|
||||
import source.tuner.fcd.proV1.FCD1TunerController;
|
||||
import source.tuner.fcd.proplusV2.FCD2TunerController;
|
||||
import source.tuner.rtl.RTL2832Tuner;
|
||||
import source.tuner.rtl.RTL2832TunerController;
|
||||
import source.tuner.rtl.e4k.E4KTunerController;
|
||||
import source.tuner.rtl.r820t.R820TTunerController;
|
||||
import source.tuner.usb.USBTunerDevice;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.ProcessingChain;
|
||||
|
||||
public class TunerManager
|
||||
{
|
||||
private static final String sLOADED = "\t[LOADED]\t";
|
||||
private static final String sNOT_LOADED = "\t[NOT LOADED]\t";
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
|
||||
private ArrayList<Tuner> mTuners = new ArrayList<Tuner>();
|
||||
|
||||
public TunerManager( ResourceManager resourceManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
loadTuners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates current tuners to get a tuner channel source for the frequency
|
||||
* specified in the channel config's source config object
|
||||
*/
|
||||
public Source getSource( ProcessingChain channel )
|
||||
{
|
||||
TunerChannelSource retVal = null;
|
||||
|
||||
|
||||
if( channel.getChannel().getSourceConfiguration()
|
||||
instanceof SourceConfigTuner )
|
||||
{
|
||||
TunerChannel tunerChannel = channel.getChannel().getTunerChannel();
|
||||
|
||||
Iterator<Tuner> it = mTuners.iterator();
|
||||
|
||||
Tuner tuner;
|
||||
|
||||
while( it.hasNext() && retVal == null )
|
||||
{
|
||||
tuner = it.next();
|
||||
|
||||
try
|
||||
{
|
||||
retVal = tuner.getChannel(
|
||||
mResourceManager.getThreadPoolManager(), tunerChannel );
|
||||
}
|
||||
catch ( RejectedExecutionException ree )
|
||||
{
|
||||
Log.error( "TunerManager - couldn't provide tuner channel "
|
||||
+ "source - " + ree.getLocalizedMessage() );
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
Log.error( "TunerManager - error obtaining channel " +
|
||||
"from tuner [" + tuner.getName() + "] - "
|
||||
+ e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of current tuners
|
||||
*/
|
||||
public List<Tuner> getTuners()
|
||||
{
|
||||
return mTuners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all USB tuners and USB/Mixer tuner devices
|
||||
*/
|
||||
private void loadTuners()
|
||||
{
|
||||
mTuners.clear();
|
||||
|
||||
//Get list of attached USB tuner devices
|
||||
ArrayList<USBTunerDevice> devices = getUSBTunerDevices();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "Tuner Manager - discovered [" + devices.size() +
|
||||
"] USB tuner devices\n" );
|
||||
|
||||
for( USBTunerDevice device: devices )
|
||||
{
|
||||
String status = sNOT_LOADED;
|
||||
String name = "Unknown";
|
||||
String reason = "No device driver class available";
|
||||
|
||||
TunerClass tunerClass = device.getTunerClass();
|
||||
|
||||
switch( tunerClass )
|
||||
{
|
||||
case FUNCUBE_DONGLE_PRO:
|
||||
//Locate the matching mixer tuner dataline
|
||||
MixerTunerDataLine fcd1Dataline =
|
||||
getMixerTunerDataLine( tunerClass.getTunerClass() );
|
||||
if( fcd1Dataline != null )
|
||||
{
|
||||
FCD1TunerController fcd1Controller;
|
||||
|
||||
try
|
||||
{
|
||||
fcd1Controller = new FCD1TunerController( device );
|
||||
|
||||
FCDTuner fcd1Tuner =
|
||||
new FCDTuner( fcd1Dataline, fcd1Controller );
|
||||
|
||||
TunerConfiguration config =
|
||||
getTunerConfiguration( fcd1Tuner );
|
||||
|
||||
if( config != null )
|
||||
{
|
||||
fcd1Tuner.apply( config );
|
||||
}
|
||||
|
||||
mTuners.add( fcd1Tuner );
|
||||
|
||||
name = fcd1Tuner.getName();
|
||||
status = sLOADED;
|
||||
reason = null;
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
reason = "Controller Source Exception: " +
|
||||
e.getLocalizedMessage();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = "Couldn't locate matching mixer/sound card device";
|
||||
}
|
||||
break;
|
||||
case FUNCUBE_DONGLE_PRO_PLUS:
|
||||
//Locate the matching mixer tuner dataline
|
||||
MixerTunerDataLine fcd2Dataline =
|
||||
getMixerTunerDataLine( tunerClass.getTunerClass() );
|
||||
|
||||
if( fcd2Dataline != null )
|
||||
{
|
||||
FCD2TunerController fcd2Controller;
|
||||
|
||||
try
|
||||
{
|
||||
fcd2Controller = new FCD2TunerController( device );
|
||||
|
||||
FCDTuner fcd2Tuner =
|
||||
new FCDTuner( fcd2Dataline, fcd2Controller );
|
||||
|
||||
TunerConfiguration config =
|
||||
getTunerConfiguration( fcd2Tuner );
|
||||
|
||||
if( config != null )
|
||||
{
|
||||
fcd2Tuner.apply( config );
|
||||
}
|
||||
|
||||
mTuners.add( fcd2Tuner );
|
||||
|
||||
status = sLOADED;
|
||||
name = fcd2Tuner.getName();
|
||||
reason = null;
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
reason = "Controller Source Exception: " +
|
||||
e.getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = "Couldn't locate matching mixer/sound card device";
|
||||
}
|
||||
break;
|
||||
case GENERIC_2832:
|
||||
case COMPRO_VIDEOMATE_U620F:
|
||||
case COMPRO_VIDEOMATE_U650F:
|
||||
case COMPRO_VIDEOMATE_U680F:
|
||||
case DEXATEK_5217_DVBT:
|
||||
case DEXATEK_DIGIVOX_MINI_II_REV3:
|
||||
case DEXATEK_LOGILINK_VG002A:
|
||||
case GENERIC_2838:
|
||||
case GIGABYTE_GTU7300:
|
||||
case GTEK_T803:
|
||||
case LIFEVIEW_LV5T_DELUXE:
|
||||
case MYGICA_TD312:
|
||||
case PEAK_102569AGPK:
|
||||
case PROLECTRIX_DV107669:
|
||||
case SVEON_STV20:
|
||||
case TERRATEC_CINERGY_T_REV1:
|
||||
case TERRATEC_CINERGY_T_REV3:
|
||||
case TERRATEC_NOXON_REV1_B3:
|
||||
case TERRATEC_NOXON_REV1_B4:
|
||||
case TERRATEC_NOXON_REV1_B7:
|
||||
case TERRATEC_NOXON_REV1_C6:
|
||||
case TERRATEC_NOXON_REV2:
|
||||
case TERRATEC_T_STICK_PLUS:
|
||||
case TWINTECH_UT40:
|
||||
case ZAAPA_ZTMINDVBZP:
|
||||
TunerType tunerType = tunerClass.getTunerClass();
|
||||
|
||||
if( tunerType == TunerType.RTL2832_VARIOUS )
|
||||
{
|
||||
tunerType = RTL2832TunerController.identifyTunerType( device );
|
||||
}
|
||||
|
||||
switch( tunerType )
|
||||
{
|
||||
case ELONICS_E4000:
|
||||
try
|
||||
{
|
||||
E4KTunerController controller =
|
||||
new E4KTunerController( device );
|
||||
|
||||
controller.init();
|
||||
|
||||
RTL2832Tuner rtlTuner =
|
||||
new RTL2832Tuner( tunerClass, controller );
|
||||
|
||||
TunerConfiguration config =
|
||||
getTunerConfiguration( rtlTuner );
|
||||
|
||||
if( config != null )
|
||||
{
|
||||
rtlTuner.apply( config );
|
||||
}
|
||||
|
||||
mTuners.add( rtlTuner );
|
||||
status = sLOADED;
|
||||
name = rtlTuner.getName();
|
||||
reason = null;
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
status = sNOT_LOADED;
|
||||
reason = "Error constructing E4K tuner "
|
||||
+ "controller - " + se.getLocalizedMessage();
|
||||
}
|
||||
break;
|
||||
case RAFAELMICRO_R820T:
|
||||
// try
|
||||
// {
|
||||
// R820TTunerController controller =
|
||||
// new R820TTunerController( device );
|
||||
//
|
||||
// controller.init();
|
||||
//
|
||||
// RTL2832Tuner rtlTuner =
|
||||
// new RTL2832Tuner( tunerClass, controller );
|
||||
//
|
||||
//
|
||||
// TunerConfiguration config =
|
||||
// getTunerConfiguration( rtlTuner );
|
||||
//
|
||||
// if( config != null )
|
||||
// {
|
||||
// rtlTuner.apply( config );
|
||||
// }
|
||||
//
|
||||
// mTuners.add( rtlTuner );
|
||||
// status = sLOADED;
|
||||
// name = rtlTuner.getName();
|
||||
// reason = null;
|
||||
// }
|
||||
// catch( SourceException se )
|
||||
// {
|
||||
// status = sNOT_LOADED;
|
||||
// reason = "Error constructing E4K tuner "
|
||||
// + "controller - " + se.getLocalizedMessage();
|
||||
// }
|
||||
// break;
|
||||
case FITIPOWER_FC0012:
|
||||
case FITIPOWER_FC0013:
|
||||
case RAFAELMICRO_R828D:
|
||||
case UNKNOWN:
|
||||
default:
|
||||
status = sNOT_LOADED;
|
||||
reason = "SDRTRunk doesn't currently support RTL2832 "
|
||||
+ "Dongle with [" + tunerType.toString() +
|
||||
"] tuner";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ETTUS_USRP_B100:
|
||||
mTuners.add( new B100Tuner( device ) );
|
||||
status = sLOADED;
|
||||
reason = null;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the tuner loading status
|
||||
*/
|
||||
sb.append( status );
|
||||
sb.append( String.format( "%04X",
|
||||
device.getDevice().getUsbDeviceDescriptor().idVendor() ) );
|
||||
sb.append( ":" );
|
||||
sb.append( String.format( "%04X",
|
||||
device.getDevice().getUsbDeviceDescriptor().idProduct() ) );
|
||||
sb.append( " " );
|
||||
// sb.append( device.getTunerType().getVendorDescription() );
|
||||
// sb.append( " " );
|
||||
// sb.append( device.getTunerType().getDeviceDescription() );
|
||||
|
||||
sb.append( name );
|
||||
|
||||
if( reason != null )
|
||||
{
|
||||
sb.append( " - " );
|
||||
sb.append( reason );
|
||||
}
|
||||
|
||||
sb.append( "\n" );
|
||||
}
|
||||
|
||||
Log.header( "Configuring USB Tuners" );
|
||||
Log.info( sb.toString() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all USB tuner devices
|
||||
*/
|
||||
private ArrayList<USBTunerDevice> getUSBTunerDevices()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
List<UsbDevice> devices = getUSBDevices();
|
||||
|
||||
sb.append( "TunerManager - discovered [" + devices.size() +
|
||||
"] attached usb devices\n" );
|
||||
|
||||
ArrayList<USBTunerDevice> tuners = new ArrayList<USBTunerDevice>();
|
||||
|
||||
for (UsbDevice device : devices )
|
||||
{
|
||||
String status = "\t[NOT RECOGNIZED]\t";
|
||||
|
||||
TunerClass type = TunerClass.valueOf( device.getUsbDeviceDescriptor() );
|
||||
|
||||
if( type != TunerClass.UNKNOWN )
|
||||
{
|
||||
status = "\t[RECOGNIZED] \t";
|
||||
tuners.add( new USBTunerDevice( device, type) );
|
||||
}
|
||||
|
||||
sb.append( status );
|
||||
sb.append( device.toString() );
|
||||
|
||||
if( type != TunerClass.UNKNOWN )
|
||||
{
|
||||
sb.append( " " );
|
||||
sb.append( type.getVendorDescription() );
|
||||
sb.append( " " );
|
||||
sb.append( type.getDeviceDescription() );
|
||||
}
|
||||
|
||||
sb.append( "\n" );
|
||||
}
|
||||
|
||||
Log.header( "USB Device Discovery" );
|
||||
Log.info( sb.toString() );
|
||||
|
||||
return tuners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all USB devices from the root hub downward, recursively, or
|
||||
* returns empty list if none are discovered
|
||||
*/
|
||||
public static List<UsbDevice> getUSBDevices()
|
||||
{
|
||||
ArrayList<UsbDevice> devices = new ArrayList<UsbDevice>();
|
||||
|
||||
try
|
||||
{
|
||||
UsbServices services = UsbHostManager.getUsbServices();
|
||||
devices = getUsbChildDevices( services.getRootUsbHub() );
|
||||
}
|
||||
catch( SecurityException e )
|
||||
{
|
||||
Log.error( "TunerManager - security exception while getting "
|
||||
+ "USB devices" );
|
||||
}
|
||||
catch( UsbException e )
|
||||
{
|
||||
Log.error( "TunerManager - usb exception while getting USB "
|
||||
+ "devices - " + e.getLocalizedMessage() );
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get (recursively) all usb child devices below the usb hub
|
||||
*/
|
||||
public static ArrayList<UsbDevice> getUsbChildDevices( UsbHub hub )
|
||||
{
|
||||
ArrayList<UsbDevice> devices = new ArrayList<UsbDevice>();
|
||||
|
||||
for ( UsbDevice device : (List<UsbDevice>) hub.getAttachedUsbDevices() )
|
||||
{
|
||||
devices.add( device );
|
||||
|
||||
if ( device.isUsbHub() )
|
||||
{
|
||||
devices.addAll( getUsbChildDevices( (UsbHub)device ) );
|
||||
}
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config = configs.get( 0 );
|
||||
}
|
||||
|
||||
//If we're still null at this point, create a default config
|
||||
if( config == null )
|
||||
{
|
||||
config = mResourceManager.getSettingsManager()
|
||||
.addNewTunerConfiguration( tuner.getTunerType(), "Default" );
|
||||
}
|
||||
|
||||
//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.
|
||||
*
|
||||
* Note: this method is not currently able to align multiple tuner mixer
|
||||
* data lines of the same tuner type. If you have multiple Funcube Dongle
|
||||
* tuners of the same TYPE, there is no guarantee that you will get the
|
||||
* correct mixer.
|
||||
*
|
||||
* @param tunerClass
|
||||
* @return
|
||||
*/
|
||||
private MixerTunerDataLine getMixerTunerDataLine( TunerType tunerClass )
|
||||
{
|
||||
Collection<MixerTunerDataLine> datalines =
|
||||
MixerManager.getInstance().getMixerTunerDataLines();
|
||||
|
||||
for( MixerTunerDataLine mixerTDL: datalines )
|
||||
{
|
||||
if( mixerTDL.getMixerTunerType().getTunerClass() == tunerClass )
|
||||
{
|
||||
return mixerTDL;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
127
src/source/tuner/TunerNode.java
Normal file
127
src/source/tuner/TunerNode.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
* 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 log.Log;
|
||||
import source.SourceException;
|
||||
import spectrum.SpectrumFrame;
|
||||
import controller.BaseNode;
|
||||
|
||||
public class TunerNode extends BaseNode implements FrequencyChangeListener
|
||||
{
|
||||
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 int mFrequency;
|
||||
private int mBandwidth;
|
||||
|
||||
public TunerNode( Tuner tuner )
|
||||
{
|
||||
super( tuner ); //does this make it a super tuner?
|
||||
|
||||
tuner.addListener( this );
|
||||
|
||||
try
|
||||
{
|
||||
mFrequency = tuner.getFrequency();
|
||||
mBandwidth = tuner.getSampleRate();
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
Log.error( "TunerNode - error reading frequency and sample rate "
|
||||
+ "from tuner - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
@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)mBandwidth / 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 )
|
||||
{
|
||||
SpectrumFrame frame =
|
||||
new SpectrumFrame( getModel().getResourceManager(),
|
||||
getTuner() );
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( newSpectrumItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged( int frequency, int bandwidth )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
mBandwidth = bandwidth;
|
||||
|
||||
getModel().nodeChanged( TunerNode.this );
|
||||
}
|
||||
}
|
||||
23
src/source/tuner/TunerSelectionListener.java
Normal file
23
src/source/tuner/TunerSelectionListener.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* 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 );
|
||||
}
|
||||
46
src/source/tuner/TunerType.java
Normal file
46
src/source/tuner/TunerType.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
* 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 enum TunerType
|
||||
{
|
||||
ELONICS_E4000( "E4000" ),
|
||||
ETTUS_WBX( "WBX" ),
|
||||
ETTUS_VARIOUS( "Ettus Tuner" ),
|
||||
FCI_FC2580( "FC2580" ),
|
||||
FITIPOWER_FC0012( "FC0012" ),
|
||||
FITIPOWER_FC0013( "FC0013" ),
|
||||
FUNCUBE_DONGLE_PRO( "Funcube Dongle Pro" ),
|
||||
FUNCUBE_DONGLE_PRO_PLUS( "Funcube Dongle Pro Plus" ),
|
||||
RAFAELMICRO_R820T( "R820T" ),
|
||||
RAFAELMICRO_R828D( "R828D" ),
|
||||
RTL2832_VARIOUS( "Generic" ),
|
||||
UNKNOWN( "Unknown" );
|
||||
|
||||
private String mLabel;
|
||||
|
||||
private TunerType( String label )
|
||||
{
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
}
|
||||
106
src/source/tuner/ettus/B100Tuner.java
Normal file
106
src/source/tuner/ettus/B100Tuner.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/*******************************************************************************
|
||||
* 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.ettus;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import log.Log;
|
||||
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 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return TunerClass.ETTUS_USRP_B100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.ETTUS_WBX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getEditor( ResourceManager resourceManager )
|
||||
{
|
||||
return new B100TunerEditorPanel( this, resourceManager );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply( TunerConfiguration config ) throws SourceException
|
||||
{
|
||||
Log.error( "B100 Tuner - can't apply tuner configuration" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSampleRate()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrequency() throws SourceException
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel( ThreadPoolManager threadPoolManager,
|
||||
TunerChannel channel ) throws RejectedExecutionException, SourceException
|
||||
{
|
||||
//TODO: pass this call to the tuner controller
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseChannel( TunerChannelSource source )
|
||||
{
|
||||
//TODO: pass this call to the tuner controller
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
50
src/source/tuner/ettus/B100TunerEditorPanel.java
Normal file
50
src/source/tuner/ettus/B100TunerEditorPanel.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* 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.ettus;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class B100TunerEditorPanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private B100Tuner mTuner;
|
||||
private ResourceManager mResourceManager;
|
||||
|
||||
public B100TunerEditorPanel( B100Tuner tuner, ResourceManager resourceManager )
|
||||
{
|
||||
mTuner = tuner;
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) );
|
||||
|
||||
setBorder( BorderFactory.createTitledBorder( "Ettus B100 Tuner" ) );
|
||||
|
||||
add( new JLabel( "Note: SDRTrunk can only recognize the B100 at this time. It cannot use this tuner") );
|
||||
}
|
||||
}
|
||||
163
src/source/tuner/fcd/FCDCommand.java
Normal file
163
src/source/tuner/fcd/FCDCommand.java
Normal file
@@ -0,0 +1,163 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public enum FCDCommand
|
||||
{
|
||||
/**
|
||||
* Note: the javaxUSB and usb4Java libraries are slightly different than
|
||||
* the signal9 HID libraries used in C, so you will see variations in the
|
||||
* byte array length and indexes, when comparing this setup to the qthid
|
||||
* source code.
|
||||
*/
|
||||
//Bootloader Mode Commands
|
||||
BL_QUERY( (byte) 0x01, 64 ), //01 Decimal
|
||||
BL_RESET( (byte) 0x08, 2 ), //08
|
||||
BL_ERASE( (byte) 0x19, 2 ), //24
|
||||
BL_SET_BYTE_ADDR( (byte) 0x1A, 6 ), //25
|
||||
BL_GET_BYTE_ADDR_RANGE( (byte) 0x1B, 6 ), //26
|
||||
BL_WRITE_FLASH_BLOCK( (byte) 0x1C, 52 ), //27
|
||||
BL_READ_FLASH_BLOCK( (byte) 0x1D, 48 ), //28
|
||||
|
||||
//Application Mode Commands
|
||||
APP_SET_FREQUENCY_KHZ( (byte)0x64, 5 ), //100
|
||||
APP_SET_FREQUENCY_HZ( (byte)0x65, 6 ), //101
|
||||
APP_GET_FREQUENCY_HZ( (byte)0x66, 6 ), //102
|
||||
APP_GET_IF_RSSI( (byte) 0x68, 3 ), //104
|
||||
APP_GET_PLL_LOCKED( (byte) 0x69, 3 ), //105
|
||||
APP_SET_DC_CORRECTION( (byte) 0x6A, 5 ), //106
|
||||
APP_GET_DC_CORRECTION( (byte) 0x6B, 6 ), //107
|
||||
APP_SET_IQ_CORRECTION( (byte) 0x6C, 5 ), //108
|
||||
APP_GET_IQ_CORRECTION( (byte) 0x6D, 6 ), //109
|
||||
APP_SET_LNA_GAIN( (byte)0x6E, 2 ), //110
|
||||
APP_SET_LNA_ENHANCE( (byte)0x6F, 2 ), //111
|
||||
APP_SET_BAND( (byte)0x70, 2 ), //112
|
||||
APP_SET_RF_FILTER( (byte)0x71, 2 ), //113
|
||||
APP_SET_MIXER_GAIN( (byte)0x72, 2 ), //114
|
||||
APP_SET_BIAS_CURRENT( (byte)0x73, 2 ), //115
|
||||
APP_SET_MIXER_FILTER( (byte)0x74, 2 ), //116
|
||||
APP_SET_IF_GAIN1( (byte)0x75, 2 ), //117
|
||||
APP_SET_IF_GAIN_MODE( (byte)0x76, 2 ), //118
|
||||
APP_SET_IF_RC_FILTER( (byte)0x77, 2 ), //119
|
||||
APP_SET_IF_GAIN2( (byte)0x78, 2 ), //120
|
||||
APP_SET_IF_GAIN3( (byte)0x79, 2 ), //121
|
||||
APP_SET_IF_FILTER( (byte)0x7A, 2 ), //122
|
||||
APP_SET_IF_GAIN4( (byte)0x7B, 2 ), //123
|
||||
APP_SET_IF_GAIN5( (byte)0x7C, 2 ), //124
|
||||
APP_SET_IF_GAIN6( (byte)0x7D, 2 ), //125
|
||||
APP_SET_BIAS_TEE( (byte)0x7E, 2 ), //126
|
||||
|
||||
APP_GET_LNA_GAIN( (byte)0x96, 3 ), //150
|
||||
APP_GET_LNA_ENHANCE( (byte)0x97, 3 ), //151
|
||||
APP_GET_BAND( (byte)0x98, 3 ), //152
|
||||
APP_GET_RF_FILTER( (byte)0x99, 3 ), //153
|
||||
APP_GET_MIXER_GAIN( (byte)0x9A, 3 ), //154
|
||||
APP_GET_BIAS_CURRENT( (byte)0x9B, 3 ), //155
|
||||
APP_GET_MIXER_FILTER( (byte)0x9C, 3 ), //156
|
||||
APP_GET_IF_GAIN1( (byte)0x9D, 3 ), //157
|
||||
APP_GET_IF_GAIN_MODE( (byte)0x9E, 3 ), //158
|
||||
APP_GET_IF_RC_FILTER( (byte)0x9F, 3 ), //159
|
||||
APP_GET_IF_GAIN2( (byte)0xA0, 3 ), //160
|
||||
APP_GET_IF_GAIN3( (byte)0xA1, 3 ), //161
|
||||
APP_GET_IF_FILTER( (byte)0xA2, 3 ), //162
|
||||
APP_GET_IF_GAIN4( (byte)0xA3, 3 ), //163
|
||||
APP_GET_IF_GAIN5( (byte)0xA4, 3 ), //164
|
||||
APP_GET_IF_GAIN6( (byte)0xA5, 3 ), //165
|
||||
APP_GET_BIAS_TEE( (byte)0xA6, 3 ), //166
|
||||
|
||||
APP_SEND_I2C_BYTE( (byte)0xC8, 2 ), //200
|
||||
APP_RECV_I2C_BYTE( (byte)0xC9, 3 ), //201
|
||||
|
||||
APP_RESET( (byte)0xFF, 1 ); //255
|
||||
|
||||
/**
|
||||
* Single-byte value to use for the command
|
||||
*/
|
||||
private byte mCommandByte;
|
||||
|
||||
/**
|
||||
* Required array length
|
||||
*/
|
||||
private int mArrayLength;
|
||||
|
||||
private FCDCommand( byte value, int responseLength )
|
||||
{
|
||||
mCommandByte = value;
|
||||
mArrayLength = responseLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array of the specified length with the command byte value
|
||||
* set in index position zero. Fill in additional command arguments prior
|
||||
* to sending to the device
|
||||
*/
|
||||
public byte[] getRequestTemplate()
|
||||
{
|
||||
byte[] retVal = new byte[ 64 ];
|
||||
|
||||
retVal[ 0 ] = mCommandByte;
|
||||
retVal[ 1 ] = (byte)0x0;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty byte array of the correct length to receive the response
|
||||
* from the associated command
|
||||
*/
|
||||
public byte[] getResponseTemplate()
|
||||
{
|
||||
return new byte[ 64 ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte value of the command
|
||||
*/
|
||||
public byte getCommand()
|
||||
{
|
||||
return mCommandByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* Total array length required to send the command or receive the response.
|
||||
*
|
||||
* Index 0: command is echoed back
|
||||
* Index 1: 0-fail, 1-success
|
||||
*/
|
||||
public int getArrayLength()
|
||||
{
|
||||
return mArrayLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the response array to verify the pass/fail value that is placed
|
||||
* in array index position 1, in responses from the device
|
||||
*/
|
||||
public static boolean checkResponse( FCDCommand command, byte[] response )
|
||||
{
|
||||
boolean valid = false;
|
||||
|
||||
if( command != null && response != null )
|
||||
{
|
||||
valid = response[ 0 ] == command.getCommand() &&
|
||||
response[ 1 ] == 1;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
53
src/source/tuner/fcd/FCDModel.java
Normal file
53
src/source/tuner/fcd/FCDModel.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public enum FCDModel
|
||||
{
|
||||
FUNCUBE_DONGLE_PRO( "FunCube Dongle Pro" ),
|
||||
FUNCUBE_DONGLE_PRO_PLUS( "FunCube Dongle Pro Plus"),
|
||||
FUNCUBE_UNKNOWN( "Unknown" );
|
||||
|
||||
private String mLabel;
|
||||
|
||||
private FCDModel( String label )
|
||||
{
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public static FCDModel getFCD( String board )
|
||||
{
|
||||
FCDModel retVal = FUNCUBE_UNKNOWN;
|
||||
|
||||
if( board.equalsIgnoreCase( "Brd 1.1" ) )
|
||||
{
|
||||
retVal = FUNCUBE_DONGLE_PRO;
|
||||
}
|
||||
else if( board.equalsIgnoreCase( "Brd 2.0" ) )
|
||||
{
|
||||
retVal = FUNCUBE_DONGLE_PRO_PLUS;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
125
src/source/tuner/fcd/FCDTuner.java
Normal file
125
src/source/tuner/fcd/FCDTuner.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*******************************************************************************
|
||||
* 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 java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import sample.Listener;
|
||||
import source.SourceException;
|
||||
import source.mixer.ShortAdapter;
|
||||
import source.tuner.FrequencyChangeListener;
|
||||
import source.tuner.MixerTuner;
|
||||
import source.tuner.MixerTunerDataLine;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannelSource;
|
||||
import source.tuner.TunerClass;
|
||||
import source.tuner.TunerConfiguration;
|
||||
import source.tuner.TunerType;
|
||||
import controller.ResourceManager;
|
||||
import controller.ThreadPoolManager;
|
||||
|
||||
public class FCDTuner extends MixerTuner
|
||||
{
|
||||
private FCDTunerController mController;
|
||||
|
||||
public FCDTuner( MixerTunerDataLine mixerTDL,
|
||||
FCDTunerController controller )
|
||||
{
|
||||
super( controller.getConfiguration().toString(),
|
||||
mixerTDL,
|
||||
new ShortAdapter() );
|
||||
|
||||
mController = controller;
|
||||
mController.addListener( (FrequencyChangeListener)this );
|
||||
}
|
||||
|
||||
public FCDTunerController getController()
|
||||
{
|
||||
return mController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return mController.getTunerClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return mController.getTunerType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
return mController.getAddress();
|
||||
}
|
||||
|
||||
@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 int getFrequency() throws SourceException
|
||||
{
|
||||
return mController.getFrequency();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel( ThreadPoolManager threadPoolManager,
|
||||
TunerChannel tunerChannel ) throws RejectedExecutionException,
|
||||
SourceException
|
||||
{
|
||||
return mController.getChannel( threadPoolManager, this, tunerChannel );
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the tuned channel so that the tuner controller can tune to
|
||||
* other frequencies as needed.
|
||||
*/
|
||||
@Override
|
||||
public void releaseChannel( TunerChannelSource source )
|
||||
{
|
||||
if( source != null )
|
||||
{
|
||||
/* Unregister for receiving samples */
|
||||
removeListener( (Listener<Float[]>)source );
|
||||
|
||||
/* Tell the controller to release the channel and cleanup */
|
||||
/* This will release the channel as a frequency change listener */
|
||||
mController.releaseChannel( source );
|
||||
}
|
||||
}
|
||||
}
|
||||
497
src/source/tuner/fcd/FCDTunerController.java
Normal file
497
src/source/tuner/fcd/FCDTunerController.java
Normal file
@@ -0,0 +1,497 @@
|
||||
/*******************************************************************************
|
||||
* 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.JPanel;
|
||||
import javax.usb.UsbClaimException;
|
||||
import javax.usb.UsbConfiguration;
|
||||
import javax.usb.UsbDevice;
|
||||
import javax.usb.UsbEndpoint;
|
||||
import javax.usb.UsbException;
|
||||
import javax.usb.UsbInterface;
|
||||
import javax.usb.UsbInterfacePolicy;
|
||||
import javax.usb.UsbPipe;
|
||||
|
||||
import log.Log;
|
||||
import source.SourceException;
|
||||
import source.tuner.TunerClass;
|
||||
import source.tuner.TunerConfiguration;
|
||||
import source.tuner.TunerController;
|
||||
import source.tuner.TunerType;
|
||||
import source.tuner.fcd.proV1.FCD1TunerController.Block;
|
||||
import source.tuner.usb.USBTunerDevice;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public abstract class FCDTunerController extends TunerController
|
||||
{
|
||||
public final static int sINT_NULL_VALUE = -1;
|
||||
public final static long sLONG_NULL_VALUE = -1l;
|
||||
public final static double sDOUBLE_NULL_VALUE = -1.0D;
|
||||
|
||||
public final static byte sFCD_INTERFACE = (byte)0x2;
|
||||
public final static byte sFCD_ENDPOINT_IN = (byte)0x82;
|
||||
public final static byte sFCD_ENDPOINT_OUT = (byte)0x2;
|
||||
|
||||
public final static boolean sFCD_FORCE_CLAIM_HID_INTERFACE = true;
|
||||
|
||||
private UsbDevice mFuncube;
|
||||
private UsbConfiguration mUsbConfiguration;
|
||||
private UsbInterface mFuncubeHID;
|
||||
private UsbPipe mPipeIn;
|
||||
private UsbPipe mPipeOut;
|
||||
private FCDConfiguration mConfiguration = new FCDConfiguration();
|
||||
private int mSampleRate;
|
||||
|
||||
public FCDTunerController( USBTunerDevice device,
|
||||
int minTunableFrequency,
|
||||
int maxTunableFrequency ) throws SourceException
|
||||
{
|
||||
super( minTunableFrequency, maxTunableFrequency );
|
||||
|
||||
mFuncube = device.getDevice();
|
||||
mUsbConfiguration = mFuncube.getActiveUsbConfiguration();
|
||||
mFuncubeHID = mUsbConfiguration.getUsbInterface( sFCD_INTERFACE );
|
||||
}
|
||||
|
||||
public abstract int getCurrentSampleRate() throws SourceException;
|
||||
|
||||
/**
|
||||
* Returns the tuner class. Since this is a generic container for both
|
||||
* types of funcube, we let the controller self identify the class and type
|
||||
*
|
||||
* @return - tuner class
|
||||
*/
|
||||
public abstract TunerClass getTunerClass();
|
||||
|
||||
/**
|
||||
* Returns the tuner type. Since this is a generic container for both
|
||||
* types of funcube, we let the controller self identify the class and type
|
||||
*
|
||||
* @return - tuner type
|
||||
*/
|
||||
public abstract TunerType getTunerType();
|
||||
|
||||
/**
|
||||
* FCD editor panel
|
||||
*/
|
||||
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 applied tuner configuration or null if one hasn't yet been
|
||||
* applied
|
||||
*/
|
||||
public abstract TunerConfiguration getTunerConfiguration();
|
||||
|
||||
/**
|
||||
* USB address
|
||||
*/
|
||||
public String getAddress()
|
||||
{
|
||||
return mFuncube.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fcd interface mode
|
||||
*/
|
||||
public void setFCDMode( Mode mode ) throws UsbException, UsbClaimException
|
||||
{
|
||||
byte[] response = null;
|
||||
|
||||
switch( mode )
|
||||
{
|
||||
case APPLICATION:
|
||||
response = send( FCDCommand.BL_QUERY.getRequestTemplate(),
|
||||
FCDCommand.BL_QUERY.getResponseTemplate() );
|
||||
break;
|
||||
case BOOTLOADER:
|
||||
response = send( FCDCommand.APP_RESET.getRequestTemplate(),
|
||||
FCDCommand.APP_RESET.getResponseTemplate() );
|
||||
break;
|
||||
case ERROR:
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
if( response != null )
|
||||
{
|
||||
mConfiguration.set( response );
|
||||
}
|
||||
else
|
||||
{
|
||||
mConfiguration.setModeUnknown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actual (uncorrected) device frequency
|
||||
*/
|
||||
public void setTunedFrequency( int frequency ) throws SourceException
|
||||
{
|
||||
try
|
||||
{
|
||||
send( FCDCommand.APP_SET_FREQUENCY_HZ, frequency );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
throw new SourceException( "Couldn't set FCD Local " +
|
||||
"Oscillator Frequency [" + frequency + "]", e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actual (uncorrected) device frequency
|
||||
*/
|
||||
public int getTunedFrequency() throws SourceException
|
||||
{
|
||||
try
|
||||
{
|
||||
return (int)send( FCDCommand.APP_GET_FREQUENCY_HZ );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
throw new SourceException( "FCDTunerController - "
|
||||
+ "couldn't get LO frequency", e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FCD device configuration
|
||||
*/
|
||||
public FCDConfiguration getConfiguration()
|
||||
{
|
||||
return mConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Claims the FCD USB HID interface. If another application currently has
|
||||
* the interface claimed, the sFCD_FORCE_CLAIM_HID_INTERFACE setting
|
||||
* will dictate if the interface is forcibly claimed from the other
|
||||
* application
|
||||
*/
|
||||
private boolean claim() throws UsbException, UsbClaimException
|
||||
{
|
||||
boolean claimed = false;
|
||||
|
||||
if( !mFuncubeHID.isClaimed() )
|
||||
{
|
||||
mFuncubeHID.claim( new UsbInterfacePolicy()
|
||||
{
|
||||
@Override
|
||||
public boolean forceClaim( UsbInterface arg0 )
|
||||
{
|
||||
return sFCD_FORCE_CLAIM_HID_INTERFACE;
|
||||
}
|
||||
} );
|
||||
|
||||
claimed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.info( "Attempted to claim the Funcube HID interface, but it's in use by another program" );
|
||||
}
|
||||
|
||||
return claimed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the claimed USB (FCD) interface
|
||||
*/
|
||||
private void release()
|
||||
{
|
||||
mPipeIn = null;
|
||||
mPipeOut = null;
|
||||
|
||||
try
|
||||
{
|
||||
mFuncubeHID.release();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
Log.error( "Exception thrown while releasing the funcube HID interface" + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper for commands that don't take arguments
|
||||
*/
|
||||
public long send( FCDCommand command ) throws UsbException, UsbClaimException
|
||||
{
|
||||
return send( command, sLONG_NULL_VALUE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the command, optionally placing the argument value parsed into
|
||||
* little endian bytes in the request array. Returns any integer value that
|
||||
* part of the response, or sINT_NULL_VALUE (-1) if it fails.
|
||||
*
|
||||
* Note: we use a long return value to avoid any issues with the MSB of a
|
||||
* 32-bit response value being misinterpreted as the integer sign bit.
|
||||
*
|
||||
* @param command
|
||||
* @param commandArgument - command argument. Use -1 for no-argument commands
|
||||
* @return - response long value, or -1 if fails
|
||||
* @throws UsbException
|
||||
* @throws UsbClaimException
|
||||
*/
|
||||
public long send( FCDCommand command, long commandArgument ) throws UsbException,
|
||||
UsbClaimException
|
||||
{
|
||||
long retVal = sLONG_NULL_VALUE;
|
||||
|
||||
byte[] request = command.getRequestTemplate();
|
||||
|
||||
if( commandArgument != sLONG_NULL_VALUE )
|
||||
{
|
||||
//Parse the value argument into the request byte indices, according to command length
|
||||
for( int x = 1; x < command.getArrayLength(); x++ )
|
||||
{
|
||||
//Little endian
|
||||
request[ x ] = (byte)( 0xFF &
|
||||
Long.rotateRight( commandArgument, ( x - 1 ) * 8 ) );
|
||||
}
|
||||
}
|
||||
|
||||
byte[] response = send( request, command.getResponseTemplate() );
|
||||
|
||||
if( response != null )
|
||||
{
|
||||
retVal = parseResponse( command, response );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request byte array to the device and returns the response array
|
||||
* filled with the response bytes from the device, or returns null if
|
||||
* something failed along the way
|
||||
*/
|
||||
private byte[] send( byte[] request, byte[] response )
|
||||
throws UsbException, UsbClaimException
|
||||
{
|
||||
byte[] retVal = null;
|
||||
|
||||
if( mPipeIn != null && mPipeOut != null )
|
||||
{
|
||||
mPipeOut.syncSubmit( request );
|
||||
|
||||
mPipeIn.syncSubmit( response );
|
||||
|
||||
retVal = response;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a multi-byte integer response value from a byte array that is
|
||||
* 2 or more bytes long
|
||||
*/
|
||||
private long parseResponse( FCDCommand command, byte[] response )
|
||||
{
|
||||
long retVal = 0;
|
||||
|
||||
//Parse the value argument into the request byte indices, according to command length
|
||||
for( int x = 2; x < command.getArrayLength(); x++ )
|
||||
{
|
||||
retVal += Long.rotateLeft( ( response[ x ] & 0xFF ), ( x - 2 ) * 8 );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected void open() throws UsbException, UsbClaimException
|
||||
{
|
||||
if( claim() )
|
||||
{
|
||||
//Get the USB endpoints
|
||||
UsbEndpoint endpointIn =
|
||||
mFuncubeHID.getUsbEndpoint( sFCD_ENDPOINT_IN );
|
||||
|
||||
UsbEndpoint endpointOut =
|
||||
mFuncubeHID.getUsbEndpoint( sFCD_ENDPOINT_OUT );
|
||||
|
||||
//Setup the pipes
|
||||
if( endpointIn != null && endpointOut != null )
|
||||
{
|
||||
mPipeOut = endpointOut.getUsbPipe();
|
||||
mPipeOut.open();
|
||||
|
||||
mPipeIn = endpointIn.getUsbPipe();
|
||||
mPipeIn.open();
|
||||
|
||||
setFCDMode( Mode.APPLICATION );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( "FCD Pro Tuner Controller - couldn't gain access " +
|
||||
"to the USB in/out endpoints or pipes." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( "FCD Pro Tuner Controller - couldn't claim the USB " +
|
||||
"interface. Check to see if another program is using it." );
|
||||
}
|
||||
}
|
||||
|
||||
protected void close()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
public class FCDConfiguration
|
||||
{
|
||||
private String mConfig;
|
||||
private Mode mMode;
|
||||
|
||||
public FCDConfiguration()
|
||||
{
|
||||
mConfig = null;
|
||||
mMode = Mode.UNKNOWN;
|
||||
}
|
||||
|
||||
private void setModeUnknown()
|
||||
{
|
||||
mConfig = null;
|
||||
mMode = Mode.UNKNOWN;
|
||||
}
|
||||
|
||||
public void set( byte[] data )
|
||||
{
|
||||
if( FCDCommand.checkResponse( FCDCommand.BL_QUERY, data ) ||
|
||||
FCDCommand.checkResponse( FCDCommand.APP_RESET, data ) )
|
||||
{
|
||||
mConfig = new String( data );
|
||||
mMode = Mode.getMode( mConfig );
|
||||
}
|
||||
else
|
||||
{
|
||||
mConfig = null;
|
||||
mMode = Mode.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
public Mode getMode()
|
||||
{
|
||||
return mMode;
|
||||
}
|
||||
|
||||
public FCDModel getModel()
|
||||
{
|
||||
FCDModel retVal = FCDModel.FUNCUBE_UNKNOWN;
|
||||
|
||||
switch( mMode )
|
||||
{
|
||||
case APPLICATION:
|
||||
retVal = FCDModel.getFCD( mConfig.substring( 15, 22 ) );
|
||||
break;
|
||||
case BOOTLOADER:
|
||||
case UNKNOWN:
|
||||
case ERROR:
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public Block getBandBlocking()
|
||||
{
|
||||
Block retVal = Block.UNKNOWN;
|
||||
|
||||
switch( mMode )
|
||||
{
|
||||
case APPLICATION:
|
||||
retVal = Block.getBlock( mConfig.substring( 23, 33 ).trim() );
|
||||
break;
|
||||
case BOOTLOADER:
|
||||
case UNKNOWN:
|
||||
case ERROR:
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public String getFirmware()
|
||||
{
|
||||
String retVal = null;
|
||||
|
||||
switch( mMode )
|
||||
{
|
||||
case APPLICATION:
|
||||
retVal = mConfig.substring( 9, 14 );
|
||||
break;
|
||||
case BOOTLOADER:
|
||||
case UNKNOWN:
|
||||
case ERROR:
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getModel().getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
public enum Mode
|
||||
{
|
||||
APPLICATION,
|
||||
BOOTLOADER,
|
||||
ERROR,
|
||||
UNKNOWN;
|
||||
|
||||
public static Mode getMode( String config )
|
||||
{
|
||||
Mode retVal = UNKNOWN;
|
||||
|
||||
if( config == null )
|
||||
{
|
||||
retVal = ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( config.length() >= 8 )
|
||||
{
|
||||
String mode = config.substring( 2, 8 ).trim();
|
||||
|
||||
if( mode.equalsIgnoreCase( "FCDAPP" ) )
|
||||
{
|
||||
retVal = APPLICATION;
|
||||
}
|
||||
else if( mode.equalsIgnoreCase( "FCDBL" ) )
|
||||
{
|
||||
retVal = BOOTLOADER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/source/tuner/fcd/FCDTunerDetailsPanel.java
Normal file
48
src/source/tuner/fcd/FCDTunerDetailsPanel.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*******************************************************************************
|
||||
* 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.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import source.tuner.rtl.RTL2832TunerController.Descriptor;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class FCDTunerDetailsPanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JLabel mAddress;
|
||||
private JLabel mCellBlock;
|
||||
private JLabel mFirmware;
|
||||
|
||||
public FCDTunerDetailsPanel( FCDTunerController controller )
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][grow]" ) );
|
||||
|
||||
add( new JLabel( "USB Address:" ) );
|
||||
add( new JLabel( controller.getAddress() ) );
|
||||
|
||||
add( new JLabel( "Cellular Band:" ) );
|
||||
add( new JLabel( controller.getConfiguration().getBandBlocking()
|
||||
.getLabel() ) );
|
||||
|
||||
add( new JLabel( "Firmware:" ) );
|
||||
add( new JLabel( controller.getConfiguration().getFirmware() ) );
|
||||
}
|
||||
}
|
||||
145
src/source/tuner/fcd/proV1/FCD1TunerConfiguration.java
Normal file
145
src/source/tuner/fcd/proV1/FCD1TunerConfiguration.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
* 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 javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
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;
|
||||
|
||||
public class FCD1TunerConfiguration extends TunerConfiguration
|
||||
{
|
||||
private double mFrequencyCorrection = 22.0d;
|
||||
private double mInphaseDCCorrection = 0.0d;
|
||||
private double mQuadratureDCCorrection = 0.0d;
|
||||
private double mPhaseCorrection = 0.0d;
|
||||
private double mGainCorrection = 0.0d;
|
||||
|
||||
private LNAGain mLNAGain = LNAGain.LNA_GAIN_PLUS_20_0;
|
||||
private LNAEnhance mLNAEnhance = LNAEnhance.LNA_ENHANCE_OFF;
|
||||
private MixerGain mMixerGain = MixerGain.MIXER_GAIN_PLUS_12_0;
|
||||
|
||||
/**
|
||||
* Default constructor for JAXB
|
||||
*/
|
||||
public FCD1TunerConfiguration()
|
||||
{
|
||||
this( "Default" );
|
||||
}
|
||||
|
||||
public FCD1TunerConfiguration( String name )
|
||||
{
|
||||
super( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.FUNCUBE_DONGLE_PRO;
|
||||
}
|
||||
|
||||
public LNAGain getLNAGain()
|
||||
{
|
||||
return mLNAGain;
|
||||
}
|
||||
|
||||
public void setLNAGain( LNAGain gain )
|
||||
{
|
||||
mLNAGain = gain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "lna_gain" )
|
||||
public LNAEnhance getLNAEnhance()
|
||||
{
|
||||
return mLNAEnhance;
|
||||
}
|
||||
|
||||
public void setLNAEnhance( LNAEnhance enhance )
|
||||
{
|
||||
mLNAEnhance = enhance;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "mixer_gain" )
|
||||
public MixerGain getMixerGain()
|
||||
{
|
||||
return mMixerGain;
|
||||
}
|
||||
|
||||
public void setMixerGain( MixerGain gain )
|
||||
{
|
||||
mMixerGain = gain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "frequency_correction" )
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double value )
|
||||
{
|
||||
mFrequencyCorrection = value;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "inphase_dc_correction" )
|
||||
public double getInphaseDCCorrection()
|
||||
{
|
||||
return mInphaseDCCorrection;
|
||||
}
|
||||
|
||||
public void setInphaseDCCorrection( double value )
|
||||
{
|
||||
mInphaseDCCorrection = value;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "quadrature_dc_correction" )
|
||||
public double getQuadratureDCCorrection()
|
||||
{
|
||||
return mQuadratureDCCorrection;
|
||||
}
|
||||
|
||||
public void setQuadratureDCCorrection( double value )
|
||||
{
|
||||
mQuadratureDCCorrection = value;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "phase_correction" )
|
||||
public double getPhaseCorrection()
|
||||
{
|
||||
return mPhaseCorrection;
|
||||
}
|
||||
|
||||
public void setPhaseCorrection( double value )
|
||||
{
|
||||
mPhaseCorrection = value;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "gain_correction" )
|
||||
public double getGainCorrection()
|
||||
{
|
||||
return mGainCorrection;
|
||||
}
|
||||
|
||||
public void setGainCorrection( double value )
|
||||
{
|
||||
mGainCorrection = value;
|
||||
}
|
||||
}
|
||||
667
src/source/tuner/fcd/proV1/FCD1TunerConfigurationPanel.java
Normal file
667
src/source/tuner/fcd/proV1/FCD1TunerConfigurationPanel.java
Normal file
@@ -0,0 +1,667 @@
|
||||
/*******************************************************************************
|
||||
* 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.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.UsbClaimException;
|
||||
import javax.usb.UsbException;
|
||||
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
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 controller.ResourceManager;
|
||||
|
||||
public class FCD1TunerConfigurationPanel extends JPanel
|
||||
{
|
||||
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() + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - usb claim "
|
||||
+ "exception while applying LNA gain value [" +
|
||||
gain.toString() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
catch ( UsbException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
FCD1TunerConfigurationPanel.this,
|
||||
"FCD Pro Tuner Controller - FCD Controller "
|
||||
+ "cannot apply LNA gain [" + gain.toString() + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - "
|
||||
+ "exception while applying LNA gain value [" +
|
||||
gain.toString() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
|
||||
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() + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - usb claim "
|
||||
+ "exception while applying LNA enhance value [" +
|
||||
enhance.toString() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
catch ( UsbException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
FCD1TunerConfigurationPanel.this,
|
||||
"FCD Pro Tuner Controller - FCD Controller "
|
||||
+ "cannot apply LNA enhance [" + enhance.toString() + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - "
|
||||
+ "exception while applying LNA enhance value [" +
|
||||
enhance.toString() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
|
||||
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() + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - usb claim "
|
||||
+ "exception while applying Mixer gain value [" +
|
||||
gain.toString() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
catch ( UsbException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
FCD1TunerConfigurationPanel.this,
|
||||
"FCD Pro Tuner Controller - FCD Controller "
|
||||
+ "cannot apply Mixer gain [" + gain.toString() + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - "
|
||||
+ "exception while applying Mixer gain value [" +
|
||||
gain.toString() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
|
||||
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() );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
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.getAddress(), config );
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
FCD1TunerConfigurationPanel.this,
|
||||
"FCD Pro Tuner Controller - couldn't "
|
||||
+ "apply the tuner configuration settings - " +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - couldn't apply "
|
||||
+ "config [" + config.getName() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
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 + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - usb claim "
|
||||
+ "exception while applying "
|
||||
+ mCorrectionComponent.toString()
|
||||
+ " correction value [" + value + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
catch ( UsbException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
FCD1TunerConfigurationPanel.this,
|
||||
"FCD Pro Tuner Controller - USB error from FCD "
|
||||
+ "Controller while applying "
|
||||
+ mCorrectionComponent.toString() +
|
||||
" correction value [" + value + "]" );
|
||||
|
||||
Log.error( "FuncubeDonglePro Controller - usb "
|
||||
+ "exception while applying "
|
||||
+ mCorrectionComponent.toString()
|
||||
+ " correction value [" + value + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
698
src/source/tuner/fcd/proV1/FCD1TunerController.java
Normal file
698
src/source/tuner/fcd/proV1/FCD1TunerController.java
Normal file
@@ -0,0 +1,698 @@
|
||||
/*******************************************************************************
|
||||
* 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 javax.swing.JPanel;
|
||||
import javax.usb.UsbClaimException;
|
||||
import javax.usb.UsbException;
|
||||
|
||||
import log.Log;
|
||||
import source.SourceException;
|
||||
import source.tuner.TunerClass;
|
||||
import source.tuner.TunerConfiguration;
|
||||
import source.tuner.TunerType;
|
||||
import source.tuner.fcd.FCDCommand;
|
||||
import source.tuner.fcd.FCDTuner;
|
||||
import source.tuner.fcd.FCDTunerController;
|
||||
import source.tuner.usb.USBTunerDevice;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class FCD1TunerController extends FCDTunerController
|
||||
{
|
||||
public static final int sMINIMUM_TUNABLE_FREQUENCY = 64000000;
|
||||
public static final int sMAXIMUM_TUNABLE_FREQUENCY = 1700000000;
|
||||
public static final int sSAMPLE_RATE = 96000;
|
||||
|
||||
private double mDCCorrectionInPhase = 0.0;
|
||||
private double mDCCorrectionQuadrature = 0.0;
|
||||
private double mPhaseCorrection = 0.0;
|
||||
private double mGainCorrection = 0.0;
|
||||
private LNAGain mLNAGain;
|
||||
private LNAEnhance mLNAEnhance;
|
||||
private MixerGain mMixerGain;
|
||||
private FCD1TunerConfiguration mTunerConfiguration;
|
||||
private FCD1TunerEditorPanel mEditor;
|
||||
|
||||
public FCD1TunerController( USBTunerDevice device )
|
||||
throws SourceException
|
||||
{
|
||||
super( device,
|
||||
sMINIMUM_TUNABLE_FREQUENCY,
|
||||
sMAXIMUM_TUNABLE_FREQUENCY );
|
||||
|
||||
mFrequencyController.setBandwidth( sSAMPLE_RATE );
|
||||
|
||||
try
|
||||
{
|
||||
open();
|
||||
|
||||
setFCDMode( Mode.APPLICATION );
|
||||
getPhaseAndGainCorrection();
|
||||
getDCIQCorrection();
|
||||
getLNAGainSetting();
|
||||
getLNAEnhanceSetting();
|
||||
getMixerGainSetting();
|
||||
|
||||
send( FCDCommand.APP_SET_MIXER_GAIN, 1 );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
|
||||
throw new SourceException( "FCDTunerController error " +
|
||||
"during construction", e );
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentSampleRate()
|
||||
{
|
||||
return sSAMPLE_RATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return TunerClass.FUNCUBE_DONGLE_PRO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.FUNCUBE_DONGLE_PRO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tuner configuration
|
||||
*
|
||||
* @return current config or null if one hasn't been applied yet
|
||||
*/
|
||||
public FCD1TunerConfiguration getTunerConfiguration()
|
||||
{
|
||||
return mTunerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply( TunerConfiguration tunerConfig )
|
||||
throws SourceException
|
||||
{
|
||||
FCD1TunerConfiguration config = (FCD1TunerConfiguration)tunerConfig;
|
||||
|
||||
try
|
||||
{
|
||||
setFrequencyCorrection( config.getFrequencyCorrection() );
|
||||
setLNAGain( config.getLNAGain() );
|
||||
setLNAEnhance( config.getLNAEnhance() );
|
||||
setMixerGain( config.getMixerGain() );
|
||||
setDCCorrectionInPhase( config.getInphaseDCCorrection() );
|
||||
setDCCorrectionQuadrature( config.getQuadratureDCCorrection() );
|
||||
setGainCorrection( config.getGainCorrection() );
|
||||
setPhaseCorrection( config.getPhaseCorrection() );
|
||||
|
||||
//If we get to here without exception, store this config
|
||||
mTunerConfiguration = config;
|
||||
}
|
||||
catch( Exception e)
|
||||
{
|
||||
//Re-cast any usb exceptions as source exceptions
|
||||
throw new SourceException( "FCD 1 Controller encountered an "
|
||||
+ "exception while applying tuner config - " +
|
||||
e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
*/
|
||||
private void getLNAGainSetting() throws UsbClaimException, UsbException
|
||||
{
|
||||
int gain = (int)send( FCDCommand.APP_GET_LNA_GAIN );
|
||||
|
||||
Log.info( "FCD1: lna gain setting is:" + gain );
|
||||
|
||||
mLNAGain = LNAGain.valueOf( gain );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return - current lna gain setting
|
||||
*/
|
||||
public LNAGain getLNAGain()
|
||||
{
|
||||
return mLNAGain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets lna gain for the controller
|
||||
* @param gain
|
||||
* @throws UsbException
|
||||
* @throws UsbClaimException
|
||||
*/
|
||||
public void setLNAGain( LNAGain gain )
|
||||
throws UsbException, UsbClaimException
|
||||
{
|
||||
send( FCDCommand.APP_SET_LNA_GAIN, gain.getSetting() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return - current phase correction setting
|
||||
*/
|
||||
public double getPhaseCorrection()
|
||||
{
|
||||
return mPhaseCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the phase correction
|
||||
* @param value - new phase correction
|
||||
* @throws IllegalArgumentException for value outside limits (0.0 <> 1.0)
|
||||
* @throws UsbClaimException - if cannot claim the FCD HID controller
|
||||
* @throws UsbException - if there was a usb error
|
||||
*/
|
||||
public void setPhaseCorrection( double value )
|
||||
throws UsbClaimException, UsbException
|
||||
{
|
||||
if( value < -1.0 || value > 1.0 )
|
||||
{
|
||||
throw new IllegalArgumentException( "Phase correction value [" +
|
||||
value + "] outside limits ( -1.0 <> 1.0 )" );
|
||||
}
|
||||
|
||||
mPhaseCorrection = value;
|
||||
setPhaseAndGainCorrection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current gain correction setting
|
||||
*/
|
||||
public double getGainCorrection()
|
||||
{
|
||||
return mGainCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value - gain correction value
|
||||
* @throws IllegalArgumentException for value outside limits (0.0 <> 1.0)
|
||||
* @throws UsbClaimException - if cannot claim the FCD HID controller
|
||||
* @throws UsbException - if there was a usb error
|
||||
*/
|
||||
public void setGainCorrection( double value )
|
||||
throws UsbClaimException, UsbException
|
||||
{
|
||||
if( value < -1.0 || value > 1.0 )
|
||||
{
|
||||
throw new IllegalArgumentException( "Gain correction value [" +
|
||||
value + "] outside limits ( -1.0 <> 1.0 )" );
|
||||
}
|
||||
|
||||
mGainCorrection = value;
|
||||
setPhaseAndGainCorrection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the phase and gain correction values to FCD.
|
||||
*
|
||||
* The interface expects an argument with the SIGNED phase value in the first
|
||||
* 16 bits and the UNSIGNED gain value in the second 16 bits, both in
|
||||
* big-endian format. Since we're sending the argument in java little endian
|
||||
* format, we place the phase in the high-order bits and the gain in the
|
||||
* low-order bits, so that the send(command) function will reorder the bytes
|
||||
* into big endian format, and place the arguments correctly.
|
||||
*
|
||||
* Gain correction values range -1.0 to 0.0 to 1.0 and applied to the dongle
|
||||
* as values 0 to 65534
|
||||
*
|
||||
* Phase correction values range -1.0 to 0.0 to 1.0 and applied to the
|
||||
* dongle as signed values -32768 to 32767
|
||||
*/
|
||||
private void setPhaseAndGainCorrection() throws UsbClaimException,
|
||||
UsbException
|
||||
{
|
||||
//UNSIGNED short gain value - masked into a long to avoid sign-extension
|
||||
long gain = (long)( ( 1.0 + mGainCorrection ) * Short.MAX_VALUE );
|
||||
|
||||
//Left shift gain to place value in upper 16 bits
|
||||
long longGain = Long.rotateLeft( ( 0xFFFF & gain ), 16 );
|
||||
|
||||
//SIGNED short phase value
|
||||
short phase = (short)( mPhaseCorrection * Short.MAX_VALUE );
|
||||
|
||||
//Merge the results
|
||||
long correction = longGain | phase;
|
||||
|
||||
send( FCDCommand.APP_SET_IQ_CORRECTION, correction );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the stored phase and gain correction values from the FCD.
|
||||
*
|
||||
* Note: testing shows that when the dongle is unplugged, any stored phase
|
||||
* and gain correction values are reset. Reading the dongle after a fresh
|
||||
* plugin shows the values reset.
|
||||
*
|
||||
* @throws UsbClaimException
|
||||
* @throws UsbException
|
||||
*/
|
||||
private void getPhaseAndGainCorrection() throws UsbClaimException,
|
||||
UsbException
|
||||
{
|
||||
long correction = send( FCDCommand.APP_GET_IQ_CORRECTION );
|
||||
|
||||
/**
|
||||
* Gain: mask the upper 16 phase bits and right shift to get the
|
||||
* unsigned short value and then divide by 32768 to get the double
|
||||
* value. We place the unsigned short value in an int to avoid sign
|
||||
* issues.
|
||||
*/
|
||||
int gain = (int)( Long.rotateRight( correction & 0xFFFF0000, 16 ) );
|
||||
|
||||
mGainCorrection = ( (double)gain / (double)Short.MAX_VALUE ) - 1.0;
|
||||
|
||||
/**
|
||||
* Phase: mask the lower 16 bits and divide by 32768 to get the double
|
||||
* value
|
||||
*/
|
||||
short phase = (short)( correction & 0x0000FFFF );
|
||||
|
||||
mPhaseCorrection = ( (double)phase / (double)Short.MAX_VALUE );
|
||||
|
||||
Log.info( "FCD1: correction:" + correction + " gain:" + gain + " phase:" + phase );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current DC correction for the I (inphase) component
|
||||
*/
|
||||
public double getDCCorrectionInPhase()
|
||||
{
|
||||
return mDCCorrectionInPhase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets DC correction for the I (inphase) component and sends the new value
|
||||
* to the FCD controller
|
||||
* @param value - new DC correction value for the inphase component
|
||||
* @throws IllegalArgumentException for values outside limits (-1.0 <> 1.0)
|
||||
* @throws UsbClaimException - if cannot claim the FCD HID controller
|
||||
* @throws UsbException - if there was a usb error
|
||||
*/
|
||||
public void setDCCorrectionInPhase( double value )
|
||||
throws UsbClaimException, UsbException
|
||||
{
|
||||
if( value < -1.0 || value > 1.0 )
|
||||
{
|
||||
throw new IllegalArgumentException( "DC inphase correction value "
|
||||
+ "[" + value + "] outside limits ( 0.0 <> 1.0 )" );
|
||||
}
|
||||
|
||||
mDCCorrectionInPhase = value;
|
||||
setDCIQCorrection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current DC correction for the Q (quadrature) component
|
||||
*/
|
||||
public double getDCCorrectionQuadrature()
|
||||
{
|
||||
return mDCCorrectionQuadrature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DC correction for the Q (quadrature) component and send the
|
||||
* new value to the FCD controller
|
||||
* @param value - new DC correction value for the quadrature component
|
||||
* @throws IllegalArgumentException for values outside limits (-1.0 <> 1.0)
|
||||
* @throws UsbClaimException - if cannot claim the FCD HID controller
|
||||
* @throws UsbException - if there was a usb error
|
||||
*/
|
||||
public void setDCCorrectionQuadrature( double value )
|
||||
throws UsbClaimException, UsbException
|
||||
{
|
||||
if( value < -1.0 || value > 1.0 )
|
||||
{
|
||||
throw new IllegalArgumentException( "DC quadrature correction "
|
||||
+ "value [" + value + "] outside limits ( 0.0 <> 1.0 )" );
|
||||
}
|
||||
|
||||
mDCCorrectionQuadrature = value;
|
||||
setDCIQCorrection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the I/Q DC offset correction values to FCD.
|
||||
*
|
||||
* The interface expects an argument with the signed inphase value in the
|
||||
* first 16 bits and the signed quadrature value in the second 16 bits,
|
||||
* both in big-endian format.
|
||||
*
|
||||
* Since we're sending the argument in java little endian format, we place
|
||||
* the quadrature in the high-order bits and the inphase in the low-order
|
||||
* bits, so that the send(command) function will reorder the bytes into big
|
||||
* endian format, and place the arguments correctly.
|
||||
*
|
||||
* Both Inphase and Quadrature correction values range -1.0 to 0.0 to 1.0
|
||||
* and are applied to the dongle as signed short values -32768 to 0 to 32767
|
||||
*/
|
||||
private void setDCIQCorrection() throws UsbClaimException, UsbException
|
||||
{
|
||||
//I & Q DC offset correction values are signed short values
|
||||
short inphase = (short)( mDCCorrectionInPhase * Short.MAX_VALUE );
|
||||
short quadrature = (short)( mDCCorrectionQuadrature * Short.MAX_VALUE );
|
||||
|
||||
//Mask the shorts into longs to preserve the sign bit and prepare
|
||||
//for merging to a single 32-bit value
|
||||
long maskedInphase = inphase & 0x0000FFFF;
|
||||
long maskedQuadrature = quadrature & 0x0000FFFF;
|
||||
|
||||
//Left shift quadrature to place value in upper 16 bits
|
||||
long shiftedQuadrature = Long.rotateLeft( maskedQuadrature, 16 );
|
||||
|
||||
//Merge the results
|
||||
long correction = shiftedQuadrature | maskedInphase;
|
||||
|
||||
// Log.info( "FCD1: setting iq correction," +
|
||||
// " inphase:" + inphase +
|
||||
// " masked inphase:" + maskedInphase +
|
||||
// " quad:" + quadrature +
|
||||
// " masked quad:" + maskedQuadrature +
|
||||
// " shifted quadrature:" + shiftedQuadrature +
|
||||
// " correction:" + correction );
|
||||
|
||||
send( FCDCommand.APP_SET_DC_CORRECTION, correction );
|
||||
}
|
||||
|
||||
private void getDCIQCorrection() throws UsbClaimException,
|
||||
UsbException
|
||||
{
|
||||
long correction = send( FCDCommand.APP_GET_DC_CORRECTION );
|
||||
|
||||
/**
|
||||
* Quadrature: mask the upper 16 bits and divide by 32768 to get the
|
||||
* stored quadrature value. Cast the 16-bit value to a short to get
|
||||
* the signed short value
|
||||
*/
|
||||
long shiftedQuadrature = correction & 0xFFFF0000;
|
||||
long quadrature = Long.rotateRight( shiftedQuadrature, 16 );
|
||||
|
||||
mDCCorrectionQuadrature = ( (short)quadrature / (double)Short.MAX_VALUE );
|
||||
|
||||
/**
|
||||
* InPhase: mask the lower 16 bits to get the short
|
||||
* value and then divide by 32768 to get the stored inphase value.
|
||||
* Cast the 16-bit value to a short to get the signed short value
|
||||
*/
|
||||
long inphase = correction & 0x0000FFFF;
|
||||
mDCCorrectionInPhase = ( (short)inphase / (double)Short.MAX_VALUE );
|
||||
|
||||
// Log.info( "FCD1:" +
|
||||
// " correction:" + correction +
|
||||
// " Q:" + quadrature +
|
||||
// " I:" + inphase +
|
||||
// " QCorr:" + mDCCorrectionQuadrature +
|
||||
// " ICorr:" + mDCCorrectionInPhase );
|
||||
}
|
||||
|
||||
private void getLNAEnhanceSetting() throws UsbClaimException, UsbException
|
||||
{
|
||||
int enhance = (int)send( FCDCommand.APP_GET_LNA_ENHANCE );
|
||||
|
||||
Log.info( "FCD1: lna enhance setting is: " + enhance );
|
||||
|
||||
mLNAEnhance = LNAEnhance.valueOf( enhance );
|
||||
}
|
||||
|
||||
public LNAEnhance getLNAEnhance()
|
||||
{
|
||||
return mLNAEnhance;
|
||||
}
|
||||
|
||||
public void setLNAEnhance( LNAEnhance enhance )
|
||||
throws UsbClaimException, UsbException
|
||||
{
|
||||
send( FCDCommand.APP_SET_LNA_ENHANCE, enhance.getSetting() );
|
||||
}
|
||||
|
||||
private void getMixerGainSetting() throws UsbClaimException, UsbException
|
||||
{
|
||||
int gain = (int)send( FCDCommand.APP_GET_MIXER_GAIN );
|
||||
|
||||
Log.info( "FCD1: mixer gain setting is:" + gain );
|
||||
|
||||
mMixerGain = MixerGain.valueOf( gain );
|
||||
}
|
||||
|
||||
public MixerGain getMixerGain()
|
||||
{
|
||||
return mMixerGain;
|
||||
}
|
||||
|
||||
public void setMixerGain( MixerGain gain ) throws UsbClaimException, UsbException
|
||||
{
|
||||
send( FCDCommand.APP_SET_MIXER_GAIN, gain.getSetting() );
|
||||
}
|
||||
|
||||
public enum Block
|
||||
{
|
||||
CELLULAR_BAND_BLOCKED( "Blocked" ),
|
||||
NO_BAND_BLOCK( "Unblocked" ),
|
||||
UNKNOWN( "Unknown" );
|
||||
|
||||
private String mLabel;
|
||||
|
||||
private Block( String label )
|
||||
{
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public static Block getBlock( String block )
|
||||
{
|
||||
Block retVal = UNKNOWN;
|
||||
|
||||
if( block.equalsIgnoreCase( "No blk" ) )
|
||||
{
|
||||
retVal = NO_BAND_BLOCK;
|
||||
}
|
||||
else if( block.equalsIgnoreCase( "Cell blk" ) )
|
||||
{
|
||||
retVal = CELLULAR_BAND_BLOCKED;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LNA Gain values suppported by the FCD Pro 1.0
|
||||
*/
|
||||
public enum LNAGain
|
||||
{
|
||||
LNA_GAIN_MINUS_5_0( 0, "-5.0 dB" ),
|
||||
LNA_GAIN_MINUS_2_5( 1, "-2.5 dB" ),
|
||||
LNA_GAIN_PLUS_0_0( 4, "0.0 dB" ),
|
||||
LNA_GAIN_PLUS_2_5( 5, "2.5 dB" ),
|
||||
LNA_GAIN_PLUS_5_0( 6, "5.0 dB" ),
|
||||
LNA_GAIN_PLUS_7_5( 7, "7.5 dB" ),
|
||||
LNA_GAIN_PLUS_10_0( 8, "10.0 dB" ),
|
||||
LNA_GAIN_PLUS_12_5( 9, "12.5 dB" ),
|
||||
LNA_GAIN_PLUS_15_0( 10, "15.0 dB" ),
|
||||
LNA_GAIN_PLUS_17_5( 11, "17.5 dB" ),
|
||||
LNA_GAIN_PLUS_20_0( 12, "20.0 dB" ),
|
||||
LNA_GAIN_PLUS_25_0( 13, "25.0 dB" ),
|
||||
LNA_GAIN_PLUS_30_0( 14, "30.0 dB" );
|
||||
|
||||
private int mSetting;
|
||||
private String mLabel;
|
||||
|
||||
private LNAGain( int setting, String label )
|
||||
{
|
||||
mSetting = setting;
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public static LNAGain valueOf( int setting )
|
||||
{
|
||||
switch( setting )
|
||||
{
|
||||
case 0:
|
||||
return LNA_GAIN_MINUS_5_0;
|
||||
case 1:
|
||||
return LNA_GAIN_MINUS_2_5;
|
||||
case 4:
|
||||
return LNA_GAIN_PLUS_0_0;
|
||||
case 5:
|
||||
return LNA_GAIN_PLUS_2_5;
|
||||
case 6:
|
||||
return LNA_GAIN_PLUS_5_0;
|
||||
case 7:
|
||||
return LNA_GAIN_PLUS_7_5;
|
||||
case 8:
|
||||
return LNA_GAIN_PLUS_10_0;
|
||||
case 9:
|
||||
return LNA_GAIN_PLUS_12_5;
|
||||
case 10:
|
||||
return LNA_GAIN_PLUS_15_0;
|
||||
case 11:
|
||||
return LNA_GAIN_PLUS_17_5;
|
||||
case 12:
|
||||
return LNA_GAIN_PLUS_20_0;
|
||||
case 13:
|
||||
return LNA_GAIN_PLUS_25_0;
|
||||
case 14:
|
||||
return LNA_GAIN_PLUS_30_0;
|
||||
default:
|
||||
throw new IllegalArgumentException( "FCD 1.0 Tuner "
|
||||
+ "Controller - unrecognized LNA gain setting "
|
||||
+ "value [" + setting + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
public int getSetting()
|
||||
{
|
||||
return mSetting;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LNA Enhance values suppported by the FCD Pro 1.0
|
||||
*/
|
||||
public enum LNAEnhance
|
||||
{
|
||||
LNA_ENHANCE_OFF( 0, "Off" ),
|
||||
LNA_ENHANCE_0( 1, "0" ),
|
||||
LNA_ENHANCE_1( 3, "1" ),
|
||||
LNA_ENHANCE_2( 5, "2" ),
|
||||
LNA_ENHANCE_3( 7, "3" );
|
||||
|
||||
private int mSetting;
|
||||
private String mLabel;
|
||||
|
||||
private LNAEnhance( int setting, String label )
|
||||
{
|
||||
mSetting = setting;
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public static LNAEnhance valueOf( int setting )
|
||||
{
|
||||
switch( setting )
|
||||
{
|
||||
case 0:
|
||||
return LNA_ENHANCE_OFF;
|
||||
case 1:
|
||||
return LNA_ENHANCE_0;
|
||||
case 3:
|
||||
return LNA_ENHANCE_1;
|
||||
case 5:
|
||||
return LNA_ENHANCE_2;
|
||||
case 7:
|
||||
return LNA_ENHANCE_3;
|
||||
default:
|
||||
throw new IllegalArgumentException( "FCD 1.0 Tuner "
|
||||
+ "Controller - unrecognized LNA enhance setting "
|
||||
+ "value [" + setting + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
public int getSetting()
|
||||
{
|
||||
return mSetting;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixer Gain values suppported by the FCD Pro 1.0
|
||||
*/
|
||||
public enum MixerGain
|
||||
{
|
||||
MIXER_GAIN_PLUS_4_0( 0, "4.0 dB" ),
|
||||
MIXER_GAIN_PLUS_12_0( 1, "12.0 dB" );
|
||||
|
||||
private int mSetting;
|
||||
private String mLabel;
|
||||
|
||||
private MixerGain( int setting, String label )
|
||||
{
|
||||
mSetting = setting;
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public static MixerGain valueOf( int setting )
|
||||
{
|
||||
switch( setting )
|
||||
{
|
||||
case 0:
|
||||
return MIXER_GAIN_PLUS_4_0;
|
||||
case 1:
|
||||
return MIXER_GAIN_PLUS_12_0;
|
||||
default:
|
||||
throw new IllegalArgumentException( "FCD 1.0 Tuner "
|
||||
+ "Controller - unrecognized mixer gain setting "
|
||||
+ "value [" + setting + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
public int getSetting()
|
||||
{
|
||||
return mSetting;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
102
src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java
Normal file
102
src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*******************************************************************************
|
||||
* 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 gui.control.JFrequencyControl;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import source.SourceException;
|
||||
import source.tuner.FrequencyChangeListener;
|
||||
import source.tuner.fcd.FCDTuner;
|
||||
import source.tuner.fcd.FCDTunerDetailsPanel;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class FCD1TunerEditorPanel extends JPanel implements FrequencyChangeListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
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( int frequency, int bandwidth )
|
||||
{
|
||||
//Disregard the bandwidth value, which shouldn't be changing
|
||||
try
|
||||
{
|
||||
mController.setFrequency( frequency );
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
Log.error( "FCTProController - error setting frequency [" +
|
||||
frequency + "] - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
82
src/source/tuner/fcd/proplusV2/FCD2TunerConfiguration.java
Normal file
82
src/source/tuner/fcd/proplusV2/FCD2TunerConfiguration.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
* 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 javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import source.tuner.TunerConfiguration;
|
||||
import source.tuner.TunerType;
|
||||
|
||||
public class FCD2TunerConfiguration extends TunerConfiguration
|
||||
{
|
||||
private boolean mGainLNA = true;
|
||||
private boolean mGainMixer = true;
|
||||
private double mFrequencyCorrection = -2.2d;
|
||||
|
||||
/**
|
||||
* Default constructor for JAXB
|
||||
*/
|
||||
public FCD2TunerConfiguration()
|
||||
{
|
||||
this( "Default" );
|
||||
}
|
||||
|
||||
public FCD2TunerConfiguration( String name )
|
||||
{
|
||||
super( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.FUNCUBE_DONGLE_PRO_PLUS;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "lna_gain" )
|
||||
public boolean getGainLNA()
|
||||
{
|
||||
return mGainLNA;
|
||||
}
|
||||
|
||||
public void setGainLNA( boolean gain )
|
||||
{
|
||||
mGainLNA = gain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "mixer_gain" )
|
||||
public boolean getGainMixer()
|
||||
{
|
||||
return mGainMixer;
|
||||
}
|
||||
|
||||
public void setGainMixer( boolean gain )
|
||||
{
|
||||
mGainMixer = gain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "frequency_correction" )
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double value )
|
||||
{
|
||||
mFrequencyCorrection = value;
|
||||
}
|
||||
}
|
||||
377
src/source/tuner/fcd/proplusV2/FCD2TunerConfigurationPanel.java
Normal file
377
src/source/tuner/fcd/proplusV2/FCD2TunerConfigurationPanel.java
Normal file
@@ -0,0 +1,377 @@
|
||||
/*******************************************************************************
|
||||
* 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.BorderFactory;
|
||||
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 log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import source.SourceException;
|
||||
import source.tuner.TunerConfiguration;
|
||||
import source.tuner.TunerConfigurationAssignment;
|
||||
import source.tuner.TunerType;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class FCD2TunerConfigurationPanel extends JPanel
|
||||
{
|
||||
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() );
|
||||
|
||||
Log.error( "FuncubeDongleProPlus Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
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.getAddress() );
|
||||
|
||||
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.getAddress(), 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.getAddress(), config );
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
FCD2TunerConfigurationPanel.this,
|
||||
"FCD Pro Plus Tuner Controller - couldn't "
|
||||
+ "apply the tuner configuration settings - " +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
Log.error( "FuncubeDongleProPlus Controller - couldn't apply "
|
||||
+ "config [" + config.getName() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
367
src/source/tuner/fcd/proplusV2/FCD2TunerController.java
Normal file
367
src/source/tuner/fcd/proplusV2/FCD2TunerController.java
Normal file
@@ -0,0 +1,367 @@
|
||||
/*******************************************************************************
|
||||
* 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 javax.swing.JPanel;
|
||||
import javax.usb.UsbClaimException;
|
||||
import javax.usb.UsbException;
|
||||
|
||||
import log.Log;
|
||||
import source.SourceException;
|
||||
import source.tuner.TunerClass;
|
||||
import source.tuner.TunerConfiguration;
|
||||
import source.tuner.TunerType;
|
||||
import source.tuner.fcd.FCDCommand;
|
||||
import source.tuner.fcd.FCDTuner;
|
||||
import source.tuner.fcd.FCDTunerController;
|
||||
import source.tuner.usb.USBTunerDevice;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class FCD2TunerController extends FCDTunerController
|
||||
{
|
||||
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 FCD2TunerController( USBTunerDevice device )
|
||||
throws SourceException
|
||||
{
|
||||
super( device,
|
||||
sMINIMUM_TUNABLE_FREQUENCY,
|
||||
sMAXIMUM_TUNABLE_FREQUENCY );
|
||||
|
||||
mFrequencyController.setBandwidth( sSAMPLE_RATE );
|
||||
|
||||
try
|
||||
{
|
||||
open();
|
||||
|
||||
setFCDMode( Mode.APPLICATION );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
throw new SourceException( "FCDTunerController error " +
|
||||
"during construction", e );
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentSampleRate()
|
||||
{
|
||||
return sSAMPLE_RATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return TunerClass.FUNCUBE_DONGLE_PRO_PLUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.FUNCUBE_DONGLE_PRO_PLUS;
|
||||
}
|
||||
|
||||
public JPanel getEditor( FCDTuner tuner, ResourceManager resourceManager )
|
||||
{
|
||||
if( mEditor == null )
|
||||
{
|
||||
mEditor = new FCD2TunerEditorPanel( tuner, resourceManager );
|
||||
}
|
||||
|
||||
return mEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply( TunerConfiguration config ) throws SourceException
|
||||
{
|
||||
if( config instanceof FCD2TunerConfiguration )
|
||||
{
|
||||
FCD2TunerConfiguration plusConfig =
|
||||
(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 ( UsbClaimException e )
|
||||
{
|
||||
throw new SourceException( "Exception while setting LNA Gain", e );
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
throw new SourceException( "Exception 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 ( UsbClaimException e )
|
||||
{
|
||||
throw new SourceException( "Exception while setting mixer gain", e );
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
throw new SourceException( "Exception while setting mixer gain", e );
|
||||
}
|
||||
|
||||
mTunerConfiguration = plusConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerConfiguration getTunerConfiguration()
|
||||
{
|
||||
return mTunerConfiguration;
|
||||
}
|
||||
|
||||
public int getDCCorrection()
|
||||
{
|
||||
int dcCorrection = -999;
|
||||
|
||||
try
|
||||
{
|
||||
dcCorrection = (int)send( FCDCommand.APP_GET_DC_CORRECTION );
|
||||
}
|
||||
catch ( UsbClaimException e )
|
||||
{
|
||||
Log.error( "FCTTunerController - couldn't claim funcube HID to"
|
||||
+ " get dc correction value" );
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
Log.error( "FCTTunerController - error getting dc correction "
|
||||
+ "value - " + e.getLocalizedMessage() );
|
||||
|
||||
}
|
||||
|
||||
return dcCorrection;
|
||||
}
|
||||
|
||||
public void setDCCorrection( int value )
|
||||
{
|
||||
try
|
||||
{
|
||||
send( FCDCommand.APP_SET_DC_CORRECTION, value );
|
||||
}
|
||||
catch ( UsbClaimException e )
|
||||
{
|
||||
Log.error( "FCDTunerController - error claiming usb hid while "
|
||||
+ "trying to set dc correction to [" + value + "]" );
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
Log.error( "FCDTunerController - error while "
|
||||
+ "trying to set dc correction to [" + value + "] - " +
|
||||
e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
public int getIQCorrection()
|
||||
{
|
||||
int iqCorrection = -999;
|
||||
|
||||
try
|
||||
{
|
||||
iqCorrection = (int)send( FCDCommand.APP_GET_IQ_CORRECTION );
|
||||
}
|
||||
catch ( UsbClaimException e )
|
||||
{
|
||||
Log.error( "FCTTunerController - couldn't claim funcube HID to"
|
||||
+ " get iq correction value" );
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
Log.error( "FCTTunerController - error getting iq correction "
|
||||
+ "value - " + e.getLocalizedMessage() );
|
||||
|
||||
}
|
||||
|
||||
return iqCorrection;
|
||||
}
|
||||
|
||||
public void setIQCorrection( int value )
|
||||
{
|
||||
try
|
||||
{
|
||||
send( FCDCommand.APP_SET_IQ_CORRECTION, value );
|
||||
}
|
||||
catch ( UsbClaimException e )
|
||||
{
|
||||
Log.error( "FCDTunerController - error claiming usb hid while "
|
||||
+ "trying to set iq correction to [" + value + "]" );
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
Log.error( "FCDTunerController - error while "
|
||||
+ "trying to set iq correction to [" + value + "] - " +
|
||||
e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
public enum Block
|
||||
{
|
||||
CELLULAR_BAND_BLOCKED( "Blocked" ),
|
||||
NO_BAND_BLOCK( "Unblocked" ),
|
||||
UNKNOWN( "Unknown" );
|
||||
|
||||
private String mLabel;
|
||||
|
||||
private Block( String label )
|
||||
{
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public static Block getBlock( String block )
|
||||
{
|
||||
Block retVal = UNKNOWN;
|
||||
|
||||
if( block.equalsIgnoreCase( "No blk" ) )
|
||||
{
|
||||
retVal = NO_BAND_BLOCK;
|
||||
}
|
||||
else if( block.equalsIgnoreCase( "Cell blk" ) )
|
||||
{
|
||||
retVal = CELLULAR_BAND_BLOCKED;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TunerRFFilter
|
||||
{
|
||||
TRF_0_4,
|
||||
TRF_4_8,
|
||||
TRF_8_16,
|
||||
TRF_16_32,
|
||||
TRF_32_75,
|
||||
TRF_75_125,
|
||||
TRF_125_250,
|
||||
TRF_145,
|
||||
TRF_410_875,
|
||||
TRF_435,
|
||||
TRF_875_2000,
|
||||
UNKNOWN;
|
||||
|
||||
public static TunerRFFilter get( int value )
|
||||
{
|
||||
TunerRFFilter retVal = UNKNOWN;
|
||||
|
||||
if( 0 <= value && value <= 10 )
|
||||
{
|
||||
retVal = values()[ value ];
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TunerIFFilter
|
||||
{
|
||||
TIF_200KHZ,
|
||||
TIF_300KHZ,
|
||||
TIF_600KHZ,
|
||||
TIF_1536KHZ,
|
||||
TIF_5MHZ,
|
||||
TIF_6MHZ,
|
||||
TIF_7MHZ,
|
||||
TIF_8MHZ,
|
||||
UNKNOWN;
|
||||
|
||||
public static TunerIFFilter get( int value )
|
||||
{
|
||||
TunerIFFilter retVal = UNKNOWN;
|
||||
|
||||
if( 0 <= value && value <= 7 )
|
||||
{
|
||||
retVal = values()[ value ];
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
public enum LNAGain
|
||||
{
|
||||
LNA_GAIN_MINUS_5_0( 0, "-5.0 dB" ),
|
||||
LNA_GAIN_MINUS_2_5( 1, "-2.5 dB" ),
|
||||
LNA_GAIN_PLUS_0_0( 4, "0.0 dB" ),
|
||||
LNA_GAIN_PLUS_2_5( 5, "2.5 dB" ),
|
||||
LNA_GAIN_PLUS_5_0( 6, "5.0 dB" ),
|
||||
LNA_GAIN_PLUS_7_5( 7, "7.5 dB" ),
|
||||
LNA_GAIN_PLUS_10_0( 8, "10.0 dB" ),
|
||||
LNA_GAIN_PLUS_12_5( 9, "12.5 dB" ),
|
||||
LNA_GAIN_PLUS_15_0( 10, "15.0 dB" ),
|
||||
LNA_GAIN_PLUS_17_5( 11, "17.5 dB" ),
|
||||
LNA_GAIN_PLUS_20_0( 12, "20.0 dB" ),
|
||||
LNA_GAIN_PLUS_25_0( 13, "25.0 dB" ),
|
||||
LNA_GAIN_PLUS_30_0( 14, "30.0 dB" );
|
||||
|
||||
private int mSetting;
|
||||
private String mLabel;
|
||||
|
||||
private LNAGain( int setting, String label )
|
||||
{
|
||||
mSetting = setting;
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public int getSetting()
|
||||
{
|
||||
return mSetting;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
101
src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java
Normal file
101
src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*******************************************************************************
|
||||
* 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.Color;
|
||||
|
||||
import gui.control.JFrequencyControl;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import source.SourceException;
|
||||
import source.tuner.FrequencyChangeListener;
|
||||
import source.tuner.fcd.FCDTuner;
|
||||
import source.tuner.fcd.FCDTunerDetailsPanel;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class FCD2TunerEditorPanel extends JPanel implements FrequencyChangeListener
|
||||
{
|
||||
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( int frequency, int bandwidth )
|
||||
{
|
||||
//Disregard the bandwidth, which shouldn't be changing
|
||||
try
|
||||
{
|
||||
mController.setFrequency( frequency );
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
Log.error( "FCTProController - error setting frequency [" +
|
||||
frequency + "] - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/source/tuner/rtl/RTL2832InfoPanel.java
Normal file
76
src/source/tuner/rtl/RTL2832InfoPanel.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* 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" ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/source/tuner/rtl/RTL2832SampleAdapter.java
Normal file
59
src/source/tuner/rtl/RTL2832SampleAdapter.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*******************************************************************************
|
||||
* 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 source.Source.SampleType;
|
||||
import source.mixer.SampleAdapter;
|
||||
|
||||
public class RTL2832SampleAdapter extends SampleAdapter
|
||||
{
|
||||
private final static float[] mLOOKUP_VALUES;
|
||||
|
||||
/**
|
||||
* Creates a static lookup table that converts the 8-bit valued range
|
||||
* from 0 - 255 into scaled float values of -128 to 0 to 127
|
||||
*/
|
||||
static
|
||||
{
|
||||
mLOOKUP_VALUES = new float[ 256 ];
|
||||
|
||||
float scale = (float)( 1.0f / 127.0f );
|
||||
|
||||
for( int x = 0; x < 256; x++ )
|
||||
{
|
||||
mLOOKUP_VALUES[ x ] = (float)( x - 128 ) * scale;
|
||||
}
|
||||
|
||||
mLOOKUP_VALUES[ 128 ] = 0.0000001f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float[] convert( byte[] samples )
|
||||
{
|
||||
Float[] convertedSamples = new Float[ samples.length ];
|
||||
int pointer = 0;
|
||||
|
||||
for( byte sample: samples )
|
||||
{
|
||||
/* Convert byte value into float from the lookup table */
|
||||
convertedSamples[ pointer++ ] = mLOOKUP_VALUES[ ( sample & 0xFF ) ];
|
||||
}
|
||||
|
||||
return convertedSamples;
|
||||
}
|
||||
}
|
||||
168
src/source/tuner/rtl/RTL2832Tuner.java
Normal file
168
src/source/tuner/rtl/RTL2832Tuner.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*******************************************************************************
|
||||
* 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 java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.usb.UsbException;
|
||||
|
||||
import log.Log;
|
||||
import sample.Listener;
|
||||
import source.SourceException;
|
||||
import source.tuner.FrequencyChangeListener;
|
||||
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.rtl.RTL2832TunerController.SampleRate;
|
||||
import controller.ResourceManager;
|
||||
import controller.ThreadPoolManager;
|
||||
|
||||
public class RTL2832Tuner extends Tuner
|
||||
{
|
||||
private TunerClass mTunerClass;
|
||||
protected RTL2832TunerController mController;
|
||||
|
||||
public RTL2832Tuner( TunerClass tunerClass,
|
||||
RTL2832TunerController controller )
|
||||
throws SourceException
|
||||
{
|
||||
super( tunerClass.getVendorDeviceLabel() + "/" +
|
||||
controller.getTunerType().getLabel() + " #" +
|
||||
controller.getUniqueID() );
|
||||
|
||||
mTunerClass = tunerClass;
|
||||
mController = controller;
|
||||
mController.addListener( (FrequencyChangeListener)this );
|
||||
}
|
||||
|
||||
public RTL2832TunerController getController()
|
||||
{
|
||||
return mController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
return mController.getUniqueID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return mTunerClass;
|
||||
}
|
||||
|
||||
@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 )
|
||||
{
|
||||
Log.error( "RTL2832 Tuner - couldn't get sample rate - " +
|
||||
e.getLocalizedMessage() );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setSampleRate( SampleRate sampleRate ) throws SourceException
|
||||
{
|
||||
try
|
||||
{
|
||||
mController.setSampleRate( sampleRate );
|
||||
}
|
||||
catch( UsbException e )
|
||||
{
|
||||
throw new SourceException( "RTL2832 Tuner - error setting "
|
||||
+ "sample rate", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrequency() throws SourceException
|
||||
{
|
||||
return mController.getFrequency();
|
||||
}
|
||||
|
||||
public void setFrequency( int frequency ) throws SourceException
|
||||
{
|
||||
mController.setFrequency( frequency );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel( ThreadPoolManager threadPoolManager,
|
||||
TunerChannel channel )
|
||||
throws RejectedExecutionException,
|
||||
SourceException
|
||||
{
|
||||
return mController.getChannel( threadPoolManager, this, channel );
|
||||
}
|
||||
/**
|
||||
* Releases the tuned channel so that the tuner controller can tune to
|
||||
* other frequencies as needed.
|
||||
*/
|
||||
@Override
|
||||
public void releaseChannel( TunerChannelSource source )
|
||||
{
|
||||
/* Unregister for receiving samples */
|
||||
removeListener( (Listener<Float[]>)source );
|
||||
|
||||
/* Tell the controller to release the channel and cleanup */
|
||||
if( source != null )
|
||||
{
|
||||
mController.releaseChannel( source );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener( Listener<Float[]> listener )
|
||||
{
|
||||
mController.addListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( Listener<Float[]> listener )
|
||||
{
|
||||
mController.removeListener( listener );
|
||||
}
|
||||
}
|
||||
1848
src/source/tuner/rtl/RTL2832TunerController.java
Normal file
1848
src/source/tuner/rtl/RTL2832TunerController.java
Normal file
File diff suppressed because it is too large
Load Diff
28
src/source/tuner/rtl/RTL2832TunerType.java
Normal file
28
src/source/tuner/rtl/RTL2832TunerType.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
124
src/source/tuner/rtl/e4k/E4KTunerConfiguration.java
Normal file
124
src/source/tuner/rtl/e4k/E4KTunerConfiguration.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*******************************************************************************
|
||||
* 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 javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import source.tuner.TunerConfiguration;
|
||||
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;
|
||||
|
||||
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_200MHZ;
|
||||
|
||||
/**
|
||||
* Default constructor for JAXB
|
||||
*/
|
||||
public E4KTunerConfiguration()
|
||||
{
|
||||
this( "Default" );
|
||||
}
|
||||
|
||||
public E4KTunerConfiguration( String name )
|
||||
{
|
||||
super( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.ELONICS_E4000;
|
||||
}
|
||||
|
||||
@XmlAttribute( name="master_gain" )
|
||||
public E4KGain getMasterGain()
|
||||
{
|
||||
return mMasterGain;
|
||||
}
|
||||
|
||||
public void setMasterGain( E4KGain gain )
|
||||
{
|
||||
mMasterGain = gain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name="mixer_gain" )
|
||||
public E4KMixerGain getMixerGain()
|
||||
{
|
||||
return mMixerGain;
|
||||
}
|
||||
|
||||
public void setMixerGain( E4KMixerGain mixerGain )
|
||||
{
|
||||
mMixerGain = mixerGain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name="lna_gain" )
|
||||
public E4KLNAGain getLNAGain()
|
||||
{
|
||||
return mLNAGain;
|
||||
}
|
||||
|
||||
public void setLNAGain( E4KLNAGain lnaGain )
|
||||
{
|
||||
mLNAGain = lnaGain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name="enhance_gain" )
|
||||
public E4KEnhanceGain getEnhanceGain()
|
||||
{
|
||||
return mEnhanceGain;
|
||||
}
|
||||
|
||||
public void setEnhanceGain( E4KEnhanceGain enhanceGain )
|
||||
{
|
||||
mEnhanceGain = enhanceGain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name="frequency_correction" )
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double value )
|
||||
{
|
||||
mFrequencyCorrection = value;
|
||||
}
|
||||
|
||||
@XmlAttribute( name="sample_rate" )
|
||||
public SampleRate getSampleRate()
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
public void setSampleRate( SampleRate sampleRate )
|
||||
{
|
||||
mSampleRate = sampleRate;
|
||||
}
|
||||
|
||||
}
|
||||
688
src/source/tuner/rtl/e4k/E4KTunerConfigurationPanel.java
Normal file
688
src/source/tuner/rtl/e4k/E4KTunerConfigurationPanel.java
Normal file
@@ -0,0 +1,688 @@
|
||||
/*******************************************************************************
|
||||
* 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 com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
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 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() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
||||
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 | UsbException eSampleRate )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
E4KTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't apply the sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "] " +
|
||||
eSampleRate.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "] " +
|
||||
eSampleRate.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
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() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
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() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply mixer "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
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() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply LNA "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
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() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply enhance "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
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() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply "
|
||||
+ "config [" + config.getName() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
2452
src/source/tuner/rtl/e4k/E4KTunerController.java
Normal file
2452
src/source/tuner/rtl/e4k/E4KTunerController.java
Normal file
File diff suppressed because it is too large
Load Diff
111
src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java
Normal file
111
src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*******************************************************************************
|
||||
* 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.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import source.SourceComponentEditor;
|
||||
import source.SourceException;
|
||||
import source.tuner.FrequencyChangeListener;
|
||||
import source.tuner.rtl.RTL2832InfoPanel;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class E4KTunerEditorPanel extends JPanel implements FrequencyChangeListener
|
||||
{
|
||||
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( final int frequency, int bandwidth )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
mController.setFrequency( frequency );
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
Log.error( "E4KTunerController - error setting frequency [" +
|
||||
frequency + "] - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
123
src/source/tuner/rtl/r820t/R820TTunerConfiguration.java
Normal file
123
src/source/tuner/rtl/r820t/R820TTunerConfiguration.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*******************************************************************************
|
||||
* 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.r820t;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import source.tuner.TunerConfiguration;
|
||||
import source.tuner.TunerType;
|
||||
import source.tuner.rtl.RTL2832TunerController.SampleRate;
|
||||
import source.tuner.rtl.r820t.R820TTunerController.R820TEnhanceGain;
|
||||
import source.tuner.rtl.r820t.R820TTunerController.R820TGain;
|
||||
import source.tuner.rtl.r820t.R820TTunerController.R820TLNAGain;
|
||||
import source.tuner.rtl.r820t.R820TTunerController.R820TMixerGain;
|
||||
|
||||
public class R820TTunerConfiguration extends TunerConfiguration
|
||||
{
|
||||
private R820TGain mMasterGain = R820TGain.AUTOMATIC;
|
||||
private R820TMixerGain mMixerGain = R820TMixerGain.AUTOMATIC;
|
||||
private R820TLNAGain mLNAGain = R820TLNAGain.AUTOMATIC;
|
||||
private R820TEnhanceGain mEnhanceGain = R820TEnhanceGain.AUTOMATIC;
|
||||
private double mFrequencyCorrection = -12.0d;
|
||||
private SampleRate mSampleRate = SampleRate.RATE_1_200MHZ;
|
||||
|
||||
/**
|
||||
* Default constructor for JAXB
|
||||
*/
|
||||
public R820TTunerConfiguration()
|
||||
{
|
||||
this( "Default" );
|
||||
}
|
||||
|
||||
public R820TTunerConfiguration( String name )
|
||||
{
|
||||
super( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.ELONICS_E4000;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "master_gain" )
|
||||
public R820TGain getMasterGain()
|
||||
{
|
||||
return mMasterGain;
|
||||
}
|
||||
|
||||
public void setMasterGain( R820TGain gain )
|
||||
{
|
||||
mMasterGain = gain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "mixer_gain" )
|
||||
public R820TMixerGain getMixerGain()
|
||||
{
|
||||
return mMixerGain;
|
||||
}
|
||||
|
||||
public void setMixerGain( R820TMixerGain mixerGain )
|
||||
{
|
||||
mMixerGain = mixerGain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "lna_gain" )
|
||||
public R820TLNAGain getLNAGain()
|
||||
{
|
||||
return mLNAGain;
|
||||
}
|
||||
|
||||
public void setLNAGain( R820TLNAGain lnaGain )
|
||||
{
|
||||
mLNAGain = lnaGain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "enhance_gain" )
|
||||
public R820TEnhanceGain getEnhanceGain()
|
||||
{
|
||||
return mEnhanceGain;
|
||||
}
|
||||
|
||||
public void setEnhanceGain( R820TEnhanceGain enhanceGain )
|
||||
{
|
||||
mEnhanceGain = enhanceGain;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "frequency_correction" )
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double value )
|
||||
{
|
||||
mFrequencyCorrection = value;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "sample_rate" )
|
||||
public SampleRate getSampleRate()
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
public void setSampleRate( SampleRate sampleRate )
|
||||
{
|
||||
mSampleRate = sampleRate;
|
||||
}
|
||||
}
|
||||
619
src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java
Normal file
619
src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java
Normal file
@@ -0,0 +1,619 @@
|
||||
/*******************************************************************************
|
||||
* 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.r820t;
|
||||
|
||||
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 log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
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.r820t.R820TTunerController.R820TEnhanceGain;
|
||||
import source.tuner.rtl.r820t.R820TTunerController.R820TGain;
|
||||
import source.tuner.rtl.r820t.R820TTunerController.R820TLNAGain;
|
||||
import source.tuner.rtl.r820t.R820TTunerController.R820TMixerGain;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class R820TTunerConfigurationPanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private ResourceManager mResourceManager;
|
||||
private R820TTunerController mController;
|
||||
private R820TTunerConfiguration mSelectedConfig;
|
||||
|
||||
private JButton mNewConfiguration;
|
||||
private JButton mDeleteConfiguration;
|
||||
private JComboBox<R820TTunerConfiguration> mComboConfigurations;
|
||||
|
||||
private JTextField mName;
|
||||
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<R820TGain> mComboMasterGain;
|
||||
private JComboBox<R820TMixerGain> mComboMixerGain;
|
||||
private JComboBox<R820TLNAGain> mComboLNAGain;
|
||||
private JComboBox<R820TEnhanceGain> mComboEnhanceGain;
|
||||
|
||||
private JComboBox<SampleRate> mComboSampleRate;
|
||||
|
||||
public R820TTunerConfigurationPanel( ResourceManager resourceManager,
|
||||
R820TTunerController controller )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
mController = controller;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the gui components
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) );
|
||||
|
||||
setBorder( BorderFactory.createTitledBorder( "Tuner Configuration" ) );
|
||||
|
||||
/**
|
||||
* Tuner configuration selector
|
||||
*/
|
||||
mComboConfigurations = new JComboBox<R820TTunerConfiguration>();
|
||||
|
||||
mComboConfigurations.setModel( getModel() );
|
||||
|
||||
/* Determine which tuner configuration should be selected/displayed */
|
||||
TunerConfigurationAssignment savedConfig = mResourceManager
|
||||
.getSettingsManager().getSelectedTunerConfiguration(
|
||||
TunerType.RAFAELMICRO_R820T, 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.RAFAELMICRO_R820T,
|
||||
mController.getUniqueID(), mSelectedConfig );
|
||||
}
|
||||
|
||||
mComboConfigurations.setSelectedItem( mSelectedConfig );
|
||||
|
||||
mComboConfigurations.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
R820TTunerConfiguration selected =
|
||||
(R820TTunerConfiguration)mComboConfigurations
|
||||
.getItemAt( mComboConfigurations.getSelectedIndex() );
|
||||
|
||||
if( selected != null )
|
||||
{
|
||||
update( selected );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add( mComboConfigurations, "span 2,wrap" );
|
||||
|
||||
|
||||
/**
|
||||
* 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( mName );
|
||||
add( new JLabel( "Name" ), "wrap" );
|
||||
|
||||
/**
|
||||
* 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(
|
||||
R820TTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
||||
add( mFrequencyCorrection );
|
||||
add( new JLabel( "Frequency Correction (ppm)" ), "wrap" );
|
||||
|
||||
/**
|
||||
* 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 | UsbException eSampleRate )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't apply the sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "] " +
|
||||
eSampleRate.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "] " +
|
||||
eSampleRate.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( mComboSampleRate );
|
||||
add( new JLabel( "Sample Rate" ), "wrap" );
|
||||
|
||||
/**
|
||||
* Gain Controls
|
||||
*/
|
||||
JPanel gainPanel = new JPanel();
|
||||
gainPanel.setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) );
|
||||
gainPanel.setBorder( BorderFactory.createTitledBorder( "Gain" ) );
|
||||
|
||||
/* Master Gain Control */
|
||||
mComboMasterGain = new JComboBox<R820TGain>( R820TGain.values() );
|
||||
mComboMasterGain.setSelectedItem( mSelectedConfig.getMasterGain() );
|
||||
|
||||
mComboMasterGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TGain gain = (R820TGain)mComboMasterGain.getSelectedItem();
|
||||
|
||||
mController.setGain( (R820TGain)mComboMasterGain.getSelectedItem(), true );
|
||||
|
||||
if( gain == R820TGain.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(
|
||||
R820TTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't apply the gain "
|
||||
+ "setting - " + e.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
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( mComboMasterGain );
|
||||
gainPanel.add( new JLabel( "Master" ), "wrap" );
|
||||
|
||||
/* Mixer Gain Control */
|
||||
mComboMixerGain = new JComboBox<R820TMixerGain>( R820TMixerGain.values() );
|
||||
mComboMixerGain.setSelectedItem( mSelectedConfig.getMixerGain() );
|
||||
mComboMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TMixerGain mixerGain =
|
||||
(R820TMixerGain)mComboMixerGain.getSelectedItem();
|
||||
|
||||
if( mComboMixerGain.isEnabled() )
|
||||
{
|
||||
mController.setMixerGain( mixerGain, true );
|
||||
}
|
||||
|
||||
mSelectedConfig.setMixerGain( mixerGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't apply the mixer "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply mixer "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
mComboMixerGain.setToolTipText( "<html>Mixer Gain. Set master gain "
|
||||
+ "to <b>MASTER</b> to enable adjustment</html>" );
|
||||
mComboMixerGain.setEnabled( false );
|
||||
gainPanel.add( mComboMixerGain );
|
||||
gainPanel.add( new JLabel( "Mixer" ), "wrap" );
|
||||
|
||||
/* LNA Gain Control */
|
||||
mComboLNAGain = new JComboBox<R820TLNAGain>( R820TLNAGain.values() );
|
||||
mComboLNAGain.setSelectedItem( mSelectedConfig.getLNAGain() );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TLNAGain lnaGain = (R820TLNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
if( mComboLNAGain.isEnabled() )
|
||||
{
|
||||
mController.setLNAGain( lnaGain, true );
|
||||
}
|
||||
|
||||
mSelectedConfig.setLNAGain( lnaGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't apply the LNA "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply LNA "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboLNAGain.setToolTipText( "<html>LNA Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
gainPanel.add( mComboLNAGain );
|
||||
gainPanel.add( new JLabel( "LNA" ), "wrap" );
|
||||
|
||||
/* Enhance Gain Control */
|
||||
mComboEnhanceGain = new JComboBox<R820TEnhanceGain>( R820TEnhanceGain.values() );
|
||||
mComboEnhanceGain.setSelectedItem( mSelectedConfig.getEnhanceGain() );
|
||||
mComboEnhanceGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TEnhanceGain enhanceGain =
|
||||
(R820TEnhanceGain)mComboEnhanceGain.getSelectedItem();
|
||||
|
||||
if( mComboEnhanceGain.isEnabled() )
|
||||
{
|
||||
mController.setEnhanceGain( enhanceGain, true );
|
||||
}
|
||||
|
||||
mSelectedConfig.setEnhanceGain( enhanceGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't apply the enhance "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply enhance "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboEnhanceGain.setToolTipText( "<html>Enhance Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
mComboEnhanceGain.setEnabled( false );
|
||||
gainPanel.add( mComboEnhanceGain );
|
||||
gainPanel.add( new JLabel( "Enhance" ), "wrap" );
|
||||
|
||||
add( gainPanel, "span" );
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
|
||||
/**
|
||||
* Delete the currently selected configuration
|
||||
*/
|
||||
mDeleteConfiguration = new JButton( "Delete" );
|
||||
|
||||
mDeleteConfiguration.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
R820TTunerConfiguration selected =
|
||||
(R820TTunerConfiguration)mComboConfigurations
|
||||
.getItemAt( mComboConfigurations.getSelectedIndex() );
|
||||
|
||||
if( selected != null )
|
||||
{
|
||||
int n = JOptionPane.showConfirmDialog(
|
||||
R820TTunerConfigurationPanel.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, "wrap" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates gui controls with the values from the tuner configuration
|
||||
* @param config - tuner configuration
|
||||
*/
|
||||
private void update( R820TTunerConfiguration 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(
|
||||
R820TTunerConfigurationPanel.this,
|
||||
"E4K Tuner Controller - couldn't "
|
||||
+ "apply the tuner configuration settings - " +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
Log.error( "E4K Tuner Controller - couldn't apply "
|
||||
+ "config [" + config.getName() + "] - " +
|
||||
e1.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<R820TTunerConfiguration> getModel()
|
||||
{
|
||||
ArrayList<TunerConfiguration> configs =
|
||||
mResourceManager.getSettingsManager()
|
||||
.getTunerConfigurations( TunerType.RAFAELMICRO_R820T );
|
||||
|
||||
DefaultComboBoxModel<R820TTunerConfiguration> model =
|
||||
new DefaultComboBoxModel<R820TTunerConfiguration>();
|
||||
|
||||
for( TunerConfiguration config: configs )
|
||||
{
|
||||
model.addElement( (R820TTunerConfiguration)config );
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a specific (named) tuner configuration
|
||||
*/
|
||||
private R820TTunerConfiguration getNamedConfiguration( String name )
|
||||
{
|
||||
ArrayList<TunerConfiguration> configs =
|
||||
mResourceManager.getSettingsManager()
|
||||
.getTunerConfigurations( TunerType.RAFAELMICRO_R820T );
|
||||
|
||||
for( TunerConfiguration config: configs )
|
||||
{
|
||||
if( config.getName().contentEquals( name ) )
|
||||
{
|
||||
return (R820TTunerConfiguration)config;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves current tuner configuration settings
|
||||
*/
|
||||
private void save()
|
||||
{
|
||||
mResourceManager.getSettingsManager().save();
|
||||
}
|
||||
}
|
||||
2408
src/source/tuner/rtl/r820t/R820TTunerController.java
Normal file
2408
src/source/tuner/rtl/r820t/R820TTunerController.java
Normal file
File diff suppressed because it is too large
Load Diff
93
src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java
Normal file
93
src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* 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.r820t;
|
||||
|
||||
import gui.control.JFrequencyControl;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import source.SourceException;
|
||||
import source.tuner.FrequencyChangeListener;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class R820TTunerEditorPanel extends JPanel implements FrequencyChangeListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private R820TTunerController mController;
|
||||
private ResourceManager mResourceManager;
|
||||
|
||||
private JFrequencyControl mFrequencyControl;
|
||||
|
||||
public R820TTunerEditorPanel( R820TTunerController controller,
|
||||
ResourceManager resourceManager )
|
||||
{
|
||||
mController = controller;
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) );
|
||||
|
||||
setBorder( BorderFactory.createTitledBorder( "Rafael Micro R820T Tuner" ) );
|
||||
|
||||
mFrequencyControl = new JFrequencyControl();
|
||||
|
||||
mFrequencyControl.addListener( this );
|
||||
|
||||
mFrequencyControl.setFrequency( mController.getFrequency(), false );
|
||||
|
||||
add( mFrequencyControl, "wrap" );
|
||||
|
||||
add( new R820TTunerConfigurationPanel( mResourceManager, mController ),
|
||||
"wrap" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency change listener for the frequency control gui component to
|
||||
* apply end-user requested frequency changes against the tuner
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged( final int frequency, int bandwidth )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
mController.setFrequency( frequency );
|
||||
}
|
||||
catch ( SourceException e )
|
||||
{
|
||||
Log.error( "E4KTunerController - error setting frequency [" +
|
||||
frequency + "] - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
44
src/source/tuner/usb/USBTunerDevice.java
Normal file
44
src/source/tuner/usb/USBTunerDevice.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* 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.usb;
|
||||
|
||||
import javax.usb.UsbDevice;
|
||||
|
||||
import source.tuner.TunerClass;
|
||||
|
||||
public class USBTunerDevice
|
||||
{
|
||||
private UsbDevice mDevice;
|
||||
private TunerClass mTunerClass;
|
||||
|
||||
public USBTunerDevice( UsbDevice device, TunerClass tunerClass )
|
||||
{
|
||||
mDevice = device;
|
||||
mTunerClass = tunerClass;
|
||||
}
|
||||
|
||||
public UsbDevice getDevice()
|
||||
{
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return mTunerClass;
|
||||
}
|
||||
}
|
||||
114
src/source/tuner/usb/USBUtils.java
Normal file
114
src/source/tuner/usb/USBUtils.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*******************************************************************************
|
||||
* 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.usb;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.usb.UsbConfiguration;
|
||||
import javax.usb.UsbDevice;
|
||||
import javax.usb.UsbDisconnectedException;
|
||||
import javax.usb.UsbEndpoint;
|
||||
import javax.usb.UsbException;
|
||||
import javax.usb.UsbHostManager;
|
||||
import javax.usb.UsbHub;
|
||||
import javax.usb.UsbInterface;
|
||||
import javax.usb.UsbServices;
|
||||
|
||||
public class USBUtils
|
||||
{
|
||||
/**
|
||||
* Returns a List of currently connected usb devices
|
||||
*/
|
||||
public static List<UsbDevice> getDevices()
|
||||
throws SecurityException, UsbException, UnsupportedEncodingException
|
||||
{
|
||||
ArrayList<UsbDevice> devices = new ArrayList<UsbDevice>();
|
||||
|
||||
UsbServices services = UsbHostManager.getUsbServices();
|
||||
|
||||
UsbHub root = services.getRootUsbHub();
|
||||
|
||||
devices.addAll( getHubDevices( root ) );
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of devices attached to the hub
|
||||
*/
|
||||
public static List<UsbDevice> getHubDevices( UsbHub hub )
|
||||
throws UnsupportedEncodingException, UsbException
|
||||
{
|
||||
ArrayList<UsbDevice> devices = new ArrayList<UsbDevice>();
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
List<UsbDevice> children = hub.getAttachedUsbDevices();
|
||||
|
||||
Iterator<UsbDevice> it = children.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
{
|
||||
UsbDevice child = it.next();
|
||||
|
||||
if( child.isUsbHub() )
|
||||
{
|
||||
devices.addAll( getHubDevices( (UsbHub)child ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
devices.add( child );
|
||||
}
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
public static String getDeviceDetails( UsbDevice device )
|
||||
throws UsbException, UnsupportedEncodingException, UsbDisconnectedException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( device.getUsbDeviceDescriptor().toString() + "\n\n" );
|
||||
|
||||
for( Object configObject: device.getUsbConfigurations() )
|
||||
{
|
||||
UsbConfiguration config = (UsbConfiguration)configObject;
|
||||
|
||||
sb.append( config.getUsbConfigurationDescriptor().toString() + "\n\n" );
|
||||
|
||||
for( Object interfaceObject: config.getUsbInterfaces() )
|
||||
{
|
||||
UsbInterface iface = (UsbInterface)interfaceObject;
|
||||
|
||||
sb.append( iface.getUsbInterfaceDescriptor().toString() + "\n\n" );
|
||||
|
||||
for( Object endpointObject: iface.getUsbEndpoints() )
|
||||
{
|
||||
UsbEndpoint endpoint = (UsbEndpoint)endpointObject;
|
||||
|
||||
sb.append( endpoint.getUsbEndpointDescriptor().toString() + "\n\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
300
src/source/wave/ComplexWaveSource.java
Normal file
300
src/source/wave/ComplexWaveSource.java
Normal file
@@ -0,0 +1,300 @@
|
||||
/*******************************************************************************
|
||||
* 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.wave;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexSample;
|
||||
|
||||
public class ComplexWaveSource extends WaveSource
|
||||
{
|
||||
private boolean mRunning = false;
|
||||
private boolean mLoop = false;
|
||||
|
||||
private AudioInputStream mInputStream = null;
|
||||
private int mBytesPerFrame = 0;
|
||||
private int mFrequency = 0;
|
||||
|
||||
private byte[] mBuffer;
|
||||
private int mBufferPointer = 0;
|
||||
private int mBufferLength;
|
||||
private ShortBuffer mBufferWrapper;
|
||||
|
||||
private static int BUFFER_SAMPLE_SIZE = 2000;
|
||||
|
||||
private ArrayList<Listener<ComplexSample>> mListeners =
|
||||
new ArrayList<Listener<ComplexSample>>();
|
||||
|
||||
/**
|
||||
* Single channel (mono) wave file playback source with optional looping
|
||||
* for continous playback.
|
||||
*
|
||||
* Playback can be invoked manually with the next() and next(x) methods to
|
||||
* get sample(s).
|
||||
*
|
||||
* Plaback can be run automatically by invoking the start() and stop()
|
||||
* methods.
|
||||
*
|
||||
* Registered float sample listener(s) will receive any samples produced
|
||||
* by the manual or automatic methods.
|
||||
*
|
||||
* @param loop - true for looping
|
||||
*
|
||||
* @throws FileNotFoundException if filename is not found
|
||||
*/
|
||||
public ComplexWaveSource( File file, boolean loop ) throws IOException
|
||||
{
|
||||
super( file, SampleType.COMPLEX );
|
||||
mLoop = loop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSampleRate()
|
||||
{
|
||||
return (int)mInputStream.getFormat().getSampleRate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frequency set for this file. Normally returns zero, but
|
||||
* the value can be set with setFrequency() method.
|
||||
*/
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the value returned from getFrequency() for this source.
|
||||
*/
|
||||
public void setFrequency( int frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the audio input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if( mInputStream != null )
|
||||
{
|
||||
mInputStream.close();
|
||||
}
|
||||
|
||||
mInputStream = null;
|
||||
}
|
||||
|
||||
public void open() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
mInputStream = AudioSystem.getAudioInputStream( getFile() );
|
||||
}
|
||||
catch( UnsupportedAudioFileException e )
|
||||
{
|
||||
throw new IOException( "MonoWaveSource - unsupported audio file "
|
||||
+ "exception - ", e );
|
||||
}
|
||||
|
||||
mBytesPerFrame = mInputStream.getFormat().getFrameSize();
|
||||
|
||||
if( mBytesPerFrame != 2 || mInputStream.getFormat().getChannels() != 2 )
|
||||
{
|
||||
throw new IOException( "Unsupported Wave Format - requires two "
|
||||
+ "channels with 16-bit samples" );
|
||||
}
|
||||
|
||||
mBuffer = new byte[ mBytesPerFrame * BUFFER_SAMPLE_SIZE ];
|
||||
|
||||
readBuffer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a sample from the wave file and broadcasts the sample to all
|
||||
* registered float listeners.
|
||||
*
|
||||
* @return - true if data was read or false if no more data. If loop is
|
||||
* set to true, then this method will continue to produce samples as long
|
||||
* as there are not IO exceptions.
|
||||
*
|
||||
* @throws IOException if unable to read data from the wave file
|
||||
*/
|
||||
/**
|
||||
* Reads the next buffer from the wave file.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void readBuffer() throws IOException
|
||||
{
|
||||
if( mInputStream != null )
|
||||
{
|
||||
/* reset the buffer pointer and fill the buffer with zeros */
|
||||
mBufferPointer = 0;
|
||||
mBufferLength = 0;
|
||||
Arrays.fill( mBuffer, (byte)0 );
|
||||
|
||||
while( mBufferLength == 0 )
|
||||
{
|
||||
boolean reset = false;
|
||||
|
||||
/* Fill the buffer with samples from the file */
|
||||
mBufferLength = (int)( mInputStream.read( mBuffer ) /
|
||||
mBytesPerFrame );
|
||||
|
||||
if( reset && mBufferLength == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we get a partial buffer, reset the file for the next read */
|
||||
if( mBufferLength < mBuffer.length && mLoop )
|
||||
{
|
||||
close();
|
||||
open();
|
||||
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( mBufferLength > 0 )
|
||||
{
|
||||
mBufferWrapper = ByteBuffer.wrap( mBuffer ).order(
|
||||
ByteOrder.LITTLE_ENDIAN ).asShortBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
mBufferWrapper = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean next( boolean broadcast ) throws IOException
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
if( mBufferPointer >= mBufferLength )
|
||||
{
|
||||
readBuffer();
|
||||
}
|
||||
|
||||
if( mBufferLength != 0 &&
|
||||
mBufferWrapper != null &&
|
||||
mBufferWrapper.hasRemaining() )
|
||||
{
|
||||
short i = mBufferWrapper.get();
|
||||
short q = mBufferWrapper.get();
|
||||
|
||||
mBufferPointer++;
|
||||
incrementCurrentLocation( 1, false );
|
||||
|
||||
if( broadcast )
|
||||
{
|
||||
send( new ComplexSample( (float)i, (float)q ) );
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public boolean next() throws IOException
|
||||
{
|
||||
return next( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next (count) samples from the wave file and broadcasts them
|
||||
* to the registered listeners.
|
||||
* @param count - number of samples to broadcast
|
||||
* @return - true if successful
|
||||
* @throws IOException for any IO issues
|
||||
*/
|
||||
public boolean next( int count ) throws IOException
|
||||
{
|
||||
for( int x = 0; x < count; x++ )
|
||||
{
|
||||
next();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpTo( long index ) throws IOException
|
||||
{
|
||||
if( index < mCurrentPosition )
|
||||
{
|
||||
close();
|
||||
open();
|
||||
}
|
||||
|
||||
while( mCurrentPosition < index )
|
||||
{
|
||||
next( false );
|
||||
}
|
||||
|
||||
incrementCurrentLocation( 0, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a sample to the registered listeners
|
||||
*/
|
||||
private void send( ComplexSample sample )
|
||||
{
|
||||
Iterator<Listener<ComplexSample>> it = mListeners.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
{
|
||||
it.next().receive( sample );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new listener to receive samples as they are read from the wave file
|
||||
*/
|
||||
public void addListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
mListeners.add( listener );
|
||||
}
|
||||
|
||||
public void removeListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
mListeners.remove( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
/* Method not implemented */
|
||||
}
|
||||
}
|
||||
290
src/source/wave/FloatWaveSource.java
Normal file
290
src/source/wave/FloatWaveSource.java
Normal file
@@ -0,0 +1,290 @@
|
||||
/*******************************************************************************
|
||||
* 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.wave;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import sample.Listener;
|
||||
|
||||
public class FloatWaveSource extends WaveSource
|
||||
{
|
||||
private boolean mRunning = false;
|
||||
private boolean mLoop = false;
|
||||
|
||||
private AudioInputStream mInputStream = null;
|
||||
private int mBytesPerFrame = 0;
|
||||
private int mFrequency = 0;
|
||||
|
||||
private byte[] mBuffer;
|
||||
private int mBufferPointer = 0;
|
||||
private int mBufferLength;
|
||||
private ShortBuffer mBufferWrapper;
|
||||
private Listener<Float> mListener;
|
||||
|
||||
private static int BUFFER_SAMPLE_SIZE = 2000;
|
||||
|
||||
|
||||
/**
|
||||
* Single channel (mono) wave file playback source with optional looping
|
||||
* for continous playback.
|
||||
*
|
||||
* Playback can be invoked manually with the next() and next(x) methods to
|
||||
* get sample(s).
|
||||
*
|
||||
* Plaback can be run automatically by invoking the start() and stop()
|
||||
* methods.
|
||||
*
|
||||
* Registered float sample listener(s) will receive any samples produced
|
||||
* by the manual or automatic methods.
|
||||
*
|
||||
* @param filename - wave filename
|
||||
*
|
||||
* @param loop - true for looping
|
||||
*
|
||||
* @throws FileNotFoundException if filename is not found
|
||||
*/
|
||||
public FloatWaveSource( File file, boolean loop ) throws IOException
|
||||
{
|
||||
super( file, SampleType.FLOAT );
|
||||
mLoop = loop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSampleRate()
|
||||
{
|
||||
return (int)mInputStream.getFormat().getSampleRate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frequency set for this file. Normally returns zero, but
|
||||
* the value can be set with setFrequency() method.
|
||||
*/
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the value returned from getFrequency() for this source.
|
||||
*/
|
||||
public void setFrequency( int frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the audio input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if( mInputStream != null )
|
||||
{
|
||||
mInputStream.close();
|
||||
}
|
||||
|
||||
mInputStream = null;
|
||||
}
|
||||
|
||||
public void open() throws IOException
|
||||
{
|
||||
if( mFile == null || !mFile.isFile() )
|
||||
{
|
||||
throw new IOException( "Empty or null file" );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mInputStream = AudioSystem.getAudioInputStream( getFile() );
|
||||
}
|
||||
catch( UnsupportedAudioFileException e )
|
||||
{
|
||||
throw new IOException( "MonoWaveSource - unsupported audio file "
|
||||
+ "exception - ", e );
|
||||
}
|
||||
|
||||
mBytesPerFrame = mInputStream.getFormat().getFrameSize();
|
||||
|
||||
if( mBytesPerFrame != 2 || mInputStream.getFormat().getChannels() != 1 )
|
||||
{
|
||||
throw new IOException( "Unsupported Wave Format - requires mono "
|
||||
+ "channel with 16-bit samples" );
|
||||
}
|
||||
|
||||
mBuffer = new byte[ mBytesPerFrame * BUFFER_SAMPLE_SIZE ];
|
||||
|
||||
readBuffer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a sample from the wave file and broadcasts the sample to all
|
||||
* registered float listeners.
|
||||
*
|
||||
* @return - true if data was read or false if no more data. If loop is
|
||||
* set to true, then this method will continue to produce samples as long
|
||||
* as there are not IO exceptions.
|
||||
*
|
||||
* @throws IOException if unable to read data from the wave file
|
||||
*/
|
||||
/**
|
||||
* Reads the next buffer from the wave file.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void readBuffer() throws IOException
|
||||
{
|
||||
if( mInputStream != null )
|
||||
{
|
||||
/* reset the buffer pointer and fill the buffer with zeros */
|
||||
mBufferPointer = 0;
|
||||
mBufferLength = 0;
|
||||
Arrays.fill( mBuffer, (byte)0 );
|
||||
|
||||
while( mBufferLength == 0 )
|
||||
{
|
||||
boolean reset = false;
|
||||
|
||||
/* Fill the buffer with samples from the file */
|
||||
mBufferLength = (int)( mInputStream.read( mBuffer ) /
|
||||
mBytesPerFrame );
|
||||
|
||||
if( reset && mBufferLength == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we get a partial buffer, reset the file for the next read */
|
||||
if( mBufferLength < mBuffer.length && mLoop )
|
||||
{
|
||||
close();
|
||||
open();
|
||||
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( mBufferLength > 0 )
|
||||
{
|
||||
mBufferWrapper = ByteBuffer.wrap( mBuffer ).order(
|
||||
ByteOrder.LITTLE_ENDIAN ).asShortBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
mBufferWrapper = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean next( boolean broadcast ) throws IOException
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
if( mBufferPointer >= mBufferLength )
|
||||
{
|
||||
readBuffer();
|
||||
}
|
||||
|
||||
if( mBufferLength != 0 &&
|
||||
mBufferWrapper != null &&
|
||||
mBufferWrapper.hasRemaining() )
|
||||
{
|
||||
short sample = mBufferWrapper.get();
|
||||
|
||||
mBufferPointer++;
|
||||
incrementCurrentLocation( 1, false );
|
||||
|
||||
if( broadcast && mListener != null )
|
||||
{
|
||||
/* Convert the short into a float value */
|
||||
mListener.receive( (float)sample );
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public boolean next() throws IOException
|
||||
{
|
||||
return next( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next (count) samples from the wave file and broadcasts them
|
||||
* to the registered listeners.
|
||||
* @param count - number of samples to broadcast
|
||||
* @return - true if successful
|
||||
* @throws IOException for any IO issues
|
||||
*/
|
||||
public boolean next( int count ) throws IOException
|
||||
{
|
||||
for( int x = 0; x < count; x++ )
|
||||
{
|
||||
next();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpTo( long index ) throws IOException
|
||||
{
|
||||
if( index < mCurrentPosition )
|
||||
{
|
||||
close();
|
||||
open();
|
||||
}
|
||||
|
||||
while( mCurrentPosition < index )
|
||||
{
|
||||
next( false );
|
||||
}
|
||||
|
||||
incrementCurrentLocation( 0, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new listener to receive samples as they are read from the wave file
|
||||
*/
|
||||
public void setListener( Listener<Float> listener )
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void removeListener( Listener<Float> listener )
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
76
src/source/wave/WaveSource.java
Normal file
76
src/source/wave/WaveSource.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* 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.wave;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import source.Source;
|
||||
|
||||
public abstract class WaveSource extends Source
|
||||
{
|
||||
protected File mFile;
|
||||
protected long mCurrentPosition = 0;
|
||||
protected PositionListener mListener;
|
||||
|
||||
public WaveSource( File file, SampleType sampleType )
|
||||
{
|
||||
super( sampleType.toString() + " Wave Source", sampleType );
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
public File getFile()
|
||||
{
|
||||
return mFile;
|
||||
}
|
||||
|
||||
public long getCurrentPosition()
|
||||
{
|
||||
return mCurrentPosition;
|
||||
}
|
||||
|
||||
public void incrementCurrentLocation( long value, boolean reset )
|
||||
{
|
||||
mCurrentPosition += value;
|
||||
|
||||
if( mListener != null )
|
||||
{
|
||||
mListener.positionUpdated( mCurrentPosition, reset );
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener( PositionListener listener )
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public abstract void open() throws IOException;
|
||||
|
||||
public abstract void close() throws IOException;
|
||||
|
||||
public abstract boolean next() throws IOException;
|
||||
|
||||
public abstract boolean next( int count ) throws IOException;
|
||||
|
||||
public abstract void jumpTo( long index ) throws IOException;
|
||||
|
||||
public interface PositionListener
|
||||
{
|
||||
public void positionUpdated( long position, boolean reset );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user