mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
* #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:
@@ -25,9 +25,13 @@ import io.github.dsheirer.module.ProcessingChain;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import java.awt.*;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.channel.metadata;
|
||||
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Channel and associated channel metadata
|
||||
*/
|
||||
public class ChannelAndMetadata
|
||||
{
|
||||
private Channel mChannel;
|
||||
private List<ChannelMetadata> mChannelMetadata;
|
||||
|
||||
/**
|
||||
* Connstructs an instance
|
||||
* @param channel
|
||||
* @param metadata
|
||||
*/
|
||||
public ChannelAndMetadata(Channel channel, List<ChannelMetadata> metadata)
|
||||
{
|
||||
mChannel = channel;
|
||||
mChannelMetadata = metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel
|
||||
*/
|
||||
public Channel getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel Metadata
|
||||
*/
|
||||
public List<ChannelMetadata> getChannelMetadata()
|
||||
{
|
||||
return mChannelMetadata;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import io.github.dsheirer.eventbus.MyEventBus;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.decoder.DecoderLogicalChannelNameIdentifier;
|
||||
import io.github.dsheirer.preference.PreferenceType;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -57,10 +58,11 @@ public class ChannelMetadataModel extends AbstractTableModel implements IChannel
|
||||
|
||||
private List<ChannelMetadata> mChannelMetadata = new ArrayList();
|
||||
private Map<ChannelMetadata,Channel> mMetadataChannelMap = new HashMap();
|
||||
private Listener<ChannelAndMetadata> mChannelAddListener;
|
||||
|
||||
public ChannelMetadataModel()
|
||||
{
|
||||
MyEventBus.getEventBus().register(this);
|
||||
MyEventBus.getGlobalEventBus().register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,21 +84,66 @@ public class ChannelMetadataModel extends AbstractTableModel implements IChannel
|
||||
}
|
||||
}
|
||||
|
||||
public void add(Collection<ChannelMetadata> channelMetadatas, Channel channel)
|
||||
public void dispose()
|
||||
{
|
||||
MyEventBus.getGlobalEventBus().unregister(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup model row for the specified channel metadata
|
||||
*/
|
||||
public int getRow(ChannelMetadata channelMetadata)
|
||||
{
|
||||
if(mChannelMetadata.contains(channelMetadata))
|
||||
{
|
||||
return mChannelMetadata.indexOf(channelMetadata);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to be notified when channel metadata(s) are added to the model.
|
||||
* @param listener to receive channel associated with the channel metadata(s) that were added
|
||||
*/
|
||||
public void setChannelAddListener(Listener<ChannelAndMetadata> listener)
|
||||
{
|
||||
mChannelAddListener = listener;
|
||||
}
|
||||
|
||||
public void add(ChannelAndMetadata channelAndMetadata)
|
||||
{
|
||||
//Execute on the swing thread to avoid threading issues
|
||||
EventQueue.invokeLater(() -> {
|
||||
for(ChannelMetadata channelMetadata: channelMetadatas)
|
||||
for(ChannelMetadata channelMetadata: channelAndMetadata.getChannelMetadata())
|
||||
{
|
||||
mChannelMetadata.add(channelMetadata);
|
||||
mMetadataChannelMap.put(channelMetadata, channel);
|
||||
mMetadataChannelMap.put(channelMetadata, channelAndMetadata.getChannel());
|
||||
int index = mChannelMetadata.indexOf(channelMetadata);
|
||||
fireTableRowsInserted(index, index);
|
||||
channelMetadata.setUpdateEventListener(ChannelMetadataModel.this);
|
||||
}
|
||||
|
||||
if(mChannelAddListener != null)
|
||||
{
|
||||
mChannelAddListener.receive(channelAndMetadata);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the mapping of channel metadata to the channel used to create the channel metadatas (and processing chain)
|
||||
* @param channelMetadatas
|
||||
* @param channel
|
||||
*/
|
||||
public void updateChannelMetadataToChannelMap(Collection<ChannelMetadata> channelMetadatas, Channel channel)
|
||||
{
|
||||
for(ChannelMetadata channelMetadata: channelMetadatas)
|
||||
{
|
||||
mMetadataChannelMap.put(channelMetadata, channel);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(ChannelMetadata channelMetadata)
|
||||
{
|
||||
//Execute on the swing thread to avoid threading issues
|
||||
|
||||
@@ -38,6 +38,8 @@ import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
@@ -60,6 +62,8 @@ import java.util.Map;
|
||||
|
||||
public class ChannelMetadataPanel extends JPanel implements ListSelectionListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelMetadataPanel.class);
|
||||
|
||||
private static final String TABLE_PREFERENCE_KEY = "channel.metadata.panel";
|
||||
private ChannelModel mChannelModel;
|
||||
private ChannelProcessingManager mChannelProcessingManager;
|
||||
@@ -70,6 +74,7 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
|
||||
private Map<State,Color> mBackgroundColors = new EnumMap<>(State.class);
|
||||
private Map<State,Color> mForegroundColors = new EnumMap<>(State.class);
|
||||
private JTableColumnWidthMonitor mTableColumnMonitor;
|
||||
private Channel mUserSelectedChannel;
|
||||
|
||||
/**
|
||||
* Table view for currently decoding channel metadata
|
||||
@@ -91,6 +96,7 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill]") );
|
||||
|
||||
mTable = new JTable(mChannelProcessingManager.getChannelMetadataModel());
|
||||
mChannelProcessingManager.getChannelMetadataModel().setChannelAddListener(new ChannelAddListener());
|
||||
|
||||
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)mTable.getDefaultRenderer(String.class);
|
||||
renderer.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
@@ -165,9 +171,10 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
|
||||
|
||||
if(selectedMetadata != null)
|
||||
{
|
||||
Channel selectedChannel = mChannelProcessingManager.getChannelMetadataModel()
|
||||
mUserSelectedChannel = mChannelProcessingManager.getChannelMetadataModel()
|
||||
.getChannelFromMetadata(selectedMetadata);
|
||||
processingChain = mChannelProcessingManager.getProcessingChain(selectedChannel);
|
||||
|
||||
processingChain = mChannelProcessingManager.getProcessingChain(mUserSelectedChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,4 +429,39 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to be notified when a channel and associated channel metadata(s) are added to the underlying
|
||||
* channel metadata model.
|
||||
*
|
||||
* When a channel is added, it is compared the the last user selected channel and if they are the same, it
|
||||
* invokes a selection event on the channel metadata row so that the channel metadata is re-selected. This is
|
||||
* primarily a hack to counter-act the DMR Capacity+ REST channel rotation where a channel is converted to a
|
||||
* traffic channel and the previous channel is restarted. The UI effect is that the user selected channel row
|
||||
* in the Now Playing window continually loses selection over the channel and causes the user to perpetually
|
||||
* chase the channel row.
|
||||
*/
|
||||
public class ChannelAddListener implements Listener<ChannelAndMetadata>
|
||||
{
|
||||
@Override
|
||||
public void receive(ChannelAndMetadata channelAndMetadata)
|
||||
{
|
||||
if(mUserSelectedChannel != null &&
|
||||
mUserSelectedChannel.getChannelID() == channelAndMetadata.getChannel().getChannelID())
|
||||
{
|
||||
List<ChannelMetadata> metadata = channelAndMetadata.getChannelMetadata();
|
||||
|
||||
if(metadata.size() > 0)
|
||||
{
|
||||
int modelRow = mChannelProcessingManager.getChannelMetadataModel().getRow(metadata.get(0));
|
||||
|
||||
if(modelRow >= 0)
|
||||
{
|
||||
int tableRow = mTable.convertRowIndexToView(modelRow);
|
||||
mTable.getSelectionModel().setSelectionInterval(tableRow, tableRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import io.github.dsheirer.source.heartbeat.IHeartbeatListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractChannelState extends Module implements IChannelEventProvider, IDecodeEventProvider,
|
||||
IDecoderStateEventProvider, ISourceEventProvider, IHeartbeatListener, ISquelchStateProvider,
|
||||
@@ -53,15 +53,35 @@ public abstract class AbstractChannelState extends Module implements IChannelEve
|
||||
protected Listener<IDecodeEvent> mDecodeEventListener;
|
||||
protected Listener<DecoderStateEvent> mDecoderStateListener;
|
||||
protected Listener<SourceEvent> mExternalSourceEventListener;
|
||||
protected Channel mChannel;
|
||||
private Channel mChannel;
|
||||
protected boolean mSourceOverflow = false;
|
||||
private HeartbeatReceiver mHeartbeatReceiver = new HeartbeatReceiver();
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param channel configuration
|
||||
*/
|
||||
public AbstractChannelState(Channel channel)
|
||||
{
|
||||
mChannel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates/replaces the current channel configuration with the argument.
|
||||
*/
|
||||
protected void updateChannelConfiguration(Channel channel)
|
||||
{
|
||||
mChannel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel configuration for this channel state
|
||||
*/
|
||||
protected Channel getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked each time that a heartbeat is received so that sub-class implementations can check current timers and
|
||||
* adjust channel state as necessary. The heartbeat arrives on a periodic basis independent of any decoded
|
||||
@@ -69,7 +89,7 @@ public abstract class AbstractChannelState extends Module implements IChannelEve
|
||||
*/
|
||||
protected abstract void checkState();
|
||||
|
||||
public abstract Collection<ChannelMetadata> getChannelMetadata();
|
||||
public abstract List<ChannelMetadata> getChannelMetadata();
|
||||
|
||||
public abstract void updateChannelStateIdentifiers(IdentifierUpdateNotification notification);
|
||||
|
||||
|
||||
@@ -24,10 +24,8 @@ import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.string.SimpleStringIdentifier;
|
||||
import io.github.dsheirer.identifier.string.StringIdentifier;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -78,7 +76,7 @@ public class AlwaysUnsquelchedDecoderState extends DecoderState
|
||||
@Override
|
||||
public void receiveDecoderStateEvent(DecoderStateEvent event)
|
||||
{
|
||||
if(event.getEvent() == Event.RESET)
|
||||
if(event.getEvent() == Event.REQUEST_RESET)
|
||||
{
|
||||
getIdentifierCollection().update(mChannelNameIdentifier);
|
||||
}
|
||||
@@ -93,7 +91,7 @@ public class AlwaysUnsquelchedDecoderState extends DecoderState
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.ALWAYS_UNSQUELCH, State.IDLE));
|
||||
broadcast(new DecoderStateEvent(this, Event.REQUEST_ALWAYS_UNSQUELCH, State.IDLE));
|
||||
getIdentifierCollection().update(mChannelNameIdentifier);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ChangeChannelTimeoutEvent extends DecoderStateEvent
|
||||
*/
|
||||
public ChangeChannelTimeoutEvent(Object source, ChannelType channelType, long timeout, int timeslot)
|
||||
{
|
||||
super(source, Event.CHANGE_CALL_TIMEOUT, State.IDLE, timeslot);
|
||||
super(source, Event.REQUEST_CHANGE_CALL_TIMEOUT, State.IDLE, timeslot);
|
||||
mChannelType = channelType;
|
||||
mCallTimeoutMilliseconds = timeout;
|
||||
}
|
||||
|
||||
@@ -125,14 +125,6 @@ public abstract class DecoderState extends AbstractDecoderState
|
||||
*/
|
||||
public abstract void init();
|
||||
|
||||
/**
|
||||
* Disposes any resources or pointers held by this instance to prepare for
|
||||
* garbage collection
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for configuration identifiers and adds them to this decoder state's identifier collection.
|
||||
* @return
|
||||
|
||||
@@ -22,16 +22,12 @@
|
||||
|
||||
package io.github.dsheirer.channel.state;
|
||||
|
||||
/**
|
||||
* State and Status request and notification events used for communication between Decoder States and Channel states
|
||||
* and by peripheral entities like the ChannelRotationMonitor.
|
||||
*/
|
||||
public class DecoderStateEvent
|
||||
{
|
||||
private static final DecoderStateEvent ACTIVE_STATE_TIMESLOT_0 =
|
||||
new DecoderStateEvent(null, Event.NOTIFICATION_CHANNEL_ACTIVE_STATE, State.ACTIVE, 0);
|
||||
private static final DecoderStateEvent ACTIVE_STATE_TIMESLOT_1 =
|
||||
new DecoderStateEvent(null, Event.NOTIFICATION_CHANNEL_ACTIVE_STATE, State.ACTIVE, 1);
|
||||
private static final DecoderStateEvent INACTIVE_STATE_TIMESLOT_0 =
|
||||
new DecoderStateEvent(null, Event.NOTIFICATION_CHANNEL_INACTIVE_STATE, State.ACTIVE, 0);
|
||||
private static final DecoderStateEvent INACTIVE_STATE_TIMESLOT_1 =
|
||||
new DecoderStateEvent(null, Event.NOTIFICATION_CHANNEL_INACTIVE_STATE, State.ACTIVE, 1);
|
||||
private Object mSource;
|
||||
private Event mEvent;
|
||||
private State mState;
|
||||
@@ -63,65 +59,14 @@ public class DecoderStateEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a channel state active event for the specified timeslot
|
||||
* @param timeslot that the state applies to
|
||||
* @return new event
|
||||
* Creates a decoder state notification event for a null source with the specified state and timeslot.
|
||||
* @param state (current) of the decoder
|
||||
* @param timeslot that is reporting state
|
||||
* @return new decoder state event
|
||||
*/
|
||||
public static DecoderStateEvent activeState(int timeslot)
|
||||
public static DecoderStateEvent stateNotification(State state, int timeslot)
|
||||
{
|
||||
if(timeslot == 0)
|
||||
{
|
||||
return ACTIVE_STATE_TIMESLOT_0;
|
||||
}
|
||||
else if(timeslot == 1)
|
||||
{
|
||||
return ACTIVE_STATE_TIMESLOT_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Only timeslots 0 and 1 are currently supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a channel state active event for the specified timeslot.
|
||||
* @param state currently
|
||||
* @return new event
|
||||
*/
|
||||
public static DecoderStateEvent activeState()
|
||||
{
|
||||
return activeState(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a channel state inactive event for the specified timeslot
|
||||
* @param timeslot that the state applies to
|
||||
* @return new event
|
||||
*/
|
||||
public static DecoderStateEvent inactiveState(int timeslot)
|
||||
{
|
||||
if(timeslot == 0)
|
||||
{
|
||||
return INACTIVE_STATE_TIMESLOT_0;
|
||||
}
|
||||
else if(timeslot == 1)
|
||||
{
|
||||
return INACTIVE_STATE_TIMESLOT_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Only timeslots 0 and 1 are currently supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a channel state active event for the specified timeslot.
|
||||
* @param state currently
|
||||
* @return new event
|
||||
*/
|
||||
public static DecoderStateEvent inactiveState()
|
||||
{
|
||||
return inactiveState(0);
|
||||
return new DecoderStateEvent(null, Event.NOTIFICATION_CHANNEL_STATE, state, timeslot);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
@@ -164,15 +109,23 @@ public class DecoderStateEvent
|
||||
|
||||
public enum Event
|
||||
{
|
||||
ALWAYS_UNSQUELCH,
|
||||
CHANGE_CALL_TIMEOUT,
|
||||
//Decode state discrete events
|
||||
CONTINUATION,
|
||||
DECODE,
|
||||
END,
|
||||
START,
|
||||
|
||||
NOTIFICATION_CHANNEL_STATE,
|
||||
NOTIFICATION_CHANNEL_ACTIVE_STATE,
|
||||
NOTIFICATION_CHANNEL_INACTIVE_STATE,
|
||||
RESET,
|
||||
SOURCE_FREQUENCY,
|
||||
START;
|
||||
NOTIFICATION_SOURCE_FREQUENCY,
|
||||
|
||||
|
||||
REQUEST_ALWAYS_UNSQUELCH,
|
||||
REQUEST_CHANGE_CALL_TIMEOUT,
|
||||
REQUEST_RESET,
|
||||
|
||||
//Request to convert the current channel to a traffic channel (used by DMR Cap+)
|
||||
REQUEST_CONVERT_TO_TRAFFIC_CHANNEL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.channel.state;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Cache for frequently reused decoder state notification events and timeslots
|
||||
*/
|
||||
public class DecoderStateNotificationEventCache
|
||||
{
|
||||
private Map<Integer,Map<State,DecoderStateEvent>> mTimeslotMap = new HashMap<>();
|
||||
|
||||
public DecoderStateNotificationEventCache()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a decoder state notification event for the state and timeslot, or reuses a previously created event.
|
||||
* @param state for the decoder
|
||||
* @param timeslot of the decoder
|
||||
* @return state notification event
|
||||
*/
|
||||
public DecoderStateEvent getStateNotificationEvent(State state, int timeslot)
|
||||
{
|
||||
Map<State,DecoderStateEvent> timeslotStateMap = mTimeslotMap.get(timeslot);
|
||||
|
||||
if(timeslotStateMap == null)
|
||||
{
|
||||
timeslotStateMap = new HashMap<>();
|
||||
mTimeslotMap.put(timeslot, timeslotStateMap);
|
||||
}
|
||||
|
||||
DecoderStateEvent event = timeslotStateMap.get(state);
|
||||
|
||||
if(event == null)
|
||||
{
|
||||
event = DecoderStateEvent.stateNotification(state, timeslot);
|
||||
timeslotStateMap.put(state, event);
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -39,7 +40,6 @@ import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentif
|
||||
import io.github.dsheirer.identifier.configuration.SiteConfigurationIdentifier;
|
||||
import io.github.dsheirer.identifier.configuration.SystemConfigurationIdentifier;
|
||||
import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.module.decode.event.IDecodeEvent;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.ISourceEventListener;
|
||||
@@ -50,11 +50,28 @@ import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Multi-Channel state tracks the overall state of all processing modules and decoders configured for the channel
|
||||
* and provides squelch control and decoder state reset events.
|
||||
*
|
||||
* Uses a state enumeration that defines allowable channel state transitions in order to track a call or data decode
|
||||
* event from start to finish. Uses a timer to monitor for inactivity and to provide a FADE period that indicates
|
||||
* to the user that the activity has stopped while continuing to provide details about the call, before the state is
|
||||
* reset to IDLE.
|
||||
*
|
||||
* State Descriptions:
|
||||
* IDLE: Normal state. No voice or data call activity
|
||||
* CALL/DATA/ENCRYPTED/CONTROL: Decoding states.
|
||||
* FADE: The phase after a voice or data call when either an explicit call end has been received, or when no new
|
||||
* signalling updates have been received, and the fade timer has expired. This phase allows for gui updates to
|
||||
* signal to the user that the call is ended, while continuing to display the call details for the user
|
||||
* TEARDOWN: Indicates a traffic channel that will be torn down for reuse.
|
||||
*/
|
||||
public class MultiChannelState extends AbstractChannelState implements IDecoderStateEventListener, ISourceEventListener,
|
||||
IdentifierUpdateListener, IStateMachineListener
|
||||
{
|
||||
@@ -70,33 +87,23 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
private Map<Integer,MutableIdentifierCollection> mIdentifierCollectionMap = new TreeMap<>();
|
||||
private Map<Integer,StateMachine> mStateMachineMap = new TreeMap<>();
|
||||
private Map<Integer,StateMonitoringSquelchController> mSquelchControllerMap = new TreeMap<>();
|
||||
private int mTimeslotCount;
|
||||
private int[] mTimeslots;
|
||||
private DecoderStateNotificationEventCache mStateNotificationCache = new DecoderStateNotificationEventCache();
|
||||
private Listener<IdentifierUpdateNotification> mIdentifierUpdateListener = new IdentifierUpdateListenerProxy();
|
||||
|
||||
/**
|
||||
* Multi-Channel state tracks the overall state of all processing modules and decoders configured for the channel
|
||||
* and provides squelch control and decoder state reset events.
|
||||
*
|
||||
* Uses a state enumeration that defines allowable channel state transitions in order to track a call or data decode
|
||||
* event from start to finish. Uses a timer to monitor for inactivity and to provide a FADE period that indicates
|
||||
* to the user that the activity has stopped while continuing to provide details about the call, before the state is
|
||||
* reset to IDLE.
|
||||
*
|
||||
* State Descriptions:
|
||||
* IDLE: Normal state. No voice or data call activity
|
||||
* CALL/DATA/ENCRYPTED/CONTROL: Decoding states.
|
||||
* FADE: The phase after a voice or data call when either an explicit call end has been received, or when no new
|
||||
* signalling updates have been received, and the fade timer has expired. This phase allows for gui updates to
|
||||
* signal to the user that the call is ended, while continuing to display the call details for the user
|
||||
* TEARDOWN: Indicates a traffic channel that will be torn down for reuse.
|
||||
* Constructs an instance
|
||||
* @param channel configuration
|
||||
* @param aliasModel for channel metadata and identifiers
|
||||
* @param timeslots array of timeslot numbers to use
|
||||
*/
|
||||
public MultiChannelState(Channel channel, AliasModel aliasModel, int timeslots)
|
||||
public MultiChannelState(Channel channel, AliasModel aliasModel, int[] timeslots)
|
||||
{
|
||||
super(channel);
|
||||
|
||||
mTimeslotCount = timeslots;
|
||||
mTimeslots = timeslots;
|
||||
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
for(int timeslot: timeslots)
|
||||
{
|
||||
mChannelMetadataMap.put(timeslot, new ChannelMetadata(aliasModel, timeslot));
|
||||
MutableIdentifierCollection mutableIdentifierCollection = new MutableIdentifierCollection(timeslot);
|
||||
@@ -113,36 +120,45 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
mSquelchControllerMap.put(timeslot, squelchController);
|
||||
stateMachine.addListener(squelchController);
|
||||
|
||||
stateMachine.setChannelType(mChannel.getChannelType());
|
||||
stateMachine.setIdentifierUpdateListener(mutableIdentifierCollection);
|
||||
stateMachine.setEndTimeoutBufferMilliseconds(RESET_TIMEOUT_DELAY);
|
||||
if(channel.getChannelType() == ChannelType.STANDARD)
|
||||
{
|
||||
stateMachine.setFadeTimeoutBufferMilliseconds(FADE_TIMEOUT_DELAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
stateMachine.setFadeTimeoutBufferMilliseconds(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS * 1000);
|
||||
}
|
||||
stateMachine.setFadeTimeoutBufferMilliseconds(FADE_TIMEOUT_DELAY);
|
||||
}
|
||||
|
||||
configureChannelType(channel);
|
||||
|
||||
createConfigurationIdentifiers(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure items according to channel type
|
||||
* @param channel configuration
|
||||
*/
|
||||
private void configureChannelType(Channel channel)
|
||||
{
|
||||
for(int timeslot: mTimeslots)
|
||||
{
|
||||
StateMachine stateMachine = mStateMachineMap.get(timeslot);
|
||||
stateMachine.setChannelType(channel.getChannelType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.MULTI_CHANNEL_ACTIVE_STATES.contains(state))
|
||||
{
|
||||
broadcast(DecoderStateEvent.activeState(timeslot));
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(DecoderStateEvent.inactiveState(timeslot));
|
||||
}
|
||||
|
||||
ChannelStateIdentifier stateIdentifier = ChannelStateIdentifier.create(state);
|
||||
ChannelStateIdentifier stateIdentifier = ChannelStateIdentifier.get(state);
|
||||
mIdentifierCollectionMap.get(timeslot).update(stateIdentifier);
|
||||
mChannelMetadataMap.get(timeslot).receive(new IdentifierUpdateNotification(stateIdentifier, IdentifierUpdateNotification.Operation.ADD, timeslot));
|
||||
|
||||
@@ -153,7 +169,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
mStateMachineMap.get(timeslot).setState(State.IDLE);
|
||||
break;
|
||||
case TEARDOWN:
|
||||
if(mChannel.isTrafficChannel())
|
||||
if(getChannel().isTrafficChannel())
|
||||
{
|
||||
checkTeardown();
|
||||
}
|
||||
@@ -191,9 +207,9 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
|
||||
if(teardown && !active)
|
||||
{
|
||||
if(mChannel.isTrafficChannel())
|
||||
if(getChannel().isTrafficChannel())
|
||||
{
|
||||
broadcast(new ChannelEvent(mChannel, ChannelEvent.Event.REQUEST_DISABLE));
|
||||
broadcast(new ChannelEvent(getChannel(), ChannelEvent.Event.REQUEST_DISABLE));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -230,7 +246,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
*/
|
||||
private void createConfigurationIdentifiers(Channel channel)
|
||||
{
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
for(int timeslot: mTimeslots)
|
||||
{
|
||||
MutableIdentifierCollection identifierCollection = mIdentifierCollectionMap.get(timeslot);
|
||||
|
||||
@@ -334,9 +350,9 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
/**
|
||||
* Channel metadata for this channel.
|
||||
*/
|
||||
public Collection<ChannelMetadata> getChannelMetadata()
|
||||
public List<ChannelMetadata> getChannelMetadata()
|
||||
{
|
||||
return mChannelMetadataMap.values();
|
||||
return new ArrayList<>(mChannelMetadataMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +361,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
for(int timeslot: mTimeslots)
|
||||
{
|
||||
reset(timeslot);
|
||||
}
|
||||
@@ -356,7 +372,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
private void reset(int timeslot)
|
||||
{
|
||||
mStateMachineMap.get(timeslot).setState(State.RESET);
|
||||
broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE, timeslot));
|
||||
broadcast(new DecoderStateEvent(this, Event.REQUEST_RESET, State.IDLE, timeslot));
|
||||
MutableIdentifierCollection identifierCollection = mIdentifierCollectionMap.get(timeslot);
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
}
|
||||
@@ -364,7 +380,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
for(int timeslot: mTimeslots)
|
||||
{
|
||||
mIdentifierCollectionMap.get(timeslot).broadcastIdentifiers();
|
||||
mStateMachineMap.get(timeslot).setState(State.RESET);
|
||||
@@ -380,12 +396,6 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mDecodeEventListener = null;
|
||||
mDecoderStateListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
@@ -480,9 +490,9 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
//Rebroadcast source frequency change events for the decoder(s) to process
|
||||
long frequency = sourceEvent.getValue().longValue();
|
||||
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
for(int timeslot: mTimeslots)
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY,
|
||||
broadcast(new DecoderStateEvent(this, Event.NOTIFICATION_SOURCE_FREQUENCY,
|
||||
mStateMachineMap.get(timeslot).getState(), frequency));
|
||||
|
||||
//Create a new frequency configuration identifier so that downstream consumers receive the change
|
||||
@@ -497,12 +507,13 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
case NOTIFICATION_MEASURED_FREQUENCY_ERROR:
|
||||
//Rebroadcast frequency error measurements to external listener if we're currently
|
||||
//in an active (ie sync locked) state.
|
||||
for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++)
|
||||
for(int timeslot: mTimeslots)
|
||||
{
|
||||
if(State.MULTI_CHANNEL_ACTIVE_STATES.contains(mStateMachineMap.get(timeslot).getState()))
|
||||
{
|
||||
broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(),
|
||||
mChannel.getChannelType().name()));
|
||||
getChannel().getChannelType().name()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -522,10 +533,10 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case ALWAYS_UNSQUELCH:
|
||||
case REQUEST_ALWAYS_UNSQUELCH:
|
||||
mSquelchControllerMap.get(event.getTimeslot()).setSquelchLock(true);
|
||||
break;
|
||||
case CHANGE_CALL_TIMEOUT:
|
||||
case REQUEST_CHANGE_CALL_TIMEOUT:
|
||||
if(event instanceof ChangeChannelTimeoutEvent)
|
||||
{
|
||||
ChangeChannelTimeoutEvent timeout = (ChangeChannelTimeoutEvent)event;
|
||||
@@ -538,19 +549,18 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS
|
||||
if(State.MULTI_CHANNEL_ACTIVE_STATES.contains(event.getState()))
|
||||
{
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(event.getState());
|
||||
|
||||
//Broadcast current channel/timeslot state so that channel rotation monitor can track
|
||||
broadcast(mStateNotificationCache.getStateNotificationEvent(event.getState(), event.getTimeslot()));
|
||||
}
|
||||
break;
|
||||
case END:
|
||||
if(mChannel.isTrafficChannel())
|
||||
{
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(event.getState());
|
||||
}
|
||||
else
|
||||
{
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(event.getState());
|
||||
}
|
||||
mStateMachineMap.get(event.getTimeslot()).setState(event.getState());
|
||||
|
||||
//Broadcast current channel/timeslot state so that channel rotation monitor can track
|
||||
broadcast(mStateNotificationCache.getStateNotificationEvent(event.getState(), event.getTimeslot()));
|
||||
break;
|
||||
case RESET:
|
||||
case REQUEST_RESET:
|
||||
/* Channel State does not respond to reset events */
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user