diff --git a/.classpath b/.classpath
index 5ac3191b..893c713b 100644
--- a/.classpath
+++ b/.classpath
@@ -24,6 +24,6 @@
-
+
diff --git a/src/controller/channel/Channel.java b/src/controller/channel/Channel.java
index 1ae34152..106d507e 100644
--- a/src/controller/channel/Channel.java
+++ b/src/controller/channel/Channel.java
@@ -48,6 +48,7 @@ import source.config.SourceConfigTuner;
import source.config.SourceConfiguration;
import source.tuner.TunerChannel;
import source.tuner.TunerChannel.Type;
+import source.tuner.frequency.AutomaticFrequencyControl;
import controller.ResourceManager;
import controller.activity.ActivitySummaryFrame;
import controller.channel.ChannelEvent.Event;
@@ -59,7 +60,6 @@ import controller.system.System;
import decode.config.AuxDecodeConfiguration;
import decode.config.DecodeConfigFactory;
import decode.config.DecodeConfiguration;
-import dsp.frequency.AutomaticFrequencyControl;
import eventlog.config.EventLogConfiguration;
@XmlSeeAlso( { Configuration.class } )
@@ -145,14 +145,15 @@ public class Channel extends Configuration
*/
public boolean hasFrequencyControl()
{
- return mProcessingChain != null && mProcessingChain.hasFrequencyControl();
+ return mProcessingChain != null &&
+ mProcessingChain.getDecoder().hasFrequencyCorrectionControl();
}
public long getFrequencyCorrection()
{
if( mProcessingChain != null )
{
- return mProcessingChain.getFrequencyCorrection();
+ return mProcessingChain.getDecoder().getFrequencyCorrection();
}
return 0;
diff --git a/src/controller/channel/ProcessingChain.java b/src/controller/channel/ProcessingChain.java
index b7d1ef58..92a0a9c7 100644
--- a/src/controller/channel/ProcessingChain.java
+++ b/src/controller/channel/ProcessingChain.java
@@ -46,12 +46,11 @@ import source.RealSource;
import source.Source;
import source.SourceException;
import source.config.SourceConfigMixer;
-import source.tuner.DirectFrequencyController;
-import source.tuner.FrequencyChangeListener;
import source.tuner.Tuner;
import source.tuner.TunerChannelSource;
+import source.tuner.frequency.AutomaticFrequencyControl;
+import source.tuner.frequency.FrequencyCorrectionControl;
import alias.AliasList;
-import audio.AudioOutputImpl;
import audio.IAudioOutput;
import audio.IAudioTypeListener;
import audio.SquelchListener;
@@ -63,7 +62,6 @@ import controller.state.ChannelState;
import controller.state.ChannelState.State;
import decode.Decoder;
import decode.DecoderFactory;
-import dsp.frequency.AutomaticFrequencyControl;
import eventlog.EventLogType;
import eventlog.EventLogger;
@@ -120,31 +118,6 @@ public class ProcessingChain implements Listener
return null;
}
- /**
- * Current frequency correction setting
- */
- public long getFrequencyCorrection()
- {
- if( mAFC != null )
- {
- return mAFC.getErrorCorrection();
- }
- else if( mDecoder != null &&
- mDecoder instanceof DirectFrequencyController )
- {
- return ( (DirectFrequencyController)mDecoder).getFrequencyCorrection();
- }
-
- return 0;
- }
-
- public boolean hasFrequencyControl()
- {
- return mAFC != null ||
- ( mDecoder != null &&
- mDecoder instanceof DirectFrequencyController );
- }
-
public Listener> getComplexReceiver()
{
return mComplexReceiver;
@@ -373,37 +346,20 @@ public class ProcessingChain implements Listener
/* Register to receive decoded messages and auxiliary messages */
mDecoder.addMessageListener( ProcessingChain.this );
- /* Automatic frequency control */
- if( mAFC != null )
- {
- mAFC.dispose();
- mAFC = null;
- }
-
- if( mSource instanceof TunerChannelSource )
+ /* Establish two-way communication between the frequency
+ * correction controller and the tuner channel source */
+ if( mSource instanceof TunerChannelSource &&
+ mDecoder.hasFrequencyCorrectionControl() )
{
TunerChannelSource tcs = (TunerChannelSource)mSource;
- if( mChannel.getDecodeConfiguration().supportsAFC() &&
- mChannel.getDecodeConfiguration().isAFCEnabled() )
+ FrequencyCorrectionControl fcc =
+ mDecoder.getFrequencyCorrectionControl();
+
+ if( fcc != null )
{
-
- int maximumCorrection = mChannel
- .getDecodeConfiguration().getAFCMaximumCorrection();
-
- mAFC = new AutomaticFrequencyControl( tcs,
- maximumCorrection );
-
- /* Register AFC to receive frequency change events */
- tcs.addListener( mAFC );
-
- /* Add AFC as listener to the decoder */
- mDecoder.addUnfilteredRealSampleListener( mAFC );
- }
- else if( mDecoder instanceof DirectFrequencyController )
- {
- ((DirectFrequencyController)mDecoder)
- .setListener( (FrequencyChangeListener)tcs );
+ tcs.addListener( fcc );
+ fcc.setListener( tcs );
}
}
diff --git a/src/decode/Decoder.java b/src/decode/Decoder.java
index 62455e18..7fe365e4 100644
--- a/src/decode/Decoder.java
+++ b/src/decode/Decoder.java
@@ -27,7 +27,10 @@ import sample.complex.ComplexSample;
import sample.real.RealSampleBroadcaster;
import sample.real.RealSampleListener;
import source.Source.SampleType;
+import source.tuner.frequency.AutomaticFrequencyControl;
+import source.tuner.frequency.FrequencyCorrectionControl;
import audio.IAudioOutput;
+import decode.config.DecodeConfiguration;
import eventlog.MessageEventLogger;
public abstract class Decoder implements Listener
@@ -40,6 +43,8 @@ public abstract class Decoder implements Listener
protected SampleType mSourceSampleType;
protected ArrayList mAuxiliaryDecoders = new ArrayList();
+
+ protected FrequencyCorrectionControl mFrequencyCorrection;
/**
* Abstract decoder class.
@@ -57,6 +62,51 @@ public abstract class Decoder implements Listener
mSourceSampleType = sampleType;
}
+ public Decoder( DecodeConfiguration config, SampleType sampleType )
+ {
+ this( sampleType );
+
+ if( config.supportsAFC() && config.isAFCEnabled() )
+ {
+ mFrequencyCorrection =
+ new AutomaticFrequencyControl( config.getAFCMaximumCorrection() );
+
+ /* Register AFC to receive non-filtered demodulated audio samples */
+ addUnfilteredRealSampleListener(
+ (RealSampleListener)mFrequencyCorrection );
+ }
+ }
+
+ /**
+ * Optional frequency correction control to provide frequency adjustments
+ * directed by the decoder.
+ */
+ public FrequencyCorrectionControl getFrequencyCorrectionControl()
+ {
+ return mFrequencyCorrection;
+ }
+
+ /**
+ * Indicates if a frequency correction controller exists for this decoder
+ */
+ public boolean hasFrequencyCorrectionControl()
+ {
+ return mFrequencyCorrection != null;
+ }
+
+ /**
+ * Current frequency correction setting or zero if no controller exists
+ */
+ public int getFrequencyCorrection()
+ {
+ if( hasFrequencyCorrectionControl() )
+ {
+ return mFrequencyCorrection.getErrorCorrection();
+ }
+
+ return 0;
+ }
+
/**
* Returns a real (ie demodulated) sample listener interface for
* connecting this decoder to a real sample stream provider
@@ -97,6 +147,11 @@ public abstract class Decoder implements Listener
mMessageBroadcaster.clear();
mComplexBroadcaster.clear();
mRealBroadcaster.clear();
+
+ if( mFrequencyCorrection != null )
+ {
+ mFrequencyCorrection.dispose();
+ }
}
/**
diff --git a/src/decode/DecoderFactory.java b/src/decode/DecoderFactory.java
index 644cbe44..da7db700 100644
--- a/src/decode/DecoderFactory.java
+++ b/src/decode/DecoderFactory.java
@@ -74,30 +74,30 @@ public class DecoderFactory
retVal = new AMDecoder( sampleType );
break;
case NBFM:
- retVal = new NBFMDecoder( sampleType );
+ retVal = new NBFMDecoder( config, sampleType );
break;
case LTR_STANDARD:
DecodeConfigLTRStandard ltrStandardConfig =
(DecodeConfigLTRStandard)config;
- retVal = new LTRStandardDecoder( sampleType, aliasList,
+ retVal = new LTRStandardDecoder( config, sampleType, aliasList,
ltrStandardConfig.getMessageDirection() );
break;
case LTR_NET:
DecodeConfigLTRNet ltrNetConfig = (DecodeConfigLTRNet)config;
- retVal = new LTRNetDecoder( sampleType, aliasList,
+ retVal = new LTRNetDecoder( config, sampleType, aliasList,
ltrNetConfig.getMessageDirection() );
break;
case MPT1327:
DecodeConfigMPT1327 mptConfig = (DecodeConfigMPT1327)config;
- retVal = new MPT1327Decoder( sampleType, aliasList,
+ retVal = new MPT1327Decoder( config, sampleType, aliasList,
mptConfig.getSync() );
break;
case PASSPORT:
- retVal = new PassportDecoder( sampleType, aliasList );
+ retVal = new PassportDecoder( config, sampleType, aliasList );
break;
case P25_PHASE1:
DecodeConfigP25Phase1 p25Config = (DecodeConfigP25Phase1)config;
diff --git a/src/decode/ltrnet/LTRNetDecoder.java b/src/decode/ltrnet/LTRNetDecoder.java
index be8da2c5..163573cc 100644
--- a/src/decode/ltrnet/LTRNetDecoder.java
+++ b/src/decode/ltrnet/LTRNetDecoder.java
@@ -33,6 +33,7 @@ import bits.MessageFramer;
import bits.SyncPattern;
import decode.Decoder;
import decode.DecoderType;
+import decode.config.DecodeConfiguration;
import dsp.filter.DCRemovalFilter2;
import dsp.fsk.LTRFSKDecoder;
import dsp.nbfm.FilteringNBFMDemodulator;
@@ -55,11 +56,12 @@ public class LTRNetDecoder extends Decoder implements Instrumentable
private List mAvailableTaps;
- public LTRNetDecoder( SampleType sampleType,
+ public LTRNetDecoder( DecodeConfiguration config,
+ SampleType sampleType,
AliasList aliasList,
MessageDirection direction )
{
- super( sampleType );
+ super( config, sampleType );
/**
* Only setup a demod chain if we're receiving complex samples. If
diff --git a/src/decode/ltrstandard/LTRStandardDecoder.java b/src/decode/ltrstandard/LTRStandardDecoder.java
index 71b50786..338e7003 100644
--- a/src/decode/ltrstandard/LTRStandardDecoder.java
+++ b/src/decode/ltrstandard/LTRStandardDecoder.java
@@ -27,6 +27,7 @@ import bits.MessageFramer;
import bits.SyncPattern;
import decode.Decoder;
import decode.DecoderType;
+import decode.config.DecodeConfiguration;
import dsp.filter.DCRemovalFilter2;
import dsp.fsk.LTRFSKDecoder;
import dsp.nbfm.FilteringNBFMDemodulator;
@@ -47,11 +48,12 @@ public class LTRStandardDecoder extends Decoder
private LTRStandardMessageProcessor mLTRMessageProcessor;
private AudioOutputImpl mAudioOutput = new AudioOutputImpl( "LTR Standard Decoder Audio Output" );
- public LTRStandardDecoder( SampleType sampleType,
- AliasList aliasList,
- MessageDirection direction )
+ public LTRStandardDecoder( DecodeConfiguration config,
+ SampleType sampleType,
+ AliasList aliasList,
+ MessageDirection direction )
{
- super( sampleType );
+ super( config, sampleType );
/**
* Only setup a demod chain if we're receiving complex samples. If
diff --git a/src/decode/mpt1327/MPT1327Decoder.java b/src/decode/mpt1327/MPT1327Decoder.java
index c3ebc6ad..7fabfbbe 100644
--- a/src/decode/mpt1327/MPT1327Decoder.java
+++ b/src/decode/mpt1327/MPT1327Decoder.java
@@ -35,6 +35,7 @@ import bits.MessageFramer;
import bits.SyncPattern;
import decode.Decoder;
import decode.DecoderType;
+import decode.config.DecodeConfiguration;
import dsp.filter.DCRemovalFilter;
import dsp.filter.FilterFactory;
import dsp.filter.Filters;
@@ -86,11 +87,12 @@ public class MPT1327Decoder extends Decoder implements Instrumentable
private MPT1327MessageProcessor mMessageProcessor;
private AudioOutputImpl mAudioOutput = new AudioOutputImpl( "MPT1327 Decoder Audio Output" );
- public MPT1327Decoder( SampleType sampleType,
+ public MPT1327Decoder( DecodeConfiguration config,
+ SampleType sampleType,
AliasList aliasList,
Sync sync )
{
- super( sampleType );
+ super( config, sampleType );
/* If we're receiving complex samples, do FM demodulation and DC removal
* and feed the output back to this decoder */
diff --git a/src/decode/nbfm/NBFMDecoder.java b/src/decode/nbfm/NBFMDecoder.java
index aa003a3a..5f8c1faa 100644
--- a/src/decode/nbfm/NBFMDecoder.java
+++ b/src/decode/nbfm/NBFMDecoder.java
@@ -17,12 +17,13 @@
******************************************************************************/
package decode.nbfm;
-import audio.AudioOutputImpl;
-import audio.IAudioOutput;
import sample.real.RealSampleListener;
import source.Source.SampleType;
+import audio.AudioOutputImpl;
+import audio.IAudioOutput;
import decode.Decoder;
import decode.DecoderType;
+import decode.config.DecodeConfiguration;
import dsp.filter.DCRemovalFilter2;
import dsp.nbfm.FilteringNBFMDemodulator;
@@ -38,9 +39,9 @@ public class NBFMDecoder extends Decoder
private DCRemovalFilter2 mDCRemovalFilter;
private AudioOutputImpl mAudioOutput = new AudioOutputImpl( "NBFM Decoder Audio Output" );
- public NBFMDecoder( SampleType sampleType )
+ public NBFMDecoder( DecodeConfiguration config, SampleType sampleType )
{
- super( sampleType );
+ super( config, sampleType );
/**
* Only setup a demod chain if we're receiving complex samples. If
diff --git a/src/decode/p25/C4FMSymbolFilter.java b/src/decode/p25/C4FMSymbolFilter.java
index 4ce6445f..65b2c286 100644
--- a/src/decode/p25/C4FMSymbolFilter.java
+++ b/src/decode/p25/C4FMSymbolFilter.java
@@ -13,13 +13,11 @@ import org.slf4j.LoggerFactory;
import sample.real.RealSampleListener;
import sample.real.RealSampleProvider;
-import source.tuner.FrequencyChangeBroadcaster;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyCorrectionControl;
+import source.tuner.frequency.FrequencyCorrectionControl.FrequencyCorrectionResetListener;
import dsp.gain.GainController;
-public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
+public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
RealSampleListener,
RealSampleProvider,
Instrumentable
@@ -200,13 +198,12 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
private float mHistory[] = new float[ NUMBER_FILTER_TAPS ];
private int mHistoryLast = 0;
+ private boolean mReset = false;
+
private RealSampleListener mListener;
- public static final long MAX_FREQUENCY_CORRECTION = 3000;
- private FrequencyChangeListener mFrequencyChangeListener;
- private long mFrequencyCorrection;
-
private GainController mGainController;
+ private FrequencyCorrectionControl mFrequencyCorrectionControl;
/**
* C4FM Symbol Filter
@@ -221,19 +218,31 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
* setting for this filter is 15.4 and that yields a symbol spread that
* is centered on 2.0, ranging 1.92 to 2.08.
*/
- public C4FMSymbolFilter( GainController gainController )
+ public C4FMSymbolFilter( GainController gainController,
+ FrequencyCorrectionControl frequencyControl )
{
mGainController = gainController;
- }
-
- public long getFrequencyCorrection()
- {
- return mFrequencyCorrection;
+
+ mFrequencyCorrectionControl = frequencyControl;
+
+ /* Register for reset events, so we can reset internal frequency tracking */
+ mFrequencyCorrectionControl.setListener( this );
}
@Override
public void receive( float sample )
{
+ if( mReset )
+ {
+ mCoarseFrequencyCorrection = 0.0f;
+ mFineFrequencyCorrection = 0.0f;
+ mSymbolSpread = 2.0f;
+ mSymbolClock = 0.0f;
+ mSymbolTime = (float)SYMBOL_RATE / (float)SAMPLE_RATE;
+
+ mReset = false;
+ }
+
mSymbolClock += mSymbolTime;
mHistory[ mHistoryLast++ ] = sample;
@@ -337,27 +346,11 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
/* send frequency correction */
if( Math.abs( mCoarseFrequencyCorrection ) > COARSE_FREQUENCY_DEADBAND )
{
- if( mFrequencyChangeListener != null )
- {
- mFrequencyCorrection += (
+ mFrequencyCorrectionControl.adjust(
500 * ( mCoarseFrequencyCorrection > 0 ? 1 : -1 ) );
- if( mFrequencyCorrection > MAX_FREQUENCY_CORRECTION )
- {
- mFrequencyCorrection = MAX_FREQUENCY_CORRECTION;
- }
- else if( -mFrequencyCorrection > MAX_FREQUENCY_CORRECTION )
- {
- mFrequencyCorrection = -MAX_FREQUENCY_CORRECTION;
- }
-
- mFrequencyChangeListener.frequencyChanged(
- new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR,
- mFrequencyCorrection ) );
-
/* reset internal frequency error tracker */
mCoarseFrequencyCorrection = 0;
- }
}
if( mSymbolSpreadTap != null )
@@ -373,6 +366,17 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
}
}
+ /**
+ * Listener interface for frequency correction reset events. We reset the
+ * coarse and fine frequency control values when the tuner channel source
+ * has changed frequency or frequency offset.
+ */
+ @Override
+ public void resetFrequencyCorrection()
+ {
+ mReset = true;
+ }
+
@Override
public void setListener( RealSampleListener listener )
{
@@ -420,16 +424,4 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
mSymbolSpreadTap = null;
}
}
-
- @Override
- public void addListener( FrequencyChangeListener listener )
- {
- mFrequencyChangeListener = listener;
- }
-
- @Override
- public void removeListener( FrequencyChangeListener listener )
- {
- mFrequencyChangeListener = null;
- }
}
diff --git a/src/decode/p25/P25ChannelState.java b/src/decode/p25/P25ChannelState.java
index dad5647c..6a6831be 100644
--- a/src/decode/p25/P25ChannelState.java
+++ b/src/decode/p25/P25ChannelState.java
@@ -56,6 +56,7 @@ import decode.p25.message.pdu.confirmed.SNDCPActivateTDSContextReject;
import decode.p25.message.pdu.confirmed.SNDCPActivateTDSContextRequest;
import decode.p25.message.pdu.confirmed.SNDCPDeactivateTDSContext;
import decode.p25.message.pdu.confirmed.SNDCPUserData;
+import decode.p25.message.pdu.osp.control.AdjacentStatusBroadcastExtended;
import decode.p25.message.pdu.osp.control.CallAlertExtended;
import decode.p25.message.pdu.osp.control.GroupAffiliationQueryExtended;
import decode.p25.message.pdu.osp.control.GroupAffiliationResponseExtended;
@@ -115,7 +116,6 @@ import decode.p25.message.tsbk.osp.voice.TelephoneInterconnectVoiceChannelGrantU
import decode.p25.message.tsbk.osp.voice.UnitToUnitAnswerRequest;
import decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrant;
import decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrantUpdate;
-import decode.p25.reference.Encryption;
import decode.p25.reference.IPProtocol;
import decode.p25.reference.Response;
import decode.p25.reference.Vendor;
@@ -1599,6 +1599,12 @@ public class P25ChannelState extends ChannelState
{
switch( pdu.getOpcode() )
{
+ case ADJACENT_STATUS_BROADCAST:
+ AdjacentStatusBroadcastExtended asbe =
+ (AdjacentStatusBroadcastExtended)pdu;
+
+ updateSystem( asbe.getSystemID() );
+ break;
case CALL_ALERT:
if( pdu instanceof CallAlertExtended )
{
@@ -2064,7 +2070,6 @@ public class P25ChannelState extends ChannelState
}
break;
default:
- mLog.debug( "PDU - unrecognized OPCODE message: " + pdu.toString() );
break;
}
}
diff --git a/src/decode/p25/P25Decoder.java b/src/decode/p25/P25Decoder.java
index 251f6063..c62cda80 100644
--- a/src/decode/p25/P25Decoder.java
+++ b/src/decode/p25/P25Decoder.java
@@ -32,8 +32,7 @@ import org.slf4j.LoggerFactory;
import sample.real.RealSampleListener;
import source.Source.SampleType;
-import source.tuner.DirectFrequencyController;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyCorrectionControl;
import alias.AliasList;
import controller.ResourceManager;
import decode.Decoder;
@@ -48,12 +47,12 @@ import dsp.gain.DirectGainControl;
import dsp.nbfm.FMDiscriminator;
import dsp.psk.CQPSKDemodulator;
import dsp.psk.QPSKStarSlicer;
-import dsp.symbol.FrameSync;
-public class P25Decoder extends Decoder
- implements DirectFrequencyController, Instrumentable
+public class P25Decoder extends Decoder implements Instrumentable
{
private final static Logger mLog = LoggerFactory.getLogger( P25Decoder.class );
+
+ private final static int MAXIMUM_FREQUENCY_CORRECTION = 3000; //Hertz, +/-
/* Instrumentation Taps */
private static final String INSTRUMENT_COMPLEX_INPUT = "Tap Point: Complex Input";
@@ -73,7 +72,7 @@ public class P25Decoder extends Decoder
/* Demods */
private FMDiscriminator mFMDemodulator;
private CQPSKDemodulator mCQPSKDemodulator;
-
+
/* Gain */
private ComplexFeedForwardGainControl mAGC;
private DirectGainControl mDGC;
@@ -162,6 +161,8 @@ public class P25Decoder extends Decoder
* can process the output as if it were coming from any other
* real sample source */
mFMDemodulator.setListener( getRealReceiver() );
+
+
}
}
@@ -175,7 +176,10 @@ public class P25Decoder extends Decoder
mDGC = new DirectGainControl( 15.0f, 0.1f, 35.0f, 0.3f );
mAudioFilter.setListener( mDGC );
- mSymbolFilter = new C4FMSymbolFilter( mDGC );
+ mFrequencyCorrection = new FrequencyCorrectionControl(
+ MAXIMUM_FREQUENCY_CORRECTION );
+
+ mSymbolFilter = new C4FMSymbolFilter( mDGC, mFrequencyCorrection );
mDGC.setListener( mSymbolFilter );
mC4FMSlicer = new C4FMSlicer();
@@ -371,35 +375,6 @@ public class P25Decoder extends Decoder
+ "not implemented in P25 Decoder" );
}
- /**
- * Registers a frequency change listener to receive frequency correction
- * events from the symbol filter
- */
- @Override
- public void setListener( FrequencyChangeListener listener )
- {
- if( mSymbolFilter != null )
- {
- mSymbolFilter.addListener( listener );
- }
-
- if( mCQPSKDemodulator != null )
- {
- mCQPSKDemodulator.addListener( listener );
- }
- }
-
- @Override
- public long getFrequencyCorrection()
- {
- if( mSymbolFilter != null )
- {
- return mSymbolFilter.getFrequencyCorrection();
- }
-
- return 0;
- }
-
public enum Modulation
{
CQPSK( "LSM SIMULCAST", "LSM" ),
diff --git a/src/decode/p25/audio/P25AudioOutput.java b/src/decode/p25/audio/P25AudioOutput.java
index 51033768..7bfcfcd7 100644
--- a/src/decode/p25/audio/P25AudioOutput.java
+++ b/src/decode/p25/audio/P25AudioOutput.java
@@ -141,7 +141,8 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener,
try
{
- mOutput = AudioSystem.getSourceDataLine( IMBEAudioFormat.PCM_SIGNED_8KHZ_16BITS );
+ mOutput = AudioSystem.getSourceDataLine(
+ IMBEAudioFormat.PCM_SIGNED_8KHZ_16BITS );
if( mOutput != null )
{
@@ -242,7 +243,7 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener,
/* Insert an 18-byte imbe frame into the stream */
mIMBETargetDataLine.receive( frame );
- /* Read 1920 bytes of converted upsamped audio from output */
+ /* Read 1920 bytes of converted audio from output */
byte[] audio = new byte[ PROCESSED_AUDIO_FRAME_SIZE ];
try
diff --git a/src/decode/passport/PassportDecoder.java b/src/decode/passport/PassportDecoder.java
index 609d1644..8293123e 100644
--- a/src/decode/passport/PassportDecoder.java
+++ b/src/decode/passport/PassportDecoder.java
@@ -32,6 +32,7 @@ import bits.MessageFramer;
import bits.SyncPattern;
import decode.Decoder;
import decode.DecoderType;
+import decode.config.DecodeConfiguration;
import dsp.filter.DCRemovalFilter2;
import dsp.fsk.LTRFSKDecoder;
import dsp.nbfm.FilteringNBFMDemodulator;
@@ -55,9 +56,11 @@ public class PassportDecoder extends Decoder implements Instrumentable
private List mAvailableTaps;
- public PassportDecoder( SampleType sampleType, AliasList aliasList )
+ public PassportDecoder( DecodeConfiguration config,
+ SampleType sampleType,
+ AliasList aliasList )
{
- super( sampleType );
+ super( config, sampleType );
/**
* Only setup a demod chain if we're receiving complex samples. If
diff --git a/src/dsp/psk/CQPSKDemodulator.java b/src/dsp/psk/CQPSKDemodulator.java
index 84eed452..91ba9870 100644
--- a/src/dsp/psk/CQPSKDemodulator.java
+++ b/src/dsp/psk/CQPSKDemodulator.java
@@ -36,6 +36,7 @@ import instrument.tap.stream.EyeDiagramDataTap;
import java.text.DecimalFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
@@ -44,7 +45,7 @@ import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.Provider;
import sample.complex.ComplexSample;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeListener;
import buffer.FloatAveragingBuffer;
import dsp.filter.interpolator.QPSKInterpolator;
@@ -297,13 +298,13 @@ public class CQPSKDemodulator implements Instrumentable,
middleSymbol.normalize();
currentSymbol.normalize();
-// if( mEyeDiagramDataTap != null )
-// {
-// mEyeDiagramDataTap.receive(
-// new EyeDiagramData( Arrays.copyOfRange( mDelayLine,
-// mDelayLinePointer, mDelayLinePointer + 20 ),
-// mMu, (float)half_sps + half_mu ) );
-// }
+ if( mEyeDiagramDataTap != null )
+ {
+ mEyeDiagramDataTap.receive(
+ new EyeDiagramData( Arrays.copyOfRange( mDelayLine,
+ mDelayLinePointer, mDelayLinePointer + 20 ),
+ mMu, (float)half_sps + half_mu ) );
+ }
/* Gardner timing error calculations */
float errorInphase = ( mPreviousSymbol.inphase() -
diff --git a/src/gui/control/JFrequencyControl.java b/src/gui/control/JFrequencyControl.java
index b70ef0d9..66a7d1c1 100644
--- a/src/gui/control/JFrequencyControl.java
+++ b/src/gui/control/JFrequencyControl.java
@@ -43,9 +43,9 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeListener;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
public class JFrequencyControl extends JPanel implements FrequencyChangeListener
{
@@ -138,7 +138,7 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener
{
if( event.getAttribute() == Attribute.FREQUENCY )
{
- setFrequency( (long)event.getValue(), false );
+ setFrequency( event.getValue().longValue(), false );
}
}
diff --git a/src/instrument/gui/AudioSourceFrame.java b/src/instrument/gui/AudioSourceFrame.java
index 191e9c9d..ff2c0e74 100644
--- a/src/instrument/gui/AudioSourceFrame.java
+++ b/src/instrument/gui/AudioSourceFrame.java
@@ -45,6 +45,9 @@ import source.wave.WaveSource.PositionListener;
import controller.ResourceManager;
import decode.Decoder;
import decode.DecoderType;
+import decode.config.DecodeConfigLTRNet;
+import decode.config.DecodeConfigMPT1327;
+import decode.config.DecodeConfigPassport;
import decode.fleetsync2.Fleetsync2Decoder;
import decode.lj1200.LJ1200Decoder;
import decode.ltrnet.LTRNetDecoder;
@@ -185,16 +188,19 @@ public class AudioSourceFrame extends JInternalFrame implements PositionListener
decoder = new LJ1200Decoder( null );
break;
case LTR_NET:
- decoder = new LTRNetDecoder( mSource.getSampleType(), null, MessageDirection.OSW );
+ decoder = new LTRNetDecoder( new DecodeConfigLTRNet(),
+ mSource.getSampleType(), null, MessageDirection.OSW );
break;
case MDC1200:
decoder = new MDCDecoder( null );
break;
case MPT1327:
- decoder = new MPT1327Decoder( mSource.getSampleType(), null, Sync.NORMAL );
+ decoder = new MPT1327Decoder( new DecodeConfigMPT1327(),
+ mSource.getSampleType(), null, Sync.NORMAL );
break;
case PASSPORT:
- decoder = new PassportDecoder( mSource.getSampleType(), null );
+ decoder = new PassportDecoder( new DecodeConfigPassport(),
+ mSource.getSampleType(), null );
break;
case P25_PHASE1:
ResourceManager rm = new ResourceManager();
diff --git a/src/sample/complex/ComplexSample.java b/src/sample/complex/ComplexSample.java
index 4c220f47..7b4bd6a9 100644
--- a/src/sample/complex/ComplexSample.java
+++ b/src/sample/complex/ComplexSample.java
@@ -81,6 +81,12 @@ public class ComplexSample implements Serializable
mRight *= scalor;
}
+ public static ComplexSample multiply( ComplexSample sample, float scalor )
+ {
+ return new ComplexSample( sample.left() * scalor,
+ sample.right() * scalor );
+ }
+
/**
* Multiplies this sample by the multiplier sample
*/
@@ -159,9 +165,17 @@ public class ComplexSample implements Serializable
* Magnitude squared of this sample
*/
public float magnitudeSquared()
+ {
+ return norm();
+ }
+
+ /**
+ * Norm of this sample = ( i * i ) + ( q * q )
+ */
+ public float norm()
{
return (float)( ( inphase() * inphase() ) +
- ( quadrature() * quadrature() ) );
+ ( quadrature() * quadrature() ) );
}
/**
@@ -293,6 +307,32 @@ public class ComplexSample implements Serializable
return (float)Math.atan2( y(), x() );
}
+ /**
+ * Constrains the i and q quantities to +/- value.
+ *
+ * @param value - maximum absolute value
+ */
+ public void clip( float value )
+ {
+ if( mLeft > value )
+ {
+ mLeft = value;
+ }
+ else if( mLeft < -value )
+ {
+ mLeft = -value;
+ }
+
+ if( mRight > value )
+ {
+ mRight = value;
+ }
+ else if( mRight < -value )
+ {
+ mRight = -value;
+ }
+ }
+
/**
* Angle of this sample in degrees
*/
@@ -321,18 +361,17 @@ public class ComplexSample implements Serializable
public static void main( String[] args )
{
- double SYMBOL_FREQUENCY = 2.0d * Math.PI * 4800.0d / 48000.0d;
- double PHASE_CORRECTION_90_DEGREES = SYMBOL_FREQUENCY / 4.0d;
- double PHASE_CORRECTION_180_DEGREES = SYMBOL_FREQUENCY / 2.0d;
-
- double angle = Math.PI / 4;
-
- ComplexSample s1 = new ComplexSample( (float)Math.sin( angle ), (float)Math.cos( angle ) );
- ComplexSample s2 = new ComplexSample( (float)Math.sin( -angle ), (float)Math.cos( -angle ) );
+ double angle = Math.PI; //180 degrees
- ComplexSample symbol = ComplexSample.multiply( s1, s2.conjugate() );
+ ComplexSample s1 = new ComplexSample( (float)Math.sin( angle ), (float)Math.cos( angle ) );
- mLog.debug( "S1:" + s1.polarAngle() + " S2:" + s2.polarAngle() + " Symbol:" + symbol.polarAngle() );
+ ComplexSample tap = new ComplexSample( 1.0f, -0.1f );
+
+ ComplexSample convolved = ComplexSample.multiply( s1, tap );
+
+ mLog.debug( "s: " + s1.toString() +
+ " t: " + tap.toString() +
+ " convolved: " + convolved.toString() );
}
}
diff --git a/src/source/recording/Recording.java b/src/source/recording/Recording.java
index 501793dd..48899f8b 100644
--- a/src/source/recording/Recording.java
+++ b/src/source/recording/Recording.java
@@ -5,12 +5,12 @@ import java.util.ArrayList;
import java.util.concurrent.RejectedExecutionException;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeListener;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelProvider;
import source.tuner.TunerChannelSource;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import controller.ResourceManager;
import controller.ThreadPoolManager;
@@ -92,7 +92,7 @@ public class Recording implements Comparable,
{
if( event.getAttribute() == Attribute.FREQUENCY )
{
- int frequency = (int)event.getValue();
+ long frequency = event.getValue().longValue();
mConfiguration.setCenterFrequency( frequency );
diff --git a/src/source/recording/RecordingEditorPanel.java b/src/source/recording/RecordingEditorPanel.java
index 03c3cb2b..37f95733 100644
--- a/src/source/recording/RecordingEditorPanel.java
+++ b/src/source/recording/RecordingEditorPanel.java
@@ -15,7 +15,7 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeListener;
import net.miginfocom.swing.MigLayout;
public class RecordingEditorPanel extends JPanel
diff --git a/src/source/tuner/DirectFrequencyController.java b/src/source/tuner/DirectFrequencyController.java
deleted file mode 100644
index ad6cf9e3..00000000
--- a/src/source/tuner/DirectFrequencyController.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package source.tuner;
-
-
-public interface DirectFrequencyController
-{
- public void setListener( FrequencyChangeListener listener );
-
- public long getFrequencyCorrection();
-}
diff --git a/src/source/tuner/Tuner.java b/src/source/tuner/Tuner.java
index 2076d3ca..c9979267 100644
--- a/src/source/tuner/Tuner.java
+++ b/src/source/tuner/Tuner.java
@@ -22,10 +22,16 @@ import java.util.concurrent.RejectedExecutionException;
import javax.swing.JPanel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import sample.Listener;
import sample.complex.ComplexBuffer;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeBroadcaster;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import controller.ResourceManager;
import controller.ThreadPoolManager;
@@ -36,6 +42,8 @@ public abstract class Tuner implements FrequencyChangeBroadcaster,
FrequencyChangeListener,
TunerChannelProvider
{
+ private final static Logger mLog = LoggerFactory.getLogger( Tuner.class );
+
private String mName;
/**
diff --git a/src/source/tuner/TunerChannelSource.java b/src/source/tuner/TunerChannelSource.java
index 2f15516d..a22f6ff0 100644
--- a/src/source/tuner/TunerChannelSource.java
+++ b/src/source/tuner/TunerChannelSource.java
@@ -33,7 +33,9 @@ import sample.complex.ComplexSample;
import sample.complex.ComplexSampleAssembler;
import source.ComplexSource;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import util.Oscillator;
import controller.ThreadPoolManager;
import controller.ThreadPoolManager.ThreadType;
@@ -173,7 +175,7 @@ public class TunerChannelSource extends ComplexSource
case SAMPLE_RATE_ERROR:
break;
case SAMPLE_RATE:
- int sampleRate = (int)event.getValue();
+ int sampleRate = event.getValue().intValue();
if( mTunerSampleRate != sampleRate )
{
@@ -196,7 +198,7 @@ public class TunerChannelSource extends ComplexSource
}
break;
case FREQUENCY_ERROR:
- mTunerFrequencyError = (int)event.getValue();
+ mTunerFrequencyError = event.getValue().intValue();
long frequencyErrorOffset = mTunerFrequency -
mTunerChannel.getFrequency() -
@@ -205,7 +207,7 @@ public class TunerChannelSource extends ComplexSource
mSineWaveGenerator.setFrequency( frequencyErrorOffset );
break;
case FREQUENCY:
- int frequency = (int)event.getValue();
+ long frequency = event.getValue().longValue();
/* If the frequency is updated, the AFC will also get reset, so
* we don't include the frequency error value here */
diff --git a/src/source/tuner/TunerController.java b/src/source/tuner/TunerController.java
index 27621896..c5cf2064 100644
--- a/src/source/tuner/TunerController.java
+++ b/src/source/tuner/TunerController.java
@@ -26,7 +26,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
-import source.tuner.FrequencyController.Tunable;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyController;
+import source.tuner.frequency.FrequencyController.Tunable;
import controller.ThreadPoolManager;
public abstract class TunerController implements Tunable
diff --git a/src/source/tuner/TunerNode.java b/src/source/tuner/TunerNode.java
index 20f1dfe4..7e4887b1 100644
--- a/src/source/tuner/TunerNode.java
+++ b/src/source/tuner/TunerNode.java
@@ -29,6 +29,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
import spectrum.SpectrumFrame;
import controller.BaseNode;
@@ -127,7 +129,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener
switch( event.getAttribute() )
{
case FREQUENCY:
- int frequency = (int)event.getValue();
+ long frequency = event.getValue().longValue();
if( mFrequency != frequency )
{
@@ -136,7 +138,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener
}
break;
case SAMPLE_RATE:
- int sampleRate = (int)event.getValue();
+ int sampleRate = event.getValue().intValue();
if( mSampleRate != sampleRate )
{
diff --git a/src/source/tuner/fcd/FCDTuner.java b/src/source/tuner/fcd/FCDTuner.java
index ae697917..1aadbba6 100644
--- a/src/source/tuner/fcd/FCDTuner.java
+++ b/src/source/tuner/fcd/FCDTuner.java
@@ -25,7 +25,6 @@ import sample.Listener;
import sample.adapter.ShortAdapter;
import sample.complex.ComplexBuffer;
import source.SourceException;
-import source.tuner.FrequencyChangeListener;
import source.tuner.MixerTuner;
import source.tuner.MixerTunerDataLine;
import source.tuner.TunerChannel;
@@ -33,6 +32,7 @@ import source.tuner.TunerChannelSource;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
+import source.tuner.frequency.FrequencyChangeListener;
import controller.ResourceManager;
import controller.ThreadPoolManager;
diff --git a/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java b/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java
index 12c7b2c5..e82b7a43 100644
--- a/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java
+++ b/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java
@@ -30,11 +30,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
-import source.tuner.FrequencyChangeListener;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerDetailsPanel;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import com.jidesoft.swing.JideTabbedPane;
@@ -99,12 +99,12 @@ public class FCD1TunerEditorPanel extends JPanel implements FrequencyChangeListe
{
try
{
- mController.setFrequency( event.getValue() );
+ mController.setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
mLog.error( "FCTProController - error setting frequency [" +
- event.getValue() + "]", e );
+ event.getValue().longValue() + "]", e );
}
}
}
diff --git a/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java b/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java
index 553f62c1..e7dcba54 100644
--- a/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java
+++ b/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java
@@ -30,11 +30,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
-import source.tuner.FrequencyChangeListener;
import source.tuner.fcd.FCDTuner;
import source.tuner.fcd.FCDTunerDetailsPanel;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import com.jidesoft.swing.JideTabbedPane;
@@ -99,12 +99,12 @@ public class FCD2TunerEditorPanel extends JPanel implements FrequencyChangeListe
//Disregard the bandwidth, which shouldn't be changing
try
{
- mController.setFrequency( event.getValue() );
+ mController.setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
mLog.error( "FCDProController - error setting frequency [" +
- event.getValue() + "]", e );
+ event.getValue().longValue() + "]", e );
}
}
}
diff --git a/src/dsp/frequency/AutomaticFrequencyControl.java b/src/source/tuner/frequency/AutomaticFrequencyControl.java
similarity index 54%
rename from src/dsp/frequency/AutomaticFrequencyControl.java
rename to src/source/tuner/frequency/AutomaticFrequencyControl.java
index ee634c8a..b655a1d5 100644
--- a/src/dsp/frequency/AutomaticFrequencyControl.java
+++ b/src/source/tuner/frequency/AutomaticFrequencyControl.java
@@ -1,16 +1,32 @@
-package dsp.frequency;
+package source.tuner.frequency;
+
+/*******************************************************************************
+ * SDR Trunk
+ * Copyright (C) 2015 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ ******************************************************************************/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.real.RealSampleListener;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import buffer.FloatAveragingBuffer;
-public class AutomaticFrequencyControl implements RealSampleListener,
- FrequencyChangeListener
+public class AutomaticFrequencyControl extends FrequencyCorrectionControl
+ implements RealSampleListener
{
private final static Logger mLog =
LoggerFactory.getLogger( AutomaticFrequencyControl.class );
@@ -35,40 +51,44 @@ public class AutomaticFrequencyControl implements RealSampleListener,
private int mSkipCounter = 0;
private int mSkipThreshold = 4;
private int mErrorCorrection = 0;
- private long mCurrentFrequency;
- private int mMaximumCorrection;
- private FrequencyChangeListener mListener;
public enum Mode
{
NORMAL,FAST;
}
- public AutomaticFrequencyControl( FrequencyChangeListener listener,
- int maximumCorrection )
+ /**
+ * Automatic Frequency Control. Monitors DC bias present in an FM
+ * demodulated audio stream and issues automatic frequency corrections to
+ * maintain the DC bias close to zero.
+ *
+ * @param maximum - maximum allowable (+/-) frequency correction value.
+ */
+ public AutomaticFrequencyControl( int maximum )
{
- mListener = listener;
- mMaximumCorrection = maximumCorrection;
+ super( maximum );
}
public void dispose()
{
- mListener = null;
+ super.dispose();
+
mBuffer = null;
}
-
- public int getErrorCorrection()
- {
- return mErrorCorrection;
- }
-
+
+ /**
+ * Resets the error correction value to zero and broadcasts a change event
+ */
public void reset()
{
mErrorCorrection = 0;
mMode = Mode.FAST;
dispatch();
}
-
+
+ /**
+ * Broadcasts a frequency correction change event to the registered listener
+ */
private void dispatch()
{
if( mListener != null )
@@ -119,86 +139,43 @@ public class AutomaticFrequencyControl implements RealSampleListener,
private void update( float average )
{
- int correction = 0;
-
+ mMode = Mode.NORMAL;
+
if( average > LARGE_ERROR )
{
- correction = -LARGE_FREQUENCY_CORRECTION;
+ adjust( -LARGE_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average > MEDIUM_ERROR )
{
- correction = -MEDIUM_FREQUENCY_CORRECTION;
+ adjust( -MEDIUM_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average > SMALL_ERROR )
{
- correction = -SMALL_FREQUENCY_CORRECTION;
- mMode = Mode.NORMAL;
+ adjust( -SMALL_FREQUENCY_CORRECTION );
}
else if( average > FINE_ERROR )
{
- correction = -FINE_FREQUENCY_CORRECTION;
- mMode = Mode.NORMAL;
+ adjust( -FINE_FREQUENCY_CORRECTION );
}
else if( average < -LARGE_ERROR )
{
- correction = LARGE_FREQUENCY_CORRECTION;
+ adjust( LARGE_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average < -MEDIUM_ERROR )
{
- correction = MEDIUM_FREQUENCY_CORRECTION;
+ adjust( MEDIUM_FREQUENCY_CORRECTION );
mMode = Mode.FAST;
}
else if( average < -SMALL_ERROR )
{
- correction = SMALL_FREQUENCY_CORRECTION;
- mMode = Mode.NORMAL;
+ adjust( SMALL_FREQUENCY_CORRECTION );
}
else if( average < -FINE_ERROR )
{
- correction = FINE_FREQUENCY_CORRECTION;
- mMode = Mode.NORMAL;
- }
-
- if( correction != 0 )
- {
- mErrorCorrection -= correction;
-
- if( Math.abs( mErrorCorrection ) > mMaximumCorrection )
- {
- mErrorCorrection = ( mErrorCorrection < 0 ) ?
- -mMaximumCorrection :
- mMaximumCorrection;
- }
-
- dispatch();
- }
- else
- {
- mMode = Mode.NORMAL;
+ adjust( FINE_FREQUENCY_CORRECTION );
}
}
-
- @Override
- public void frequencyChanged( FrequencyChangeEvent event )
- {
- switch( event.getAttribute() )
- {
- case FREQUENCY:
- int frequency = (int)event.getValue();
-
- if( mCurrentFrequency != frequency )
- {
- mCurrentFrequency = frequency;
-
- reset();
- }
- case SAMPLE_RATE_ERROR:
- break;
- default:
- break;
- }
- }
}
diff --git a/src/source/tuner/FrequencyChangeBroadcaster.java b/src/source/tuner/frequency/FrequencyChangeBroadcaster.java
similarity index 97%
rename from src/source/tuner/FrequencyChangeBroadcaster.java
rename to src/source/tuner/frequency/FrequencyChangeBroadcaster.java
index 467f8a32..89c03bf6 100644
--- a/src/source/tuner/FrequencyChangeBroadcaster.java
+++ b/src/source/tuner/frequency/FrequencyChangeBroadcaster.java
@@ -15,7 +15,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
******************************************************************************/
-package source.tuner;
+package source.tuner.frequency;
+
public interface FrequencyChangeBroadcaster
{
diff --git a/src/source/tuner/FrequencyChangeEvent.java b/src/source/tuner/frequency/FrequencyChangeEvent.java
similarity index 68%
rename from src/source/tuner/FrequencyChangeEvent.java
rename to src/source/tuner/frequency/FrequencyChangeEvent.java
index b2dad23c..0ab125bc 100644
--- a/src/source/tuner/FrequencyChangeEvent.java
+++ b/src/source/tuner/frequency/FrequencyChangeEvent.java
@@ -1,4 +1,4 @@
-package source.tuner;
+package source.tuner.frequency;
public class FrequencyChangeEvent
{
@@ -12,9 +12,9 @@ public class FrequencyChangeEvent
}
private Attribute mAttribute;
- private long mValue;
+ private Number mValue;
- public FrequencyChangeEvent( Attribute attribute, long value )
+ public FrequencyChangeEvent( Attribute attribute, Number value )
{
mAttribute = attribute;
mValue = value;
@@ -25,10 +25,8 @@ public class FrequencyChangeEvent
return mAttribute;
}
- public long getValue()
+ public Number getValue()
{
return mValue;
}
-
-
}
diff --git a/src/source/tuner/FrequencyChangeListener.java b/src/source/tuner/frequency/FrequencyChangeListener.java
similarity index 97%
rename from src/source/tuner/FrequencyChangeListener.java
rename to src/source/tuner/frequency/FrequencyChangeListener.java
index 3aee68de..fab9f28a 100644
--- a/src/source/tuner/FrequencyChangeListener.java
+++ b/src/source/tuner/frequency/FrequencyChangeListener.java
@@ -15,7 +15,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
******************************************************************************/
-package source.tuner;
+package source.tuner.frequency;
+
/**
* Interface for broadcasting changes to frequency, bandwidth, sample rate,
diff --git a/src/source/tuner/FrequencyController.java b/src/source/tuner/frequency/FrequencyController.java
similarity index 93%
rename from src/source/tuner/FrequencyController.java
rename to src/source/tuner/frequency/FrequencyController.java
index ccd1d2e7..53371832 100644
--- a/src/source/tuner/FrequencyController.java
+++ b/src/source/tuner/frequency/FrequencyController.java
@@ -15,15 +15,20 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
******************************************************************************/
-package source.tuner;
+package source.tuner.frequency;
import java.util.ArrayList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import source.SourceException;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
public class FrequencyController
{
+ private final static Logger mLog = LoggerFactory.getLogger( FrequencyController.class );
+
private Tunable mTunable;
private long mFrequency = 101100000;
private long mTunedFrequency = 101100000;
@@ -167,6 +172,10 @@ public class FrequencyController
/* Reset the frequency, but don't broadcast a change */
setFrequency( mFrequency, false );
}
+
+ broadcastFrequencyChangeEvent( new FrequencyChangeEvent(
+ Attribute.SAMPLE_RATE_ERROR, mFrequencyCorrection ) );
+
}
/**
diff --git a/src/source/tuner/frequency/FrequencyCorrectionControl.java b/src/source/tuner/frequency/FrequencyCorrectionControl.java
new file mode 100644
index 00000000..a2853c67
--- /dev/null
+++ b/src/source/tuner/frequency/FrequencyCorrectionControl.java
@@ -0,0 +1,164 @@
+package source.tuner.frequency;
+
+/*******************************************************************************
+ * SDR Trunk
+ * Copyright (C) 2015 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ ******************************************************************************/
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
+
+/**
+ * Frequency control for providing frequency error correction to a tuner channel
+ */
+public class FrequencyCorrectionControl implements FrequencyChangeListener
+{
+ private final static Logger mLog =
+ LoggerFactory.getLogger( FrequencyCorrectionControl.class );
+
+ protected FrequencyChangeListener mListener;
+ protected FrequencyCorrectionResetListener mResetListener;
+
+ protected int mErrorCorrection = 0;
+ private int mMaximumCorrection = 3000;
+
+ /**
+ * Frequency correction controller.
+ *
+ * @param maximum - defines the maximum +/- allowable frequency correction
+ * value
+ */
+ public FrequencyCorrectionControl( int maximum )
+ {
+ mMaximumCorrection = maximum;
+ }
+
+ /**
+ * Cleanup
+ */
+ public void dispose()
+ {
+ mListener = null;
+ mResetListener = null;
+ }
+
+ /**
+ * Registers a listener to receive frequency correction events
+ */
+ public void setListener( FrequencyChangeListener listener )
+ {
+ mListener = listener;
+ }
+
+ /**
+ * Registers a listener to receive frequency correction resets
+ */
+ public void setListener( FrequencyCorrectionResetListener listener )
+ {
+ mResetListener = listener;
+ }
+
+ /**
+ * Listener for source frequency or frequency offset value changes to
+ * reset this frequency controller value to zero.
+ */
+ @Override
+ public void frequencyChanged( FrequencyChangeEvent event )
+ {
+ Attribute attribute = event.getAttribute();
+
+ if( attribute == Attribute.FREQUENCY ||
+ attribute == Attribute.SAMPLE_RATE_ERROR )
+ {
+ reset();
+ }
+ }
+
+ /**
+ * Resets frequency correction value to zero and notifies any reset
+ * listeners
+ */
+ protected void reset()
+ {
+ setErrorCorrection( 0, false );
+
+ if( mResetListener != null )
+ {
+ mResetListener.resetFrequencyCorrection();
+ }
+ }
+
+ /**
+ * Sets frequency correction to the specified value and broadcasts a change
+ */
+ public void setErrorCorrection( int correction )
+ {
+ setErrorCorrection( correction, true );
+ }
+
+ /**
+ * Sets frequency correction to the specified value
+ */
+ public void setErrorCorrection( int correction, boolean broadcast )
+ {
+ mErrorCorrection = correction;
+
+ /* Limit frequency correction to +/- max correction value */
+ if( mErrorCorrection > mMaximumCorrection )
+ {
+ mErrorCorrection = mMaximumCorrection;
+ }
+ else if( mErrorCorrection < -mMaximumCorrection )
+ {
+ mErrorCorrection = -mMaximumCorrection;
+ }
+
+ /* Broadcast a change event */
+ if( broadcast && mListener != null )
+ {
+ mListener.frequencyChanged(
+ new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR,
+ mErrorCorrection ) );
+ }
+ }
+
+ /**
+ * Increments the frequency error correction value by the specified adjustment
+ */
+ public void adjust( int adjustment )
+ {
+ setErrorCorrection( getErrorCorrection() + adjustment );
+ }
+
+ /**
+ * Current frequency error correction value
+ * @return
+ */
+ public int getErrorCorrection()
+ {
+ return mErrorCorrection;
+ }
+
+ /**
+ * Listener interface to be notified when this control is reset to a zero
+ * frequency correction value
+ */
+ public interface FrequencyCorrectionResetListener
+ {
+ public void resetFrequencyCorrection();
+ }
+}
diff --git a/src/source/tuner/FrequencyLimitException.java b/src/source/tuner/frequency/FrequencyLimitException.java
similarity index 96%
rename from src/source/tuner/FrequencyLimitException.java
rename to src/source/tuner/frequency/FrequencyLimitException.java
index 63778b5a..be72a74e 100644
--- a/src/source/tuner/FrequencyLimitException.java
+++ b/src/source/tuner/frequency/FrequencyLimitException.java
@@ -1,4 +1,4 @@
-package source.tuner;
+package source.tuner.frequency;
public class FrequencyLimitException extends Exception
{
diff --git a/src/source/tuner/hackrf/HackRFTunerEditorPanel.java b/src/source/tuner/hackrf/HackRFTunerEditorPanel.java
index 5f4dec78..a594eab7 100644
--- a/src/source/tuner/hackrf/HackRFTunerEditorPanel.java
+++ b/src/source/tuner/hackrf/HackRFTunerEditorPanel.java
@@ -31,9 +31,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import source.tuner.hackrf.HackRFTunerController.BoardID;
import com.jidesoft.swing.JideTabbedPane;
@@ -114,11 +114,11 @@ public class HackRFTunerEditorPanel extends JPanel
{
try
{
- mController.setFrequency( event.getValue() );
+ mController.setFrequency( event.getValue().longValue() );
}
catch ( SourceException e )
{
- mLog.error( "error setting frequency [" + event.getValue() + "]", e );
+ mLog.error( "error setting frequency [" + event.getValue().longValue() + "]", e );
}
}
}
diff --git a/src/source/tuner/rtl/RTL2832Tuner.java b/src/source/tuner/rtl/RTL2832Tuner.java
index 7f421b7b..2f82e760 100644
--- a/src/source/tuner/rtl/RTL2832Tuner.java
+++ b/src/source/tuner/rtl/RTL2832Tuner.java
@@ -28,13 +28,13 @@ import org.usb4java.LibUsbException;
import sample.Listener;
import sample.complex.ComplexBuffer;
import source.SourceException;
-import source.tuner.FrequencyChangeListener;
import source.tuner.Tuner;
import source.tuner.TunerChannel;
import source.tuner.TunerChannelSource;
import source.tuner.TunerClass;
import source.tuner.TunerConfiguration;
import source.tuner.TunerType;
+import source.tuner.frequency.FrequencyChangeListener;
import source.tuner.rtl.RTL2832TunerController.SampleRate;
import controller.ResourceManager;
import controller.ThreadPoolManager;
diff --git a/src/source/tuner/rtl/RTL2832TunerController.java b/src/source/tuner/rtl/RTL2832TunerController.java
index 91db8979..acffcde3 100644
--- a/src/source/tuner/rtl/RTL2832TunerController.java
+++ b/src/source/tuner/rtl/RTL2832TunerController.java
@@ -55,8 +55,8 @@ import sample.Listener;
import sample.adapter.ByteSampleAdapter;
import sample.complex.ComplexBuffer;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import source.tuner.TunerController;
import source.tuner.TunerType;
import buffer.FloatAveragingBuffer;
diff --git a/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java b/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java
index ed042e5f..fcb6f72c 100644
--- a/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java
+++ b/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java
@@ -31,9 +31,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeListener;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import source.tuner.rtl.RTL2832InfoPanel;
import com.jidesoft.swing.JideTabbedPane;
@@ -100,7 +100,7 @@ public class E4KTunerEditorPanel extends JPanel implements FrequencyChangeListen
{
if( event.getAttribute() == Attribute.FREQUENCY )
{
- final int frequency = (int)event.getValue();
+ final long frequency = event.getValue().longValue();
EventQueue.invokeLater( new Runnable()
{
diff --git a/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java b/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java
index b4cc9bc7..36bde408 100644
--- a/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java
+++ b/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java
@@ -31,9 +31,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeListener;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import source.tuner.rtl.RTL2832InfoPanel;
import com.jidesoft.swing.JideTabbedPane;
@@ -99,7 +99,7 @@ public class R820TTunerEditorPanel extends JPanel implements FrequencyChangeList
{
if( event.getAttribute() == Attribute.FREQUENCY )
{
- final int frequency = (int)event.getValue();
+ final long frequency = event.getValue().longValue();
EventQueue.invokeLater( new Runnable()
{
diff --git a/src/spectrum/ChannelSpectrumPanel.java b/src/spectrum/ChannelSpectrumPanel.java
index eb9e5e98..e2f1cc32 100644
--- a/src/spectrum/ChannelSpectrumPanel.java
+++ b/src/spectrum/ChannelSpectrumPanel.java
@@ -25,8 +25,8 @@ import settings.Setting;
import settings.SettingChangeListener;
import settings.SettingsManager;
import source.Source.SampleType;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import spectrum.converter.DFTResultsConverter;
import spectrum.converter.RealDecibelConverter;
import spectrum.menu.AveragingItem;
diff --git a/src/spectrum/DFTProcessor.java b/src/spectrum/DFTProcessor.java
index d445dc57..6df2e493 100644
--- a/src/spectrum/DFTProcessor.java
+++ b/src/spectrum/DFTProcessor.java
@@ -34,8 +34,8 @@ import sample.Listener;
import sample.complex.ComplexBuffer;
import source.Source;
import source.Source.SampleType;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
import spectrum.converter.DFTResultsConverter;
import dsp.filter.Window;
import dsp.filter.Window.WindowType;
@@ -460,7 +460,7 @@ public class DFTProcessor implements Listener,
case SAMPLE_RATE_ERROR:
break;
case SAMPLE_RATE:
- mSampleRate = (int)event.getValue();
+ mSampleRate = event.getValue().intValue();
calculateConsumptionRate();
break;
default:
diff --git a/src/spectrum/OverlayPanel.java b/src/spectrum/OverlayPanel.java
index 1db379c7..1ffd2835 100644
--- a/src/spectrum/OverlayPanel.java
+++ b/src/spectrum/OverlayPanel.java
@@ -41,9 +41,9 @@ import settings.ColorSetting;
import settings.ColorSetting.ColorSettingName;
import settings.Setting;
import settings.SettingChangeListener;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeListener;
import source.tuner.TunerChannel;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
import controller.ResourceManager;
import controller.channel.Channel;
import controller.channel.Channel.ChannelType;
@@ -568,7 +568,7 @@ public class OverlayPanel extends JPanel
switch( event.getAttribute() )
{
case SAMPLE_RATE:
- mBandwidth = (int)event.getValue();
+ mBandwidth = event.getValue().intValue();
if( mBandwidth < 200000 )
{
@@ -580,7 +580,7 @@ public class OverlayPanel extends JPanel
}
break;
case FREQUENCY:
- mFrequency = event.getValue();
+ mFrequency = event.getValue().longValue();
break;
default:
break;
@@ -798,8 +798,8 @@ public class OverlayPanel extends JPanel
switch( event.getAttribute() )
{
case FREQUENCY:
- LabelDisplay display =
- LabelDisplay.fromFrequency( event.getValue() );
+ LabelDisplay display = LabelDisplay
+ .fromFrequency( event.getValue().longValue() );
if( mLabelDisplay != display )
{
diff --git a/src/spectrum/SpectralDisplayPanel.java b/src/spectrum/SpectralDisplayPanel.java
index 9417d629..f31d621e 100644
--- a/src/spectrum/SpectralDisplayPanel.java
+++ b/src/spectrum/SpectralDisplayPanel.java
@@ -56,9 +56,9 @@ import settings.SettingChangeListener;
import settings.SettingsManager;
import source.Source.SampleType;
import source.SourceException;
-import source.tuner.FrequencyChangeEvent;
-import source.tuner.FrequencyChangeEvent.Attribute;
-import source.tuner.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent;
+import source.tuner.frequency.FrequencyChangeListener;
+import source.tuner.frequency.FrequencyChangeEvent.Attribute;
import source.tuner.Tuner;
import source.tuner.TunerSelectionListener;
import spectrum.OverlayPanel.ChannelDisplay;