mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 17:47:32 -05:00
Merge pull request #391 from DSheirer/389-add-active-to-channel-states
389 Add ACTIVE Channel State and Update P25 Decoder State processing
This commit is contained in:
@@ -123,6 +123,11 @@ public class AttributeMonitor<T>
|
|||||||
{
|
{
|
||||||
mCurrentValue = null;
|
mCurrentValue = null;
|
||||||
mOccurrenceCounts.clear();
|
mOccurrenceCounts.clear();
|
||||||
|
|
||||||
|
if(mListener != null)
|
||||||
|
{
|
||||||
|
mListener.receive(new AttributeChangeRequest(mAttribute, null, null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,32 +25,36 @@ import io.github.dsheirer.controller.channel.ChannelProcessingManager;
|
|||||||
import io.github.dsheirer.controller.channel.ChannelUtils;
|
import io.github.dsheirer.controller.channel.ChannelUtils;
|
||||||
import io.github.dsheirer.icon.IconManager;
|
import io.github.dsheirer.icon.IconManager;
|
||||||
import io.github.dsheirer.module.ProcessingChain;
|
import io.github.dsheirer.module.ProcessingChain;
|
||||||
import io.github.dsheirer.properties.SystemProperties;
|
|
||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.table.DefaultTableCellRenderer;
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
import java.awt.*;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ChannelMetadataPanel extends JPanel implements ListSelectionListener
|
public class ChannelMetadataPanel extends JPanel implements ListSelectionListener
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelMetadataPanel.class);
|
|
||||||
|
|
||||||
private static final String PROPERTY_PREFIX_BACKGROUND = "channel.metadata.panel.state.color.";
|
|
||||||
private static final String PROPERTY_PREFIX_FOREGROUND = "channel.metadata.panel.text.color.";
|
|
||||||
private ChannelProcessingManager mChannelProcessingManager;
|
private ChannelProcessingManager mChannelProcessingManager;
|
||||||
private IconManager mIconManager;
|
private IconManager mIconManager;
|
||||||
private JTable mTable;
|
private JTable mTable;
|
||||||
private Broadcaster<ProcessingChain> mSelectedProcessingChainBroadcaster = new Broadcaster<>();
|
private Broadcaster<ProcessingChain> mSelectedProcessingChainBroadcaster = new Broadcaster<>();
|
||||||
|
private Map<State,Color> mBackgroundColors = new HashMap<>();
|
||||||
|
private Map<State,Color> mForegroundColors = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table view for currently decoding channel metadata
|
* Table view for currently decoding channel metadata
|
||||||
@@ -94,7 +98,34 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
|
|||||||
|
|
||||||
add(scrollPane);
|
add(scrollPane);
|
||||||
|
|
||||||
// new TableColumnWidthMonitor(mTable, PROPERTY_PREFIX, new int[] {15,15,15,15,25,25,25,25,15,40});
|
setColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the background and foreground color palette for the various channel states.
|
||||||
|
*/
|
||||||
|
private void setColors()
|
||||||
|
{
|
||||||
|
mBackgroundColors.put(State.ACTIVE, Color.CYAN);
|
||||||
|
mForegroundColors.put(State.ACTIVE, Color.YELLOW);
|
||||||
|
mBackgroundColors.put(State.CALL, Color.BLUE);
|
||||||
|
mForegroundColors.put(State.CALL, Color.YELLOW);
|
||||||
|
mBackgroundColors.put(State.CONTROL, Color.ORANGE);
|
||||||
|
mForegroundColors.put(State.CONTROL, Color.BLUE);
|
||||||
|
mBackgroundColors.put(State.DATA, Color.GREEN);
|
||||||
|
mForegroundColors.put(State.DATA, Color.BLUE);
|
||||||
|
mBackgroundColors.put(State.ENCRYPTED, Color.MAGENTA);
|
||||||
|
mForegroundColors.put(State.ENCRYPTED, Color.WHITE);
|
||||||
|
mBackgroundColors.put(State.FADE, Color.LIGHT_GRAY);
|
||||||
|
mForegroundColors.put(State.FADE, Color.DARK_GRAY);
|
||||||
|
mBackgroundColors.put(State.IDLE, Color.WHITE);
|
||||||
|
mForegroundColors.put(State.IDLE, Color.DARK_GRAY);
|
||||||
|
mBackgroundColors.put(State.OVERFLOW, Color.RED);
|
||||||
|
mForegroundColors.put(State.OVERFLOW, Color.YELLOW);
|
||||||
|
mBackgroundColors.put(State.RESET, Color.PINK);
|
||||||
|
mForegroundColors.put(State.RESET, Color.YELLOW);
|
||||||
|
mBackgroundColors.put(State.TEARDOWN, Color.DARK_GRAY);
|
||||||
|
mForegroundColors.put(State.TEARDOWN, Color.WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,44 +216,14 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
|
|||||||
State state = (State)value;
|
State state = (State)value;
|
||||||
label.setText(state.getDisplayValue());
|
label.setText(state.getDisplayValue());
|
||||||
|
|
||||||
switch(state)
|
if(mBackgroundColors.containsKey(state))
|
||||||
{
|
{
|
||||||
case CALL:
|
background = mBackgroundColors.get(state);
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "call", Color.BLUE);
|
}
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "call", Color.YELLOW);
|
|
||||||
break;
|
if(mForegroundColors.containsKey(state))
|
||||||
case CONTROL:
|
{
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "control", Color.ORANGE);
|
foreground = mForegroundColors.get(state);
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "control", Color.BLUE);
|
|
||||||
break;
|
|
||||||
case DATA:
|
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "data", Color.GREEN);
|
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "data", Color.BLUE);
|
|
||||||
break;
|
|
||||||
case ENCRYPTED:
|
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "encrypted", Color.MAGENTA);
|
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "encrypted", Color.WHITE);
|
|
||||||
break;
|
|
||||||
case FADE:
|
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "fade", Color.LIGHT_GRAY.BLUE);
|
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "fade", Color.YELLOW);
|
|
||||||
break;
|
|
||||||
case IDLE:
|
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "idle", Color.WHITE);
|
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "idle", Color.BLUE);
|
|
||||||
break;
|
|
||||||
case OVERFLOW:
|
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "overflow", Color.RED);
|
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "overflow", Color.YELLOW);
|
|
||||||
break;
|
|
||||||
case RESET:
|
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "reset", Color.PINK);
|
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "reset", Color.YELLOW);
|
|
||||||
break;
|
|
||||||
case TEARDOWN:
|
|
||||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "teardown", Color.DARK_GRAY);
|
|
||||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "teardown", Color.WHITE);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -303,6 +303,11 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
|||||||
{
|
{
|
||||||
switch(state)
|
switch(state)
|
||||||
{
|
{
|
||||||
|
case ACTIVE:
|
||||||
|
broadcast(SquelchState.SQUELCH);
|
||||||
|
updateFadeTimeout();
|
||||||
|
mState = state;
|
||||||
|
break;
|
||||||
case CONTROL:
|
case CONTROL:
|
||||||
//Don't allow traffic channels to be control channels, otherwise they can't transition to teardown
|
//Don't allow traffic channels to be control channels, otherwise they can't transition to teardown
|
||||||
if(isStandardChannel())
|
if(isStandardChannel())
|
||||||
|
|||||||
@@ -24,54 +24,114 @@ import java.util.EnumSet;
|
|||||||
*/
|
*/
|
||||||
public enum State
|
public enum State
|
||||||
{
|
{
|
||||||
IDLE("IDLE")
|
/**
|
||||||
|
* Active state indicates that valid messages are being decoded that do not indicate any call or data
|
||||||
|
* activity. For example, this is used for P25 when a channel is actively transmitting Terminator Data
|
||||||
|
* Units in between data packets or at the beginning or end of a call.
|
||||||
|
*/
|
||||||
|
ACTIVE("ACTIVE")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangeTo(State state)
|
public boolean canChangeTo(State state)
|
||||||
{
|
{
|
||||||
return state != TEARDOWN && state != RESET && state != OVERFLOW;
|
return state == CALL |
|
||||||
|
state == CONTROL ||
|
||||||
|
state == DATA ||
|
||||||
|
state == ENCRYPTED ||
|
||||||
|
state == FADE ||
|
||||||
|
state == TEARDOWN;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Indicates that call messages are being decoded, or a call is in progress (ie producing audio).
|
||||||
|
*/
|
||||||
CALL("CALL")
|
CALL("CALL")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangeTo(State state)
|
public boolean canChangeTo(State state)
|
||||||
{
|
{
|
||||||
return state == CONTROL || state == DATA || state == ENCRYPTED || state == FADE || state == TEARDOWN;
|
return state == ACTIVE ||
|
||||||
}
|
state == CONTROL ||
|
||||||
},
|
state == DATA ||
|
||||||
DATA("DATA")
|
state == ENCRYPTED ||
|
||||||
{
|
state == FADE ||
|
||||||
@Override
|
state == TEARDOWN;
|
||||||
public boolean canChangeTo(State state)
|
|
||||||
{
|
|
||||||
return state == CALL || state == CONTROL || state == ENCRYPTED || state == FADE || state == TEARDOWN;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ENCRYPTED("ENCRYPTED")
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean canChangeTo(State state)
|
|
||||||
{
|
|
||||||
return state == FADE || state == TEARDOWN;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Indicates a trunking control channel is being decoded.
|
||||||
|
*/
|
||||||
CONTROL("CONTROL")
|
CONTROL("CONTROL")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangeTo(State state)
|
public boolean canChangeTo(State state)
|
||||||
{
|
{
|
||||||
return state == IDLE || state == FADE;
|
return state == IDLE ||
|
||||||
|
state == FADE;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Indicates data packets are being decoded
|
||||||
|
*/
|
||||||
|
DATA("DATA")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean canChangeTo(State state)
|
||||||
|
{
|
||||||
|
return state == ACTIVE ||
|
||||||
|
state == CALL ||
|
||||||
|
state == CONTROL ||
|
||||||
|
state == ENCRYPTED ||
|
||||||
|
state == FADE ||
|
||||||
|
state == TEARDOWN;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Indicates encrypted audio is detected.
|
||||||
|
*/
|
||||||
|
ENCRYPTED("ENCRYPTED")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean canChangeTo(State state)
|
||||||
|
{
|
||||||
|
return state == FADE ||
|
||||||
|
state == TEARDOWN;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Fade state occurs when the channel is no longer actively decoding an messages. This is a transitory
|
||||||
|
* state before transition to IDLE or back to an active state.
|
||||||
|
*/
|
||||||
FADE("FADE")
|
FADE("FADE")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangeTo(State state)
|
public boolean canChangeTo(State state)
|
||||||
{
|
{
|
||||||
return state != FADE && state != RESET && state != OVERFLOW;
|
return state != FADE &&
|
||||||
|
state != RESET &&
|
||||||
|
state != OVERFLOW;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Indicates the channel is idle and not actively decoding any messages
|
||||||
|
*/
|
||||||
|
IDLE("IDLE")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean canChangeTo(State state)
|
||||||
|
{
|
||||||
|
return state != TEARDOWN &&
|
||||||
|
state != RESET &&
|
||||||
|
state != OVERFLOW;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Indicates that the channel's sample buffer has overflowed and new buffer samples are no longer being
|
||||||
|
* delivered to the channel. This state persists until the processing catches up and reduces the number
|
||||||
|
* of samples in the input buffer below a threshold value. Transition to and from this state is exclusively
|
||||||
|
* managed by the Channel State and no other channel states can be processed from the channel decoders
|
||||||
|
* until the channel state is taken out of overflow.
|
||||||
|
*/
|
||||||
OVERFLOW("OVERFLOW")
|
OVERFLOW("OVERFLOW")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@@ -80,6 +140,9 @@ public enum State
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Indicates that the channel has been reset and is ready to use for a new decoding session.
|
||||||
|
*/
|
||||||
RESET("RESET")
|
RESET("RESET")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@@ -88,6 +151,10 @@ public enum State
|
|||||||
return state == IDLE;
|
return state == IDLE;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Call or data teardown. This state is used by traffic channels to indicate that a call or data session
|
||||||
|
* has concluded and the channel is ready for tear down and reuse.
|
||||||
|
*/
|
||||||
TEARDOWN("TEARDOWN")
|
TEARDOWN("TEARDOWN")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@@ -99,7 +166,7 @@ public enum State
|
|||||||
|
|
||||||
private String mDisplayValue;
|
private String mDisplayValue;
|
||||||
|
|
||||||
public static final EnumSet<State> CALL_STATES = EnumSet.of(CALL, CONTROL, DATA, ENCRYPTED);
|
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> IDLE_STATES = EnumSet.of(IDLE, FADE);
|
||||||
|
|
||||||
private State(String displayValue)
|
private State(String displayValue)
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
if(mCurrentCallEvent != null)
|
if(mCurrentCallEvent != null)
|
||||||
{
|
{
|
||||||
mCurrentCallEvent.end();
|
mCurrentCallEvent.end();
|
||||||
|
broadcast(mCurrentCallEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentCallEvent = null;
|
mCurrentCallEvent = null;
|
||||||
@@ -395,6 +396,10 @@ public class P25DecoderState extends DecoderState
|
|||||||
*/
|
*/
|
||||||
private void processTDU(TDUMessage tdu)
|
private void processTDU(TDUMessage tdu)
|
||||||
{
|
{
|
||||||
|
if(mChannelType == ChannelType.STANDARD)
|
||||||
|
{
|
||||||
|
broadcast(new DecoderStateEvent(this, Event.DECODE, State.ACTIVE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -432,19 +437,21 @@ public class P25DecoderState extends DecoderState
|
|||||||
*/
|
*/
|
||||||
private void processTDULC(TDULinkControlMessage tdulc)
|
private void processTDULC(TDULinkControlMessage tdulc)
|
||||||
{
|
{
|
||||||
|
if(mCurrentCallEvent != null)
|
||||||
|
{
|
||||||
|
mCurrentCallEvent.end();
|
||||||
|
broadcast(mCurrentCallEvent);
|
||||||
|
mCurrentCallEvent = null;
|
||||||
|
}
|
||||||
|
|
||||||
if(tdulc.getOpcode() == LinkControlOpcode.CALL_TERMINATION_OR_CANCELLATION)
|
if(tdulc.getOpcode() == LinkControlOpcode.CALL_TERMINATION_OR_CANCELLATION)
|
||||||
{
|
{
|
||||||
broadcast(new DecoderStateEvent(this, Event.END, State.FADE));
|
broadcast(new DecoderStateEvent(this, Event.END, State.FADE));
|
||||||
|
|
||||||
if(mCurrentCallEvent != null)
|
|
||||||
{
|
|
||||||
mCurrentCallEvent.end();
|
|
||||||
mCurrentCallEvent = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL));
|
broadcast(new DecoderStateEvent(this, Event.DECODE, State.ACTIVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(tdulc.getOpcode())
|
switch(tdulc.getOpcode())
|
||||||
@@ -495,22 +502,17 @@ public class P25DecoderState extends DecoderState
|
|||||||
/* This opcode as handled at the beginning of the method */
|
/* This opcode as handled at the beginning of the method */
|
||||||
break;
|
break;
|
||||||
case CHANNEL_IDENTIFIER_UPDATE:
|
case CHANNEL_IDENTIFIER_UPDATE:
|
||||||
//TODO: does the activity summary need this message?
|
|
||||||
|
|
||||||
/* This message is handled by the P25MessageProcessor and
|
/* This message is handled by the P25MessageProcessor and
|
||||||
* inserted into any channels needing frequency band info */
|
* inserted into any channels needing frequency band info */
|
||||||
break;
|
break;
|
||||||
case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
|
case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
|
||||||
//TODO: does the activity summary need this message?
|
|
||||||
|
|
||||||
/* This message is handled by the P25MessageProcessor and
|
/* This message is handled by the P25MessageProcessor and
|
||||||
* inserted into any channels needing frequency band info */
|
* inserted into any channels needing frequency band info */
|
||||||
break;
|
break;
|
||||||
case EXTENDED_FUNCTION_COMMAND:
|
case EXTENDED_FUNCTION_COMMAND:
|
||||||
if(tdulc instanceof ExtendedFunctionCommand)
|
if(tdulc instanceof ExtendedFunctionCommand)
|
||||||
{
|
{
|
||||||
ExtendedFunctionCommand efc =
|
ExtendedFunctionCommand efc = (ExtendedFunctionCommand)tdulc;
|
||||||
(ExtendedFunctionCommand)tdulc;
|
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.COMMAND)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.COMMAND)
|
||||||
.aliasList(getAliasList())
|
.aliasList(getAliasList())
|
||||||
@@ -606,42 +608,25 @@ public class P25DecoderState extends DecoderState
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GROUP_VOICE_CHANNEL_USER:
|
case GROUP_VOICE_CHANNEL_USER:
|
||||||
/* Used on a traffic channel to reflect current call entities */
|
//Used on a traffic channel to reflect that the channel is currently being used by the
|
||||||
|
//TO talkgroup, but that channel is currently quiet (ie no voice) */
|
||||||
if(tdulc instanceof GroupVoiceChannelUser)
|
if(tdulc instanceof GroupVoiceChannelUser)
|
||||||
{
|
{
|
||||||
GroupVoiceChannelUser gvcuser =
|
GroupVoiceChannelUser gvcuser = (GroupVoiceChannelUser)tdulc;
|
||||||
(GroupVoiceChannelUser)tdulc;
|
|
||||||
|
|
||||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL));
|
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.ACTIVE));
|
||||||
|
|
||||||
|
//The from value should always be "000000" indicating that nobody is currently talking
|
||||||
|
mFromTalkgroupMonitor.reset();
|
||||||
|
|
||||||
String from = gvcuser.getSourceAddress();
|
|
||||||
String to = gvcuser.getGroupAddress();
|
String to = gvcuser.getGroupAddress();
|
||||||
|
|
||||||
mFromTalkgroupMonitor.process(from);
|
|
||||||
mToTalkgroupMonitor.process(to);
|
mToTalkgroupMonitor.process(to);
|
||||||
|
|
||||||
if(mCurrentCallEvent == null)
|
|
||||||
{
|
|
||||||
mCurrentCallEvent = new P25CallEvent.Builder(CallEvent.CallEventType.GROUP_CALL)
|
|
||||||
.aliasList(getAliasList())
|
|
||||||
.channel(mCurrentChannel)
|
|
||||||
.details("TDULC GROUP VOICE CHANNEL USER" +
|
|
||||||
(gvcuser.isEncrypted() ? "ENCRYPTED " : "") +
|
|
||||||
(gvcuser.isEmergency() ? "EMERGENCY " : ""))
|
|
||||||
.frequency(mCurrentChannelFrequency)
|
|
||||||
.from(from)
|
|
||||||
.to(to)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
broadcast(mCurrentCallEvent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MESSAGE_UPDATE:
|
case MESSAGE_UPDATE:
|
||||||
if(tdulc instanceof MessageUpdate)
|
if(tdulc instanceof MessageUpdate)
|
||||||
{
|
{
|
||||||
MessageUpdate mu =
|
MessageUpdate mu = (MessageUpdate)tdulc;
|
||||||
(MessageUpdate)tdulc;
|
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.SDM)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.SDM)
|
||||||
.aliasList(getAliasList())
|
.aliasList(getAliasList())
|
||||||
@@ -748,8 +733,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
io.github.dsheirer.module.decode.p25.message.tdu.lc.SecondaryControlChannelBroadcast sccb =
|
io.github.dsheirer.module.decode.p25.message.tdu.lc.SecondaryControlChannelBroadcast sccb =
|
||||||
(io.github.dsheirer.module.decode.p25.message.tdu.lc.SecondaryControlChannelBroadcast)tdulc;
|
(io.github.dsheirer.module.decode.p25.message.tdu.lc.SecondaryControlChannelBroadcast)tdulc;
|
||||||
|
|
||||||
String site = sccb.getRFSubsystemID() + "-" +
|
String site = sccb.getRFSubsystemID() + "-" + sccb.getSiteID();
|
||||||
sccb.getSiteID();
|
|
||||||
|
|
||||||
mSiteAttributeMonitor.process(site);
|
mSiteAttributeMonitor.process(site);
|
||||||
}
|
}
|
||||||
@@ -761,11 +745,9 @@ public class P25DecoderState extends DecoderState
|
|||||||
case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
|
case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
|
||||||
if(tdulc instanceof SecondaryControlChannelBroadcastExplicit)
|
if(tdulc instanceof SecondaryControlChannelBroadcastExplicit)
|
||||||
{
|
{
|
||||||
SecondaryControlChannelBroadcastExplicit sccb =
|
SecondaryControlChannelBroadcastExplicit sccb = (SecondaryControlChannelBroadcastExplicit)tdulc;
|
||||||
(SecondaryControlChannelBroadcastExplicit)tdulc;
|
|
||||||
|
|
||||||
String site = sccb.getRFSubsystemID() + "-" +
|
String site = sccb.getRFSubsystemID() + "-" + sccb.getSiteID();
|
||||||
sccb.getSiteID();
|
|
||||||
|
|
||||||
mSiteAttributeMonitor.process(site);
|
mSiteAttributeMonitor.process(site);
|
||||||
}
|
}
|
||||||
@@ -777,8 +759,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
case STATUS_QUERY:
|
case STATUS_QUERY:
|
||||||
if(tdulc instanceof StatusQuery)
|
if(tdulc instanceof StatusQuery)
|
||||||
{
|
{
|
||||||
StatusQuery sq =
|
StatusQuery sq = (StatusQuery)tdulc;
|
||||||
(StatusQuery)tdulc;
|
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.QUERY)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.QUERY)
|
||||||
.aliasList(getAliasList())
|
.aliasList(getAliasList())
|
||||||
@@ -816,8 +797,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
|
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
|
||||||
if(tdulc instanceof TelephoneInterconnectAnswerRequest)
|
if(tdulc instanceof TelephoneInterconnectAnswerRequest)
|
||||||
{
|
{
|
||||||
TelephoneInterconnectAnswerRequest tiar =
|
TelephoneInterconnectAnswerRequest tiar = (TelephoneInterconnectAnswerRequest)tdulc;
|
||||||
(TelephoneInterconnectAnswerRequest)tdulc;
|
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.PAGE)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.PAGE)
|
||||||
.aliasList(getAliasList())
|
.aliasList(getAliasList())
|
||||||
@@ -835,8 +815,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
if(mChannelType == ChannelType.STANDARD &&
|
if(mChannelType == ChannelType.STANDARD &&
|
||||||
tdulc instanceof TelephoneInterconnectVoiceChannelUser)
|
tdulc instanceof TelephoneInterconnectVoiceChannelUser)
|
||||||
{
|
{
|
||||||
TelephoneInterconnectVoiceChannelUser tivcu =
|
TelephoneInterconnectVoiceChannelUser tivcu = (TelephoneInterconnectVoiceChannelUser)tdulc;
|
||||||
(TelephoneInterconnectVoiceChannelUser)tdulc;
|
|
||||||
|
|
||||||
String to = tivcu.getAddress();
|
String to = tivcu.getAddress();
|
||||||
|
|
||||||
@@ -860,8 +839,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
case UNIT_AUTHENTICATION_COMMAND:
|
case UNIT_AUTHENTICATION_COMMAND:
|
||||||
if(tdulc instanceof UnitAuthenticationCommand)
|
if(tdulc instanceof UnitAuthenticationCommand)
|
||||||
{
|
{
|
||||||
UnitAuthenticationCommand uac =
|
UnitAuthenticationCommand uac = (UnitAuthenticationCommand)tdulc;
|
||||||
(UnitAuthenticationCommand)tdulc;
|
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.COMMAND)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.COMMAND)
|
||||||
.aliasList(getAliasList())
|
.aliasList(getAliasList())
|
||||||
@@ -877,8 +855,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
case UNIT_REGISTRATION_COMMAND:
|
case UNIT_REGISTRATION_COMMAND:
|
||||||
if(tdulc instanceof UnitRegistrationCommand)
|
if(tdulc instanceof UnitRegistrationCommand)
|
||||||
{
|
{
|
||||||
UnitRegistrationCommand urc =
|
UnitRegistrationCommand urc = (UnitRegistrationCommand)tdulc;
|
||||||
(UnitRegistrationCommand)tdulc;
|
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.COMMAND)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.COMMAND)
|
||||||
.aliasList(getAliasList())
|
.aliasList(getAliasList())
|
||||||
@@ -894,8 +871,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
case UNIT_TO_UNIT_ANSWER_REQUEST:
|
case UNIT_TO_UNIT_ANSWER_REQUEST:
|
||||||
if(tdulc instanceof UnitToUnitAnswerRequest)
|
if(tdulc instanceof UnitToUnitAnswerRequest)
|
||||||
{
|
{
|
||||||
UnitToUnitAnswerRequest uuar =
|
UnitToUnitAnswerRequest uuar = (UnitToUnitAnswerRequest)tdulc;
|
||||||
(UnitToUnitAnswerRequest)tdulc;
|
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.PAGE)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.PAGE)
|
||||||
.aliasList(getAliasList())
|
.aliasList(getAliasList())
|
||||||
@@ -913,27 +889,12 @@ public class P25DecoderState extends DecoderState
|
|||||||
/* Used on traffic channels to indicate the current call entities */
|
/* Used on traffic channels to indicate the current call entities */
|
||||||
if(tdulc instanceof UnitToUnitVoiceChannelUser)
|
if(tdulc instanceof UnitToUnitVoiceChannelUser)
|
||||||
{
|
{
|
||||||
UnitToUnitVoiceChannelUser uuvcu =
|
UnitToUnitVoiceChannelUser uuvcu = (UnitToUnitVoiceChannelUser)tdulc;
|
||||||
(UnitToUnitVoiceChannelUser)tdulc;
|
|
||||||
|
|
||||||
String from = uuvcu.getSourceAddress();
|
mFromTalkgroupMonitor.reset();
|
||||||
mFromTalkgroupMonitor.process(from);
|
|
||||||
|
|
||||||
String to = uuvcu.getTargetAddress();
|
String to = uuvcu.getTargetAddress();
|
||||||
mToTalkgroupMonitor.process(to);
|
mToTalkgroupMonitor.process(to);
|
||||||
|
|
||||||
if(mCurrentCallEvent != null)
|
|
||||||
{
|
|
||||||
mCurrentCallEvent = new P25CallEvent.Builder(CallEvent.CallEventType.UNIT_TO_UNIT_CALL)
|
|
||||||
.aliasList(getAliasList())
|
|
||||||
.channel(mCurrentChannel)
|
|
||||||
.details((uuvcu.isEncrypted() ? "ENCRYPTED " : "") +
|
|
||||||
(uuvcu.isEmergency() ? "EMERGENCY " : ""))
|
|
||||||
.frequency(mCurrentChannelFrequency)
|
|
||||||
.from(from)
|
|
||||||
.to(to)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1166,9 +1127,17 @@ public class P25DecoderState extends DecoderState
|
|||||||
(io.github.dsheirer.module.decode.p25.message.ldu.lc.GroupVoiceChannelUser)ldu;
|
(io.github.dsheirer.module.decode.p25.message.ldu.lc.GroupVoiceChannelUser)ldu;
|
||||||
|
|
||||||
mFromTalkgroupMonitor.process(gvcuser.getSourceAddress());
|
mFromTalkgroupMonitor.process(gvcuser.getSourceAddress());
|
||||||
|
mCurrentCallEvent.setFromID(mFromTalkgroupMonitor.getValue());
|
||||||
|
|
||||||
mToTalkgroupMonitor.process(gvcuser.getGroupAddress());
|
mToTalkgroupMonitor.process(gvcuser.getGroupAddress());
|
||||||
|
|
||||||
|
String to = mToTalkgroupMonitor.getValue();
|
||||||
|
|
||||||
|
if(mCurrentCallEvent.getToID() == null || !mCurrentCallEvent.getToID().contentEquals(to))
|
||||||
|
{
|
||||||
|
mCurrentCallEvent.setToID(to);
|
||||||
|
}
|
||||||
|
|
||||||
if(mChannelType == ChannelType.STANDARD)
|
if(mChannelType == ChannelType.STANDARD)
|
||||||
{
|
{
|
||||||
if(mCurrentCallEvent.getCallEventType() != CallEvent.CallEventType.GROUP_CALL)
|
if(mCurrentCallEvent.getCallEventType() != CallEvent.CallEventType.GROUP_CALL)
|
||||||
@@ -1631,14 +1600,13 @@ public class P25DecoderState extends DecoderState
|
|||||||
*/
|
*/
|
||||||
private void processPDU(PDUMessage pdu)
|
private void processPDU(PDUMessage pdu)
|
||||||
{
|
{
|
||||||
|
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.DATA));
|
||||||
|
|
||||||
if(pdu instanceof PacketData || pdu instanceof PDUTypeUnknown)
|
if(pdu instanceof PacketData || pdu instanceof PDUTypeUnknown)
|
||||||
{
|
{
|
||||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.DATA));
|
|
||||||
}
|
}
|
||||||
else if(pdu instanceof PDUConfirmedMessage)
|
else if(pdu instanceof PDUConfirmedMessage)
|
||||||
{
|
{
|
||||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.DATA));
|
|
||||||
|
|
||||||
PDUConfirmedMessage pduc = (PDUConfirmedMessage)pdu;
|
PDUConfirmedMessage pduc = (PDUConfirmedMessage)pdu;
|
||||||
|
|
||||||
switch(pduc.getPDUType())
|
switch(pduc.getPDUType())
|
||||||
@@ -1723,6 +1691,11 @@ public class P25DecoderState extends DecoderState
|
|||||||
sbTo.append(sud.getUDPDestinationPort());
|
sbTo.append(sud.getUDPDestinationPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mFromTalkgroupMonitor.reset();
|
||||||
|
mFromTalkgroupMonitor.process(sbFrom.toString());
|
||||||
|
mToTalkgroupMonitor.reset();
|
||||||
|
mToTalkgroupMonitor.process(pduc.getLogicalLinkID());
|
||||||
|
|
||||||
broadcast(new DecoderStateEvent(this, Event.START, State.DATA));
|
broadcast(new DecoderStateEvent(this, Event.START, State.DATA));
|
||||||
|
|
||||||
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.DATA_CALL)
|
broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.DATA_CALL)
|
||||||
@@ -1750,9 +1723,6 @@ public class P25DecoderState extends DecoderState
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* These are alternate trunking control blocks in PDU format */
|
|
||||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CONTROL));
|
|
||||||
|
|
||||||
switch(pdu.getOpcode())
|
switch(pdu.getOpcode())
|
||||||
{
|
{
|
||||||
case GROUP_DATA_CHANNEL_GRANT:
|
case GROUP_DATA_CHANNEL_GRANT:
|
||||||
|
|||||||
Reference in New Issue
Block a user