mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Merges from master branch.
This commit is contained in:
@@ -6,8 +6,9 @@ import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
|
||||
public abstract class ComplexSource extends Source implements Provider<ComplexBuffer>
|
||||
{
|
||||
public ComplexSource()
|
||||
{
|
||||
super( SampleType.COMPLEX );
|
||||
}
|
||||
@Override
|
||||
public SampleType getSampleType()
|
||||
{
|
||||
return SampleType.COMPLEX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for broadcasting changes to frequency, bandwidth, sample rate,
|
||||
* and actual sample rate values 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 ISourceEventListener
|
||||
{
|
||||
Listener<SourceEvent> getSourceEventListener();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source;
|
||||
|
||||
public interface ISourceEventProcessor
|
||||
{
|
||||
void process(SourceEvent event) throws SourceException;
|
||||
}
|
||||
@@ -16,15 +16,15 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.frequency;
|
||||
package io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
/**
|
||||
* Provider of Frequency Change Events
|
||||
* Provider of Source Change Events
|
||||
*/
|
||||
public interface IFrequencyChangeProvider
|
||||
public interface ISourceEventProvider
|
||||
{
|
||||
void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener );
|
||||
void removeFrequencyChangeListener();
|
||||
void setSourceEventListener(Listener<SourceEvent> listener );
|
||||
void removeSourceEventListener();
|
||||
}
|
||||
@@ -54,4 +54,11 @@ public class InvalidFrequencyException extends SourceException
|
||||
{
|
||||
return mValidFrequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
return super.getMessage() + " Invalid Frequency: " + getInvalidFrequency() +
|
||||
" - current valid frequency:" + getValidFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ import io.github.dsheirer.sample.real.RealBuffer;
|
||||
|
||||
public abstract class RealSource extends Source implements Provider<RealBuffer>
|
||||
{
|
||||
public RealSource()
|
||||
{
|
||||
super( SampleType.REAL );
|
||||
}
|
||||
@Override
|
||||
public SampleType getSampleType()
|
||||
{
|
||||
return SampleType.REAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,42 +17,53 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.channel.heartbeat.IHeartbeatProvider;
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.real.IOverflowListener;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeListener;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProvider;
|
||||
import io.github.dsheirer.source.heartbeat.HeartbeatManager;
|
||||
import io.github.dsheirer.source.heartbeat.IHeartbeatProvider;
|
||||
|
||||
/**
|
||||
* Abstract class to define the minimum functionality of a sample data provider.
|
||||
*/
|
||||
public abstract class Source extends Module implements IFrequencyChangeListener, IFrequencyChangeProvider,
|
||||
IHeartbeatProvider
|
||||
public abstract class Source extends Module implements ISourceEventListener, ISourceEventProvider, IHeartbeatProvider
|
||||
{
|
||||
protected SampleType mSampleType;
|
||||
private HeartbeatManager mHeartbeatManager = new HeartbeatManager();
|
||||
|
||||
/**
|
||||
* Heartbeat manager for this source
|
||||
*/
|
||||
public HeartbeatManager getHeartbeatManager()
|
||||
{
|
||||
return mHeartbeatManager;
|
||||
}
|
||||
|
||||
|
||||
protected IOverflowListener mOverflowListener;
|
||||
|
||||
public Source( SampleType sampleType )
|
||||
{
|
||||
mSampleType = sampleType;
|
||||
}
|
||||
|
||||
public abstract int getSampleRate() throws SourceException;
|
||||
|
||||
public abstract long getFrequency() throws SourceException;
|
||||
|
||||
/**
|
||||
* Indicates the type of samples provided by this source: real or complex
|
||||
*/
|
||||
public abstract SampleType getSampleType();
|
||||
|
||||
/**
|
||||
* Sample rate provided by this source
|
||||
*
|
||||
* @throws SourceException if there is an issue determining the sample rate for this source
|
||||
*/
|
||||
public abstract double getSampleRate();
|
||||
|
||||
/**
|
||||
* Center frequency for this source in Hertz
|
||||
*
|
||||
* @throws SourceException if there is an issue in determining the center frequency for this source
|
||||
*/
|
||||
public abstract long getFrequency();
|
||||
|
||||
/**
|
||||
* Process any cleanup actions to prepare for garbage collection of this source
|
||||
*/
|
||||
public abstract void dispose();
|
||||
|
||||
public SampleType getSampleType()
|
||||
{
|
||||
return mSampleType;
|
||||
}
|
||||
|
||||
public void setSampleType( SampleType sampleType )
|
||||
{
|
||||
mSampleType = sampleType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive overflow state changes. Use null argument to clear the listener
|
||||
@@ -65,9 +76,9 @@ public abstract class Source extends Module implements IFrequencyChangeListener,
|
||||
/**
|
||||
* Broadcasts an overflow state
|
||||
*
|
||||
* @param overflow true if overlow, false if normal
|
||||
* @param overflow true if overflow, false if normal
|
||||
*/
|
||||
protected void broadcastOverflowState(boolean overflow)
|
||||
public void broadcastOverflowState(boolean overflow)
|
||||
{
|
||||
if(mOverflowListener != null)
|
||||
{
|
||||
|
||||
202
src/main/java/io/github/dsheirer/source/SourceEvent.java
Normal file
202
src/main/java/io/github/dsheirer/source/SourceEvent.java
Normal file
@@ -0,0 +1,202 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source;
|
||||
|
||||
public class SourceEvent
|
||||
{
|
||||
public enum Event
|
||||
{
|
||||
NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_CHANNEL_SAMPLE_RATE_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_POLYPHASE_CHANNEL_COUNT_CHANGE,
|
||||
NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
|
||||
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
REQUEST_FREQUENCY_CHANGE,
|
||||
REQUEST_SOURCE_DISPOSE,
|
||||
REQUEST_START_SAMPLE_STREAM,
|
||||
REQUEST_STOP_SAMPLE_STREAM;
|
||||
}
|
||||
|
||||
private Event mEvent;
|
||||
private Number mValue;
|
||||
private Source mSource;
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
private SourceEvent(Event event, Number value)
|
||||
{
|
||||
mEvent = event;
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
private SourceEvent(Event event, Source source)
|
||||
{
|
||||
mEvent = event;
|
||||
mSource = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event description.
|
||||
*/
|
||||
public Event getEvent()
|
||||
{
|
||||
return mEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value associated with the event.
|
||||
*/
|
||||
public Number getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public boolean hasValue()
|
||||
{
|
||||
return mValue != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Source associated with the event
|
||||
*/
|
||||
public Source getSource()
|
||||
{
|
||||
return mSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this event contains an optional source
|
||||
*/
|
||||
public boolean hasSource()
|
||||
{
|
||||
return mSource != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new frequency change event
|
||||
*
|
||||
* @param frequency in hertz
|
||||
*/
|
||||
public static SourceEvent frequencyChange(long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new frequency correction change event
|
||||
*
|
||||
* @param frequencyCorrection in hertz
|
||||
*/
|
||||
public static SourceEvent frequencyCorrectionChange(long frequencyCorrection)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CORRECTION_CHANGE, frequencyCorrection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel frequency correction change event
|
||||
*
|
||||
* @param frequencyCorrection in hertz
|
||||
*/
|
||||
public static SourceEvent channelFrequencyCorrectionChange(long frequencyCorrection)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE, frequencyCorrection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new sample rate change event
|
||||
*
|
||||
* @param sampleRate in hertz
|
||||
*/
|
||||
public static SourceEvent sampleRateChange(double sampleRate)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE, sampleRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel sample rate change event
|
||||
*
|
||||
* @param sampleRate in hertz
|
||||
*/
|
||||
public static SourceEvent channelSampleRateChange(double sampleRate)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_CHANNEL_SAMPLE_RATE_CHANGE, sampleRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel count change event
|
||||
*
|
||||
* @param channelCount
|
||||
*/
|
||||
public static SourceEvent channelCountChange(int channelCount)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_POLYPHASE_CHANNEL_COUNT_CHANGE, channelCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new frequency change request event
|
||||
*
|
||||
* @param frequency requested
|
||||
*/
|
||||
public static SourceEvent frequencyRequest(long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_FREQUENCY_CHANGE, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel frequency correction change request event
|
||||
*
|
||||
* @param frequency requested
|
||||
*/
|
||||
public static SourceEvent channelFrequencyCorrectionRequest(long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new start sample stream request event
|
||||
*/
|
||||
public static SourceEvent startSampleStream(Source source)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_START_SAMPLE_STREAM, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new stop sample stream request event
|
||||
*/
|
||||
public static SourceEvent stopSampleStream(Source source)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_STOP_SAMPLE_STREAM, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a request to dispose of the source. This is normally used for TunerChannelSource to notify the
|
||||
* parent source manager that the channel is no longer needed
|
||||
*/
|
||||
public static SourceEvent sourceDisposeRequest(Source source)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_SOURCE_DISPOSE, source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SourceEventListenerToProcessorAdapter implements Listener<SourceEvent>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(SourceEventListenerToProcessorAdapter.class);
|
||||
|
||||
private ISourceEventProcessor mSourceEventProcessor;
|
||||
|
||||
/**
|
||||
* Adapter to implement ISourceEventListener/Listener<SourceEvent> and adapt to a source event processor
|
||||
*/
|
||||
public SourceEventListenerToProcessorAdapter(ISourceEventProcessor sourceEventProcessor)
|
||||
{
|
||||
mSourceEventProcessor = sourceEventProcessor;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mSourceEventProcessor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
if(mSourceEventProcessor != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mSourceEventProcessor.process(sourceEvent);
|
||||
}
|
||||
catch(SourceException e)
|
||||
{
|
||||
mLog.error("Error while transferring source event to source event processor [" +
|
||||
mSourceEventProcessor.getClass() + "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +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/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.config;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import io.github.dsheirer.source.SourceType;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel.Type;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
|
||||
public class SourceConfigRecording extends SourceConfiguration
|
||||
{
|
||||
@@ -59,11 +56,11 @@ public class SourceConfigRecording extends SourceConfiguration
|
||||
{
|
||||
return getRecordingAlias();
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
/* Create a tuner channel with a default bandwidth of 15 kHz */
|
||||
return new TunerChannel( Type.LOCKED, mFrequency, 15000 );
|
||||
}
|
||||
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
/* Create a tuner channel with a default bandwidth of 12.5 kHz */
|
||||
return new TunerChannel(mFrequency, 12500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,15 +21,14 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import io.github.dsheirer.source.SourceType;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel.Type;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
@JsonSubTypes.Type(value = SourceConfigTuner.class, name = "sourceConfigTuner")
|
||||
public class SourceConfigTuner extends SourceConfiguration
|
||||
{
|
||||
private static DecimalFormat sFORMAT = new DecimalFormat("0.00000");
|
||||
private static DecimalFormat FREQUENCY_FORMAT = new DecimalFormat("0.00000");
|
||||
|
||||
private long mFrequency = 0;
|
||||
private int mBandwidth = 12500;
|
||||
@@ -62,12 +61,12 @@ public class SourceConfigTuner extends SourceConfiguration
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return sFORMAT.format((double)mFrequency / 1000000.0d) + " MHz";
|
||||
return FREQUENCY_FORMAT.format((double)mFrequency / 1000000.0d) + " MHz";
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return new TunerChannel(Type.LOCKED, mFrequency, mBandwidth);
|
||||
return new TunerChannel(mFrequency, mBandwidth);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.heartbeat;
|
||||
|
||||
public class Heartbeat
|
||||
{
|
||||
/**
|
||||
* Periodic pulse that is broadcast to subscribing modules within the demodulating chain so that
|
||||
* monitoring of state and other attributes can occur on the primary demodulation and decoding
|
||||
* thread.
|
||||
*/
|
||||
public Heartbeat()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.heartbeat;
|
||||
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
public class HeartbeatManager
|
||||
{
|
||||
private static final Heartbeat HEARTBEAT = new Heartbeat();
|
||||
private Broadcaster<Heartbeat> mHeartbeatBroadcaster = new Broadcaster<>();
|
||||
|
||||
/**
|
||||
* Broadcasts heartbeat as commanded and handles listener registration details.
|
||||
*/
|
||||
public HeartbeatManager()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a heartbeat to all registered listeners
|
||||
*/
|
||||
public void broadcast()
|
||||
{
|
||||
mHeartbeatBroadcaster.broadcast(HEARTBEAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the listener to receive heartbeats
|
||||
*/
|
||||
public void addHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
mHeartbeatBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving heartbeats
|
||||
* @param listener
|
||||
*/
|
||||
public void removeHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
mHeartbeatBroadcaster.removeListener(listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.heartbeat;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
public interface IHeartbeatListener
|
||||
{
|
||||
public Listener<Heartbeat> getHeartbeatListener();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.heartbeat;
|
||||
|
||||
public interface IHeartbeatProvider
|
||||
{
|
||||
public HeartbeatManager getHeartbeatManager();
|
||||
}
|
||||
@@ -17,14 +17,11 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.mixer;
|
||||
|
||||
import io.github.dsheirer.channel.heartbeat.Heartbeat;
|
||||
import io.github.dsheirer.dsp.gain.AutomaticGainControl;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
import io.github.dsheirer.source.RealSource;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -34,7 +31,6 @@ import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class RealMixerSource extends RealSource
|
||||
@@ -49,9 +45,6 @@ public class RealMixerSource extends RealSource
|
||||
private AudioFormat mAudioFormat;
|
||||
private int mBytesPerFrame = 0;
|
||||
private ISampleAdapter mSampleAdapter;
|
||||
private AutomaticGainControl mAGC = new AutomaticGainControl();
|
||||
private Listener<Heartbeat> mHeartbeatListener;
|
||||
private static final Heartbeat HEARTBEAT = new Heartbeat();
|
||||
|
||||
private CopyOnWriteArrayList<Listener<RealBuffer>> mSampleListeners = new CopyOnWriteArrayList<Listener<RealBuffer>>();
|
||||
|
||||
@@ -76,44 +69,24 @@ public class RealMixerSource extends RealSource
|
||||
mSampleAdapter = sampleAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive heartbeats from this source.
|
||||
*
|
||||
* @param listener to receive heartbeats
|
||||
*/
|
||||
@Override
|
||||
public void setHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
mHeartbeatListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the currently registered heartbeat listener
|
||||
*/
|
||||
@Override
|
||||
public void removeHeartbeatListener()
|
||||
{
|
||||
mHeartbeatListener = null;
|
||||
}
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
@@ -121,7 +94,7 @@ public class RealMixerSource extends RealSource
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ScheduledExecutorService executor)
|
||||
public void start()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -176,11 +149,11 @@ public class RealMixerSource extends RealSource
|
||||
}
|
||||
}
|
||||
|
||||
public int getSampleRate()
|
||||
public double getSampleRate()
|
||||
{
|
||||
if(mTargetDataLine != null)
|
||||
{
|
||||
return (int)mTargetDataLine.getFormat().getSampleRate();
|
||||
return mTargetDataLine.getFormat().getSampleRate();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -191,7 +164,7 @@ public class RealMixerSource extends RealSource
|
||||
/**
|
||||
* Returns the frequency of this source. Default is 0.
|
||||
*/
|
||||
public long getFrequency() throws SourceException
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
@@ -220,11 +193,7 @@ public class RealMixerSource extends RealSource
|
||||
{
|
||||
if(mRunning.compareAndSet(false, true))
|
||||
{
|
||||
//Send a heartbeat every time we run
|
||||
if(mHeartbeatListener != null)
|
||||
{
|
||||
mHeartbeatListener.receive(HEARTBEAT);
|
||||
}
|
||||
getHeartbeatManager().broadcast();
|
||||
|
||||
if(mTargetDataLine == null)
|
||||
{
|
||||
|
||||
@@ -1,26 +1,37 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.recording;
|
||||
|
||||
import io.github.dsheirer.settings.SettingsManager;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.ITunerChannelProvider;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.List;
|
||||
|
||||
public class Recording implements Comparable<Recording>,
|
||||
IFrequencyChangeProcessor,
|
||||
ITunerChannelProvider
|
||||
public class Recording implements Comparable<Recording>, ISourceEventProcessor, ITunerChannelProvider
|
||||
{
|
||||
private RecordingConfiguration mConfiguration;
|
||||
|
||||
private ArrayList<TunerChannelSource> mTunerChannels =
|
||||
new ArrayList<TunerChannelSource>();
|
||||
private List<TunerChannelSource> mTunerChannels = new ArrayList<TunerChannelSource>();
|
||||
|
||||
@SuppressWarnings( "unused" )
|
||||
private long mCenterFrequency;
|
||||
@@ -65,8 +76,7 @@ public class Recording implements Comparable<Recording>,
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel( TunerChannel channel )
|
||||
throws RejectedExecutionException, SourceException
|
||||
public TunerChannelSource getChannel( TunerChannel channel )
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
@@ -89,9 +99,9 @@ public class Recording implements Comparable<Recording>,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event ) throws SourceException
|
||||
public void process(SourceEvent event ) throws SourceException
|
||||
{
|
||||
if( event.getEvent() == Event.NOTIFICATION_FREQUENCY_CHANGE )
|
||||
if( event.getEvent() == SourceEvent.Event.NOTIFICATION_FREQUENCY_CHANGE )
|
||||
{
|
||||
long frequency = event.getValue().longValue();
|
||||
|
||||
@@ -103,7 +113,7 @@ public class Recording implements Comparable<Recording>,
|
||||
|
||||
for( TunerChannelSource channel: mTunerChannels )
|
||||
{
|
||||
channel.frequencyChanged( event );
|
||||
channel.process( event );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.config.SourceConfigRecording;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -33,8 +33,7 @@ import java.util.List;
|
||||
|
||||
public class RecordingSourceManager
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( RecordingSourceManager.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger( RecordingSourceManager.class );
|
||||
|
||||
private ArrayList<Recording> mRecordings = new ArrayList<Recording>();
|
||||
|
||||
@@ -50,12 +49,12 @@ public class RecordingSourceManager
|
||||
* Iterates current recordings to get a tuner channel source for the frequency
|
||||
* specified in the channel config's source config object
|
||||
*/
|
||||
public Source getSource(SourceConfiguration config, int bandwidth )
|
||||
public Source getSource( SourceConfiguration config, int bandwidth )
|
||||
throws SourceException
|
||||
{
|
||||
TunerChannelSource retVal = null;
|
||||
|
||||
if( config instanceof SourceConfigRecording)
|
||||
if( config instanceof SourceConfigRecording )
|
||||
{
|
||||
SourceConfigRecording configRecording = (SourceConfigRecording)config;
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
@@ -25,18 +27,14 @@ public interface ITunerChannelProvider
|
||||
{
|
||||
/**
|
||||
* Returns a tuner frequency channel source, tuned to the correct frequency
|
||||
*
|
||||
* @param frequency - desired frequency
|
||||
*
|
||||
*
|
||||
* @return - source for 48k sample rate
|
||||
*/
|
||||
public abstract TunerChannelSource getChannel( TunerChannel channel )
|
||||
public abstract TunerChannelSource getChannel(TunerChannel channel )
|
||||
throws RejectedExecutionException, SourceException;
|
||||
|
||||
/**
|
||||
* Releases the tuned channel resources
|
||||
*
|
||||
* @param channel - previously obtained tuner channel
|
||||
*/
|
||||
public abstract void releaseChannel( TunerChannelSource source );
|
||||
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.ComplexSampleListListener;
|
||||
import io.github.dsheirer.source.mixer.ComplexMixer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class MixerTuner extends Tuner implements Listener<ComplexBuffer>
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( MixerTuner.class );
|
||||
|
||||
protected MixerTunerType mMixerTunerType;
|
||||
protected ComplexMixer mComplexMixer;
|
||||
protected ArrayList<ComplexSampleListListener> mListeners =
|
||||
new ArrayList<ComplexSampleListListener>();
|
||||
|
||||
/**
|
||||
* Wrapper class to add basic Tuner functionality to the ComplexMixer.
|
||||
* Subclasses should couple this functionality with a tuner controller class
|
||||
* to support tuning.
|
||||
*/
|
||||
public MixerTuner( String name,
|
||||
TunerController tunerController,
|
||||
MixerTunerType mixerTunerType,
|
||||
TargetDataLine targetDataLine,
|
||||
ISampleAdapter sampleAdapter )
|
||||
{
|
||||
super( name, tunerController );
|
||||
|
||||
mMixerTunerType = mixerTunerType;
|
||||
|
||||
mComplexMixer = new ComplexMixer( targetDataLine,
|
||||
mMixerTunerType.getAudioFormat(),
|
||||
name,
|
||||
sampleAdapter,
|
||||
(Listener<ComplexBuffer>)this );
|
||||
}
|
||||
|
||||
public MixerTuner( String name,
|
||||
TunerController tunerController,
|
||||
MixerTunerDataLine mixerTuner,
|
||||
ISampleAdapter sampleAdapter )
|
||||
{
|
||||
this( name,
|
||||
tunerController,
|
||||
mixerTuner.getMixerTunerType(),
|
||||
mixerTuner.getTargetDataLine(),
|
||||
sampleAdapter );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mComplexMixer.stop();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public MixerTunerType getMixerTunerType()
|
||||
{
|
||||
return mMixerTunerType;
|
||||
}
|
||||
|
||||
public TargetDataLine getTargetDataLine()
|
||||
{
|
||||
return mComplexMixer.getTargetDataLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the received complex buffers from the mComplexMixer to all
|
||||
* listeners registered on the parent Tuner class
|
||||
*/
|
||||
@Override
|
||||
public void receive( ComplexBuffer buffer )
|
||||
{
|
||||
super.broadcast( buffer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the parent Tuner class listener management method to allow
|
||||
* starting the buffer processing thread
|
||||
*/
|
||||
@Override
|
||||
public void addListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
super.addListener( listener );
|
||||
|
||||
/* We can call start multiple times -- it ignores additional requests */
|
||||
mComplexMixer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the parent Tuner class listener management method to allow
|
||||
* stopping the buffer processing thread when there are no more listeners
|
||||
*/
|
||||
@Override
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
super.removeListener( listener );
|
||||
|
||||
if( mSampleListeners.isEmpty() )
|
||||
{
|
||||
mComplexMixer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,196 +17,145 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.manager.AbstractSourceManager;
|
||||
import io.github.dsheirer.source.tuner.manager.TunerSourceManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
/**
|
||||
* Tuner - provides tuner channel sources, representing a channel frequency
|
||||
*/
|
||||
public abstract class Tuner implements ITunerChannelProvider
|
||||
public abstract class Tuner
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( Tuner.class );
|
||||
|
||||
private String mName;
|
||||
private TunerController mTunerController;
|
||||
/**
|
||||
* Sample Listeners - these will typically be the DFT processor for spectral
|
||||
* display, or it will be one or more tuner channel sources
|
||||
*/
|
||||
protected List<Listener<ComplexBuffer>> mSampleListeners =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
protected List<Listener<TunerEvent>> mTunerChangeListeners =
|
||||
new ArrayList<>();
|
||||
|
||||
public Tuner( String name, TunerController tunerController )
|
||||
{
|
||||
mName = name;
|
||||
mTunerController = tunerController;
|
||||
private final static Logger mLog = LoggerFactory.getLogger(Tuner.class);
|
||||
|
||||
//Rebroadcast frequency and sample rate change events as tuner events
|
||||
mTunerController.addListener( new IFrequencyChangeProcessor()
|
||||
{
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event )
|
||||
{
|
||||
switch( event.getEvent() )
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
broadcast( new TunerEvent( Tuner.this,
|
||||
TunerEvent.Event.FREQUENCY ));
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
broadcast( new TunerEvent( Tuner.this,
|
||||
TunerEvent.Event.SAMPLE_RATE ));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public TunerController getTunerController()
|
||||
{
|
||||
return mTunerController;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mSampleListeners.clear();
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
protected Broadcaster<TunerEvent> mTunerEventBroadcaster = new Broadcaster<>();
|
||||
private TunerController mTunerController;
|
||||
private String mName;
|
||||
private AbstractSourceManager mTunerSourceManager;
|
||||
|
||||
/**
|
||||
* @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 size in bits
|
||||
*/
|
||||
public abstract double getSampleSize();
|
||||
|
||||
/**
|
||||
* 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( 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<ComplexBuffer> listener )
|
||||
/**
|
||||
* Abstract tuner class.
|
||||
* @param name of the tuner
|
||||
* @param tunerController for the tuner
|
||||
*/
|
||||
public Tuner(String name, TunerController tunerController)
|
||||
{
|
||||
mSampleListeners.add( listener );
|
||||
}
|
||||
mName = name;
|
||||
mTunerController = tunerController;
|
||||
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
mSampleListeners.remove( listener );
|
||||
mTunerSourceManager = new TunerSourceManager(mTunerController);
|
||||
|
||||
//Rebroadcast frequency and sample rate change events as tuner events
|
||||
mTunerController.addListener(new ISourceEventProcessor()
|
||||
{
|
||||
@Override
|
||||
public void process(SourceEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
broadcast(new TunerEvent(Tuner.this, Event.FREQUENCY));
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
broadcast(new TunerEvent(Tuner.this, Event.SAMPLE_RATE));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the samples to all registered listeners
|
||||
* Source Manager. Provides access to registering for complex buffer samples and source event notifications.
|
||||
*/
|
||||
public void broadcast( ComplexBuffer sampleBuffer )
|
||||
public AbstractSourceManager getSourceManager()
|
||||
{
|
||||
for( Listener<ComplexBuffer> listener: mSampleListeners )
|
||||
{
|
||||
listener.receive( sampleBuffer );
|
||||
}
|
||||
return mTunerSourceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener
|
||||
*/
|
||||
public void addTunerChangeListener( Listener<TunerEvent> listener )
|
||||
public TunerController getTunerController()
|
||||
{
|
||||
mTunerChangeListeners.add( listener );
|
||||
return mTunerController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeTunerChangeListener( Listener<TunerEvent> listener )
|
||||
public String toString()
|
||||
{
|
||||
mTunerChangeListeners.remove( listener );
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 size in bits
|
||||
*/
|
||||
public abstract double getSampleSize();
|
||||
|
||||
/**
|
||||
* Registers the listener
|
||||
*/
|
||||
public void addTunerChangeListener(Listener<TunerEvent> listener)
|
||||
{
|
||||
mTunerEventBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeTunerChangeListener(Listener<TunerEvent> listener)
|
||||
{
|
||||
mTunerEventBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the tuner change event
|
||||
*/
|
||||
public void broadcast( TunerEvent event )
|
||||
public void broadcast(TunerEvent tunerEvent)
|
||||
{
|
||||
for( Listener<TunerEvent> listener: mTunerChangeListeners )
|
||||
{
|
||||
listener.receive( event );
|
||||
}
|
||||
mTunerEventBroadcaster.broadcast(tunerEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
public class TunerChannel implements Comparable<TunerChannel>
|
||||
{
|
||||
private Type mType;
|
||||
private long mFrequency;
|
||||
private int mBandwidth;
|
||||
|
||||
public TunerChannel( Type type, long frequency, int bandwidth )
|
||||
{
|
||||
mType = type;
|
||||
mFrequency = frequency;
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public Type getType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
public void setType( Type type )
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency( long frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mBandwidth;
|
||||
}
|
||||
|
||||
public void setBandwidth( int bandwidth )
|
||||
{
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public long getMinFrequency()
|
||||
{
|
||||
return mFrequency - ( mBandwidth / 2 );
|
||||
}
|
||||
|
||||
public long getMaxFrequency()
|
||||
{
|
||||
return mFrequency + ( mBandwidth / 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if any part of this tuner channel overlaps the specified range
|
||||
*/
|
||||
public boolean overlaps( long minimum, long maximum )
|
||||
{
|
||||
long channelMin = getMinFrequency();
|
||||
long channelMax = getMaxFrequency();
|
||||
|
||||
return ( ( minimum <= channelMin && channelMin <= maximum ) ||
|
||||
( minimum <= channelMax && channelMax <= maximum ) ||
|
||||
( minimum <= channelMin && channelMax <= maximum ) ||
|
||||
( channelMin <= minimum && maximum <= channelMax ) );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "Channel: " );
|
||||
sb.append( getMinFrequency() );
|
||||
sb.append( "-" );
|
||||
sb.append( getMaxFrequency() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo( TunerChannel otherLock )
|
||||
{
|
||||
if( this.equals( otherLock ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else 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
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public interface TunerChannelProvider
|
||||
{
|
||||
/**
|
||||
* Returns a tuner frequency channel source, tuned to the correct frequency
|
||||
*
|
||||
* @param frequency - desired frequency
|
||||
*
|
||||
* @return - source for 48k sample rate
|
||||
*/
|
||||
public abstract TunerChannelSource getChannel( TunerChannel channel )
|
||||
throws RejectedExecutionException, SourceException;
|
||||
|
||||
/**
|
||||
* Releases the tuned channel resources
|
||||
*
|
||||
* @param channel - previously obtained tuner channel
|
||||
*/
|
||||
public abstract void releaseChannel( TunerChannelSource source );
|
||||
|
||||
|
||||
}
|
||||
@@ -1,572 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.channel.heartbeat.Heartbeat;
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window.WindowType;
|
||||
import io.github.dsheirer.dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import io.github.dsheirer.dsp.mixer.Oscillator;
|
||||
import io.github.dsheirer.sample.Buffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
||||
import io.github.dsheirer.sample.complex.Complex;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.real.IOverflowListener;
|
||||
import io.github.dsheirer.source.ComplexSource;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeListener;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class TunerChannelSource extends ComplexSource implements IFrequencyChangeProcessor, Listener<ComplexBuffer>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerChannelSource.class);
|
||||
|
||||
//Maximum number of filled buffers for the blocking queue
|
||||
private static final int BUFFER_MAX_CAPACITY = 300;
|
||||
|
||||
//Threshold for resetting buffer overflow condition
|
||||
private static final int BUFFER_OVERFLOW_RESET_THRESHOLD = 100;
|
||||
|
||||
private static int CHANNEL_RATE = 48000;
|
||||
private static int CHANNEL_PASS_FREQUENCY = 12000;
|
||||
private static final Heartbeat HEARTBEAT = new Heartbeat();
|
||||
|
||||
private OverflowableTransferQueue<ComplexBuffer> mBuffer;
|
||||
|
||||
private Tuner mTuner;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Oscillator mMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private Listener<Heartbeat> mHeartbeatListener;
|
||||
private IFrequencyChangeProcessor mFrequencyChangeProcessor;
|
||||
private DownstreamProcessor mDownstreamFrequencyEventProcessor = new DownstreamProcessor();
|
||||
private ScheduledFuture<?> mTaskHandle;
|
||||
|
||||
private long mTunerFrequency = 0;
|
||||
private int mTunerSampleRate;
|
||||
private int mChannelFrequencyCorrection = 0;
|
||||
|
||||
private DecimationProcessor mDecimationProcessor = new DecimationProcessor();
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private boolean mExpended = false;
|
||||
|
||||
/**
|
||||
* Provides a Digital Drop Channel (DDC) to decimate the IQ output from a
|
||||
* tuner down to a 48 kHz IQ channel rate.
|
||||
*
|
||||
* Note: this class can only be used once (started and stopped) and a new
|
||||
* tuner channel source must be requested from the tuner once this object
|
||||
* has been stopped. This is because channels are managed dynamically and
|
||||
* center tuned frequency may have changed since this source was obtained
|
||||
* and thus the tuner might no longer be able to source this channel once it
|
||||
* has been stopped.
|
||||
*
|
||||
* @param tuner to obtain wideband IQ samples from
|
||||
* @param tunerChannel specifying the center frequency for the DDC
|
||||
* @throws RejectedExecutionException if the thread pool manager cannot
|
||||
* accept the decimation processing task
|
||||
* @throws SourceException if the tuner has an issue providing IQ samples
|
||||
*/
|
||||
public TunerChannelSource(Tuner tuner, TunerChannel tunerChannel) throws RejectedExecutionException, SourceException
|
||||
{
|
||||
mTuner = tuner;
|
||||
mTunerChannel = tunerChannel;
|
||||
mTuner.getTunerController().addListener((IFrequencyChangeProcessor) this);
|
||||
mTunerFrequency = mTuner.getTunerController().getFrequency();
|
||||
|
||||
mBuffer = new OverflowableTransferQueue<>(BUFFER_MAX_CAPACITY, BUFFER_OVERFLOW_RESET_THRESHOLD);
|
||||
|
||||
/* Setup the frequency translator to the current source frequency */
|
||||
long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency();
|
||||
|
||||
mMixer = new Oscillator(frequencyOffset, mTuner.getTunerController().getSampleRate());
|
||||
|
||||
/* Fire a sample rate change event to setup the decimation chain */
|
||||
frequencyChanged(new FrequencyChangeEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
mTuner.getTunerController().getSampleRate()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default source overflow listener management to delegate responsibility to the overflow buffer
|
||||
*/
|
||||
@Override
|
||||
public void setOverflowListener(IOverflowListener listener)
|
||||
{
|
||||
mBuffer.setOverflowListener(listener);
|
||||
}
|
||||
|
||||
public void start(ScheduledExecutorService executor)
|
||||
{
|
||||
if(mExpended)
|
||||
{
|
||||
throw new IllegalStateException("Attempt to re-start an expended tuner channel source. TunerChannelSource" +
|
||||
" objects can only be used once. ");
|
||||
}
|
||||
|
||||
if(mRunning.compareAndSet(false, true))
|
||||
{
|
||||
//Broadcast current frequency and sample rate settings so all downstream components are aware
|
||||
mDownstreamFrequencyEventProcessor.broadcastCurrentFrequency();
|
||||
mDownstreamFrequencyEventProcessor.broadcastCurrentSampleRate();
|
||||
|
||||
//Schedule the decimation task to run every 9 ms (111 iterations/second), an odd periodicity relative
|
||||
//to the inbound periodicity of 20 ms, to attempt to avoid thread queue contention
|
||||
mTaskHandle = executor.scheduleAtFixedRate(mDecimationProcessor, 0, 9, TimeUnit.MILLISECONDS);
|
||||
|
||||
/* Finally, register to receive samples from the tuner */
|
||||
mTuner.addListener((Listener<ComplexBuffer>) this);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Attempt to start() an already running tuner channel source was ignored");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(mRunning.compareAndSet(true, false))
|
||||
{
|
||||
mTuner.releaseChannel(this);
|
||||
mDecimationProcessor.shutdown();
|
||||
|
||||
if(mTaskHandle != null)
|
||||
{
|
||||
mTaskHandle.cancel(true);
|
||||
mTaskHandle = null;
|
||||
}
|
||||
|
||||
mBuffer.clear();
|
||||
|
||||
mExpended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Attempt to stop() an already stopped tuner channel source was ignored");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
if(!mRunning.get())
|
||||
{
|
||||
/* Tell the tuner to release/unregister our resources */
|
||||
mTuner.getTunerController().removeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the frequency correction value and broadcasts the change to the registered downstream listener.
|
||||
* @param correction current frequency correction value.
|
||||
*/
|
||||
private void setFrequencyCorrection(int correction)
|
||||
{
|
||||
mChannelFrequencyCorrection = correction;
|
||||
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
mDownstreamFrequencyEventProcessor.broadcast(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE, mChannelFrequencyCorrection));
|
||||
}
|
||||
|
||||
public Tuner getTuner()
|
||||
{
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(ComplexBuffer buffer)
|
||||
{
|
||||
if(mRunning.get())
|
||||
{
|
||||
mBuffer.offer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFrequencyChangeListener(IFrequencyChangeProcessor processor)
|
||||
{
|
||||
mFrequencyChangeProcessor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
/* Save a pointer to the listener so that if we have to change the
|
||||
* decimation filter, we can re-add the listener */
|
||||
mListener = listener;
|
||||
|
||||
mDecimationFilter.setListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mDecimationFilter.removeListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for frequency change events received from the tuner and channel
|
||||
* frequency correction events received from the channel consumer/listener
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event) throws SourceException
|
||||
{
|
||||
// Echo the event to the registered event listener
|
||||
if(mFrequencyChangeProcessor != null)
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(event);
|
||||
}
|
||||
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
mTunerFrequency = event.getValue().longValue();
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
//Reset frequency correction so that downstream components can recalculate the value
|
||||
setFrequencyCorrection(0);
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
int sampleRate = event.getValue().intValue();
|
||||
setSampleRate(sampleRate);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sample rate to the requested value and notifies any downstream components of the change
|
||||
* @param sampleRate to set
|
||||
*/
|
||||
private void setSampleRate(int sampleRate)
|
||||
{
|
||||
if(mTunerSampleRate != sampleRate)
|
||||
{
|
||||
mMixer.setSampleRate(sampleRate);
|
||||
|
||||
/* Get new decimation filter */
|
||||
mDecimationFilter = FilterFactory.getDecimationFilter(sampleRate, CHANNEL_RATE, 1,
|
||||
CHANNEL_PASS_FREQUENCY, 60, WindowType.HAMMING);
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilter.setListener(mListener);
|
||||
|
||||
mTunerSampleRate = sampleRate;
|
||||
|
||||
mDownstreamFrequencyEventProcessor.broadcastCurrentSampleRate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the local mixer frequency offset from the tuned frequency,
|
||||
* channel's requested frequency, and channel frequency correction.
|
||||
*/
|
||||
private void updateMixerFrequencyOffset()
|
||||
{
|
||||
long offset = mTunerFrequency - mTunerChannel.getFrequency() - mChannelFrequencyCorrection;
|
||||
mMixer.setFrequency(offset);
|
||||
}
|
||||
|
||||
public int getSampleRate() throws SourceException
|
||||
{
|
||||
return CHANNEL_RATE;
|
||||
}
|
||||
|
||||
public long getFrequency() throws SourceException
|
||||
{
|
||||
return mTunerChannel.getFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements IFrequencyChangeProvider to enable this source to broadcast frequency change events to downstream
|
||||
* listeners.
|
||||
*
|
||||
* @param listener to receive downstream events
|
||||
*/
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
{
|
||||
mDownstreamFrequencyEventProcessor.setFrequencyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements IFrequencyChangeProvider to remove the frequency change listener from receiving down-stream frequency
|
||||
* change events.
|
||||
*/
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
{
|
||||
mDownstreamFrequencyEventProcessor.removeFrequencyChangeListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements IFrequencyChangeListener to receive frequency change events containing requests from downstream
|
||||
* listeners to change frequency values.
|
||||
* @return listener
|
||||
*/
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
{
|
||||
return mDownstreamFrequencyEventProcessor.getFrequencyChangeListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive heartbeats from this source.
|
||||
* @param listener to receive heartbeats
|
||||
*/
|
||||
@Override
|
||||
public void setHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
mHeartbeatListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the currently registered heartbeat listener
|
||||
*/
|
||||
@Override
|
||||
public void removeHeartbeatListener()
|
||||
{
|
||||
mHeartbeatListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Managers frequency change requests and notifications from/to any downstream component. Downstream
|
||||
* components are those that receive samples from this tuner channel source. These downstream components will be
|
||||
* notified of any frequency or sample rate change events and will also be able to request frequency correction
|
||||
* updates.
|
||||
*/
|
||||
public class DownstreamProcessor implements IFrequencyChangeListener, IFrequencyChangeProvider,
|
||||
Listener<FrequencyChangeEvent>
|
||||
{
|
||||
//Listener to receive downstream events
|
||||
private Listener<FrequencyChangeEvent> mListener;
|
||||
|
||||
/**
|
||||
* Broadcasts the frequency change event to the downstream frequency change listener
|
||||
* @param event to broadcast
|
||||
*/
|
||||
public void broadcast(FrequencyChangeEvent event)
|
||||
{
|
||||
if(mListener != null)
|
||||
{
|
||||
mListener.receive(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the current frequency of this tuner channel source to the downstream listener
|
||||
*/
|
||||
public void broadcastCurrentFrequency()
|
||||
{
|
||||
try
|
||||
{
|
||||
long frequency = getFrequency();
|
||||
broadcast(new FrequencyChangeEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, frequency));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Error obtaining frequency from tuner to broadcast downstream");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the current decimated sample rate of this tuner channel source
|
||||
*/
|
||||
public void broadcastCurrentSampleRate()
|
||||
{
|
||||
try
|
||||
{
|
||||
//Note: downstream sample rate is currently a fixed value -- it will change in the future
|
||||
broadcast(new FrequencyChangeEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE, getSampleRate()));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Error obtaining sample rate from tuner to broadcast downstream");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the downstream listener to receive frequency change events from this tuner channel source
|
||||
* @param listener to receive events
|
||||
*/
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the downstream listener from receiving frequency change events.
|
||||
*/
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for receiving frequency change events from downstream components
|
||||
*/
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes frequency change events from downstream components.
|
||||
* @param event to process
|
||||
*/
|
||||
@Override
|
||||
public void receive(FrequencyChangeEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
//Frequency correction requests are the only change requests supported from downstream components
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
setFrequencyCorrection(event.getValue().intValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decimates an inbound buffer of I/Q samples from the source down to the
|
||||
* standard 48000 channel sample rate
|
||||
*/
|
||||
public class DecimationProcessor implements Runnable
|
||||
{
|
||||
private boolean mProcessing = true;
|
||||
private List<ComplexBuffer> mSampleBuffers = new ArrayList<ComplexBuffer>();
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
mProcessing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
/* General exception handler so that any errors won't kill the
|
||||
* decimation thread and cause the input buffers to fill up and
|
||||
* run the program out of memory */
|
||||
try
|
||||
{
|
||||
if(mProcessing)
|
||||
{
|
||||
//Send a heartbeat every time this runs to allow downstream components to perform periodic
|
||||
//state monitoring functions on this thread
|
||||
if(mHeartbeatListener != null)
|
||||
{
|
||||
mHeartbeatListener.receive(HEARTBEAT);
|
||||
}
|
||||
|
||||
mBuffer.drainTo(mSampleBuffers, 20);
|
||||
|
||||
for(Buffer buffer : mSampleBuffers)
|
||||
{
|
||||
/* Check to see if we've been shutdown */
|
||||
if(!mProcessing)
|
||||
{
|
||||
mBuffer.clear();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
float[] samples = buffer.getSamples();
|
||||
|
||||
/* We make a copy of the buffer so that we don't affect
|
||||
* anyone else that is using the same buffer, like other
|
||||
* channels or the spectral display */
|
||||
float[] translated = new float[samples.length];
|
||||
|
||||
/* Perform frequency translation */
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
mMixer.rotate();
|
||||
|
||||
translated[x] = Complex.multiplyInphase(
|
||||
samples[x], samples[x + 1], mMixer.inphase(), mMixer.quadrature());
|
||||
|
||||
translated[x + 1] = Complex.multiplyQuadrature(
|
||||
samples[x], samples[x + 1], mMixer.inphase(), mMixer.quadrature());
|
||||
}
|
||||
|
||||
if(mProcessing)
|
||||
{
|
||||
final ComplexPrimeCICDecimate filter = mDecimationFilter;
|
||||
filter.receive(new ComplexBuffer(translated));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
/* Only log the stack trace if we're still processing */
|
||||
if(mProcessing)
|
||||
{
|
||||
mLog.error("Error encountered during decimation process", e);
|
||||
}
|
||||
}
|
||||
catch(Throwable throwable)
|
||||
{
|
||||
mLog.error("Code error encountered during decimation process - channel thread will probably die", throwable);
|
||||
}
|
||||
|
||||
/* Check to see if we've been shutdown */
|
||||
if(!mProcessing)
|
||||
{
|
||||
mBuffer.clear();
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,8 @@ public enum TunerClass
|
||||
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" ),
|
||||
ZAAPA_ZTMINDVBZP( TunerType.FITIPOWER_FC0012, "1B80", "D398", "Zaapa", "ZT-MINDVBZP" ),
|
||||
TEST_TUNER(TunerType.TEST, "0", "0", "ABC Tuners Inc.", "Model XYZ"),
|
||||
UNKNOWN( TunerType.UNKNOWN, "0", "0", "Unknown Manufacturer", "Unknown Device" );
|
||||
|
||||
private TunerType mTunerType;
|
||||
|
||||
@@ -17,13 +17,21 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.IComplexBufferProvider;
|
||||
import io.github.dsheirer.source.ISourceEventListener;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceEventListenerToProcessorAdapter;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.channel.CICTunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyController;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyController.Tunable;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -31,15 +39,18 @@ import java.util.SortedSet;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public abstract class TunerController implements Tunable, IFrequencyChangeProcessor
|
||||
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
|
||||
IComplexBufferProvider, Listener<ComplexBuffer>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
|
||||
protected Broadcaster<ComplexBuffer> mSampleBroadcaster = new Broadcaster<>();
|
||||
|
||||
/* List of currently tuned channels being served to demod channels */
|
||||
private SortedSet<TunerChannel> mTunedChannels = new ConcurrentSkipListSet<>();
|
||||
protected FrequencyController mFrequencyController;
|
||||
private int mMiddleUnusable;
|
||||
private double mUsableBandwidthPercentage;
|
||||
private Listener<SourceEvent> mSourceEventListener;
|
||||
|
||||
/**
|
||||
* Abstract tuner controller class. The tuner controller manages frequency bandwidth and currently tuned channels
|
||||
@@ -57,6 +68,16 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
mFrequencyController = new FrequencyController(this, minimumFrequency, maximumFrequency, 0.0d);
|
||||
mMiddleUnusable = middleUnusable;
|
||||
mUsableBandwidthPercentage = usableBandwidth;
|
||||
mSourceEventListener = new SourceEventListenerToProcessorAdapter(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the ISourceEventListener interface to receive requests from sample consumers
|
||||
*/
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
return mSourceEventListener;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,11 +89,28 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
* Responds to requests to set the frequency
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event) throws SourceException
|
||||
public void process(SourceEvent sourceEvent ) throws SourceException
|
||||
{
|
||||
if(event.getEvent() == Event.REQUEST_FREQUENCY_CHANGE)
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
setFrequency(event.getValue().longValue());
|
||||
case REQUEST_FREQUENCY_CHANGE:
|
||||
setFrequency( sourceEvent.getValue().longValue() );
|
||||
break;
|
||||
case REQUEST_START_SAMPLE_STREAM:
|
||||
if(sourceEvent.getSource() instanceof Listener)
|
||||
{
|
||||
addComplexBufferListener((Listener<ComplexBuffer>)sourceEvent.getSource());
|
||||
}
|
||||
break;
|
||||
case REQUEST_STOP_SAMPLE_STREAM:
|
||||
if(sourceEvent.getSource() instanceof Listener)
|
||||
{
|
||||
removeComplexBufferListener((Listener<ComplexBuffer>)sourceEvent.getSource());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mLog.error("Ignoring unrecognized source event: " + sourceEvent.getEvent().name() + " from [" +
|
||||
sourceEvent.getSource().getClass() + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +140,15 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
return mFrequencyController.getFrequency();
|
||||
}
|
||||
|
||||
public int getSampleRate()
|
||||
@Override
|
||||
public boolean canTune(long frequency)
|
||||
{
|
||||
return mFrequencyController.getBandwidth();
|
||||
return mFrequencyController.canTune(frequency);
|
||||
}
|
||||
|
||||
public double getSampleRate()
|
||||
{
|
||||
return mFrequencyController.getSampleRate();
|
||||
}
|
||||
|
||||
public double getFrequencyCorrection()
|
||||
@@ -210,7 +254,7 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
updateLOFrequency();
|
||||
}
|
||||
|
||||
source = new TunerChannelSource(tuner, channel);
|
||||
source = new CICTunerChannelSource(tuner, channel);
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
@@ -351,11 +395,13 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener to be notified any time that the tuner changes frequency or bandwidth/sample rate.
|
||||
* 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.
|
||||
* Note: this is normally used by the Tuner. Any additional listeners can
|
||||
* be registered on the tuner.
|
||||
*/
|
||||
public void addListener(IFrequencyChangeProcessor processor)
|
||||
public void addListener( ISourceEventProcessor processor )
|
||||
{
|
||||
mFrequencyController.addListener(processor);
|
||||
}
|
||||
@@ -363,8 +409,52 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
/**
|
||||
* Removes the frequency change listener
|
||||
*/
|
||||
public void removeListener(IFrequencyChangeProcessor processor)
|
||||
public void removeListener( ISourceEventProcessor processor )
|
||||
{
|
||||
mFrequencyController.removeFrequencyChangeProcessor(processor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the listener to receive complex buffer samples
|
||||
*/
|
||||
@Override
|
||||
public void addComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mSampleBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving complex buffer samples
|
||||
*/
|
||||
@Override
|
||||
public void removeComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mSampleBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if there are any complex buffer listeners registered on this controller
|
||||
*/
|
||||
@Override
|
||||
public boolean hasComplexBufferListeners()
|
||||
{
|
||||
return mSampleBroadcaster.hasListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the buffer to any registered listeners
|
||||
*/
|
||||
protected void broadcast(ComplexBuffer complexBuffer)
|
||||
{
|
||||
mSampleBroadcaster.broadcast(complexBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Listener<T> interface to receive and distribute complex buffers from subclass implementations
|
||||
*/
|
||||
@Override
|
||||
public void receive(ComplexBuffer complexBuffer)
|
||||
{
|
||||
broadcast(complexBuffer);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner;
|
||||
@@ -29,11 +27,18 @@ import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.RowFilter;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
import java.awt.*;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
@@ -54,13 +59,13 @@ public class TunerEditor extends Editor<Tuner>
|
||||
private JScrollPane mEditorScroller;
|
||||
private Editor<TunerConfiguration> mEditor = new EmptyEditor<>( "a tuner" );
|
||||
private JideSplitPane mEditorSplitPane = new JideSplitPane();
|
||||
|
||||
|
||||
public TunerEditor( TunerConfigurationModel tunerConfigurationModel )
|
||||
{
|
||||
mTunerConfigurationModel = tunerConfigurationModel;
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
public void init()
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill]" ) );
|
||||
@@ -69,7 +74,7 @@ public class TunerEditor extends Editor<Tuner>
|
||||
listPanel.setLayout( new MigLayout( "fill,wrap 3", "[grow,fill]", "[][][][grow,fill][]" ) );
|
||||
|
||||
listPanel.add( mSelectedTunerType, "span" );
|
||||
|
||||
|
||||
mFrequencyControl.setEnabled( false );
|
||||
listPanel.add( mFrequencyControl, "span" );
|
||||
|
||||
@@ -85,7 +90,7 @@ public class TunerEditor extends Editor<Tuner>
|
||||
if( !event.getValueIsAdjusting() )
|
||||
{
|
||||
int row = mTunerConfigurationTable.getSelectedRow();
|
||||
|
||||
|
||||
if( row >= 0 )
|
||||
{
|
||||
int modelRow = mTunerConfigurationTable.convertRowIndexToModel( row );
|
||||
@@ -100,8 +105,8 @@ public class TunerEditor extends Editor<Tuner>
|
||||
} );
|
||||
|
||||
JScrollPane tableScroller = new JScrollPane( mTunerConfigurationTable );
|
||||
tableScroller.setHorizontalScrollBarPolicy(
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
|
||||
tableScroller.setHorizontalScrollBarPolicy(
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
|
||||
listPanel.add( new JLabel( "Tuner Configurations" ), "span" );
|
||||
listPanel.add( tableScroller, "span" );
|
||||
|
||||
@@ -113,14 +118,14 @@ public class TunerEditor extends Editor<Tuner>
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
Tuner tuner = getItem();
|
||||
|
||||
|
||||
String name = mTunerConfigurationModel
|
||||
.getDistinctName( tuner.getTunerType(), tuner.getUniqueID() );
|
||||
|
||||
|
||||
TunerConfiguration config = TunerConfigurationFactory
|
||||
.getTunerConfiguration( tuner.getTunerType(),
|
||||
tuner.getUniqueID(), name );
|
||||
|
||||
.getTunerConfiguration( tuner.getTunerType(),
|
||||
tuner.getUniqueID(), name );
|
||||
|
||||
mTunerConfigurationModel.addTunerConfiguration( config );
|
||||
}
|
||||
} );
|
||||
@@ -133,21 +138,21 @@ public class TunerEditor extends Editor<Tuner>
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
int choice = JOptionPane.showConfirmDialog( TunerEditor.this,
|
||||
"Do you want to delete this tuner configuration?",
|
||||
"Delete Tuner Configuration?", JOptionPane.YES_NO_OPTION );
|
||||
|
||||
int choice = JOptionPane.showConfirmDialog( TunerEditor.this,
|
||||
"Do you want to delete this tuner configuration?",
|
||||
"Delete Tuner Configuration?", JOptionPane.YES_NO_OPTION );
|
||||
|
||||
if( choice == JOptionPane.YES_OPTION )
|
||||
{
|
||||
TunerConfiguration selected = getSelectedTunerConfiguration();
|
||||
|
||||
|
||||
mTunerConfigurationModel.removeTunerConfiguration( selected );
|
||||
mTunerConfigurationTable.setRowSelectionInterval( 0, 0 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
listPanel.add( mDeleteConfigurationButton );
|
||||
|
||||
|
||||
mAssignConfigurationButton.setEnabled( false );
|
||||
mAssignConfigurationButton.setToolTipText( "Assigns to the currently selected tuner configuration to the selected tuner" );
|
||||
mAssignConfigurationButton.addActionListener( new ActionListener()
|
||||
@@ -156,18 +161,18 @@ public class TunerEditor extends Editor<Tuner>
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
TunerConfiguration selected = getSelectedTunerConfiguration();
|
||||
|
||||
|
||||
mTunerConfigurationModel.assignTunerConfiguration( selected );
|
||||
setTunerConfiguration( getSelectedTunerConfiguration() );
|
||||
}
|
||||
} );
|
||||
listPanel.add( mAssignConfigurationButton );
|
||||
|
||||
|
||||
//Set preferred size on both scrollers to same width, so they split the space
|
||||
listPanel.setPreferredSize( new Dimension( 100, 80 ) );
|
||||
JScrollPane listScroller = new JScrollPane( listPanel );
|
||||
listScroller.setPreferredSize( new Dimension( 100, 80 ) );
|
||||
|
||||
|
||||
mEditorScroller = new JScrollPane( mEditor );
|
||||
mEditorScroller.setPreferredSize( new Dimension( 100, 80 ) );
|
||||
|
||||
@@ -177,15 +182,15 @@ public class TunerEditor extends Editor<Tuner>
|
||||
|
||||
add( mEditorSplitPane );
|
||||
}
|
||||
|
||||
|
||||
private TunerConfiguration getSelectedTunerConfiguration()
|
||||
{
|
||||
int tableRow = mTunerConfigurationTable.getSelectedRow();
|
||||
|
||||
|
||||
if( tableRow >= 0 )
|
||||
{
|
||||
int modelRow = mTunerConfigurationTable.convertRowIndexToModel( tableRow );
|
||||
|
||||
|
||||
if( modelRow >= 0 )
|
||||
{
|
||||
return mTunerConfigurationModel.getTunerConfiguration( modelRow );
|
||||
@@ -194,7 +199,7 @@ public class TunerEditor extends Editor<Tuner>
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
@@ -211,9 +216,9 @@ public class TunerEditor extends Editor<Tuner>
|
||||
previous.getTunerController().removeListener( mFrequencyControl );
|
||||
mFrequencyControl.removeListener( previous.getTunerController() );
|
||||
}
|
||||
|
||||
|
||||
super.setItem( tuner );
|
||||
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
mSelectedTunerType.setText( tuner.getName() );
|
||||
@@ -222,21 +227,21 @@ public class TunerEditor extends Editor<Tuner>
|
||||
mNewConfigurationButton.setEnabled( true );
|
||||
|
||||
//Change to an editor for this config's tuner type
|
||||
mEditor = TunerConfigurationFactory.getEditor( getItem(), mTunerConfigurationModel );
|
||||
|
||||
mRowSorter.setRowFilter( new ConfigurationRowFilter( tuner.getTunerType(),
|
||||
tuner.getUniqueID() ) );
|
||||
mEditor = TunerConfigurationFactory.getEditor( getItem(), mTunerConfigurationModel );
|
||||
|
||||
mRowSorter.setRowFilter( new ConfigurationRowFilter( tuner.getTunerType(),
|
||||
tuner.getUniqueID() ) );
|
||||
|
||||
TunerConfiguration assigned = mTunerConfigurationModel
|
||||
.getTunerConfiguration( tuner.getTunerType(), tuner.getUniqueID() );
|
||||
|
||||
int modelIndex = mTunerConfigurationModel.getRowIndex( assigned );
|
||||
|
||||
|
||||
if( modelIndex >= 0 )
|
||||
{
|
||||
int viewIndex = mTunerConfigurationTable
|
||||
.convertRowIndexToView( modelIndex );
|
||||
|
||||
.convertRowIndexToView( modelIndex );
|
||||
|
||||
if( viewIndex >= 0 )
|
||||
{
|
||||
mTunerConfigurationTable
|
||||
@@ -245,14 +250,14 @@ public class TunerEditor extends Editor<Tuner>
|
||||
}
|
||||
|
||||
//Link frequency control to the tuner
|
||||
mFrequencyControl.addListener( tuner.getTunerController() );
|
||||
|
||||
//Link tuner to frequency control
|
||||
tuner.getTunerController().addListener( mFrequencyControl );
|
||||
mFrequencyControl.addListener( tuner.getTunerController() );
|
||||
|
||||
//Set the displayed frequency without adjusting the tuner's frequency
|
||||
mFrequencyControl.setFrequency(
|
||||
tuner.getTunerController().getFrequency(), false );
|
||||
//Link tuner to frequency control
|
||||
tuner.getTunerController().addListener( mFrequencyControl );
|
||||
|
||||
//Set the displayed frequency without adjusting the tuner's frequency
|
||||
mFrequencyControl.setFrequency(
|
||||
tuner.getTunerController().getFrequency(), false );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,15 +268,15 @@ public class TunerEditor extends Editor<Tuner>
|
||||
mRowSorter.setRowFilter( null );
|
||||
mEditor = new EmptyEditor<TunerConfiguration>();
|
||||
}
|
||||
|
||||
//Swap out the editor
|
||||
|
||||
//Swap out the editor
|
||||
int split = mEditorSplitPane.getDividerLocation( 0 );
|
||||
mEditorSplitPane.remove( mEditorScroller );
|
||||
mEditorScroller = new JScrollPane( mEditor );
|
||||
mEditorSplitPane.add( mEditorScroller );
|
||||
mEditorSplitPane.setDividerLocation( 0, split );
|
||||
}
|
||||
|
||||
|
||||
private void setTunerConfiguration( TunerConfiguration config )
|
||||
{
|
||||
if( config != null )
|
||||
@@ -293,7 +298,7 @@ public class TunerEditor extends Editor<Tuner>
|
||||
{
|
||||
mAssignConfigurationButton.setEnabled( false );
|
||||
}
|
||||
|
||||
|
||||
if( mDeleteConfigurationButton.isEnabled() )
|
||||
{
|
||||
mDeleteConfigurationButton.setEnabled( false );
|
||||
@@ -306,39 +311,39 @@ public class TunerEditor extends Editor<Tuner>
|
||||
{
|
||||
mDeleteConfigurationButton.setEnabled( false );
|
||||
}
|
||||
|
||||
|
||||
if( mAssignConfigurationButton.isEnabled() )
|
||||
{
|
||||
mAssignConfigurationButton.setEnabled( false );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mEditor.setItem( config );
|
||||
}
|
||||
|
||||
|
||||
public class ConfigurationRowFilter extends RowFilter<TunerConfigurationModel,Integer>
|
||||
{
|
||||
private TunerType mTunerType;
|
||||
private String mUniqueID;
|
||||
|
||||
|
||||
public ConfigurationRowFilter( TunerType type, String uniqueID )
|
||||
{
|
||||
mTunerType = type;
|
||||
mUniqueID = uniqueID;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean include( javax.swing.RowFilter.Entry<? extends TunerConfigurationModel,
|
||||
? extends Integer> entry )
|
||||
public boolean include( javax.swing.RowFilter.Entry<? extends TunerConfigurationModel,
|
||||
? extends Integer> entry )
|
||||
{
|
||||
TunerConfiguration config = entry.getModel()
|
||||
.getTunerConfiguration( entry.getIdentifier() );
|
||||
.getTunerConfiguration( entry.getIdentifier() );
|
||||
|
||||
return config != null &&
|
||||
config.getTunerType() == mTunerType &&
|
||||
config.getUniqueID() != null &&
|
||||
config.getUniqueID().contentEquals( mUniqueID );
|
||||
return config != null &&
|
||||
config.getTunerType() == mTunerType &&
|
||||
config.getUniqueID() != null &&
|
||||
config.getUniqueID().contentEquals( mUniqueID );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -246,25 +246,21 @@ public class TunerManager
|
||||
+ "supported");
|
||||
}
|
||||
|
||||
private TunerInitStatus initFuncubeProTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
private TunerInitStatus initFuncubeProTuner(Device device, DeviceDescriptor descriptor)
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(
|
||||
TunerClass.FUNCUBE_DONGLE_PRO.getTunerType());
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(TunerClass.FUNCUBE_DONGLE_PRO.getTunerType());
|
||||
|
||||
if(dataline != null)
|
||||
{
|
||||
FCD1TunerController controller =
|
||||
new FCD1TunerController(device, descriptor);
|
||||
FCD1TunerController controller = new FCD1TunerController(dataline, device, descriptor);
|
||||
|
||||
try
|
||||
{
|
||||
controller.init();
|
||||
|
||||
FCDTuner tuner =
|
||||
new FCDTuner(dataline, controller);
|
||||
FCDTuner tuner = new FCDTuner(controller);
|
||||
|
||||
return new TunerInitStatus(tuner, "LOADED");
|
||||
}
|
||||
@@ -284,25 +280,21 @@ public class TunerManager
|
||||
+ "loaded - " + reason);
|
||||
}
|
||||
|
||||
private TunerInitStatus initFuncubeProPlusTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
private TunerInitStatus initFuncubeProPlusTuner(Device device, DeviceDescriptor descriptor)
|
||||
{
|
||||
String reason = "NOT LOADED";
|
||||
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(
|
||||
TunerClass.FUNCUBE_DONGLE_PRO_PLUS.getTunerType());
|
||||
MixerTunerDataLine dataline = getMixerTunerDataLine(TunerClass.FUNCUBE_DONGLE_PRO_PLUS.getTunerType());
|
||||
|
||||
if(dataline != null)
|
||||
{
|
||||
FCD2TunerController controller =
|
||||
new FCD2TunerController(device, descriptor);
|
||||
FCD2TunerController controller = new FCD2TunerController(dataline, device, descriptor);
|
||||
|
||||
try
|
||||
{
|
||||
controller.init();
|
||||
|
||||
FCDTuner tuner =
|
||||
new FCDTuner(dataline, controller);
|
||||
FCDTuner tuner = new FCDTuner(controller);
|
||||
|
||||
return new TunerInitStatus(tuner, "LOADED");
|
||||
}
|
||||
@@ -323,8 +315,7 @@ public class TunerManager
|
||||
+ "loaded - " + reason);
|
||||
}
|
||||
|
||||
private TunerInitStatus initHackRFTuner(Device device,
|
||||
DeviceDescriptor descriptor)
|
||||
private TunerInitStatus initHackRFTuner(Device device, DeviceDescriptor descriptor)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -5,6 +5,8 @@ import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||
import org.slf4j.Logger;
|
||||
@@ -15,282 +17,275 @@ import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public class TunerModel extends AbstractTableModel implements Listener<TunerEvent>
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final static Logger mLog = LoggerFactory.getLogger( TunerModel.class );
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int TUNER_TYPE = 0;
|
||||
public static final int TUNER_ID = 1;
|
||||
public static final int SAMPLE_RATE = 2;
|
||||
public static final int FREQUENCY = 3;
|
||||
public static final int CHANNEL_COUNT = 4;
|
||||
public static final int SPECTRAL_DISPLAY_MAIN = 5;
|
||||
public static final int SPECTRAL_DISPLAY_NEW = 6;
|
||||
|
||||
private static final String MHZ = " MHz";
|
||||
private static final String[] COLUMNS =
|
||||
{ "Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Spectral", "Display" };
|
||||
|
||||
private List<Tuner> mTuners = new ArrayList<>();
|
||||
private List<Listener<TunerEvent>> mTunerEventListeners = new ArrayList<>();
|
||||
private DecimalFormat mFrequencyFormat = new DecimalFormat( "0.00000" );
|
||||
private DecimalFormat mSampleRateFormat = new DecimalFormat( "0.000" );
|
||||
|
||||
private TunerConfigurationModel mTunerConfigurationModel;
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerModel.class);
|
||||
|
||||
public TunerModel( TunerConfigurationModel tunerConfigurationModel )
|
||||
{
|
||||
mTunerConfigurationModel = tunerConfigurationModel;
|
||||
}
|
||||
|
||||
public TunerConfigurationModel getTunerConfigurationModel()
|
||||
{
|
||||
return mTunerConfigurationModel;
|
||||
}
|
||||
public static final int TUNER_TYPE = 0;
|
||||
public static final int TUNER_ID = 1;
|
||||
public static final int SAMPLE_RATE = 2;
|
||||
public static final int FREQUENCY = 3;
|
||||
public static final int CHANNEL_COUNT = 4;
|
||||
public static final int SPECTRAL_DISPLAY_MAIN = 5;
|
||||
public static final int SPECTRAL_DISPLAY_NEW = 6;
|
||||
|
||||
/**
|
||||
* List of Tuners currently in the model
|
||||
*/
|
||||
public List<Tuner> getTuners()
|
||||
{
|
||||
return mTuners;
|
||||
}
|
||||
|
||||
public Tuner getTuner( int index )
|
||||
{
|
||||
if( index < mTuners.size() )
|
||||
{
|
||||
return mTuners.get( index );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static final String MHZ = " MHz";
|
||||
private static final String[] COLUMNS =
|
||||
{"Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Spectral", "Display"};
|
||||
|
||||
public void addTuners( List<Tuner> Tuners )
|
||||
{
|
||||
for( Tuner tuner: Tuners )
|
||||
{
|
||||
addTuner( tuner );
|
||||
}
|
||||
}
|
||||
private List<Tuner> mTuners = new ArrayList<>();
|
||||
private List<Listener<TunerEvent>> mTunerEventListeners = new ArrayList<>();
|
||||
private DecimalFormat mFrequencyFormat = new DecimalFormat("0.00000");
|
||||
private DecimalFormat mSampleRateFormat = new DecimalFormat("0.000");
|
||||
|
||||
/**
|
||||
* Adds the Tuner to this model
|
||||
*/
|
||||
public void addTuner( Tuner tuner )
|
||||
{
|
||||
if( !mTuners.contains( tuner ) )
|
||||
{
|
||||
//Get the tuner configuration and apply it to the tuner - this
|
||||
//call should always produce a tuner configuration
|
||||
TunerConfiguration config = mTunerConfigurationModel
|
||||
.getTunerConfiguration( tuner.getTunerType(), tuner.getUniqueID() );
|
||||
|
||||
try
|
||||
{
|
||||
tuner.getTunerController().apply( config );
|
||||
|
||||
mTuners.add( tuner );
|
||||
|
||||
int index = mTuners.indexOf( tuner );
|
||||
|
||||
fireTableRowsInserted( index, index );
|
||||
|
||||
tuner.addTunerChangeListener( this );
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
mLog.error( "Couldn't apply tuner configuration to tuner - ["
|
||||
+ tuner.getTunerType().name() + "] with id ["
|
||||
+ tuner.getUniqueID() + "] - tuner will not be included" );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
private TunerConfigurationModel mTunerConfigurationModel;
|
||||
|
||||
/**
|
||||
* Removes the Tuner from this model
|
||||
*/
|
||||
public void removeTuner( Tuner tuner )
|
||||
{
|
||||
if( mTuners.contains( tuner ) )
|
||||
{
|
||||
tuner.removeTunerChangeListener( this );
|
||||
|
||||
int index = mTuners.indexOf( tuner );
|
||||
|
||||
mTuners.remove( tuner );
|
||||
|
||||
fireTableRowsDeleted( index, index );
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener( Listener<TunerEvent> listener )
|
||||
{
|
||||
mTunerEventListeners.add( listener );
|
||||
}
|
||||
public TunerModel(TunerConfigurationModel tunerConfigurationModel)
|
||||
{
|
||||
mTunerConfigurationModel = tunerConfigurationModel;
|
||||
}
|
||||
|
||||
public void removeListener( Listener<TunerEvent> listener )
|
||||
{
|
||||
mTunerEventListeners.remove( listener );
|
||||
}
|
||||
public TunerConfigurationModel getTunerConfigurationModel()
|
||||
{
|
||||
return mTunerConfigurationModel;
|
||||
}
|
||||
|
||||
public void broadcast( TunerEvent event )
|
||||
{
|
||||
for( Listener<TunerEvent> listener: mTunerEventListeners )
|
||||
{
|
||||
listener.receive( event );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* List of Tuners currently in the model
|
||||
*/
|
||||
public List<Tuner> getTuners()
|
||||
{
|
||||
return mTuners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests to display the first tuner in this model. Invoke this method
|
||||
* after all listeners have registered and tuners have been added to this
|
||||
* model, in order to inform the primary display to use the first tuner.
|
||||
*/
|
||||
public void requestFirstTunerDisplay()
|
||||
{
|
||||
if( mTuners.size() > 0 )
|
||||
{
|
||||
broadcast( new TunerEvent( mTuners.get( 0 ),
|
||||
Event.REQUEST_MAIN_SPECTRAL_DISPLAY ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( TunerEvent event )
|
||||
{
|
||||
if( event.getTuner() != null )
|
||||
{
|
||||
int index = mTuners.indexOf( event.getTuner() );
|
||||
|
||||
if( index >= 0 )
|
||||
{
|
||||
switch( event.getEvent() )
|
||||
{
|
||||
case CHANNEL_COUNT:
|
||||
fireTableCellUpdated( index, CHANNEL_COUNT );
|
||||
break;
|
||||
case FREQUENCY:
|
||||
fireTableCellUpdated( index, FREQUENCY );
|
||||
mTunerConfigurationModel.tunerFrequencyChanged( event.getTuner() );
|
||||
break;
|
||||
case SAMPLE_RATE:
|
||||
fireTableCellUpdated( index, SAMPLE_RATE );
|
||||
break;
|
||||
case REQUEST_MAIN_SPECTRAL_DISPLAY:
|
||||
fireTableCellUpdated( index, SPECTRAL_DISPLAY_MAIN );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
broadcast( event );
|
||||
}
|
||||
public Tuner getTuner(int index)
|
||||
{
|
||||
if(index < mTuners.size())
|
||||
{
|
||||
return mTuners.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount()
|
||||
{
|
||||
return mTuners.size();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount()
|
||||
{
|
||||
return COLUMNS.length;
|
||||
}
|
||||
public void addTuners(List<Tuner> Tuners)
|
||||
{
|
||||
for(Tuner tuner : Tuners)
|
||||
{
|
||||
addTuner(tuner);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt( int rowIndex, int columnIndex )
|
||||
{
|
||||
if( rowIndex < mTuners.size() )
|
||||
{
|
||||
Tuner tuner = mTuners.get( rowIndex );
|
||||
/**
|
||||
* Adds the Tuner to this model
|
||||
*/
|
||||
public void addTuner(Tuner tuner)
|
||||
{
|
||||
if(!mTuners.contains(tuner))
|
||||
{
|
||||
//Get the tuner configuration and apply it to the tuner - this
|
||||
//call should always produce a tuner configuration
|
||||
TunerConfiguration config = mTunerConfigurationModel
|
||||
.getTunerConfiguration(tuner.getTunerType(), tuner.getUniqueID());
|
||||
|
||||
switch( columnIndex )
|
||||
{
|
||||
case TUNER_TYPE:
|
||||
return tuner.getTunerType().getLabel();
|
||||
case TUNER_ID:
|
||||
return tuner.getUniqueID();
|
||||
case SAMPLE_RATE:
|
||||
int sampleRate = tuner.getTunerController().getSampleRate();
|
||||
try
|
||||
{
|
||||
tuner.getTunerController().apply(config);
|
||||
|
||||
return mSampleRateFormat.format( sampleRate / 1E6D ) + MHZ;
|
||||
case FREQUENCY:
|
||||
try
|
||||
{
|
||||
long frequency = tuner.getTunerController().getFrequency();
|
||||
|
||||
return mFrequencyFormat.format( frequency / 1E6D ) + MHZ;
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
case CHANNEL_COUNT:
|
||||
return tuner.getTunerController().getChannelCount();
|
||||
case SPECTRAL_DISPLAY_MAIN:
|
||||
return "Main";
|
||||
case SPECTRAL_DISPLAY_NEW:
|
||||
return "New";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
mTuners.add(tuner);
|
||||
|
||||
int index = mTuners.indexOf(tuner);
|
||||
|
||||
fireTableRowsInserted(index, index);
|
||||
|
||||
tuner.addTunerChangeListener(this);
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Couldn't apply tuner configuration to tuner - ["
|
||||
+ tuner.getTunerType().name() + "] with id ["
|
||||
+ tuner.getUniqueID() + "] - tuner will not be included");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Tuner from this model
|
||||
*/
|
||||
public void removeTuner(Tuner tuner)
|
||||
{
|
||||
if(mTuners.contains(tuner))
|
||||
{
|
||||
tuner.removeTunerChangeListener(this);
|
||||
|
||||
int index = mTuners.indexOf(tuner);
|
||||
|
||||
mTuners.remove(tuner);
|
||||
|
||||
fireTableRowsDeleted(index, index);
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(Listener<TunerEvent> listener)
|
||||
{
|
||||
mTunerEventListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(Listener<TunerEvent> listener)
|
||||
{
|
||||
mTunerEventListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void broadcast(TunerEvent event)
|
||||
{
|
||||
for(Listener<TunerEvent> listener : mTunerEventListeners)
|
||||
{
|
||||
listener.receive(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests to display the first tuner in this model. Invoke this method
|
||||
* after all listeners have registered and tuners have been added to this
|
||||
* model, in order to inform the primary display to use the first tuner.
|
||||
*/
|
||||
public void requestFirstTunerDisplay()
|
||||
{
|
||||
if(mTuners.size() > 0)
|
||||
{
|
||||
broadcast(new TunerEvent(mTuners.get(0),
|
||||
Event.REQUEST_MAIN_SPECTRAL_DISPLAY));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(TunerEvent event)
|
||||
{
|
||||
if(event.getTuner() != null)
|
||||
{
|
||||
int index = mTuners.indexOf(event.getTuner());
|
||||
|
||||
if(index >= 0)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case CHANNEL_COUNT:
|
||||
fireTableCellUpdated(index, CHANNEL_COUNT);
|
||||
break;
|
||||
case FREQUENCY:
|
||||
fireTableCellUpdated(index, FREQUENCY);
|
||||
mTunerConfigurationModel.tunerFrequencyChanged(event.getTuner());
|
||||
break;
|
||||
case SAMPLE_RATE:
|
||||
fireTableCellUpdated(index, SAMPLE_RATE);
|
||||
break;
|
||||
case REQUEST_MAIN_SPECTRAL_DISPLAY:
|
||||
fireTableCellUpdated(index, SPECTRAL_DISPLAY_MAIN);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
broadcast(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount()
|
||||
{
|
||||
return mTuners.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount()
|
||||
{
|
||||
return COLUMNS.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex)
|
||||
{
|
||||
if(rowIndex < mTuners.size())
|
||||
{
|
||||
Tuner tuner = mTuners.get(rowIndex);
|
||||
|
||||
switch(columnIndex)
|
||||
{
|
||||
case TUNER_TYPE:
|
||||
return tuner.getTunerType().getLabel();
|
||||
case TUNER_ID:
|
||||
return tuner.getUniqueID();
|
||||
case SAMPLE_RATE:
|
||||
double sampleRate = tuner.getTunerController().getSampleRate();
|
||||
|
||||
return mSampleRateFormat.format(sampleRate / 1E6D) + MHZ;
|
||||
case FREQUENCY:
|
||||
try
|
||||
{
|
||||
long frequency = tuner.getTunerController().getFrequency();
|
||||
|
||||
return mFrequencyFormat.format(frequency / 1E6D) + MHZ;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
case CHANNEL_COUNT:
|
||||
return tuner.getTunerController().getChannelCount();
|
||||
case SPECTRAL_DISPLAY_MAIN:
|
||||
return "Main";
|
||||
case SPECTRAL_DISPLAY_NEW:
|
||||
return "New";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex)
|
||||
{
|
||||
return COLUMNS[columnIndex];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName( int columnIndex )
|
||||
{
|
||||
return COLUMNS[ columnIndex ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates current tuners to get a tuner channel source for the frequency
|
||||
* specified in the channel config's source config object.
|
||||
*
|
||||
*
|
||||
* Returns null if no tuner can source the channel
|
||||
*/
|
||||
public Source getSource(SourceConfigTuner config, int bandwidth )
|
||||
public Source getSource(SourceConfigTuner config, int bandwidth)
|
||||
{
|
||||
TunerChannelSource retVal = null;
|
||||
|
||||
TunerChannel tunerChannel = config.getTunerChannel();
|
||||
|
||||
tunerChannel.setBandwidth( bandwidth );
|
||||
|
||||
Iterator<Tuner> it = mTuners.iterator();
|
||||
|
||||
Tuner tuner;
|
||||
|
||||
while( it.hasNext() && retVal == null )
|
||||
{
|
||||
tuner = it.next();
|
||||
|
||||
try
|
||||
TunerChannelSource retVal = null;
|
||||
|
||||
TunerChannel tunerChannel = config.getTunerChannel();
|
||||
|
||||
tunerChannel.setBandwidth(bandwidth);
|
||||
|
||||
Iterator<Tuner> it = mTuners.iterator();
|
||||
|
||||
Tuner tuner;
|
||||
|
||||
while(it.hasNext() && retVal == null)
|
||||
{
|
||||
tuner = it.next();
|
||||
|
||||
try
|
||||
{
|
||||
retVal = tuner.getChannel( tunerChannel );
|
||||
retVal = tuner.getSourceManager().getSource(tunerChannel);
|
||||
}
|
||||
catch ( RejectedExecutionException ree )
|
||||
{
|
||||
mLog.error( "couldn't provide tuner channel source", ree );
|
||||
}
|
||||
catch ( SourceException e )
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error( "error obtaining channel from tuner [" +
|
||||
tuner.getName() + "]", e );
|
||||
mLog.error("Error obtaining channel source from tuner [" + tuner.getName() + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,16 +20,16 @@ package io.github.dsheirer.source.tuner;
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.gui.control.JFrequencyControl;
|
||||
import io.github.dsheirer.gui.editor.Editor;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class TunerSourceEditor extends Editor<Channel>
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JFrequencyControl mFrequencyControl;
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JFrequencyControl mFrequencyControl;
|
||||
|
||||
public TunerSourceEditor()
|
||||
{
|
||||
@@ -41,10 +41,10 @@ public class TunerSourceEditor extends Editor<Channel>
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[left]", "" ) );
|
||||
mFrequencyControl = new JFrequencyControl();
|
||||
mFrequencyControl.setEnabled( false );
|
||||
mFrequencyControl.addListener( new IFrequencyChangeProcessor()
|
||||
mFrequencyControl.addListener( new ISourceEventProcessor()
|
||||
{
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event )
|
||||
public void process(SourceEvent event )
|
||||
{
|
||||
setModified( true );
|
||||
}
|
||||
@@ -63,16 +63,16 @@ public class TunerSourceEditor extends Editor<Channel>
|
||||
|
||||
setModified( false );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setItem( Channel item )
|
||||
{
|
||||
super.setItem( item );
|
||||
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
SourceConfiguration config = getItem().getSourceConfiguration();
|
||||
|
||||
|
||||
mFrequencyControl.setEnabled( true );
|
||||
|
||||
if( config instanceof SourceConfigTuner )
|
||||
@@ -92,4 +92,4 @@ public class TunerSourceEditor extends Editor<Channel>
|
||||
setModified( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ public enum TunerType
|
||||
RAFAELMICRO_R820T( "R820T" ),
|
||||
RAFAELMICRO_R828D( "R828D" ),
|
||||
RTL2832_VARIOUS( "Generic" ),
|
||||
TEST("Test"),
|
||||
UNKNOWN( "Unknown" );
|
||||
|
||||
private String mLabel;
|
||||
|
||||
@@ -17,21 +17,13 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.airspy;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.airspy.AirspyTunerController.BoardID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public class AirspyTuner extends Tuner
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( AirspyTuner.class );
|
||||
@@ -40,15 +32,15 @@ public class AirspyTuner extends Tuner
|
||||
{
|
||||
super( "Airspy " + controller.getDeviceInfo().getSerialNumber(), controller );
|
||||
}
|
||||
|
||||
|
||||
public AirspyTunerController getController()
|
||||
{
|
||||
return (AirspyTunerController)getTunerController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
public String getUniqueID()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getController().getDeviceInfo().getSerialNumber();
|
||||
@@ -57,9 +49,9 @@ public class AirspyTuner extends Tuner
|
||||
{
|
||||
mLog.error( "error getting serial number", e );
|
||||
}
|
||||
|
||||
|
||||
return BoardID.AIRSPY.getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
@@ -78,50 +70,4 @@ public class AirspyTuner extends Tuner
|
||||
{
|
||||
return 13.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel( TunerChannel channel )
|
||||
throws RejectedExecutionException, SourceException
|
||||
{
|
||||
//TODO: this channel has a decimated sample rate of:
|
||||
// 10.0 MSps = 10,000,000 / 208 = 48076.923
|
||||
// 5.0 MSps = 5,000,000 / 104 = 48076.923
|
||||
// 2.5 MSps = 2,500,000 / 52 = 48076.923
|
||||
//Consider implementing a fractional resampler to get a correct 48 kHz
|
||||
//output sample rate
|
||||
|
||||
TunerChannelSource source = getController().getChannel( this, channel );
|
||||
|
||||
if( source != null )
|
||||
{
|
||||
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseChannel( TunerChannelSource source )
|
||||
{
|
||||
/* Unregister for receiving samples */
|
||||
removeListener( (Listener<ComplexBuffer>)source );
|
||||
|
||||
/* Tell the controller to release the channel and cleanup */
|
||||
if( source != null )
|
||||
{
|
||||
getController().releaseChannel( source );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
getController().addListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
getController().removeListener( listener );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
package io.github.dsheirer.source.tuner.airspy;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTransferProcessor;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTunerController;
|
||||
import org.apache.commons.io.EndianUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -62,7 +60,7 @@ import java.util.List;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
public class AirspyTunerController extends TunerController
|
||||
public class AirspyTunerController extends USBTunerController
|
||||
{
|
||||
public static final Gain LINEARITY_GAIN_DEFAULT = Gain.LINEARITY_14;
|
||||
public static final Gain SENSITIVITY_GAIN_DEFAULT = Gain.SENSITIVITY_10;
|
||||
@@ -183,6 +181,14 @@ public class AirspyTunerController extends TunerController
|
||||
USB_TRANSFER_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected USBTransferProcessor getUSBTransferProcessor()
|
||||
{
|
||||
return mUSBTransferProcessor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Claims the USB interface. If another application currently has
|
||||
* the interface claimed, the USB_FORCE_CLAIM_INTERFACE setting
|
||||
@@ -368,7 +374,7 @@ public class AirspyTunerController extends TunerController
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentSampleRate() throws SourceException
|
||||
public double getCurrentSampleRate()
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
@@ -456,7 +462,7 @@ public class AirspyTunerController extends TunerController
|
||||
throw new UsbException("Couldnt set sample packing enabled: " + enabled);
|
||||
}
|
||||
|
||||
/* If we didn't throw an exception above, then update the sample adapter
|
||||
/* If we didn't throw an exception above, then update the sample adapter
|
||||
* to process samples accordingly */
|
||||
mSampleAdapter.setSamplePacking(enabled);
|
||||
}
|
||||
@@ -671,7 +677,7 @@ public class AirspyTunerController extends TunerController
|
||||
mDeviceInfo = new AirspyDeviceInformation();
|
||||
}
|
||||
|
||||
/* Board ID */
|
||||
/* Board ID */
|
||||
try
|
||||
{
|
||||
int boardID = readByte(Command.BOARD_ID_READ, 0, 0, true);
|
||||
@@ -683,7 +689,7 @@ public class AirspyTunerController extends TunerController
|
||||
mLog.error("Error reading airspy board ID", e);
|
||||
}
|
||||
|
||||
/* Version String */
|
||||
/* Version String */
|
||||
try
|
||||
{
|
||||
//NOTE: libairspy is internally reading 127 bytes, however airspy_info
|
||||
@@ -696,8 +702,8 @@ public class AirspyTunerController extends TunerController
|
||||
{
|
||||
mLog.error("Error reading airspy version string", e);
|
||||
}
|
||||
|
||||
/* Part ID and Serial Number */
|
||||
|
||||
/* Part ID and Serial Number */
|
||||
try
|
||||
{
|
||||
//Read 6 x 32-bit integers = 24 bytes
|
||||
@@ -1183,34 +1189,4 @@ public class AirspyTunerController extends TunerController
|
||||
return mValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started.
|
||||
*/
|
||||
public void addListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
if(mUSBTransferProcessor != null)
|
||||
{
|
||||
mUSBTransferProcessor.addListener(listener);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.error("Couldn't add IQ buffer listener to Airspy tuner - processor is null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners.
|
||||
*/
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
if(mUSBTransferProcessor != null)
|
||||
{
|
||||
mUSBTransferProcessor.removeListener(listener);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.error("Couldn't remove IQ buffer listener from Airspy tuner - processor is null");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,19 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.LibUsbException;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.usb.UsbException;
|
||||
@@ -42,43 +54,43 @@ import java.util.List;
|
||||
|
||||
public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( AirspyTunerEditor.class );
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( AirspyTunerEditor.class );
|
||||
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
|
||||
private JComboBox<AirspySampleRate> mSampleRateCombo;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<AirspySampleRate> mSampleRateCombo;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
|
||||
private JComboBox<GainMode> mGainModeCombo;
|
||||
private JComboBox<GainMode> mGainModeCombo;
|
||||
|
||||
private JSlider mMasterGain;
|
||||
private JLabel mMasterGainValueLabel;
|
||||
private JSlider mMasterGain;
|
||||
private JLabel mMasterGainValueLabel;
|
||||
|
||||
private JSlider mIFGain;
|
||||
private JLabel mIFGainValueLabel;
|
||||
private JSlider mIFGain;
|
||||
private JLabel mIFGainValueLabel;
|
||||
|
||||
private JSlider mLNAGain;
|
||||
private JLabel mLNAGainValueLabel;
|
||||
private JSlider mLNAGain;
|
||||
private JLabel mLNAGainValueLabel;
|
||||
|
||||
private JSlider mMixerGain;
|
||||
private JLabel mMixerGainValueLabel;
|
||||
private JSlider mMixerGain;
|
||||
private JLabel mMixerGainValueLabel;
|
||||
|
||||
private JCheckBox mLNAAGC;
|
||||
private JCheckBox mMixerAGC;
|
||||
private JCheckBox mLNAAGC;
|
||||
private JCheckBox mMixerAGC;
|
||||
|
||||
private AirspyTunerController mController;
|
||||
private boolean mLoading;
|
||||
private AirspyTunerController mController;
|
||||
private boolean mLoading;
|
||||
|
||||
public AirspyTunerEditor( TunerConfigurationModel tunerConfigurationModel,
|
||||
AirspyTuner tuner )
|
||||
public AirspyTunerEditor( TunerConfigurationModel tunerConfigurationModel,
|
||||
AirspyTuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = tuner.getController();
|
||||
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -88,33 +100,33 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
return (AirspyTunerConfiguration)getItem();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][grow]" ) );
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][grow]" ) );
|
||||
|
||||
add( new JLabel( "Airspy Tuner Configuration" ), "span,align center" );
|
||||
|
||||
|
||||
mConfigurationName = new JTextField();
|
||||
mConfigurationName.setEnabled( false );
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
} );
|
||||
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
add( mConfigurationName, "span 2" );
|
||||
|
||||
|
||||
mTunerInfo = new JButton( "Tuner Info" );
|
||||
mTunerInfo.setEnabled( false );
|
||||
mTunerInfo.addActionListener( new ActionListener()
|
||||
@@ -122,22 +134,22 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( AirspyTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
JOptionPane.showMessageDialog( AirspyTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
} );
|
||||
add( mTunerInfo );
|
||||
|
||||
|
||||
/**
|
||||
* Sample Rate
|
||||
*/
|
||||
add( new JLabel( "Sample Rate:" ) );
|
||||
|
||||
|
||||
List<AirspySampleRate> rates = mController.getSampleRates();
|
||||
|
||||
mSampleRateCombo = new JComboBox<AirspySampleRate>(
|
||||
new DefaultComboBoxModel<AirspySampleRate>( rates.toArray(
|
||||
new AirspySampleRate[ rates.size() ] ) ) );
|
||||
|
||||
mSampleRateCombo = new JComboBox<AirspySampleRate>(
|
||||
new DefaultComboBoxModel<AirspySampleRate>( rates.toArray(
|
||||
new AirspySampleRate[ rates.size() ] ) ) );
|
||||
mSampleRateCombo.setEnabled( false );
|
||||
mSampleRateCombo.addActionListener( new ActionListener()
|
||||
{
|
||||
@@ -150,62 +162,62 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mController.setSampleRate( rate );
|
||||
save();
|
||||
}
|
||||
}
|
||||
catch ( LibUsbException | UsbException | SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( AirspyTunerEditor.this,
|
||||
JOptionPane.showMessageDialog( AirspyTunerEditor.this,
|
||||
"Couldn't set sample rate to " + rate.getLabel() );
|
||||
|
||||
|
||||
mLog.error( "Error setting airspy sample rate", e1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
add( mSampleRateCombo );
|
||||
|
||||
/**
|
||||
* Frequency Correction
|
||||
*/
|
||||
SpinnerModel model =
|
||||
new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
/**
|
||||
* Frequency Correction
|
||||
*/
|
||||
SpinnerModel model =
|
||||
new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
final double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
mLog.error( "Error setting frequency correction value", e1 );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection );
|
||||
|
||||
|
||||
save();
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection );
|
||||
|
||||
add( new JSeparator(), "span,growx,push" );
|
||||
|
||||
/**
|
||||
@@ -222,11 +234,11 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
GainMode mode = (GainMode)mGainModeCombo.getSelectedItem();
|
||||
|
||||
updateGainComponents( mode );
|
||||
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
AirspyTunerConfiguration airspy = getConfiguration();
|
||||
|
||||
|
||||
Gain gain = airspy.getGain();
|
||||
|
||||
if( mode == GainMode.CUSTOM )
|
||||
@@ -247,25 +259,25 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
mLNAGain.setValue( gain.getLNA() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
save();
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
add( mGainModeCombo, "wrap" );
|
||||
|
||||
/**
|
||||
* Gain
|
||||
*/
|
||||
add( new JLabel( "Master:" ) );
|
||||
|
||||
mMasterGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.GAIN_MIN,
|
||||
AirspyTunerController.GAIN_MAX,
|
||||
AirspyTunerController.GAIN_MIN );
|
||||
|
||||
mMasterGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.GAIN_MIN,
|
||||
AirspyTunerController.GAIN_MAX,
|
||||
AirspyTunerController.GAIN_MIN );
|
||||
mMasterGain.setMajorTickSpacing( 1 );
|
||||
mMasterGain.setPaintTicks( true );
|
||||
|
||||
|
||||
mMasterGain.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
@@ -280,31 +292,31 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
mController.setGain( gain );
|
||||
save();
|
||||
mMasterGainValueLabel.setText( String.valueOf( gain.getValue() ) );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
mLog.error( "Couldn't set airspy gain to:" + gain.name(), e );
|
||||
JOptionPane.showMessageDialog( mMasterGain, "Couldn't set gain value to " +
|
||||
gain.getValue() );
|
||||
JOptionPane.showMessageDialog( mMasterGain, "Couldn't set gain value to " +
|
||||
gain.getValue() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( mMasterGain, "span 2" );
|
||||
|
||||
|
||||
mMasterGainValueLabel = new JLabel( "0" );
|
||||
add( mMasterGainValueLabel );
|
||||
|
||||
|
||||
add( new JLabel( "IF:" ) );
|
||||
|
||||
mIFGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.IF_GAIN_MIN,
|
||||
AirspyTunerController.IF_GAIN_MAX,
|
||||
AirspyTunerController.IF_GAIN_MIN );
|
||||
|
||||
|
||||
mIFGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.IF_GAIN_MIN,
|
||||
AirspyTunerController.IF_GAIN_MAX,
|
||||
AirspyTunerController.IF_GAIN_MIN );
|
||||
|
||||
mIFGain.setMajorTickSpacing( 1 );
|
||||
mIFGain.setPaintTicks( true );
|
||||
|
||||
|
||||
mIFGain.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
@@ -317,34 +329,34 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
mController.setIFGain( gain );
|
||||
save();
|
||||
mIFGainValueLabel.setText( String.valueOf( gain ) );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
mLog.error( "Couldn't set airspy IF gain to:" + gain, e );
|
||||
|
||||
|
||||
JOptionPane.showMessageDialog( mIFGain, "Couldn't set IF gain value to " + gain );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( mIFGain, "span 2" );
|
||||
|
||||
|
||||
mIFGainValueLabel = new JLabel( "0" );
|
||||
add( mIFGainValueLabel );
|
||||
|
||||
|
||||
/**
|
||||
* Mixer Gain
|
||||
* Mixer Gain
|
||||
*/
|
||||
add( new JLabel( "Mixer:" ) );
|
||||
|
||||
mMixerGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.MIXER_GAIN_MIN,
|
||||
AirspyTunerController.MIXER_GAIN_MAX,
|
||||
AirspyTunerController.MIXER_GAIN_MIN );
|
||||
|
||||
|
||||
mMixerGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.MIXER_GAIN_MIN,
|
||||
AirspyTunerController.MIXER_GAIN_MAX,
|
||||
AirspyTunerController.MIXER_GAIN_MIN );
|
||||
|
||||
mMixerGain.setMajorTickSpacing( 1 );
|
||||
mMixerGain.setPaintTicks( true );
|
||||
|
||||
|
||||
mMixerGain.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
@@ -357,7 +369,7 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
mController.setMixerGain( gain );
|
||||
save();
|
||||
mMixerGainValueLabel.setText( String.valueOf( gain ) );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
mLog.error( "Couldn't set airspy Mixer gain to:" + gain, e );
|
||||
@@ -370,17 +382,17 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
|
||||
mMixerGainValueLabel = new JLabel( "0" );
|
||||
add( mMixerGainValueLabel );
|
||||
|
||||
|
||||
add( new JLabel( "LNA:" ) );
|
||||
|
||||
mLNAGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.LNA_GAIN_MIN,
|
||||
AirspyTunerController.LNA_GAIN_MAX,
|
||||
AirspyTunerController.LNA_GAIN_MIN );
|
||||
|
||||
|
||||
mLNAGain = new JSlider( JSlider.HORIZONTAL,
|
||||
AirspyTunerController.LNA_GAIN_MIN,
|
||||
AirspyTunerController.LNA_GAIN_MAX,
|
||||
AirspyTunerController.LNA_GAIN_MIN );
|
||||
|
||||
mLNAGain.setMajorTickSpacing( 1 );
|
||||
mLNAGain.setPaintTicks( true );
|
||||
|
||||
|
||||
mLNAGain.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
@@ -393,7 +405,7 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
mController.setLNAGain( gain );
|
||||
save();
|
||||
mLNAGainValueLabel.setText( String.valueOf( gain ) );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
mLog.error( "Couldn't set airspy LNA gain to:" + gain, e );
|
||||
@@ -406,7 +418,7 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
|
||||
mLNAGainValueLabel = new JLabel( "0" );
|
||||
add( mLNAGainValueLabel );
|
||||
|
||||
|
||||
mMixerAGC = new JCheckBox( "Mixer AGC" );
|
||||
mMixerAGC.addActionListener( new ActionListener()
|
||||
{
|
||||
@@ -417,16 +429,16 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mController.setMixerAGC( mMixerAGC.isSelected() );
|
||||
mMixerGain.setEnabled( !mMixerAGC.isSelected() );
|
||||
|
||||
|
||||
save();
|
||||
}
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
mLog.error( "Error setting Mixer AGC Enabled" );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
add( mMixerAGC, "span 2,center" );
|
||||
|
||||
mLNAAGC = new JCheckBox( "LNA AGC" );
|
||||
@@ -441,26 +453,26 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
mLNAGain.setEnabled( !mLNAAGC.isSelected() );
|
||||
|
||||
save();
|
||||
}
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
mLog.error( "Error setting LNA AGC Enabled" );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
add( mLNAAGC, "span 2,center" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the enabled state of each of the gain controls according to the
|
||||
* specified gain mode. The master gain control is enabled for linearity
|
||||
* and sensitivity and the individual gain controls are disabled, and
|
||||
* vice-versa for custom mode.
|
||||
*/
|
||||
private void updateGainComponents( GainMode mode )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the enabled state of each of the gain controls according to the
|
||||
* specified gain mode. The master gain control is enabled for linearity
|
||||
* and sensitivity and the individual gain controls are disabled, and
|
||||
* vice-versa for custom mode.
|
||||
*/
|
||||
private void updateGainComponents( GainMode mode )
|
||||
{
|
||||
switch( mode )
|
||||
{
|
||||
case LINEARITY:
|
||||
@@ -471,20 +483,20 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
}
|
||||
if( mIFGain.isEnabled() )
|
||||
{
|
||||
mIFGain.setEnabled( false );
|
||||
mIFGain.setEnabled( false );
|
||||
mIFGainValueLabel.setEnabled( false );
|
||||
}
|
||||
if( mLNAGain.isEnabled() )
|
||||
{
|
||||
mLNAAGC.setEnabled( false );
|
||||
mLNAGainValueLabel.setEnabled( false );
|
||||
mLNAGain.setEnabled( false );
|
||||
mLNAGainValueLabel.setEnabled( false );
|
||||
mLNAGain.setEnabled( false );
|
||||
}
|
||||
if( mMixerGain.isEnabled() )
|
||||
{
|
||||
mMixerGainValueLabel.setEnabled( false );
|
||||
mMixerAGC.setEnabled( false );
|
||||
mMixerGain.setEnabled( false );
|
||||
mMixerGainValueLabel.setEnabled( false );
|
||||
mMixerAGC.setEnabled( false );
|
||||
mMixerGain.setEnabled( false );
|
||||
}
|
||||
break;
|
||||
case SENSITIVITY:
|
||||
@@ -495,20 +507,20 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
}
|
||||
if( mIFGain.isEnabled() )
|
||||
{
|
||||
mIFGain.setEnabled( false );
|
||||
mIFGain.setEnabled( false );
|
||||
mIFGainValueLabel.setEnabled( false );
|
||||
}
|
||||
if( mLNAGain.isEnabled() )
|
||||
{
|
||||
mLNAAGC.setEnabled( false );
|
||||
mLNAGainValueLabel.setEnabled( false );
|
||||
mLNAGain.setEnabled( false );
|
||||
mLNAGainValueLabel.setEnabled( false );
|
||||
mLNAGain.setEnabled( false );
|
||||
}
|
||||
if( mMixerGain.isEnabled() )
|
||||
{
|
||||
mMixerGainValueLabel.setEnabled( false );
|
||||
mMixerAGC.setEnabled( false );
|
||||
mMixerGain.setEnabled( false );
|
||||
mMixerGainValueLabel.setEnabled( false );
|
||||
mMixerAGC.setEnabled( false );
|
||||
mMixerGain.setEnabled( false );
|
||||
}
|
||||
break;
|
||||
case CUSTOM:
|
||||
@@ -519,36 +531,36 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
}
|
||||
if( !mIFGain.isEnabled() )
|
||||
{
|
||||
mIFGain.setEnabled( true );
|
||||
mIFGain.setEnabled( true );
|
||||
mIFGainValueLabel.setEnabled( true );
|
||||
}
|
||||
if( !mLNAGain.isEnabled() )
|
||||
{
|
||||
mLNAAGC.setEnabled( true );
|
||||
mLNAGainValueLabel.setEnabled( true );
|
||||
mLNAGain.setEnabled( true );
|
||||
mLNAGainValueLabel.setEnabled( true );
|
||||
mLNAGain.setEnabled( true );
|
||||
}
|
||||
if( !mMixerGain.isEnabled() )
|
||||
{
|
||||
mMixerGainValueLabel.setEnabled( true );
|
||||
mMixerAGC.setEnabled( true );
|
||||
mMixerGain.setEnabled( true );
|
||||
mMixerGainValueLabel.setEnabled( true );
|
||||
mMixerAGC.setEnabled( true );
|
||||
mMixerGain.setEnabled( true );
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
AirspyTunerConfiguration config = getConfiguration();
|
||||
config.setName( mConfigurationName.getText() );
|
||||
config.setSampleRate( ((AirspySampleRate)mSampleRateCombo.getSelectedItem()).getRate() );
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
AirspyTunerConfiguration config = getConfiguration();
|
||||
config.setName( mConfigurationName.getText() );
|
||||
config.setSampleRate( ((AirspySampleRate)mSampleRateCombo.getSelectedItem()).getRate() );
|
||||
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection.getModel()).getNumber().doubleValue();
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
|
||||
Gain gain = Gain.getGain( (GainMode)mGainModeCombo.getSelectedItem(), mMasterGain.getValue() );
|
||||
@@ -559,15 +571,15 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
config.setLNAGain( mLNAGain.getValue() );
|
||||
config.setMixerAGC( mMixerAGC.isSelected() );
|
||||
config.setLNAAGC( mLNAAGC.isSelected() );
|
||||
|
||||
|
||||
getTunerConfigurationModel().broadcast( new TunerConfigurationEvent( config, TunerConfigurationEvent.Event.CHANGE ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private AirspySampleRate fromValue( int value )
|
||||
{
|
||||
List<AirspySampleRate> rates = mController.getSampleRates();
|
||||
|
||||
|
||||
for( AirspySampleRate rate: rates )
|
||||
{
|
||||
if( rate.getRate() == value )
|
||||
@@ -580,10 +592,10 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
return rates.get( 0 );
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets all controls to the argument enabled state
|
||||
*/
|
||||
@@ -593,52 +605,52 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mConfigurationName.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mTunerInfo.isEnabled() != enabled )
|
||||
{
|
||||
mTunerInfo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mSampleRateCombo.isEnabled() != enabled )
|
||||
{
|
||||
mSampleRateCombo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mFrequencyCorrection.isEnabled() != enabled )
|
||||
{
|
||||
mFrequencyCorrection.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mGainModeCombo.isEnabled() != enabled )
|
||||
{
|
||||
mGainModeCombo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mMasterGain.isEnabled() != enabled )
|
||||
{
|
||||
mMasterGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mIFGain.isEnabled() != enabled )
|
||||
{
|
||||
mIFGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mMixerGain.isEnabled() != enabled )
|
||||
{
|
||||
mMixerGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mMixerAGC.isEnabled() != enabled )
|
||||
{
|
||||
mMixerAGC.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mLNAGain.isEnabled() != enabled )
|
||||
{
|
||||
mLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mLNAAGC.isEnabled() != enabled )
|
||||
{
|
||||
mLNAAGC.setEnabled( enabled );
|
||||
@@ -646,43 +658,43 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the tuner configuration to the editor. If the configuration is assigned to the
|
||||
* Applies the tuner configuration to the editor. If the configuration is assigned to the
|
||||
* currently selected tuner, then the settings are applied.
|
||||
*/
|
||||
@Override
|
||||
public void setItem( TunerConfiguration config )
|
||||
{
|
||||
super.setItem( config );
|
||||
|
||||
|
||||
mLoading = true;
|
||||
|
||||
|
||||
if( hasItem() && getItem().isAssigned() )
|
||||
{
|
||||
AirspyTunerConfiguration airspy = getConfiguration();
|
||||
|
||||
|
||||
setControlsEnabled( true );
|
||||
|
||||
|
||||
mConfigurationName.setText( airspy.getName() );
|
||||
|
||||
AirspySampleRate rate = fromValue( airspy.getSampleRate() );
|
||||
|
||||
|
||||
if( rate != null )
|
||||
{
|
||||
mSampleRateCombo.setSelectedItem( rate );
|
||||
}
|
||||
|
||||
|
||||
mFrequencyCorrection.setValue( airspy.getFrequencyCorrection() );
|
||||
|
||||
GainMode mode = Gain.getGainMode( airspy.getGain() );
|
||||
|
||||
//This will set the master, IF, Mixer, LNA and AGC controls
|
||||
mGainModeCombo.setSelectedItem( mode );
|
||||
|
||||
|
||||
if( mode == GainMode.CUSTOM )
|
||||
{
|
||||
mMasterGain.setValue( airspy.getGain().getValue() );
|
||||
mIFGain.setValue( airspy.getIFGain() );
|
||||
|
||||
|
||||
if( airspy.isMixerAGC() )
|
||||
{
|
||||
mMixerAGC.setSelected( airspy.isMixerAGC() );
|
||||
@@ -707,7 +719,7 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mMixerAGC.setSelected( false );
|
||||
mLNAAGC.setSelected( false );
|
||||
|
||||
|
||||
Gain gain = airspy.getGain();
|
||||
|
||||
mMasterGain.setValue( gain.getValue() );
|
||||
@@ -721,16 +733,16 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( hasItem() ? getItem().getName() : "" );
|
||||
}
|
||||
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
|
||||
|
||||
private String getTunerInfo()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
AirspyDeviceInformation info = mController.getDeviceInfo();
|
||||
|
||||
|
||||
sb.append( "<html><h3>Airspy Tuner</h3>" );
|
||||
sb.append( "<b>Serial: </b>" );
|
||||
sb.append( info.getSerialNumber() );
|
||||
@@ -740,15 +752,15 @@ public class AirspyTunerEditor extends TunerConfigurationEditor
|
||||
String[] firmware = info.getVersion().split( " " );
|
||||
sb.append( firmware.length > 1 ? firmware[ 0 ] : info.getVersion() );
|
||||
sb.append( "<br>" );
|
||||
|
||||
|
||||
sb.append( "<b>Part: </b>" );
|
||||
sb.append( info.getPartNumber() );
|
||||
sb.append( "<br>" );
|
||||
|
||||
|
||||
sb.append( "<b>Board ID: </b>" );
|
||||
sb.append( info.getBoardID().getLabel() );
|
||||
sb.append( "<br>" );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import io.github.dsheirer.dsp.mixer.Oscillator;
|
||||
import io.github.dsheirer.sample.Buffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
||||
import io.github.dsheirer.sample.complex.Complex;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CICTunerChannelSource extends TunerChannelSource
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(CICTunerChannelSource.class);
|
||||
|
||||
//Maximum number of filled buffers for the blocking queue
|
||||
private static final int BUFFER_MAX_CAPACITY = 300;
|
||||
|
||||
//Threshold for resetting buffer overflow condition
|
||||
private static final int BUFFER_OVERFLOW_RESET_THRESHOLD = 100;
|
||||
|
||||
private static double CHANNEL_RATE = 48000.0;
|
||||
private static int CHANNEL_PASS_FREQUENCY = 12000;
|
||||
|
||||
private OverflowableTransferQueue<ComplexBuffer> mBuffer;
|
||||
|
||||
private Oscillator mFrequencyCorrectionMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private List<ComplexBuffer> mSampleBuffers = new ArrayList<ComplexBuffer>();
|
||||
private long mTunerFrequency = 0;
|
||||
private double mTunerSampleRate;
|
||||
private long mChannelFrequencyCorrection = 0;
|
||||
|
||||
/**
|
||||
* Implements a heterodyne/decimate Digital Drop Channel (DDC) to decimate the IQ output from a tuner down to a
|
||||
* fixed 48 kHz IQ channel rate.
|
||||
*
|
||||
* Note: this class can only be used once (started and stopped) and a new tuner channel source must be requested
|
||||
* from the tuner once this object has been stopped. This is because channels are managed dynamically and center
|
||||
* tuned frequency may have changed since this source was obtained and thus the tuner might no longer be able to
|
||||
* source this channel once it has been stopped.
|
||||
*
|
||||
* @param tunerChannel specifying the center frequency for the DDC
|
||||
*/
|
||||
public CICTunerChannelSource(Tuner tuner, TunerChannel tunerChannel)
|
||||
{
|
||||
super(tuner.getTunerController().getSourceEventListener(), tunerChannel);
|
||||
|
||||
mBuffer = new OverflowableTransferQueue<>(BUFFER_MAX_CAPACITY, BUFFER_OVERFLOW_RESET_THRESHOLD);
|
||||
mBuffer.setSourceOverflowListener(this);
|
||||
|
||||
//Setup the frequency translator to the current source frequency
|
||||
mTunerFrequency = tuner.getTunerController().getFrequency();
|
||||
long frequencyOffset = mTunerFrequency - getTunerChannel().getFrequency();
|
||||
mFrequencyCorrectionMixer = new Oscillator(frequencyOffset, tuner.getTunerController().getSampleRate());
|
||||
|
||||
//Setup the decimation filter chain
|
||||
setSampleRate(tuner.getTunerController().getSampleRate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the center frequency for the incoming sample buffers
|
||||
* @param frequency in hertz
|
||||
*/
|
||||
@Override
|
||||
protected void setFrequency(long frequency)
|
||||
{
|
||||
mTunerFrequency = frequency;
|
||||
|
||||
//Reset frequency correction so that consumer components can adjust
|
||||
setFrequencyCorrection(0);
|
||||
|
||||
updateMixerFrequencyOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current frequency correction being applied to the channel sample stream
|
||||
* @return correction in hertz
|
||||
*/
|
||||
@Override
|
||||
public long getFrequencyCorrection()
|
||||
{
|
||||
return mChannelFrequencyCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the frequency correction value and broadcasts the change to the registered downstream listener.
|
||||
* @param correction current frequency correction value.
|
||||
*/
|
||||
protected void setFrequencyCorrection(long correction)
|
||||
{
|
||||
mChannelFrequencyCorrection = correction;
|
||||
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mChannelFrequencyCorrection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary input method for receiving complex sample buffers from the wideband source (ie tuner)
|
||||
* @param buffer to receive and eventually process
|
||||
*/
|
||||
public void receive(ComplexBuffer buffer)
|
||||
{
|
||||
mBuffer.offer(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
/* Save a pointer to the listener so that if we have to change the
|
||||
* decimation filter, we can re-add the listener */
|
||||
mListener = listener;
|
||||
|
||||
mDecimationFilter.setListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mDecimationFilter.removeListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sample rate to the requested value and notifies any downstream components of the change
|
||||
* @param sampleRate to set
|
||||
*/
|
||||
protected void setSampleRate(double sampleRate)
|
||||
{
|
||||
if(mTunerSampleRate != sampleRate)
|
||||
{
|
||||
mFrequencyCorrectionMixer.setSampleRate(sampleRate);
|
||||
|
||||
/* Get new decimation filter */
|
||||
mDecimationFilter = FilterFactory.getDecimationFilter((int)sampleRate, (int)CHANNEL_RATE, 1,
|
||||
CHANNEL_PASS_FREQUENCY, 60, Window.WindowType.HAMMING);
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilter.setListener(mListener);
|
||||
|
||||
mTunerSampleRate = sampleRate;
|
||||
|
||||
broadcastConsumerSourceEvent(SourceEvent.channelSampleRateChange(getSampleRate()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the local mixer frequency offset from the tuned frequency,
|
||||
* channel's requested frequency, and channel frequency correction.
|
||||
*/
|
||||
private void updateMixerFrequencyOffset()
|
||||
{
|
||||
long offset = mTunerFrequency - getTunerChannel().getFrequency() - mChannelFrequencyCorrection;
|
||||
mFrequencyCorrectionMixer.setFrequency(offset);
|
||||
}
|
||||
|
||||
public double getSampleRate()
|
||||
{
|
||||
return CHANNEL_RATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSamples()
|
||||
{
|
||||
mBuffer.drainTo(mSampleBuffers, 20);
|
||||
|
||||
for(Buffer buffer : mSampleBuffers)
|
||||
{
|
||||
float[] samples = buffer.getSamples();
|
||||
|
||||
/* We make a copy of the buffer so that we don't affect
|
||||
* anyone else that is using the same buffer, like other
|
||||
* channels or the spectral display */
|
||||
float[] translated = new float[samples.length];
|
||||
|
||||
/* Perform frequency translation */
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
mFrequencyCorrectionMixer.rotate();
|
||||
|
||||
translated[x] = Complex.multiplyInphase(
|
||||
samples[x], samples[x + 1], mFrequencyCorrectionMixer.inphase(), mFrequencyCorrectionMixer.quadrature());
|
||||
|
||||
translated[x + 1] = Complex.multiplyQuadrature(
|
||||
samples[x], samples[x + 1], mFrequencyCorrectionMixer.inphase(), mFrequencyCorrectionMixer.quadrature());
|
||||
}
|
||||
|
||||
final ComplexPrimeCICDecimate filter = mDecimationFilter;
|
||||
|
||||
if(filter != null)
|
||||
{
|
||||
filter.receive(new ComplexBuffer(translated));
|
||||
}
|
||||
}
|
||||
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.channel;
|
||||
|
||||
public class TunerChannel implements Comparable<TunerChannel>
|
||||
{
|
||||
private long mFrequency;
|
||||
private int mBandwidth;
|
||||
|
||||
public TunerChannel(long frequency, int bandwidth)
|
||||
{
|
||||
mFrequency = frequency;
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mBandwidth;
|
||||
}
|
||||
|
||||
public void setBandwidth(int bandwidth)
|
||||
{
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public long getMinFrequency()
|
||||
{
|
||||
return mFrequency - (mBandwidth / 2);
|
||||
}
|
||||
|
||||
public long getMaxFrequency()
|
||||
{
|
||||
return mFrequency + (mBandwidth / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if any part of this tuner channel overlaps the specified range
|
||||
*/
|
||||
public boolean overlaps(long minimum, long maximum)
|
||||
{
|
||||
long channelMin = getMinFrequency();
|
||||
long channelMax = getMaxFrequency();
|
||||
|
||||
return ((minimum <= channelMin && channelMin <= maximum) ||
|
||||
(minimum <= channelMax && channelMax <= maximum) ||
|
||||
(minimum <= channelMin && channelMax <= maximum) ||
|
||||
(channelMin <= minimum && maximum <= channelMax));
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("Channel: ");
|
||||
sb.append(getMinFrequency());
|
||||
sb.append("-");
|
||||
sb.append(getMaxFrequency());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TunerChannel otherLock)
|
||||
{
|
||||
return Long.compare(getFrequency(), otherLock.getFrequency());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
|
||||
public interface TunerChannelProvider
|
||||
{
|
||||
/**
|
||||
* Returns a tuner frequency channel source, tuned to the correct frequency
|
||||
*
|
||||
* @return - source for 48k sample rate
|
||||
*/
|
||||
public TunerChannelSource getChannel( TunerChannel channel ) throws SourceException;
|
||||
|
||||
/**
|
||||
* Releases the tuned channel resources
|
||||
*/
|
||||
public void releaseChannel( TunerChannelSource source );
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.ComplexSource;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceEventListenerToProcessorAdapter;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class TunerChannelSource extends ComplexSource implements ISourceEventProcessor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerChannelSource.class);
|
||||
private static final long BUFFER_PROCESSOR_RUN_INTERVAL_MILLISECONDS = 50;
|
||||
private SourceEventListenerToProcessorAdapter mConsumerSourceEventListenerAdapter;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Listener<SourceEvent> mProducerSourceEventListener;
|
||||
private Listener<SourceEvent> mConsumerSourceEventListener;
|
||||
private BufferProcessor mBufferProcessor = new BufferProcessor();
|
||||
|
||||
/**
|
||||
* Tuner Channel Source is a Digital Drop Channel (DDC) abstract class that defines the minimum functionality
|
||||
* requirements for a channel sample source.
|
||||
*
|
||||
* @param producerSourceEventListener to receive source event requests (e.g. start/stop sample stream)
|
||||
* @param tunerChannel describing the desired channel frequency and bandwidth/minimum sample rate
|
||||
*/
|
||||
public TunerChannelSource(Listener<SourceEvent> producerSourceEventListener, TunerChannel tunerChannel)
|
||||
{
|
||||
mProducerSourceEventListener = producerSourceEventListener;
|
||||
mTunerChannel = tunerChannel;
|
||||
mConsumerSourceEventListenerAdapter = new SourceEventListenerToProcessorAdapter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFrequency()
|
||||
{
|
||||
return mTunerChannel.getFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the center frequency for the sample streaming being sent from the producer.
|
||||
* @param frequency in hertz
|
||||
*/
|
||||
protected abstract void setFrequency(long frequency);
|
||||
|
||||
/**
|
||||
* Sets the sample rate of the incoming sample stream from the producer
|
||||
* @param sampleRate in hertz
|
||||
*/
|
||||
protected abstract void setSampleRate(double sampleRate);
|
||||
|
||||
/**
|
||||
* Sets the frequency correction for the outbound sample stream to the consumer
|
||||
* @param correction in hertz
|
||||
*/
|
||||
protected abstract void setFrequencyCorrection(long correction);
|
||||
|
||||
/**
|
||||
* Frequency correction value currently being applied to the outbound sample stream
|
||||
*/
|
||||
public abstract long getFrequencyCorrection();
|
||||
|
||||
/**
|
||||
* Sets the listener to receive the complex buffer sample output from this channel
|
||||
* @param complexBufferListener to receive complex buffers
|
||||
*/
|
||||
public abstract void setListener(Listener<ComplexBuffer> complexBufferListener);
|
||||
|
||||
/**
|
||||
* Commands sub-class to process queued samples and distribute them to the consumer. This method will be invoked
|
||||
* by an interval timer.
|
||||
*/
|
||||
protected abstract void processSamples();
|
||||
|
||||
/**
|
||||
* Tuner channel for this tuner channel source
|
||||
*/
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this tuner channel source producing sample stream.
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
//Broadcast current frequency and sample rate so consumer can configure correctly
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyChange(getFrequency()));
|
||||
broadcastConsumerSourceEvent(SourceEvent.sampleRateChange(getSampleRate()));
|
||||
|
||||
if(mProducerSourceEventListener != null)
|
||||
{
|
||||
mProducerSourceEventListener.receive(SourceEvent.startSampleStream(this));
|
||||
}
|
||||
|
||||
mBufferProcessor.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops this tuner channel source from producing a sample stream. Note: tuner channel sources are one-time usage
|
||||
* only. Invoking this method will also tell the source manager to dispose of this source.
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
if(mProducerSourceEventListener != null)
|
||||
{
|
||||
mProducerSourceEventListener.receive(SourceEvent.stopSampleStream(this));
|
||||
mProducerSourceEventListener.receive(SourceEvent.sourceDisposeRequest(this));
|
||||
}
|
||||
|
||||
mBufferProcessor.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
//Reset is not valid for a tuner channel source - ignored
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked after the buffer processor is completely shutdown so that this instance can perform any
|
||||
* cleanup operations needed to dispose of this instance.
|
||||
*/
|
||||
protected void performDisposal()
|
||||
{
|
||||
mProducerSourceEventListener = null;
|
||||
mConsumerSourceEventListener = null;
|
||||
mConsumerSourceEventListenerAdapter.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes source event notifications received from the producer/parent and source event requests received from
|
||||
* the consumer.
|
||||
*
|
||||
* @param sourceEvent to process
|
||||
* @throws SourceException if there is an error while processing the source event
|
||||
*/
|
||||
@Override
|
||||
public void process(SourceEvent sourceEvent) throws SourceException
|
||||
{
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
//Notification events from the producer
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
setFrequency(sourceEvent.getValue().longValue());
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
setSampleRate(sourceEvent.getValue().doubleValue());
|
||||
break;
|
||||
|
||||
//Request events from the consumer
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
setFrequencyCorrection(sourceEvent.getValue().longValue());
|
||||
break;
|
||||
|
||||
default:
|
||||
mLog.error("Ignoring unrecognized source event: " + sourceEvent.getEvent() + " from [" +
|
||||
sourceEvent.getSource().getClass() + "]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the source event to the incoming sample stream producer.
|
||||
* @param sourceEvent to broadcast
|
||||
*/
|
||||
protected void broadcastProducerSourceEvent(SourceEvent sourceEvent)
|
||||
{
|
||||
if(mProducerSourceEventListener != null)
|
||||
{
|
||||
mProducerSourceEventListener.receive(sourceEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the source event to the outbound sample stream consumer.
|
||||
* @param sourceEvent to broadcast
|
||||
*/
|
||||
protected void broadcastConsumerSourceEvent(SourceEvent sourceEvent)
|
||||
{
|
||||
if(mConsumerSourceEventListener != null)
|
||||
{
|
||||
mConsumerSourceEventListener.receive(sourceEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the ISourceEventListener interface for receiving source events (ie requests) from a consumer.
|
||||
*
|
||||
* Note: source events are simply transferred to the process() method in this class.
|
||||
*/
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
return mConsumerSourceEventListenerAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the ISourceEventProvider interface to set the consumer listener for source events.
|
||||
* @param listener to receive consumer source events
|
||||
*/
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mConsumerSourceEventListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the ISourceEventProvider interface to remove the consumer listener for source events.
|
||||
*/
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mConsumerSourceEventListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processor to periodically invoke buffer sample processing on an interval timer. At each interval this processor
|
||||
* sends a heartbeat to the registered consumer and then commands the sub-class implementation to process any
|
||||
* queued buffers and distribute complex buffer sample(s) to the registered consumer.
|
||||
*/
|
||||
public class BufferProcessor implements Runnable
|
||||
{
|
||||
private ScheduledFuture<?> mScheduledFuture;
|
||||
private boolean mStopped = false;
|
||||
|
||||
/**
|
||||
* Commands this processor to do a shutdown at the end of this or the next iteration. Once successfully
|
||||
* shutdown, it will invoke the performDisposal() method to cleanup this instance.
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
mStopped = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts buffer processing on a fixed interval using a scheduled thread pool
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
if(mScheduledFuture == null)
|
||||
{
|
||||
mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(this, 0,
|
||||
BUFFER_PROCESSOR_RUN_INTERVAL_MILLISECONDS, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the Runnable interface to periodically send a heartbeat and then process buffer samples.
|
||||
*/
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if(!mStopped)
|
||||
{
|
||||
getHeartbeatManager().broadcast();
|
||||
processSamples();
|
||||
}
|
||||
|
||||
if(mStopped)
|
||||
{
|
||||
if(mScheduledFuture != null)
|
||||
{
|
||||
//Set may-interrupt to false so that we can complete this iteration
|
||||
mScheduledFuture.cancel(false);
|
||||
}
|
||||
|
||||
mScheduledFuture = null;
|
||||
|
||||
performDisposal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.configuration;
|
||||
@@ -31,8 +29,7 @@ import java.util.List;
|
||||
public class TunerConfigurationModel extends AbstractTableModel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( TunerConfigurationModel.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger( TunerConfigurationModel.class );
|
||||
|
||||
public static final int TUNER_TYPE = 0;
|
||||
public static final int CONFIGURATION_NAME = 1;
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.ettus;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTunerDevice;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public class B100Tuner extends Tuner
|
||||
{
|
||||
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", null );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return TunerClass.ETTUS_USRP_B100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.ETTUS_WBX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleSize()
|
||||
{
|
||||
return 16.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel( 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;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.ettus;
|
||||
|
||||
import io.github.dsheirer.settings.SettingsManager;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class B100TunerEditorPanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public B100TunerEditorPanel( B100Tuner tuner, SettingsManager settingsManager )
|
||||
{
|
||||
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") );
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,33 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.fcd;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ShortAdapter;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.MixerTuner;
|
||||
import io.github.dsheirer.source.tuner.MixerTunerDataLine;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public class FCDTuner extends MixerTuner
|
||||
public class FCDTuner extends Tuner
|
||||
{
|
||||
public FCDTuner( MixerTunerDataLine mixerTDL,
|
||||
FCDTunerController controller )
|
||||
public FCDTuner(FCDTunerController controller)
|
||||
{
|
||||
super( controller.getConfiguration().toString(),
|
||||
controller,
|
||||
mixerTDL,
|
||||
new ShortAdapter() );
|
||||
super( controller.getConfiguration().toString(), controller);
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
//TODO: release the mixer tuner data line as well
|
||||
|
||||
getController().dispose();
|
||||
}
|
||||
|
||||
@@ -77,36 +59,4 @@ public class FCDTuner extends MixerTuner
|
||||
{
|
||||
return 16.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel( TunerChannel tunerChannel )
|
||||
throws RejectedExecutionException, SourceException
|
||||
{
|
||||
TunerChannelSource source = getController().getChannel( this, tunerChannel );
|
||||
|
||||
if( source != null )
|
||||
{
|
||||
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<ComplexBuffer>)source );
|
||||
|
||||
/* Tell the controller to release the channel and cleanup */
|
||||
/* This will release the channel as a frequency change listener */
|
||||
getController().releaseChannel( source );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,16 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.fcd;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ShortAdapter;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.mixer.ComplexMixer;
|
||||
import io.github.dsheirer.source.tuner.MixerTunerDataLine;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.fcd.proV1.FCD1TunerController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.Device;
|
||||
@@ -32,6 +36,7 @@ import org.usb4java.DeviceHandle;
|
||||
import org.usb4java.LibUsb;
|
||||
import org.usb4java.LibUsbException;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.usb.UsbClaimException;
|
||||
import javax.usb.UsbException;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -54,6 +59,8 @@ public abstract class FCDTunerController extends TunerController
|
||||
private DeviceHandle mDeviceHandle;
|
||||
|
||||
private FCDConfiguration mConfiguration = new FCDConfiguration();
|
||||
protected ComplexMixer mComplexMixer;
|
||||
|
||||
|
||||
/**
|
||||
* Generic FCD tuner controller - contains functionality common across both
|
||||
@@ -64,11 +71,8 @@ public abstract class FCDTunerController extends TunerController
|
||||
* @param minTunableFrequency
|
||||
* @param maxTunableFrequency
|
||||
*/
|
||||
public FCDTunerController(Device device,
|
||||
DeviceDescriptor descriptor,
|
||||
int sampleRate,
|
||||
int minTunableFrequency,
|
||||
int maxTunableFrequency)
|
||||
public FCDTunerController(MixerTunerDataLine mixerTDL, Device device, DeviceDescriptor descriptor, String tunerName,
|
||||
int minTunableFrequency, int maxTunableFrequency, AudioFormat audioFormat)
|
||||
{
|
||||
super(minTunableFrequency, maxTunableFrequency, DC_SPIKE_AVOID_BUFFER, USABLE_BANDWIDTH_PERCENT);
|
||||
mDevice = device;
|
||||
@@ -76,11 +80,45 @@ public abstract class FCDTunerController extends TunerController
|
||||
|
||||
try
|
||||
{
|
||||
mFrequencyController.setSampleRate(sampleRate);
|
||||
mFrequencyController.setSampleRate((int)audioFormat.getSampleRate());
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Error setting sample rate to [" + sampleRate + "]", se);
|
||||
mLog.error("Error setting sample rate to [" + audioFormat.getSampleRate() + "]", se);
|
||||
}
|
||||
|
||||
mComplexMixer = new ComplexMixer( mixerTDL.getTargetDataLine(), audioFormat, tunerName, new ShortAdapter(),
|
||||
mSampleBroadcaster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the super class functionality to auto-start the complex mixer and provide samples to listeners
|
||||
*/
|
||||
@Override
|
||||
public void addComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
boolean hasExistingListeners = hasComplexBufferListeners();
|
||||
|
||||
super.addComplexBufferListener(listener);
|
||||
|
||||
if(!hasExistingListeners)
|
||||
{
|
||||
mComplexMixer.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the super class functionality to auto-stop the complex mixer and stop sample stream when there are no
|
||||
* more registered listeners
|
||||
*/
|
||||
@Override
|
||||
public void removeComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
super.removeComplexBufferListener(listener);
|
||||
|
||||
if(!hasComplexBufferListeners())
|
||||
{
|
||||
mComplexMixer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +173,7 @@ public abstract class FCDTunerController extends TunerController
|
||||
/**
|
||||
* Sample rate of the tuner
|
||||
*/
|
||||
public abstract int getCurrentSampleRate() throws SourceException;
|
||||
public abstract double getCurrentSampleRate();
|
||||
|
||||
/**
|
||||
* Tuner class
|
||||
@@ -402,7 +440,7 @@ public abstract class FCDTunerController extends TunerController
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(64);
|
||||
|
||||
/* The FCD expects little-endian formatted values */
|
||||
/* The FCD expects little-endian formatted values */
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
buffer.put(0, command.getCommand());
|
||||
@@ -538,14 +576,14 @@ public abstract class FCDTunerController extends TunerController
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public FCD1TunerController.Block getBandBlocking()
|
||||
public Block getBandBlocking()
|
||||
{
|
||||
FCD1TunerController.Block retVal = FCD1TunerController.Block.UNKNOWN;
|
||||
Block retVal = Block.UNKNOWN;
|
||||
|
||||
switch(mMode)
|
||||
{
|
||||
case APPLICATION:
|
||||
retVal = FCD1TunerController.Block.getBlock(mConfig.substring(23, 33).trim());
|
||||
retVal = Block.getBlock(mConfig.substring(23, 33).trim());
|
||||
break;
|
||||
case BOOTLOADER:
|
||||
case UNKNOWN:
|
||||
@@ -615,4 +653,39 @@ public abstract class FCDTunerController extends TunerController
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,13 +21,26 @@ import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEditor;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||
import io.github.dsheirer.source.tuner.fcd.FCDTuner;
|
||||
import io.github.dsheirer.source.tuner.fcd.proV1.FCD1TunerController.LNAEnhance;
|
||||
import io.github.dsheirer.source.tuner.fcd.proV1.FCD1TunerController.LNAGain;
|
||||
import io.github.dsheirer.source.tuner.fcd.proV1.FCD1TunerController.MixerGain;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -38,30 +51,30 @@ import java.text.DecimalFormat;
|
||||
|
||||
public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final static Logger mLog = LoggerFactory.getLogger( FCD1TunerEditor.class );
|
||||
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<FCD1TunerController.LNAGain> mComboLNAGain;
|
||||
private JComboBox<FCD1TunerController.LNAEnhance> mComboLNAEnhance;
|
||||
private JComboBox<FCD1TunerController.MixerGain> mComboMixerGain;
|
||||
private CorrectionSpinner mCorrectionDCI;
|
||||
private CorrectionSpinner mCorrectionDCQ;
|
||||
private CorrectionSpinner mCorrectionGain;
|
||||
private CorrectionSpinner mCorrectionPhase;
|
||||
private boolean mLoading;
|
||||
|
||||
private FCD1TunerController mController;
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<LNAGain> mComboLNAGain;
|
||||
private JComboBox<LNAEnhance> mComboLNAEnhance;
|
||||
private JComboBox<MixerGain> mComboMixerGain;
|
||||
private CorrectionSpinner mCorrectionDCI;
|
||||
private CorrectionSpinner mCorrectionDCQ;
|
||||
private CorrectionSpinner mCorrectionGain;
|
||||
private CorrectionSpinner mCorrectionPhase;
|
||||
private boolean mLoading;
|
||||
|
||||
public FCD1TunerEditor(TunerConfigurationModel tunerConfigurationModel, FCDTuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (FCD1TunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
private FCD1TunerController mController;
|
||||
|
||||
public FCD1TunerEditor( TunerConfigurationModel tunerConfigurationModel, FCDTuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (FCD1TunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private FCD1TunerConfiguration getConfiguration()
|
||||
{
|
||||
@@ -69,33 +82,33 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
return (FCD1TunerConfiguration)getItem();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][][][][][][grow]" ) );
|
||||
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][][][][][][grow]" ) );
|
||||
|
||||
add( new JLabel( "FCD Pro Tuner Configuration" ), "span,align center" );
|
||||
|
||||
mConfigurationName = new JTextField();
|
||||
mConfigurationName.setEnabled( false );
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
} );
|
||||
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
add( mConfigurationName, "span 2" );
|
||||
|
||||
|
||||
mTunerInfo = new JButton( "Tuner Info" );
|
||||
mTunerInfo.setEnabled( false );
|
||||
mTunerInfo.addActionListener( new ActionListener()
|
||||
@@ -103,189 +116,189 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
} );
|
||||
add( mTunerInfo );
|
||||
|
||||
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner "
|
||||
+ "Controller - couldn't apply frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "FuncubeDonglePro Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value, e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection, "wrap" );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner "
|
||||
+ "Controller - couldn't apply frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "FuncubeDonglePro Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value, e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection, "wrap" );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
add( new JLabel( "Gain" ), "span,align center" );
|
||||
|
||||
mComboLNAGain = new JComboBox<FCD1TunerController.LNAGain>( FCD1TunerController.LNAGain.values() );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.setToolTipText( "Adjust the low noise amplifier gain setting." );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mComboLNAGain = new JComboBox<LNAGain>( LNAGain.values() );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.setToolTipText( "Adjust the low noise amplifier gain setting." );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
FCD1TunerController.LNAGain gain = (FCD1TunerController.LNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
LNAGain gain = (LNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
mController.setLNAGain( gain );
|
||||
save();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner Controller"
|
||||
+ " - error setting LNA gain [" + gain.toString() + "]" );
|
||||
|
||||
mLog.error( "FuncubeDonglePro Controller - error setting gain [" + gain.toString() + "]", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "LNA:" ) );
|
||||
add( mComboLNAGain );
|
||||
|
||||
/**
|
||||
* LNA Enhance
|
||||
*/
|
||||
mComboLNAEnhance = new JComboBox<FCD1TunerController.LNAEnhance>( FCD1TunerController.LNAEnhance.values() );
|
||||
mComboLNAEnhance.setToolTipText( "Adjust the LNA enhance setting. Default value is OFF" );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner Controller"
|
||||
+ " - error setting LNA gain [" + gain.toString() + "]" );
|
||||
|
||||
mComboLNAEnhance.addActionListener( new ActionListener()
|
||||
{
|
||||
mLog.error( "FuncubeDonglePro Controller - error setting gain [" + gain.toString() + "]", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "LNA:" ) );
|
||||
add( mComboLNAGain );
|
||||
|
||||
/**
|
||||
* LNA Enhance
|
||||
*/
|
||||
mComboLNAEnhance = new JComboBox<LNAEnhance>( LNAEnhance.values() );
|
||||
mComboLNAEnhance.setToolTipText( "Adjust the LNA enhance setting. Default value is OFF" );
|
||||
|
||||
mComboLNAEnhance.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
FCD1TunerController.LNAEnhance enhance = (FCD1TunerController.LNAEnhance)mComboLNAEnhance.getSelectedItem();
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
LNAEnhance enhance = (LNAEnhance)mComboLNAEnhance.getSelectedItem();
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
mController.setLNAEnhance( enhance );
|
||||
save();
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner"
|
||||
+ " error setting LNA enhance gain [" + enhance.toString() + "]" );
|
||||
|
||||
mLog.error( "FCDPro - error setting LNA enhance [" + enhance.toString() + "]", e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "Enhance:" ) );
|
||||
add( mComboLNAEnhance );
|
||||
|
||||
/**
|
||||
* Mixer Gain
|
||||
*/
|
||||
mComboMixerGain = new JComboBox<FCD1TunerController.MixerGain>( FCD1TunerController.MixerGain.values() );
|
||||
mComboMixerGain.setToolTipText( "Adjust mixer gain setting" );
|
||||
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCD Pro Tuner"
|
||||
+ " error setting LNA enhance gain [" + enhance.toString() + "]" );
|
||||
|
||||
mComboMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mLog.error( "FCDPro - error setting LNA enhance [" + enhance.toString() + "]", e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "Enhance:" ) );
|
||||
add( mComboLNAEnhance );
|
||||
|
||||
/**
|
||||
* Mixer Gain
|
||||
*/
|
||||
mComboMixerGain = new JComboBox<MixerGain>( MixerGain.values() );
|
||||
mComboMixerGain.setToolTipText( "Adjust mixer gain setting" );
|
||||
|
||||
|
||||
mComboMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
FCD1TunerController.MixerGain gain = (FCD1TunerController.MixerGain)mComboMixerGain.getSelectedItem();
|
||||
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
MixerGain gain = (MixerGain)mComboMixerGain.getSelectedItem();
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
mController.setMixerGain( gain );
|
||||
save();
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCDPro - error setting"
|
||||
+ " mixer gain [" + gain.toString() + "]" );
|
||||
|
||||
mLog.error( "FCDPro - error setting mixer gain [" + gain.toString() + "]", e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "Mixer:" ) );
|
||||
add( mComboMixerGain, "wrap" );
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCDPro - error setting"
|
||||
+ " mixer gain [" + gain.toString() + "]" );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
mLog.error( "FCDPro - error setting mixer gain [" + gain.toString() + "]", e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "Mixer:" ) );
|
||||
add( mComboMixerGain, "wrap" );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
add( new JLabel( "Correction" ), "span,align center" );
|
||||
|
||||
/**
|
||||
* Inphase DC Correction
|
||||
*/
|
||||
mCorrectionDCI = new CorrectionSpinner( Correction.DC_INPHASE, 0.0, 0.00001, 5 );
|
||||
mCorrectionDCI.setEnabled( false );
|
||||
mCorrectionDCI.setToolTipText( "DC Bias Correction/Inphase "
|
||||
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "DC Inphase:" ) );
|
||||
add( mCorrectionDCI );
|
||||
/**
|
||||
* Inphase DC Correction
|
||||
*/
|
||||
mCorrectionDCI = new CorrectionSpinner( Correction.DC_INPHASE, 0.0, 0.00001, 5 );
|
||||
mCorrectionDCI.setEnabled( false );
|
||||
mCorrectionDCI.setToolTipText( "DC Bias Correction/Inphase "
|
||||
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "DC Inphase:" ) );
|
||||
add( mCorrectionDCI );
|
||||
|
||||
/**
|
||||
* Quadrature DC Correction
|
||||
*/
|
||||
mCorrectionDCQ = new CorrectionSpinner( Correction.DC_QUADRATURE, 0.0, 0.00001, 5 );
|
||||
mCorrectionDCQ.setToolTipText( "DC Bias Correction/Quadrature "
|
||||
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "DC Quadrature:" ) );
|
||||
add( mCorrectionDCQ );
|
||||
/**
|
||||
* Quadrature DC Correction
|
||||
*/
|
||||
mCorrectionDCQ = new CorrectionSpinner( Correction.DC_QUADRATURE, 0.0, 0.00001, 5 );
|
||||
mCorrectionDCQ.setToolTipText( "DC Bias Correction/Quadrature "
|
||||
+ "Component: valid values are -1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "DC Quadrature:" ) );
|
||||
add( mCorrectionDCQ );
|
||||
|
||||
/**
|
||||
* Gain Correction
|
||||
*/
|
||||
mCorrectionGain = new CorrectionSpinner( Correction.GAIN, 0.0, 0.00001, 5 );
|
||||
mCorrectionGain.setToolTipText( "Gain Correction: valid values are "
|
||||
+ "-1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "Gain:" ) );
|
||||
add( mCorrectionGain );
|
||||
/**
|
||||
* Gain Correction
|
||||
*/
|
||||
mCorrectionGain = new CorrectionSpinner( Correction.GAIN, 0.0, 0.00001, 5 );
|
||||
mCorrectionGain.setToolTipText( "Gain Correction: valid values are "
|
||||
+ "-1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "Gain:" ) );
|
||||
add( mCorrectionGain );
|
||||
|
||||
/**
|
||||
* Phase Correction
|
||||
*/
|
||||
mCorrectionPhase = new CorrectionSpinner( Correction.PHASE, 0.0, 0.00001, 5 );
|
||||
mCorrectionPhase.setToolTipText( "Phase Correction: valid values are "
|
||||
+ "-1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "Phase:" ) );
|
||||
add( mCorrectionPhase );
|
||||
}
|
||||
/**
|
||||
* Phase Correction
|
||||
*/
|
||||
mCorrectionPhase = new CorrectionSpinner( Correction.PHASE, 0.0, 0.00001, 5 );
|
||||
mCorrectionPhase.setToolTipText( "Phase Correction: valid values are "
|
||||
+ "-1.0 to 1.0 (default: 0.0)" );
|
||||
add( new JLabel( "Phase:" ) );
|
||||
add( mCorrectionPhase );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each of the tuner configuration controls to the enabled argument state
|
||||
@@ -296,12 +309,12 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mConfigurationName.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mTunerInfo.isEnabled() != enabled )
|
||||
{
|
||||
mTunerInfo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mFrequencyCorrection.isEnabled() != enabled )
|
||||
{
|
||||
mFrequencyCorrection.setEnabled( enabled );
|
||||
@@ -311,32 +324,32 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mComboLNAEnhance.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mComboLNAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mComboMixerGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMixerGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mCorrectionDCI.isEnabled() != enabled )
|
||||
{
|
||||
mCorrectionDCI.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mCorrectionDCQ.isEnabled() != enabled )
|
||||
{
|
||||
mCorrectionDCQ.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mCorrectionGain.isEnabled() != enabled )
|
||||
{
|
||||
mCorrectionGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mCorrectionPhase.isEnabled() != enabled )
|
||||
{
|
||||
mCorrectionPhase.setEnabled( enabled );
|
||||
@@ -348,7 +361,7 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "<html><h3>Funcube Dongle Pro Tuner</h3>" );
|
||||
|
||||
|
||||
sb.append( "<b>USB ID: </b>" );
|
||||
sb.append( mController.getUSBID() );
|
||||
sb.append( "<br>" );
|
||||
@@ -371,37 +384,37 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
FCD1TunerConfiguration config = getConfiguration();
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
FCD1TunerConfiguration config = getConfiguration();
|
||||
|
||||
config.setName( mConfigurationName.getText() );
|
||||
config.setName( mConfigurationName.getText() );
|
||||
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
config.setLNAEnhance( (FCD1TunerController.LNAEnhance)mComboLNAEnhance.getSelectedItem() );
|
||||
config.setLNAGain( (FCD1TunerController.LNAGain)mComboLNAGain.getSelectedItem() );
|
||||
config.setMixerGain( (FCD1TunerController.MixerGain)mComboMixerGain.getSelectedItem() );
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
config.setLNAEnhance( (LNAEnhance)mComboLNAEnhance.getSelectedItem() );
|
||||
config.setLNAGain( (LNAGain)mComboLNAGain.getSelectedItem() );
|
||||
config.setMixerGain( (MixerGain)mComboMixerGain.getSelectedItem() );
|
||||
|
||||
double dci = ((SpinnerNumberModel)mCorrectionDCI.getModel()).getNumber().doubleValue();
|
||||
config.setInphaseDCCorrection( dci );
|
||||
|
||||
config.setInphaseDCCorrection( dci );
|
||||
|
||||
double dcq = ((SpinnerNumberModel)mCorrectionDCQ.getModel()).getNumber().doubleValue();
|
||||
config.setQuadratureDCCorrection( dcq );
|
||||
|
||||
config.setQuadratureDCCorrection( dcq );
|
||||
|
||||
double gain = ((SpinnerNumberModel)mCorrectionGain.getModel()).getNumber().doubleValue();
|
||||
config.setGainCorrection( gain );
|
||||
|
||||
config.setGainCorrection( gain );
|
||||
|
||||
double phase = ((SpinnerNumberModel)mCorrectionPhase.getModel()).getNumber().doubleValue();
|
||||
config.setPhaseCorrection( phase );
|
||||
|
||||
getTunerConfigurationModel().broadcast( new TunerConfigurationEvent( getConfiguration(), TunerConfigurationEvent.Event.CHANGE ) );
|
||||
}
|
||||
config.setPhaseCorrection( phase );
|
||||
|
||||
getTunerConfigurationModel().broadcast( new TunerConfigurationEvent( getConfiguration(), Event.CHANGE ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -415,19 +428,19 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
if( hasItem() )
|
||||
{
|
||||
FCD1TunerConfiguration config = getConfiguration();
|
||||
|
||||
|
||||
if( tunerConfiguration.isAssigned() )
|
||||
{
|
||||
setControlsEnabled( true );
|
||||
mConfigurationName.setText( config.getName() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mComboLNAEnhance.setSelectedItem( config.getLNAEnhance() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboMixerGain.setSelectedItem( config.getMixerGain() );
|
||||
mCorrectionDCI.setValue( config.getInphaseDCCorrection() );
|
||||
mCorrectionDCQ.setValue( config.getQuadratureDCCorrection() );
|
||||
mCorrectionGain.setValue( config.getGainCorrection() );
|
||||
mCorrectionPhase.setValue( config.getPhaseCorrection() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mComboLNAEnhance.setSelectedItem( config.getLNAEnhance() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboMixerGain.setSelectedItem( config.getMixerGain() );
|
||||
mCorrectionDCI.setValue( config.getInphaseDCCorrection() );
|
||||
mCorrectionDCQ.setValue( config.getQuadratureDCCorrection() );
|
||||
mCorrectionGain.setValue( config.getGainCorrection() );
|
||||
mCorrectionPhase.setValue( config.getPhaseCorrection() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -440,44 +453,44 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( "" );
|
||||
}
|
||||
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
|
||||
public enum Correction { GAIN, PHASE, DC_INPHASE, DC_QUADRATURE };
|
||||
|
||||
public class CorrectionSpinner extends JSpinner
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final double MIN_VALUE = -1.0d;
|
||||
private static final double MAX_VALUE = 1.0d;
|
||||
|
||||
private Correction mCorrectionComponent;
|
||||
|
||||
public enum Correction { GAIN, PHASE, DC_INPHASE, DC_QUADRATURE };
|
||||
|
||||
public class CorrectionSpinner extends JSpinner
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final double MIN_VALUE = -1.0d;
|
||||
private static final double MAX_VALUE = 1.0d;
|
||||
|
||||
private Correction mCorrectionComponent;
|
||||
|
||||
public CorrectionSpinner( Correction component, double initialValue, double step, int decimalPlaces )
|
||||
{
|
||||
{
|
||||
mCorrectionComponent = component;
|
||||
|
||||
SpinnerModel model = new SpinnerNumberModel( initialValue, MIN_VALUE, MAX_VALUE, step );
|
||||
setModel( model );
|
||||
|
||||
JSpinner.NumberEditor editor = (JSpinner.NumberEditor)getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( decimalPlaces );
|
||||
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
SpinnerModel model = new SpinnerNumberModel( initialValue, MIN_VALUE, MAX_VALUE, step );
|
||||
setModel( model );
|
||||
|
||||
addChangeListener( new ChangeListener()
|
||||
{
|
||||
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 =
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
double value =
|
||||
((SpinnerNumberModel)getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
switch( mCorrectionComponent )
|
||||
{
|
||||
case DC_INPHASE:
|
||||
@@ -493,20 +506,20 @@ public class FCD1TunerEditor extends TunerConfigurationEditor
|
||||
mController.setPhaseCorrection( value );
|
||||
break;
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCDPro - error "
|
||||
+ "applying " + mCorrectionComponent.toString() + " correction value ["
|
||||
+ value + "]" );
|
||||
|
||||
mLog.error( "FCDPro - error applying "+ mCorrectionComponent.toString()
|
||||
+ " correction value [" + value + "]", e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( Exception e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD1TunerEditor.this, "FCDPro - error "
|
||||
+ "applying " + mCorrectionComponent.toString() + " correction value ["
|
||||
+ value + "]" );
|
||||
|
||||
mLog.error( "FCDPro - error applying "+ mCorrectionComponent.toString()
|
||||
+ " correction value [" + value + "]", e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
package io.github.dsheirer.source.tuner.fcd.proplusV2;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.MixerTunerDataLine;
|
||||
import io.github.dsheirer.source.tuner.MixerTunerType;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
@@ -41,11 +42,10 @@ public class FCD2TunerController extends FCDTunerController
|
||||
public static final int MAXIMUM_TUNABLE_FREQUENCY = 2050000000;
|
||||
public static final int SAMPLE_RATE = 192000;
|
||||
|
||||
public FCD2TunerController(Device device, DeviceDescriptor descriptor)
|
||||
public FCD2TunerController(MixerTunerDataLine mixerTDL, Device device, DeviceDescriptor descriptor)
|
||||
{
|
||||
super(device, descriptor,
|
||||
(int)MixerTunerType.FUNCUBE_DONGLE_PRO_PLUS.getAudioFormat().getSampleRate(),
|
||||
MINIMUM_TUNABLE_FREQUENCY, MAXIMUM_TUNABLE_FREQUENCY);
|
||||
super(mixerTDL, device, descriptor, MixerTunerType.FUNCUBE_DONGLE_PRO_PLUS.getDisplayString(),
|
||||
MINIMUM_TUNABLE_FREQUENCY, MAXIMUM_TUNABLE_FREQUENCY, MixerTunerType.FUNCUBE_DONGLE_PRO.getAudioFormat());
|
||||
}
|
||||
|
||||
public void init() throws SourceException
|
||||
@@ -64,7 +64,7 @@ public class FCD2TunerController extends FCDTunerController
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentSampleRate()
|
||||
public double getCurrentSampleRate()
|
||||
{
|
||||
return SAMPLE_RATE;
|
||||
}
|
||||
@@ -200,39 +200,4 @@ public class FCD2TunerController extends FCDTunerController
|
||||
mLog.error("error setting IQ correction to [" + value + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,16 @@ import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -40,24 +49,24 @@ import java.text.DecimalFormat;
|
||||
public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( FCD2TunerEditor.class );
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JCheckBox mLNAGain;
|
||||
private JCheckBox mMixerGain;
|
||||
private boolean mLoading;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private FCD2TunerController mController;
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JCheckBox mLNAGain;
|
||||
private JCheckBox mMixerGain;
|
||||
private boolean mLoading;
|
||||
|
||||
public FCD2TunerEditor( TunerConfigurationModel tunerConfigurationModel, FCDTuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (FCD2TunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
private FCD2TunerController mController;
|
||||
|
||||
public FCD2TunerEditor( TunerConfigurationModel tunerConfigurationModel, FCDTuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (FCD2TunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private FCD2TunerConfiguration getConfiguration()
|
||||
{
|
||||
@@ -65,33 +74,33 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
return (FCD2TunerConfiguration)getItem();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][grow]" ) );
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][grow]" ) );
|
||||
|
||||
add( new JLabel( "FCD Pro+ Tuner Configuration" ), "span,align center" );
|
||||
|
||||
mConfigurationName = new JTextField();
|
||||
mConfigurationName.setEnabled( false );
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
} );
|
||||
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
add( mConfigurationName, "span 2" );
|
||||
|
||||
|
||||
mTunerInfo = new JButton( "Tuner Info" );
|
||||
mTunerInfo.setEnabled( false );
|
||||
mTunerInfo.addActionListener( new ActionListener()
|
||||
@@ -99,103 +108,103 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD2TunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
JOptionPane.showMessageDialog( FCD2TunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
} );
|
||||
add( mTunerInfo );
|
||||
|
||||
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD2TunerEditor.this, "FCD Pro Plus Tuner "
|
||||
+ "Controller - couldn't apply frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "FuncubeDongleProPlus Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value, e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection, "wrap" );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( FCD2TunerEditor.this, "FCD Pro Plus Tuner "
|
||||
+ "Controller - couldn't apply frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
mLNAGain = new JCheckBox( "LNA Gain" );
|
||||
mLNAGain.setEnabled( false );
|
||||
mLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent event )
|
||||
{
|
||||
try
|
||||
{
|
||||
mController.setLNAGain( mLNAGain.isSelected() );
|
||||
save();
|
||||
}
|
||||
catch( SourceException e )
|
||||
{
|
||||
mLog.error( "Couldn't set LNA gain for FCD2", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mLog.error( "FuncubeDongleProPlus Controller - couldn't apply "
|
||||
+ "frequency correction value: " + value, e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "" ) );
|
||||
add( mLNAGain );
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection, "wrap" );
|
||||
|
||||
/**
|
||||
* Mixer Gain
|
||||
*/
|
||||
mMixerGain = new JCheckBox( "Mixer Gain" );
|
||||
|
||||
mMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent event )
|
||||
{
|
||||
try
|
||||
{
|
||||
mController.setMixerGain( mMixerGain.isSelected() );
|
||||
save();
|
||||
}
|
||||
catch( SourceException e )
|
||||
{
|
||||
mLog.error( "Couldn't set mixer gain for FCD2", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
|
||||
add( new JLabel( "" ) );
|
||||
add( mMixerGain );
|
||||
}
|
||||
mLNAGain = new JCheckBox( "LNA Gain" );
|
||||
mLNAGain.setEnabled( false );
|
||||
mLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent event )
|
||||
{
|
||||
try
|
||||
{
|
||||
mController.setLNAGain( mLNAGain.isSelected() );
|
||||
save();
|
||||
}
|
||||
catch( SourceException e )
|
||||
{
|
||||
mLog.error( "Couldn't set LNA gain for FCD2", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "" ) );
|
||||
add( mLNAGain );
|
||||
|
||||
/**
|
||||
* Mixer Gain
|
||||
*/
|
||||
mMixerGain = new JCheckBox( "Mixer Gain" );
|
||||
|
||||
mMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent event )
|
||||
{
|
||||
try
|
||||
{
|
||||
mController.setMixerGain( mMixerGain.isSelected() );
|
||||
save();
|
||||
}
|
||||
catch( SourceException e )
|
||||
{
|
||||
mLog.error( "Couldn't set mixer gain for FCD2", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "" ) );
|
||||
add( mMixerGain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each of the tuner configuration controls to the enabled argument state
|
||||
@@ -206,12 +215,12 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mConfigurationName.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mTunerInfo.isEnabled() != enabled )
|
||||
{
|
||||
mTunerInfo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mFrequencyCorrection.isEnabled() != enabled )
|
||||
{
|
||||
mFrequencyCorrection.setEnabled( enabled );
|
||||
@@ -221,7 +230,7 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mMixerGain.isEnabled() != enabled )
|
||||
{
|
||||
mMixerGain.setEnabled( enabled );
|
||||
@@ -233,7 +242,7 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "<html><h3>Funcube Dongle Pro Plus Tuner</h3>" );
|
||||
|
||||
|
||||
sb.append( "<b>USB ID: </b>" );
|
||||
sb.append( mController.getUSBID() );
|
||||
sb.append( "<br>" );
|
||||
@@ -256,26 +265,26 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
FCD2TunerConfiguration config = getConfiguration();
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
FCD2TunerConfiguration config = getConfiguration();
|
||||
|
||||
config.setName( mConfigurationName.getText() );
|
||||
config.setName( mConfigurationName.getText() );
|
||||
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
|
||||
config.setGainLNA( mLNAGain.isSelected() );
|
||||
config.setGainMixer( mMixerGain.isSelected() );
|
||||
|
||||
getTunerConfigurationModel().broadcast(
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
|
||||
config.setGainLNA( mLNAGain.isSelected() );
|
||||
config.setGainMixer( mMixerGain.isSelected() );
|
||||
|
||||
getTunerConfigurationModel().broadcast(
|
||||
new TunerConfigurationEvent( getConfiguration(), Event.CHANGE ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -289,15 +298,15 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
if( hasItem() )
|
||||
{
|
||||
FCD2TunerConfiguration config = getConfiguration();
|
||||
|
||||
|
||||
|
||||
|
||||
if( tunerConfiguration.isAssigned() )
|
||||
{
|
||||
setControlsEnabled( true );
|
||||
mConfigurationName.setText( config.getName() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mLNAGain.setSelected( config.getGainLNA() );
|
||||
mMixerGain.setSelected( config.getGainMixer() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mLNAGain.setSelected( config.getGainLNA() );
|
||||
mMixerGain.setSelected( config.getGainMixer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -310,7 +319,7 @@ public class FCD2TunerEditor extends TunerConfigurationEditor
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( "" );
|
||||
}
|
||||
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +1,127 @@
|
||||
package io.github.dsheirer.source.tuner.frequency;
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import io.github.dsheirer.source.ISourceEventProvider;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class DCTrackingFrequencyControl extends Module
|
||||
implements Listener<RealBuffer>, IFrequencyChangeProvider
|
||||
public class DCTrackingFrequencyControl extends Module implements Listener<RealBuffer>, ISourceEventProvider
|
||||
{
|
||||
private static float COARSE_THRESHOLD = 0.1f;
|
||||
private static float LOOP_GAIN = 0.1f;
|
||||
private static float COARSE_GAIN = 1000.0f;
|
||||
private static float FINE_GAIN = 100.0f;
|
||||
private int mErrorCorrection = 0;
|
||||
private int mMaximumFrequencyCorrection = 0;
|
||||
private Listener<FrequencyChangeEvent> mListener;
|
||||
|
||||
/**
|
||||
* DC offset Automatic Frequency Control. Monitors DC bias present in an FM
|
||||
* demodulated audio stream and issues automatic frequency corrections to
|
||||
* maintain the DC bias close to zero.
|
||||
*
|
||||
* @param maximum - maximum allowable (+/-) frequency correction value.
|
||||
*/
|
||||
public DCTrackingFrequencyControl( int maximum )
|
||||
{
|
||||
mMaximumFrequencyCorrection = maximum;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
private static float COARSE_THRESHOLD = 0.1f;
|
||||
private static float LOOP_GAIN = 0.1f;
|
||||
private static float COARSE_GAIN = 1000.0f;
|
||||
private static float FINE_GAIN = 100.0f;
|
||||
private int mErrorCorrection = 0;
|
||||
private int mMaximumFrequencyCorrection = 0;
|
||||
private Listener<SourceEvent> mListener;
|
||||
|
||||
@Override
|
||||
public void receive( RealBuffer buffer )
|
||||
{
|
||||
double sum = 0.0d;
|
||||
|
||||
for( float sample: buffer.getSamples() )
|
||||
{
|
||||
sum += sample;
|
||||
}
|
||||
|
||||
float mean = (float)( sum / (double)buffer.getSamples().length );
|
||||
|
||||
float adjustment = 0.0f;
|
||||
|
||||
if( mean > COARSE_THRESHOLD || mean < - COARSE_THRESHOLD )
|
||||
{
|
||||
adjustment = mean * COARSE_GAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustment = mean * FINE_GAIN;
|
||||
}
|
||||
/**
|
||||
* DC offset Automatic Frequency Control. Monitors DC bias present in an FM
|
||||
* demodulated audio stream and issues automatic frequency corrections to
|
||||
* maintain the DC bias close to zero.
|
||||
*
|
||||
* @param maximum - maximum allowable (+/-) frequency correction value.
|
||||
*/
|
||||
public DCTrackingFrequencyControl(int maximum)
|
||||
{
|
||||
mMaximumFrequencyCorrection = maximum;
|
||||
}
|
||||
|
||||
setErrorCorrection( mErrorCorrection + (int)( (float)adjustment * LOOP_GAIN ) );
|
||||
}
|
||||
|
||||
private void setErrorCorrection( int correction )
|
||||
{
|
||||
if( mListener != null )
|
||||
{
|
||||
if( correction > mMaximumFrequencyCorrection )
|
||||
{
|
||||
correction = mMaximumFrequencyCorrection;
|
||||
}
|
||||
else if( correction < -mMaximumFrequencyCorrection )
|
||||
{
|
||||
correction = -mMaximumFrequencyCorrection;
|
||||
}
|
||||
|
||||
if( correction != mErrorCorrection )
|
||||
{
|
||||
mListener.receive( new FrequencyChangeEvent(
|
||||
Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, correction ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
public void dispose()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
@Override
|
||||
public void receive(RealBuffer buffer)
|
||||
{
|
||||
double sum = 0.0d;
|
||||
|
||||
@Override
|
||||
public void start( ScheduledExecutorService executor )
|
||||
{
|
||||
}
|
||||
for(float sample : buffer.getSamples())
|
||||
{
|
||||
sum += sample;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
float mean = (float)(sum / (double)buffer.getSamples().length);
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
setErrorCorrection( 0 );
|
||||
}
|
||||
float adjustment = 0.0f;
|
||||
|
||||
if(mean > COARSE_THRESHOLD || mean < -COARSE_THRESHOLD)
|
||||
{
|
||||
adjustment = mean * COARSE_GAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustment = mean * FINE_GAIN;
|
||||
}
|
||||
|
||||
setErrorCorrection(mErrorCorrection + (int)((float)adjustment * LOOP_GAIN));
|
||||
}
|
||||
|
||||
private void setErrorCorrection(int correction)
|
||||
{
|
||||
if(mListener != null)
|
||||
{
|
||||
if(correction > mMaximumFrequencyCorrection)
|
||||
{
|
||||
correction = mMaximumFrequencyCorrection;
|
||||
}
|
||||
else if(correction < -mMaximumFrequencyCorrection)
|
||||
{
|
||||
correction = -mMaximumFrequencyCorrection;
|
||||
}
|
||||
|
||||
if(correction != mErrorCorrection)
|
||||
{
|
||||
mListener.receive(SourceEvent.channelFrequencyCorrectionRequest(correction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
setErrorCorrection(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package io.github.dsheirer.source.tuner.frequency;
|
||||
|
||||
public class FrequencyChangeEvent
|
||||
{
|
||||
public enum Event
|
||||
{
|
||||
NOTIFICATION_FREQUENCY_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
|
||||
REQUEST_FREQUENCY_CHANGE,
|
||||
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE;
|
||||
}
|
||||
|
||||
private Event mEvent;
|
||||
private Number mValue;
|
||||
|
||||
public FrequencyChangeEvent( Event event, Number value )
|
||||
{
|
||||
mEvent = event;
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public Event getEvent()
|
||||
{
|
||||
return mEvent;
|
||||
}
|
||||
|
||||
public Number getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package io.github.dsheirer.source.tuner.frequency;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FrequencyChangeProcessorWrapper
|
||||
implements IFrequencyChangeListener, Listener<FrequencyChangeEvent>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( FrequencyChangeProcessorWrapper.class );
|
||||
|
||||
private IFrequencyChangeProcessor mProcessor;
|
||||
|
||||
/**
|
||||
* Provides IFrequencyChangeListener wrapper for an IFrequencyChangeProcessor
|
||||
*/
|
||||
public FrequencyChangeProcessorWrapper( IFrequencyChangeProcessor handler )
|
||||
{
|
||||
mProcessor = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( FrequencyChangeEvent event )
|
||||
{
|
||||
if( mProcessor != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessor.frequencyChanged( event );
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
mLog.error("Error sending frequency change event to embedded processor", se);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +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/>
|
||||
* *********************************************************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.frequency;
|
||||
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.InvalidFrequencyException;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FrequencyController
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( FrequencyController.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger(FrequencyController.class);
|
||||
|
||||
private Tunable mTunable;
|
||||
private long mFrequency = 101100000;
|
||||
private long mTunedFrequency = 101100000;
|
||||
private long mMinimumFrequency;
|
||||
private long mMaximumFrequency;
|
||||
private double mFrequencyCorrection = 0d;
|
||||
private int mSampleRate = 0;
|
||||
|
||||
private ArrayList<IFrequencyChangeProcessor> mProcessors = new ArrayList<>();
|
||||
|
||||
public FrequencyController( Tunable tunable,
|
||||
long minFrequency,
|
||||
long maxFrequency,
|
||||
double frequencyCorrection )
|
||||
private double mFrequencyCorrection = 0.0d;
|
||||
private double mSampleRate = 0.0d;
|
||||
|
||||
private List<ISourceEventProcessor> mProcessors = new ArrayList<>();
|
||||
|
||||
public FrequencyController(Tunable tunable, long minFrequency, long maxFrequency, double frequencyCorrection)
|
||||
{
|
||||
mTunable = tunable;
|
||||
mMinimumFrequency = minFrequency;
|
||||
@@ -51,23 +49,31 @@ public class FrequencyController
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bandwidth/sample rate in hertz
|
||||
* Get bandwidth in hertz
|
||||
*/
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mSampleRate;
|
||||
return (int)mSampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sample rate in hertz
|
||||
*/
|
||||
public void setSampleRate( int sampleRate ) throws SourceException
|
||||
public void setSampleRate(int sampleRate) throws SourceException
|
||||
{
|
||||
mSampleRate = sampleRate;
|
||||
|
||||
|
||||
broadcastSampleRateChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sample rate in hertz
|
||||
*/
|
||||
public double getSampleRate()
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get frequency in hertz
|
||||
*/
|
||||
@@ -78,13 +84,24 @@ public class FrequencyController
|
||||
|
||||
/**
|
||||
* Set frequency
|
||||
*
|
||||
* @param frequency in hertz
|
||||
* @throws SourceException if tunable doesn't support tuning a corrected
|
||||
* version of the requested frequency
|
||||
* version of the requested frequency
|
||||
*/
|
||||
public void setFrequency( long frequency ) throws SourceException
|
||||
public void setFrequency(long frequency) throws SourceException
|
||||
{
|
||||
setFrequency( frequency, true );
|
||||
setFrequency(frequency, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the specified frequency can be tuned (ie is within min/max frequency) by this controller.
|
||||
* @param frequency to evaluate
|
||||
* @return true if the frequency falls within the tuning range of this controller
|
||||
*/
|
||||
public boolean canTune(long frequency)
|
||||
{
|
||||
return getMinimumFrequency() <= frequency && frequency <= getMaximumFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,149 +109,147 @@ public class FrequencyController
|
||||
* method supports changing the frequency correction value without
|
||||
* broadcasting a frequency change event.
|
||||
*/
|
||||
private void setFrequency( long frequency, boolean broadcastChange ) throws SourceException
|
||||
private void setFrequency(long frequency, boolean broadcastChange) throws SourceException
|
||||
{
|
||||
long tunedFrequency = getTunedFrequency( frequency );
|
||||
|
||||
if( tunedFrequency < mMinimumFrequency )
|
||||
long tunedFrequency = getTunedFrequency(frequency);
|
||||
|
||||
if(tunedFrequency < mMinimumFrequency)
|
||||
{
|
||||
throw new InvalidFrequencyException( "Requested frequency not valid", frequency, mMinimumFrequency );
|
||||
throw new InvalidFrequencyException("Requested frequency not valid", frequency, mMinimumFrequency);
|
||||
}
|
||||
|
||||
if( tunedFrequency > mMaximumFrequency )
|
||||
if(tunedFrequency > mMaximumFrequency)
|
||||
{
|
||||
throw new InvalidFrequencyException( "Requested frequency not valid", frequency, mMaximumFrequency );
|
||||
throw new InvalidFrequencyException("Requested frequency not valid", frequency, mMaximumFrequency);
|
||||
}
|
||||
|
||||
mFrequency = frequency;
|
||||
|
||||
mTunedFrequency = tunedFrequency;
|
||||
|
||||
if( mTunable != null )
|
||||
if(mTunable != null)
|
||||
{
|
||||
mTunable.setTunedFrequency( mTunedFrequency );
|
||||
mTunable.setTunedFrequency(mTunedFrequency);
|
||||
}
|
||||
|
||||
/* Broadcast to all listeners that the frequency has changed */
|
||||
if( broadcastChange )
|
||||
if(broadcastChange)
|
||||
{
|
||||
broadcastFrequencyChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public long getTunedFrequency()
|
||||
{
|
||||
return mTunedFrequency;
|
||||
}
|
||||
|
||||
|
||||
public long getMinimumFrequency()
|
||||
{
|
||||
return mMinimumFrequency;
|
||||
}
|
||||
|
||||
|
||||
public long getMaximumFrequency()
|
||||
{
|
||||
return mMaximumFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the tuned frequency by adding frequency correction to the
|
||||
* corrected frequency.
|
||||
* @param correctedFrequency
|
||||
*/
|
||||
private long getTunedFrequency( long correctedFrequency )
|
||||
{
|
||||
return (long)( (double)correctedFrequency /
|
||||
( 1.0 + ( mFrequencyCorrection / 1000000.0 ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the corrected frequency by subtracting frequency correction
|
||||
* from the tuned frequency.
|
||||
* @param tunedFrequency
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private long getCorrectedFrequency( long tunedFrequency )
|
||||
{
|
||||
return (long)( (double)tunedFrequency /
|
||||
( 1.0 - ( mFrequencyCorrection / 1000000.0 ) ) );
|
||||
}
|
||||
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double correction ) throws SourceException
|
||||
{
|
||||
mFrequencyCorrection = correction;
|
||||
/**
|
||||
* Calculate the tuned frequency by adding frequency correction to the
|
||||
* corrected frequency.
|
||||
*
|
||||
* @param correctedFrequency
|
||||
*/
|
||||
private long getTunedFrequency(long correctedFrequency)
|
||||
{
|
||||
return (long)((double)correctedFrequency /
|
||||
(1.0 + (mFrequencyCorrection / 1000000.0)));
|
||||
}
|
||||
|
||||
if( mFrequency > 0 )
|
||||
{
|
||||
setFrequency( mFrequency, true );
|
||||
}
|
||||
/**
|
||||
* Calculate the corrected frequency by subtracting frequency correction
|
||||
* from the tuned frequency.
|
||||
*
|
||||
* @param tunedFrequency
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private long getCorrectedFrequency(long tunedFrequency)
|
||||
{
|
||||
return (long)((double)tunedFrequency /
|
||||
(1.0 - (mFrequencyCorrection / 1000000.0)));
|
||||
}
|
||||
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection(double correction) throws SourceException
|
||||
{
|
||||
mFrequencyCorrection = correction;
|
||||
|
||||
if(mFrequency > 0)
|
||||
{
|
||||
setFrequency(mFrequency, true);
|
||||
}
|
||||
|
||||
broadcastFrequencyCorrectionChange();
|
||||
}
|
||||
|
||||
broadcastFrequencyErrorChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds listener to receive frequency change events
|
||||
*/
|
||||
//TODO: rename this to addFrequencyChangeProcessor()
|
||||
public void addListener( IFrequencyChangeProcessor processor )
|
||||
public void addListener(ISourceEventProcessor processor)
|
||||
{
|
||||
if( !mProcessors.contains( processor ) )
|
||||
if(!mProcessors.contains(processor))
|
||||
{
|
||||
mProcessors.add( processor );
|
||||
mProcessors.add(processor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes listener from receiving frequency change events
|
||||
*/
|
||||
public void removeFrequencyChangeProcessor( IFrequencyChangeProcessor processor )
|
||||
public void removeFrequencyChangeProcessor(ISourceEventProcessor processor)
|
||||
{
|
||||
mProcessors.remove( processor );
|
||||
mProcessors.remove(processor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Broadcasts a change/update to the current (uncorrected) frequency or the
|
||||
* bandwidth/sample rate value.
|
||||
*/
|
||||
protected void broadcastFrequencyChange() throws SourceException
|
||||
{
|
||||
broadcastFrequencyChangeEvent(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CHANGE, mFrequency ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast a frequency error/correction value change
|
||||
*/
|
||||
protected void broadcastFrequencyErrorChange() throws SourceException
|
||||
{
|
||||
broadcastFrequencyChangeEvent(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CORRECTION_CHANGE, mFrequencyCorrection ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a sample rate change
|
||||
*/
|
||||
protected void broadcastSampleRateChange() throws SourceException
|
||||
{
|
||||
broadcastFrequencyChangeEvent(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_SAMPLE_RATE_CHANGE, mSampleRate ) );
|
||||
}
|
||||
|
||||
public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event ) throws SourceException
|
||||
{
|
||||
for( IFrequencyChangeProcessor processor: mProcessors )
|
||||
{
|
||||
processor.frequencyChanged( event );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Broadcasts a change/update to the current (uncorrected) frequency or the
|
||||
* bandwidth/sample rate value.
|
||||
*/
|
||||
protected void broadcastFrequencyChange() throws SourceException
|
||||
{
|
||||
broadcast(SourceEvent.frequencyChange(mFrequency));
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast a frequency error/correction value change
|
||||
*/
|
||||
protected void broadcastFrequencyCorrectionChange() throws SourceException
|
||||
{
|
||||
broadcast(SourceEvent.frequencyCorrectionChange((int)mFrequencyCorrection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a sample rate change
|
||||
*/
|
||||
protected void broadcastSampleRateChange() throws SourceException
|
||||
{
|
||||
broadcast(SourceEvent.sampleRateChange(mSampleRate));
|
||||
}
|
||||
|
||||
public void broadcast(SourceEvent event) throws SourceException
|
||||
{
|
||||
for(ISourceEventProcessor processor : mProcessors)
|
||||
{
|
||||
processor.process(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface Tunable
|
||||
{
|
||||
/**
|
||||
@@ -245,11 +260,16 @@ public class FrequencyController
|
||||
/**
|
||||
* Sets the tuned frequency of the device
|
||||
*/
|
||||
public void setTunedFrequency( long frequency ) throws SourceException;
|
||||
public void setTunedFrequency(long frequency) throws SourceException;
|
||||
|
||||
/**
|
||||
* Gets the current bandwidth setting of the device
|
||||
*/
|
||||
public int getCurrentSampleRate() throws SourceException;
|
||||
public double getCurrentSampleRate() throws SourceException;
|
||||
|
||||
/**
|
||||
* Indicates if this tunable can tune the frequency
|
||||
*/
|
||||
public boolean canTune(long frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.frequency;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for broadcasting changes to frequency, bandwidth, sample rate,
|
||||
* and actual sample rate values 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 IFrequencyChangeListener
|
||||
{
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener();
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package io.github.dsheirer.source.tuner.frequency;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
|
||||
public interface IFrequencyChangeProcessor
|
||||
{
|
||||
public void frequencyChanged( FrequencyChangeEvent event ) throws SourceException;
|
||||
}
|
||||
@@ -1,124 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.hackrf;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.hackrf.HackRFTunerController.BoardID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public class HackRFTuner extends Tuner
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( HackRFTuner.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger( HackRFTuner.class );
|
||||
|
||||
public HackRFTuner( HackRFTunerController controller ) throws SourceException
|
||||
{
|
||||
super( "HackRF", controller );
|
||||
}
|
||||
|
||||
public HackRFTunerController getController()
|
||||
{
|
||||
return (HackRFTunerController)getTunerController();
|
||||
}
|
||||
public HackRFTuner( HackRFTunerController controller ) throws SourceException
|
||||
{
|
||||
super( "HackRF", controller );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
//TODO: dispose of something here
|
||||
}
|
||||
|
||||
@Override
|
||||
public HackRFTunerController getController()
|
||||
{
|
||||
return (HackRFTunerController)getTunerController();
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return TunerClass.HACKRF_ONE;
|
||||
return TunerClass.HACKRF_ONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.HACKRF;
|
||||
return TunerType.HACKRF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleSize()
|
||||
{
|
||||
return 11.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel(TunerChannel channel )
|
||||
throws RejectedExecutionException, SourceException
|
||||
@Override
|
||||
public double getSampleSize()
|
||||
{
|
||||
TunerChannelSource source = getController().getChannel( this, channel );
|
||||
|
||||
if( source != null )
|
||||
{
|
||||
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
|
||||
}
|
||||
|
||||
return source;
|
||||
return 11.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseChannel( TunerChannelSource source )
|
||||
{
|
||||
/* Unregister for receiving samples */
|
||||
removeListener( (Listener<ComplexBuffer>)source );
|
||||
|
||||
/* Tell the controller to release the channel and cleanup */
|
||||
if( source != null )
|
||||
{
|
||||
getController().releaseChannel( source );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getController().getSerial().getSerialNumber();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
mLog.error( "error gettting serial number", e );
|
||||
}
|
||||
|
||||
return HackRFTunerController.BoardID.HACKRF_ONE.getLabel();
|
||||
try
|
||||
{
|
||||
return getController().getSerial().getSerialNumber();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
mLog.error( "error gettting serial number", e );
|
||||
}
|
||||
|
||||
return BoardID.HACKRF_ONE.getLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
getController().addListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
getController().removeListener( listener );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,13 +53,11 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.hackrf;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ByteSampleAdapter;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTransferProcessor;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTunerController;
|
||||
import org.apache.commons.io.EndianUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -74,7 +72,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class HackRFTunerController extends TunerController
|
||||
public class HackRFTunerController extends USBTunerController
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(HackRFTunerController.class);
|
||||
|
||||
@@ -158,6 +156,12 @@ public class HackRFTunerController extends TunerController
|
||||
mUSBTransferProcessor = new USBTransferProcessor(name, mDeviceHandle, mSampleAdapter, USB_TRANSFER_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected USBTransferProcessor getUSBTransferProcessor()
|
||||
{
|
||||
return mUSBTransferProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Claims the USB interface. If another application currently has
|
||||
* the interface claimed, the USB_FORCE_CLAIM_INTERFACE setting
|
||||
@@ -328,7 +332,7 @@ public class HackRFTunerController extends TunerController
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentSampleRate() throws SourceException
|
||||
public double getCurrentSampleRate()
|
||||
{
|
||||
return mSampleRate.getRate();
|
||||
}
|
||||
@@ -522,7 +526,7 @@ public class HackRFTunerController extends TunerController
|
||||
write(Request.SET_SAMPLE_RATE, 0, 0, buffer);
|
||||
}
|
||||
|
||||
public int getSampleRate()
|
||||
public double getSampleRate()
|
||||
{
|
||||
return mSampleRate.getRate();
|
||||
}
|
||||
@@ -872,23 +876,4 @@ public class HackRFTunerController extends TunerController
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sample listener. If the buffer processing thread is
|
||||
* not currently running, starts it running in a new thread.
|
||||
*/
|
||||
public void addListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mUSBTransferProcessor.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the sample listener. If this is the last registered listener,
|
||||
* shuts down the buffer processing thread.
|
||||
*/
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mUSBTransferProcessor.removeListener(listener);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.hackrf;
|
||||
|
||||
@@ -22,11 +20,24 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEditor;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||
import io.github.dsheirer.source.tuner.hackrf.HackRFTunerController.HackRFLNAGain;
|
||||
import io.github.dsheirer.source.tuner.hackrf.HackRFTunerController.HackRFSampleRate;
|
||||
import io.github.dsheirer.source.tuner.hackrf.HackRFTunerController.HackRFVGAGain;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.usb.UsbException;
|
||||
@@ -40,196 +51,196 @@ public class HackRFTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final static Logger mLog = LoggerFactory.getLogger( HackRFTunerEditor.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger( HackRFTunerEditor.class );
|
||||
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JComboBox<HackRFTunerController.HackRFSampleRate> mComboSampleRate;
|
||||
private JComboBox<HackRFSampleRate> mComboSampleRate;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JToggleButton mAmplifier;
|
||||
private JComboBox<HackRFTunerController.HackRFLNAGain> mComboLNAGain;
|
||||
private JComboBox<HackRFTunerController.HackRFVGAGain> mComboVGAGain;
|
||||
private JComboBox<HackRFLNAGain> mComboLNAGain;
|
||||
private JComboBox<HackRFVGAGain> mComboVGAGain;
|
||||
private boolean mLoading;
|
||||
|
||||
private HackRFTunerController mController;
|
||||
|
||||
public HackRFTunerEditor(TunerConfigurationModel tunerConfigurationModel, HackRFTuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
|
||||
mController = tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
public HackRFTunerEditor( TunerConfigurationModel tunerConfigurationModel, HackRFTuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
|
||||
private HackRFTunerConfiguration getConfiguration()
|
||||
{
|
||||
if( hasItem() )
|
||||
{
|
||||
return (HackRFTunerConfiguration)getItem();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
mController = tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private HackRFTunerConfiguration getConfiguration()
|
||||
{
|
||||
if( hasItem() )
|
||||
{
|
||||
return (HackRFTunerConfiguration)getItem();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][grow]" ) );
|
||||
|
||||
add( new JLabel( "HackRF Tuner Configuration" ), "span,align center" );
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][grow]" ) );
|
||||
|
||||
mConfigurationName = new JTextField();
|
||||
mConfigurationName.setEnabled( false );
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override
|
||||
add( new JLabel( "HackRF Tuner Configuration" ), "span,align center" );
|
||||
|
||||
mConfigurationName = new JTextField();
|
||||
mConfigurationName.setEnabled( false );
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
save();
|
||||
save();
|
||||
}
|
||||
@Override
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
} );
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
add( mConfigurationName, "span 2" );
|
||||
|
||||
mTunerInfo = new JButton( "Tuner Info" );
|
||||
mTunerInfo.setEnabled( false );
|
||||
mTunerInfo.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
} );
|
||||
add( mTunerInfo );
|
||||
|
||||
mComboSampleRate = new JComboBox<>( HackRFTunerController.HackRFSampleRate.values() );
|
||||
mComboSampleRate.setEnabled( false );
|
||||
mComboSampleRate.addActionListener( new ActionListener()
|
||||
} );
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
add( mConfigurationName, "span 2" );
|
||||
|
||||
mTunerInfo = new JButton( "Tuner Info" );
|
||||
mTunerInfo.setEnabled( false );
|
||||
mTunerInfo.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
HackRFTunerController.HackRFSampleRate sampleRate =
|
||||
(HackRFTunerController.HackRFSampleRate)mComboSampleRate.getSelectedItem();
|
||||
try
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
} );
|
||||
add( mTunerInfo );
|
||||
|
||||
mComboSampleRate = new JComboBox<>( HackRFSampleRate.values() );
|
||||
mComboSampleRate.setEnabled( false );
|
||||
mComboSampleRate.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
HackRFSampleRate sampleRate =
|
||||
(HackRFSampleRate)mComboSampleRate.getSelectedItem();
|
||||
try
|
||||
{
|
||||
|
||||
mController.setSampleRate( sampleRate );
|
||||
save();
|
||||
mController.setSampleRate( sampleRate );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException |UsbException e2 )
|
||||
catch ( SourceException|UsbException e2 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply the sample rate setting [" + sampleRate.getLabel() +
|
||||
"] " + e2.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply sample rate setting [" +
|
||||
sampleRate.getLabel() + "]", e );
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply the sample rate setting [" + sampleRate.getLabel() +
|
||||
"] " + e2.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply sample rate setting [" +
|
||||
sampleRate.getLabel() + "]", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( new JLabel( "Sample Rate:" ) );
|
||||
add( mComboSampleRate );
|
||||
|
||||
|
||||
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
JSpinner.NumberEditor editor = (JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
JSpinner.NumberEditor editor = (JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
final double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
final double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply frequency correction "
|
||||
+ "value: " + value, e1 );
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply frequency correction value: " + value +
|
||||
e1.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply frequency correction "
|
||||
+ "value: " + value, e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
add( new JLabel( "Gain" ) );
|
||||
add( new JLabel( "" ), "span 2" ); //filler
|
||||
|
||||
|
||||
mAmplifier = new JToggleButton( "Amplifier" );
|
||||
mAmplifier.setEnabled( false );
|
||||
mAmplifier.addActionListener( new ActionListener()
|
||||
mAmplifier.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
mController.setAmplifierEnabled( mAmplifier.isSelected() );
|
||||
save();
|
||||
mController.setAmplifierEnabled( mAmplifier.isSelected() );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
mLog.error( "couldn't enable/disable amplifier", e );
|
||||
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "Couldn't change amplifier setting",
|
||||
"Error changing amplifier setting", JOptionPane.ERROR_MESSAGE );
|
||||
mLog.error( "couldn't enable/disable amplifier", e );
|
||||
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "Couldn't change amplifier setting",
|
||||
"Error changing amplifier setting", JOptionPane.ERROR_MESSAGE );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( mAmplifier );
|
||||
|
||||
mComboLNAGain = new JComboBox<HackRFTunerController.HackRFLNAGain>( HackRFTunerController.HackRFLNAGain.values() );
|
||||
|
||||
mComboLNAGain = new JComboBox<HackRFLNAGain>( HackRFLNAGain.values() );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
HackRFTunerController.HackRFLNAGain lnaGain = (HackRFTunerController.HackRFLNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
if ( lnaGain == null )
|
||||
{
|
||||
lnaGain = HackRFTunerController.HackRFLNAGain.GAIN_0;
|
||||
}
|
||||
|
||||
mController.setLNAGain( lnaGain );
|
||||
save();
|
||||
HackRFLNAGain lnaGain = (HackRFLNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
if ( lnaGain == null )
|
||||
{
|
||||
lnaGain = HackRFLNAGain.GAIN_0;
|
||||
}
|
||||
|
||||
mController.setLNAGain( lnaGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply the LNA gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply LNA gain setting - ", e );
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply the LNA gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply LNA gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
@@ -237,30 +248,30 @@ public class HackRFTunerEditor extends TunerConfigurationEditor
|
||||
add( new JLabel( "LNA:" ) );
|
||||
add( mComboLNAGain );
|
||||
|
||||
mComboVGAGain = new JComboBox<HackRFTunerController.HackRFVGAGain>( HackRFTunerController.HackRFVGAGain.values() );
|
||||
mComboVGAGain.addActionListener( new ActionListener()
|
||||
mComboVGAGain = new JComboBox<HackRFVGAGain>( HackRFVGAGain.values() );
|
||||
mComboVGAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
HackRFTunerController.HackRFVGAGain vgaGain = (HackRFTunerController.HackRFVGAGain)mComboVGAGain.getSelectedItem();
|
||||
HackRFVGAGain vgaGain = (HackRFVGAGain)mComboVGAGain.getSelectedItem();
|
||||
|
||||
if( vgaGain == null )
|
||||
{
|
||||
vgaGain = HackRFTunerController.HackRFVGAGain.GAIN_4;
|
||||
}
|
||||
|
||||
mController.setVGAGain( vgaGain );
|
||||
save();
|
||||
if( vgaGain == null )
|
||||
{
|
||||
vgaGain = HackRFVGAGain.GAIN_4;
|
||||
}
|
||||
|
||||
mController.setVGAGain( vgaGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply the VGA gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply VGA gain setting", e );
|
||||
JOptionPane.showMessageDialog( HackRFTunerEditor.this, "HackRF Tuner Controller"
|
||||
+ " - couldn't apply the VGA gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "HackRF Tuner Controller - couldn't apply VGA gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
@@ -269,177 +280,177 @@ public class HackRFTunerEditor extends TunerConfigurationEditor
|
||||
add( mComboVGAGain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each of the tuner configuration controls to the enabled argument state
|
||||
*/
|
||||
private void setControlsEnabled( boolean enabled )
|
||||
{
|
||||
if( mConfigurationName.isEnabled() != enabled )
|
||||
{
|
||||
mConfigurationName.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mTunerInfo.isEnabled() != enabled )
|
||||
{
|
||||
mTunerInfo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mFrequencyCorrection.isEnabled() != enabled )
|
||||
{
|
||||
mFrequencyCorrection.setEnabled( enabled );
|
||||
}
|
||||
/**
|
||||
* Sets each of the tuner configuration controls to the enabled argument state
|
||||
*/
|
||||
private void setControlsEnabled( boolean enabled )
|
||||
{
|
||||
if( mConfigurationName.isEnabled() != enabled )
|
||||
{
|
||||
mConfigurationName.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mTunerInfo.isEnabled() != enabled )
|
||||
{
|
||||
mTunerInfo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mFrequencyCorrection.isEnabled() != enabled )
|
||||
{
|
||||
mFrequencyCorrection.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboSampleRate.isEnabled() != enabled )
|
||||
{
|
||||
mComboSampleRate.setEnabled( enabled );
|
||||
mComboSampleRate.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mAmplifier.isEnabled() != enabled )
|
||||
{
|
||||
mAmplifier.setEnabled( enabled );
|
||||
mAmplifier.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboLNAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboLNAGain.setEnabled( enabled );
|
||||
mComboLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mComboVGAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboVGAGain.setEnabled( enabled );
|
||||
mComboVGAGain.setEnabled( enabled );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getTunerInfo()
|
||||
{
|
||||
HackRFTunerController.BoardID board = HackRFTunerController.BoardID.INVALID;
|
||||
private String getTunerInfo()
|
||||
{
|
||||
HackRFTunerController.BoardID board = HackRFTunerController.BoardID.INVALID;
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
board = mController.getBoardID();
|
||||
board = mController.getBoardID();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
mLog.error( "couldn't read HackRF board identifier", e );
|
||||
mLog.error( "couldn't read HackRF board identifier", e );
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "<html><h3>HackRF Tuner</h3>" );
|
||||
sb.append( "<html><h3>HackRF Tuner</h3>" );
|
||||
|
||||
sb.append( "<b>Board: </b>" );
|
||||
sb.append( board.getLabel() );
|
||||
sb.append( "<br>" );
|
||||
sb.append( "<b>Board: </b>" );
|
||||
sb.append( board.getLabel() );
|
||||
sb.append( "<br>" );
|
||||
|
||||
HackRFTunerController.Serial serial = null;
|
||||
|
||||
try
|
||||
{
|
||||
serial = mController.getSerial();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
mLog.error( "couldn't read HackRF serial number", e );
|
||||
}
|
||||
|
||||
if( serial != null )
|
||||
{
|
||||
sb.append( "<b>Serial: </b>" );
|
||||
sb.append( serial.getSerialNumber() );
|
||||
sb.append( "<br>" );
|
||||
|
||||
sb.append( "<b>Part: </b>" );
|
||||
sb.append( serial.getPartID() );
|
||||
sb.append( "<br>" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "<b>Serial: Unknown</b><br>" );
|
||||
sb.append( "<b>Part: Unknown</b><br>" );
|
||||
}
|
||||
|
||||
String firmware = null;
|
||||
|
||||
try
|
||||
{
|
||||
firmware = mController.getFirmwareVersion();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
mLog.error( "couldn't read HackRF firmware version", e );
|
||||
}
|
||||
|
||||
if( firmware != null )
|
||||
{
|
||||
sb.append( "<b>Firmware: </b>" );
|
||||
sb.append( firmware );
|
||||
sb.append( "<br>" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "<b>Firmware: Unknown</b><br>" );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
HackRFTunerController.Serial serial = null;
|
||||
|
||||
@Override
|
||||
public void setItem( TunerConfiguration tunerConfiguration )
|
||||
{
|
||||
super.setItem( tunerConfiguration );
|
||||
try
|
||||
{
|
||||
serial = mController.getSerial();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
mLog.error( "couldn't read HackRF serial number", e );
|
||||
}
|
||||
|
||||
//Toggle loading so that we don't fire a change event and schedule a settings file save
|
||||
mLoading = true;
|
||||
if( serial != null )
|
||||
{
|
||||
sb.append( "<b>Serial: </b>" );
|
||||
sb.append( serial.getSerialNumber() );
|
||||
sb.append( "<br>" );
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
HackRFTunerConfiguration config = getConfiguration();
|
||||
|
||||
if( tunerConfiguration.isAssigned() )
|
||||
{
|
||||
setControlsEnabled( true );
|
||||
|
||||
mConfigurationName.setText( config.getName() );
|
||||
mComboSampleRate.setSelectedItem( config.getSampleRate() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mAmplifier.setSelected( config.getAmplifierEnabled() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboVGAGain.setSelectedItem( config.getVGAGain() );
|
||||
}
|
||||
else
|
||||
{
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( config.getName() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( "" );
|
||||
}
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
sb.append( "<b>Part: </b>" );
|
||||
sb.append( serial.getPartID() );
|
||||
sb.append( "<br>" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "<b>Serial: Unknown</b><br>" );
|
||||
sb.append( "<b>Part: Unknown</b><br>" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
HackRFTunerConfiguration config = getConfiguration();
|
||||
String firmware = null;
|
||||
|
||||
config.setName( mConfigurationName.getText() );
|
||||
try
|
||||
{
|
||||
firmware = mController.getFirmwareVersion();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
mLog.error( "couldn't read HackRF firmware version", e );
|
||||
}
|
||||
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
config.setSampleRate( (HackRFTunerController.HackRFSampleRate)mComboSampleRate.getSelectedItem() );
|
||||
config.setAmplifierEnabled( mAmplifier.isSelected() );
|
||||
config.setLNAGain( (HackRFTunerController.HackRFLNAGain)mComboLNAGain.getSelectedItem() );
|
||||
config.setVGAGain( (HackRFTunerController.HackRFVGAGain)mComboVGAGain.getSelectedItem() );
|
||||
|
||||
getTunerConfigurationModel().broadcast(
|
||||
new TunerConfigurationEvent( getConfiguration(), TunerConfigurationEvent.Event.CHANGE ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( firmware != null )
|
||||
{
|
||||
sb.append( "<b>Firmware: </b>" );
|
||||
sb.append( firmware );
|
||||
sb.append( "<br>" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "<b>Firmware: Unknown</b><br>" );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem( TunerConfiguration tunerConfiguration )
|
||||
{
|
||||
super.setItem( tunerConfiguration );
|
||||
|
||||
//Toggle loading so that we don't fire a change event and schedule a settings file save
|
||||
mLoading = true;
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
HackRFTunerConfiguration config = getConfiguration();
|
||||
|
||||
if( tunerConfiguration.isAssigned() )
|
||||
{
|
||||
setControlsEnabled( true );
|
||||
|
||||
mConfigurationName.setText( config.getName() );
|
||||
mComboSampleRate.setSelectedItem( config.getSampleRate() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mAmplifier.setSelected( config.getAmplifierEnabled() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboVGAGain.setSelectedItem( config.getVGAGain() );
|
||||
}
|
||||
else
|
||||
{
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( config.getName() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( "" );
|
||||
}
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
HackRFTunerConfiguration config = getConfiguration();
|
||||
|
||||
config.setName( mConfigurationName.getText() );
|
||||
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
config.setSampleRate( (HackRFSampleRate)mComboSampleRate.getSelectedItem() );
|
||||
config.setAmplifierEnabled( mAmplifier.isSelected() );
|
||||
config.setLNAGain( (HackRFLNAGain)mComboLNAGain.getSelectedItem() );
|
||||
config.setVGAGain( (HackRFVGAGain)mComboVGAGain.getSelectedItem() );
|
||||
|
||||
getTunerConfigurationModel().broadcast(
|
||||
new TunerConfigurationEvent( getConfiguration(), TunerConfigurationEvent.Event.CHANGE ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.manager;
|
||||
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.IComplexBufferProvider;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface to define the functionality of a source manager for handling tuner channel management, complex buffer
|
||||
* listeners, and source event listeners.
|
||||
*/
|
||||
public abstract class AbstractSourceManager implements IComplexBufferProvider, Listener<SourceEvent>
|
||||
{
|
||||
protected Broadcaster<ComplexBuffer> mComplexBufferBroadcaster = new Broadcaster<>();
|
||||
|
||||
/**
|
||||
* Indicates if this source manager can tune (ie provide a source for) the specified tuner channel
|
||||
*/
|
||||
public abstract boolean canTune(TunerChannel tunerChannel);
|
||||
|
||||
/**
|
||||
* List of tuner channels being sourced by this source manager
|
||||
*/
|
||||
public abstract List<TunerChannel> getChannels();
|
||||
|
||||
/**
|
||||
* Obtains a source for the tuner channel or returns null if the channel cannot be sourced by this tuner.
|
||||
* Note: use the canTune() method to check if a tuner channel can be sourced/tuned prior to accessing this method.
|
||||
*
|
||||
* @param tunerChannel for requested source
|
||||
* @return tuner channel source or null
|
||||
*/
|
||||
public abstract TunerChannelSource getSource(TunerChannel tunerChannel);
|
||||
|
||||
|
||||
/**
|
||||
* Releases the source and all related resources
|
||||
*/
|
||||
public abstract void releaseSource(TunerChannelSource source);
|
||||
|
||||
/**
|
||||
* Adds the listener to receive source events from this source manager
|
||||
*
|
||||
* @param sourceEventListener to add
|
||||
*/
|
||||
public abstract void addSourceEventListener(Listener<SourceEvent> sourceEventListener);
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving source events from this source manager
|
||||
* @param sourceEventListener to remove
|
||||
*/
|
||||
public abstract void removeSourceEventListener(Listener<SourceEvent> sourceEventListener);
|
||||
|
||||
/**
|
||||
* Adds the listener to receive complex buffer samples
|
||||
*/
|
||||
@Override
|
||||
public void addComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mComplexBufferBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving complex buffer samples
|
||||
*/
|
||||
@Override
|
||||
public void removeComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mComplexBufferBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if there are any complex buffer listeners registered with this source manager
|
||||
*/
|
||||
@Override
|
||||
public boolean hasComplexBufferListeners()
|
||||
{
|
||||
return mComplexBufferBroadcaster.hasListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the buffer to any registered listeners
|
||||
*/
|
||||
protected void broadcast(ComplexBuffer complexBuffer)
|
||||
{
|
||||
mComplexBufferBroadcaster.broadcast(complexBuffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.manager;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelManager;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TunerSourceManager extends AbstractSourceManager
|
||||
{
|
||||
private PolyphaseChannelManager mPolyphaseChannelManager;
|
||||
private TunerController mTunerController;
|
||||
|
||||
public TunerSourceManager(TunerController tunerController)
|
||||
{
|
||||
mTunerController = tunerController;
|
||||
}
|
||||
|
||||
//TODO: broadcast a tuner event each time we add a new channel to the polyphase manager
|
||||
|
||||
@Override
|
||||
public boolean canTune(TunerChannel tunerChannel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TunerChannel> getChannels()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getSource(TunerChannel tunerChannel)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSource(TunerChannelSource source)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSourceEventListener(Listener<SourceEvent> sourceEventListener)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSourceEventListener(Listener<SourceEvent> sourceEventListener)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,143 +17,59 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.rtl;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.LibUsbException;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public class RTL2832Tuner extends Tuner
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( RTL2832Tuner.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger(RTL2832Tuner.class);
|
||||
|
||||
private TunerClass mTunerClass;
|
||||
private TunerClass mTunerClass;
|
||||
|
||||
public RTL2832Tuner( TunerClass tunerClass,
|
||||
RTL2832TunerController controller )
|
||||
throws SourceException
|
||||
{
|
||||
super( tunerClass.getVendorDeviceLabel() + "/" +
|
||||
controller.getTunerType().getLabel() + " " +
|
||||
controller.getUniqueID(), controller );
|
||||
|
||||
mTunerClass = tunerClass;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
//TODO: dispose of something here
|
||||
}
|
||||
|
||||
public RTL2832TunerController getController()
|
||||
{
|
||||
return (RTL2832TunerController)getTunerController();
|
||||
}
|
||||
public RTL2832Tuner(TunerClass tunerClass, RTL2832TunerController controller) throws SourceException
|
||||
{
|
||||
super(tunerClass.getVendorDeviceLabel() + "/" + controller.getTunerType().getLabel() + " " +
|
||||
controller.getUniqueID(), controller);
|
||||
|
||||
@Override
|
||||
mTunerClass = tunerClass;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public RTL2832TunerController getController()
|
||||
{
|
||||
return (RTL2832TunerController)getTunerController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
return getController().getUniqueID();
|
||||
return getController().getUniqueID();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return mTunerClass;
|
||||
return mTunerClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return getController().getTunerType();
|
||||
return getController().getTunerType();
|
||||
}
|
||||
|
||||
public void setSampleRate( RTL2832TunerController.SampleRate sampleRate ) throws SourceException
|
||||
{
|
||||
try
|
||||
{
|
||||
getController().setSampleRate( sampleRate );
|
||||
}
|
||||
catch( LibUsbException e )
|
||||
{
|
||||
throw new SourceException( "RTL2832 Tuner - error setting "
|
||||
+ "sample rate", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleSize()
|
||||
{
|
||||
//Note: although sample size is 8, we set it to 11 to align with the
|
||||
//actual noise floor.
|
||||
return 11.0;
|
||||
}
|
||||
|
||||
public void setFrequency( int frequency ) throws SourceException
|
||||
{
|
||||
getController().setFrequency( frequency );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerChannelSource getChannel(TunerChannel channel )
|
||||
throws RejectedExecutionException,
|
||||
SourceException
|
||||
{
|
||||
TunerChannelSource source = null;
|
||||
|
||||
try
|
||||
{
|
||||
source = getController().getChannel( this, channel );
|
||||
|
||||
if( source != null )
|
||||
{
|
||||
broadcast( new TunerEvent( this, TunerEvent.Event.CHANNEL_COUNT ) );
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
mLog.error( "couldn't provide source channel", e );
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the tuned channel so that the tuner controller can tune to
|
||||
* other frequencies as needed.
|
||||
*/
|
||||
@Override
|
||||
public void releaseChannel( TunerChannelSource source )
|
||||
@Override
|
||||
public double getSampleSize()
|
||||
{
|
||||
/* Unregister for receiving samples */
|
||||
removeListener( (Listener<ComplexBuffer>)source );
|
||||
|
||||
/* Tell the controller to release the channel and cleanup */
|
||||
if( source != null )
|
||||
{
|
||||
getController().releaseChannel( source );
|
||||
}
|
||||
//Note: although sample size is 8, we set it to 11 to align with the
|
||||
//actual noise floor.
|
||||
return 11.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
getController().addListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
getController().removeListener( listener );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,10 @@ import io.github.dsheirer.sample.adapter.ByteSampleAdapter;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTransferProcessor;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTunerController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.Device;
|
||||
@@ -46,7 +46,7 @@ import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public abstract class RTL2832TunerController extends TunerController
|
||||
public abstract class RTL2832TunerController extends USBTunerController
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(RTL2832TunerController.class);
|
||||
|
||||
@@ -162,6 +162,12 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
USB_TRANSFER_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected USBTransferProcessor getUSBTransferProcessor()
|
||||
{
|
||||
return mUSBTransferProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Claims the USB interface. Attempts to detach the active kernel driver
|
||||
* if one is currently attached.
|
||||
@@ -238,21 +244,21 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
/* Set intermediate frequency to 0 Hz */
|
||||
setIFFrequency(0);
|
||||
|
||||
/* Enable I/Q ADC Input */
|
||||
/* Enable I/Q ADC Input */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ZERO,
|
||||
(short) 0x08,
|
||||
(short) 0xCD,
|
||||
1);
|
||||
|
||||
/* Enable zero-IF mode */
|
||||
|
||||
/* Enable zero-IF mode */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ONE,
|
||||
(short) 0xB1,
|
||||
(short) 0x1B,
|
||||
1);
|
||||
|
||||
/* Set default i/q path */
|
||||
|
||||
/* Set default i/q path */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ZERO,
|
||||
(short) 0x06,
|
||||
@@ -271,21 +277,21 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
long ifFrequency = ((long) TWO_TO_22_POWER * (long) frequency) /
|
||||
(long) mOscillatorFrequency * -1;
|
||||
|
||||
/* Write byte 2 (high) */
|
||||
/* Write byte 2 (high) */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ONE,
|
||||
(short) 0x19,
|
||||
(short) (Long.rotateRight(ifFrequency, 16) & 0x3F),
|
||||
1);
|
||||
|
||||
/* Write byte 1 (middle) */
|
||||
|
||||
/* Write byte 1 (middle) */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ONE,
|
||||
(short) 0x1A,
|
||||
(short) (Long.rotateRight(ifFrequency, 8) & 0xFF),
|
||||
1);
|
||||
|
||||
/* Write byte 0 (low) */
|
||||
|
||||
/* Write byte 0 (low) */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ONE,
|
||||
(short) 0x1B,
|
||||
@@ -341,8 +347,8 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
try
|
||||
{
|
||||
claimInterface(handle);
|
||||
|
||||
/* Perform a dummy write to see if the device needs reset */
|
||||
|
||||
/* Perform a dummy write to see if the device needs reset */
|
||||
boolean resetRequired = false;
|
||||
|
||||
try
|
||||
@@ -392,14 +398,14 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the baseband */
|
||||
/* Initialize the baseband */
|
||||
initBaseband(handle);
|
||||
|
||||
enableI2CRepeater(handle, true);
|
||||
|
||||
boolean controlI2CRepeater = false;
|
||||
|
||||
/* Test for each tuner type until we find the correct one */
|
||||
/* Test for each tuner type until we find the correct one */
|
||||
if(isTuner(TunerTypeCheck.E4K, handle, controlI2CRepeater))
|
||||
{
|
||||
tunerClass = TunerType.ELONICS_E4000;
|
||||
@@ -448,7 +454,7 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
{
|
||||
if(mUSBTransferProcessor != null)
|
||||
{
|
||||
mUSBTransferProcessor.removeAllListeners();
|
||||
mUSBTransferProcessor.removeListener();
|
||||
TunerManager.LIBUSB_TRANSFER_PROCESSOR.unregisterTransferProcessor(mUSBTransferProcessor);
|
||||
}
|
||||
|
||||
@@ -468,32 +474,32 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
|
||||
public static void initBaseband(DeviceHandle handle) throws LibUsbException
|
||||
{
|
||||
/* Initialize USB */
|
||||
/* Initialize USB */
|
||||
writeRegister(handle, Block.USB, Address.USB_SYSCTL.getAddress(), 0x09, 1);
|
||||
writeRegister(handle, Block.USB, Address.USB_EPA_MAXPKT.getAddress(), 0x0002, 2);
|
||||
writeRegister(handle, Block.USB, Address.USB_EPA_CTL.getAddress(), 0x1002, 2);
|
||||
|
||||
/* Power on demod */
|
||||
/* Power on demod */
|
||||
writeRegister(handle, Block.SYS, Address.DEMOD_CTL_1.getAddress(), 0x22, 1);
|
||||
writeRegister(handle, Block.SYS, Address.DEMOD_CTL.getAddress(), 0xE8, 1);
|
||||
|
||||
/* Reset demod */
|
||||
/* Reset demod */
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x01, 0x14, 1); //Bit 3 = soft reset
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x01, 0x10, 1);
|
||||
|
||||
/* Disable spectrum inversion and adjacent channel rejection */
|
||||
|
||||
/* Disable spectrum inversion and adjacent channel rejection */
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x15, 0x00, 1);
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x16, 0x0000, 2);
|
||||
|
||||
/* Clear DDC shift and IF frequency registers */
|
||||
/* Clear DDC shift and IF frequency registers */
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x16, 0x00, 1);
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x17, 0x00, 1);
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x18, 0x00, 1);
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x19, 0x00, 1);
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x1A, 0x00, 1);
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x1B, 0x00, 1);
|
||||
|
||||
/* Set FIR coefficients */
|
||||
|
||||
/* Set FIR coefficients */
|
||||
for(int x = 0; x < sFIR_COEFFICIENTS.length; x++)
|
||||
{
|
||||
writeDemodRegister(handle,
|
||||
@@ -502,32 +508,32 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
sFIR_COEFFICIENTS[x],
|
||||
1);
|
||||
}
|
||||
|
||||
/* Enable SDR mode, disable DAGC (bit 5) */
|
||||
|
||||
/* Enable SDR mode, disable DAGC (bit 5) */
|
||||
writeDemodRegister(handle, Page.ZERO, (short) 0x19, 0x05, 1);
|
||||
|
||||
/* Init FSM state-holding register */
|
||||
|
||||
/* Init FSM state-holding register */
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x93, 0xF0, 1);
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x94, 0x0F, 1);
|
||||
|
||||
/* Disable AGC (en_dagc, bit 0) (seems to have no effect) */
|
||||
|
||||
/* Disable AGC (en_dagc, bit 0) (seems to have no effect) */
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x11, 0x00, 1);
|
||||
|
||||
/* Disable RF and IF AGC loop */
|
||||
/* Disable RF and IF AGC loop */
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0x04, 0x00, 1);
|
||||
|
||||
/* Disable PID filter */
|
||||
|
||||
/* Disable PID filter */
|
||||
writeDemodRegister(handle, Page.ZERO, (short) 0x61, 0x60, 1);
|
||||
|
||||
/* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */
|
||||
/* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */
|
||||
writeDemodRegister(handle, Page.ZERO, (short) 0x06, 0x80, 1);
|
||||
|
||||
/* Enable Zero-if mode (en_bbin bit),
|
||||
* DC cancellation (en_dc_est),
|
||||
* IQ estimation/compensation (en_iq_comp, en_iq_est) */
|
||||
|
||||
/* Enable Zero-if mode (en_bbin bit),
|
||||
* DC cancellation (en_dc_est),
|
||||
* IQ estimation/compensation (en_iq_comp, en_iq_est) */
|
||||
writeDemodRegister(handle, Page.ONE, (short) 0xB1, 0x1B, 1);
|
||||
|
||||
/* Disable 4.096 MHz clock output on pin TP_CK0 */
|
||||
/* Disable 4.096 MHz clock output on pin TP_CK0 */
|
||||
writeDemodRegister(handle, Page.ZERO, (short) 0x0D, 0x83, 1);
|
||||
}
|
||||
|
||||
@@ -896,10 +902,10 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
if(type == TunerTypeCheck.FC0012 ||
|
||||
type == TunerTypeCheck.FC2580)
|
||||
{
|
||||
/* Initialize the GPIOs */
|
||||
/* Initialize the GPIOs */
|
||||
setGPIOOutput(handle, (byte) 0x20);
|
||||
|
||||
/* Reset tuner before probing */
|
||||
/* Reset tuner before probing */
|
||||
setGPIOBit(handle, (byte) 0x20, true);
|
||||
setGPIOBit(handle, (byte) 0x20, false);
|
||||
}
|
||||
@@ -924,7 +930,7 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getCurrentSampleRate() throws SourceException
|
||||
public double getCurrentSampleRate()
|
||||
{
|
||||
return mSampleRate.getRate();
|
||||
}
|
||||
@@ -942,7 +948,7 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
|
||||
SampleRate sampleRate = SampleRate.getClosest(rate);
|
||||
|
||||
/* If we're not currently set to this rate, set it as the current rate */
|
||||
/* If we're not currently set to this rate, set it as the current rate */
|
||||
if(sampleRate.getRate() != rate)
|
||||
{
|
||||
setSampleRate(sampleRate);
|
||||
@@ -961,23 +967,23 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
|
||||
public void setSampleRate(SampleRate sampleRate) throws SourceException
|
||||
{
|
||||
/* Write high-order 16-bits of sample rate ratio to demod register */
|
||||
/* Write high-order 16-bits of sample rate ratio to demod register */
|
||||
writeDemodRegister(mDeviceHandle, Page.ONE, (short) 0x9F,
|
||||
sampleRate.getRatioHighBits(), 2);
|
||||
|
||||
/* Write low-order 16-bits of sample rate ratio to demod register.
|
||||
* Note: none of the defined rates have a low order ratio value, so we
|
||||
* simply write a zero to the register */
|
||||
|
||||
/* Write low-order 16-bits of sample rate ratio to demod register.
|
||||
* Note: none of the defined rates have a low order ratio value, so we
|
||||
* simply write a zero to the register */
|
||||
writeDemodRegister(mDeviceHandle, Page.ONE, (short) 0xA1, 0, 2);
|
||||
|
||||
/* Set sample rate correction to 0 */
|
||||
|
||||
/* Set sample rate correction to 0 */
|
||||
setSampleRateFrequencyCorrection(0);
|
||||
|
||||
/* Reset the demod for the changes to take effect */
|
||||
/* Reset the demod for the changes to take effect */
|
||||
writeDemodRegister(mDeviceHandle, Page.ONE, (short) 0x01, 0x14, 1);
|
||||
writeDemodRegister(mDeviceHandle, Page.ONE, (short) 0x01, 0x10, 1);
|
||||
|
||||
/* Apply any tuner specific sample rate filter settings */
|
||||
/* Apply any tuner specific sample rate filter settings */
|
||||
setSampleRateFilters(sampleRate.getRate());
|
||||
|
||||
mSampleRate = sampleRate;
|
||||
@@ -999,7 +1005,7 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
(short) 0x3E,
|
||||
(Integer.rotateRight(offset, 8) & 0xFF),
|
||||
1);
|
||||
/* Test to retune controller to apply frequency correction */
|
||||
/* Test to retune controller to apply frequency correction */
|
||||
try
|
||||
{
|
||||
mFrequencyController.setFrequency(mFrequencyController.getFrequency());
|
||||
@@ -1052,7 +1058,7 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
|
||||
try
|
||||
{
|
||||
/* Tell the RTL-2832 to address the EEPROM */
|
||||
/* Tell the RTL-2832 to address the EEPROM */
|
||||
writeRegister(handle, Block.I2C, EEPROM_ADDRESS, (byte) offset, 1);
|
||||
}
|
||||
catch(LibUsbException e)
|
||||
@@ -1410,13 +1416,13 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
|
||||
private int getLabel(int start)
|
||||
{
|
||||
/* Validate length and check second byte for ETX (0x03) */
|
||||
/* Validate length and check second byte for ETX (0x03) */
|
||||
if(start > 254 || mData[start + 1] != (byte) 0x03)
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
|
||||
/* Get label length, including the length and ETX bytes */
|
||||
/* Get label length, including the length and ETX bytes */
|
||||
int length = 0xFF & mData[start];
|
||||
|
||||
if(start + length > 255)
|
||||
@@ -1424,10 +1430,10 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
return 256;
|
||||
}
|
||||
|
||||
/* Get the label bytes */
|
||||
/* Get the label bytes */
|
||||
byte[] data = Arrays.copyOfRange(mData, start + 2, start + length);
|
||||
|
||||
/* Translate the bytes as UTF-16 Little Endian and store the label */
|
||||
|
||||
/* Translate the bytes as UTF-16 Little Endian and store the label */
|
||||
String label = new String(data, Charset.forName("UTF-16LE"));
|
||||
|
||||
mLabels.add(label);
|
||||
@@ -1489,20 +1495,33 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sample listener. If the USB transfer processor is not currently running, it will auto-start
|
||||
* Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started.
|
||||
*/
|
||||
public void addListener(Listener<ComplexBuffer> listener)
|
||||
@Override
|
||||
public void addComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mUSBTransferProcessor.addListener(listener);
|
||||
boolean hasExistingListeners = hasComplexBufferListeners();
|
||||
|
||||
super.addComplexBufferListener(listener);
|
||||
|
||||
if(!hasExistingListeners)
|
||||
{
|
||||
mUSBTransferProcessor.setListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the sample listener. If this is the last registered listener, the USB transfer processor will
|
||||
* halt buffer processing
|
||||
* Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners.
|
||||
*/
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
@Override
|
||||
public void removeComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mUSBTransferProcessor.removeListener(listener);
|
||||
super.removeComplexBufferListener(listener);
|
||||
|
||||
if(!hasComplexBufferListeners())
|
||||
{
|
||||
mUSBTransferProcessor.removeListener();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1531,4 +1550,4 @@ public abstract class RTL2832TunerController extends TunerController
|
||||
resetUSBBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,8 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
|
||||
/* The local oscillator is defined by whole (integer) units of the oscillator
|
||||
* frequency and fractional units representing 1/65536th of the oscillator
|
||||
* frequency, meaning we can only tune the local oscillator in units of
|
||||
* 439.453125 hertz. */
|
||||
* frequency, meaning we can only tune the local oscillator in units of
|
||||
* 439.453125 hertz. */
|
||||
public static final long E4K_PLL_Y = 65536l; /* 16-bit fractional register */
|
||||
public static final byte MASTER1_RESET = (byte) 0x01;
|
||||
public static final byte MASTER1_NORM_STBY = (byte) 0x02;
|
||||
@@ -191,7 +191,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
|
||||
try
|
||||
{
|
||||
/* Read the contents of the 256-byte EEPROM */
|
||||
/* Read the contents of the 256-byte EEPROM */
|
||||
eeprom = readEEPROM(mDeviceHandle, (short) 0, 256);
|
||||
}
|
||||
catch(Exception e)
|
||||
@@ -218,7 +218,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
|
||||
try
|
||||
{
|
||||
/* Dummy write to test USB interface */
|
||||
/* Dummy write to test USB interface */
|
||||
writeRegister(mDeviceHandle, Block.USB,
|
||||
Address.USB_SYSCTL.getAddress(), (short) 0x09, 1);
|
||||
|
||||
@@ -263,7 +263,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
@Override
|
||||
public void setSampleRateFilters(int bandwidth) throws SourceException
|
||||
{
|
||||
/* Determine repeater state so we can restore it when done */
|
||||
/* Determine repeater state so we can restore it when done */
|
||||
boolean i2CRepeaterEnabled = isI2CRepeaterEnabled();
|
||||
|
||||
if(!i2CRepeaterEnabled)
|
||||
@@ -293,7 +293,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
{
|
||||
try
|
||||
{
|
||||
/* Determine repeater state so we can restore it when done */
|
||||
/* Determine repeater state so we can restore it when done */
|
||||
boolean i2CRepeaterEnabled = isI2CRepeaterEnabled();
|
||||
|
||||
if(!i2CRepeaterEnabled)
|
||||
@@ -313,7 +313,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
int pllSetting = readE4KRegister(Register.SYNTH7, controlI2CRepeater);
|
||||
PLL pll = PLL.fromSetting(pllSetting);
|
||||
|
||||
/* Return the repeater to its previous state */
|
||||
/* Return the repeater to its previous state */
|
||||
if(!i2CRepeaterEnabled)
|
||||
{
|
||||
enableI2CRepeater(mDeviceHandle, false);
|
||||
@@ -331,22 +331,22 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
@Override
|
||||
public void setTunedFrequency(long frequency) throws SourceException
|
||||
{
|
||||
/* Get the phase locked loop setting */
|
||||
/* Get the phase locked loop setting */
|
||||
PLL pll = PLL.fromFrequency(frequency);
|
||||
|
||||
/* Z is an integer representing the number of scaled oscillator frequency
|
||||
* increments the multiplied frequency. */
|
||||
/* Z is an integer representing the number of scaled oscillator frequency
|
||||
* increments the multiplied frequency. */
|
||||
byte z = (byte) (frequency / pll.getScaledOscillator());
|
||||
|
||||
/* remainder is just as it describes. It is what is left over after we
|
||||
* carve out scaled oscillator frequency increments (z) from the desired
|
||||
* frequency. */
|
||||
/* remainder is just as it describes. It is what is left over after we
|
||||
* carve out scaled oscillator frequency increments (z) from the desired
|
||||
* frequency. */
|
||||
int remainder = (int) (frequency - ((z & 0xFF) * pll.getScaledOscillator()));
|
||||
|
||||
/* X is a 16-bit representation of the remainder */
|
||||
/* X is a 16-bit representation of the remainder */
|
||||
int x = (int) ((double) remainder / (double) pll.getScaledOscillator() * E4K_PLL_Y);
|
||||
|
||||
/* Calculate the exact (tunable) frequency and apply that to the tuner */
|
||||
/* Calculate the exact (tunable) frequency and apply that to the tuner */
|
||||
long actualFrequency = calculateActualFrequency(pll, z, x);
|
||||
|
||||
/**
|
||||
@@ -360,34 +360,34 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
actualFrequency = calculateActualFrequency(pll, z, x);
|
||||
}
|
||||
|
||||
/* Apply the actual frequency */
|
||||
/* Apply the actual frequency */
|
||||
try
|
||||
{
|
||||
enableI2CRepeater(mDeviceHandle, true);
|
||||
|
||||
boolean controlI2CRepeater = false;
|
||||
|
||||
/* Write the PLL setting */
|
||||
/* Write the PLL setting */
|
||||
writeE4KRegister(Register.SYNTH7, pll.getIndex(), controlI2CRepeater);
|
||||
|
||||
/* Write z (integral) value */
|
||||
/* Write z (integral) value */
|
||||
writeE4KRegister(Register.SYNTH3, z, controlI2CRepeater);
|
||||
|
||||
/* Write the x (fractional) value high-order byte to synth4 register */
|
||||
/* Write the x (fractional) value high-order byte to synth4 register */
|
||||
writeE4KRegister(Register.SYNTH4, (byte) (x & 0xFF), controlI2CRepeater);
|
||||
|
||||
/* Write the x (fractional) value low-order byte to synth5 register */
|
||||
/* Write the x (fractional) value low-order byte to synth5 register */
|
||||
writeE4KRegister(Register.SYNTH5,
|
||||
(byte) ((Integer.rotateRight(x, 8)) & 0xFF),
|
||||
controlI2CRepeater);
|
||||
|
||||
/* Set the band for the new frequency */
|
||||
/* Set the band for the new frequency */
|
||||
setBand(actualFrequency, controlI2CRepeater);
|
||||
|
||||
/* Set the filter */
|
||||
/* Set the filter */
|
||||
setRFFilter(actualFrequency, controlI2CRepeater);
|
||||
|
||||
/* Check for PLL lock */
|
||||
/* Check for PLL lock */
|
||||
int lock = readE4KRegister(Register.SYNTH1, controlI2CRepeater);
|
||||
|
||||
if(!((lock & 0x1) == 0x1))
|
||||
@@ -425,24 +425,24 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
|
||||
boolean i2CRepeaterControl = false;
|
||||
|
||||
/* Perform dummy read */
|
||||
/* Perform dummy read */
|
||||
readE4KRegister(Register.DUMMY, i2CRepeaterControl);
|
||||
|
||||
/* Reset everything and clear POR indicator */
|
||||
/* NOTE: register value remains 0010 even after we write 0111 to it */
|
||||
/* Reset everything and clear POR indicator */
|
||||
/* NOTE: register value remains 0010 even after we write 0111 to it */
|
||||
writeE4KRegister(Register.MASTER1, (byte) (MASTER1_RESET |
|
||||
MASTER1_NORM_STBY |
|
||||
MASTER1_POR_DET),
|
||||
i2CRepeaterControl);
|
||||
|
||||
/* Configure clock input */
|
||||
/* Configure clock input */
|
||||
writeE4KRegister(Register.CLK_INP, (byte) 0x00, i2CRepeaterControl);
|
||||
|
||||
/* Disable clock output */
|
||||
/* Disable clock output */
|
||||
writeE4KRegister(Register.REF_CLK, (byte) 0x00, i2CRepeaterControl);
|
||||
writeE4KRegister(Register.CLKOUT_PWDN, (byte) 0x96, i2CRepeaterControl);
|
||||
|
||||
/* Magic Init */
|
||||
/* Magic Init */
|
||||
magicInit(i2CRepeaterControl);
|
||||
|
||||
// /* Set common mode voltage a bit higher for more margin - 850 mv */
|
||||
@@ -456,7 +456,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
// writeE4KRegister( Register.DCTIME1, (byte)0x01, i2CRepeaterControl );
|
||||
// writeE4KRegister( Register.DCTIME2, (byte)0x01, i2CRepeaterControl );
|
||||
//
|
||||
/* Set LNA Mode */
|
||||
/* Set LNA Mode */
|
||||
writeE4KRegister(Register.AGC4, (byte) 0x10, i2CRepeaterControl); //High Threshold
|
||||
writeE4KRegister(Register.AGC5, (byte) 0x04, i2CRepeaterControl); //Low Threshold
|
||||
writeE4KRegister(Register.AGC6, (byte) 0x1A, i2CRepeaterControl); //LNA calibrate + loop rate
|
||||
@@ -496,12 +496,12 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
// i2CRepeaterControl );
|
||||
|
||||
|
||||
/* Use automatic gain as a default */
|
||||
/* Use automatic gain as a default */
|
||||
setLNAGain(E4KLNAGain.AUTOMATIC, i2CRepeaterControl);
|
||||
setMixerGain(E4KMixerGain.AUTOMATIC, i2CRepeaterControl);
|
||||
setEnhanceGain(E4KEnhanceGain.AUTOMATIC, i2CRepeaterControl);
|
||||
|
||||
/* Set IF gain stages */
|
||||
/* Set IF gain stages */
|
||||
setIFStage1Gain(IFStage1Gain.GAIN_PLUS6, i2CRepeaterControl);
|
||||
setIFStage2Gain(IFStage2Gain.GAIN_PLUS0, i2CRepeaterControl);
|
||||
setIFStage3Gain(IFStage3Gain.GAIN_PLUS0, i2CRepeaterControl);
|
||||
@@ -509,7 +509,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
setIFStage5Gain(IFStage5Gain.GAIN_PLUS9, i2CRepeaterControl);
|
||||
setIFStage6Gain(IFStage6Gain.GAIN_PLUS9, i2CRepeaterControl);
|
||||
|
||||
/* Set the most narrow filter we can possible use */
|
||||
/* Set the most narrow filter we can possible use */
|
||||
setMixerFilter(MixerFilter.BW_1M9, i2CRepeaterControl);
|
||||
setRCFilter(RCFilter.BW_1M0, i2CRepeaterControl);
|
||||
setChannelFilter(ChannelFilter.BW_2M15, i2CRepeaterControl);
|
||||
@@ -519,7 +519,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
// /* Disable DC detector */
|
||||
// setDCRangeDetectorEnabled( false, i2CRepeaterControl );
|
||||
|
||||
/* Disable time variant DC correction */
|
||||
/* Disable time variant DC correction */
|
||||
writeMaskedE4KRegister(Register.DC5, (byte) 0x03, (byte) 0, i2CRepeaterControl);
|
||||
writeMaskedE4KRegister(Register.DCTIME1, (byte) 0x03, (byte) 0, i2CRepeaterControl);
|
||||
writeMaskedE4KRegister(Register.DCTIME2, (byte) 0x03, (byte) 0, i2CRepeaterControl);
|
||||
@@ -541,7 +541,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
enableI2CRepeater(mDeviceHandle, true);
|
||||
}
|
||||
|
||||
/* Capture current gain settings to reapply at the end */
|
||||
/* Capture current gain settings to reapply at the end */
|
||||
IFStage1Gain stage1 = getIFStage1Gain(i2CRepeaterControl);
|
||||
IFStage2Gain stage2 = getIFStage2Gain(i2CRepeaterControl);
|
||||
IFStage3Gain stage3 = getIFStage3Gain(i2CRepeaterControl);
|
||||
@@ -549,15 +549,15 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
IFStage5Gain stage5 = getIFStage5Gain(i2CRepeaterControl);
|
||||
IFStage6Gain stage6 = getIFStage6Gain(i2CRepeaterControl);
|
||||
|
||||
/* Set Mixer gain to manual using current auto Mixer gain setting */
|
||||
/* Set Mixer gain to manual using current auto Mixer gain setting */
|
||||
E4KMixerGain mixerGain = getMixerGain(i2CRepeaterControl);
|
||||
setMixerGain(mixerGain, i2CRepeaterControl);
|
||||
|
||||
/* Set LNA gain to manual using current auto LNA gain setting */
|
||||
/* Set LNA gain to manual using current auto LNA gain setting */
|
||||
E4KLNAGain lnaGain = getLNAGain(i2CRepeaterControl);
|
||||
setLNAGain(lnaGain, i2CRepeaterControl);
|
||||
|
||||
/* Set IF Stage 2 - 6 gains to maximum */
|
||||
/* Set IF Stage 2 - 6 gains to maximum */
|
||||
setIFStage2Gain(IFStage2Gain.GAIN_PLUS9, i2CRepeaterControl);
|
||||
setIFStage3Gain(IFStage3Gain.GAIN_PLUS9, i2CRepeaterControl);
|
||||
setIFStage4Gain(IFStage4Gain.GAIN_PLUS2B, i2CRepeaterControl);
|
||||
@@ -570,17 +570,17 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
*/
|
||||
for(DCGainCombination combo : DCGainCombination.values())
|
||||
{
|
||||
/* Set mixer and stage1 gain values */
|
||||
/* Set mixer and stage1 gain values */
|
||||
setMixerGain(combo.getMixerGain(), i2CRepeaterControl);
|
||||
setIFStage1Gain(combo.getIFStage1Gain(), i2CRepeaterControl);
|
||||
|
||||
/* Turn on the DC range detector */
|
||||
/* Turn on the DC range detector */
|
||||
setDCRangeDetectorEnabled(true, i2CRepeaterControl);
|
||||
|
||||
/* Calibrate the DC value */
|
||||
/* Calibrate the DC value */
|
||||
writeE4KRegister(Register.DC1, (byte) 0x01, i2CRepeaterControl);
|
||||
|
||||
/* Get the I/Q offset and range values */
|
||||
/* Get the I/Q offset and range values */
|
||||
byte offsetI = (byte) (readE4KRegister(Register.DC2,
|
||||
i2CRepeaterControl) & 0x3F);
|
||||
byte offsetQ = (byte) (readE4KRegister(Register.DC3,
|
||||
@@ -590,7 +590,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
byte rangeI = (byte) (range & 0x3);
|
||||
byte rangeQ = (byte) ((range >> 4) & 0x3);
|
||||
|
||||
/* Write the offset and range values to the lookup table */
|
||||
/* Write the offset and range values to the lookup table */
|
||||
writeE4KRegister(combo.getIRegister(),
|
||||
(byte) (offsetI | (rangeI << 6)),
|
||||
i2CRepeaterControl);
|
||||
@@ -735,7 +735,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
AGC7_MIX_GAIN_MANUAL,
|
||||
localI2CRepeaterControl);
|
||||
|
||||
/* Set the desired manual gain setting */
|
||||
/* Set the desired manual gain setting */
|
||||
writeMaskedE4KRegister(E4KMixerGain.getRegister(),
|
||||
E4KMixerGain.getMask(),
|
||||
gain.getValue(),
|
||||
@@ -945,7 +945,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
|
||||
Band band = Band.fromFrequency(frequency);
|
||||
|
||||
/* Set the bias */
|
||||
/* Set the bias */
|
||||
switch(band)
|
||||
{
|
||||
case UHF:
|
||||
@@ -1018,8 +1018,8 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs magic initialization ... and that's all we need to know, I guess
|
||||
*/
|
||||
* Performs magic initialization ... and that's all we need to know, I guess
|
||||
*/
|
||||
private void magicInit(boolean controlI2CRepeater) throws UsbException
|
||||
{
|
||||
if(controlI2CRepeater)
|
||||
@@ -1058,7 +1058,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
{
|
||||
int temp = readE4KRegister(register, controlI2CRepeater);
|
||||
|
||||
/* If the register is not set to the masked value, then change it */
|
||||
/* If the register is not set to the masked value, then change it */
|
||||
if((byte) (temp & mask) != value)
|
||||
{
|
||||
writeE4KRegister(register,
|
||||
@@ -1207,7 +1207,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
}
|
||||
|
||||
/* Returns the PLL setting with the closest frequency that is greater
|
||||
* than the frequency argument */
|
||||
* than the frequency argument */
|
||||
public static PLL fromFrequency(long frequency)
|
||||
{
|
||||
for(PLL pll : values())
|
||||
@@ -1288,7 +1288,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
M1720(14, 1710000000, 1735000000),
|
||||
|
||||
/* Note: max frequency is currently limited by the max integer value
|
||||
* and we set the max frequency for this filter to 2147 MHz */
|
||||
* and we set the max frequency for this filter to 2147 MHz */
|
||||
M1750(15, 1735000000, 2147000000);
|
||||
|
||||
private int mValue;
|
||||
@@ -1446,7 +1446,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
}
|
||||
}
|
||||
|
||||
/* default */
|
||||
/* default */
|
||||
return MixerFilter.BW_27M0;
|
||||
}
|
||||
|
||||
@@ -1557,7 +1557,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
}
|
||||
}
|
||||
|
||||
/* default */
|
||||
/* default */
|
||||
return RCFilter.BW_21M4;
|
||||
}
|
||||
|
||||
@@ -1684,7 +1684,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
}
|
||||
}
|
||||
|
||||
/* default */
|
||||
/* default */
|
||||
return ChannelFilter.BW_5M50;
|
||||
}
|
||||
|
||||
@@ -2509,4 +2509,4 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
return (byte) mValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.rtl.e4k;
|
||||
|
||||
@@ -24,6 +22,7 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||
import io.github.dsheirer.source.tuner.rtl.RTL2832Tuner;
|
||||
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController;
|
||||
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController.SampleRate;
|
||||
import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KEnhanceGain;
|
||||
import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KGain;
|
||||
import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KLNAGain;
|
||||
@@ -33,7 +32,16 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.LibUsbException;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.usb.UsbException;
|
||||
@@ -46,28 +54,28 @@ import java.text.DecimalFormat;
|
||||
public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( E4KTunerEditor.class );
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JComboBox<RTL2832TunerController.SampleRate> mComboSampleRate;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<E4KGain> mComboMasterGain;
|
||||
private JComboBox<E4KMixerGain> mComboMixerGain;
|
||||
private JComboBox<E4KLNAGain> mComboLNAGain;
|
||||
private JComboBox<E4KEnhanceGain> mComboEnhanceGain;
|
||||
|
||||
private E4KTunerController mController;
|
||||
private boolean mLoading;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public E4KTunerEditor(TunerConfigurationModel tunerConfigurationModel, RTL2832Tuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (E4KTunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JComboBox<SampleRate> mComboSampleRate;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<E4KGain> mComboMasterGain;
|
||||
private JComboBox<E4KMixerGain> mComboMixerGain;
|
||||
private JComboBox<E4KLNAGain> mComboLNAGain;
|
||||
private JComboBox<E4KEnhanceGain> mComboEnhanceGain;
|
||||
|
||||
private E4KTunerController mController;
|
||||
private boolean mLoading;
|
||||
|
||||
public E4KTunerEditor( TunerConfigurationModel tunerConfigurationModel, RTL2832Tuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (E4KTunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private E4KTunerConfiguration getConfiguration()
|
||||
{
|
||||
@@ -75,15 +83,15 @@ public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
return (E4KTunerConfiguration)getItem();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][][grow]" ) );
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][][grow]" ) );
|
||||
|
||||
add( new JLabel( "E4000 Tuner Configuration" ), "span,align center" );
|
||||
|
||||
/**
|
||||
@@ -92,19 +100,19 @@ public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
add( new JLabel( "Name:" ) );
|
||||
mConfigurationName = new JTextField();
|
||||
mConfigurationName.setEnabled( false );
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
} );
|
||||
|
||||
|
||||
add( mConfigurationName, "span 2" );
|
||||
|
||||
|
||||
mTunerInfo = new JButton( "Tuner Info" );
|
||||
mTunerInfo.setEnabled( false );
|
||||
mTunerInfo.addActionListener( new ActionListener()
|
||||
@@ -112,223 +120,223 @@ public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
} );
|
||||
add( mTunerInfo );
|
||||
|
||||
mComboSampleRate = new JComboBox<>( RTL2832TunerController.SampleRate.values() );
|
||||
mComboSampleRate.setEnabled( false );
|
||||
mComboSampleRate.addActionListener( new ActionListener()
|
||||
{
|
||||
mComboSampleRate = new JComboBox<>( SampleRate.values() );
|
||||
mComboSampleRate.setEnabled( false );
|
||||
mComboSampleRate.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
RTL2832TunerController.SampleRate sampleRate = (RTL2832TunerController.SampleRate)mComboSampleRate.getSelectedItem();
|
||||
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
SampleRate sampleRate = (SampleRate)mComboSampleRate.getSelectedItem();
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
mController.setSampleRate( sampleRate );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException | LibUsbException eSampleRate )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this,
|
||||
"E4K Tuner Controller - couldn't apply the sample rate setting [" +
|
||||
sampleRate.getLabel() + "] " + eSampleRate.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply sample rate setting [" +
|
||||
sampleRate.getLabel() + "]", eSampleRate );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( new JLabel( "Sample Rate:" ) );
|
||||
add( mComboSampleRate );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException | LibUsbException eSampleRate )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this,
|
||||
"E4K Tuner Controller - couldn't apply the sample rate setting [" +
|
||||
sampleRate.getLabel() + "] " + eSampleRate.getLocalizedMessage() );
|
||||
|
||||
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply sample rate setting [" +
|
||||
sampleRate.getLabel() + "]", eSampleRate );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( new JLabel( "Sample Rate:" ) );
|
||||
add( mComboSampleRate );
|
||||
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
SpinnerModel model = new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
final double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply frequency correction value: " + value + e1.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply frequency correction value:"
|
||||
+ value, e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection );
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply frequency correction value: " + value + e1.getLocalizedMessage() );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
add( new JLabel( "Gain" ), "wrap" );
|
||||
|
||||
mComboMasterGain = new JComboBox<E4KGain>( E4KGain.values() );
|
||||
mComboMasterGain.setEnabled( false );
|
||||
mComboMasterGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply frequency correction value:"
|
||||
+ value, e1 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
add( new JLabel( "Gain" ), "wrap" );
|
||||
|
||||
mComboMasterGain = new JComboBox<E4KGain>( E4KGain.values() );
|
||||
mComboMasterGain.setEnabled( false );
|
||||
mComboMasterGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
E4KGain gain = (E4KGain)mComboMasterGain.getSelectedItem();
|
||||
|
||||
mController.setGain( (E4KGain)mComboMasterGain.getSelectedItem(), true );
|
||||
|
||||
if( gain == E4KGain.MANUAL )
|
||||
{
|
||||
mComboMixerGain.setSelectedItem( mController.getMixerGain( true ) );
|
||||
mComboMixerGain.setEnabled( true );
|
||||
|
||||
mComboLNAGain.setSelectedItem( mController.getLNAGain( true ) );
|
||||
mComboLNAGain.setEnabled( true );
|
||||
|
||||
mComboEnhanceGain.setSelectedItem( mController.getEnhanceGain( true ) );
|
||||
mComboEnhanceGain.setEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
mComboMixerGain.setEnabled( false );
|
||||
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
|
||||
mController.setGain( (E4KGain)mComboMasterGain.getSelectedItem(), true );
|
||||
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
|
||||
if( gain == E4KGain.MANUAL )
|
||||
{
|
||||
mComboMixerGain.setSelectedItem( mController.getMixerGain( true ) );
|
||||
mComboMixerGain.setEnabled( true );
|
||||
|
||||
mComboEnhanceGain.setEnabled( false );
|
||||
mComboEnhanceGain.setSelectedItem( gain.getEnhanceGain() );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
mComboMasterGain.setToolTipText( "<html>Select <b>AUTOMATIC</b> for auto "
|
||||
+ "gain, <b>MANUAL</b> to enable<br> independent control of "
|
||||
+ "<i>Mixer</i>, <i>LNA</i> and <i>Enhance</i> gain<br>"
|
||||
+ "settings, or one of the individual gain settings for<br>"
|
||||
+ "semi-manual gain control</html>" );
|
||||
add( new JLabel( "Master:" ) );
|
||||
add( mComboMasterGain );
|
||||
mComboLNAGain.setSelectedItem( mController.getLNAGain( true ) );
|
||||
mComboLNAGain.setEnabled( true );
|
||||
|
||||
mComboMixerGain = new JComboBox<E4KMixerGain>( E4KMixerGain.values() );
|
||||
mComboMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mComboEnhanceGain.setSelectedItem( mController.getEnhanceGain( true ) );
|
||||
mComboEnhanceGain.setEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
mComboMixerGain.setEnabled( false );
|
||||
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
|
||||
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
|
||||
|
||||
mComboEnhanceGain.setEnabled( false );
|
||||
mComboEnhanceGain.setSelectedItem( gain.getEnhanceGain() );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
mComboMasterGain.setToolTipText( "<html>Select <b>AUTOMATIC</b> for auto "
|
||||
+ "gain, <b>MANUAL</b> to enable<br> independent control of "
|
||||
+ "<i>Mixer</i>, <i>LNA</i> and <i>Enhance</i> gain<br>"
|
||||
+ "settings, or one of the individual gain settings for<br>"
|
||||
+ "semi-manual gain control</html>" );
|
||||
add( new JLabel( "Master:" ) );
|
||||
add( mComboMasterGain );
|
||||
|
||||
mComboMixerGain = new JComboBox<E4KMixerGain>( E4KMixerGain.values() );
|
||||
mComboMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
E4KMixerGain mixerGain = (E4KMixerGain)mComboMixerGain.getSelectedItem();
|
||||
mController.setMixerGain( mixerGain, true );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the mixer gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply mixer gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboMixerGain.setToolTipText( "<html>Mixer Gain. Set master gain "
|
||||
+ "to <b>MASTER</b> to enable adjustment</html>" );
|
||||
mComboMixerGain.setEnabled( false );
|
||||
add( new JLabel( "Mixer:" ) );
|
||||
add( mComboMixerGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the mixer gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mComboLNAGain = new JComboBox<E4KLNAGain>( E4KLNAGain.values() );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply mixer gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboMixerGain.setToolTipText( "<html>Mixer Gain. Set master gain "
|
||||
+ "to <b>MASTER</b> to enable adjustment</html>" );
|
||||
mComboMixerGain.setEnabled( false );
|
||||
add( new JLabel( "Mixer:" ) );
|
||||
add( mComboMixerGain );
|
||||
|
||||
mComboLNAGain = new JComboBox<E4KLNAGain>( E4KLNAGain.values() );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
E4KLNAGain lnaGain = (E4KLNAGain)mComboLNAGain.getSelectedItem();
|
||||
mController.setLNAGain( lnaGain, true );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the LNA gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply LNA gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboLNAGain.setToolTipText( "<html>LNA Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
add( new JLabel( "LNA:" ) );
|
||||
add( mComboLNAGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the LNA gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mComboEnhanceGain = new JComboBox<E4KEnhanceGain>( E4KEnhanceGain.values() );
|
||||
mComboEnhanceGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply LNA gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboLNAGain.setToolTipText( "<html>LNA Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
add( new JLabel( "LNA:" ) );
|
||||
add( mComboLNAGain );
|
||||
|
||||
mComboEnhanceGain = new JComboBox<E4KEnhanceGain>( E4KEnhanceGain.values() );
|
||||
mComboEnhanceGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
E4KEnhanceGain enhance = (E4KEnhanceGain)mComboEnhanceGain.getSelectedItem();
|
||||
mController.setEnhanceGain( enhance, true );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the enhance gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply enhance gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboEnhanceGain.setToolTipText( "<html>Enhance Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
mComboEnhanceGain.setEnabled( false );
|
||||
add( new JLabel( "Enhance:" ) );
|
||||
add( mComboEnhanceGain );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( E4KTunerEditor.this, "E4K Tuner Controller - "
|
||||
+ "couldn't apply the enhance gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "E4K Tuner Controller - couldn't apply enhance gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboEnhanceGain.setToolTipText( "<html>Enhance Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
mComboEnhanceGain.setEnabled( false );
|
||||
add( new JLabel( "Enhance:" ) );
|
||||
add( mComboEnhanceGain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each of the tuner configuration controls to the enabled argument state
|
||||
*/
|
||||
@@ -338,51 +346,51 @@ public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mConfigurationName.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mTunerInfo.isEnabled() != enabled )
|
||||
{
|
||||
mTunerInfo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mFrequencyCorrection.isEnabled() != enabled )
|
||||
{
|
||||
mFrequencyCorrection.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboSampleRate.isEnabled() != enabled )
|
||||
{
|
||||
mComboSampleRate.setEnabled( enabled );
|
||||
}
|
||||
if( mComboSampleRate.isEnabled() != enabled )
|
||||
{
|
||||
mComboSampleRate.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboMasterGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMasterGain.setEnabled( enabled );
|
||||
}
|
||||
if( mComboMasterGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMasterGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboMixerGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMixerGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboLNAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboEnhanceGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboEnhanceGain.setEnabled( enabled );
|
||||
}
|
||||
if( mComboMixerGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMixerGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboLNAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboEnhanceGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboEnhanceGain.setEnabled( enabled );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getTunerInfo()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
RTL2832TunerController.Descriptor descriptor = mController.getDescriptor();
|
||||
|
||||
|
||||
sb.append( "<html><h3>RTL-2832 with E4000 Tuner</h3>" );
|
||||
|
||||
|
||||
if( descriptor == null )
|
||||
{
|
||||
sb.append( "No EEPROM Descriptor Available" );
|
||||
@@ -422,27 +430,27 @@ public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
E4KTunerConfiguration config = getConfiguration();
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
E4KTunerConfiguration config = getConfiguration();
|
||||
|
||||
config.setName( mConfigurationName.getText() );
|
||||
config.setName( mConfigurationName.getText() );
|
||||
|
||||
config.setSampleRate( (RTL2832TunerController.SampleRate)mComboSampleRate.getSelectedItem() );
|
||||
config.setSampleRate( (SampleRate)mComboSampleRate.getSelectedItem() );
|
||||
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
|
||||
config.setMasterGain( (E4KGain)mComboMasterGain.getSelectedItem() );
|
||||
config.setMixerGain( (E4KMixerGain)mComboMixerGain.getSelectedItem() );
|
||||
config.setMasterGain( (E4KGain)mComboMasterGain.getSelectedItem() );
|
||||
config.setMixerGain( (E4KMixerGain)mComboMixerGain.getSelectedItem() );
|
||||
config.setLNAGain( (E4KLNAGain)mComboLNAGain.getSelectedItem() );
|
||||
config.setEnhanceGain( (E4KEnhanceGain)mComboEnhanceGain.getSelectedItem() );
|
||||
|
||||
|
||||
getTunerConfigurationModel().broadcast( new TunerConfigurationEvent(
|
||||
getConfiguration(), TunerConfigurationEvent.Event.CHANGE ) );
|
||||
}
|
||||
|
||||
getConfiguration(), TunerConfigurationEvent.Event.CHANGE ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -456,18 +464,18 @@ public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
if( hasItem() )
|
||||
{
|
||||
E4KTunerConfiguration config = getConfiguration();
|
||||
|
||||
|
||||
if( tunerConfiguration.isAssigned() )
|
||||
{
|
||||
setControlsEnabled( true );
|
||||
setControlsEnabled( true );
|
||||
|
||||
mConfigurationName.setText( config.getName() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mComboSampleRate.setSelectedItem( config.getSampleRate() );
|
||||
mComboMasterGain.setSelectedItem( config.getMasterGain() );
|
||||
mComboMixerGain.setSelectedItem( config.getMixerGain() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboEnhanceGain.setSelectedItem( config.getEnhanceGain() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mComboSampleRate.setSelectedItem( config.getSampleRate() );
|
||||
mComboMasterGain.setSelectedItem( config.getMasterGain() );
|
||||
mComboMixerGain.setSelectedItem( config.getMixerGain() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboEnhanceGain.setSelectedItem( config.getEnhanceGain() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -480,7 +488,7 @@ public class E4KTunerEditor extends TunerConfigurationEditor
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( "" );
|
||||
}
|
||||
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* Java port of librtlsdr <https://github.com/steve-m/librtlsdr>
|
||||
*
|
||||
@@ -32,14 +32,13 @@ import org.usb4java.Device;
|
||||
import org.usb4java.DeviceDescriptor;
|
||||
import org.usb4java.LibUsbException;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JPanel;
|
||||
import javax.usb.UsbException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class R820TTunerController extends RTL2832TunerController
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger(R820TTunerController.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(R820TTunerController.class);
|
||||
|
||||
public static final long MIN_FREQUENCY = 3180000;
|
||||
public static final long MAX_FREQUENCY = 1782030000;
|
||||
@@ -188,14 +187,14 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
/* Set intermediate frequency to R820T IF frequency */
|
||||
setIFFrequency(R820T_IF_FREQUENCY);
|
||||
|
||||
/* Enable spectrum inversion */
|
||||
/* Enable spectrum inversion */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ONE,
|
||||
(short) 0x15,
|
||||
(short) 0x01,
|
||||
1);
|
||||
|
||||
/* Set default i/q path */
|
||||
|
||||
/* Set default i/q path */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ZERO,
|
||||
(short) 0x06,
|
||||
@@ -215,23 +214,23 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
{
|
||||
FrequencyRange range = FrequencyRange.getRangeForFrequency(frequency);
|
||||
|
||||
/* Set open drain */
|
||||
/* Set open drain */
|
||||
writeR820TRegister(Register.DRAIN, range.getOpenDrain(), controlI2C);
|
||||
|
||||
/* RF_MUX, Polymux */
|
||||
/* RF_MUX, Polymux */
|
||||
writeR820TRegister(Register.RF_POLY_MUX, range.getRFMuxPolyMux(), controlI2C);
|
||||
|
||||
/* TF Band */
|
||||
|
||||
/* TF Band */
|
||||
writeR820TRegister(Register.TF_BAND, range.getTFC(), controlI2C);
|
||||
|
||||
/* XTAL CAP & Drive */
|
||||
|
||||
/* XTAL CAP & Drive */
|
||||
writeR820TRegister(Register.PLL_XTAL_CAPACITOR_AND_DRIVE,
|
||||
range.getXTALHighCap0P(), controlI2C);
|
||||
|
||||
/* Register 8 - what is it? */
|
||||
|
||||
/* Register 8 - what is it? */
|
||||
writeR820TRegister(Register.UNKNOWN_REGISTER_8, (byte) 0x00, controlI2C);
|
||||
|
||||
/* Register 9 - what is it? */
|
||||
|
||||
/* Register 9 - what is it? */
|
||||
writeR820TRegister(Register.UNKNOWN_REGISTER_9, (byte) 0x00, controlI2C);
|
||||
}
|
||||
|
||||
@@ -240,7 +239,7 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
*/
|
||||
public void init() throws SourceException
|
||||
{
|
||||
/* Initialize the super class to open and claim the usb interface*/
|
||||
/* Initialize the super class to open and claim the usb interface*/
|
||||
super.init();
|
||||
|
||||
try
|
||||
@@ -266,24 +265,24 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
*/
|
||||
public void initTuner(boolean controlI2C) throws UsbException
|
||||
{
|
||||
/* Disable zero IF mode */
|
||||
/* Disable zero IF mode */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ONE,
|
||||
(short) 0xB1,
|
||||
(short) 0x1A,
|
||||
1);
|
||||
|
||||
/* Only enable in-phase ADC input */
|
||||
|
||||
/* Only enable in-phase ADC input */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ZERO,
|
||||
(short) 0x08,
|
||||
(short) 0x4D,
|
||||
1);
|
||||
|
||||
/* Set intermediate frequency to R820T IF frequency (3.57 MHz) */
|
||||
|
||||
/* Set intermediate frequency to R820T IF frequency (3.57 MHz) */
|
||||
setIFFrequency(R820T_IF_FREQUENCY);
|
||||
|
||||
/* Enable spectrum inversion */
|
||||
/* Enable spectrum inversion */
|
||||
writeDemodRegister(mDeviceHandle,
|
||||
Page.ONE,
|
||||
(short) 0x15,
|
||||
@@ -303,12 +302,12 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
*/
|
||||
private void setTVStandard(boolean controlI2C) throws UsbException
|
||||
{
|
||||
/* Init Flag & Xtal check Result */
|
||||
/* Init Flag & Xtal check Result */
|
||||
writeR820TRegister(Register.XTAL_CHECK, (byte) 0x00, controlI2C);
|
||||
|
||||
/* Set version */
|
||||
|
||||
/* Set version */
|
||||
writeR820TRegister(Register.VERSION, VERSION, controlI2C);
|
||||
|
||||
|
||||
/* LT Gain Test */
|
||||
writeR820TRegister(Register.LNA_TOP, (byte) 0x00, controlI2C);
|
||||
|
||||
@@ -326,7 +325,7 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
writeR820TRegister(Register.PLL_XTAL_CAPACITOR, (byte) 0x00, controlI2C);
|
||||
|
||||
setPLL(56000 * 1000, controlI2C);
|
||||
|
||||
|
||||
/* Start trigger */
|
||||
writeR820TRegister(Register.CALIBRATION_TRIGGER, (byte) 0x10, controlI2C);
|
||||
|
||||
@@ -349,36 +348,36 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
{
|
||||
calibrationCode = 0;
|
||||
}
|
||||
|
||||
/* Write calibration code */
|
||||
|
||||
/* Write calibration code */
|
||||
byte filt_q = 0x10;
|
||||
|
||||
writeR820TRegister(Register.FILTER_CALIBRATION_CODE,
|
||||
(byte) (calibrationCode | filt_q), controlI2C);
|
||||
|
||||
/* Set BW, Filter gain & HP Corner */
|
||||
/* Set BW, Filter gain & HP Corner */
|
||||
writeR820TRegister(Register.BANDWIDTH_FILTER_GAIN_HIGHPASS_FILTER_CORNER,
|
||||
(byte) 0x6B, controlI2C);
|
||||
|
||||
/* Set Image_R */
|
||||
/* Set Image_R */
|
||||
writeR820TRegister(Register.IMAGE_REVERSE, (byte) 0x00, controlI2C);
|
||||
|
||||
/* Set filter_3db, V6MHz */
|
||||
|
||||
/* Set filter_3db, V6MHz */
|
||||
writeR820TRegister(Register.FILTER_GAIN, (byte) 0x10, controlI2C);
|
||||
|
||||
/* Channel filter extension */
|
||||
/* Channel filter extension */
|
||||
writeR820TRegister(Register.CHANNEL_FILTER_EXTENSION, (byte) 0x60, controlI2C);
|
||||
|
||||
/* Loop through */
|
||||
/* Loop through */
|
||||
writeR820TRegister(Register.LOOP_THROUGH, (byte) 0x00, controlI2C);
|
||||
|
||||
/* Loop through attenuation */
|
||||
/* Loop through attenuation */
|
||||
writeR820TRegister(Register.LOOP_THROUGH_ATTENUATION, (byte) 0x00, controlI2C);
|
||||
|
||||
/* Filter extension widest */
|
||||
|
||||
/* Filter extension widest */
|
||||
writeR820TRegister(Register.FILTER_EXTENSION_WIDEST, (byte) 0x00, controlI2C);
|
||||
|
||||
/* RF poly filter current */
|
||||
/* RF poly filter current */
|
||||
writeR820TRegister(Register.RF_POLY_FILTER_CURRENT, (byte) 0x60, controlI2C);
|
||||
}
|
||||
|
||||
@@ -404,7 +403,7 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
private void systemFrequencySelect(long frequency, boolean controlI2C)
|
||||
throws UsbException
|
||||
{
|
||||
/* LNA top? */
|
||||
/* LNA top? */
|
||||
writeR820TRegister(Register.LNA_TOP2, (byte) 0xE5, controlI2C);
|
||||
|
||||
byte mixer_top;
|
||||
@@ -431,8 +430,8 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
writeR820TRegister(Register.LNA_VTH_L, (byte) 0x53, controlI2C);
|
||||
|
||||
writeR820TRegister(Register.MIXER_VTH_L, (byte) 0x75, controlI2C);
|
||||
|
||||
/* Air-In only for Astrometa */
|
||||
|
||||
/* Air-In only for Astrometa */
|
||||
writeR820TRegister(Register.AIR_CABLE1_INPUT_SELECTOR, (byte) 0x00, controlI2C);
|
||||
|
||||
writeR820TRegister(Register.CABLE2_INPUT_SELECTOR, (byte) 0x00, controlI2C);
|
||||
@@ -443,7 +442,7 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
|
||||
writeR820TRegister(Register.FILTER_CURRENT, (byte) 0x40, controlI2C);
|
||||
|
||||
/* if( type != TUNER_ANALOG_TV ) ... */
|
||||
/* if( type != TUNER_ANALOG_TV ) ... */
|
||||
|
||||
writeR820TRegister(Register.LNA_TOP, (byte) 0x00, controlI2C);
|
||||
|
||||
@@ -457,10 +456,10 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
|
||||
writeR820TRegister(Register.MIXER_TOP2, mixer_top, controlI2C);
|
||||
|
||||
/* LNA discharge current */
|
||||
/* LNA discharge current */
|
||||
writeR820TRegister(Register.LNA_DISCHARGE_CURRENT, (byte) 0x14, controlI2C);
|
||||
|
||||
/* AGC clock 1 khz, external det1 cap 1u */
|
||||
|
||||
/* AGC clock 1 khz, external det1 cap 1u */
|
||||
writeR820TRegister(Register.AGC_CLOCK, (byte) 0x20, controlI2C);
|
||||
}
|
||||
|
||||
@@ -474,7 +473,7 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
*/
|
||||
private void setPLL(long frequency, boolean controlI2C) throws UsbException
|
||||
{
|
||||
/* Set reference divider to 0 */
|
||||
/* Set reference divider to 0 */
|
||||
writeR820TRegister(Register.REFERENCE_DIVIDER_2, (byte) 0x00, controlI2C);
|
||||
|
||||
/* Set PLL autotune to 128kHz */
|
||||
@@ -525,7 +524,7 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
* settings */
|
||||
if(!isPLLLocked(controlI2C))
|
||||
{
|
||||
/* Increase VCO current */
|
||||
/* Increase VCO current */
|
||||
writeR820TRegister(Register.VCO_CURRENT, (byte) 0x60, controlI2C);
|
||||
|
||||
if(!isPLLLocked(controlI2C))
|
||||
@@ -612,8 +611,8 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
|
||||
mShadowRegister[register.getRegister()] = value;
|
||||
|
||||
// Log.info( "R820T writing register " +
|
||||
// String.format( "%02X", register.getRegister() ) + " value " +
|
||||
// Log.info( "R820T writing register " +
|
||||
// String.format( "%02X", register.getRegister() ) + " value " +
|
||||
// String.format( "%02X", value ) );
|
||||
}
|
||||
|
||||
@@ -1293,4 +1292,4 @@ public class R820TTunerController extends RTL2832TunerController
|
||||
"] must be in the range 0 - 31");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,12 +24,26 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||
import io.github.dsheirer.source.tuner.rtl.RTL2832Tuner;
|
||||
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController;
|
||||
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController.SampleRate;
|
||||
import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TGain;
|
||||
import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TLNAGain;
|
||||
import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TMixerGain;
|
||||
import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TVGAGain;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.LibUsbException;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.usb.UsbException;
|
||||
@@ -44,61 +58,61 @@ public class R820TTunerEditor extends TunerConfigurationEditor
|
||||
private final static Logger mLog = LoggerFactory.getLogger( R820TTunerEditor.class );
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final R820TTunerController.R820TGain DEFAULT_GAIN = R820TTunerController.R820TGain.GAIN_279;
|
||||
|
||||
private R820TTunerController mController;
|
||||
private static final R820TGain DEFAULT_GAIN = R820TGain.GAIN_279;
|
||||
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JComboBox<RTL2832TunerController.SampleRate> mComboSampleRate;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<R820TTunerController.R820TGain> mComboMasterGain;
|
||||
private JComboBox<R820TTunerController.R820TMixerGain> mComboMixerGain;
|
||||
private JComboBox<R820TTunerController.R820TLNAGain> mComboLNAGain;
|
||||
private JComboBox<R820TTunerController.R820TVGAGain> mComboVGAGain;
|
||||
private boolean mLoading;
|
||||
private R820TTunerController mController;
|
||||
|
||||
private JTextField mConfigurationName;
|
||||
private JButton mTunerInfo;
|
||||
private JComboBox<SampleRate> mComboSampleRate;
|
||||
private JSpinner mFrequencyCorrection;
|
||||
private JComboBox<R820TGain> mComboMasterGain;
|
||||
private JComboBox<R820TMixerGain> mComboMixerGain;
|
||||
private JComboBox<R820TLNAGain> mComboLNAGain;
|
||||
private JComboBox<R820TVGAGain> mComboVGAGain;
|
||||
private boolean mLoading;
|
||||
|
||||
public R820TTunerEditor( TunerConfigurationModel tunerConfigurationModel, RTL2832Tuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (R820TTunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public R820TTunerEditor(TunerConfigurationModel tunerConfigurationModel, RTL2832Tuner tuner )
|
||||
{
|
||||
super( tunerConfigurationModel );
|
||||
mController = (R820TTunerController)tuner.getController();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private R820TTunerConfiguration getConfiguration()
|
||||
{
|
||||
if( hasItem() )
|
||||
{
|
||||
return (R820TTunerConfiguration)getItem();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][][grow]" ) );
|
||||
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]",
|
||||
"[][][][][][][][grow]" ) );
|
||||
|
||||
add( new JLabel( "R820T Tuner Configuration" ), "span,align center" );
|
||||
|
||||
mConfigurationName = new JTextField();
|
||||
mConfigurationName.setEnabled( false );
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
mConfigurationName.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
public void focusLost( FocusEvent e )
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
public void focusGained( FocusEvent e ) {}
|
||||
} );
|
||||
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
add( mConfigurationName, "span 2" );
|
||||
|
||||
|
||||
mTunerInfo = new JButton( "Tuner Info" );
|
||||
mTunerInfo.setEnabled( false );
|
||||
mTunerInfo.addActionListener( new ActionListener()
|
||||
@@ -106,279 +120,279 @@ public class R820TTunerEditor extends TunerConfigurationEditor
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this, getTunerInfo(),
|
||||
"Tuner Info", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
} );
|
||||
add( mTunerInfo );
|
||||
|
||||
mComboSampleRate = new JComboBox<>( RTL2832TunerController.SampleRate.values() );
|
||||
mComboSampleRate.setEnabled( false );
|
||||
mComboSampleRate.addActionListener( new ActionListener()
|
||||
{
|
||||
|
||||
mComboSampleRate = new JComboBox<>( SampleRate.values() );
|
||||
mComboSampleRate.setEnabled( false );
|
||||
mComboSampleRate.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
RTL2832TunerController.SampleRate sampleRate =
|
||||
(RTL2832TunerController.SampleRate)mComboSampleRate.getSelectedItem();
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
SampleRate sampleRate =
|
||||
(SampleRate)mComboSampleRate.getSelectedItem();
|
||||
try
|
||||
{
|
||||
{
|
||||
|
||||
mController.setSampleRate( sampleRate );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException | LibUsbException eSampleRate )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "] " +
|
||||
eSampleRate.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "]",
|
||||
eSampleRate );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( new JLabel( "Sample Rate:" ) );
|
||||
add( mComboSampleRate );
|
||||
save();
|
||||
}
|
||||
catch ( SourceException | LibUsbException eSampleRate )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "] " +
|
||||
eSampleRate.getLocalizedMessage() );
|
||||
|
||||
/**
|
||||
* Frequency Correction
|
||||
*/
|
||||
SpinnerModel model =
|
||||
new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply sample "
|
||||
+ "rate setting [" + sampleRate.getLabel() + "]",
|
||||
eSampleRate );
|
||||
}
|
||||
}
|
||||
} );
|
||||
add( new JLabel( "Sample Rate:" ) );
|
||||
add( mComboSampleRate );
|
||||
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
/**
|
||||
* Frequency Correction
|
||||
*/
|
||||
SpinnerModel model =
|
||||
new SpinnerNumberModel( 0.0, //initial value
|
||||
-1000.0, //min
|
||||
1000.0, //max
|
||||
0.1 ); //step
|
||||
|
||||
JSpinner.NumberEditor editor =
|
||||
(JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
|
||||
|
||||
DecimalFormat format = editor.getFormat();
|
||||
format.setMinimumFractionDigits( 1 );
|
||||
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
|
||||
mFrequencyCorrection = new JSpinner( model );
|
||||
mFrequencyCorrection.setEnabled( false );
|
||||
|
||||
mFrequencyCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
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 )
|
||||
{
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
final double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
.getModel()).getNumber().doubleValue();
|
||||
|
||||
try
|
||||
{
|
||||
mController.setFrequencyCorrection( value );
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
}
|
||||
catch ( SourceException e1 )
|
||||
{
|
||||
mLog.error( "Error setting frequency correction value", e1 );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
|
||||
/**
|
||||
* Gain Controls
|
||||
*/
|
||||
add( new JLabel( "Gain" ), "wrap" );
|
||||
|
||||
/* Master Gain Control */
|
||||
mComboMasterGain = new JComboBox<R820TTunerController.R820TGain>( R820TTunerController.R820TGain.values() );
|
||||
mComboMasterGain.setEnabled( false );
|
||||
mComboMasterGain.addActionListener( new ActionListener()
|
||||
{
|
||||
save();
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "PPM:" ) );
|
||||
add( mFrequencyCorrection );
|
||||
|
||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,grow" );
|
||||
|
||||
/**
|
||||
* Gain Controls
|
||||
*/
|
||||
add( new JLabel( "Gain" ), "wrap" );
|
||||
|
||||
/* Master Gain Control */
|
||||
mComboMasterGain = new JComboBox<R820TGain>( R820TGain.values() );
|
||||
mComboMasterGain.setEnabled( false );
|
||||
mComboMasterGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TTunerController.R820TGain gain = (R820TTunerController.R820TGain)mComboMasterGain.getSelectedItem();
|
||||
|
||||
mController.setGain( (R820TTunerController.R820TGain)mComboMasterGain.getSelectedItem(), true );
|
||||
|
||||
if( gain == R820TTunerController.R820TGain.MANUAL )
|
||||
{
|
||||
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
|
||||
mComboMixerGain.setEnabled( true );
|
||||
|
||||
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
|
||||
mComboLNAGain.setEnabled( true );
|
||||
{
|
||||
R820TGain gain = (R820TGain)mComboMasterGain.getSelectedItem();
|
||||
|
||||
mComboVGAGain.setSelectedItem( gain.getVGAGain() );
|
||||
mComboVGAGain.setEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
mComboMixerGain.setEnabled( false );
|
||||
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
|
||||
mController.setGain( (R820TGain)mComboMasterGain.getSelectedItem(), true );
|
||||
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
|
||||
if( gain == R820TGain.MANUAL )
|
||||
{
|
||||
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
|
||||
mComboMixerGain.setEnabled( true );
|
||||
|
||||
mComboVGAGain.setEnabled( false );
|
||||
mComboVGAGain.setSelectedItem( gain.getVGAGain() );
|
||||
}
|
||||
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
|
||||
mComboLNAGain.setEnabled( true );
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the gain "
|
||||
+ "setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply "
|
||||
+ "gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboMasterGain.setToolTipText( "<html>Select <b>AUTOMATIC</b> for auto "
|
||||
+ "gain, <b>MANUAL</b> to enable<br> independent control of "
|
||||
+ "<i>Mixer</i>, <i>LNA</i> and <i>Enhance</i> gain<br>"
|
||||
+ "settings, or one of the individual gain settings for<br>"
|
||||
+ "semi-manual gain control</html>" );
|
||||
add( new JLabel( "Master:" ) );
|
||||
add( mComboMasterGain );
|
||||
mComboVGAGain.setSelectedItem( gain.getVGAGain() );
|
||||
mComboVGAGain.setEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
mComboMixerGain.setEnabled( false );
|
||||
mComboMixerGain.setSelectedItem( gain.getMixerGain() );
|
||||
|
||||
/* Mixer Gain Control */
|
||||
mComboMixerGain = new JComboBox<R820TTunerController.R820TMixerGain>( R820TTunerController.R820TMixerGain.values() );
|
||||
mComboMixerGain.setEnabled( false );
|
||||
mComboMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.setSelectedItem( gain.getLNAGain() );
|
||||
|
||||
mComboVGAGain.setEnabled( false );
|
||||
mComboVGAGain.setSelectedItem( gain.getVGAGain() );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog(
|
||||
R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the gain "
|
||||
+ "setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply "
|
||||
+ "gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboMasterGain.setToolTipText( "<html>Select <b>AUTOMATIC</b> for auto "
|
||||
+ "gain, <b>MANUAL</b> to enable<br> independent control of "
|
||||
+ "<i>Mixer</i>, <i>LNA</i> and <i>Enhance</i> gain<br>"
|
||||
+ "settings, or one of the individual gain settings for<br>"
|
||||
+ "semi-manual gain control</html>" );
|
||||
add( new JLabel( "Master:" ) );
|
||||
add( mComboMasterGain );
|
||||
|
||||
/* Mixer Gain Control */
|
||||
mComboMixerGain = new JComboBox<R820TMixerGain>( R820TMixerGain.values() );
|
||||
mComboMixerGain.setEnabled( false );
|
||||
mComboMixerGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TTunerController.R820TMixerGain mixerGain =
|
||||
(R820TTunerController.R820TMixerGain)mComboMixerGain.getSelectedItem();
|
||||
|
||||
{
|
||||
R820TMixerGain mixerGain =
|
||||
(R820TMixerGain)mComboMixerGain.getSelectedItem();
|
||||
|
||||
if( mixerGain == null )
|
||||
{
|
||||
mixerGain = DEFAULT_GAIN.getMixerGain();
|
||||
}
|
||||
|
||||
|
||||
if( mComboMixerGain.isEnabled() )
|
||||
{
|
||||
mController.setMixerGain( mixerGain, true );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the mixer "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply mixer "
|
||||
+ "gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboMixerGain.setToolTipText( "<html>Mixer Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
|
||||
add( new JLabel( "Mixer:" ) );
|
||||
add( mComboMixerGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the mixer "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
/* LNA Gain Control */
|
||||
mComboLNAGain = new JComboBox<R820TTunerController.R820TLNAGain>( R820TTunerController.R820TLNAGain.values() );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply mixer "
|
||||
+ "gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboMixerGain.setToolTipText( "<html>Mixer Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
|
||||
add( new JLabel( "Mixer:" ) );
|
||||
add( mComboMixerGain );
|
||||
|
||||
/* LNA Gain Control */
|
||||
mComboLNAGain = new JComboBox<R820TLNAGain>( R820TLNAGain.values() );
|
||||
mComboLNAGain.setEnabled( false );
|
||||
mComboLNAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TTunerController.R820TLNAGain lnaGain =
|
||||
(R820TTunerController.R820TLNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
{
|
||||
R820TLNAGain lnaGain =
|
||||
(R820TLNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
if ( lnaGain == null )
|
||||
{
|
||||
lnaGain = DEFAULT_GAIN.getLNAGain();
|
||||
}
|
||||
|
||||
|
||||
if( mComboLNAGain.isEnabled() )
|
||||
{
|
||||
mController.setLNAGain( lnaGain, true );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the LNA "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply LNA "
|
||||
+ "gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboLNAGain.setToolTipText( "<html>LNA Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
|
||||
add( new JLabel( "LNA:" ) );
|
||||
add( mComboLNAGain );
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the LNA "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
/* VGA Gain Control */
|
||||
mComboVGAGain = new JComboBox<R820TTunerController.R820TVGAGain>( R820TTunerController.R820TVGAGain.values() );
|
||||
mComboVGAGain.setEnabled( false );
|
||||
mComboVGAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply LNA "
|
||||
+ "gain setting - ", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboLNAGain.setToolTipText( "<html>LNA Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
|
||||
add( new JLabel( "LNA:" ) );
|
||||
add( mComboLNAGain );
|
||||
|
||||
/* VGA Gain Control */
|
||||
mComboVGAGain = new JComboBox<R820TVGAGain>( R820TVGAGain.values() );
|
||||
mComboVGAGain.setEnabled( false );
|
||||
mComboVGAGain.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
R820TTunerController.R820TVGAGain vgaGain =
|
||||
(R820TTunerController.R820TVGAGain)mComboVGAGain.getSelectedItem();
|
||||
{
|
||||
R820TVGAGain vgaGain =
|
||||
(R820TVGAGain)mComboVGAGain.getSelectedItem();
|
||||
|
||||
if( vgaGain == null )
|
||||
{
|
||||
vgaGain = DEFAULT_GAIN.getVGAGain();
|
||||
}
|
||||
|
||||
|
||||
if( mComboVGAGain.isEnabled() )
|
||||
{
|
||||
mController.setVGAGain( vgaGain, true );
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the VGA "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply VGA "
|
||||
+ "gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboVGAGain.setToolTipText( "<html>VGA Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
add( new JLabel( "VGA:" ) );
|
||||
add( mComboVGAGain );
|
||||
}
|
||||
|
||||
|
||||
save();
|
||||
}
|
||||
catch ( UsbException e )
|
||||
{
|
||||
JOptionPane.showMessageDialog( R820TTunerEditor.this,
|
||||
"R820T Tuner Controller - couldn't apply the VGA "
|
||||
+ "gain setting - " + e.getLocalizedMessage() );
|
||||
|
||||
mLog.error( "R820T Tuner Controller - couldn't apply VGA "
|
||||
+ "gain setting", e );
|
||||
}
|
||||
}
|
||||
} );
|
||||
mComboVGAGain.setToolTipText( "<html>VGA Gain. Set master gain "
|
||||
+ "to <b>MANUAL</b> to enable adjustment</html>" );
|
||||
add( new JLabel( "VGA:" ) );
|
||||
add( mComboVGAGain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each of the tuner configuration controls to the enabled argument state
|
||||
*/
|
||||
@@ -388,41 +402,41 @@ public class R820TTunerEditor extends TunerConfigurationEditor
|
||||
{
|
||||
mConfigurationName.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mTunerInfo.isEnabled() != enabled )
|
||||
{
|
||||
mTunerInfo.setEnabled( enabled );
|
||||
}
|
||||
|
||||
|
||||
if( mFrequencyCorrection.isEnabled() != enabled )
|
||||
{
|
||||
mFrequencyCorrection.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboSampleRate.isEnabled() != enabled )
|
||||
{
|
||||
mComboSampleRate.setEnabled( enabled );
|
||||
}
|
||||
if( mComboSampleRate.isEnabled() != enabled )
|
||||
{
|
||||
mComboSampleRate.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboMasterGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMasterGain.setEnabled( enabled );
|
||||
}
|
||||
if( mComboMasterGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMasterGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboMixerGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMixerGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboLNAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboVGAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboVGAGain.setEnabled( enabled );
|
||||
}
|
||||
if( mComboMixerGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboMixerGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboLNAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboLNAGain.setEnabled( enabled );
|
||||
}
|
||||
|
||||
if( mComboVGAGain.isEnabled() != enabled )
|
||||
{
|
||||
mComboVGAGain.setEnabled( enabled );
|
||||
}
|
||||
}
|
||||
|
||||
private String getTunerInfo()
|
||||
@@ -430,9 +444,9 @@ public class R820TTunerEditor extends TunerConfigurationEditor
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
RTL2832TunerController.Descriptor descriptor = mController.getDescriptor();
|
||||
|
||||
|
||||
sb.append( "<html><h3>RTL-2832 with R820T Tuner</h3>" );
|
||||
|
||||
|
||||
if( descriptor == null )
|
||||
{
|
||||
sb.append( "No EEPROM Descriptor Available" );
|
||||
@@ -468,37 +482,37 @@ public class R820TTunerEditor extends TunerConfigurationEditor
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
R820TTunerConfiguration config = getConfiguration();
|
||||
if( hasItem() && !mLoading )
|
||||
{
|
||||
R820TTunerConfiguration config = getConfiguration();
|
||||
|
||||
config.setName( mConfigurationName.getText() );
|
||||
config.setName( mConfigurationName.getText() );
|
||||
|
||||
double value = ((SpinnerNumberModel)mFrequencyCorrection
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
|
||||
config.setSampleRate( (RTL2832TunerController.SampleRate)mComboSampleRate.getSelectedItem() );
|
||||
|
||||
R820TTunerController.R820TGain gain = (R820TTunerController.R820TGain)mComboMasterGain.getSelectedItem();
|
||||
.getModel()).getNumber().doubleValue();
|
||||
config.setFrequencyCorrection( value );
|
||||
|
||||
config.setSampleRate( (SampleRate)mComboSampleRate.getSelectedItem() );
|
||||
|
||||
R820TGain gain = (R820TGain)mComboMasterGain.getSelectedItem();
|
||||
config.setMasterGain( gain );
|
||||
|
||||
R820TTunerController.R820TMixerGain mixerGain = (R820TTunerController.R820TMixerGain)mComboMixerGain.getSelectedItem();
|
||||
|
||||
R820TMixerGain mixerGain = (R820TMixerGain)mComboMixerGain.getSelectedItem();
|
||||
config.setMixerGain( mixerGain );
|
||||
|
||||
R820TTunerController.R820TLNAGain lnaGain = (R820TTunerController.R820TLNAGain)mComboLNAGain.getSelectedItem();
|
||||
|
||||
R820TLNAGain lnaGain = (R820TLNAGain)mComboLNAGain.getSelectedItem();
|
||||
config.setLNAGain( lnaGain );
|
||||
|
||||
R820TTunerController.R820TVGAGain vgaGain = (R820TTunerController.R820TVGAGain)mComboVGAGain.getSelectedItem();
|
||||
R820TVGAGain vgaGain = (R820TVGAGain)mComboVGAGain.getSelectedItem();
|
||||
config.setVGAGain( vgaGain );
|
||||
|
||||
getTunerConfigurationModel().broadcast(
|
||||
|
||||
getTunerConfigurationModel().broadcast(
|
||||
new TunerConfigurationEvent( getConfiguration(), TunerConfigurationEvent.Event.CHANGE ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -508,21 +522,21 @@ public class R820TTunerEditor extends TunerConfigurationEditor
|
||||
|
||||
//Toggle loading so that we don't fire a change event and schedule a settings file save
|
||||
mLoading = true;
|
||||
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
R820TTunerConfiguration config = getConfiguration();
|
||||
|
||||
|
||||
if( tunerConfiguration.isAssigned() )
|
||||
{
|
||||
setControlsEnabled( true );
|
||||
mConfigurationName.setText( config.getName() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mComboSampleRate.setSelectedItem( config.getSampleRate() );
|
||||
mComboMasterGain.setSelectedItem( config.getMasterGain() );
|
||||
mComboMixerGain.setSelectedItem( config.getMixerGain() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboVGAGain.setSelectedItem( config.getVGAGain() );
|
||||
mFrequencyCorrection.setValue( config.getFrequencyCorrection() );
|
||||
mComboSampleRate.setSelectedItem( config.getSampleRate() );
|
||||
mComboMasterGain.setSelectedItem( config.getMasterGain() );
|
||||
mComboMixerGain.setSelectedItem( config.getMixerGain() );
|
||||
mComboLNAGain.setSelectedItem( config.getLNAGain() );
|
||||
mComboVGAGain.setSelectedItem( config.getVGAGain() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -535,7 +549,7 @@ public class R820TTunerEditor extends TunerConfigurationEditor
|
||||
setControlsEnabled( false );
|
||||
mConfigurationName.setText( "" );
|
||||
}
|
||||
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.test;
|
||||
|
||||
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SampleGenerator
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(SampleGenerator.class);
|
||||
|
||||
private LowPhaseNoiseOscillator mOscillator;
|
||||
private int mSweepUpdateInterval;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private long mInterval;
|
||||
private int mSamplesPerInterval;
|
||||
private ScheduledFuture<?> mScheduledFuture;
|
||||
|
||||
/**
|
||||
* Generates complex sample buffers at the specified sample rate with a unity gain tone at the specified
|
||||
* frequency. This generator runs via a scheduled thread pool and generates samples at the specified time
|
||||
* interval.
|
||||
*
|
||||
* @param sampleRate of the complex samples
|
||||
* @param frequency of the tone produced by the generator
|
||||
* @param interval in milliseconds for generating samples
|
||||
* @param sweepUpdateRate to turn on sweeping of the tone frequency where the frequency is incremented by the
|
||||
* rate specified at each interval, resetting to 1 Hz after reaching/exceeding the highest frequency.
|
||||
*/
|
||||
public SampleGenerator(int sampleRate, long frequency, long interval, int sweepUpdateRate)
|
||||
{
|
||||
if(Math.abs(sweepUpdateRate) >= sampleRate)
|
||||
{
|
||||
throw new IllegalArgumentException("Sweep update rate cannot be greater than sample rate");
|
||||
}
|
||||
|
||||
mLog.debug("Sample Generator - Sample Rate:" + sampleRate + " Frequency:" + frequency);
|
||||
mOscillator = new LowPhaseNoiseOscillator(sampleRate, frequency);
|
||||
mInterval = interval;
|
||||
mSweepUpdateInterval = sweepUpdateRate;
|
||||
|
||||
updateSamplesPerInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates complex sample buffers at the specified sample rate with a unity gain tone at the specified
|
||||
* frequency. This generator runs via a scheduled thread pool and generates samples at the specified time
|
||||
* interval.
|
||||
*
|
||||
* @param sampleRate of the complex samples
|
||||
* @param frequency of the tone produced by the generator
|
||||
* @param interval in milliseconds for generating samples
|
||||
*/
|
||||
public SampleGenerator(int sampleRate, long frequency, long interval)
|
||||
{
|
||||
this(sampleRate, frequency, interval, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the number of complex samples generated per interval
|
||||
*/
|
||||
private void updateSamplesPerInterval()
|
||||
{
|
||||
mSamplesPerInterval = (int)((double)mOscillator.getSampleRate() * ((double)mInterval / 1000.0));
|
||||
|
||||
mLog.debug("Sample Generator - " + mSamplesPerInterval + " samples every " + mInterval + "ms");
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the generator producing samples
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
if(mScheduledFuture == null)
|
||||
{
|
||||
mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new Generator(), 0, mInterval,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException("Sample generator is already started");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the generator from producing samples
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
if(mScheduledFuture != null)
|
||||
{
|
||||
mScheduledFuture.cancel(true);
|
||||
mScheduledFuture = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException("Sample generator is already stopped");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive samples once the generator starts. Note: invoke this method with null
|
||||
* argument to de-register the listener.
|
||||
*
|
||||
* @param listener to receive complex sample buffers
|
||||
*/
|
||||
public void setListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tone frequency for this generator
|
||||
* @param frequency to generate
|
||||
*/
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
mOscillator.setFrequency(frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current tone frequency for this generator
|
||||
*/
|
||||
public long getFrequency()
|
||||
{
|
||||
return mOscillator.getFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sample rate for this generator
|
||||
* @param sampleRate in hertz for complex samples
|
||||
*/
|
||||
public void setSampleRate(int sampleRate)
|
||||
{
|
||||
mOscillator.setSampleRate(sampleRate);
|
||||
updateSamplesPerInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a complex sample buffer and distributes the buffer to a registered listener
|
||||
*/
|
||||
public class Generator implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if(mListener != null)
|
||||
{
|
||||
float[] samples = mOscillator.generate(mSamplesPerInterval);
|
||||
mListener.receive(new ComplexBuffer(samples));
|
||||
|
||||
if(mSweepUpdateInterval != 0)
|
||||
{
|
||||
long updatedFrequency = mOscillator.getFrequency() + mSweepUpdateInterval;
|
||||
|
||||
if(updatedFrequency > mOscillator.getSampleRate() / 2)
|
||||
{
|
||||
mOscillator.setFrequency(mOscillator.getSampleRate() / -2);
|
||||
}
|
||||
else if(updatedFrequency < mOscillator.getSampleRate() / -2)
|
||||
{
|
||||
mOscillator.setFrequency(mOscillator.getSampleRate() / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
mOscillator.setFrequency(updatedFrequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.test;
|
||||
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Testing tuner that implements an internal oscillator to output a unity gain tone at a specified frequency offset
|
||||
* from a configurable center tune frequency and sample rate
|
||||
*/
|
||||
public class TestTuner extends Tuner
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TestTuner.class);
|
||||
private static int mInstanceCounter = 1;
|
||||
private final int mInstanceID = mInstanceCounter++;
|
||||
|
||||
public TestTuner()
|
||||
{
|
||||
super("Test Tuner", new TestTunerController());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tuner controller cast as a test tuner controller.
|
||||
*
|
||||
* Note: this is a temporary method until the tuner controller interface can be updated with the start(listener)
|
||||
* and stop() methods.
|
||||
*/
|
||||
public TestTunerController getTunerController()
|
||||
{
|
||||
return (TestTunerController)getTunerController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
return getName() + "-" + mInstanceID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return TunerClass.TEST_TUNER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerClass.TEST_TUNER.getTunerType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleSize()
|
||||
{
|
||||
return 16.0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.test;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TestTunerController extends TunerController
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TestTunerController.class);
|
||||
|
||||
public static final long MINIMUM_FREQUENCY = 1000000l; //1 MHz
|
||||
public static final long MAXIMUM_FREQUENCY = 10000000000l; //10 GHz
|
||||
public static final long DEFAULT_CENTER_FREQUENCY = 100000000; //100 MHz
|
||||
public static final int DEFAULT_SAMPLE_RATE = 50000; //25 kHz
|
||||
public static final int DC_NOISE_BANDWIDTH = 5000; // +/-5 kHz
|
||||
public static final double USABLE_BANDWIDTH = 0.90; //90% usable bandwidth - 5% unusable on either end
|
||||
public static final int SPECTRAL_FRAME_RATE = 20;
|
||||
public static final long SAMPLE_GENERATION_INTERVAL = 1000 / SPECTRAL_FRAME_RATE;
|
||||
|
||||
private SampleGenerator mSampleGenerator;
|
||||
private long mReferenceFrequency = DEFAULT_CENTER_FREQUENCY;
|
||||
|
||||
/**
|
||||
* Tuner controller testing implementation.
|
||||
*/
|
||||
public TestTunerController()
|
||||
{
|
||||
super(MINIMUM_FREQUENCY, MAXIMUM_FREQUENCY, DC_NOISE_BANDWIDTH, USABLE_BANDWIDTH);
|
||||
|
||||
int sweepRate = 0; //Hz per interval
|
||||
|
||||
mSampleGenerator = new SampleGenerator(DEFAULT_SAMPLE_RATE, 12500, SAMPLE_GENERATION_INTERVAL, sweepRate);
|
||||
|
||||
try
|
||||
{
|
||||
mLog.debug("Setting frequency ...");
|
||||
mFrequencyController.setFrequency(DEFAULT_CENTER_FREQUENCY);
|
||||
mLog.debug("Setting sample rate of freq controller to: " + DEFAULT_SAMPLE_RATE);
|
||||
mFrequencyController.setSampleRate(DEFAULT_SAMPLE_RATE);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the tuner controller producing samples that will be delivered to the specified listener
|
||||
*/
|
||||
public void start(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mSampleGenerator.setListener(listener);
|
||||
mSampleGenerator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mSampleGenerator.stop();
|
||||
mSampleGenerator.setListener(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the tuner controller sample generator and deregisters the listener
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(TunerConfiguration config) throws SourceException
|
||||
{
|
||||
mLog.error("Request to apply tuner configuration was ignored");
|
||||
}
|
||||
|
||||
/**
|
||||
* Current center frequency for this tuner
|
||||
* @throws SourceException
|
||||
*/
|
||||
@Override
|
||||
public long getTunedFrequency() throws SourceException
|
||||
{
|
||||
return mReferenceFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the center frequency for this tuner
|
||||
* @param frequency in hertz
|
||||
* @throws SourceException
|
||||
*/
|
||||
@Override
|
||||
public void setTunedFrequency(long frequency) throws SourceException
|
||||
{
|
||||
mReferenceFrequency = frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tone frequency for the sample generator. The tone frequency is offset from the center tuned frequency.
|
||||
* @param toneFrequency
|
||||
*/
|
||||
public void setToneFrequency(long toneFrequency)
|
||||
{
|
||||
long frequency = toneFrequency - mReferenceFrequency;
|
||||
mSampleGenerator.setFrequency(frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current tone frequency for this test controller.
|
||||
* @return
|
||||
*/
|
||||
public long getToneFrequency()
|
||||
{
|
||||
return mReferenceFrequency + mSampleGenerator.getFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current sample rate for this tuner controller
|
||||
*/
|
||||
@Override
|
||||
public double getCurrentSampleRate()
|
||||
{
|
||||
return mFrequencyController.getSampleRate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sample rate for this tuner controller
|
||||
*/
|
||||
public void setSampleRate(int sampleRate) throws SourceException
|
||||
{
|
||||
mFrequencyController.setSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.tuner.usb;
|
||||
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
@@ -69,10 +68,10 @@ public class USBTransferProcessor implements TransferCallback
|
||||
//Byte array transfer buffers size in bytes
|
||||
private int mBufferSize;
|
||||
|
||||
private Broadcaster<ComplexBuffer> mComplexBufferBroadcaster = new Broadcaster<>();
|
||||
private OverflowableTransferQueue<byte[]> mFilledBuffers;
|
||||
private LinkedTransferQueue<Transfer> mAvailableTransfers = new LinkedTransferQueue<>();
|
||||
private LinkedTransferQueue<Transfer> mTransfersInProgress = new LinkedTransferQueue<>();
|
||||
private Listener<ComplexBuffer> mComplexBufferListener;
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
|
||||
@@ -233,36 +232,26 @@ public class USBTransferProcessor implements TransferCallback
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if there are complex buffer listeners registered with this processor
|
||||
* Sets the listener and auto-starts the buffer processor
|
||||
*/
|
||||
public boolean hasListeners()
|
||||
public void setListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
return mComplexBufferBroadcaster.hasListeners();
|
||||
}
|
||||
|
||||
public void addListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mComplexBufferBroadcaster.addListener(listener);
|
||||
|
||||
mComplexBufferListener = listener;
|
||||
start();
|
||||
}
|
||||
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
/**
|
||||
* Auto-stops the buffer processor and removes the listener
|
||||
*/
|
||||
public void removeListener()
|
||||
{
|
||||
mComplexBufferBroadcaster.removeListener(listener);
|
||||
|
||||
if(!hasListeners())
|
||||
if(mComplexBufferListener != null)
|
||||
{
|
||||
stop();
|
||||
mComplexBufferListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllListeners()
|
||||
{
|
||||
mComplexBufferBroadcaster.clear();
|
||||
stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares (allocates) a set of transfer buffers for use in transferring data from the USB device via the bulk
|
||||
* interface. Since we're using direct allocation (native), buffers are retained and reused across multiple
|
||||
@@ -424,7 +413,10 @@ public class USBTransferProcessor implements TransferCallback
|
||||
{
|
||||
float[] complexSamples = mSampleAdapter.convert(buffer);
|
||||
|
||||
mComplexBufferBroadcaster.broadcast(new ComplexBuffer(complexSamples));
|
||||
if(mComplexBufferListener != null)
|
||||
{
|
||||
mComplexBufferListener.receive(new ComplexBuffer(complexSamples));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 io.github.dsheirer.source.tuner.usb;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
|
||||
public abstract class USBTunerController extends TunerController
|
||||
{
|
||||
/**
|
||||
* USB tuner controller class. Provides auto-start and auto-stop function when complex buffer listeners are added
|
||||
* or removed from this tuner controller.
|
||||
*
|
||||
* @param minimumFrequency minimum uncorrected tunable frequency
|
||||
* @param maximumFrequency maximum uncorrected tunable frequency
|
||||
* @param middleUnusable is the +/- value center DC spike to avoid for channels
|
||||
* @param usableBandwidth percentage of usable bandwidth relative to space at the extreme ends of the spectrum
|
||||
*/
|
||||
public USBTunerController(long minimumFrequency, long maximumFrequency, int middleUnusable, double usableBandwidth)
|
||||
{
|
||||
super(minimumFrequency, maximumFrequency, middleUnusable, usableBandwidth);
|
||||
}
|
||||
|
||||
protected abstract USBTransferProcessor getUSBTransferProcessor();
|
||||
|
||||
/**
|
||||
* Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started.
|
||||
*/
|
||||
@Override
|
||||
public void addComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
boolean hasExistingListeners = hasComplexBufferListeners();
|
||||
|
||||
super.addComplexBufferListener(listener);
|
||||
|
||||
if(!hasExistingListeners)
|
||||
{
|
||||
getUSBTransferProcessor().setListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners.
|
||||
*/
|
||||
@Override
|
||||
public void removeComplexBufferListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
super.removeComplexBufferListener(listener);
|
||||
|
||||
if(!hasComplexBufferListeners())
|
||||
{
|
||||
getUSBTransferProcessor().removeListener();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,14 +18,13 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.wave;
|
||||
|
||||
import io.github.dsheirer.channel.heartbeat.Heartbeat;
|
||||
import io.github.dsheirer.sample.ConversionUtils;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.ComplexSource;
|
||||
import io.github.dsheirer.source.IControllableFileSource;
|
||||
import io.github.dsheirer.source.IFrameLocationListener;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -36,12 +35,10 @@ import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class ComplexWaveSource extends ComplexSource implements IControllableFileSource
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger(ComplexWaveSource.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexWaveSource.class);
|
||||
|
||||
private IFrameLocationListener mFrameLocationListener;
|
||||
private int mBytesPerFrame;
|
||||
@@ -57,49 +54,33 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented
|
||||
*/
|
||||
@Override
|
||||
public void setHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented
|
||||
*/
|
||||
@Override
|
||||
public void removeHeartbeatListener()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
stop();
|
||||
start(null);
|
||||
start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ScheduledExecutorService executor)
|
||||
public void start()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -132,11 +113,11 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSampleRate()
|
||||
public double getSampleRate()
|
||||
{
|
||||
if(mInputStream != null)
|
||||
{
|
||||
return (int)mInputStream.getFormat().getSampleRate();
|
||||
return mInputStream.getFormat().getSampleRate();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -17,14 +17,13 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.source.wave;
|
||||
|
||||
import io.github.dsheirer.channel.heartbeat.Heartbeat;
|
||||
import io.github.dsheirer.sample.ConversionUtils;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
import io.github.dsheirer.source.IControllableFileSource;
|
||||
import io.github.dsheirer.source.IFrameLocationListener;
|
||||
import io.github.dsheirer.source.RealSource;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -35,7 +34,6 @@ import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class RealWaveSource extends RealSource implements IControllableFileSource, AutoCloseable
|
||||
{
|
||||
@@ -54,52 +52,35 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented
|
||||
*/
|
||||
@Override
|
||||
public void setHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented
|
||||
*/
|
||||
@Override
|
||||
public void removeHeartbeatListener()
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
stop();
|
||||
start(null);
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start(ScheduledExecutorService executor)
|
||||
public void start()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -129,16 +110,15 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
@Override
|
||||
public long getFrameCount() throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSampleRate()
|
||||
public double getSampleRate()
|
||||
{
|
||||
if(mInputStream != null)
|
||||
{
|
||||
return (int)mInputStream.getFormat().getSampleRate();
|
||||
return mInputStream.getFormat().getSampleRate();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user