mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
#39 WIP - updates tunerchannelsource as the parent class for the CIC
and polyphase sub class implementations. Converts all source implementations and tuners to treat sample rate as a double.
This commit is contained in:
@@ -18,51 +18,85 @@
|
||||
******************************************************************************/
|
||||
package source.tuner.channel;
|
||||
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Buffer;
|
||||
import sample.Listener;
|
||||
import sample.complex.Complex;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import sample.real.IOverflowListener;
|
||||
import source.ComplexSource;
|
||||
import source.SourceException;
|
||||
import source.ISourceEventListener;
|
||||
import source.ISourceEventProvider;
|
||||
import source.SourceEvent;
|
||||
import source.ISourceEventProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.SourceEventListenerToProcessorAdapter;
|
||||
import source.SourceException;
|
||||
import util.ThreadPool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class TunerChannelSource extends ComplexSource implements ISourceEventProcessor, Listener<ComplexBuffer>
|
||||
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;
|
||||
protected Listener<SourceEvent> mSourceEventListener;
|
||||
private Listener<SourceEvent> mProducerSourceEventListener;
|
||||
private Listener<SourceEvent> mConsumerSourceEventListener;
|
||||
private BufferProcessor mBufferProcessor = new BufferProcessor();
|
||||
|
||||
/**
|
||||
* Requirements:
|
||||
* 1. Provide complex buffer samples
|
||||
* 2. Fetch complex buffer samples from subclass implementations (for distribution)
|
||||
* 3. Provide heartbeat at each interval
|
||||
* 4. Provide start/stop running
|
||||
* 5. Provide support for downstream consumer source events (delegate to the sub class)
|
||||
* 6. Support buffer overflow listeners
|
||||
* Tuner Channel Source is a Digital Drop Channel (DDC) abstract class that defines the minimum functionality
|
||||
* requirements for a channel sample source.
|
||||
*
|
||||
* @param sourceEventListener to receive source dispose request
|
||||
* @param tunerChannel
|
||||
* @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> sourceEventListener, TunerChannel tunerChannel)
|
||||
public TunerChannelSource(Listener<SourceEvent> producerSourceEventListener, TunerChannel tunerChannel)
|
||||
{
|
||||
mSourceEventListener = sourceEventListener;
|
||||
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
|
||||
*/
|
||||
@@ -71,17 +105,27 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this tuner channel source producing sample stream.
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
if(mSourceEventListener != null)
|
||||
//Broadcast current frequency and sample rate so consumer can configure correctly
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyChange(getFrequency()));
|
||||
broadcastConsumerSourceEvent(SourceEvent.sampleRateChange(getSampleRate()));
|
||||
|
||||
if(mProducerSourceEventListener != null)
|
||||
{
|
||||
mSourceEventListener.receive(SourceEvent.startSampleStream(this));
|
||||
mProducerSourceEventListener.receive(SourceEvent.startSampleStream(this));
|
||||
}
|
||||
|
||||
//TODO: broadcast center frequency and sample rate to downstream listeners.
|
||||
mBufferProcessor.start();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,11 +134,13 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
if(mSourceEventListener != null)
|
||||
if(mProducerSourceEventListener != null)
|
||||
{
|
||||
mSourceEventListener.receive(SourceEvent.stopSampleStream(this));
|
||||
mSourceEventListener.receive(SourceEvent.sourceDisposeRequest(this));
|
||||
mProducerSourceEventListener.receive(SourceEvent.stopSampleStream(this));
|
||||
mProducerSourceEventListener.receive(SourceEvent.sourceDisposeRequest(this));
|
||||
}
|
||||
|
||||
mBufferProcessor.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,4 +148,159 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
{
|
||||
//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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user