mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-15 10:07:26 -05:00
Automatic Frequency Control enhancement. Provides default AFC and ability to disable in the Decoder tab of each channel. Spectral display includes visual indicators of frequency center (grey) and current AFC offset (yellow).
This commit is contained in:
@@ -56,6 +56,7 @@ import controller.system.System;
|
|||||||
import decode.config.AuxDecodeConfiguration;
|
import decode.config.AuxDecodeConfiguration;
|
||||||
import decode.config.DecodeConfigFactory;
|
import decode.config.DecodeConfigFactory;
|
||||||
import decode.config.DecodeConfiguration;
|
import decode.config.DecodeConfiguration;
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
import eventlog.config.EventLogConfiguration;
|
import eventlog.config.EventLogConfiguration;
|
||||||
|
|
||||||
@XmlSeeAlso( { Configuration.class } )
|
@XmlSeeAlso( { Configuration.class } )
|
||||||
@@ -134,6 +135,27 @@ public class Channel extends Configuration
|
|||||||
return mChannelType;
|
return mChannelType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the channel is using Automatic Frequency Control
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean hasAFC()
|
||||||
|
{
|
||||||
|
return getAFC() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutomaticFrequencyControl getAFC()
|
||||||
|
{
|
||||||
|
if( isProcessing() )
|
||||||
|
{
|
||||||
|
return getProcessingChain().getAFC();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the resource manager responsible for this channel and registers
|
* Sets the resource manager responsible for this channel and registers
|
||||||
* the channel manager as a listener to this channel. Fires channel add
|
* the channel manager as a listener to this channel. Fires channel add
|
||||||
|
|||||||
@@ -34,13 +34,11 @@ import record.wave.ComplexWaveRecorder;
|
|||||||
import record.wave.FloatWaveRecorder;
|
import record.wave.FloatWaveRecorder;
|
||||||
import sample.Broadcaster;
|
import sample.Broadcaster;
|
||||||
import sample.Listener;
|
import sample.Listener;
|
||||||
import sample.Provider;
|
|
||||||
import sample.complex.ComplexSample;
|
import sample.complex.ComplexSample;
|
||||||
import source.ComplexSource;
|
import source.ComplexSource;
|
||||||
import source.FloatArraySource;
|
import source.FloatArraySource;
|
||||||
import source.FloatSource;
|
import source.FloatSource;
|
||||||
import source.Source;
|
import source.Source;
|
||||||
import source.Source.SampleType;
|
|
||||||
import source.SourceException;
|
import source.SourceException;
|
||||||
import source.config.SourceConfigMixer;
|
import source.config.SourceConfigMixer;
|
||||||
import source.tuner.Tuner;
|
import source.tuner.Tuner;
|
||||||
@@ -57,6 +55,8 @@ import controller.state.ChannelState;
|
|||||||
import controller.state.ChannelState.State;
|
import controller.state.ChannelState.State;
|
||||||
import decode.Decoder;
|
import decode.Decoder;
|
||||||
import decode.DecoderFactory;
|
import decode.DecoderFactory;
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
|
import dsp.afc.FrequencyErrorListener;
|
||||||
import eventlog.EventLogType;
|
import eventlog.EventLogType;
|
||||||
import eventlog.EventLogger;
|
import eventlog.EventLogger;
|
||||||
|
|
||||||
@@ -73,6 +73,7 @@ public class ProcessingChain implements Listener<Message>
|
|||||||
protected List<Recorder> mRecorders = new ArrayList<Recorder>();
|
protected List<Recorder> mRecorders = new ArrayList<Recorder>();
|
||||||
protected ArrayList<EventLogger> mEventLoggers = new ArrayList<EventLogger>();
|
protected ArrayList<EventLogger> mEventLoggers = new ArrayList<EventLogger>();
|
||||||
protected AudioOutput mAudioOutput;
|
protected AudioOutput mAudioOutput;
|
||||||
|
protected AutomaticFrequencyControl mAFC;
|
||||||
protected ChannelState mChannelState;
|
protected ChannelState mChannelState;
|
||||||
protected ResourceManager mResourceManager;
|
protected ResourceManager mResourceManager;
|
||||||
private ScheduledFuture<?> mProcessorTask;
|
private ScheduledFuture<?> mProcessorTask;
|
||||||
@@ -102,6 +103,14 @@ public class ProcessingChain implements Listener<Message>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatic Frequency Control, or null if disabled
|
||||||
|
*/
|
||||||
|
public AutomaticFrequencyControl getAFC()
|
||||||
|
{
|
||||||
|
return mAFC;
|
||||||
|
}
|
||||||
|
|
||||||
public Listener<List<ComplexSample>> getComplexListener()
|
public Listener<List<ComplexSample>> getComplexListener()
|
||||||
{
|
{
|
||||||
return mComplexListener;
|
return mComplexListener;
|
||||||
@@ -379,6 +388,28 @@ public class ProcessingChain implements Listener<Message>
|
|||||||
|
|
||||||
mAudioOutput = new AudioOutput( threadName );
|
mAudioOutput = new AudioOutput( threadName );
|
||||||
addFloatListener( mAudioOutput );
|
addFloatListener( mAudioOutput );
|
||||||
|
|
||||||
|
/* Automatic frequency control */
|
||||||
|
if( mAFC != null )
|
||||||
|
{
|
||||||
|
mAFC.dispose();
|
||||||
|
mAFC = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( mSource instanceof FrequencyErrorListener &&
|
||||||
|
mChannel.getDecodeConfiguration().isAFCEnabled() )
|
||||||
|
{
|
||||||
|
FrequencyErrorListener listener =
|
||||||
|
(FrequencyErrorListener)mSource;
|
||||||
|
|
||||||
|
mAFC = new AutomaticFrequencyControl( listener );
|
||||||
|
|
||||||
|
/* Register AFC to receive frequency change events */
|
||||||
|
listener.addListener( mAFC );
|
||||||
|
|
||||||
|
/* Add AFC as listener to the decoder */
|
||||||
|
mDecoder.addUnfilteredFloatListener( mAFC );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,11 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package decode;
|
package decode;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
|
||||||
import controller.Editor;
|
import controller.Editor;
|
||||||
import decode.config.DecodeConfiguration;
|
import decode.config.DecodeConfiguration;
|
||||||
|
|
||||||
@@ -26,9 +31,24 @@ public class DecodeEditor extends Editor
|
|||||||
|
|
||||||
protected DecodeConfiguration mConfig;
|
protected DecodeConfiguration mConfig;
|
||||||
|
|
||||||
|
protected JCheckBox mAFC;
|
||||||
|
|
||||||
public DecodeEditor( DecodeConfiguration config )
|
public DecodeEditor( DecodeConfiguration config )
|
||||||
{
|
{
|
||||||
mConfig = config;
|
mConfig = config;
|
||||||
|
|
||||||
|
mAFC = new JCheckBox( "Automatic Frequency Control" );
|
||||||
|
mAFC.setSelected( mConfig.isAFCEnabled() );
|
||||||
|
mAFC.addActionListener( new ActionListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void actionPerformed( ActionEvent arg0 )
|
||||||
|
{
|
||||||
|
mConfig.setAFC( mAFC.isSelected() );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
add( mAFC, "wrap" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecodeConfiguration getConfig()
|
public DecodeConfiguration getConfig()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package decode;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
import message.Message;
|
import message.Message;
|
||||||
import sample.Broadcaster;
|
import sample.Broadcaster;
|
||||||
import sample.Listener;
|
import sample.Listener;
|
||||||
@@ -131,6 +132,8 @@ public abstract class Decoder implements Listener<Message>
|
|||||||
mFloatBroadcaster.addListener( listener );
|
mFloatBroadcaster.addListener( listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void addUnfilteredFloatListener( Listener<Float> listener );
|
||||||
|
|
||||||
public void removeFloatListener( Listener<Float> listener )
|
public void removeFloatListener( Listener<Float> listener )
|
||||||
{
|
{
|
||||||
mFloatBroadcaster.removeListener( listener );
|
mFloatBroadcaster.removeListener( listener );
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package decode.config;
|
package decode.config;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ import decode.DecoderType;
|
|||||||
public abstract class DecodeConfiguration extends Configuration
|
public abstract class DecodeConfiguration extends Configuration
|
||||||
{
|
{
|
||||||
private DecoderType mDecoderType = DecoderType.NBFM;
|
private DecoderType mDecoderType = DecoderType.NBFM;
|
||||||
|
private boolean mAFCEnabled = true;
|
||||||
|
|
||||||
public DecodeConfiguration()
|
public DecodeConfiguration()
|
||||||
{
|
{
|
||||||
@@ -47,4 +49,20 @@ public abstract class DecodeConfiguration extends Configuration
|
|||||||
{
|
{
|
||||||
return mDecoderType;
|
return mDecoderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@XmlElement( name = "afc" )
|
||||||
|
public boolean getAFC()
|
||||||
|
{
|
||||||
|
return mAFCEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAFCEnabled()
|
||||||
|
{
|
||||||
|
return mAFCEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAFC( boolean enabled )
|
||||||
|
{
|
||||||
|
mAFCEnabled = enabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,4 +181,10 @@ public class Fleetsync2Decoder extends Decoder implements Instrumentable
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
//Not implemented
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import message.MessageDirection;
|
import message.MessageDirection;
|
||||||
|
import sample.Listener;
|
||||||
import source.Source.SampleType;
|
import source.Source.SampleType;
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
import bits.MessageFramer;
|
import bits.MessageFramer;
|
||||||
@@ -148,4 +149,14 @@ public class LTRNetDecoder extends Decoder implements Instrumentable
|
|||||||
{
|
{
|
||||||
mLTRFSKDecoder.removeTap( tap );
|
mLTRFSKDecoder.removeTap( tap );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
if( mDemodulator != null )
|
||||||
|
{
|
||||||
|
mDemodulator.addListener( listener );
|
||||||
|
}
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
import javax.swing.DefaultComboBoxModel;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
|
|
||||||
import message.MessageDirection;
|
import message.MessageDirection;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package decode.ltrstandard;
|
package decode.ltrstandard;
|
||||||
|
|
||||||
import message.MessageDirection;
|
import message.MessageDirection;
|
||||||
|
import sample.Listener;
|
||||||
import source.Source.SampleType;
|
import source.Source.SampleType;
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
import bits.MessageFramer;
|
import bits.MessageFramer;
|
||||||
@@ -115,4 +116,13 @@ public class LTRStandardDecoder extends Decoder
|
|||||||
{
|
{
|
||||||
return DecoderType.LTR_STANDARD;
|
return DecoderType.LTR_STANDARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
if( mDemodulator != null )
|
||||||
|
{
|
||||||
|
mDemodulator.addListener( listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import instrument.tap.stream.FloatTap;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import sample.Listener;
|
||||||
import source.Source.SampleType;
|
import source.Source.SampleType;
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
import bits.MessageFramer;
|
import bits.MessageFramer;
|
||||||
@@ -199,4 +200,10 @@ public class MDCDecoder extends Decoder implements Instrumentable
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
//Not implemented
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public class MPT1327ChannelState extends ChannelState
|
|||||||
private ChannelMap mChannelMap;
|
private ChannelMap mChannelMap;
|
||||||
private MPT1327ActivitySummary mActivitySummary;
|
private MPT1327ActivitySummary mActivitySummary;
|
||||||
|
|
||||||
|
|
||||||
public MPT1327ChannelState( ProcessingChain processingChain,
|
public MPT1327ChannelState( ProcessingChain processingChain,
|
||||||
AliasList aliasList,
|
AliasList aliasList,
|
||||||
ChannelMap channelMap )
|
ChannelMap channelMap )
|
||||||
@@ -156,72 +157,72 @@ public class MPT1327ChannelState extends ChannelState
|
|||||||
setState( State.CONTROL );
|
setState( State.CONTROL );
|
||||||
break;
|
break;
|
||||||
case GTC:
|
case GTC:
|
||||||
int channelNumber = mpt.getChannel();
|
if( mpt.isValidCall() )
|
||||||
|
|
||||||
if( !getProcessingChain().getChannel()
|
|
||||||
.hasTrafficChannel( channelNumber ) )
|
|
||||||
{
|
{
|
||||||
String aliasListName = mProcessingChain
|
int channelNumber = mpt.getChannel();
|
||||||
.getChannel().getAliasListName();
|
|
||||||
|
|
||||||
Channel traffic = getTrafficChannel( channelNumber,
|
if( !getProcessingChain().getChannel()
|
||||||
aliasListName );
|
.hasTrafficChannel( channelNumber ) )
|
||||||
|
{
|
||||||
|
String aliasListName = mProcessingChain
|
||||||
|
.getChannel().getAliasListName();
|
||||||
|
|
||||||
/* Set the system and site to same as control channel */
|
Channel traffic = getTrafficChannel( channelNumber,
|
||||||
traffic.setSystem( getProcessingChain().getChannel()
|
aliasListName );
|
||||||
.getSystem(), false );
|
|
||||||
traffic.setSite( getProcessingChain().getChannel()
|
|
||||||
.getSite(), false );
|
|
||||||
|
|
||||||
/* Add the traffic channel to the parent control channel */
|
/* Set the system and site to same as control channel */
|
||||||
getProcessingChain().getChannel()
|
traffic.setSystem( getProcessingChain().getChannel()
|
||||||
.addTrafficChannel( channelNumber, traffic );
|
.getSystem(), false );
|
||||||
|
traffic.setSite( getProcessingChain().getChannel()
|
||||||
|
.getSite(), false );
|
||||||
|
|
||||||
/* Start the traffic channel */
|
/* Add the traffic channel to the parent control channel */
|
||||||
traffic.setEnabled( true );
|
getProcessingChain().getChannel()
|
||||||
|
.addTrafficChannel( channelNumber, traffic );
|
||||||
|
|
||||||
/* Set traffic channel state info */
|
/* Start the traffic channel */
|
||||||
MPT1327ChannelState trafficState =
|
traffic.setEnabled( true );
|
||||||
(MPT1327ChannelState)traffic
|
|
||||||
.getProcessingChain().getChannelState();
|
|
||||||
|
|
||||||
MPT1327ChannelState controlState =
|
/* Set traffic channel state info */
|
||||||
(MPT1327ChannelState)getProcessingChain()
|
MPT1327ChannelState trafficState =
|
||||||
.getChannelState();
|
(MPT1327ChannelState)traffic
|
||||||
|
.getProcessingChain().getChannelState();
|
||||||
|
|
||||||
trafficState.setChannelMap( controlState.getChannelMap() );
|
MPT1327ChannelState controlState =
|
||||||
trafficState.setChannelNumber( channelNumber );
|
(MPT1327ChannelState)getProcessingChain()
|
||||||
trafficState.setFromTalkgroup( mpt.getFromID() );
|
.getChannelState();
|
||||||
trafficState.setToTalkgroup( mpt.getToID() );
|
|
||||||
|
|
||||||
/* Add this control channel as message listener on the
|
trafficState.setChannelMap( controlState.getChannelMap() );
|
||||||
* traffic channel so we can receive call tear-down
|
trafficState.setChannelNumber( channelNumber );
|
||||||
* messages */
|
trafficState.setFromTalkgroup( mpt.getFromID() );
|
||||||
traffic.addListener( (Listener<Message>)this );
|
trafficState.setToTalkgroup( mpt.getToID() );
|
||||||
|
|
||||||
CallEventType type = traffic.isProcessing() ?
|
/* Add this control channel as message listener on the
|
||||||
CallEventType.CALL_START :
|
* traffic channel so we can receive call tear-down
|
||||||
CallEventType.CALL_START_NO_TUNER;
|
* messages */
|
||||||
|
traffic.addListener( (Listener<Message>)this );
|
||||||
|
|
||||||
/*
|
CallEventType type = traffic.isProcessing() ?
|
||||||
* Set the traffic channel's call event model to
|
CallEventType.CALL_START :
|
||||||
* share the control channel's call event model
|
CallEventType.CALL_START_NO_TUNER;
|
||||||
*/
|
|
||||||
traffic.getProcessingChain().getChannelState()
|
|
||||||
.setCallEventModel( mCallEventModel );
|
|
||||||
|
|
||||||
mCallEventModel.add(
|
/*
|
||||||
new MPT1327CallEvent.Builder( type )
|
* Set the traffic channel's call event model to
|
||||||
.aliasList( traffic.getProcessingChain().getAliasList() )
|
* share the control channel's call event model
|
||||||
.channel( channelNumber )
|
*/
|
||||||
.frequency( mChannelMap.getFrequency( channelNumber ) )
|
traffic.getProcessingChain().getChannelState()
|
||||||
.from( mpt.getFromID() )
|
.setCallEventModel( mCallEventModel );
|
||||||
.to( mpt.getToID() )
|
|
||||||
.build() );
|
mCallEventModel.add(
|
||||||
|
new MPT1327CallEvent.Builder( type )
|
||||||
|
.aliasList( traffic.getProcessingChain().getAliasList() )
|
||||||
|
.channel( channelNumber )
|
||||||
|
.frequency( mChannelMap.getFrequency( channelNumber ) )
|
||||||
|
.from( mpt.getFromID() )
|
||||||
|
.to( mpt.getToID() )
|
||||||
|
.build() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long frequency = mChannelMap.getFrequency( channelNumber );
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CLEAR:
|
case CLEAR:
|
||||||
case MAINT:
|
case MAINT:
|
||||||
@@ -237,7 +238,7 @@ public class MPT1327ChannelState extends ChannelState
|
|||||||
mCallEventModel.add(
|
mCallEventModel.add(
|
||||||
new MPT1327CallEvent.Builder( CallEventType.SDM )
|
new MPT1327CallEvent.Builder( CallEventType.SDM )
|
||||||
.aliasList( mAliasList )
|
.aliasList( mAliasList )
|
||||||
.details( mpt.getMessageType().getDescription() )
|
.details( mpt.getMessage() )
|
||||||
.from( mpt.getFromID() )
|
.from( mpt.getFromID() )
|
||||||
.to( mpt.getToID() )
|
.to( mpt.getToID() )
|
||||||
.build() );
|
.build() );
|
||||||
@@ -378,6 +379,7 @@ public class MPT1327ChannelState extends ChannelState
|
|||||||
traffic.setSourceConfiguration( source );
|
traffic.setSourceConfiguration( source );
|
||||||
|
|
||||||
DecodeConfigMPT1327 decode = new DecodeConfigMPT1327();
|
DecodeConfigMPT1327 decode = new DecodeConfigMPT1327();
|
||||||
|
|
||||||
traffic.setDecodeConfiguration( decode );
|
traffic.setDecodeConfiguration( decode );
|
||||||
|
|
||||||
traffic.setAliasListName( aliasListName );
|
traffic.setAliasListName( aliasListName );
|
||||||
|
|||||||
@@ -25,13 +25,16 @@ import instrument.tap.stream.FloatTap;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import log.Log;
|
||||||
import sample.Broadcaster;
|
import sample.Broadcaster;
|
||||||
|
import sample.Listener;
|
||||||
import source.Source.SampleType;
|
import source.Source.SampleType;
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
import bits.MessageFramer;
|
import bits.MessageFramer;
|
||||||
import bits.SyncPattern;
|
import bits.SyncPattern;
|
||||||
import decode.Decoder;
|
import decode.Decoder;
|
||||||
import decode.DecoderType;
|
import decode.DecoderType;
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
import dsp.filter.DCRemovalFilter;
|
import dsp.filter.DCRemovalFilter;
|
||||||
import dsp.filter.FilterFactory;
|
import dsp.filter.FilterFactory;
|
||||||
import dsp.filter.Filters;
|
import dsp.filter.Filters;
|
||||||
@@ -95,7 +98,7 @@ public class MPT1327Decoder extends Decoder implements Instrumentable
|
|||||||
/* I/Q low pass filtering narrow band FM demodulator */
|
/* I/Q low pass filtering narrow band FM demodulator */
|
||||||
mNBFMDemodulator = new NBFMDemodulator(
|
mNBFMDemodulator = new NBFMDemodulator(
|
||||||
FilterFactory.getLowPass( 48000, 4000, 73, WindowType.HAMMING ),
|
FilterFactory.getLowPass( 48000, 4000, 73, WindowType.HAMMING ),
|
||||||
1.0002 );
|
1.0002, true );
|
||||||
|
|
||||||
this.addComplexListener( mNBFMDemodulator );
|
this.addComplexListener( mNBFMDemodulator );
|
||||||
|
|
||||||
@@ -167,6 +170,15 @@ public class MPT1327Decoder extends Decoder implements Instrumentable
|
|||||||
mTrafficMessageFramer.addMessageListener( mMessageProcessor );
|
mTrafficMessageFramer.addMessageListener( mMessageProcessor );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
if( mNBFMDemodulator != null )
|
||||||
|
{
|
||||||
|
mNBFMDemodulator.addListener( listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DecoderType getType()
|
public DecoderType getType()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -282,6 +282,13 @@ public class MPT1327Message extends Message
|
|||||||
mCRC[ 0 ] == CRC.CORRECTED;
|
mCRC[ 0 ] == CRC.CORRECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isValidCall()
|
||||||
|
{
|
||||||
|
return getPrefix() != 0 &&
|
||||||
|
getIdent1() != 0 &&
|
||||||
|
getIdent2() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a decoded message string
|
* Constructs a decoded message string
|
||||||
*/
|
*/
|
||||||
@@ -312,9 +319,9 @@ public class MPT1327Message extends Message
|
|||||||
*/
|
*/
|
||||||
public MPTMessageType getMessageType()
|
public MPTMessageType getMessageType()
|
||||||
{
|
{
|
||||||
int type = mMessage.getInt( B1_MESSAGE_TYPE );
|
int value = mMessage.getInt( B1_MESSAGE_TYPE );
|
||||||
|
|
||||||
return MPTMessageType.fromNumber( type );
|
return MPTMessageType.fromNumber( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -766,6 +773,7 @@ public class MPT1327Message extends Message
|
|||||||
case HEAD_PLUS2:
|
case HEAD_PLUS2:
|
||||||
case HEAD_PLUS3:
|
case HEAD_PLUS3:
|
||||||
case HEAD_PLUS4:
|
case HEAD_PLUS4:
|
||||||
|
sb.append( " " );
|
||||||
sb.append( getSDM() );
|
sb.append( getSDM() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -947,9 +955,12 @@ public class MPT1327Message extends Message
|
|||||||
break;
|
break;
|
||||||
case USER:
|
case USER:
|
||||||
default:
|
default:
|
||||||
sb.append( format( prefix, 3 ) );
|
if( prefix != 0 || ident != 0 )
|
||||||
sb.append( "-" );
|
{
|
||||||
sb.append( format( ident, 4) );
|
sb.append( format( prefix, 3 ) );
|
||||||
|
sb.append( "-" );
|
||||||
|
sb.append( format( ident, 4) );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1701,7 +1712,7 @@ public class MPT1327Message extends Message
|
|||||||
public enum Descriptor
|
public enum Descriptor
|
||||||
{
|
{
|
||||||
DESC0( "EXTENDED ADDRESSING INFORMATION",
|
DESC0( "EXTENDED ADDRESSING INFORMATION",
|
||||||
"SERIAL NUMBER",
|
"ESN",
|
||||||
"SINGLE SEGMENT TRANSACTIONS (SST) ONLY" ),
|
"SINGLE SEGMENT TRANSACTIONS (SST) ONLY" ),
|
||||||
DESC1( "PSTN DIALED DIGITS", "RESERVED", "N/A" ),
|
DESC1( "PSTN DIALED DIGITS", "RESERVED", "N/A" ),
|
||||||
DESC2( "PABX EXTENSION", "RESERVED", "N/A" ),
|
DESC2( "PABX EXTENSION", "RESERVED", "N/A" ),
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package decode.nbfm;
|
package decode.nbfm;
|
||||||
|
|
||||||
|
import sample.Listener;
|
||||||
import source.Source.SampleType;
|
import source.Source.SampleType;
|
||||||
import decode.Decoder;
|
import decode.Decoder;
|
||||||
import decode.DecoderType;
|
import decode.DecoderType;
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
import dsp.filter.DCRemovalFilter2;
|
import dsp.filter.DCRemovalFilter2;
|
||||||
import dsp.nbfm.FilteringNBFMDemodulator;
|
import dsp.nbfm.FilteringNBFMDemodulator;
|
||||||
|
|
||||||
@@ -74,4 +76,13 @@ public class NBFMConventionalDecoder extends Decoder
|
|||||||
{
|
{
|
||||||
return DecoderType.NBFM;
|
return DecoderType.NBFM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
if( mDemodulator != null )
|
||||||
|
{
|
||||||
|
mDemodulator.addListener( listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package decode.nbfm;
|
package decode.nbfm;
|
||||||
|
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
|
||||||
import decode.DecodeEditor;
|
import decode.DecodeEditor;
|
||||||
import decode.config.DecodeConfiguration;
|
import decode.config.DecodeConfiguration;
|
||||||
|
|
||||||
@@ -24,6 +26,8 @@ public class NBFMEditor extends DecodeEditor
|
|||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private JCheckBox mAFC;
|
||||||
|
|
||||||
public NBFMEditor( DecodeConfiguration config )
|
public NBFMEditor( DecodeConfiguration config )
|
||||||
{
|
{
|
||||||
super( config );
|
super( config );
|
||||||
|
|||||||
@@ -24,10 +24,12 @@ import instrument.tap.stream.FloatTap;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import sample.Listener;
|
||||||
import source.Source.SampleType;
|
import source.Source.SampleType;
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
import decode.Decoder;
|
import decode.Decoder;
|
||||||
import decode.DecoderType;
|
import decode.DecoderType;
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
import dsp.filter.DCRemovalFilter2;
|
import dsp.filter.DCRemovalFilter2;
|
||||||
import dsp.fsk.C4FMDecoder;
|
import dsp.fsk.C4FMDecoder;
|
||||||
import dsp.nbfm.FilteringNBFMDemodulator;
|
import dsp.nbfm.FilteringNBFMDemodulator;
|
||||||
@@ -141,4 +143,11 @@ public class P25Decoder extends Decoder implements Instrumentable
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,14 @@ import instrument.tap.Tap;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import sample.Listener;
|
||||||
import source.Source.SampleType;
|
import source.Source.SampleType;
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
import bits.MessageFramer;
|
import bits.MessageFramer;
|
||||||
import bits.SyncPattern;
|
import bits.SyncPattern;
|
||||||
import decode.Decoder;
|
import decode.Decoder;
|
||||||
import decode.DecoderType;
|
import decode.DecoderType;
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
import dsp.filter.DCRemovalFilter2;
|
import dsp.filter.DCRemovalFilter2;
|
||||||
import dsp.fsk.LTRFSKDecoder;
|
import dsp.fsk.LTRFSKDecoder;
|
||||||
import dsp.nbfm.FilteringNBFMDemodulator;
|
import dsp.nbfm.FilteringNBFMDemodulator;
|
||||||
@@ -138,4 +140,13 @@ public class PassportDecoder extends Decoder implements Instrumentable
|
|||||||
{
|
{
|
||||||
mPassportFSKDecoder.removeTap( tap );
|
mPassportFSKDecoder.removeTap( tap );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnfilteredFloatListener( Listener<Float> listener )
|
||||||
|
{
|
||||||
|
if( mNBFMDemodulator != null )
|
||||||
|
{
|
||||||
|
mNBFMDemodulator.addListener( listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
169
src/dsp/afc/AutomaticFrequencyControl.java
Normal file
169
src/dsp/afc/AutomaticFrequencyControl.java
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package dsp.afc;
|
||||||
|
|
||||||
|
import sample.Listener;
|
||||||
|
import source.tuner.FrequencyChangeListener;
|
||||||
|
import buffer.FloatAveragingBuffer;
|
||||||
|
|
||||||
|
public class AutomaticFrequencyControl implements Listener<Float>,
|
||||||
|
FrequencyChangeListener
|
||||||
|
{
|
||||||
|
private static float LARGE_ERROR = 10000.0f;
|
||||||
|
private static float MEDIUM_ERROR = 5000.0f;
|
||||||
|
private static float SMALL_ERROR = 1000.0f;
|
||||||
|
private static float FINE_ERROR = 500.0f;
|
||||||
|
private static int SAMPLE_THRESHOLD = 15000;
|
||||||
|
private Mode mMode = Mode.FAST;
|
||||||
|
|
||||||
|
private FloatAveragingBuffer mBuffer =
|
||||||
|
new FloatAveragingBuffer( SAMPLE_THRESHOLD );
|
||||||
|
|
||||||
|
private int mSampleCounter = 0;
|
||||||
|
private int mSkipCounter = 0;
|
||||||
|
private int mSkipThreshold = 4;
|
||||||
|
private int mErrorCorrection = 0;
|
||||||
|
private long mCurrentFrequency;
|
||||||
|
private int mCurrentSampleRate;
|
||||||
|
private FrequencyErrorListener mListener;
|
||||||
|
|
||||||
|
public enum Mode
|
||||||
|
{
|
||||||
|
NORMAL,FAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutomaticFrequencyControl( FrequencyErrorListener listener )
|
||||||
|
{
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
mListener = null;
|
||||||
|
mBuffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getErrorCorrection()
|
||||||
|
{
|
||||||
|
return mErrorCorrection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
mErrorCorrection = 0;
|
||||||
|
mMode = Mode.FAST;
|
||||||
|
dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dispatch()
|
||||||
|
{
|
||||||
|
if( mListener != null )
|
||||||
|
{
|
||||||
|
mListener.setError( mErrorCorrection );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void receive( Float sample )
|
||||||
|
{
|
||||||
|
if( mMode == Mode.FAST )
|
||||||
|
{
|
||||||
|
float average = mBuffer.get( sample.floatValue() );
|
||||||
|
|
||||||
|
mSampleCounter++;
|
||||||
|
|
||||||
|
if( mSampleCounter >= SAMPLE_THRESHOLD )
|
||||||
|
{
|
||||||
|
mSampleCounter = 0;
|
||||||
|
|
||||||
|
update( average );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mSkipCounter++;
|
||||||
|
|
||||||
|
if( mSkipCounter >= mSkipThreshold )
|
||||||
|
{
|
||||||
|
mSkipCounter = 0;
|
||||||
|
|
||||||
|
float average = mBuffer.get( sample.floatValue() );
|
||||||
|
|
||||||
|
mSampleCounter++;
|
||||||
|
|
||||||
|
if( mSampleCounter >= SAMPLE_THRESHOLD )
|
||||||
|
{
|
||||||
|
mSampleCounter = 0;
|
||||||
|
|
||||||
|
update( average );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update( float average )
|
||||||
|
{
|
||||||
|
int correction = 0;
|
||||||
|
|
||||||
|
if( average > LARGE_ERROR )
|
||||||
|
{
|
||||||
|
correction = -1000;
|
||||||
|
mMode = Mode.FAST;
|
||||||
|
}
|
||||||
|
else if( average > MEDIUM_ERROR )
|
||||||
|
{
|
||||||
|
correction = -500;
|
||||||
|
mMode = Mode.FAST;
|
||||||
|
}
|
||||||
|
else if( average > SMALL_ERROR )
|
||||||
|
{
|
||||||
|
correction = -100;
|
||||||
|
mMode = Mode.NORMAL;
|
||||||
|
}
|
||||||
|
else if( average > FINE_ERROR )
|
||||||
|
{
|
||||||
|
correction = -50;
|
||||||
|
mMode = Mode.NORMAL;
|
||||||
|
}
|
||||||
|
else if( average < -LARGE_ERROR )
|
||||||
|
{
|
||||||
|
correction = 1000;
|
||||||
|
mMode = Mode.FAST;
|
||||||
|
}
|
||||||
|
else if( average < -MEDIUM_ERROR )
|
||||||
|
{
|
||||||
|
correction = 500;
|
||||||
|
mMode = Mode.FAST;
|
||||||
|
}
|
||||||
|
else if( average < -SMALL_ERROR )
|
||||||
|
{
|
||||||
|
correction = 100;
|
||||||
|
mMode = Mode.NORMAL;
|
||||||
|
}
|
||||||
|
else if( average < -FINE_ERROR )
|
||||||
|
{
|
||||||
|
correction = 50;
|
||||||
|
mMode = Mode.NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( correction != 0 )
|
||||||
|
{
|
||||||
|
mErrorCorrection -= correction;
|
||||||
|
dispatch();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mMode = Mode.NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void frequencyChanged( long frequency, int bandwidth )
|
||||||
|
{
|
||||||
|
if( mCurrentFrequency != frequency || mCurrentSampleRate != bandwidth )
|
||||||
|
{
|
||||||
|
mCurrentFrequency = frequency;
|
||||||
|
mCurrentSampleRate = bandwidth;
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/dsp/afc/FrequencyErrorListener.java
Normal file
10
src/dsp/afc/FrequencyErrorListener.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package dsp.afc;
|
||||||
|
|
||||||
|
import source.tuner.FrequencyChangeListener;
|
||||||
|
|
||||||
|
public interface FrequencyErrorListener
|
||||||
|
{
|
||||||
|
public void setError( int error );
|
||||||
|
|
||||||
|
public void addListener( FrequencyChangeListener listener );
|
||||||
|
}
|
||||||
@@ -17,9 +17,11 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package dsp.nbfm;
|
package dsp.nbfm;
|
||||||
|
|
||||||
|
import log.Log;
|
||||||
import sample.Broadcaster;
|
import sample.Broadcaster;
|
||||||
import sample.Listener;
|
import sample.Listener;
|
||||||
import sample.complex.ComplexSample;
|
import sample.complex.ComplexSample;
|
||||||
|
import dsp.afc.AutomaticFrequencyControl;
|
||||||
import dsp.filter.ComplexFIRFilter;
|
import dsp.filter.ComplexFIRFilter;
|
||||||
import dsp.filter.FilterFactory;
|
import dsp.filter.FilterFactory;
|
||||||
import dsp.filter.Window.WindowType;
|
import dsp.filter.Window.WindowType;
|
||||||
@@ -30,7 +32,17 @@ public class NBFMDemodulator implements Listener<ComplexSample>
|
|||||||
private ComplexFIRFilter mIQFilter;
|
private ComplexFIRFilter mIQFilter;
|
||||||
private FMDiscriminator mDiscriminator;
|
private FMDiscriminator mDiscriminator;
|
||||||
|
|
||||||
public NBFMDemodulator( double[] iqFilter, double iqGain )
|
/**
|
||||||
|
* Implements a quadrature narrow-band demodulator that produces float
|
||||||
|
* valued demodulated, audio filtered output samples.
|
||||||
|
*/
|
||||||
|
public NBFMDemodulator()
|
||||||
|
{
|
||||||
|
this( FilterFactory.getLowPass( 48000, 4000, 73, WindowType.HAMMING ),
|
||||||
|
1.0002, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
public NBFMDemodulator( double[] iqFilter, double iqGain, boolean afc )
|
||||||
{
|
{
|
||||||
mIQFilter = new ComplexFIRFilter( iqFilter, iqGain );
|
mIQFilter = new ComplexFIRFilter( iqFilter, iqGain );
|
||||||
|
|
||||||
@@ -54,16 +66,6 @@ public class NBFMDemodulator implements Listener<ComplexSample>
|
|||||||
mIQFilter.dispose();
|
mIQFilter.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a quadrature narrow-band demodulator that produces float
|
|
||||||
* valued demodulated, audio filtered output samples.
|
|
||||||
*/
|
|
||||||
public NBFMDemodulator()
|
|
||||||
{
|
|
||||||
this( FilterFactory.getLowPass( 48000, 4000, 73, WindowType.HAMMING ),
|
|
||||||
1.0002 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive method for complex samples that are fed into this class to be
|
* Receive method for complex samples that are fed into this class to be
|
||||||
* processed
|
* processed
|
||||||
|
|||||||
@@ -24,22 +24,23 @@ import java.util.concurrent.RejectedExecutionException;
|
|||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import log.Log;
|
||||||
import sample.Listener;
|
import sample.Listener;
|
||||||
import sample.Provider;
|
|
||||||
import sample.complex.ComplexSample;
|
import sample.complex.ComplexSample;
|
||||||
import sample.complex.ComplexSampleAssembler;
|
import sample.complex.ComplexSampleAssembler;
|
||||||
import source.ComplexSource;
|
import source.ComplexSource;
|
||||||
import source.Source.SampleType;
|
|
||||||
import source.SourceException;
|
import source.SourceException;
|
||||||
import util.Oscillator;
|
import util.Oscillator;
|
||||||
import controller.ThreadPoolManager;
|
import controller.ThreadPoolManager;
|
||||||
import controller.ThreadPoolManager.ThreadType;
|
import controller.ThreadPoolManager.ThreadType;
|
||||||
|
import dsp.afc.FrequencyErrorListener;
|
||||||
import dsp.filter.ComplexFilter;
|
import dsp.filter.ComplexFilter;
|
||||||
import dsp.filter.FilterFactory;
|
import dsp.filter.FilterFactory;
|
||||||
import dsp.filter.Window.WindowType;
|
import dsp.filter.Window.WindowType;
|
||||||
|
|
||||||
public class TunerChannelSource extends ComplexSource
|
public class TunerChannelSource extends ComplexSource
|
||||||
implements FrequencyChangeListener,
|
implements FrequencyChangeListener,
|
||||||
|
FrequencyErrorListener,
|
||||||
Listener<Float[]>
|
Listener<Float[]>
|
||||||
{
|
{
|
||||||
private static int sCHANNEL_RATE = 48000;
|
private static int sCHANNEL_RATE = 48000;
|
||||||
@@ -55,8 +56,10 @@ public class TunerChannelSource extends ComplexSource
|
|||||||
|
|
||||||
private ComplexSampleAssembler mBufferAssembler =
|
private ComplexSampleAssembler mBufferAssembler =
|
||||||
new ComplexSampleAssembler( 3000 );
|
new ComplexSampleAssembler( 3000 );
|
||||||
private long mTunerFrequency;
|
private long mTunerFrequency = 0;
|
||||||
|
private int mTunerFrequencyError = 0;
|
||||||
private int mTunerSampleRate;
|
private int mTunerSampleRate;
|
||||||
|
private FrequencyChangeListener mFrequencyChangeListener;
|
||||||
private ThreadPoolManager mThreadPoolManager;
|
private ThreadPoolManager mThreadPoolManager;
|
||||||
private ScheduledFuture<?> mTaskHandle;
|
private ScheduledFuture<?> mTaskHandle;
|
||||||
|
|
||||||
@@ -95,6 +98,8 @@ public class TunerChannelSource extends ComplexSource
|
|||||||
@Override
|
@Override
|
||||||
public void dispose()
|
public void dispose()
|
||||||
{
|
{
|
||||||
|
mFrequencyChangeListener = null;
|
||||||
|
|
||||||
//Tell the tuner to release our resources
|
//Tell the tuner to release our resources
|
||||||
mTuner.removeListener( (FrequencyChangeListener)this );
|
mTuner.removeListener( (FrequencyChangeListener)this );
|
||||||
mTuner.releaseChannel( this );
|
mTuner.releaseChannel( this );
|
||||||
@@ -155,43 +160,33 @@ public class TunerChannelSource extends ComplexSource
|
|||||||
@Override
|
@Override
|
||||||
public void frequencyChanged( long frequency, int bandwidth )
|
public void frequencyChanged( long frequency, int bandwidth )
|
||||||
{
|
{
|
||||||
|
/* Send change to Automatic Frequency Control */
|
||||||
/* Frequency change */
|
if( mFrequencyChangeListener != null )
|
||||||
if( frequency != mTunerFrequency )
|
|
||||||
{
|
{
|
||||||
long frequencyOffset = frequency - mTunerChannel.getFrequency();
|
mFrequencyChangeListener.frequencyChanged( frequency, bandwidth );
|
||||||
|
|
||||||
if( mSineWaveGenerator == null )
|
|
||||||
{
|
|
||||||
mSineWaveGenerator =
|
|
||||||
new Oscillator( frequencyOffset, bandwidth );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mSineWaveGenerator.setFrequency( frequencyOffset );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the buffer for the frequency to take immediate effect */
|
|
||||||
mBuffer.clear();
|
|
||||||
|
|
||||||
mTunerFrequency = frequency;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long frequencyOffset = frequency -
|
||||||
|
mTunerChannel.getFrequency() -
|
||||||
|
mTunerFrequencyError;
|
||||||
|
|
||||||
|
if( mSineWaveGenerator == null )
|
||||||
|
{
|
||||||
|
mSineWaveGenerator = new Oscillator( frequencyOffset, bandwidth );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mSineWaveGenerator.setFrequency( frequencyOffset );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the buffer for the frequency to take immediate effect */
|
||||||
|
// mBuffer.clear();
|
||||||
|
|
||||||
|
mTunerFrequency = frequency;
|
||||||
|
|
||||||
/* Bandwidth/Sample rate change */
|
/* Bandwidth/Sample rate change */
|
||||||
if( bandwidth != mTunerSampleRate )
|
if( bandwidth != mTunerSampleRate )
|
||||||
{
|
{
|
||||||
long frequencyOffset = frequency - mTunerChannel.getFrequency();
|
|
||||||
|
|
||||||
if( mSineWaveGenerator == null )
|
|
||||||
{
|
|
||||||
mSineWaveGenerator =
|
|
||||||
new Oscillator( frequencyOffset, bandwidth );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mSineWaveGenerator.setSampleRate( bandwidth );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the original decimation filter output listener */
|
/* Get the original decimation filter output listener */
|
||||||
Listener<ComplexSample> listener = null;
|
Listener<ComplexSample> listener = null;
|
||||||
|
|
||||||
@@ -270,4 +265,26 @@ public class TunerChannelSource extends ComplexSource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatic Frequency Control
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setError( int error )
|
||||||
|
{
|
||||||
|
if( mTunerFrequencyError != error )
|
||||||
|
{
|
||||||
|
mTunerFrequencyError = error;
|
||||||
|
frequencyChanged( mTunerFrequency, mTunerSampleRate );
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info( "TunerChannelSource - mistuned quantity:" +
|
||||||
|
mTunerFrequencyError + " Hz" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addListener( FrequencyChangeListener listener )
|
||||||
|
{
|
||||||
|
mFrequencyChangeListener = listener;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1354,7 +1354,7 @@ public abstract class RTL2832TunerController extends TunerController
|
|||||||
RATE_1_440MHZ( 0x0500, 0x0000, 1440000, "1.440 MHz" ),
|
RATE_1_440MHZ( 0x0500, 0x0000, 1440000, "1.440 MHz" ),
|
||||||
RATE_1_680MHZ( 0x044A, 0x0000, 1680000, "1.680 MHz" ),
|
RATE_1_680MHZ( 0x044A, 0x0000, 1680000, "1.680 MHz" ),
|
||||||
RATE_1_824MHZ( 0x03F3, 0x0000, 1824000, "1.824 MHz" ),
|
RATE_1_824MHZ( 0x03F3, 0x0000, 1824000, "1.824 MHz" ),
|
||||||
RATE_2_016MHZ( 0x0387, 0x0000, 2016000, "2.016 MHz" );
|
RATE_2_016MHZ( 0x038F, 0x0000, 2016000, "2.016 MHz" );
|
||||||
|
|
||||||
/* Note: usb4java library buffer processing scheme doesn't seem capable
|
/* Note: usb4java library buffer processing scheme doesn't seem capable
|
||||||
* of supporting these rates */
|
* of supporting these rates */
|
||||||
|
|||||||
@@ -302,6 +302,32 @@ public class OverlayPanel extends JPanel
|
|||||||
xaxis, (float)(getSize().getHeight()) - mSpectrumInset ) );
|
xaxis, (float)(getSize().getHeight()) - mSpectrumInset ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a vertical line at the xaxis
|
||||||
|
*/
|
||||||
|
private void drawAFC( Graphics2D graphics, float xaxis, boolean isError )
|
||||||
|
{
|
||||||
|
float height = (float)(getSize().getHeight()) - mSpectrumInset;
|
||||||
|
|
||||||
|
if( isError )
|
||||||
|
{
|
||||||
|
graphics.setColor( Color.YELLOW );
|
||||||
|
|
||||||
|
graphics.draw( new Line2D.Float( xaxis, height * 0.75f,
|
||||||
|
xaxis, height - 1.0f ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
graphics.setColor( Color.LIGHT_GRAY );
|
||||||
|
|
||||||
|
graphics.draw( new Line2D.Float( xaxis, height * 0.65f,
|
||||||
|
xaxis, height - 1.0f ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the x-axis value corresponding to the frequency
|
* Returns the x-axis value corresponding to the frequency
|
||||||
*/
|
*/
|
||||||
@@ -436,8 +462,22 @@ public class OverlayPanel extends JPanel
|
|||||||
yAxis,
|
yAxis,
|
||||||
width );
|
width );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Draw Automatic Frequency Control line */
|
||||||
|
if( channel.hasAFC() )
|
||||||
|
{
|
||||||
|
int frequency = (int)tunerChannel.getFrequency();
|
||||||
|
|
||||||
|
int error = frequency + channel.getAFC().getErrorCorrection();
|
||||||
|
|
||||||
|
drawAFC( graphics, getAxisFromFrequency( frequency ), false );
|
||||||
|
|
||||||
|
drawAFC( graphics, getAxisFromFrequency( error ), true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a textual label at the x/y position, clipping the end of the text
|
* Draws a textual label at the x/y position, clipping the end of the text
|
||||||
* to fit within the maxwidth value.
|
* to fit within the maxwidth value.
|
||||||
|
|||||||
Reference in New Issue
Block a user