mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
* Resolves #701 Updates P25P2 Tone metadata handling and P25P2 channel state management.
This commit is contained in:
@@ -105,7 +105,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
//Set the proxy as a listener so that echo'd updates are broadcast externally
|
||||
mutableIdentifierCollection.setIdentifierUpdateListener(mIdentifierUpdateNotificationProxy);
|
||||
|
||||
StateMachine stateMachine = new StateMachine(timeslot);
|
||||
StateMachine stateMachine = new StateMachine(timeslot, State.MULTI_CHANNEL_ACTIVE_STATES);
|
||||
mStateMachineMap.put(timeslot, stateMachine);
|
||||
stateMachine.addListener(this);
|
||||
|
||||
@@ -133,7 +133,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
public void stateChanged(State state, int timeslot)
|
||||
{
|
||||
//Broadcast current channel state so that channel rotation monitor can track
|
||||
if(state.isActiveState())
|
||||
if(State.MULTI_CHANNEL_ACTIVE_STATES.contains(state))
|
||||
{
|
||||
broadcast(DecoderStateEvent.activeState(timeslot));
|
||||
}
|
||||
@@ -148,9 +148,6 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case IDLE:
|
||||
broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE));
|
||||
break;
|
||||
case RESET:
|
||||
reset(timeslot);
|
||||
mStateMachineMap.get(timeslot).setState(State.IDLE);
|
||||
@@ -173,19 +170,49 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
*/
|
||||
private void checkTeardown()
|
||||
{
|
||||
boolean teardown = true;
|
||||
boolean teardown = false;
|
||||
boolean active = false;
|
||||
|
||||
for(StateMachine stateMachine: mStateMachineMap.values())
|
||||
{
|
||||
if(stateMachine.getState().isActiveState())
|
||||
State state = stateMachine.getState();
|
||||
|
||||
//If we have an active state in either timeslot, don't teardown. IDLE is a special state that is active
|
||||
//but doesn't prevent a teardown when the other timeslot is in TEARDOWN
|
||||
if(State.MULTI_CHANNEL_ACTIVE_STATES.contains(state) && state != State.IDLE)
|
||||
{
|
||||
teardown = false;
|
||||
active = true;
|
||||
}
|
||||
else if(state == State.TEARDOWN)
|
||||
{
|
||||
teardown = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(teardown)
|
||||
if(teardown && !active)
|
||||
{
|
||||
broadcast(new ChannelEvent(mChannel, ChannelEvent.Event.REQUEST_DISABLE));
|
||||
if(mChannel.isTrafficChannel())
|
||||
{
|
||||
broadcast(new ChannelEvent(mChannel, ChannelEvent.Event.REQUEST_DISABLE));
|
||||
}
|
||||
else
|
||||
{
|
||||
for(StateMachine stateMachine: mStateMachineMap.values())
|
||||
{
|
||||
stateMachine.setState(State.RESET);
|
||||
}
|
||||
}
|
||||
}
|
||||
//If one timeslot is teardown but the other is still active, reset the teardown timeslot to IDLE
|
||||
else if(teardown && active)
|
||||
{
|
||||
for(StateMachine stateMachine: mStateMachineMap.values())
|
||||
{
|
||||
if(stateMachine.getState() == State.TEARDOWN)
|
||||
{
|
||||
stateMachine.setState(State.RESET);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,11 +367,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
{
|
||||
mIdentifierCollectionMap.get(timeslot).broadcastIdentifiers();
|
||||
|
||||
if(mChannel.getChannelType() == ChannelType.TRAFFIC)
|
||||
{
|
||||
mStateMachineMap.get(timeslot).setState(State.ACTIVE);
|
||||
}
|
||||
mStateMachineMap.get(timeslot).setState(State.RESET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,7 +499,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
//in an active (ie sync locked) state.
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
{
|
||||
if(mStateMachineMap.get(timeslot).getState().isActiveState())
|
||||
if(State.MULTI_CHANNEL_ACTIVE_STATES.contains(mStateMachineMap.get(timeslot).getState()))
|
||||
{
|
||||
broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(),
|
||||
mChannel.getChannelType().name()));
|
||||
@@ -511,7 +534,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
case CONTINUATION:
|
||||
case DECODE:
|
||||
case START:
|
||||
if(State.CALL_STATES.contains(event.getState()))
|
||||
if(State.MULTI_CHANNEL_ACTIVE_STATES.contains(event.getState()))
|
||||
{
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(event.getState());
|
||||
}
|
||||
@@ -519,11 +542,11 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
case END:
|
||||
if(mChannel.isTrafficChannel())
|
||||
{
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(State.TEARDOWN);
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(event.getState());
|
||||
}
|
||||
else
|
||||
{
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(State.FADE);
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(event.getState());
|
||||
}
|
||||
break;
|
||||
case RESET:
|
||||
|
||||
@@ -94,7 +94,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
|
||||
private DecoderStateEventReceiver mDecoderStateEventReceiver = new DecoderStateEventReceiver();
|
||||
private SourceEventListener mInternalSourceEventListener;
|
||||
private ChannelMetadata mChannelMetadata;
|
||||
private StateMachine mStateMachine = new StateMachine(0);
|
||||
private StateMachine mStateMachine = new StateMachine(0, State.SINGLE_CHANNEL_ACTIVE_STATES);
|
||||
private StateMonitoringSquelchController mSquelchController = new StateMonitoringSquelchController(0);
|
||||
|
||||
public SingleChannelState(Channel channel, AliasModel aliasModel)
|
||||
@@ -123,7 +123,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
|
||||
public void stateChanged(State state, int timeslot)
|
||||
{
|
||||
//Broadcast current channel state so that channel rotation monitor can track
|
||||
if(state.isActiveState())
|
||||
if(State.SINGLE_CHANNEL_ACTIVE_STATES.contains(state))
|
||||
{
|
||||
broadcast(DecoderStateEvent.activeState(timeslot));
|
||||
}
|
||||
@@ -377,7 +377,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
|
||||
case NOTIFICATION_MEASURED_FREQUENCY_ERROR:
|
||||
//Rebroadcast frequency error measurements to external listener if we're currently
|
||||
//in an active (ie sync locked) state.
|
||||
if(mStateMachine.getState().isActiveState())
|
||||
if(State.SINGLE_CHANNEL_ACTIVE_STATES.contains(mStateMachine.getState()))
|
||||
{
|
||||
broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(),
|
||||
mChannel.getChannelType().name()));
|
||||
@@ -411,7 +411,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
|
||||
case CONTINUATION:
|
||||
case DECODE:
|
||||
case START:
|
||||
if(State.CALL_STATES.contains(event.getState()))
|
||||
if(State.SINGLE_CHANNEL_ACTIVE_STATES.contains(event.getState()))
|
||||
{
|
||||
mStateMachine.setState(event.getState());
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public enum State
|
||||
state == DATA ||
|
||||
state == ENCRYPTED ||
|
||||
state == FADE ||
|
||||
state == IDLE ||
|
||||
state == TEARDOWN ||
|
||||
state == RESET;
|
||||
}
|
||||
@@ -60,6 +61,7 @@ public enum State
|
||||
state == DATA ||
|
||||
state == ENCRYPTED ||
|
||||
state == FADE ||
|
||||
state == IDLE ||
|
||||
state == TEARDOWN ||
|
||||
state == RESET;
|
||||
}
|
||||
@@ -121,7 +123,8 @@ public enum State
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Indicates the channel is idle and not actively decoding any messages
|
||||
* Indicates the channel is idle and not actively decoding any messages or in a multiple timeslot decoder this
|
||||
* state reflects active decoding that indicates the timeslot is idle.
|
||||
*/
|
||||
IDLE("IDLE")
|
||||
{
|
||||
@@ -159,8 +162,8 @@ public enum State
|
||||
|
||||
private String mDisplayValue;
|
||||
|
||||
public static final EnumSet<State> CALL_STATES = EnumSet.of(ACTIVE, CALL, CONTROL, DATA, ENCRYPTED);
|
||||
public static final EnumSet<State> IDLE_STATES = EnumSet.of(IDLE, FADE);
|
||||
public static final EnumSet<State> SINGLE_CHANNEL_ACTIVE_STATES = EnumSet.of(ACTIVE, CALL, CONTROL, DATA, ENCRYPTED);
|
||||
public static final EnumSet<State> MULTI_CHANNEL_ACTIVE_STATES = EnumSet.of(ACTIVE, CALL, CONTROL, DATA, ENCRYPTED, IDLE);
|
||||
|
||||
private State(String displayValue)
|
||||
{
|
||||
@@ -169,17 +172,6 @@ public enum State
|
||||
|
||||
public abstract boolean canChangeTo(State state);
|
||||
|
||||
/**
|
||||
* Indicates that this state is an active (ie decoding) state and is one of the states
|
||||
* enumerated in the CALL_STATES enumeration set.
|
||||
*
|
||||
* @return true if this state is an active state
|
||||
*/
|
||||
public boolean isActiveState()
|
||||
{
|
||||
return CALL_STATES.contains(this);
|
||||
}
|
||||
|
||||
public String getDisplayValue()
|
||||
{
|
||||
return mDisplayValue;
|
||||
|
||||
@@ -30,8 +30,12 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* State machine for tracking a channel state.
|
||||
*/
|
||||
public class StateMachine
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(StateMachine.class);
|
||||
@@ -42,13 +46,21 @@ public class StateMachine
|
||||
protected long mEndTimeout;
|
||||
protected long mEndTimeoutBuffer = 0;
|
||||
private int mTimeslot;
|
||||
private EnumSet<State> mActiveStates;
|
||||
private Channel.ChannelType mChannelType = Channel.ChannelType.STANDARD;
|
||||
private List<IStateMachineListener> mStateMachineListeners = new ArrayList<>();
|
||||
private Listener<IdentifierUpdateNotification> mIdentifierUpdateListener;
|
||||
|
||||
public StateMachine(int timeslot)
|
||||
/**
|
||||
* Constructs an instance
|
||||
*
|
||||
* @param timeslot for this state machine
|
||||
* @param activeStates set of states considered active for updating the fade timeout
|
||||
*/
|
||||
public StateMachine(int timeslot, EnumSet<State> activeStates)
|
||||
{
|
||||
mTimeslot = timeslot;
|
||||
mActiveStates = activeStates;
|
||||
}
|
||||
|
||||
public void addListener(IStateMachineListener listener)
|
||||
@@ -73,7 +85,7 @@ public class StateMachine
|
||||
|
||||
public void checkState()
|
||||
{
|
||||
if(mState.isActiveState() && mFadeTimeout <= System.currentTimeMillis())
|
||||
if(mActiveStates.contains(mState) && mFadeTimeout <= System.currentTimeMillis())
|
||||
{
|
||||
setState(State.FADE);
|
||||
}
|
||||
@@ -92,18 +104,22 @@ public class StateMachine
|
||||
{
|
||||
if(state == mState)
|
||||
{
|
||||
if(State.CALL_STATES.contains(state))
|
||||
if(mActiveStates.contains(state))
|
||||
{
|
||||
updateFadeTimeout();
|
||||
}
|
||||
}
|
||||
else if(mState.canChangeTo(state))
|
||||
{
|
||||
if(mActiveStates.contains(state))
|
||||
{
|
||||
updateFadeTimeout();
|
||||
}
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case ACTIVE:
|
||||
mState = state;
|
||||
updateFadeTimeout();
|
||||
broadcast(ChannelStateIdentifier.ACTIVE);
|
||||
break;
|
||||
case CONTROL:
|
||||
@@ -111,23 +127,19 @@ public class StateMachine
|
||||
if(mChannelType == Channel.ChannelType.STANDARD)
|
||||
{
|
||||
mState = state;
|
||||
updateFadeTimeout();
|
||||
broadcast(ChannelStateIdentifier.CONTROL);
|
||||
}
|
||||
break;
|
||||
case DATA:
|
||||
mState = state;
|
||||
updateFadeTimeout();
|
||||
broadcast(ChannelStateIdentifier.DATA);
|
||||
break;
|
||||
case ENCRYPTED:
|
||||
mState = state;
|
||||
updateFadeTimeout();
|
||||
broadcast(ChannelStateIdentifier.ENCRYPTED);
|
||||
break;
|
||||
case CALL:
|
||||
mState = state;
|
||||
updateFadeTimeout();
|
||||
broadcast(ChannelStateIdentifier.CALL);
|
||||
break;
|
||||
case FADE:
|
||||
|
||||
Reference in New Issue
Block a user