#6 DMR Decoder (#947)

* #6 DMR decoder feature - work in progress

* #6 DMR Decoder.

* #6 DMR Decoder.  Code review updates.

Co-authored-by: Zhenyu Mao <maozhenyu@foxmail.com>
Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
Denny Sheirer
2020-10-12 04:57:59 -04:00
committed by GitHub
parent b061db1189
commit 7eec82deee
436 changed files with 36258 additions and 2409 deletions

View File

@@ -21,12 +21,13 @@
*/
package io.github.dsheirer.channel.state;
import com.google.common.eventbus.Subscribe;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.squelch.SquelchStateEvent;
import io.github.dsheirer.channel.metadata.ChannelMetadata;
import io.github.dsheirer.channel.state.DecoderStateEvent.Event;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.Channel.ChannelType;
import io.github.dsheirer.controller.channel.ChannelConfigurationChangeNotification;
import io.github.dsheirer.controller.channel.ChannelEvent;
import io.github.dsheirer.identifier.IdentifierClass;
import io.github.dsheirer.identifier.IdentifierUpdateListener;
@@ -51,7 +52,6 @@ import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -97,6 +97,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
private ChannelMetadata mChannelMetadata;
private StateMachine mStateMachine = new StateMachine(0, State.SINGLE_CHANNEL_ACTIVE_STATES);
private StateMonitoringSquelchController mSquelchController = new StateMonitoringSquelchController(0);
private DecoderStateNotificationEventCache mStateNotificationCache = new DecoderStateNotificationEventCache();
public SingleChannelState(Channel channel, AliasModel aliasModel)
{
@@ -107,10 +108,21 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
mStateMachine.addListener(this);
mStateMachine.addListener(mSquelchController);
mStateMachine.setChannelType(mChannel.getChannelType());
mStateMachine.setIdentifierUpdateListener(mIdentifierCollection);
mStateMachine.setEndTimeoutBufferMilliseconds(RESET_TIMEOUT_DELAY);
if(channel.getChannelType() == ChannelType.STANDARD)
configureChannelType(channel);
}
/**
* Configure items according to channel type
* @param channel configuration
*/
private void configureChannelType(Channel channel)
{
mStateMachine.setChannelType(getChannel().getChannelType());
if(channel.isStandardChannel())
{
mStateMachine.setFadeTimeoutBufferMilliseconds(FADE_TIMEOUT_DELAY);
}
@@ -125,36 +137,38 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
}
}
/**
* Receive notification that the underlying channel configuration has changed.
* @param notification
*/
@Subscribe
public void channelConfigurationChanged(ChannelConfigurationChangeNotification notification)
{
updateChannelConfiguration(notification.getChannel());
configureChannelType(notification.getChannel());
createConfigurationIdentifiers(notification.getChannel());
}
@Override
public void stateChanged(State state, int timeslot)
{
//Broadcast current channel state so that channel rotation monitor can track
if(State.SINGLE_CHANNEL_ACTIVE_STATES.contains(state))
{
broadcast(DecoderStateEvent.activeState(timeslot));
}
else
{
broadcast(DecoderStateEvent.inactiveState(timeslot));
}
ChannelStateIdentifier stateIdentifier = ChannelStateIdentifier.create(state);
ChannelStateIdentifier stateIdentifier = ChannelStateIdentifier.get(state);
mIdentifierCollection.update(stateIdentifier);
mChannelMetadata.receive(new IdentifierUpdateNotification(stateIdentifier, IdentifierUpdateNotification.Operation.ADD, timeslot));
switch(state)
{
case IDLE:
broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE));
broadcast(new DecoderStateEvent(this, Event.REQUEST_RESET, State.IDLE));
break;
case RESET:
reset();
mStateMachine.setState(State.IDLE);
break;
case TEARDOWN:
if(mChannel.isTrafficChannel())
if(getChannel().isTrafficChannel())
{
broadcast(new ChannelEvent(mChannel, ChannelEvent.Event.REQUEST_DISABLE));
broadcast(new ChannelEvent(getChannel(), ChannelEvent.Event.REQUEST_DISABLE));
}
else
{
@@ -258,7 +272,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
/**
* Channel metadata for this channel.
*/
public Collection<ChannelMetadata> getChannelMetadata()
public List<ChannelMetadata> getChannelMetadata()
{
return Collections.singletonList(mChannelMetadata);
}
@@ -270,7 +284,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
public void reset()
{
mStateMachine.setState(State.RESET);
broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE));
broadcast(new DecoderStateEvent(this, Event.REQUEST_RESET, State.IDLE));
mIdentifierCollection.remove(IdentifierClass.USER);
sourceOverflow(false);
}
@@ -280,7 +294,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
{
mIdentifierCollection.broadcastIdentifiers();
if(mChannel.getChannelType() == ChannelType.TRAFFIC)
if(getChannel().isTrafficChannel())
{
mStateMachine.setState(State.ACTIVE);
}
@@ -292,12 +306,6 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
mSquelchController.setSquelchLock(false);
}
public void dispose()
{
mDecodeEventListener = null;
mDecoderStateListener = null;
}
@Override
public Listener<SourceEvent> getSourceEventListener()
{
@@ -372,7 +380,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
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, mStateMachine.getState(), frequency));
broadcast(new DecoderStateEvent(this, Event.NOTIFICATION_SOURCE_FREQUENCY, mStateMachine.getState(), frequency));
//Create a new frequency configuration identifier so that downstream consumers receive the change
//via channel metadata and audio packet updates - this is a silent add that is sent as a notification
@@ -386,7 +394,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
if(State.SINGLE_CHANNEL_ACTIVE_STATES.contains(mStateMachine.getState()))
{
broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(),
mChannel.getChannelType().name()));
getChannel().getChannelType().name()));
}
break;
}
@@ -405,10 +413,10 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
{
switch(event.getEvent())
{
case ALWAYS_UNSQUELCH:
case REQUEST_ALWAYS_UNSQUELCH:
mSquelchController.setSquelchLock(true);
break;
case CHANGE_CALL_TIMEOUT:
case REQUEST_CHANGE_CALL_TIMEOUT:
if(event instanceof ChangeChannelTimeoutEvent)
{
ChangeChannelTimeoutEvent timeout = (ChangeChannelTimeoutEvent)event;
@@ -420,19 +428,28 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder
if(State.SINGLE_CHANNEL_ACTIVE_STATES.contains(event.getState()))
{
mStateMachine.setState(event.getState());
//Broadcast state so channel rotation manager can track
broadcast(mStateNotificationCache.getStateNotificationEvent(event.getState(), event.getTimeslot()));
}
break;
case END:
if(mChannel.isTrafficChannel())
if(getChannel().isTrafficChannel())
{
mStateMachine.setState(State.TEARDOWN);
//Broadcast state so channel rotation manager can track
broadcast(mStateNotificationCache.getStateNotificationEvent(State.TEARDOWN, event.getTimeslot()));
}
else
{
mStateMachine.setState(State.FADE);
//Broadcast state so channel rotation manager can track
broadcast(mStateNotificationCache.getStateNotificationEvent(State.FADE, event.getTimeslot()));
}
break;
case RESET:
case REQUEST_RESET:
/* Channel State does not respond to reset events */
break;
default: