mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Resolves #373 - Adds support for Tuner frequency error PPM monitoring
and auto-correction for R820T tuners. -Updated TunerModel and TunerViewPanel to add 2 new columns to display the current tuner's PPM setting and (when available) the measured frequency error averaged over 5 second intervals provided by certain decoders (e.g. P25 C4FM and LSM). Frequency error value from P25 decoders is provided from the Costas Loop PLL once 2 or more P25 message sync events have been observed in a short period. -Updated R820T tuner to auto-correct PPM when measured frequency error exceeds the +/- 0.4PPM threshold for a period of 30 seconds or more. Feature can be enabled/disabled by user in the tuner editor panel. Resolved several issues with P25 C4FM/LSM decoders that was impacting performance related to channel misalignment from tuner PPM offsets.
This commit is contained in:
@@ -35,17 +35,16 @@ import io.github.dsheirer.module.decode.event.ICallEventProvider;
|
||||
import io.github.dsheirer.sample.IOverflowListener;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.ISourceEventListener;
|
||||
import io.github.dsheirer.source.ISourceEventProvider;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.heartbeat.Heartbeat;
|
||||
import io.github.dsheirer.source.heartbeat.IHeartbeatListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.github.dsheirer.source.SourceEvent.Event.NOTIFICATION_FREQUENCY_CHANGE;
|
||||
|
||||
public class ChannelState extends Module implements ICallEventProvider, IDecoderStateEventListener,
|
||||
IDecoderStateEventProvider, ISourceEventListener, IHeartbeatListener, ISquelchStateProvider,
|
||||
IAttributeChangeRequestListener, IOverflowListener
|
||||
IDecoderStateEventProvider, ISourceEventListener, ISourceEventProvider, IHeartbeatListener,
|
||||
ISquelchStateProvider, IAttributeChangeRequestListener, IOverflowListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelState.class);
|
||||
|
||||
@@ -57,12 +56,13 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
||||
private Listener<CallEvent> mCallEventListener;
|
||||
private Listener<DecoderStateEvent> mDecoderStateListener;
|
||||
private Listener<SquelchState> mSquelchStateListener;
|
||||
private Listener<SourceEvent> mExternalSourceEventListener;
|
||||
private DecoderStateEventReceiver mDecoderStateEventReceiver = new DecoderStateEventReceiver();
|
||||
private HeartbeatReceiver mHeartbeatReceiver = new HeartbeatReceiver();
|
||||
private ChannelType mChannelType;
|
||||
private TrafficChannelManager mTrafficChannelEndListener;
|
||||
private CallEvent mTrafficChannelCallEvent;
|
||||
private SourceChangeListener mSourceChangeListener;
|
||||
private SourceEventListener mInternalSourceEventListener;
|
||||
|
||||
private boolean mSquelchLocked = false;
|
||||
private boolean mSelected = false;
|
||||
@@ -160,12 +160,12 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
if(mSourceChangeListener == null)
|
||||
if(mInternalSourceEventListener == null)
|
||||
{
|
||||
mSourceChangeListener = new SourceChangeListener();
|
||||
mInternalSourceEventListener = new SourceEventListener();
|
||||
}
|
||||
|
||||
return mSourceChangeListener;
|
||||
return mInternalSourceEventListener;
|
||||
}
|
||||
|
||||
private boolean isStandardChannel()
|
||||
@@ -255,6 +255,17 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the source event to a registered external source event listener
|
||||
*/
|
||||
protected void broadcast(SourceEvent sourceEvent)
|
||||
{
|
||||
if(mExternalSourceEventListener != null)
|
||||
{
|
||||
mExternalSourceEventListener.receive(sourceEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the squelch state listener
|
||||
*/
|
||||
@@ -516,18 +527,46 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to receive frequency change events and rebroadcast them to the decoder states
|
||||
* Registers the listener to receive source events from the channel state
|
||||
*/
|
||||
public class SourceChangeListener implements Listener<SourceEvent>
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mExternalSourceEventListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-Registers a listener from receiving source events from the channel state
|
||||
*/
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mExternalSourceEventListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to receive source events.
|
||||
*/
|
||||
public class SourceEventListener implements Listener<SourceEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
if(sourceEvent.getEvent() == NOTIFICATION_FREQUENCY_CHANGE)
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
long frequency = sourceEvent.getValue().longValue();
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, getState(), frequency));
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
//Rebroadcast source frequency change events for the decoder(s) to process
|
||||
long frequency = sourceEvent.getValue().longValue();
|
||||
broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, getState(), frequency));
|
||||
break;
|
||||
case NOTIFICATION_MEASURED_FREQUENCY_ERROR:
|
||||
//Rebroadcast frequency error measurements to external listener if we're currently
|
||||
//in an active (ie sync locked) state.
|
||||
if(getState().isActiveState())
|
||||
{
|
||||
broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(), mChannelType.name()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user