mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
P25 - adds direct frequency control for the C4FM symbol filter to adjust the tuner channel for frequency correction.
This commit is contained in:
@@ -141,24 +141,21 @@ public class Channel extends Configuration
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the channel is using Automatic Frequency Control
|
||||
* @return
|
||||
* Indicates if the channel has Automatic or Direct Frequency Control
|
||||
*/
|
||||
public boolean hasAFC()
|
||||
public boolean hasFrequencyControl()
|
||||
{
|
||||
return getAFC() != null;
|
||||
return mProcessingChain != null && mProcessingChain.hasFrequencyControl();
|
||||
}
|
||||
|
||||
public AutomaticFrequencyControl getAFC()
|
||||
public long getFrequencyCorrection()
|
||||
{
|
||||
if( isProcessing() )
|
||||
if( mProcessingChain != null )
|
||||
{
|
||||
return getProcessingChain().getAFC();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
return mProcessingChain.getFrequencyCorrection();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,6 +46,8 @@ 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 alias.AliasList;
|
||||
@@ -109,11 +111,28 @@ public class ProcessingChain implements Listener<Message>
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatic Frequency Control, or null if disabled
|
||||
* Current frequency correction setting
|
||||
*/
|
||||
public AutomaticFrequencyControl getAFC()
|
||||
public long getFrequencyCorrection()
|
||||
{
|
||||
return mAFC;
|
||||
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<List<ComplexSample>> getComplexReceiver()
|
||||
@@ -370,23 +389,31 @@ public class ProcessingChain implements Listener<Message>
|
||||
mAFC = null;
|
||||
}
|
||||
|
||||
if( mSource instanceof TunerChannelSource &&
|
||||
mChannel.getDecodeConfiguration().supportsAFC() &&
|
||||
mChannel.getDecodeConfiguration().isAFCEnabled() )
|
||||
if( mSource instanceof TunerChannelSource )
|
||||
{
|
||||
TunerChannelSource tcs = (TunerChannelSource)mSource;
|
||||
|
||||
int maximumCorrection = mChannel
|
||||
.getDecodeConfiguration().getAFCMaximumCorrection();
|
||||
|
||||
mAFC = new AutomaticFrequencyControl( tcs,
|
||||
maximumCorrection );
|
||||
if( mChannel.getDecodeConfiguration().supportsAFC() &&
|
||||
mChannel.getDecodeConfiguration().isAFCEnabled() )
|
||||
{
|
||||
|
||||
int maximumCorrection = mChannel
|
||||
.getDecodeConfiguration().getAFCMaximumCorrection();
|
||||
|
||||
mAFC = new AutomaticFrequencyControl( tcs,
|
||||
maximumCorrection );
|
||||
|
||||
/* Register AFC to receive frequency change events */
|
||||
tcs.addListener( mAFC );
|
||||
/* Register AFC to receive frequency change events */
|
||||
tcs.addListener( mAFC );
|
||||
|
||||
/* Add AFC as listener to the decoder */
|
||||
mDecoder.addUnfilteredRealSampleListener( mAFC );
|
||||
/* Add AFC as listener to the decoder */
|
||||
mDecoder.addUnfilteredRealSampleListener( mAFC );
|
||||
}
|
||||
else if( mDecoder instanceof DirectFrequencyController )
|
||||
{
|
||||
((DirectFrequencyController)mDecoder)
|
||||
.setListener( (FrequencyChangeListener)tcs );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import sample.real.RealSampleListener;
|
||||
import source.Source.SampleType;
|
||||
import source.tuner.DirectFrequencyController;
|
||||
import source.tuner.FrequencyChangeListener;
|
||||
import alias.AliasList;
|
||||
import decode.Decoder;
|
||||
import decode.DecoderType;
|
||||
@@ -42,7 +44,8 @@ import dsp.fsk.C4FMSymbolFilter;
|
||||
import dsp.fsk.P25MessageFramer;
|
||||
import dsp.nbfm.FMDiscriminator;
|
||||
|
||||
public class P25Decoder extends Decoder implements Instrumentable
|
||||
public class P25Decoder extends Decoder
|
||||
implements DirectFrequencyController, Instrumentable
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( P25Decoder.class );
|
||||
|
||||
@@ -196,4 +199,20 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
throw new IllegalArgumentException( "unfiltered real sample provider "
|
||||
+ "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 )
|
||||
{
|
||||
mSymbolFilter.addListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFrequencyCorrection()
|
||||
{
|
||||
return mSymbolFilter.getFrequencyCorrection();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +117,24 @@ public class PDUConfirmedMessage extends PDUMessage
|
||||
{
|
||||
/* 16 octets per block, and 12 octets in final block */
|
||||
int count = getBlocksToFollowCount() * 16 - 4;
|
||||
|
||||
int padding = getPadOctetCount();
|
||||
|
||||
/* Hack: motorola sndcp packet data control - when it says there are 15
|
||||
* pad octets and only 1 data block of 12 data octets, that means there
|
||||
* are more pad octets than available data and they appear to suppress
|
||||
* the final padded data block containing the 12 pad octets. The data
|
||||
* block count should be 2, but it says 1, so they're either not sending
|
||||
* the final block, or there is an error in the block count */
|
||||
if( padding > count )
|
||||
{
|
||||
count -= ( padding - 12 );
|
||||
}
|
||||
else
|
||||
{
|
||||
count -= padding;
|
||||
}
|
||||
|
||||
count -= getPadOctetCount();
|
||||
|
||||
count -= getDataHeaderOffset();
|
||||
|
||||
|
||||
@@ -13,8 +13,13 @@ 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;
|
||||
|
||||
public class C4FMSymbolFilter implements RealSampleListener,
|
||||
public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
|
||||
RealSampleListener,
|
||||
RealSampleProvider,
|
||||
Instrumentable
|
||||
{
|
||||
@@ -180,7 +185,8 @@ public class C4FMSymbolFilter implements RealSampleListener,
|
||||
private static final double K_FINE_FREQUENCY = 0.125;
|
||||
|
||||
/* Frequency correction broadcast threshold */
|
||||
private static final double COARSE_FREQUENCY_DEADBAND = 1.66;
|
||||
// private static final double COARSE_FREQUENCY_DEADBAND = 1.66;
|
||||
private static final double COARSE_FREQUENCY_DEADBAND = 1.20;
|
||||
|
||||
/* 2.0 symbol spread gives -3, -1, 1, 3 */
|
||||
private float mSymbolSpread = 2.0f;
|
||||
@@ -194,6 +200,9 @@ public class C4FMSymbolFilter implements RealSampleListener,
|
||||
private int mHistoryLast = 0;
|
||||
|
||||
private RealSampleListener mListener;
|
||||
|
||||
private FrequencyChangeListener mFrequencyChangeListener;
|
||||
private long mFrequencyCorrection;
|
||||
|
||||
private float mGain = 15.4f;
|
||||
|
||||
@@ -219,6 +228,11 @@ public class C4FMSymbolFilter implements RealSampleListener,
|
||||
{
|
||||
}
|
||||
|
||||
public long getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( float sample )
|
||||
{
|
||||
@@ -311,13 +325,24 @@ public class C4FMSymbolFilter implements RealSampleListener,
|
||||
|
||||
mFineFrequencyCorrection += ( symbolError * K_FINE_FREQUENCY );
|
||||
|
||||
// /* send frequency correction */
|
||||
// if( Math.abs( mCoarseFrequencyCorrection ) > COARSE_FREQUENCY_DEADBAND )
|
||||
// {
|
||||
// mLog.debug( "Frequency Correction [" +
|
||||
// ( mCoarseFrequencyCorrection > 0 ? "-" : "+" ) +
|
||||
// mCoarseFrequencyCorrection + "]" );
|
||||
// }
|
||||
/* send frequency correction */
|
||||
if( Math.abs( mCoarseFrequencyCorrection ) > COARSE_FREQUENCY_DEADBAND )
|
||||
{
|
||||
if( mFrequencyChangeListener != null )
|
||||
{
|
||||
mFrequencyCorrection += (
|
||||
500 * ( mCoarseFrequencyCorrection > 0 ? 1 : -1 ) );
|
||||
|
||||
mFrequencyChangeListener.frequencyChanged(
|
||||
new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR,
|
||||
mFrequencyCorrection ) );
|
||||
|
||||
/* reset internal frequency error tracker */
|
||||
mCoarseFrequencyCorrection = 0;
|
||||
|
||||
mLog.debug( "Frequency Corrected: " + mFrequencyCorrection );
|
||||
}
|
||||
}
|
||||
|
||||
if( mSymbolSpreadTap != null )
|
||||
{
|
||||
@@ -343,7 +368,7 @@ public class C4FMSymbolFilter implements RealSampleListener,
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Tap> getTaps()
|
||||
{
|
||||
@@ -379,4 +404,16 @@ public class C4FMSymbolFilter implements RealSampleListener,
|
||||
mSymbolSpreadTap = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener( FrequencyChangeListener listener )
|
||||
{
|
||||
mFrequencyChangeListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( FrequencyChangeListener listener )
|
||||
{
|
||||
mFrequencyChangeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
9
src/source/tuner/DirectFrequencyController.java
Normal file
9
src/source/tuner/DirectFrequencyController.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package source.tuner;
|
||||
|
||||
|
||||
public interface DirectFrequencyController
|
||||
{
|
||||
public void setListener( FrequencyChangeListener listener );
|
||||
|
||||
public long getFrequencyCorrection();
|
||||
}
|
||||
@@ -500,11 +500,11 @@ public class OverlayPanel extends JPanel
|
||||
}
|
||||
|
||||
/* Draw Automatic Frequency Control line */
|
||||
if( channel.hasAFC() )
|
||||
if( channel.hasFrequencyControl() )
|
||||
{
|
||||
int frequency = (int)tunerChannel.getFrequency();
|
||||
long frequency = tunerChannel.getFrequency();
|
||||
|
||||
int error = frequency + channel.getAFC().getErrorCorrection();
|
||||
long error = frequency + channel.getFrequencyCorrection();
|
||||
|
||||
drawAFC( graphics, getAxisFromFrequency( frequency ), false );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user