diff --git a/src/alias/Alias.java b/src/alias/Alias.java
index 3770b014..fd9ca32a 100644
--- a/src/alias/Alias.java
+++ b/src/alias/Alias.java
@@ -52,7 +52,7 @@ public class Alias
public Alias()
{
}
-
+
public Alias( String name )
{
mName = name;
diff --git a/src/alias/PatchGroupAlias.java b/src/alias/PatchGroupAlias.java
new file mode 100644
index 00000000..6d5ddaa1
--- /dev/null
+++ b/src/alias/PatchGroupAlias.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * sdrtrunk
+ * Copyright (C) 2014-2017 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
+ *
+ ******************************************************************************/
+package alias;
+
+import alias.action.AliasAction;
+import alias.id.AliasID;
+import alias.id.AliasIDType;
+import alias.id.broadcast.BroadcastChannel;
+import alias.id.priority.Priority;
+import alias.id.talkgroup.TalkgroupID;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PatchGroupAlias extends Alias
+{
+ private List mPatchedAliases = new ArrayList<>();
+
+ /**
+ * Patch group alias is a single alias for a group of aliases that are temporarily patched together. This will
+ * normally be used for patched talkgroups, but could be used with any type of alias identifiers that can be
+ * temporarily joined to form a patch group.
+ *
+ * Alias properties such as recordable, streamable and call priority are an aggregation from the set of patched
+ * aliases contained in this patch group alias and where applicable, return the highest value/priority from the
+ * group of patched aliases.
+ */
+ public PatchGroupAlias()
+ {
+ }
+
+ /**
+ * List of patched aliases contained in this patch group
+ */
+ public List getPatchedAliases()
+ {
+ return mPatchedAliases;
+ }
+
+ /**
+ * Removes/clears all patched aliases from this patch alias group
+ */
+ public void clearPatchedAliases()
+ {
+ mPatchedAliases.clear();
+ }
+
+ /**
+ * Adds the patched alias to this patch alias group
+ */
+ public void addPatchedAlias(Alias alias)
+ {
+ mPatchedAliases.add(alias);
+ }
+
+ /**
+ * Removes the patched alias from this patch alias group
+ */
+ public void removePatchedAlias(Alias alias)
+ {
+ mPatchedAliases.remove(alias);
+ }
+
+ @Override
+ public String getName()
+ {
+ if(getId().size() > 0)
+ {
+ for(AliasID id: getId())
+ {
+ if(id.getType() == AliasIDType.TALKGROUP)
+ {
+ return "PATCH:" + ((TalkgroupID)id).getTalkgroup();
+ }
+ }
+ }
+
+ return "PATCH";
+ }
+
+ @Override
+ public List getAction()
+ {
+ List aliasActions = new ArrayList<>();
+
+ for(Alias alias: mPatchedAliases)
+ {
+ aliasActions.addAll(alias.getAction());
+ }
+
+ return aliasActions;
+ }
+
+ @Override
+ public boolean hasActions()
+ {
+ for(Alias alias: mPatchedAliases)
+ {
+ if(alias.hasActions())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public int getCallPriority()
+ {
+ int highestPriority = Priority.DEFAULT_PRIORITY;
+
+ for(Alias alias: mPatchedAliases)
+ {
+ if(alias.getCallPriority() < highestPriority)
+ {
+ highestPriority = alias.getCallPriority();
+ }
+ }
+
+ return highestPriority;
+ }
+
+ @Override
+ public boolean hasCallPriority()
+ {
+ for(Alias alias: mPatchedAliases)
+ {
+ if(alias.hasCallPriority())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isRecordable()
+ {
+ for(Alias alias: mPatchedAliases)
+ {
+ if(alias.isRecordable())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isStreamable()
+ {
+ for(Alias alias: mPatchedAliases)
+ {
+ if(alias.isStreamable())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public List getBroadcastChannels()
+ {
+ List broadcastChannels = new ArrayList<>();
+
+ for(Alias alias: mPatchedAliases)
+ {
+ for(BroadcastChannel broadcastChannel: alias.getBroadcastChannels())
+ {
+ if(!broadcastChannels.contains(broadcastChannel))
+ {
+ broadcastChannels.add(broadcastChannel);
+ }
+ }
+ }
+
+ return broadcastChannels;
+ }
+
+ @Override
+ public boolean hasBroadcastChannel(String channel)
+ {
+ for(Alias alias: mPatchedAliases)
+ {
+ if(alias.hasBroadcastChannel(channel))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/alias/id/talkgroup/TalkgroupID.java b/src/alias/id/talkgroup/TalkgroupID.java
index fe7b3ec3..cb2e8097 100644
--- a/src/alias/id/talkgroup/TalkgroupID.java
+++ b/src/alias/id/talkgroup/TalkgroupID.java
@@ -1,83 +1,89 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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
******************************************************************************/
package alias.id.talkgroup;
-import javax.xml.bind.annotation.XmlAttribute;
-
import alias.id.AliasID;
import alias.id.AliasIDType;
+import javax.xml.bind.annotation.XmlAttribute;
+
public class TalkgroupID extends AliasID
{
- private String mTalkgroup;
-
- public TalkgroupID()
- {
- }
+ private String mTalkgroup;
- @XmlAttribute
- public String getTalkgroup()
- {
- return mTalkgroup;
- }
-
- public void setTalkgroup( String talkgroup )
- {
- mTalkgroup = talkgroup;
- }
-
- @Override
- public boolean isValid()
- {
- return mTalkgroup != null;
- }
-
- public String toString()
- {
- StringBuilder sb = new StringBuilder();
-
- sb.append( "Talkgroup: " + mTalkgroup );
-
- return sb.toString();
- }
-
- @Override
- public boolean matches( AliasID id )
+ public TalkgroupID()
{
- boolean retVal = false;
-
- if( id instanceof TalkgroupID )
- {
- TalkgroupID tgid = (TalkgroupID)id;
-
- //Create a pattern - replace * wildcards with regex single-char wildcard
- String pattern = mTalkgroup.replace( "*", ".?" );
-
- retVal = tgid.getTalkgroup().matches( pattern );
- }
-
- return retVal;
+ //No arg JAXB constructor
}
- @Override
+ public TalkgroupID(String talkgroup)
+ {
+ mTalkgroup = talkgroup;
+ }
+
+ @XmlAttribute
+ public String getTalkgroup()
+ {
+ return mTalkgroup;
+ }
+
+ public void setTalkgroup(String talkgroup)
+ {
+ mTalkgroup = talkgroup;
+ }
+
+ @Override
+ public boolean isValid()
+ {
+ return mTalkgroup != null;
+ }
+
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Talkgroup: " + mTalkgroup);
+
+ return sb.toString();
+ }
+
+ @Override
+ public boolean matches(AliasID id)
+ {
+ boolean retVal = false;
+
+ if(id instanceof TalkgroupID)
+ {
+ TalkgroupID tgid = (TalkgroupID) id;
+
+ //Create a pattern - replace * wildcards with regex single-char wildcard
+ String pattern = mTalkgroup.replace("*", ".?");
+
+ retVal = tgid.getTalkgroup().matches(pattern);
+ }
+
+ return retVal;
+ }
+
+ @Override
public AliasIDType getType()
{
- return AliasIDType.TALKGROUP;
+ return AliasIDType.TALKGROUP;
}
}
diff --git a/src/module/decode/p25/P25DecoderState.java b/src/module/decode/p25/P25DecoderState.java
index b73bef11..c597f598 100644
--- a/src/module/decode/p25/P25DecoderState.java
+++ b/src/module/decode/p25/P25DecoderState.java
@@ -1,17 +1,17 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 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
******************************************************************************/
@@ -19,6 +19,8 @@ package module.decode.p25;
import alias.Alias;
import alias.AliasList;
+import alias.PatchGroupAlias;
+import alias.id.talkgroup.TalkgroupID;
import audio.metadata.Metadata;
import audio.metadata.MetadataType;
import controller.channel.Channel.ChannelType;
@@ -143,812 +145,813 @@ import java.util.concurrent.ScheduledExecutorService;
public class P25DecoderState extends DecoderState
{
- private final static Logger mLog = LoggerFactory.getLogger( P25DecoderState.class );
- private static final DecimalFormat mFrequencyFormatter =
- new DecimalFormat( "0.000000" );
+ private final static Logger mLog = LoggerFactory.getLogger(P25DecoderState.class);
+ private static final DecimalFormat mFrequencyFormatter =
+ new DecimalFormat("0.000000");
- private module.decode.p25.message.tsbk.osp.control.NetworkStatusBroadcast mNetworkStatus;
- private NetworkStatusBroadcastExtended mNetworkStatusExtended;
- private ProtectionParameterBroadcast mProtectionParameterBroadcast;
- private RFSSStatusBroadcast mRFSSStatusMessage;
- private RFSSStatusBroadcastExtended mRFSSStatusMessageExtended;
- private SNDCPDataChannelAnnouncementExplicit mSNDCPDataChannel;
+ private module.decode.p25.message.tsbk.osp.control.NetworkStatusBroadcast mNetworkStatus;
+ private NetworkStatusBroadcastExtended mNetworkStatusExtended;
+ private ProtectionParameterBroadcast mProtectionParameterBroadcast;
+ private RFSSStatusBroadcast mRFSSStatusMessage;
+ private RFSSStatusBroadcastExtended mRFSSStatusMessageExtended;
+ private SNDCPDataChannelAnnouncementExplicit mSNDCPDataChannel;
- private Set mSecondaryControlChannels =
- new TreeSet<>();
-
- private Map mBands = new HashMap<>();
- private Map mRegistrations = new HashMap<>();
- private Map mNeighborMap = new HashMap<>();
+ private Set mSecondaryControlChannels =
+ new TreeSet<>();
- private String mLastCommandEventID;
- private String mLastPageEventID;
- private String mLastQueryEventID;
- private String mLastRegistrationEventID;
- private String mLastResponseEventID;
+ private Map mBands = new HashMap<>();
+ private Map mRegistrations = new HashMap<>();
+ private Map mNeighborMap = new HashMap<>();
+ private Map> mPatchGroupMap = new HashMap<>();
- private String mNAC;
- private String mSystem;
- private String mSite;
- private String mSiteAlias;
- private String mFromTalkgroup;
- private Alias mFromAlias;
- private String mToTalkgroup;
- private Alias mToAlias;
- private String mCurrentChannel = "CURRENT";
- private long mCurrentChannelFrequency = 0;
+ private String mLastCommandEventID;
+ private String mLastPageEventID;
+ private String mLastQueryEventID;
+ private String mLastRegistrationEventID;
+ private String mLastResponseEventID;
- private ChannelType mChannelType;
- private Modulation mModulation;
- private boolean mIgnoreDataCalls;
- private boolean mControlChannelShutdownLogged;
+ private String mNAC;
+ private String mSystem;
+ private String mSite;
+ private String mSiteAlias;
+ private String mFromTalkgroup;
+ private Alias mFromAlias;
+ private String mToTalkgroup;
+ private Alias mToAlias;
+ private String mCurrentChannel = "CURRENT";
+ private long mCurrentChannelFrequency = 0;
- private P25CallEvent mCurrentCallEvent;
- private List mCallDetectTalkgroups = new ArrayList<>();
- private Map mChannelCallMap = new HashMap<>();
-
- public P25DecoderState( AliasList aliasList,
- ChannelType channelType,
- Modulation modulation,
- boolean ignoreDataCalls )
- {
- super( aliasList );
- mChannelType = channelType;
- mModulation = modulation;
- mIgnoreDataCalls = ignoreDataCalls;
- }
-
- public Modulation getModulation()
- {
- return mModulation;
- }
-
- @Override
- public DecoderType getDecoderType()
- {
- return DecoderType.P25_PHASE1;
- }
+ private ChannelType mChannelType;
+ private Modulation mModulation;
+ private boolean mIgnoreDataCalls;
+ private boolean mControlChannelShutdownLogged;
- @Override
- public void stop()
- {
- }
+ private P25CallEvent mCurrentCallEvent;
+ private List mCallDetectTalkgroups = new ArrayList<>();
+ private Map mChannelCallMap = new HashMap<>();
- /**
- * Performs a full reset to prepare this object for reuse on a new channel
- */
- @Override
- public void reset()
- {
- resetState();
-
- updateNAC( null );
- updateSite( null );
- updateSystem( null );
- }
+ public P25DecoderState(AliasList aliasList,
+ ChannelType channelType,
+ Modulation modulation,
+ boolean ignoreDataCalls)
+ {
+ super(aliasList);
+ mChannelType = channelType;
+ mModulation = modulation;
+ mIgnoreDataCalls = ignoreDataCalls;
+ }
- /**
- * Resets any temporal state details
- */
- private void resetState()
- {
- mFromTalkgroup = null;
- broadcast( ChangedAttribute.FROM_TALKGROUP );
-
- mFromAlias = null;
- broadcast( ChangedAttribute.FROM_TALKGROUP_ALIAS );
-
- mToTalkgroup = null;
- broadcast( ChangedAttribute.TO_TALKGROUP );
-
- mToAlias = null;
- broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
+ public Modulation getModulation()
+ {
+ return mModulation;
+ }
- mCallDetectTalkgroups.clear();
-
- if( mCurrentCallEvent != null )
- {
- mCurrentCallEvent.end();
- }
-
- mCurrentCallEvent = null;
- }
+ @Override
+ public DecoderType getDecoderType()
+ {
+ return DecoderType.P25_PHASE1;
+ }
- /**
- * Performs any initialization operations to prepare for use
- */
- @Override
- public void init()
- {
- }
+ @Override
+ public void stop()
+ {
+ }
- /**
- * Indicates if there a call event exists for the specified channel and
- * from and to talkgroup identifiers.
- *
- * @param channel - channel number
- * @param from user id
- * @param to talkgroup or user id
- * @return true if there is a call event
- */
- public boolean hasCallEvent( String channel, String from, String to )
- {
- boolean hasEvent = false;
-
- if( mChannelCallMap.containsKey( channel ) )
- {
- P25CallEvent event = mChannelCallMap.get( channel );
-
- if( to != null &&
- event.getToID() != null &&
- to.contentEquals( event.getToID() ) )
- {
- if( from != null )
- {
- if( event.getFromID() == null )
- {
- hasEvent = true;
- }
- else if( from.contentEquals( event.getFromID() ) )
- {
- hasEvent = true;
- }
- }
- else
- {
- hasEvent = true;
- }
- }
- }
-
- return hasEvent;
- }
+ /**
+ * Performs a full reset to prepare this object for reuse on a new channel
+ */
+ @Override
+ public void reset()
+ {
+ resetState();
- /**
- * Adds the channel and event to the current channel call map. If an entry
- * already exists, terminates the event and broadcasts the update.
- *
- * @param event to place in the map
- */
- public void registerCallEvent( P25CallEvent event )
- {
- if( mChannelCallMap.containsKey( event.getChannel() ) )
- {
- P25CallEvent previousEvent = mChannelCallMap.remove( event.getChannel() );
-
- previousEvent.end();
-
- broadcast( previousEvent );
- }
-
- mChannelCallMap.put( event.getChannel(), event );
- }
-
- private void updateCallEvent( String channel, String from, String to )
- {
- P25CallEvent event = mChannelCallMap.get( channel );
-
- if( event != null &&
- to != null &&
- event.getToID() != null &&
- event.getToID().contentEquals( to ) )
- {
- if( event.getFromID() == null &&
- from != null &&
- !from.contentEquals( "0000" ) &&
- !from.contentEquals( "000000" ) )
- {
- event.setFromID( from );
- broadcast( event );
- }
- }
- }
+ updateNAC(null);
+ updateSite(null);
+ updateSystem(null);
+ }
+
+ /**
+ * Resets any temporal state details
+ */
+ private void resetState()
+ {
+ mFromTalkgroup = null;
+ broadcast(ChangedAttribute.FROM_TALKGROUP);
+
+ mFromAlias = null;
+ broadcast(ChangedAttribute.FROM_TALKGROUP_ALIAS);
+
+ mToTalkgroup = null;
+ broadcast(ChangedAttribute.TO_TALKGROUP);
+
+ mToAlias = null;
+ broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS);
+
+ mCallDetectTalkgroups.clear();
+
+ if(mCurrentCallEvent != null)
+ {
+ mCurrentCallEvent.end();
+ }
+
+ mCurrentCallEvent = null;
+ }
+
+ /**
+ * Performs any initialization operations to prepare for use
+ */
+ @Override
+ public void init()
+ {
+ }
+
+ /**
+ * Indicates if there a call event exists for the specified channel and
+ * from and to talkgroup identifiers.
+ *
+ * @param channel - channel number
+ * @param from user id
+ * @param to talkgroup or user id
+ * @return true if there is a call event
+ */
+ public boolean hasCallEvent(String channel, String from, String to)
+ {
+ boolean hasEvent = false;
+
+ if(mChannelCallMap.containsKey(channel))
+ {
+ P25CallEvent event = mChannelCallMap.get(channel);
+
+ if(to != null &&
+ event.getToID() != null &&
+ to.contentEquals(event.getToID()))
+ {
+ if(from != null)
+ {
+ if(event.getFromID() == null)
+ {
+ hasEvent = true;
+ }
+ else if(from.contentEquals(event.getFromID()))
+ {
+ hasEvent = true;
+ }
+ }
+ else
+ {
+ hasEvent = true;
+ }
+ }
+ }
+
+ return hasEvent;
+ }
+
+ /**
+ * Adds the channel and event to the current channel call map. If an entry
+ * already exists, terminates the event and broadcasts the update.
+ *
+ * @param event to place in the map
+ */
+ public void registerCallEvent(P25CallEvent event)
+ {
+ if(mChannelCallMap.containsKey(event.getChannel()))
+ {
+ P25CallEvent previousEvent = mChannelCallMap.remove(event.getChannel());
+
+ previousEvent.end();
+
+ broadcast(previousEvent);
+ }
+
+ mChannelCallMap.put(event.getChannel(), event);
+ }
+
+ private void updateCallEvent(String channel, String from, String to)
+ {
+ P25CallEvent event = mChannelCallMap.get(channel);
+
+ if(event != null &&
+ to != null &&
+ event.getToID() != null &&
+ event.getToID().contentEquals(to))
+ {
+ if(event.getFromID() == null &&
+ from != null &&
+ !from.contentEquals("0000") &&
+ !from.contentEquals("000000"))
+ {
+ event.setFromID(from);
+ broadcast(event);
+ }
+ }
+ }
+
+ /**
+ * Primary message processing method.
+ */
+ public void receive(Message message)
+ {
+ if(message instanceof P25Message)
+ {
+ updateNAC(((P25Message) message).getNAC());
- /**
- * Primary message processing method.
- */
- public void receive( Message message )
- {
- if( message instanceof P25Message )
- {
- updateNAC( ( (P25Message)message ).getNAC() );
-
/* Voice Vocoder messages */
- if( message instanceof LDUMessage )
- {
- processLDU( (LDUMessage)message );
- }
+ if(message instanceof LDUMessage)
+ {
+ processLDU((LDUMessage) message);
+ }
/* Trunking Signalling Messages */
- else if( message instanceof TSBKMessage )
- {
- processTSBK( (TSBKMessage)message );
- }
+ else if(message instanceof TSBKMessage)
+ {
+ processTSBK((TSBKMessage) message);
+ }
/* Terminator Data Unit with Link Control Message */
- else if( message instanceof TDULinkControlMessage )
- {
- processTDULC( (TDULinkControlMessage)message );
- }
+ else if(message instanceof TDULinkControlMessage)
+ {
+ processTDULC((TDULinkControlMessage) message);
+ }
/* Packet Data Unit Messages */
- else if( message instanceof PDUMessage )
- {
- processPDU( (PDUMessage)message );
- }
+ else if(message instanceof PDUMessage)
+ {
+ processPDU((PDUMessage) message);
+ }
/* Header Data Unit Message - preceeds voice LDUs */
- else if( message instanceof HDUMessage )
- {
- processHDU( (HDUMessage)message );
- }
+ else if(message instanceof HDUMessage)
+ {
+ processHDU((HDUMessage) message);
+ }
/* Terminator Data Unit, or default message if CRC failed */
- else if( message instanceof TDUMessage )
- {
- processTDU( (TDUMessage)message );
- }
- }
- }
+ else if(message instanceof TDUMessage)
+ {
+ processTDU((TDUMessage) message);
+ }
+ }
+ }
- /**
- * Terminator Data Unit
- */
- private void processTDU( TDUMessage tdu )
- {
- }
+ /**
+ * Terminator Data Unit
+ */
+ private void processTDU(TDUMessage tdu)
+ {
+ }
- /**
- * Header Data Unit - first message in a call sequence.
- */
- private void processHDU( HDUMessage hdu )
- {
- if( hdu.isValid() )
- {
- broadcast( new DecoderStateEvent( this, Event.START, State.CALL ) );
+ /**
+ * Header Data Unit - first message in a call sequence.
+ */
+ private void processHDU(HDUMessage hdu)
+ {
+ if(hdu.isValid())
+ {
+ broadcast(new DecoderStateEvent(this, Event.START, State.CALL));
- String to = hdu.getToID();
-
- updateTo( to );
-
- if( mCurrentCallEvent == null )
- {
- mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.CALL )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( ( hdu.isEncrypted() ? "ENCRYPTED " : "" ) )
- .frequency( mCurrentChannelFrequency )
- .to( to )
- .build();
-
- broadcast( mCurrentCallEvent );
- }
-
- }
- }
+ String to = hdu.getToID();
- /**
- * Terminator Data Unit with Link Control - transmitted multiple times at
- * beginning or end of call sequence and includes embedded link control messages
- */
- private void processTDULC( TDULinkControlMessage tdulc )
- {
- if( tdulc.getOpcode() == LinkControlOpcode.CALL_TERMINATION_OR_CANCELLATION )
- {
- broadcast( new DecoderStateEvent( this, Event.END, State.FADE ) );
-
- if( mCurrentCallEvent != null )
- {
- mCurrentCallEvent.end();
- mCurrentCallEvent = null;
- }
- }
- else
- {
- broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CALL ) );
- }
-
- switch( tdulc.getOpcode() )
- {
- case ADJACENT_SITE_STATUS_BROADCAST:
- if( tdulc instanceof AdjacentSiteStatusBroadcast )
- {
- IAdjacentSite ias = (IAdjacentSite)tdulc;
-
- mNeighborMap.put( ias.getUniqueID(), ias );
-
- updateSystem( ias.getSystemID() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT:
- if( tdulc instanceof AdjacentSiteStatusBroadcastExplicit )
- {
- IAdjacentSite ias = (IAdjacentSite)tdulc;
-
- mNeighborMap.put( ias.getUniqueID(), ias );
-
- updateSystem( ias.getSystemID() );
- }
- break;
- case CALL_ALERT:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.CallAlert )
- {
- module.decode.p25.message.tdu.lc.CallAlert ca =
- (module.decode.p25.message.tdu.lc.CallAlert)tdulc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( ca.getSourceAddress() )
- .to( ca.getTargetAddress() )
- .details( "CALL ALERT" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case CALL_TERMINATION_OR_CANCELLATION:
+ updateTo(to);
+
+ if(mCurrentCallEvent == null)
+ {
+ mCurrentCallEvent = new P25CallEvent.Builder(CallEventType.CALL)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details((hdu.isEncrypted() ? "ENCRYPTED " : ""))
+ .frequency(mCurrentChannelFrequency)
+ .to(to)
+ .build();
+
+ broadcast(mCurrentCallEvent);
+ }
+
+ }
+ }
+
+ /**
+ * Terminator Data Unit with Link Control - transmitted multiple times at
+ * beginning or end of call sequence and includes embedded link control messages
+ */
+ private void processTDULC(TDULinkControlMessage tdulc)
+ {
+ if(tdulc.getOpcode() == LinkControlOpcode.CALL_TERMINATION_OR_CANCELLATION)
+ {
+ broadcast(new DecoderStateEvent(this, Event.END, State.FADE));
+
+ if(mCurrentCallEvent != null)
+ {
+ mCurrentCallEvent.end();
+ mCurrentCallEvent = null;
+ }
+ }
+ else
+ {
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL));
+ }
+
+ switch(tdulc.getOpcode())
+ {
+ case ADJACENT_SITE_STATUS_BROADCAST:
+ if(tdulc instanceof AdjacentSiteStatusBroadcast)
+ {
+ IAdjacentSite ias = (IAdjacentSite) tdulc;
+
+ mNeighborMap.put(ias.getUniqueID(), ias);
+
+ updateSystem(ias.getSystemID());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT:
+ if(tdulc instanceof AdjacentSiteStatusBroadcastExplicit)
+ {
+ IAdjacentSite ias = (IAdjacentSite) tdulc;
+
+ mNeighborMap.put(ias.getUniqueID(), ias);
+
+ updateSystem(ias.getSystemID());
+ }
+ break;
+ case CALL_ALERT:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.CallAlert)
+ {
+ module.decode.p25.message.tdu.lc.CallAlert ca =
+ (module.decode.p25.message.tdu.lc.CallAlert) tdulc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(ca.getSourceAddress())
+ .to(ca.getTargetAddress())
+ .details("CALL ALERT")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case CALL_TERMINATION_OR_CANCELLATION:
/* This opcode as handled at the beginning of the method */
- break;
- case CHANNEL_IDENTIFIER_UPDATE:
- //TODO: does the activity summary need this message?
+ break;
+ 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 */
- break;
- case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
- //TODO: does the activity summary need this message?
+ break;
+ 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 */
- break;
- case EXTENDED_FUNCTION_COMMAND:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.ExtendedFunctionCommand )
- {
- module.decode.p25.message.tdu.lc.ExtendedFunctionCommand efc =
- (module.decode.p25.message.tdu.lc.ExtendedFunctionCommand)tdulc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( efc.getTargetAddress() )
- .details( "FUNCTION:" + efc.getExtendedFunction().getLabel() +
- " ARG:" + efc.getArgument() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case GROUP_AFFILIATION_QUERY:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.GroupAffiliationQuery )
- {
- module.decode.p25.message.tdu.lc.GroupAffiliationQuery gaq =
- (module.decode.p25.message.tdu.lc.GroupAffiliationQuery)tdulc;
+ break;
+ case EXTENDED_FUNCTION_COMMAND:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.ExtendedFunctionCommand)
+ {
+ module.decode.p25.message.tdu.lc.ExtendedFunctionCommand efc =
+ (module.decode.p25.message.tdu.lc.ExtendedFunctionCommand) tdulc;
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "GROUP AFFILIATION QUERY" )
- .from( gaq.getSourceAddress() )
- .to( gaq.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case GROUP_VOICE_CHANNEL_UPDATE:
- /* Used only on trunked systems on the outbound channel, to
- * reflect user activity on other channels. We process this
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(efc.getTargetAddress())
+ .details("FUNCTION:" + efc.getExtendedFunction().getLabel() +
+ " ARG:" + efc.getArgument())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case GROUP_AFFILIATION_QUERY:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.GroupAffiliationQuery)
+ {
+ module.decode.p25.message.tdu.lc.GroupAffiliationQuery gaq =
+ (module.decode.p25.message.tdu.lc.GroupAffiliationQuery) tdulc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("GROUP AFFILIATION QUERY")
+ .from(gaq.getSourceAddress())
+ .to(gaq.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_UPDATE:
+ /* Used only on trunked systems on the outbound channel, to
+ * reflect user activity on other channels. We process this
* as a call detect */
- if( tdulc instanceof GroupVoiceChannelUpdate )
- {
- GroupVoiceChannelUpdate gvcu = (GroupVoiceChannelUpdate)tdulc;
+ if(tdulc instanceof GroupVoiceChannelUpdate)
+ {
+ GroupVoiceChannelUpdate gvcu = (GroupVoiceChannelUpdate) tdulc;
- String groupA = gvcu.getGroupAddressA();
+ String groupA = gvcu.getGroupAddressA();
- if( !mCallDetectTalkgroups.contains( groupA ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
- .aliasList( getAliasList() )
- .channel( gvcu.getChannelA() )
- .details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
- .frequency( gvcu.getDownlinkFrequencyA() )
- .to( groupA )
- .build() );
-
- mCallDetectTalkgroups.add( groupA );
- }
-
- String groupB = gvcu.getGroupAddressB();
+ if(!mCallDetectTalkgroups.contains(groupA))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
+ .aliasList(getAliasList())
+ .channel(gvcu.getChannelA())
+ .details((gvcu.isEncrypted() ? "ENCRYPTED" : ""))
+ .frequency(gvcu.getDownlinkFrequencyA())
+ .to(groupA)
+ .build());
- if( !mCallDetectTalkgroups.contains( groupB ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
- .aliasList( getAliasList() )
- .channel( gvcu.getChannelB() )
- .details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
- .frequency( gvcu.getDownlinkFrequencyB() )
- .to( groupB )
- .build() );
-
- mCallDetectTalkgroups.add( groupB );
- }
- }
- break;
- case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
+ mCallDetectTalkgroups.add(groupA);
+ }
+
+ String groupB = gvcu.getGroupAddressB();
+
+ if(!mCallDetectTalkgroups.contains(groupB))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
+ .aliasList(getAliasList())
+ .channel(gvcu.getChannelB())
+ .details((gvcu.isEncrypted() ? "ENCRYPTED" : ""))
+ .frequency(gvcu.getDownlinkFrequencyB())
+ .to(groupB)
+ .build());
+
+ mCallDetectTalkgroups.add(groupB);
+ }
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
/* Reflects other call activity on the system: CALL DETECT */
- if( mChannelType == ChannelType.STANDARD &&
- tdulc instanceof GroupVoiceChannelUpdateExplicit )
- {
- GroupVoiceChannelUpdateExplicit gvcue =
- (GroupVoiceChannelUpdateExplicit)tdulc;
-
- String group = gvcue.getGroupAddress();
-
- if( !mCallDetectTalkgroups.contains( group ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
- .aliasList( getAliasList() )
- .channel( gvcue.getTransmitChannel() )
- .details( ( gvcue.isEncrypted() ? "ENCRYPTED" : "" ) )
- .frequency( gvcue.getDownlinkFrequency() )
- .to( group )
- .build() );
-
- mCallDetectTalkgroups.add( group );
- }
- }
- break;
- case GROUP_VOICE_CHANNEL_USER:
+ if(mChannelType == ChannelType.STANDARD &&
+ tdulc instanceof GroupVoiceChannelUpdateExplicit)
+ {
+ GroupVoiceChannelUpdateExplicit gvcue =
+ (GroupVoiceChannelUpdateExplicit) tdulc;
+
+ String group = gvcue.getGroupAddress();
+
+ if(!mCallDetectTalkgroups.contains(group))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
+ .aliasList(getAliasList())
+ .channel(gvcue.getTransmitChannel())
+ .details((gvcue.isEncrypted() ? "ENCRYPTED" : ""))
+ .frequency(gvcue.getDownlinkFrequency())
+ .to(group)
+ .build());
+
+ mCallDetectTalkgroups.add(group);
+ }
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_USER:
/* Used on a traffic channel to reflect current call entities */
- if( tdulc instanceof module.decode.p25.message.tdu.lc.GroupVoiceChannelUser )
- {
- module.decode.p25.message.tdu.lc.GroupVoiceChannelUser gvcuser =
- (module.decode.p25.message.tdu.lc.GroupVoiceChannelUser)tdulc;
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.GroupVoiceChannelUser)
+ {
+ module.decode.p25.message.tdu.lc.GroupVoiceChannelUser gvcuser =
+ (module.decode.p25.message.tdu.lc.GroupVoiceChannelUser) tdulc;
- broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CALL ) );
-
- String from = gvcuser.getSourceAddress();
- String to = gvcuser.getGroupAddress();
-
- updateFrom( from );
- updateTo( to );
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL));
- if( mCurrentCallEvent == null )
- {
- mCurrentCallEvent = new P25CallEvent.Builder( 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;
- case MESSAGE_UPDATE:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.MessageUpdate )
- {
- module.decode.p25.message.tdu.lc.MessageUpdate mu =
- (module.decode.p25.message.tdu.lc.MessageUpdate)tdulc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.SDM )
- .aliasList( getAliasList() )
- .from( mu.getSourceAddress() )
- .to( mu.getTargetAddress() )
- .details( "MSG: " + mu.getShortDataMessage() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case NETWORK_STATUS_BROADCAST:
- if( tdulc instanceof NetworkStatusBroadcast )
- {
- updateSystem( ((NetworkStatusBroadcast)tdulc).getSystem() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case NETWORK_STATUS_BROADCAST_EXPLICIT:
- if( tdulc instanceof NetworkStatusBroadcastExplicit )
- {
- updateSystem( ((NetworkStatusBroadcastExplicit)tdulc).getSystem() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case PROTECTION_PARAMETER_BROADCAST:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.ProtectionParameterBroadcast )
- {
- module.decode.p25.message.tdu.lc.ProtectionParameterBroadcast ppb =
- (module.decode.p25.message.tdu.lc.ProtectionParameterBroadcast)tdulc;
+ String from = gvcuser.getSourceAddress();
+ String to = gvcuser.getGroupAddress();
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( ppb.getTargetAddress() )
- .details( "ENCRYPTION: " +
- ppb.getEncryption().name() + " KEY:" +
- ppb.getEncryptionKey() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case RFSS_STATUS_BROADCAST:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.RFSSStatusBroadcast )
- {
- module.decode.p25.message.tdu.lc.RFSSStatusBroadcast rfsssb =
- (module.decode.p25.message.tdu.lc.RFSSStatusBroadcast)tdulc;
-
- updateSystem( rfsssb.getSystem() );
+ updateFrom(from);
+ updateTo(to);
- String site = rfsssb.getRFSubsystemID() + "-" +
- rfsssb.getSiteID();
+ if(mCurrentCallEvent == null)
+ {
+ mCurrentCallEvent = new P25CallEvent.Builder(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();
- updateSite( site );
-
- if( mCurrentChannel == null ||
- !mCurrentChannel.contentEquals( rfsssb.getChannel() ) )
- {
- mCurrentChannel = rfsssb.getChannel();
- mCurrentChannelFrequency = rfsssb.getDownlinkFrequency();
- }
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case RFSS_STATUS_BROADCAST_EXPLICIT:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.RFSSStatusBroadcastExplicit )
- {
- module.decode.p25.message.tdu.lc.RFSSStatusBroadcastExplicit rfsssbe =
- (module.decode.p25.message.tdu.lc.RFSSStatusBroadcastExplicit)tdulc;
-
- String site = rfsssbe.getRFSubsystemID() + "-" +
- rfsssbe.getSiteID();
+ broadcast(mCurrentCallEvent);
+ }
+ }
+ break;
+ case MESSAGE_UPDATE:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.MessageUpdate)
+ {
+ module.decode.p25.message.tdu.lc.MessageUpdate mu =
+ (module.decode.p25.message.tdu.lc.MessageUpdate) tdulc;
- updateSite( site );
-
- if( mCurrentChannel == null ||
- !mCurrentChannel.contentEquals( rfsssbe.getTransmitChannel() ) )
- {
- mCurrentChannel = rfsssbe.getTransmitChannel();
- mCurrentChannelFrequency = rfsssbe.getDownlinkFrequency();
- }
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case SECONDARY_CONTROL_CHANNEL_BROADCAST:
- if( tdulc instanceof SecondaryControlChannelBroadcast )
- {
- SecondaryControlChannelBroadcast sccb =
- (SecondaryControlChannelBroadcast)tdulc;
-
- String site = sccb.getRFSubsystemID() + "-" +
- sccb.getSiteID();
+ broadcast(new P25CallEvent.Builder(CallEventType.SDM)
+ .aliasList(getAliasList())
+ .from(mu.getSourceAddress())
+ .to(mu.getTargetAddress())
+ .details("MSG: " + mu.getShortDataMessage())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case NETWORK_STATUS_BROADCAST:
+ if(tdulc instanceof NetworkStatusBroadcast)
+ {
+ updateSystem(((NetworkStatusBroadcast) tdulc).getSystem());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case NETWORK_STATUS_BROADCAST_EXPLICIT:
+ if(tdulc instanceof NetworkStatusBroadcastExplicit)
+ {
+ updateSystem(((NetworkStatusBroadcastExplicit) tdulc).getSystem());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case PROTECTION_PARAMETER_BROADCAST:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.ProtectionParameterBroadcast)
+ {
+ module.decode.p25.message.tdu.lc.ProtectionParameterBroadcast ppb =
+ (module.decode.p25.message.tdu.lc.ProtectionParameterBroadcast) tdulc;
- updateSite( site );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
- if( tdulc instanceof SecondaryControlChannelBroadcastExplicit )
- {
- SecondaryControlChannelBroadcastExplicit sccb =
- (SecondaryControlChannelBroadcastExplicit)tdulc;
-
- String site = sccb.getRFSubsystemID() + "-" +
- sccb.getSiteID();
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(ppb.getTargetAddress())
+ .details("ENCRYPTION: " +
+ ppb.getEncryption().name() + " KEY:" +
+ ppb.getEncryptionKey())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case RFSS_STATUS_BROADCAST:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.RFSSStatusBroadcast)
+ {
+ module.decode.p25.message.tdu.lc.RFSSStatusBroadcast rfsssb =
+ (module.decode.p25.message.tdu.lc.RFSSStatusBroadcast) tdulc;
- updateSite( site );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case STATUS_QUERY:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.StatusQuery )
- {
- module.decode.p25.message.tdu.lc.StatusQuery sq =
- (module.decode.p25.message.tdu.lc.StatusQuery)tdulc;
+ updateSystem(rfsssb.getSystem());
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "STATUS QUERY" )
- .from( sq.getSourceAddress() )
- .to( sq.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case STATUS_UPDATE:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.StatusUpdate )
- {
- module.decode.p25.message.tdu.lc.StatusUpdate su =
- (module.decode.p25.message.tdu.lc.StatusUpdate)tdulc;
+ String site = rfsssb.getRFSubsystemID() + "-" +
+ rfsssb.getSiteID();
- broadcast( new P25CallEvent.Builder( CallEventType.STATUS )
- .aliasList( getAliasList() )
- .details( "STATUS UNIT:" + su.getUnitStatus() +
- " USER:" + su.getUserStatus() )
- .from( su.getSourceAddress() )
- .to( su.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case SYSTEM_SERVICE_BROADCAST:
+ updateSite(site);
+
+ if(mCurrentChannel == null ||
+ !mCurrentChannel.contentEquals(rfsssb.getChannel()))
+ {
+ mCurrentChannel = rfsssb.getChannel();
+ mCurrentChannelFrequency = rfsssb.getDownlinkFrequency();
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case RFSS_STATUS_BROADCAST_EXPLICIT:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.RFSSStatusBroadcastExplicit)
+ {
+ module.decode.p25.message.tdu.lc.RFSSStatusBroadcastExplicit rfsssbe =
+ (module.decode.p25.message.tdu.lc.RFSSStatusBroadcastExplicit) tdulc;
+
+ String site = rfsssbe.getRFSubsystemID() + "-" +
+ rfsssbe.getSiteID();
+
+ updateSite(site);
+
+ if(mCurrentChannel == null ||
+ !mCurrentChannel.contentEquals(rfsssbe.getTransmitChannel()))
+ {
+ mCurrentChannel = rfsssbe.getTransmitChannel();
+ mCurrentChannelFrequency = rfsssbe.getDownlinkFrequency();
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case SECONDARY_CONTROL_CHANNEL_BROADCAST:
+ if(tdulc instanceof SecondaryControlChannelBroadcast)
+ {
+ SecondaryControlChannelBroadcast sccb =
+ (SecondaryControlChannelBroadcast) tdulc;
+
+ String site = sccb.getRFSubsystemID() + "-" +
+ sccb.getSiteID();
+
+ updateSite(site);
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
+ if(tdulc instanceof SecondaryControlChannelBroadcastExplicit)
+ {
+ SecondaryControlChannelBroadcastExplicit sccb =
+ (SecondaryControlChannelBroadcastExplicit) tdulc;
+
+ String site = sccb.getRFSubsystemID() + "-" +
+ sccb.getSiteID();
+
+ updateSite(site);
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case STATUS_QUERY:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.StatusQuery)
+ {
+ module.decode.p25.message.tdu.lc.StatusQuery sq =
+ (module.decode.p25.message.tdu.lc.StatusQuery) tdulc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("STATUS QUERY")
+ .from(sq.getSourceAddress())
+ .to(sq.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case STATUS_UPDATE:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.StatusUpdate)
+ {
+ module.decode.p25.message.tdu.lc.StatusUpdate su =
+ (module.decode.p25.message.tdu.lc.StatusUpdate) tdulc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.STATUS)
+ .aliasList(getAliasList())
+ .details("STATUS UNIT:" + su.getUnitStatus() +
+ " USER:" + su.getUserStatus())
+ .from(su.getSourceAddress())
+ .to(su.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case SYSTEM_SERVICE_BROADCAST:
/* This message doesn't provide anything we need for channel state */
- break;
- case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.TelephoneInterconnectAnswerRequest )
- {
- module.decode.p25.message.tdu.lc.TelephoneInterconnectAnswerRequest tiar =
- (module.decode.p25.message.tdu.lc.TelephoneInterconnectAnswerRequest)tdulc;
+ break;
+ case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.TelephoneInterconnectAnswerRequest)
+ {
+ module.decode.p25.message.tdu.lc.TelephoneInterconnectAnswerRequest tiar =
+ (module.decode.p25.message.tdu.lc.TelephoneInterconnectAnswerRequest) tdulc;
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( tiar.getTelephoneNumber() )
- .to( tiar.getTargetAddress() )
- .details( "TELEPHONE CALL ALERT" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
- if( mChannelType == ChannelType.STANDARD &&
- tdulc instanceof module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser )
- {
- module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser tivcu =
- (module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser)tdulc;
-
- String to = tivcu.getAddress();
-
- updateTo( to );
-
- if( mCurrentCallEvent == null )
- {
- mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.TELEPHONE_INTERCONNECT )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( ( tivcu.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( tivcu.isEmergency() ? " EMERGENCY" : "") )
- .frequency( mCurrentChannelFrequency )
- .to( to )
- .build();
-
- broadcast( mCurrentCallEvent );
- }
- }
- break;
- case UNIT_AUTHENTICATION_COMMAND:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.UnitAuthenticationCommand )
- {
- module.decode.p25.message.tdu.lc.UnitAuthenticationCommand uac =
- (module.decode.p25.message.tdu.lc.UnitAuthenticationCommand)tdulc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( uac.getCompleteTargetAddress() )
- .details( "AUTHENTICATE" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case UNIT_REGISTRATION_COMMAND:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.UnitRegistrationCommand )
- {
- module.decode.p25.message.tdu.lc.UnitRegistrationCommand urc =
- (module.decode.p25.message.tdu.lc.UnitRegistrationCommand)tdulc;
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(tiar.getTelephoneNumber())
+ .to(tiar.getTargetAddress())
+ .details("TELEPHONE CALL ALERT")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
+ if(mChannelType == ChannelType.STANDARD &&
+ tdulc instanceof module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser)
+ {
+ module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser tivcu =
+ (module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser) tdulc;
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( urc.getCompleteTargetAddress() )
- .details( "REGISTER" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case UNIT_TO_UNIT_ANSWER_REQUEST:
- if( tdulc instanceof module.decode.p25.message.tdu.lc.UnitToUnitAnswerRequest )
- {
- module.decode.p25.message.tdu.lc.UnitToUnitAnswerRequest uuar =
- (module.decode.p25.message.tdu.lc.UnitToUnitAnswerRequest)tdulc;
+ String to = tivcu.getAddress();
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( uuar.getSourceAddress() )
- .to( uuar.getTargetAddress() )
- .details( "UNIT TO UNIT CALL ALERT" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( tdulc );
- }
- break;
- case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
+ updateTo(to);
+
+ if(mCurrentCallEvent == null)
+ {
+ mCurrentCallEvent = new P25CallEvent.Builder(CallEventType.TELEPHONE_INTERCONNECT)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details((tivcu.isEncrypted() ? "ENCRYPTED" : "") +
+ (tivcu.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(mCurrentChannelFrequency)
+ .to(to)
+ .build();
+
+ broadcast(mCurrentCallEvent);
+ }
+ }
+ break;
+ case UNIT_AUTHENTICATION_COMMAND:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.UnitAuthenticationCommand)
+ {
+ module.decode.p25.message.tdu.lc.UnitAuthenticationCommand uac =
+ (module.decode.p25.message.tdu.lc.UnitAuthenticationCommand) tdulc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(uac.getCompleteTargetAddress())
+ .details("AUTHENTICATE")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case UNIT_REGISTRATION_COMMAND:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.UnitRegistrationCommand)
+ {
+ module.decode.p25.message.tdu.lc.UnitRegistrationCommand urc =
+ (module.decode.p25.message.tdu.lc.UnitRegistrationCommand) tdulc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(urc.getCompleteTargetAddress())
+ .details("REGISTER")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case UNIT_TO_UNIT_ANSWER_REQUEST:
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.UnitToUnitAnswerRequest)
+ {
+ module.decode.p25.message.tdu.lc.UnitToUnitAnswerRequest uuar =
+ (module.decode.p25.message.tdu.lc.UnitToUnitAnswerRequest) tdulc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(uuar.getSourceAddress())
+ .to(uuar.getTargetAddress())
+ .details("UNIT TO UNIT CALL ALERT")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(tdulc);
+ }
+ break;
+ case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
/* Used on traffic channels to indicate the current call entities */
- if( tdulc instanceof module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser )
- {
- module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser uuvcu =
- (module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser)tdulc;
+ if(tdulc instanceof module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser)
+ {
+ module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser uuvcu =
+ (module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser) tdulc;
- String from = uuvcu.getSourceAddress();
- updateFrom( from );
+ String from = uuvcu.getSourceAddress();
+ updateFrom(from);
- String to = uuvcu.getTargetAddress();
- updateTo( to );
-
- if( mCurrentCallEvent != null )
- {
- mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( ( uuvcu.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( uuvcu.isEmergency() ? "EMERGENCY " : "" ) )
- .frequency( mCurrentChannelFrequency )
- .from( from )
- .to( to )
- .build();
- }
- }
- break;
- default:
- break;
- }
- }
-
- /**
- * Log optional vendor format messages that we don't yet support so that we
- * can understand those messages and eventually add support.
- */
- private void logAlternateVendorMessage( P25Message message )
- {
+ String to = uuvcu.getTargetAddress();
+ updateTo(to);
+
+ if(mCurrentCallEvent != null)
+ {
+ mCurrentCallEvent = new P25CallEvent.Builder(CallEventType.UNIT_TO_UNIT_CALL)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details((uuvcu.isEncrypted() ? "ENCRYPTED " : "") +
+ (uuvcu.isEmergency() ? "EMERGENCY " : ""))
+ .frequency(mCurrentChannelFrequency)
+ .from(from)
+ .to(to)
+ .build();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Log optional vendor format messages that we don't yet support so that we
+ * can understand those messages and eventually add support.
+ */
+ private void logAlternateVendorMessage(P25Message message)
+ {
// if( message.isValid() )
// {
// mLog.info( "PLEASE NOTIFY DEVELOPER - UNRECOGNIZED P25 VENDOR FORMAT -"
@@ -956,2734 +959,2875 @@ public class P25DecoderState extends DecoderState
// + " MSG:" + message.getBinaryMessage()
// + " CLASS:" + message.getClass() );
// }
- }
-
- /**
- * Processes LDU voice frame messages. Sends continuation events to keep
- * the channel state synchronized and processes the embedded link control
- * messages to capture/broadcast peripheral events like paging.
- */
- private void processLDU( LDUMessage ldu )
- {
- broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CALL ) );
-
- if( mCurrentCallEvent == null )
- {
- mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.CALL )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .frequency( mCurrentChannelFrequency )
- .build();
-
- broadcast( mCurrentCallEvent );
- }
-
- if( ldu instanceof LDU1Message )
- {
- switch( ((LDU1Message)ldu).getOpcode() )
- {
- case ADJACENT_SITE_STATUS_BROADCAST:
- if( ldu instanceof module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcast )
- {
- IAdjacentSite ias = (IAdjacentSite)ldu;
-
- mNeighborMap.put( ias.getUniqueID(), ias );
-
- updateSystem( ias.getSystemID() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
+ }
- break;
- case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT:
- if( ldu instanceof module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcastExplicit )
- {
- IAdjacentSite ias = (IAdjacentSite)ldu;
-
- mNeighborMap.put( ias.getUniqueID(), ias );
-
- updateSystem( ias.getSystemID() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case CALL_ALERT:
- if( ldu instanceof module.decode.p25.message.ldu.lc.CallAlert )
- {
- module.decode.p25.message.ldu.lc.CallAlert ca =
- (module.decode.p25.message.ldu.lc.CallAlert)ldu;
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( ca.getSourceAddress() )
- .to( ca.getTargetAddress() )
- .details( "CALL ALERT" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case CALL_TERMINATION_OR_CANCELLATION:
- broadcast( new DecoderStateEvent( this, Event.END, State.FADE ) );
- mCurrentCallEvent = null;
+ /**
+ * Processes LDU voice frame messages. Sends continuation events to keep
+ * the channel state synchronized and processes the embedded link control
+ * messages to capture/broadcast peripheral events like paging.
+ */
+ private void processLDU(LDUMessage ldu)
+ {
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL));
- if( !( ldu instanceof CallTermination ) )
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case CHANNEL_IDENTIFIER_UPDATE:
- //TODO: do we need this for the activity summary?
+ if(mCurrentCallEvent == null)
+ {
+ mCurrentCallEvent = new P25CallEvent.Builder(CallEventType.CALL)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .frequency(mCurrentChannelFrequency)
+ .build();
- /* This message is handled by the P25MessageProcessor and
+ broadcast(mCurrentCallEvent);
+ }
+
+ if(ldu instanceof LDU1Message)
+ {
+ switch(((LDU1Message) ldu).getOpcode())
+ {
+ case ADJACENT_SITE_STATUS_BROADCAST:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcast)
+ {
+ IAdjacentSite ias = (IAdjacentSite) ldu;
+
+ mNeighborMap.put(ias.getUniqueID(), ias);
+
+ updateSystem(ias.getSystemID());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+
+ break;
+ case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcastExplicit)
+ {
+ IAdjacentSite ias = (IAdjacentSite) ldu;
+
+ mNeighborMap.put(ias.getUniqueID(), ias);
+
+ updateSystem(ias.getSystemID());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case CALL_ALERT:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.CallAlert)
+ {
+ module.decode.p25.message.ldu.lc.CallAlert ca =
+ (module.decode.p25.message.ldu.lc.CallAlert) ldu;
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(ca.getSourceAddress())
+ .to(ca.getTargetAddress())
+ .details("CALL ALERT")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case CALL_TERMINATION_OR_CANCELLATION:
+ broadcast(new DecoderStateEvent(this, Event.END, State.FADE));
+ mCurrentCallEvent = null;
+
+ if(!(ldu instanceof CallTermination))
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case CHANNEL_IDENTIFIER_UPDATE:
+ //TODO: do we need this for the activity summary?
+
+ /* This message is handled by the P25MessageProcessor and
* inserted into any channels needing frequency band info */
- break;
- case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
- //TODO: do we need this for the activity summary?
+ break;
+ case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
+ //TODO: do we need this for the activity summary?
- /* This message is handled by the P25MessageProcessor and
+ /* This message is handled by the P25MessageProcessor and
* inserted into any channels needing frequency band info */
- break;
- case EXTENDED_FUNCTION_COMMAND:
- if( ldu instanceof module.decode.p25.message.ldu.lc.ExtendedFunctionCommand )
- {
- module.decode.p25.message.ldu.lc.ExtendedFunctionCommand efc =
- (module.decode.p25.message.ldu.lc.ExtendedFunctionCommand)ldu;
+ break;
+ case EXTENDED_FUNCTION_COMMAND:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.ExtendedFunctionCommand)
+ {
+ module.decode.p25.message.ldu.lc.ExtendedFunctionCommand efc =
+ (module.decode.p25.message.ldu.lc.ExtendedFunctionCommand) ldu;
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( efc.getTargetAddress() )
- .details( "FUNCTION:" + efc.getExtendedFunction().getLabel() +
- " ARG:" + efc.getArgument() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case GROUP_AFFILIATION_QUERY:
- if( mChannelType == ChannelType.STANDARD &&
- ldu instanceof module.decode.p25.message.ldu.lc.GroupAffiliationQuery )
- {
- module.decode.p25.message.ldu.lc.GroupAffiliationQuery gaq =
- (module.decode.p25.message.ldu.lc.GroupAffiliationQuery)ldu;
-
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "GROUP AFFILIATION QUERY" )
- .from( gaq.getSourceAddress() )
- .to( gaq.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case GROUP_VOICE_CHANNEL_UPDATE:
- if( ldu instanceof module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate )
- {
- module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate gvcu =
- (module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate)ldu;
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(efc.getTargetAddress())
+ .details("FUNCTION:" + efc.getExtendedFunction().getLabel() +
+ " ARG:" + efc.getArgument())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case GROUP_AFFILIATION_QUERY:
+ if(mChannelType == ChannelType.STANDARD &&
+ ldu instanceof module.decode.p25.message.ldu.lc.GroupAffiliationQuery)
+ {
+ module.decode.p25.message.ldu.lc.GroupAffiliationQuery gaq =
+ (module.decode.p25.message.ldu.lc.GroupAffiliationQuery) ldu;
- String userA = gvcu.getGroupAddressA();
- String userB = gvcu.getGroupAddressB();
-
- if( mChannelType == ChannelType.STANDARD )
- {
- if( !mCallDetectTalkgroups.contains( userA ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
- .aliasList( getAliasList() )
- .channel( gvcu.getChannelA() )
- .details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
- .frequency( gvcu.getDownlinkFrequencyA() )
- .to( userA )
- .build() );
-
- mCallDetectTalkgroups.add( userA );
- }
-
- if( userB != null &&
- !userB.contentEquals( "0000" ) &&
- !mCallDetectTalkgroups.contains( userB ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
- .aliasList( getAliasList() )
- .channel( gvcu.getChannelB() )
- .details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
- .frequency( gvcu.getDownlinkFrequencyB() )
- .to( userB )
- .build() );
-
- mCallDetectTalkgroups.add( userB );
- }
- }
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
- if( ldu instanceof module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit )
- {
- module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit gvcue =
- (module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit)ldu;
-
- String group = gvcue.getGroupAddress();
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("GROUP AFFILIATION QUERY")
+ .from(gaq.getSourceAddress())
+ .to(gaq.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_UPDATE:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate)
+ {
+ module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate gvcu =
+ (module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate) ldu;
- if( mChannelType == ChannelType.STANDARD )
- {
- if( !mCallDetectTalkgroups.contains( group ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
- .aliasList( getAliasList() )
- .channel( gvcue.getTransmitChannel() )
- .details( ( gvcue.isEncrypted() ? "ENCRYPTED" : "" ) )
- .frequency( gvcue.getDownlinkFrequency() )
- .to( group )
- .build() );
-
- mCallDetectTalkgroups.add( group );
- }
- }
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case GROUP_VOICE_CHANNEL_USER:
+ String userA = gvcu.getGroupAddressA();
+ String userB = gvcu.getGroupAddressB();
+
+ if(mChannelType == ChannelType.STANDARD)
+ {
+ if(!mCallDetectTalkgroups.contains(userA))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
+ .aliasList(getAliasList())
+ .channel(gvcu.getChannelA())
+ .details((gvcu.isEncrypted() ? "ENCRYPTED" : ""))
+ .frequency(gvcu.getDownlinkFrequencyA())
+ .to(userA)
+ .build());
+
+ mCallDetectTalkgroups.add(userA);
+ }
+
+ if(userB != null &&
+ !userB.contentEquals("0000") &&
+ !mCallDetectTalkgroups.contains(userB))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
+ .aliasList(getAliasList())
+ .channel(gvcu.getChannelB())
+ .details((gvcu.isEncrypted() ? "ENCRYPTED" : ""))
+ .frequency(gvcu.getDownlinkFrequencyB())
+ .to(userB)
+ .build());
+
+ mCallDetectTalkgroups.add(userB);
+ }
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit)
+ {
+ module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit gvcue =
+ (module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit) ldu;
+
+ String group = gvcue.getGroupAddress();
+
+ if(mChannelType == ChannelType.STANDARD)
+ {
+ if(!mCallDetectTalkgroups.contains(group))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
+ .aliasList(getAliasList())
+ .channel(gvcue.getTransmitChannel())
+ .details((gvcue.isEncrypted() ? "ENCRYPTED" : ""))
+ .frequency(gvcue.getDownlinkFrequency())
+ .to(group)
+ .build());
+
+ mCallDetectTalkgroups.add(group);
+ }
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_USER:
/* Indicates the current user of the current channel */
- if( ldu instanceof module.decode.p25.message.ldu.lc.GroupVoiceChannelUser )
- {
- module.decode.p25.message.ldu.lc.GroupVoiceChannelUser gvcuser =
- (module.decode.p25.message.ldu.lc.GroupVoiceChannelUser)ldu;
+ if(ldu instanceof module.decode.p25.message.ldu.lc.GroupVoiceChannelUser)
+ {
+ module.decode.p25.message.ldu.lc.GroupVoiceChannelUser gvcuser =
+ (module.decode.p25.message.ldu.lc.GroupVoiceChannelUser) ldu;
- updateFrom( gvcuser.getSourceAddress() );
-
- updateTo( gvcuser.getGroupAddress() );
-
- if( mChannelType == ChannelType.STANDARD )
- {
- if( mCurrentCallEvent.getCallEventType() != CallEventType.GROUP_CALL )
- {
- mCurrentCallEvent.setCallEventType( CallEventType.GROUP_CALL );
- broadcast( mCurrentCallEvent );
- }
+ updateFrom(gvcuser.getSourceAddress());
- if( mCurrentCallEvent.getDetails() == null )
- {
- mCurrentCallEvent.setDetails(
- ( gvcuser.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( gvcuser.isEmergency() ? "EMERGENCY " : "" ) );
+ updateTo(gvcuser.getGroupAddress());
- broadcast( mCurrentCallEvent );
- }
- }
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case MESSAGE_UPDATE:
- if( ldu instanceof module.decode.p25.message.ldu.lc.MessageUpdate )
- {
- module.decode.p25.message.ldu.lc.MessageUpdate mu =
- (module.decode.p25.message.ldu.lc.MessageUpdate)ldu;
+ if(mChannelType == ChannelType.STANDARD)
+ {
+ if(mCurrentCallEvent.getCallEventType() != CallEventType.GROUP_CALL)
+ {
+ mCurrentCallEvent.setCallEventType(CallEventType.GROUP_CALL);
+ broadcast(mCurrentCallEvent);
+ }
- broadcast( new P25CallEvent.Builder( CallEventType.SDM )
- .aliasList( getAliasList() )
- .from( mu.getSourceAddress() )
- .to( mu.getTargetAddress() )
- .details( "MSG: " + mu.getShortDataMessage() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case NETWORK_STATUS_BROADCAST:
- if( ldu instanceof module.decode.p25.message.ldu.lc.NetworkStatusBroadcast )
- {
- updateSystem( ((module.decode.p25.message.ldu.lc.NetworkStatusBroadcast)ldu).getSystem() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case NETWORK_STATUS_BROADCAST_EXPLICIT:
- if( ldu instanceof module.decode.p25.message.ldu.lc.NetworkStatusBroadcastExplicit )
- {
- updateSystem( ((module.decode.p25.message.ldu.lc.NetworkStatusBroadcastExplicit)ldu).getSystem() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case PROTECTION_PARAMETER_BROADCAST:
- if( ldu instanceof module.decode.p25.message.ldu.lc.ProtectionParameterBroadcast )
- {
- module.decode.p25.message.ldu.lc.ProtectionParameterBroadcast ppb =
- (module.decode.p25.message.ldu.lc.ProtectionParameterBroadcast)ldu;
+ if(mCurrentCallEvent.getDetails() == null)
+ {
+ mCurrentCallEvent.setDetails(
+ (gvcuser.isEncrypted() ? "ENCRYPTED " : "") +
+ (gvcuser.isEmergency() ? "EMERGENCY " : ""));
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( ppb.getTargetAddress() )
- .details( "ENCRYPTION: " +
- ppb.getEncryption().name() + " KEY:" +
- ppb.getEncryptionKey() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case RFSS_STATUS_BROADCAST:
- if( ldu instanceof module.decode.p25.message.ldu.lc.RFSSStatusBroadcast )
- {
- module.decode.p25.message.ldu.lc.RFSSStatusBroadcast rfsssb =
- (module.decode.p25.message.ldu.lc.RFSSStatusBroadcast)ldu;
-
- updateSystem( rfsssb.getSystem() );
+ broadcast(mCurrentCallEvent);
+ }
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case MESSAGE_UPDATE:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.MessageUpdate)
+ {
+ module.decode.p25.message.ldu.lc.MessageUpdate mu =
+ (module.decode.p25.message.ldu.lc.MessageUpdate) ldu;
- String site = rfsssb.getRFSubsystemID() + "-" +
- rfsssb.getSiteID();
+ broadcast(new P25CallEvent.Builder(CallEventType.SDM)
+ .aliasList(getAliasList())
+ .from(mu.getSourceAddress())
+ .to(mu.getTargetAddress())
+ .details("MSG: " + mu.getShortDataMessage())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case NETWORK_STATUS_BROADCAST:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.NetworkStatusBroadcast)
+ {
+ updateSystem(((module.decode.p25.message.ldu.lc.NetworkStatusBroadcast) ldu).getSystem());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case NETWORK_STATUS_BROADCAST_EXPLICIT:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.NetworkStatusBroadcastExplicit)
+ {
+ updateSystem(((module.decode.p25.message.ldu.lc.NetworkStatusBroadcastExplicit) ldu).getSystem());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case PROTECTION_PARAMETER_BROADCAST:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.ProtectionParameterBroadcast)
+ {
+ module.decode.p25.message.ldu.lc.ProtectionParameterBroadcast ppb =
+ (module.decode.p25.message.ldu.lc.ProtectionParameterBroadcast) ldu;
- updateSite( site );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case RFSS_STATUS_BROADCAST_EXPLICIT:
- if( ldu instanceof module.decode.p25.message.ldu.lc.RFSSStatusBroadcastExplicit )
- {
- module.decode.p25.message.ldu.lc.RFSSStatusBroadcastExplicit rfsssbe =
- (module.decode.p25.message.ldu.lc.RFSSStatusBroadcastExplicit)ldu;
-
- String site = rfsssbe.getRFSubsystemID() + "-" +
- rfsssbe.getSiteID();
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(ppb.getTargetAddress())
+ .details("ENCRYPTION: " +
+ ppb.getEncryption().name() + " KEY:" +
+ ppb.getEncryptionKey())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case RFSS_STATUS_BROADCAST:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.RFSSStatusBroadcast)
+ {
+ module.decode.p25.message.ldu.lc.RFSSStatusBroadcast rfsssb =
+ (module.decode.p25.message.ldu.lc.RFSSStatusBroadcast) ldu;
- updateSite( site );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case SECONDARY_CONTROL_CHANNEL_BROADCAST:
- if( ldu instanceof module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcast )
- {
- module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcast sccb =
- (module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcast)ldu;
-
- String site = sccb.getRFSubsystemID() + "-" +
- sccb.getSiteID();
+ updateSystem(rfsssb.getSystem());
- updateSite( site );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
- if( ldu instanceof module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcastExplicit )
- {
- module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcastExplicit sccb =
- (module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcastExplicit)ldu;
-
- String site = sccb.getRFSubsystemID() + "-" +
- sccb.getSiteID();
+ String site = rfsssb.getRFSubsystemID() + "-" +
+ rfsssb.getSiteID();
- updateSite( site );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case STATUS_QUERY:
- if( ldu instanceof module.decode.p25.message.ldu.lc.StatusQuery )
- {
- module.decode.p25.message.ldu.lc.StatusQuery sq =
- (module.decode.p25.message.ldu.lc.StatusQuery)ldu;
+ updateSite(site);
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case RFSS_STATUS_BROADCAST_EXPLICIT:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.RFSSStatusBroadcastExplicit)
+ {
+ module.decode.p25.message.ldu.lc.RFSSStatusBroadcastExplicit rfsssbe =
+ (module.decode.p25.message.ldu.lc.RFSSStatusBroadcastExplicit) ldu;
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "STATUS QUERY" )
- .from( sq.getSourceAddress() )
- .to( sq.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case STATUS_UPDATE:
- if( ldu instanceof module.decode.p25.message.ldu.lc.StatusUpdate )
- {
- module.decode.p25.message.ldu.lc.StatusUpdate su =
- (module.decode.p25.message.ldu.lc.StatusUpdate)ldu;
+ String site = rfsssbe.getRFSubsystemID() + "-" +
+ rfsssbe.getSiteID();
- broadcast( new P25CallEvent.Builder( CallEventType.STATUS )
- .aliasList( getAliasList() )
- .details( "STATUS UNIT:" + su.getUnitStatus() +
- " USER:" + su.getUserStatus() )
- .from( su.getSourceAddress() )
- .to( su.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case SYSTEM_SERVICE_BROADCAST:
+ updateSite(site);
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case SECONDARY_CONTROL_CHANNEL_BROADCAST:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcast)
+ {
+ module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcast sccb =
+ (module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcast) ldu;
+
+ String site = sccb.getRFSubsystemID() + "-" +
+ sccb.getSiteID();
+
+ updateSite(site);
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcastExplicit)
+ {
+ module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcastExplicit sccb =
+ (module.decode.p25.message.ldu.lc.SecondaryControlChannelBroadcastExplicit) ldu;
+
+ String site = sccb.getRFSubsystemID() + "-" +
+ sccb.getSiteID();
+
+ updateSite(site);
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case STATUS_QUERY:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.StatusQuery)
+ {
+ module.decode.p25.message.ldu.lc.StatusQuery sq =
+ (module.decode.p25.message.ldu.lc.StatusQuery) ldu;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("STATUS QUERY")
+ .from(sq.getSourceAddress())
+ .to(sq.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case STATUS_UPDATE:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.StatusUpdate)
+ {
+ module.decode.p25.message.ldu.lc.StatusUpdate su =
+ (module.decode.p25.message.ldu.lc.StatusUpdate) ldu;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.STATUS)
+ .aliasList(getAliasList())
+ .details("STATUS UNIT:" + su.getUnitStatus() +
+ " USER:" + su.getUserStatus())
+ .from(su.getSourceAddress())
+ .to(su.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case SYSTEM_SERVICE_BROADCAST:
/* This message doesn't provide anything we need for channel state */
- break;
- case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
- if( ldu instanceof module.decode.p25.message.ldu.lc.TelephoneInterconnectAnswerRequest )
- {
- module.decode.p25.message.ldu.lc.TelephoneInterconnectAnswerRequest tiar =
- (module.decode.p25.message.ldu.lc.TelephoneInterconnectAnswerRequest)ldu;
+ break;
+ case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.TelephoneInterconnectAnswerRequest)
+ {
+ module.decode.p25.message.ldu.lc.TelephoneInterconnectAnswerRequest tiar =
+ (module.decode.p25.message.ldu.lc.TelephoneInterconnectAnswerRequest) ldu;
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( tiar.getTelephoneNumber() )
- .to( tiar.getTargetAddress() )
- .details( "TELEPHONE CALL ALERT" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(tiar.getTelephoneNumber())
+ .to(tiar.getTargetAddress())
+ .details("TELEPHONE CALL ALERT")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
/* Indicates the current user of the current channel */
- if( mChannelType == ChannelType.STANDARD &&
- ldu instanceof TelephoneInterconnectVoiceChannelUser )
- {
- TelephoneInterconnectVoiceChannelUser tivcu =
- (TelephoneInterconnectVoiceChannelUser)ldu;
+ if(mChannelType == ChannelType.STANDARD &&
+ ldu instanceof TelephoneInterconnectVoiceChannelUser)
+ {
+ TelephoneInterconnectVoiceChannelUser tivcu =
+ (TelephoneInterconnectVoiceChannelUser) ldu;
- updateTo( tivcu.getAddress() );
+ updateTo(tivcu.getAddress());
- if( mCurrentCallEvent.getCallEventType() != CallEventType.TELEPHONE_INTERCONNECT )
- {
- mCurrentCallEvent.setCallEventType( CallEventType.TELEPHONE_INTERCONNECT );
- broadcast( mCurrentCallEvent );
- }
+ if(mCurrentCallEvent.getCallEventType() != CallEventType.TELEPHONE_INTERCONNECT)
+ {
+ mCurrentCallEvent.setCallEventType(CallEventType.TELEPHONE_INTERCONNECT);
+ broadcast(mCurrentCallEvent);
+ }
- if( mCurrentCallEvent.getDetails() == null )
- {
- mCurrentCallEvent.setDetails(
- ( tivcu.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( tivcu.isEmergency() ? "EMERGENCY " : "" ) );
+ if(mCurrentCallEvent.getDetails() == null)
+ {
+ mCurrentCallEvent.setDetails(
+ (tivcu.isEncrypted() ? "ENCRYPTED " : "") +
+ (tivcu.isEmergency() ? "EMERGENCY " : ""));
- broadcast( mCurrentCallEvent );
- }
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case UNIT_AUTHENTICATION_COMMAND:
- if( ldu instanceof module.decode.p25.message.ldu.lc.UnitAuthenticationCommand )
- {
- module.decode.p25.message.ldu.lc.UnitAuthenticationCommand uac =
- (module.decode.p25.message.ldu.lc.UnitAuthenticationCommand)ldu;
+ broadcast(mCurrentCallEvent);
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case UNIT_AUTHENTICATION_COMMAND:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.UnitAuthenticationCommand)
+ {
+ module.decode.p25.message.ldu.lc.UnitAuthenticationCommand uac =
+ (module.decode.p25.message.ldu.lc.UnitAuthenticationCommand) ldu;
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( uac.getCompleteTargetAddress() )
- .details( "AUTHENTICATE" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case UNIT_REGISTRATION_COMMAND:
- if( ldu instanceof module.decode.p25.message.ldu.lc.UnitRegistrationCommand )
- {
- module.decode.p25.message.ldu.lc.UnitRegistrationCommand urc =
- (module.decode.p25.message.ldu.lc.UnitRegistrationCommand)ldu;
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(uac.getCompleteTargetAddress())
+ .details("AUTHENTICATE")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case UNIT_REGISTRATION_COMMAND:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.UnitRegistrationCommand)
+ {
+ module.decode.p25.message.ldu.lc.UnitRegistrationCommand urc =
+ (module.decode.p25.message.ldu.lc.UnitRegistrationCommand) ldu;
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .to( urc.getCompleteTargetAddress() )
- .details( "REGISTER" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case UNIT_TO_UNIT_ANSWER_REQUEST:
- if( ldu instanceof module.decode.p25.message.ldu.lc.UnitToUnitAnswerRequest )
- {
- module.decode.p25.message.ldu.lc.UnitToUnitAnswerRequest uuar =
- (module.decode.p25.message.ldu.lc.UnitToUnitAnswerRequest)ldu;
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .to(urc.getCompleteTargetAddress())
+ .details("REGISTER")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case UNIT_TO_UNIT_ANSWER_REQUEST:
+ if(ldu instanceof module.decode.p25.message.ldu.lc.UnitToUnitAnswerRequest)
+ {
+ module.decode.p25.message.ldu.lc.UnitToUnitAnswerRequest uuar =
+ (module.decode.p25.message.ldu.lc.UnitToUnitAnswerRequest) ldu;
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( uuar.getSourceAddress() )
- .to( uuar.getTargetAddress() )
- .details( "UNIT TO UNIT CALL ALERT" )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
- if( mChannelType == ChannelType.STANDARD &&
- ldu instanceof UnitToUnitVoiceChannelUser )
- {
- UnitToUnitVoiceChannelUser uuvcu =
- (UnitToUnitVoiceChannelUser)ldu;
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(uuar.getSourceAddress())
+ .to(uuar.getTargetAddress())
+ .details("UNIT TO UNIT CALL ALERT")
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
+ if(mChannelType == ChannelType.STANDARD &&
+ ldu instanceof UnitToUnitVoiceChannelUser)
+ {
+ UnitToUnitVoiceChannelUser uuvcu =
+ (UnitToUnitVoiceChannelUser) ldu;
- updateFrom( uuvcu.getSourceAddress() );
-
- updateTo( uuvcu.getTargetAddress() );
-
- if( mCurrentCallEvent.getCallEventType() != CallEventType.UNIT_TO_UNIT_CALL )
- {
- mCurrentCallEvent.setCallEventType( CallEventType.UNIT_TO_UNIT_CALL );
- broadcast( mCurrentCallEvent );
- }
+ updateFrom(uuvcu.getSourceAddress());
- if( mCurrentCallEvent.getDetails() == null )
- {
- mCurrentCallEvent.setDetails(
- ( uuvcu.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( uuvcu.isEmergency() ? "EMERGENCY " : "" ) );
+ updateTo(uuvcu.getTargetAddress());
- broadcast( mCurrentCallEvent );
- }
- }
- else
- {
- logAlternateVendorMessage( ldu );
- }
- break;
- default:
- break;
- }
- }
- }
-
- /**
- * Process a Trunking Signalling Block message
- */
- private void processTSBK( TSBKMessage tsbk )
- {
+ if(mCurrentCallEvent.getCallEventType() != CallEventType.UNIT_TO_UNIT_CALL)
+ {
+ mCurrentCallEvent.setCallEventType(CallEventType.UNIT_TO_UNIT_CALL);
+ broadcast(mCurrentCallEvent);
+ }
+
+ if(mCurrentCallEvent.getDetails() == null)
+ {
+ mCurrentCallEvent.setDetails(
+ (uuvcu.isEncrypted() ? "ENCRYPTED " : "") +
+ (uuvcu.isEmergency() ? "EMERGENCY " : ""));
+
+ broadcast(mCurrentCallEvent);
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(ldu);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Process a Trunking Signalling Block message
+ */
+ private void processTSBK(TSBKMessage tsbk)
+ {
/* Trunking Signalling Block Messages - indicates Control Channel */
- broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CONTROL));
- if( tsbk.getVendor() == Vendor.STANDARD )
- {
- switch( tsbk.getOpcode() )
- {
- case ADJACENT_STATUS_BROADCAST:
- if( tsbk instanceof AdjacentStatusBroadcast )
- {
- IAdjacentSite ias = (IAdjacentSite)tsbk;
-
- mNeighborMap.put( ias.getUniqueID(), ias );
-
- updateSystem( ias.getSystemID() );
- }
- break;
- case ACKNOWLEDGE_RESPONSE:
- processTSBKResponse( tsbk );
- break;
- case AUTHENTICATION_COMMAND:
- processTSBKCommand( tsbk );
- break;
- case CALL_ALERT:
- processTSBKPage( tsbk );
- break;
- case DENY_RESPONSE:
- processTSBKResponse( tsbk );
- break;
- case EXTENDED_FUNCTION_COMMAND:
- processTSBKCommand( tsbk );
- break;
- case GROUP_AFFILIATION_QUERY:
- processTSBKQuery( tsbk );
- break;
- case GROUP_AFFILIATION_RESPONSE:
- processTSBKResponse( tsbk );
- break;
- case GROUP_DATA_CHANNEL_ANNOUNCEMENT:
- case GROUP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
- processTSBKDataChannelAnnouncement( tsbk);
- break;
- case GROUP_DATA_CHANNEL_GRANT:
- case GROUP_VOICE_CHANNEL_GRANT:
- case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
- case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
- case INDIVIDUAL_DATA_CHANNEL_GRANT:
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
- processTSBKChannelGrant( tsbk );
- break;
- case IDENTIFIER_UPDATE_NON_VUHF:
- case IDENTIFIER_UPDATE_VHF_UHF_BANDS:
- IdentifierUpdate iu = (IdentifierUpdate)tsbk;
-
- if( !mBands.containsKey( iu.getIdentifier() ) )
- {
- mBands.put( iu.getIdentifier(), iu );
- }
- break;
- case LOCATION_REGISTRATION_RESPONSE:
- case UNIT_DEREGISTRATION_ACKNOWLEDGE:
- processTSBKResponse( tsbk );
- break;
- case MESSAGE_UPDATE:
- processTSBKMessage( tsbk );
- break;
- case NETWORK_STATUS_BROADCAST:
- mNetworkStatus = (module.decode.p25.message.tsbk.osp
- .control.NetworkStatusBroadcast)tsbk;
- break;
- case PROTECTION_PARAMETER_UPDATE:
- processTSBKResponse( tsbk );
- break;
- case QUEUED_RESPONSE:
- processTSBKResponse( tsbk );
- break;
- case RADIO_UNIT_MONITOR_COMMAND:
- processTSBKCommand( tsbk );
- break;
- case RFSS_STATUS_BROADCAST:
- processTSBKRFSSStatus( (RFSSStatusBroadcast)tsbk );
- break;
- case ROAMING_ADDRESS_COMMAND:
- processTSBKCommand( tsbk );
- break;
- case SECONDARY_CONTROL_CHANNEL_BROADCAST:
- module.decode.p25.message.tsbk.osp.control.SecondaryControlChannelBroadcast sccb =
- (module.decode.p25.message.tsbk.osp.control.SecondaryControlChannelBroadcast)tsbk;
-
- if( sccb.getDownlinkFrequency1() > 0 )
- {
- mSecondaryControlChannels.add( sccb );
- }
- break;
- case SNDCP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
- mSNDCPDataChannel = (SNDCPDataChannelAnnouncementExplicit)tsbk;
- break;
- case SNDCP_DATA_CHANNEL_GRANT:
- processTSBKChannelGrant( tsbk );
- break;
- case STATUS_QUERY:
- processTSBKQuery( tsbk );
- break;
- case STATUS_UPDATE:
- processTSBKResponse( tsbk );
- break;
- case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
- case UNIT_TO_UNIT_ANSWER_REQUEST:
- processTSBKPage( tsbk );
- break;
- case UNIT_REGISTRATION_COMMAND:
- processTSBKCommand( tsbk );
- break;
- case UNIT_REGISTRATION_RESPONSE:
- processTSBKResponse( tsbk );
- break;
- default:
- break;
- }
- }
- else if( tsbk.getVendor() == Vendor.MOTOROLA )
- {
- processMotorolaTSBK((MotorolaTSBKMessage)tsbk);
- }
- }
+ if(tsbk.getVendor() == Vendor.STANDARD)
+ {
+ switch(tsbk.getOpcode())
+ {
+ case ADJACENT_STATUS_BROADCAST:
+ if(tsbk instanceof AdjacentStatusBroadcast)
+ {
+ IAdjacentSite ias = (IAdjacentSite) tsbk;
- /**
- * Process a Packet Data Unit message
- */
- private void processPDU( PDUMessage pdu )
- {
- if( pdu instanceof PacketData || pdu instanceof PDUTypeUnknown )
- {
- broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.DATA ) );
- }
- else if( pdu instanceof PDUConfirmedMessage )
- {
- broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.DATA ) );
-
- PDUConfirmedMessage pduc = (PDUConfirmedMessage)pdu;
+ mNeighborMap.put(ias.getUniqueID(), ias);
- switch( pduc.getPDUType() )
- {
- case SNDCP_ACTIVATE_TDS_CONTEXT_ACCEPT:
- SNDCPActivateTDSContextAccept satca =
- (SNDCPActivateTDSContextAccept)pduc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( "ACTIVATE SNDCP USE IP:" + satca.getIPAddress() )
- .frequency( mCurrentChannelFrequency )
- .to( satca.getLogicalLinkID() )
- .build() );
- break;
- case SNDCP_ACTIVATE_TDS_CONTEXT_REJECT:
- SNDCPActivateTDSContextReject satcr =
- (SNDCPActivateTDSContextReject)pduc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( "REJECT: SNDCP CONTEXT ACTIVATION "
- + "REASON:" + satcr.getReason().getLabel() )
- .frequency( mCurrentChannelFrequency )
- .to( satcr.getLogicalLinkID() )
- .build() );
- break;
- case SNDCP_ACTIVATE_TDS_CONTEXT_REQUEST:
- SNDCPActivateTDSContextRequest satcreq =
- (SNDCPActivateTDSContextRequest)pduc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( "REQUEST SNDCP USE IP:" + satcreq.getIPAddress() )
- .frequency( mCurrentChannelFrequency )
- .from( satcreq.getLogicalLinkID() )
- .build() );
- break;
- case SNDCP_DEACTIVATE_TDS_CONTEXT_ACCEPT:
- SNDCPDeactivateTDSContext sdtca =
- (SNDCPDeactivateTDSContext)pduc;
+ updateSystem(ias.getSystemID());
+ }
+ break;
+ case ACKNOWLEDGE_RESPONSE:
+ processTSBKResponse(tsbk);
+ break;
+ case AUTHENTICATION_COMMAND:
+ processTSBKCommand(tsbk);
+ break;
+ case CALL_ALERT:
+ processTSBKPage(tsbk);
+ break;
+ case DENY_RESPONSE:
+ processTSBKResponse(tsbk);
+ break;
+ case EXTENDED_FUNCTION_COMMAND:
+ processTSBKCommand(tsbk);
+ break;
+ case GROUP_AFFILIATION_QUERY:
+ processTSBKQuery(tsbk);
+ break;
+ case GROUP_AFFILIATION_RESPONSE:
+ processTSBKResponse(tsbk);
+ break;
+ case GROUP_DATA_CHANNEL_ANNOUNCEMENT:
+ case GROUP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
+ processTSBKDataChannelAnnouncement(tsbk);
+ break;
+ case GROUP_DATA_CHANNEL_GRANT:
+ case GROUP_VOICE_CHANNEL_GRANT:
+ case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
+ case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
+ case INDIVIDUAL_DATA_CHANNEL_GRANT:
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
+ processTSBKChannelGrant(tsbk);
+ break;
+ case IDENTIFIER_UPDATE_NON_VUHF:
+ case IDENTIFIER_UPDATE_VHF_UHF_BANDS:
+ IdentifierUpdate iu = (IdentifierUpdate) tsbk;
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( "ACCEPT DEACTIVATE SNDCP CONTEXT" )
- .frequency( mCurrentChannelFrequency )
- .from( sdtca.getLogicalLinkID() )
- .build() );
- break;
- case SNDCP_DEACTIVATE_TDS_CONTEXT_REQUEST:
- SNDCPDeactivateTDSContext sdtcreq =
- (SNDCPDeactivateTDSContext)pduc;
-
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( "REQUEST DEACTIVATE SNDCP CONTEXT" )
- .frequency( mCurrentChannelFrequency )
- .from( sdtcreq.getLogicalLinkID() )
- .build() );
- break;
- case SNDCP_RF_CONFIRMED_DATA:
- SNDCPUserData sud = (SNDCPUserData)pduc;
-
- StringBuilder sbFrom = new StringBuilder();
- StringBuilder sbTo = new StringBuilder();
-
- sbFrom.append( sud.getSourceIPAddress() );
- sbTo.append( sud.getDestinationIPAddress() );
-
- if( sud.getIPProtocol() == IPProtocol.UDP )
- {
- sbFrom.append( ":" );
- sbFrom.append( sud.getUDPSourcePort() );
- sbTo.append( ":" );
- sbTo.append( sud.getUDPDestinationPort() );
- }
+ if(!mBands.containsKey(iu.getIdentifier()))
+ {
+ mBands.put(iu.getIdentifier(), iu);
+ }
+ break;
+ case LOCATION_REGISTRATION_RESPONSE:
+ case UNIT_DEREGISTRATION_ACKNOWLEDGE:
+ processTSBKResponse(tsbk);
+ break;
+ case MESSAGE_UPDATE:
+ processTSBKMessage(tsbk);
+ break;
+ case NETWORK_STATUS_BROADCAST:
+ mNetworkStatus = (module.decode.p25.message.tsbk.osp
+ .control.NetworkStatusBroadcast) tsbk;
+ break;
+ case PROTECTION_PARAMETER_UPDATE:
+ processTSBKResponse(tsbk);
+ break;
+ case QUEUED_RESPONSE:
+ processTSBKResponse(tsbk);
+ break;
+ case RADIO_UNIT_MONITOR_COMMAND:
+ processTSBKCommand(tsbk);
+ break;
+ case RFSS_STATUS_BROADCAST:
+ processTSBKRFSSStatus((RFSSStatusBroadcast) tsbk);
+ break;
+ case ROAMING_ADDRESS_COMMAND:
+ processTSBKCommand(tsbk);
+ break;
+ case SECONDARY_CONTROL_CHANNEL_BROADCAST:
+ module.decode.p25.message.tsbk.osp.control.SecondaryControlChannelBroadcast sccb =
+ (module.decode.p25.message.tsbk.osp.control.SecondaryControlChannelBroadcast) tsbk;
- broadcast( new DecoderStateEvent( this, Event.START, State.DATA ) );
-
- broadcast( new P25CallEvent.Builder( CallEventType.DATA_CALL )
- .aliasList( getAliasList() )
- .channel( mCurrentChannel )
- .details( "DATA: " + sud.getPayload() +
- " RADIO IP:" + sbTo.toString() )
- .frequency( mCurrentChannelFrequency )
- .from( sbFrom.toString() )
- .to( pduc.getLogicalLinkID() )
- .build() );
- break;
- case SNDCP_RF_UNCONFIRMED_DATA:
- break;
- default:
+ if(sccb.getDownlinkFrequency1() > 0)
+ {
+ mSecondaryControlChannels.add(sccb);
+ }
+ break;
+ case SNDCP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
+ mSNDCPDataChannel = (SNDCPDataChannelAnnouncementExplicit) tsbk;
+ break;
+ case SNDCP_DATA_CHANNEL_GRANT:
+ processTSBKChannelGrant(tsbk);
+ break;
+ case STATUS_QUERY:
+ processTSBKQuery(tsbk);
+ break;
+ case STATUS_UPDATE:
+ processTSBKResponse(tsbk);
+ break;
+ case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
+ case UNIT_TO_UNIT_ANSWER_REQUEST:
+ processTSBKPage(tsbk);
+ break;
+ case UNIT_REGISTRATION_COMMAND:
+ processTSBKCommand(tsbk);
+ break;
+ case UNIT_REGISTRATION_RESPONSE:
+ processTSBKResponse(tsbk);
+ break;
+ default:
+ break;
+ }
+ }
+ else if(tsbk.getVendor() == Vendor.MOTOROLA)
+ {
+ processMotorolaTSBK((MotorolaTSBKMessage) tsbk);
+ }
+ }
+
+ /**
+ * Process a Packet Data Unit message
+ */
+ private void processPDU(PDUMessage pdu)
+ {
+ if(pdu instanceof PacketData || pdu instanceof PDUTypeUnknown)
+ {
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.DATA));
+ }
+ else if(pdu instanceof PDUConfirmedMessage)
+ {
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.DATA));
+
+ PDUConfirmedMessage pduc = (PDUConfirmedMessage) pdu;
+
+ switch(pduc.getPDUType())
+ {
+ case SNDCP_ACTIVATE_TDS_CONTEXT_ACCEPT:
+ SNDCPActivateTDSContextAccept satca =
+ (SNDCPActivateTDSContextAccept) pduc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details("ACTIVATE SNDCP USE IP:" + satca.getIPAddress())
+ .frequency(mCurrentChannelFrequency)
+ .to(satca.getLogicalLinkID())
+ .build());
+ break;
+ case SNDCP_ACTIVATE_TDS_CONTEXT_REJECT:
+ SNDCPActivateTDSContextReject satcr =
+ (SNDCPActivateTDSContextReject) pduc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details("REJECT: SNDCP CONTEXT ACTIVATION "
+ + "REASON:" + satcr.getReason().getLabel())
+ .frequency(mCurrentChannelFrequency)
+ .to(satcr.getLogicalLinkID())
+ .build());
+ break;
+ case SNDCP_ACTIVATE_TDS_CONTEXT_REQUEST:
+ SNDCPActivateTDSContextRequest satcreq =
+ (SNDCPActivateTDSContextRequest) pduc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details("REQUEST SNDCP USE IP:" + satcreq.getIPAddress())
+ .frequency(mCurrentChannelFrequency)
+ .from(satcreq.getLogicalLinkID())
+ .build());
+ break;
+ case SNDCP_DEACTIVATE_TDS_CONTEXT_ACCEPT:
+ SNDCPDeactivateTDSContext sdtca =
+ (SNDCPDeactivateTDSContext) pduc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details("ACCEPT DEACTIVATE SNDCP CONTEXT")
+ .frequency(mCurrentChannelFrequency)
+ .from(sdtca.getLogicalLinkID())
+ .build());
+ break;
+ case SNDCP_DEACTIVATE_TDS_CONTEXT_REQUEST:
+ SNDCPDeactivateTDSContext sdtcreq =
+ (SNDCPDeactivateTDSContext) pduc;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details("REQUEST DEACTIVATE SNDCP CONTEXT")
+ .frequency(mCurrentChannelFrequency)
+ .from(sdtcreq.getLogicalLinkID())
+ .build());
+ break;
+ case SNDCP_RF_CONFIRMED_DATA:
+ SNDCPUserData sud = (SNDCPUserData) pduc;
+
+ StringBuilder sbFrom = new StringBuilder();
+ StringBuilder sbTo = new StringBuilder();
+
+ sbFrom.append(sud.getSourceIPAddress());
+ sbTo.append(sud.getDestinationIPAddress());
+
+ if(sud.getIPProtocol() == IPProtocol.UDP)
+ {
+ sbFrom.append(":");
+ sbFrom.append(sud.getUDPSourcePort());
+ sbTo.append(":");
+ sbTo.append(sud.getUDPDestinationPort());
+ }
+
+ broadcast(new DecoderStateEvent(this, Event.START, State.DATA));
+
+ broadcast(new P25CallEvent.Builder(CallEventType.DATA_CALL)
+ .aliasList(getAliasList())
+ .channel(mCurrentChannel)
+ .details("DATA: " + sud.getPayload() +
+ " RADIO IP:" + sbTo.toString())
+ .frequency(mCurrentChannelFrequency)
+ .from(sbFrom.toString())
+ .to(pduc.getLogicalLinkID())
+ .build());
+ break;
+ case SNDCP_RF_UNCONFIRMED_DATA:
+ break;
+ default:
// mLog.debug( "PDUC - Unrecognized Message: " + pduc.toString() );
- break;
- }
- }
- else
- {
+ break;
+ }
+ }
+ else
+ {
/* These are alternate trunking control blocks in PDU format */
- broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
-
- switch( pdu.getOpcode() )
- {
- case GROUP_DATA_CHANNEL_GRANT:
- case GROUP_VOICE_CHANNEL_GRANT:
- case INDIVIDUAL_DATA_CHANNEL_GRANT:
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
- processPDUChannelGrant( pdu );
- break;
- case ADJACENT_STATUS_BROADCAST:
- if( pdu instanceof AdjacentStatusBroadcastExtended )
- {
- IAdjacentSite ias = (IAdjacentSite)pdu;
-
- mNeighborMap.put( ias.getUniqueID(), ias );
-
- updateSystem( ias.getSystemID() );
- }
- break;
- case CALL_ALERT:
- if( pdu instanceof CallAlertExtended )
- {
- CallAlertExtended ca = (CallAlertExtended)pdu;
-
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( ca.getWACN() + "-" + ca.getSystemID() + "-" +
- ca.getSourceID() )
- .to( ca.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case GROUP_AFFILIATION_QUERY:
- if( pdu instanceof GroupAffiliationQueryExtended )
- {
- GroupAffiliationQueryExtended gaqe =
- (GroupAffiliationQueryExtended)pdu;
-
- if( mLastQueryEventID == null || !gaqe.getTargetAddress()
- .contentEquals( mLastQueryEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "GROUP AFFILIATION" )
- .from( gaqe.getWACN() + "-" + gaqe.getSystemID() +
- "-" + gaqe.getSourceID() )
- .to( gaqe.getTargetAddress() )
- .build() );
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CONTROL));
- mLastQueryEventID = gaqe.getToID();
- }
- }
- break;
- case GROUP_AFFILIATION_RESPONSE:
- if( pdu instanceof GroupAffiliationResponseExtended )
- {
- GroupAffiliationResponseExtended gar =
- (GroupAffiliationResponseExtended)pdu;
-
- if( mLastResponseEventID == null || !gar.getTargetAddress()
- .contentEquals( mLastResponseEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "AFFILIATION:" + gar.getResponse().name() +
- " FOR GROUP:" + gar.getGroupWACN() + "-" +
- gar.getGroupSystemID() + "-" +
- gar.getGroupID() + " ANNOUNCEMENT GROUP:" +
- gar.getAnnouncementGroupID() )
- .from( gar.getSourceWACN() + "-" +
- gar.getSourceSystemID() + "-" +
- gar.getSourceID() )
- .to( gar.getTargetAddress() )
- .build() );
-
- mLastResponseEventID = gar.getTargetAddress();
- }
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case MESSAGE_UPDATE:
- if( pdu instanceof MessageUpdateExtended )
- {
- MessageUpdateExtended mu = (MessageUpdateExtended)pdu;
-
- broadcast( new P25CallEvent.Builder( CallEventType.SDM )
- .aliasList( getAliasList() )
- .details( "MESSAGE: " + mu.getMessage() )
- .from( mu.getSourceWACN() + "-" + mu.getSourceSystemID() +
- "-" + mu.getSourceID() )
- .to( mu.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case NETWORK_STATUS_BROADCAST:
- if( pdu instanceof NetworkStatusBroadcastExtended )
- {
- mNetworkStatusExtended = (NetworkStatusBroadcastExtended)pdu;
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case PROTECTION_PARAMETER_BROADCAST:
- if( pdu instanceof ProtectionParameterBroadcast )
- {
- mProtectionParameterBroadcast =
- (ProtectionParameterBroadcast)pdu;
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case RFSS_STATUS_BROADCAST:
- if( pdu instanceof RFSSStatusBroadcastExtended )
- {
- mRFSSStatusMessageExtended = (RFSSStatusBroadcastExtended)pdu;
-
- updateNAC( mRFSSStatusMessageExtended.getNAC() );
- updateSystem( mRFSSStatusMessageExtended.getSystemID() );
- updateSite( mRFSSStatusMessageExtended.getRFSubsystemID() +
- "-" + mRFSSStatusMessageExtended.getSiteID() );
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case ROAMING_ADDRESS_UPDATE:
- if( pdu instanceof RoamingAddressUpdateExtended )
- {
- RoamingAddressUpdateExtended raue =
- (RoamingAddressUpdateExtended)pdu;
+ switch(pdu.getOpcode())
+ {
+ case GROUP_DATA_CHANNEL_GRANT:
+ case GROUP_VOICE_CHANNEL_GRANT:
+ case INDIVIDUAL_DATA_CHANNEL_GRANT:
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
+ processPDUChannelGrant(pdu);
+ break;
+ case ADJACENT_STATUS_BROADCAST:
+ if(pdu instanceof AdjacentStatusBroadcastExtended)
+ {
+ IAdjacentSite ias = (IAdjacentSite) pdu;
- StringBuilder sb = new StringBuilder();
- sb.append( "ROAMING ADDRESS STACK A:" );
- sb.append( raue.getWACNA() + "-" + raue.getSystemIDA() );
-
- if( raue.isFormat2() )
- {
- sb.append( " B:" );
- sb.append( raue.getWACNB() + "-" + raue.getSystemIDB() );
- sb.append( " C:" );
- sb.append( raue.getWACNC() + "-" + raue.getSystemIDC() );
- sb.append( " D:" );
- sb.append( raue.getWACND() + "-" + raue.getSystemIDD() );
- }
-
- if( raue.isFormat3() )
- {
- sb.append( " E:" );
- sb.append( raue.getWACNE() + "-" + raue.getSystemIDE() );
- sb.append( " F:" );
- sb.append( raue.getWACNF() + "-" + raue.getSystemIDF() );
- sb.append( " G:" );
- sb.append( raue.getWACNG() + "-" + raue.getSystemIDG() );
- }
-
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( sb.toString() )
- .from( raue.getSourceID() )
- .to( raue.getTargetAddress() )
- .build() );
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case STATUS_QUERY:
- if( pdu instanceof StatusQueryExtended )
- {
- StatusQueryExtended sq = (StatusQueryExtended)pdu;
-
- if( mLastQueryEventID == null || !sq.getTargetAddress()
- .contentEquals( mLastQueryEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "STATUS QUERY" )
- .from( sq.getSourceWACN() + "-" +
- sq.getSourceSystemID() + "-" +
- sq.getSourceID() )
- .to( sq.getTargetAddress() )
- .build() );
+ mNeighborMap.put(ias.getUniqueID(), ias);
- mLastQueryEventID = sq.getToID();
- }
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case STATUS_UPDATE:
- if( pdu instanceof StatusUpdateExtended )
- {
- StatusUpdateExtended su = (StatusUpdateExtended)pdu;
+ updateSystem(ias.getSystemID());
+ }
+ break;
+ case CALL_ALERT:
+ if(pdu instanceof CallAlertExtended)
+ {
+ CallAlertExtended ca = (CallAlertExtended) pdu;
- if( mLastResponseEventID == null || !mLastResponseEventID
- .contentEquals( su.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "STATUS USER: " + su.getUserStatus() +
- " UNIT: " + su.getUnitStatus() )
- .from( su.getSourceWACN() + "-" +
- su.getSourceSystemID() + "-" +
- su.getSourceID() )
- .to( su.getTargetAddress() )
- .build() );
-
- mLastResponseEventID = su.getTargetAddress();
- }
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case UNIT_REGISTRATION_RESPONSE:
- if( pdu instanceof UnitRegistrationResponseExtended )
- {
- UnitRegistrationResponseExtended urr =
- (UnitRegistrationResponseExtended)pdu;
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(ca.getWACN() + "-" + ca.getSystemID() + "-" +
+ ca.getSourceID())
+ .to(ca.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case GROUP_AFFILIATION_QUERY:
+ if(pdu instanceof GroupAffiliationQueryExtended)
+ {
+ GroupAffiliationQueryExtended gaqe =
+ (GroupAffiliationQueryExtended) pdu;
- if( urr.getResponse() == Response.ACCEPT )
- {
- mRegistrations.put( urr.getAssignedSourceAddress(),
- System.currentTimeMillis() );
- }
-
- if( mLastRegistrationEventID == null || !mLastRegistrationEventID
- .contentEquals( urr.getAssignedSourceAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.REGISTER )
- .aliasList( getAliasList() )
- .details( "REGISTRATION:" + urr.getResponse().name() +
- " FOR EXTERNAL SYSTEM ADDRESS: " +
- urr.getWACN() + "-" +
- urr.getSystemID() + "-" +
- urr.getSourceAddress() +
- " SOURCE ID: " + urr.getSourceID() )
- .from( urr.getAssignedSourceAddress() )
- .build() );
-
- mLastRegistrationEventID = urr.getAssignedSourceAddress();
- }
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case UNIT_TO_UNIT_ANSWER_REQUEST:
- if( pdu instanceof UnitToUnitAnswerRequestExplicit )
- {
- UnitToUnitAnswerRequestExplicit utuare =
- (UnitToUnitAnswerRequestExplicit)pdu;
+ if(mLastQueryEventID == null || !gaqe.getTargetAddress()
+ .contentEquals(mLastQueryEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("GROUP AFFILIATION")
+ .from(gaqe.getWACN() + "-" + gaqe.getSystemID() +
+ "-" + gaqe.getSourceID())
+ .to(gaqe.getTargetAddress())
+ .build());
- if( mLastPageEventID == null || !mLastPageEventID
- .contentEquals( utuare.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .details( ( utuare.isEmergency() ? "EMERGENCY" : "" ) )
- .from( utuare.getWACN() + "-" +
- utuare.getSystemID() + "-" +
- utuare.getSourceID() )
- .to( utuare.getTargetAddress() )
- .build() );
-
- mLastPageEventID = utuare.getTargetAddress();
- }
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- default:
- break;
- }
- }
- }
-
- private void processPDUChannelGrant( PDUMessage pdu )
- {
- String channel = null;
- String from = null;
- String to = null;
-
- switch( pdu.getOpcode() )
- {
- case GROUP_DATA_CHANNEL_GRANT:
- if( pdu instanceof GroupDataChannelGrantExtended )
- {
- GroupDataChannelGrantExtended gdcge =
- (GroupDataChannelGrantExtended)pdu;
+ mLastQueryEventID = gaqe.getToID();
+ }
+ }
+ break;
+ case GROUP_AFFILIATION_RESPONSE:
+ if(pdu instanceof GroupAffiliationResponseExtended)
+ {
+ GroupAffiliationResponseExtended gar =
+ (GroupAffiliationResponseExtended) pdu;
- channel = gdcge.getTransmitChannel();
- from = gdcge.getSourceAddress();
- to = gdcge.getGroupAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( gdcge.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gdcge.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gdcge.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( callEvent );
- broadcast( callEvent );
- }
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
-
- if( !mIgnoreDataCalls )
- {
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- break;
- case GROUP_VOICE_CHANNEL_GRANT:
- if( pdu instanceof GroupVoiceChannelGrantExplicit )
- {
- GroupVoiceChannelGrantExplicit gvcge =
- (GroupVoiceChannelGrantExplicit)pdu;
+ if(mLastResponseEventID == null || !gar.getTargetAddress()
+ .contentEquals(mLastResponseEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("AFFILIATION:" + gar.getResponse().name() +
+ " FOR GROUP:" + gar.getGroupWACN() + "-" +
+ gar.getGroupSystemID() + "-" +
+ gar.getGroupID() + " ANNOUNCEMENT GROUP:" +
+ gar.getAnnouncementGroupID())
+ .from(gar.getSourceWACN() + "-" +
+ gar.getSourceSystemID() + "-" +
+ gar.getSourceID())
+ .to(gar.getTargetAddress())
+ .build());
- channel = gvcge.getTransmitChannel();
- from = gvcge.getSourceAddress();
- to = gvcge.getGroupAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( gvcge.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gvcge.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gvcge.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( callEvent );
- broadcast( callEvent );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case INDIVIDUAL_DATA_CHANNEL_GRANT:
- if( pdu instanceof IndividualDataChannelGrantExtended )
- {
- IndividualDataChannelGrantExtended idcge =
- (IndividualDataChannelGrantExtended)pdu;
-
- channel = idcge.getTransmitChannel();
- from = idcge.getSourceWACN() + "-" +
- idcge.getSourceSystemID() + "-" +
- idcge.getSourceAddress();
- to = idcge.getTargetAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( idcge.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( idcge.isEmergency() ? " EMERGENCY" : "") )
- .frequency( idcge.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( callEvent );
- broadcast( callEvent );
- }
-
- if( !mIgnoreDataCalls )
- {
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
- TelephoneInterconnectChannelGrantExplicit ticge =
- (TelephoneInterconnectChannelGrantExplicit)pdu;
+ mLastResponseEventID = gar.getTargetAddress();
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case MESSAGE_UPDATE:
+ if(pdu instanceof MessageUpdateExtended)
+ {
+ MessageUpdateExtended mu = (MessageUpdateExtended) pdu;
- channel = ticge.getTransmitChannel();
-
- //We don't know if the subscriber is calling or being called, so
- //we use the same address in both from/to fields
- from = ticge.getAddress();
- to = ticge.getAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.TELEPHONE_INTERCONNECT )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( ticge.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( ticge.isEmergency() ? " EMERGENCY" : "") +
- " CALL TIMER:" + ticge.getCallTimer() )
- .frequency( ticge.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( callEvent );
- broadcast( callEvent );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
- if( pdu instanceof UnitToUnitVoiceChannelGrantExtended )
- {
- UnitToUnitVoiceChannelGrantExtended uuvcge =
- (UnitToUnitVoiceChannelGrantExtended)pdu;
-
- channel = uuvcge.getTransmitChannel();
- from = uuvcge.getSourceWACN() + "-" +
- uuvcge.getSourceSystemID() + "-" +
- uuvcge.getSourceID();
- to = uuvcge.getTargetAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( uuvcge.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( uuvcge.isEmergency() ? " EMERGENCY" : "") )
- .frequency( uuvcge.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( callEvent );
- broadcast( callEvent );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
- if( pdu instanceof UnitToUnitVoiceChannelGrantUpdateExtended )
- {
- UnitToUnitVoiceChannelGrantUpdateExtended uuvcgue =
- (UnitToUnitVoiceChannelGrantUpdateExtended)pdu;
+ broadcast(new P25CallEvent.Builder(CallEventType.SDM)
+ .aliasList(getAliasList())
+ .details("MESSAGE: " + mu.getMessage())
+ .from(mu.getSourceWACN() + "-" + mu.getSourceSystemID() +
+ "-" + mu.getSourceID())
+ .to(mu.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case NETWORK_STATUS_BROADCAST:
+ if(pdu instanceof NetworkStatusBroadcastExtended)
+ {
+ mNetworkStatusExtended = (NetworkStatusBroadcastExtended) pdu;
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case PROTECTION_PARAMETER_BROADCAST:
+ if(pdu instanceof ProtectionParameterBroadcast)
+ {
+ mProtectionParameterBroadcast =
+ (ProtectionParameterBroadcast) pdu;
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case RFSS_STATUS_BROADCAST:
+ if(pdu instanceof RFSSStatusBroadcastExtended)
+ {
+ mRFSSStatusMessageExtended = (RFSSStatusBroadcastExtended) pdu;
- channel = uuvcgue.getTransmitChannel();
- from = uuvcgue.getSourceWACN() + "-" +
- uuvcgue.getSourceSystemID() + "-" +
- uuvcgue.getSourceID();
- to = uuvcgue.getTargetAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( uuvcgue.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( uuvcgue.isEmergency() ? " EMERGENCY" : "") )
- .frequency( uuvcgue.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( callEvent );
- broadcast( callEvent );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
-
- }
- else
- {
- logAlternateVendorMessage( pdu );
- }
- break;
- default:
- break;
- }
- }
-
- private void processTSBKCommand( TSBKMessage message )
- {
- switch( message.getOpcode() )
- {
- case AUTHENTICATION_COMMAND:
- AuthenticationCommand ac = (AuthenticationCommand)message;
-
- if( mLastCommandEventID == null || !mLastCommandEventID
- .contentEquals( ac.getFullTargetID() ))
- {
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .details( "AUTHENTICATE" )
- .to( ac.getWACN() + "-" + ac.getSystemID() + "-" +
- ac.getTargetID() )
- .build() );
-
- mLastCommandEventID = ac.getFullTargetID();
- }
- break;
- case EXTENDED_FUNCTION_COMMAND:
- ExtendedFunctionCommand efc = (ExtendedFunctionCommand)message;
+ updateNAC(mRFSSStatusMessageExtended.getNAC());
+ updateSystem(mRFSSStatusMessageExtended.getSystemID());
+ updateSite(mRFSSStatusMessageExtended.getRFSubsystemID() +
+ "-" + mRFSSStatusMessageExtended.getSiteID());
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case ROAMING_ADDRESS_UPDATE:
+ if(pdu instanceof RoamingAddressUpdateExtended)
+ {
+ RoamingAddressUpdateExtended raue =
+ (RoamingAddressUpdateExtended) pdu;
- if( mLastCommandEventID == null || !mLastCommandEventID
- .contentEquals( efc.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.FUNCTION )
- .aliasList( getAliasList() )
- .details( "EXTENDED FUNCTION: " +
- efc.getExtendedFunction().getLabel() )
- .from( efc.getSourceAddress() )
- .to( efc.getTargetAddress() )
- .build() );
-
- mLastCommandEventID = efc.getTargetAddress();
- }
- break;
- case RADIO_UNIT_MONITOR_COMMAND:
- RadioUnitMonitorCommand rumc = (RadioUnitMonitorCommand)message;
-
- if( mLastCommandEventID == null || !mLastCommandEventID
- .contentEquals( rumc.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .details( "RADIO UNIT MONITOR" )
- .from( rumc.getSourceAddress() )
- .to( rumc.getTargetAddress() )
- .build() );
-
- mLastCommandEventID = rumc.getTargetAddress();
- }
- break;
- case ROAMING_ADDRESS_COMMAND:
- RoamingAddressCommand rac = (RoamingAddressCommand)message;
-
- if( mLastCommandEventID == null || !mLastCommandEventID
- .contentEquals( rac.getTargetID() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .details( rac.getStackOperation().name() +
- " ROAMING ADDRESS " + rac.getWACN() + "-" +
- rac.getSystemID() )
- .to( rac.getTargetID() )
- .build() );
-
- mLastCommandEventID = rac.getTargetID();
- }
- break;
- case UNIT_REGISTRATION_COMMAND:
- UnitRegistrationCommand urc = (UnitRegistrationCommand)message;
-
- if( mLastCommandEventID == null || !mLastCommandEventID
- .contentEquals( urc.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.COMMAND )
- .aliasList( getAliasList() )
- .details( "REGISTER" )
- .from( urc.getSourceAddress() )
- .to( urc.getTargetAddress() )
- .build() );
-
- mLastCommandEventID = urc.getTargetAddress();
- }
- break;
- default:
- break;
- }
- }
-
- private void processTSBKMessage( TSBKMessage message )
- {
- MessageUpdate mu = (MessageUpdate)message;
-
- broadcast( new P25CallEvent.Builder( CallEventType.SDM )
- .aliasList( getAliasList() )
- .details( "MESSAGE: " + mu.getMessage() )
- .from( mu.getSourceAddress() )
- .to( mu.getTargetAddress() )
- .build() );
- }
-
- private void processTSBKQuery( TSBKMessage message )
- {
- switch( message.getOpcode() )
- {
- case GROUP_AFFILIATION_QUERY:
- GroupAffiliationQuery gaq = (GroupAffiliationQuery)message;
+ StringBuilder sb = new StringBuilder();
+ sb.append("ROAMING ADDRESS STACK A:");
+ sb.append(raue.getWACNA() + "-" + raue.getSystemIDA());
- if( mLastQueryEventID == null || !mLastQueryEventID
- .contentEquals( gaq.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "GROUP AFFILIATION" )
- .from( gaq.getSourceAddress() )
- .to( gaq.getTargetAddress() )
- .build() );
- }
- break;
- case STATUS_QUERY:
- StatusQuery sq = (StatusQuery)message;
-
- if( mLastQueryEventID == null || !mLastQueryEventID
- .contentEquals( sq.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.QUERY )
- .aliasList( getAliasList() )
- .details( "STATUS QUERY" )
- .from( sq.getSourceAddress() )
- .to( sq.getTargetAddress() )
- .build() );
- }
- break;
- default:
- break;
- }
- }
-
- private void processTSBKResponse( TSBKMessage message )
- {
- switch( message.getOpcode() )
- {
- case ACKNOWLEDGE_RESPONSE:
- AcknowledgeResponse ar = (AcknowledgeResponse)message;
-
- if( mLastResponseEventID == null || !ar.getTargetAddress()
- .contentEquals( mLastResponseEventID ) )
- {
- String to = ar.getTargetAddress();
-
- if( ar.hasAdditionalInformation() && ar.hasExtendedAddress() )
- {
- to = ar.getWACN() + "-" + ar.getSystemID() + "-" +
- ar.getTargetAddress();
- }
-
- String from = null;
-
- if( ar.hasAdditionalInformation() && !ar.hasExtendedAddress() )
- {
- from = ar.getFromID();
- }
+ if(raue.isFormat2())
+ {
+ sb.append(" B:");
+ sb.append(raue.getWACNB() + "-" + raue.getSystemIDB());
+ sb.append(" C:");
+ sb.append(raue.getWACNC() + "-" + raue.getSystemIDC());
+ sb.append(" D:");
+ sb.append(raue.getWACND() + "-" + raue.getSystemIDD());
+ }
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "ACKNOWLEDGE" )
- .from( from )
- .to( to )
- .build() );
-
- mLastResponseEventID = ar.getTargetAddress();
- }
- break;
- case DENY_RESPONSE:
- DenyResponse dr = (DenyResponse)message;
-
- if( mLastResponseEventID == null || !dr.getTargetAddress()
- .contentEquals( mLastResponseEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "DENY REASON: " + dr.getReason().name() +
- " REQUESTED: " + dr.getServiceType().name() )
- .from( dr.getSourceAddress() )
- .to( dr.getTargetAddress() )
- .build() );
-
- mLastResponseEventID = dr.getTargetAddress();
- }
- break;
- case GROUP_AFFILIATION_RESPONSE:
- GroupAffiliationResponse gar = (GroupAffiliationResponse)message;
-
- if( mLastResponseEventID == null || !gar.getTargetAddress()
- .contentEquals( mLastResponseEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "AFFILIATION:" + gar.getResponse().name() +
- " FOR " + gar.getAffiliationScope() +
- " GROUP:" + gar.getGroupAddress() +
- " ANNOUNCEMENT GROUP:" +
- gar.getAnnouncementGroupAddress() )
- .to( gar.getTargetAddress() )
- .build() );
+ if(raue.isFormat3())
+ {
+ sb.append(" E:");
+ sb.append(raue.getWACNE() + "-" + raue.getSystemIDE());
+ sb.append(" F:");
+ sb.append(raue.getWACNF() + "-" + raue.getSystemIDF());
+ sb.append(" G:");
+ sb.append(raue.getWACNG() + "-" + raue.getSystemIDG());
+ }
- mLastResponseEventID = gar.getTargetAddress();
- }
- break;
- case LOCATION_REGISTRATION_RESPONSE:
- LocationRegistrationResponse lrr =
- (LocationRegistrationResponse)message;
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details(sb.toString())
+ .from(raue.getSourceID())
+ .to(raue.getTargetAddress())
+ .build());
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case STATUS_QUERY:
+ if(pdu instanceof StatusQueryExtended)
+ {
+ StatusQueryExtended sq = (StatusQueryExtended) pdu;
- if( lrr.getResponse() == Response.ACCEPT )
- {
- mRegistrations.put( lrr.getTargetAddress(),
- System.currentTimeMillis() );
- }
+ if(mLastQueryEventID == null || !sq.getTargetAddress()
+ .contentEquals(mLastQueryEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("STATUS QUERY")
+ .from(sq.getSourceWACN() + "-" +
+ sq.getSourceSystemID() + "-" +
+ sq.getSourceID())
+ .to(sq.getTargetAddress())
+ .build());
- if( mLastRegistrationEventID == null ||
- !mLastRegistrationEventID.contentEquals( lrr.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.REGISTER )
- .aliasList( getAliasList() )
- .details( "REGISTRATION:" + lrr.getResponse().name() +
- " SITE: " + lrr.getRFSSID() + "-" +
- lrr.getSiteID() )
- .from( lrr.getTargetAddress() )
- .to( lrr.getGroupAddress() )
- .build() );
-
- mLastRegistrationEventID = lrr.getTargetAddress();
- }
- break;
- case PROTECTION_PARAMETER_UPDATE:
- ProtectionParameterUpdate ppu = (ProtectionParameterUpdate)message;
-
- if( mLastResponseEventID == null || !ppu.getTargetAddress()
- .contentEquals( mLastResponseEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "USE ENCRYPTION ALGORITHM:" +
- ppu.getAlgorithm().name() + " KEY:" +
- ppu.getKeyID() )
- .to( ppu.getTargetAddress() )
- .build() );
-
- mLastResponseEventID = ppu.getTargetAddress();
- }
- break;
- case QUEUED_RESPONSE:
- QueuedResponse qr = (QueuedResponse)message;
-
- if( mLastResponseEventID == null || !qr.getTargetAddress()
- .contentEquals( mLastResponseEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "QUEUED REASON: " + qr.getReason().name() +
- " REQUESTED: " + qr.getServiceType().name() )
- .from( qr.getSourceAddress() )
- .to( qr.getTargetAddress() )
- .build() );
-
- mLastResponseEventID = qr.getTargetAddress();
- }
- break;
- case STATUS_UPDATE:
- StatusUpdate su = (StatusUpdate)message;
-
- if( mLastResponseEventID == null || !su.getTargetAddress()
- .contentEquals( mLastResponseEventID ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.RESPONSE )
- .aliasList( getAliasList() )
- .details( "STATUS USER: " + su.getUserStatus() +
- " UNIT: " + su.getUnitStatus() )
- .from( su.getSourceAddress() )
- .to( su.getTargetAddress() )
- .build() );
-
- mLastResponseEventID = su.getTargetAddress();
- }
-
- break;
- case UNIT_REGISTRATION_RESPONSE:
- UnitRegistrationResponse urr = (UnitRegistrationResponse)message;
+ mLastQueryEventID = sq.getToID();
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case STATUS_UPDATE:
+ if(pdu instanceof StatusUpdateExtended)
+ {
+ StatusUpdateExtended su = (StatusUpdateExtended) pdu;
- if( urr.getResponse() == Response.ACCEPT )
- {
- mRegistrations.put( urr.getSourceAddress(),
- System.currentTimeMillis() );
- }
+ if(mLastResponseEventID == null || !mLastResponseEventID
+ .contentEquals(su.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("STATUS USER: " + su.getUserStatus() +
+ " UNIT: " + su.getUnitStatus())
+ .from(su.getSourceWACN() + "-" +
+ su.getSourceSystemID() + "-" +
+ su.getSourceID())
+ .to(su.getTargetAddress())
+ .build());
- if( mLastRegistrationEventID == null ||
- !mLastRegistrationEventID.contentEquals( urr.getSourceAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.REGISTER )
- .aliasList( getAliasList() )
- .details( "REGISTRATION:" + urr.getResponse().name() +
- " SYSTEM: " + urr.getSystemID() +
- " SOURCE ID: " + urr.getSourceID() )
- .from( urr.getSourceAddress() )
- .build() );
-
- mLastRegistrationEventID = urr.getSourceAddress();
- }
- break;
- case UNIT_DEREGISTRATION_ACKNOWLEDGE:
- UnitDeregistrationAcknowledge udr =
- (UnitDeregistrationAcknowledge)message;
+ mLastResponseEventID = su.getTargetAddress();
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case UNIT_REGISTRATION_RESPONSE:
+ if(pdu instanceof UnitRegistrationResponseExtended)
+ {
+ UnitRegistrationResponseExtended urr =
+ (UnitRegistrationResponseExtended) pdu;
- if( mLastRegistrationEventID == null ||
- !mLastRegistrationEventID.contentEquals( udr.getSourceID() ) )
- {
-
- broadcast( new P25CallEvent.Builder( CallEventType.DEREGISTER )
- .aliasList( getAliasList() )
- .from( udr.getSourceID() )
- .build() );
+ if(urr.getResponse() == Response.ACCEPT)
+ {
+ mRegistrations.put(urr.getAssignedSourceAddress(),
+ System.currentTimeMillis());
+ }
- List keysToRemove = new ArrayList();
+ if(mLastRegistrationEventID == null || !mLastRegistrationEventID
+ .contentEquals(urr.getAssignedSourceAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.REGISTER)
+ .aliasList(getAliasList())
+ .details("REGISTRATION:" + urr.getResponse().name() +
+ " FOR EXTERNAL SYSTEM ADDRESS: " +
+ urr.getWACN() + "-" +
+ urr.getSystemID() + "-" +
+ urr.getSourceAddress() +
+ " SOURCE ID: " + urr.getSourceID())
+ .from(urr.getAssignedSourceAddress())
+ .build());
+
+ mLastRegistrationEventID = urr.getAssignedSourceAddress();
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case UNIT_TO_UNIT_ANSWER_REQUEST:
+ if(pdu instanceof UnitToUnitAnswerRequestExplicit)
+ {
+ UnitToUnitAnswerRequestExplicit utuare =
+ (UnitToUnitAnswerRequestExplicit) pdu;
+
+ if(mLastPageEventID == null || !mLastPageEventID
+ .contentEquals(utuare.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .details((utuare.isEmergency() ? "EMERGENCY" : ""))
+ .from(utuare.getWACN() + "-" +
+ utuare.getSystemID() + "-" +
+ utuare.getSourceID())
+ .to(utuare.getTargetAddress())
+ .build());
+
+ mLastPageEventID = utuare.getTargetAddress();
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private void processPDUChannelGrant(PDUMessage pdu)
+ {
+ String channel = null;
+ String from = null;
+ String to = null;
+
+ switch(pdu.getOpcode())
+ {
+ case GROUP_DATA_CHANNEL_GRANT:
+ if(pdu instanceof GroupDataChannelGrantExtended)
+ {
+ GroupDataChannelGrantExtended gdcge =
+ (GroupDataChannelGrantExtended) pdu;
+
+ channel = gdcge.getTransmitChannel();
+ from = gdcge.getSourceAddress();
+ to = gdcge.getGroupAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent callEvent = new P25CallEvent.Builder(CallEventType.DATA_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((gdcge.isEncrypted() ? "ENCRYPTED" : "") +
+ (gdcge.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gdcge.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(callEvent);
+ broadcast(callEvent);
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+
+ if(!mIgnoreDataCalls)
+ {
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_GRANT:
+ if(pdu instanceof GroupVoiceChannelGrantExplicit)
+ {
+ GroupVoiceChannelGrantExplicit gvcge =
+ (GroupVoiceChannelGrantExplicit) pdu;
+
+ channel = gvcge.getTransmitChannel();
+ from = gvcge.getSourceAddress();
+ to = gvcge.getGroupAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent callEvent = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((gvcge.isEncrypted() ? "ENCRYPTED" : "") +
+ (gvcge.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gvcge.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(callEvent);
+ broadcast(callEvent);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case INDIVIDUAL_DATA_CHANNEL_GRANT:
+ if(pdu instanceof IndividualDataChannelGrantExtended)
+ {
+ IndividualDataChannelGrantExtended idcge =
+ (IndividualDataChannelGrantExtended) pdu;
+
+ channel = idcge.getTransmitChannel();
+ from = idcge.getSourceWACN() + "-" +
+ idcge.getSourceSystemID() + "-" +
+ idcge.getSourceAddress();
+ to = idcge.getTargetAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent callEvent = new P25CallEvent.Builder(CallEventType.DATA_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((idcge.isEncrypted() ? "ENCRYPTED" : "") +
+ (idcge.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(idcge.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(callEvent);
+ broadcast(callEvent);
+ }
+
+ if(!mIgnoreDataCalls)
+ {
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
+ TelephoneInterconnectChannelGrantExplicit ticge =
+ (TelephoneInterconnectChannelGrantExplicit) pdu;
+
+ channel = ticge.getTransmitChannel();
+
+ //We don't know if the subscriber is calling or being called, so
+ //we use the same address in both from/to fields
+ from = ticge.getAddress();
+ to = ticge.getAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent callEvent = new P25CallEvent.Builder(CallEventType.TELEPHONE_INTERCONNECT)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((ticge.isEncrypted() ? "ENCRYPTED" : "") +
+ (ticge.isEmergency() ? " EMERGENCY" : "") +
+ " CALL TIMER:" + ticge.getCallTimer())
+ .frequency(ticge.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(callEvent);
+ broadcast(callEvent);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
+ if(pdu instanceof UnitToUnitVoiceChannelGrantExtended)
+ {
+ UnitToUnitVoiceChannelGrantExtended uuvcge =
+ (UnitToUnitVoiceChannelGrantExtended) pdu;
+
+ channel = uuvcge.getTransmitChannel();
+ from = uuvcge.getSourceWACN() + "-" +
+ uuvcge.getSourceSystemID() + "-" +
+ uuvcge.getSourceID();
+ to = uuvcge.getTargetAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent callEvent = new P25CallEvent.Builder(CallEventType.UNIT_TO_UNIT_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((uuvcge.isEncrypted() ? "ENCRYPTED" : "") +
+ (uuvcge.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(uuvcge.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(callEvent);
+ broadcast(callEvent);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
+ if(pdu instanceof UnitToUnitVoiceChannelGrantUpdateExtended)
+ {
+ UnitToUnitVoiceChannelGrantUpdateExtended uuvcgue =
+ (UnitToUnitVoiceChannelGrantUpdateExtended) pdu;
+
+ channel = uuvcgue.getTransmitChannel();
+ from = uuvcgue.getSourceWACN() + "-" +
+ uuvcgue.getSourceSystemID() + "-" +
+ uuvcgue.getSourceID();
+ to = uuvcgue.getTargetAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent callEvent = new P25CallEvent.Builder(CallEventType.UNIT_TO_UNIT_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((uuvcgue.isEncrypted() ? "ENCRYPTED" : "") +
+ (uuvcgue.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(uuvcgue.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(callEvent);
+ broadcast(callEvent);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+
+ }
+ else
+ {
+ logAlternateVendorMessage(pdu);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void processTSBKCommand(TSBKMessage message)
+ {
+ switch(message.getOpcode())
+ {
+ case AUTHENTICATION_COMMAND:
+ AuthenticationCommand ac = (AuthenticationCommand) message;
+
+ if(mLastCommandEventID == null || !mLastCommandEventID
+ .contentEquals(ac.getFullTargetID()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .details("AUTHENTICATE")
+ .to(ac.getWACN() + "-" + ac.getSystemID() + "-" +
+ ac.getTargetID())
+ .build());
+
+ mLastCommandEventID = ac.getFullTargetID();
+ }
+ break;
+ case EXTENDED_FUNCTION_COMMAND:
+ ExtendedFunctionCommand efc = (ExtendedFunctionCommand) message;
+
+ if(mLastCommandEventID == null || !mLastCommandEventID
+ .contentEquals(efc.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.FUNCTION)
+ .aliasList(getAliasList())
+ .details("EXTENDED FUNCTION: " +
+ efc.getExtendedFunction().getLabel())
+ .from(efc.getSourceAddress())
+ .to(efc.getTargetAddress())
+ .build());
+
+ mLastCommandEventID = efc.getTargetAddress();
+ }
+ break;
+ case RADIO_UNIT_MONITOR_COMMAND:
+ RadioUnitMonitorCommand rumc = (RadioUnitMonitorCommand) message;
+
+ if(mLastCommandEventID == null || !mLastCommandEventID
+ .contentEquals(rumc.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .details("RADIO UNIT MONITOR")
+ .from(rumc.getSourceAddress())
+ .to(rumc.getTargetAddress())
+ .build());
+
+ mLastCommandEventID = rumc.getTargetAddress();
+ }
+ break;
+ case ROAMING_ADDRESS_COMMAND:
+ RoamingAddressCommand rac = (RoamingAddressCommand) message;
+
+ if(mLastCommandEventID == null || !mLastCommandEventID
+ .contentEquals(rac.getTargetID()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .details(rac.getStackOperation().name() +
+ " ROAMING ADDRESS " + rac.getWACN() + "-" +
+ rac.getSystemID())
+ .to(rac.getTargetID())
+ .build());
+
+ mLastCommandEventID = rac.getTargetID();
+ }
+ break;
+ case UNIT_REGISTRATION_COMMAND:
+ UnitRegistrationCommand urc = (UnitRegistrationCommand) message;
+
+ if(mLastCommandEventID == null || !mLastCommandEventID
+ .contentEquals(urc.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.COMMAND)
+ .aliasList(getAliasList())
+ .details("REGISTER")
+ .from(urc.getSourceAddress())
+ .to(urc.getTargetAddress())
+ .build());
+
+ mLastCommandEventID = urc.getTargetAddress();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void processTSBKMessage(TSBKMessage message)
+ {
+ MessageUpdate mu = (MessageUpdate) message;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.SDM)
+ .aliasList(getAliasList())
+ .details("MESSAGE: " + mu.getMessage())
+ .from(mu.getSourceAddress())
+ .to(mu.getTargetAddress())
+ .build());
+ }
+
+ private void processTSBKQuery(TSBKMessage message)
+ {
+ switch(message.getOpcode())
+ {
+ case GROUP_AFFILIATION_QUERY:
+ GroupAffiliationQuery gaq = (GroupAffiliationQuery) message;
+
+ if(mLastQueryEventID == null || !mLastQueryEventID
+ .contentEquals(gaq.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("GROUP AFFILIATION")
+ .from(gaq.getSourceAddress())
+ .to(gaq.getTargetAddress())
+ .build());
+ }
+ break;
+ case STATUS_QUERY:
+ StatusQuery sq = (StatusQuery) message;
+
+ if(mLastQueryEventID == null || !mLastQueryEventID
+ .contentEquals(sq.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.QUERY)
+ .aliasList(getAliasList())
+ .details("STATUS QUERY")
+ .from(sq.getSourceAddress())
+ .to(sq.getTargetAddress())
+ .build());
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void processTSBKResponse(TSBKMessage message)
+ {
+ switch(message.getOpcode())
+ {
+ case ACKNOWLEDGE_RESPONSE:
+ AcknowledgeResponse ar = (AcknowledgeResponse) message;
+
+ if(mLastResponseEventID == null || !ar.getTargetAddress()
+ .contentEquals(mLastResponseEventID))
+ {
+ String to = ar.getTargetAddress();
+
+ if(ar.hasAdditionalInformation() && ar.hasExtendedAddress())
+ {
+ to = ar.getWACN() + "-" + ar.getSystemID() + "-" +
+ ar.getTargetAddress();
+ }
+
+ String from = null;
+
+ if(ar.hasAdditionalInformation() && !ar.hasExtendedAddress())
+ {
+ from = ar.getFromID();
+ }
+
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("ACKNOWLEDGE")
+ .from(from)
+ .to(to)
+ .build());
+
+ mLastResponseEventID = ar.getTargetAddress();
+ }
+ break;
+ case DENY_RESPONSE:
+ DenyResponse dr = (DenyResponse) message;
+
+ if(mLastResponseEventID == null || !dr.getTargetAddress()
+ .contentEquals(mLastResponseEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("DENY REASON: " + dr.getReason().name() +
+ " REQUESTED: " + dr.getServiceType().name())
+ .from(dr.getSourceAddress())
+ .to(dr.getTargetAddress())
+ .build());
+
+ mLastResponseEventID = dr.getTargetAddress();
+ }
+ break;
+ case GROUP_AFFILIATION_RESPONSE:
+ GroupAffiliationResponse gar = (GroupAffiliationResponse) message;
+
+ if(mLastResponseEventID == null || !gar.getTargetAddress()
+ .contentEquals(mLastResponseEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("AFFILIATION:" + gar.getResponse().name() +
+ " FOR " + gar.getAffiliationScope() +
+ " GROUP:" + gar.getGroupAddress() +
+ " ANNOUNCEMENT GROUP:" +
+ gar.getAnnouncementGroupAddress())
+ .to(gar.getTargetAddress())
+ .build());
+
+ mLastResponseEventID = gar.getTargetAddress();
+ }
+ break;
+ case LOCATION_REGISTRATION_RESPONSE:
+ LocationRegistrationResponse lrr =
+ (LocationRegistrationResponse) message;
+
+ if(lrr.getResponse() == Response.ACCEPT)
+ {
+ mRegistrations.put(lrr.getTargetAddress(),
+ System.currentTimeMillis());
+ }
+
+ if(mLastRegistrationEventID == null ||
+ !mLastRegistrationEventID.contentEquals(lrr.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.REGISTER)
+ .aliasList(getAliasList())
+ .details("REGISTRATION:" + lrr.getResponse().name() +
+ " SITE: " + lrr.getRFSSID() + "-" +
+ lrr.getSiteID())
+ .from(lrr.getTargetAddress())
+ .to(lrr.getGroupAddress())
+ .build());
+
+ mLastRegistrationEventID = lrr.getTargetAddress();
+ }
+ break;
+ case PROTECTION_PARAMETER_UPDATE:
+ ProtectionParameterUpdate ppu = (ProtectionParameterUpdate) message;
+
+ if(mLastResponseEventID == null || !ppu.getTargetAddress()
+ .contentEquals(mLastResponseEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("USE ENCRYPTION ALGORITHM:" +
+ ppu.getAlgorithm().name() + " KEY:" +
+ ppu.getKeyID())
+ .to(ppu.getTargetAddress())
+ .build());
+
+ mLastResponseEventID = ppu.getTargetAddress();
+ }
+ break;
+ case QUEUED_RESPONSE:
+ QueuedResponse qr = (QueuedResponse) message;
+
+ if(mLastResponseEventID == null || !qr.getTargetAddress()
+ .contentEquals(mLastResponseEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("QUEUED REASON: " + qr.getReason().name() +
+ " REQUESTED: " + qr.getServiceType().name())
+ .from(qr.getSourceAddress())
+ .to(qr.getTargetAddress())
+ .build());
+
+ mLastResponseEventID = qr.getTargetAddress();
+ }
+ break;
+ case STATUS_UPDATE:
+ StatusUpdate su = (StatusUpdate) message;
+
+ if(mLastResponseEventID == null || !su.getTargetAddress()
+ .contentEquals(mLastResponseEventID))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.RESPONSE)
+ .aliasList(getAliasList())
+ .details("STATUS USER: " + su.getUserStatus() +
+ " UNIT: " + su.getUnitStatus())
+ .from(su.getSourceAddress())
+ .to(su.getTargetAddress())
+ .build());
+
+ mLastResponseEventID = su.getTargetAddress();
+ }
+
+ break;
+ case UNIT_REGISTRATION_RESPONSE:
+ UnitRegistrationResponse urr = (UnitRegistrationResponse) message;
+
+ if(urr.getResponse() == Response.ACCEPT)
+ {
+ mRegistrations.put(urr.getSourceAddress(),
+ System.currentTimeMillis());
+ }
+
+ if(mLastRegistrationEventID == null ||
+ !mLastRegistrationEventID.contentEquals(urr.getSourceAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.REGISTER)
+ .aliasList(getAliasList())
+ .details("REGISTRATION:" + urr.getResponse().name() +
+ " SYSTEM: " + urr.getSystemID() +
+ " SOURCE ID: " + urr.getSourceID())
+ .from(urr.getSourceAddress())
+ .build());
+
+ mLastRegistrationEventID = urr.getSourceAddress();
+ }
+ break;
+ case UNIT_DEREGISTRATION_ACKNOWLEDGE:
+ UnitDeregistrationAcknowledge udr =
+ (UnitDeregistrationAcknowledge) message;
+
+ if(mLastRegistrationEventID == null ||
+ !mLastRegistrationEventID.contentEquals(udr.getSourceID()))
+ {
+
+ broadcast(new P25CallEvent.Builder(CallEventType.DEREGISTER)
+ .aliasList(getAliasList())
+ .from(udr.getSourceID())
+ .build());
+
+ List keysToRemove = new ArrayList();
/* Remove this radio from the registrations set */
- for( String key: mRegistrations.keySet() )
- {
- if( key.startsWith( udr.getSourceID() ) )
- {
- keysToRemove.add( key );
- }
- }
-
- for( String key: keysToRemove )
- {
- mRegistrations.remove( key );
- }
+ for(String key : mRegistrations.keySet())
+ {
+ if(key.startsWith(udr.getSourceID()))
+ {
+ keysToRemove.add(key);
+ }
+ }
- mLastRegistrationEventID = udr.getSourceID();
- }
- break;
- default:
- break;
- }
- }
-
- private void processTSBKRFSSStatus( RFSSStatusBroadcast message )
- {
- mRFSSStatusMessage = message;
-
- updateNAC( message.getNAC() );
-
- updateSystem( message.getSystemID() );
-
- updateSite( message.getRFSubsystemID() + "-" + message.getSiteID() );
- }
-
- private void processTSBKDataChannelAnnouncement( TSBKMessage message )
- {
- switch( message.getOpcode() )
- {
- case GROUP_DATA_CHANNEL_ANNOUNCEMENT:
- GroupDataChannelAnnouncement gdca = (GroupDataChannelAnnouncement)message;
-
- broadcast( new P25CallEvent.Builder( CallEventType.ANNOUNCEMENT )
- .aliasList( getAliasList() )
- .channel( gdca.getChannel1() )
- .details( ( gdca.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gdca.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gdca.getDownlinkFrequency1() )
- .to( gdca.getGroupAddress1() )
- .build() );
-
- if( gdca.hasChannelNumber2() )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.ANNOUNCEMENT )
- .aliasList( getAliasList() )
- .channel( gdca.getChannel2() )
- .details( ( gdca.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gdca.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gdca.getDownlinkFrequency2() )
- .to( gdca.getGroupAddress2() )
- .build() );
- }
- break;
- case GROUP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
- GroupDataChannelAnnouncementExplicit gdcae =
- (GroupDataChannelAnnouncementExplicit)message;
-
- broadcast( new P25CallEvent.Builder( CallEventType.DATA_CALL )
- .aliasList( getAliasList() )
- .channel( gdcae.getTransmitChannel() )
- .details( ( gdcae.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gdcae.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gdcae.getDownlinkFrequency() )
- .to( gdcae.getGroupAddress() )
- .build() );
- break;
- default:
- break;
- }
- }
+ for(String key : keysToRemove)
+ {
+ mRegistrations.remove(key);
+ }
- /**
- * Process Motorola vendor-specific Trunking Signaling Block messages
+ mLastRegistrationEventID = udr.getSourceID();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void processTSBKRFSSStatus(RFSSStatusBroadcast message)
+ {
+ mRFSSStatusMessage = message;
+
+ updateNAC(message.getNAC());
+
+ updateSystem(message.getSystemID());
+
+ updateSite(message.getRFSubsystemID() + "-" + message.getSiteID());
+ }
+
+ private void processTSBKDataChannelAnnouncement(TSBKMessage message)
+ {
+ switch(message.getOpcode())
+ {
+ case GROUP_DATA_CHANNEL_ANNOUNCEMENT:
+ GroupDataChannelAnnouncement gdca = (GroupDataChannelAnnouncement) message;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.ANNOUNCEMENT)
+ .aliasList(getAliasList())
+ .channel(gdca.getChannel1())
+ .details((gdca.isEncrypted() ? "ENCRYPTED" : "") +
+ (gdca.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gdca.getDownlinkFrequency1())
+ .to(gdca.getGroupAddress1())
+ .build());
+
+ if(gdca.hasChannelNumber2())
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.ANNOUNCEMENT)
+ .aliasList(getAliasList())
+ .channel(gdca.getChannel2())
+ .details((gdca.isEncrypted() ? "ENCRYPTED" : "") +
+ (gdca.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gdca.getDownlinkFrequency2())
+ .to(gdca.getGroupAddress2())
+ .build());
+ }
+ break;
+ case GROUP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
+ GroupDataChannelAnnouncementExplicit gdcae =
+ (GroupDataChannelAnnouncementExplicit) message;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.DATA_CALL)
+ .aliasList(getAliasList())
+ .channel(gdcae.getTransmitChannel())
+ .details((gdcae.isEncrypted() ? "ENCRYPTED" : "") +
+ (gdcae.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gdcae.getDownlinkFrequency())
+ .to(gdcae.getGroupAddress())
+ .build());
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Process Motorola vendor-specific Trunking Signaling Block messages
*/
- private void processMotorolaTSBK(MotorolaTSBKMessage tsbk)
- {
- String channel;
- String from;
- String to;
+ private void processMotorolaTSBK(MotorolaTSBKMessage tsbk)
+ {
+ String channel;
+ String from;
+ String to;
- switch(((MotorolaTSBKMessage)tsbk).getMotorolaOpcode())
- {
- case PATCH_GROUP_CHANNEL_GRANT:
- PatchGroupVoiceChannelGrant gvcg = (PatchGroupVoiceChannelGrant)tsbk;
+ switch(((MotorolaTSBKMessage) tsbk).getMotorolaOpcode())
+ {
+ case PATCH_GROUP_CHANNEL_GRANT:
+ PatchGroupVoiceChannelGrant gvcg = (PatchGroupVoiceChannelGrant) tsbk;
- channel = gvcg.getChannel();
- from = gvcg.getSourceAddress();
- to = gvcg.getPatchGroupAddress();
+ channel = gvcg.getChannel();
+ from = gvcg.getSourceAddress();
+ to = gvcg.getPatchGroupAddress();
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.PATCH_GROUP_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( gvcg.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( gvcg.isEmergency() ? " EMERGENCY " : "") +
- "PATCH SESSION MODE:" + gvcg.getSessionMode().name())
- .frequency( gvcg.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((gvcg.isEncrypted() ? "ENCRYPTED " : "") +
+ (gvcg.isEmergency() ? " EMERGENCY " : "") +
+ "PATCH SESSION MODE:" + gvcg.getSessionMode().name())
+ .frequency(gvcg.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
- registerCallEvent( event );
- broadcast( event );
- }
+ registerCallEvent(event);
+ broadcast(event);
+ }
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case PATCH_GROUP_CHANNEL_GRANT_UPDATE:
- PatchGroupVoiceChannelGrantUpdate gvcgu = (PatchGroupVoiceChannelGrantUpdate) tsbk;
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case PATCH_GROUP_CHANNEL_GRANT_UPDATE:
+ PatchGroupVoiceChannelGrantUpdate gvcgu = (PatchGroupVoiceChannelGrantUpdate) tsbk;
- channel = gvcgu.getChannel1();
- to = gvcgu.getPatchGroupAddress1();
+ channel = gvcgu.getChannel1();
+ to = gvcgu.getPatchGroupAddress1();
- if( hasCallEvent( channel, null, to ) )
- {
- updateCallEvent( channel, null, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.PATCH_GROUP_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( gvcgu.isEncrypted() ? "ENCRYPTED " : "" ) +
- "PATCH UPDATE - GROUP 2:" + gvcgu.getPatchGroupAddress2() +
- " DN:" + gvcgu.getDownlinkFrequency2())
- .frequency( gvcgu.getDownlinkFrequency1() )
- .to( to )
- .build();
+ if(hasCallEvent(channel, null, to))
+ {
+ updateCallEvent(channel, null, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((gvcgu.isEncrypted() ? "ENCRYPTED " : "") +
+ "PATCH UPDATE - GROUP 2:" + gvcgu.getPatchGroupAddress2() +
+ " DN:" + gvcgu.getDownlinkFrequency2())
+ .frequency(gvcgu.getDownlinkFrequency1())
+ .to(to)
+ .build();
- registerCallEvent( event );
- broadcast( event );
- }
+ registerCallEvent(event);
+ broadcast(event);
+ }
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case PATCH_GROUP_ADD:
- PatchGroupAdd pga = (PatchGroupAdd)tsbk;
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case PATCH_GROUP_ADD:
+ PatchGroupAdd pga = (PatchGroupAdd) tsbk;
- StringBuilder sb = new StringBuilder();
+ if(addPatchGroup(pga.getPatchGroupAddress(), pga.getPatchedTalkgroups()))
+ {
+ StringBuilder sb = new StringBuilder();
- sb.append("PATCH GROUP:").append(pga.getPatchGroupAddress());
- sb.append(" 1:").append(pga.getGroupAddress1());
- sb.append(" 2:").append(pga.getGroupAddress2());
- sb.append(" 3:").append(pga.getGroupAddress3());
+ sb.append("PATCH GROUP:").append(pga.getPatchGroupAddress());
+ sb.append(" ").append(pga.getPatchedTalkgroups());
- broadcast( new P25CallEvent.Builder( CallEventType.PATCH_GROUP_ADD )
- .aliasList( getAliasList() )
- .details( sb.toString() )
- .build() );
- break;
- case PATCH_GROUP_DELETE:
- PatchGroupDelete pgd = (PatchGroupDelete)tsbk;
+ broadcast(new P25CallEvent.Builder(CallEventType.PATCH_GROUP_ADD)
+ .aliasList(getAliasList())
+ .details(sb.toString())
+ .build());
+ }
+ break;
+ case PATCH_GROUP_DELETE:
+ PatchGroupDelete pgd = (PatchGroupDelete) tsbk;
- StringBuilder sbpgd = new StringBuilder();
+ if(removePatchGroup(pgd.getPatchGroupAddress(), pgd.getPatchedTalkgroups()))
+ {
+ StringBuilder sbpgd = new StringBuilder();
- sbpgd.append("PATCH GROUP:").append(pgd.getPatchGroupAddress());
- sbpgd.append(" 1:").append(pgd.getGroupAddress1());
- sbpgd.append(" 2:").append(pgd.getGroupAddress2());
- sbpgd.append(" 3:").append(pgd.getGroupAddress3());
+ sbpgd.append("PATCH GROUP:").append(pgd.getPatchGroupAddress());
+ sbpgd.append(" ").append(pgd.getPatchedTalkgroups());
- broadcast( new P25CallEvent.Builder( CallEventType.PATCH_GROUP_DELETE )
- .aliasList( getAliasList() )
- .details( sbpgd.toString() )
- .build() );
- break;
- case CCH_PLANNED_SHUTDOWN:
- if( !mControlChannelShutdownLogged )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.NOTIFICATION )
- .details( "PLANNED CONTROL CHANNEL SHUTDOWN" )
- .build() );
+ broadcast(new P25CallEvent.Builder(CallEventType.PATCH_GROUP_DELETE)
+ .aliasList(getAliasList())
+ .details(sbpgd.toString())
+ .build());
+ }
+ break;
+ case CCH_PLANNED_SHUTDOWN:
+ if(!mControlChannelShutdownLogged)
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.NOTIFICATION)
+ .details("PLANNED CONTROL CHANNEL SHUTDOWN")
+ .build());
- mControlChannelShutdownLogged = true;
- }
- break;
- }
- }
+ mControlChannelShutdownLogged = true;
+ }
+ break;
+ }
+ }
- /**
- * Process a traffic channel allocation message
- */
- private void processTSBKChannelGrant( TSBKMessage message )
- {
- String channel = null;
- String from = null;
- String to = null;
-
- switch( message.getOpcode() )
- {
- case GROUP_DATA_CHANNEL_GRANT:
- GroupDataChannelGrant gdcg = (GroupDataChannelGrant)message;
+ /**
+ * Creates a new patch group or updates an existing patch group with the patched talkgroup entries.
+ *
+ * @param patchGroupID for the patch group
+ * @param talkgroupsToAdd to include in the patch group
+ * @return true if the patch group or the patch group map was updated
+ */
+ private boolean addPatchGroup(String patchGroupID, List talkgroupsToAdd)
+ {
+ boolean updated = false;
- channel = gdcg.getChannel();
- from = gdcg.getSourceAddress();
- to = gdcg.getGroupAddress();
+ if(patchGroupID != null && !talkgroupsToAdd.isEmpty())
+ {
+ List patchedTalkgroups = mPatchGroupMap.get(patchGroupID);
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.DATA_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( gdcg.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gdcg.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gdcg.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
+ if(patchedTalkgroups == null)
+ {
+ patchedTalkgroups = new ArrayList<>();
+ }
- registerCallEvent( event );
- broadcast( event );
- }
-
- if( !mIgnoreDataCalls )
- {
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- break;
- case GROUP_VOICE_CHANNEL_GRANT:
- GroupVoiceChannelGrant gvcg = (GroupVoiceChannelGrant)message;
+ for(String talkgroupToAdd: talkgroupsToAdd)
+ {
+ if(!patchedTalkgroups.contains(talkgroupToAdd))
+ {
+ patchedTalkgroups.add(talkgroupToAdd);
+ updated = true;
+ }
+ }
- channel = gvcg.getChannel();
- from = gvcg.getSourceAddress();
- to = gvcg.getGroupAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( gvcg.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gvcg.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gvcg.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
+ if(updated)
+ {
+ mPatchGroupMap.put(patchGroupID, patchedTalkgroups);
+ updatePatchAlias(patchGroupID, patchedTalkgroups);
+ }
+ }
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
- GroupVoiceChannelGrantUpdate gvcgu =
- (GroupVoiceChannelGrantUpdate)message;
+ return updated;
+ }
- channel = gvcgu.getChannel1();
- from = null;
- to = gvcgu.getGroupAddress1();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .channel( gvcgu.getChannel1() )
- .details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gvcgu.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gvcgu.getDownlinkFrequency1() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
+ /**
+ * Removes the patched talkgroups from the patch group and removes the patch group from the patch group map if
+ * there are no more patched talkgroups in the patch group.
+ *
+ * @param patchGroupID for the patch group
+ * @param talkgroupsToRemove to remove from the patch group
+ * @return true if the patch group or the patch group map was updated
+ */
+ private boolean removePatchGroup(String patchGroupID, List talkgroupsToRemove)
+ {
+ boolean updated = false;
- if( gvcgu.hasChannelNumber2() )
- {
- channel = gvcgu.getChannel2();
- to = gvcgu.getGroupAddress2();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event2 = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
- .aliasList( getAliasList() )
- .channel( gvcgu.getChannel2() )
- .details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gvcgu.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gvcgu.getDownlinkFrequency2() )
- .to( gvcgu.getGroupAddress2() )
- .build();
-
- registerCallEvent( event2 );
- broadcast( event2 );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- break;
- case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
- GroupVoiceChannelGrantUpdateExplicit gvcgue =
- (GroupVoiceChannelGrantUpdateExplicit)message;
+ if(patchGroupID != null && !talkgroupsToRemove.isEmpty())
+ {
+ List patchedTalkgroups = mPatchGroupMap.get(patchGroupID);
- channel = gvcgue.getTransmitChannelIdentifier() + "-" +
- gvcgue.getTransmitChannelNumber();
- from = null;
- to = gvcgue.getGroupAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( gvcgue.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( gvcgue.isEmergency() ? " EMERGENCY" : "") )
- .frequency( gvcgue.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
+ if(patchedTalkgroups != null)
+ {
+ for(String talkgroupToRemove: talkgroupsToRemove)
+ {
+ if(patchedTalkgroups.contains(talkgroupToRemove))
+ {
+ patchedTalkgroups.remove(talkgroupToRemove);
+ updated = true;
+ }
+ }
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case INDIVIDUAL_DATA_CHANNEL_GRANT:
- IndividualDataChannelGrant idcg = (IndividualDataChannelGrant)message;
+ if(patchedTalkgroups.isEmpty())
+ {
+ mPatchGroupMap.remove(patchGroupID);
+ removePatchGroupAlias(patchGroupID);
+ updated = true;
+ }
+ else
+ {
+ updatePatchAlias(patchGroupID, patchedTalkgroups);
+ }
+ }
+ }
- channel = idcg.getChannel();
- from = idcg.getSourceAddress();
- to = idcg.getTargetAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.DATA_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( idcg.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( idcg.isEmergency() ? " EMERGENCY" : "") )
- .frequency( idcg.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
-
- if( !mIgnoreDataCalls )
- {
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- break;
- case SNDCP_DATA_CHANNEL_GRANT:
- SNDCPDataChannelGrant sdcg = (SNDCPDataChannelGrant)message;
-
- channel = sdcg.getTransmitChannel();
- from = null;
- to = sdcg.getTargetAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder( CallEventType.DATA_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( sdcg.isEncrypted() ? "ENCRYPTED" : "" ) +
- ( sdcg.isEmergency() ? " EMERGENCY" : "") )
- .frequency( sdcg.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
-
- if( !mIgnoreDataCalls )
- {
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- }
- break;
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
- TelephoneInterconnectVoiceChannelGrant tivcg =
- (TelephoneInterconnectVoiceChannelGrant)message;
-
- channel = tivcg.getChannel();
- from = null;
+ return updated;
+ }
+
+ /**
+ * Adds/updates a patch group alias to the alias list containing aliases for each of the patched talkgroups
+ *
+ * @param patchGroupID for the patch group
+ * @param patchedTalkgroups containing the talkgroup IDs for each of the patched talkgroups
+ */
+ private void updatePatchAlias(String patchGroupID, List patchedTalkgroups)
+ {
+ PatchGroupAlias patchGroupAlias = null;
+
+ //Check for an existing alias for the patch talkgroup
+ Alias alias = getAliasList().getTalkgroupAlias(patchGroupID);
+
+ if(alias instanceof PatchGroupAlias)
+ {
+ patchGroupAlias = (PatchGroupAlias)alias;
+ }
+ else if(alias != null)
+ {
+ //If the talkgroup is already aliased to a non-patch group, do nothing
+ }
+ else
+ {
+ patchGroupAlias = new PatchGroupAlias();
+ patchGroupAlias.addAliasID(new TalkgroupID(patchGroupID));
+ getAliasList().addAlias(patchGroupAlias);
+ }
+
+ if(patchGroupAlias != null)
+ {
+ patchGroupAlias.clearPatchedAliases();
+
+ for(String patchedTalkgroup: patchedTalkgroups)
+ {
+ Alias patchedAlias = getAliasList().getTalkgroupAlias(patchedTalkgroup);
+
+ if(patchedAlias != null)
+ {
+ patchGroupAlias.addPatchedAlias(patchedAlias);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes the temporary patch group alias from the alias list
+ */
+ private void removePatchGroupAlias(String patchGroupID)
+ {
+ Alias alias = getAliasList().getTalkgroupAlias(patchGroupID);
+
+ if(alias instanceof PatchGroupAlias)
+ {
+ getAliasList().removeAlias(alias);
+ }
+ }
+
+ /**
+ * Process a traffic channel allocation message
+ */
+ private void processTSBKChannelGrant(TSBKMessage message)
+ {
+ String channel = null;
+ String from = null;
+ String to = null;
+
+ switch(message.getOpcode())
+ {
+ case GROUP_DATA_CHANNEL_GRANT:
+ GroupDataChannelGrant gdcg = (GroupDataChannelGrant) message;
+
+ channel = gdcg.getChannel();
+ from = gdcg.getSourceAddress();
+ to = gdcg.getGroupAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((gdcg.isEncrypted() ? "ENCRYPTED" : "") +
+ (gdcg.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gdcg.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ if(!mIgnoreDataCalls)
+ {
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_GRANT:
+ GroupVoiceChannelGrant gvcg = (GroupVoiceChannelGrant) message;
+
+ channel = gvcg.getChannel();
+ from = gvcg.getSourceAddress();
+ to = gvcg.getGroupAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((gvcg.isEncrypted() ? "ENCRYPTED" : "") +
+ (gvcg.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gvcg.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
+ GroupVoiceChannelGrantUpdate gvcgu =
+ (GroupVoiceChannelGrantUpdate) message;
+
+ channel = gvcgu.getChannel1();
+ from = null;
+ to = gvcgu.getGroupAddress1();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .channel(gvcgu.getChannel1())
+ .details((gvcgu.isEncrypted() ? "ENCRYPTED" : "") +
+ (gvcgu.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gvcgu.getDownlinkFrequency1())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+
+ if(gvcgu.hasChannelNumber2())
+ {
+ channel = gvcgu.getChannel2();
+ to = gvcgu.getGroupAddress2();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event2 = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
+ .aliasList(getAliasList())
+ .channel(gvcgu.getChannel2())
+ .details((gvcgu.isEncrypted() ? "ENCRYPTED" : "") +
+ (gvcgu.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gvcgu.getDownlinkFrequency2())
+ .to(gvcgu.getGroupAddress2())
+ .build();
+
+ registerCallEvent(event2);
+ broadcast(event2);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ break;
+ case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
+ GroupVoiceChannelGrantUpdateExplicit gvcgue =
+ (GroupVoiceChannelGrantUpdateExplicit) message;
+
+ channel = gvcgue.getTransmitChannelIdentifier() + "-" +
+ gvcgue.getTransmitChannelNumber();
+ from = null;
+ to = gvcgue.getGroupAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((gvcgue.isEncrypted() ? "ENCRYPTED" : "") +
+ (gvcgue.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(gvcgue.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case INDIVIDUAL_DATA_CHANNEL_GRANT:
+ IndividualDataChannelGrant idcg = (IndividualDataChannelGrant) message;
+
+ channel = idcg.getChannel();
+ from = idcg.getSourceAddress();
+ to = idcg.getTargetAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((idcg.isEncrypted() ? "ENCRYPTED" : "") +
+ (idcg.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(idcg.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ if(!mIgnoreDataCalls)
+ {
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ break;
+ case SNDCP_DATA_CHANNEL_GRANT:
+ SNDCPDataChannelGrant sdcg = (SNDCPDataChannelGrant) message;
+
+ channel = sdcg.getTransmitChannel();
+ from = null;
+ to = sdcg.getTargetAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((sdcg.isEncrypted() ? "ENCRYPTED" : "") +
+ (sdcg.isEmergency() ? " EMERGENCY" : ""))
+ .frequency(sdcg.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ if(!mIgnoreDataCalls)
+ {
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ }
+ break;
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
+ TelephoneInterconnectVoiceChannelGrant tivcg =
+ (TelephoneInterconnectVoiceChannelGrant) message;
+
+ channel = tivcg.getChannel();
+ from = null;
/* Address is ambiguous and could mean either source or target,
* so we'll place the value in the to field */
- to = tivcg.getAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder(
- CallEventType.TELEPHONE_INTERCONNECT )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( tivcg.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( tivcg.isEmergency() ? "EMERGENCY " : "") +
- "CALL TIMER:" + tivcg.getCallTimer() )
- .frequency( tivcg.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
+ to = tivcg.getAddress();
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
- TelephoneInterconnectVoiceChannelGrantUpdate tivcgu =
- (TelephoneInterconnectVoiceChannelGrantUpdate)message;
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(
+ CallEventType.TELEPHONE_INTERCONNECT)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((tivcg.isEncrypted() ? "ENCRYPTED " : "") +
+ (tivcg.isEmergency() ? "EMERGENCY " : "") +
+ "CALL TIMER:" + tivcg.getCallTimer())
+ .frequency(tivcg.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
+ TelephoneInterconnectVoiceChannelGrantUpdate tivcgu =
+ (TelephoneInterconnectVoiceChannelGrantUpdate) message;
+
+ channel = tivcgu.getChannelIdentifier() + "-" +
+ tivcgu.getChannelNumber();
+ from = null;
- channel = tivcgu.getChannelIdentifier() + "-" +
- tivcgu.getChannelNumber();
- from = null;
-
/* Address is ambiguous and could mean either source or target,
* so we'll place the value in the to field */
- to = tivcgu.getAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder(
- CallEventType.TELEPHONE_INTERCONNECT )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( tivcgu.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( tivcgu.isEmergency() ? "EMERGENCY " : "") +
- "CALL TIMER:" + tivcgu.getCallTimer() )
- .frequency( tivcgu.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
+ to = tivcgu.getAddress();
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
- UnitToUnitVoiceChannelGrant uuvcg =
- (UnitToUnitVoiceChannelGrant)message;
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(
+ CallEventType.TELEPHONE_INTERCONNECT)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((tivcgu.isEncrypted() ? "ENCRYPTED " : "") +
+ (tivcgu.isEmergency() ? "EMERGENCY " : "") +
+ "CALL TIMER:" + tivcgu.getCallTimer())
+ .frequency(tivcgu.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
- channel = uuvcg.getChannelIdentifier() + "-" +
- uuvcg.getChannelNumber();
- from = uuvcg.getSourceAddress();
- to = uuvcg.getTargetAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder(
- CallEventType.UNIT_TO_UNIT_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( uuvcg.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( uuvcg.isEmergency() ? "EMERGENCY " : "") )
- .frequency( uuvcg.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
- UnitToUnitVoiceChannelGrantUpdate uuvcgu =
- (UnitToUnitVoiceChannelGrantUpdate)message;
+ registerCallEvent(event);
+ broadcast(event);
+ }
- channel = uuvcgu.getChannelIdentifier() + "-" +
- uuvcgu.getChannelNumber();
- from = uuvcgu.getSourceAddress();
- to = uuvcgu.getTargetAddress();
-
- if( hasCallEvent( channel, from, to ) )
- {
- updateCallEvent( channel, from, to );
- }
- else
- {
- P25CallEvent event = new P25CallEvent.Builder(
- CallEventType.UNIT_TO_UNIT_CALL )
- .aliasList( getAliasList() )
- .channel( channel )
- .details( ( uuvcgu.isEncrypted() ? "ENCRYPTED " : "" ) +
- ( uuvcgu.isEmergency() ? "EMERGENCY " : "") )
- .frequency( uuvcgu.getDownlinkFrequency() )
- .from( from )
- .to( to )
- .build();
-
- registerCallEvent( event );
- broadcast( event );
- }
-
- broadcast( new TrafficChannelAllocationEvent( this,
- mChannelCallMap.get( channel ) ) );
- break;
- default:
- break;
- }
- }
-
- /**
- * Broadcasts an update for the TO group or unit address
- */
- private void updateTo( final String to )
- {
- if( to != null && !to.contentEquals( "0000" ) && !to.contentEquals( "000000" ) )
- {
- if( mToTalkgroup == null || !mToTalkgroup.contentEquals( to ) )
- {
- mToTalkgroup = to;
-
- broadcast( ChangedAttribute.TO_TALKGROUP );
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
+ UnitToUnitVoiceChannelGrant uuvcg =
+ (UnitToUnitVoiceChannelGrant) message;
- if( hasAliasList() )
- {
- mToAlias = getAliasList().getTalkgroupAlias( mToTalkgroup );
- }
- else
- {
- mToAlias = null;
- }
+ channel = uuvcg.getChannelIdentifier() + "-" +
+ uuvcg.getChannelNumber();
+ from = uuvcg.getSourceAddress();
+ to = uuvcg.getTargetAddress();
- broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(
+ CallEventType.UNIT_TO_UNIT_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((uuvcg.isEncrypted() ? "ENCRYPTED " : "") +
+ (uuvcg.isEmergency() ? "EMERGENCY " : ""))
+ .frequency(uuvcg.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
+ UnitToUnitVoiceChannelGrantUpdate uuvcgu =
+ (UnitToUnitVoiceChannelGrantUpdate) message;
+
+ channel = uuvcgu.getChannelIdentifier() + "-" +
+ uuvcgu.getChannelNumber();
+ from = uuvcgu.getSourceAddress();
+ to = uuvcgu.getTargetAddress();
+
+ if(hasCallEvent(channel, from, to))
+ {
+ updateCallEvent(channel, from, to);
+ }
+ else
+ {
+ P25CallEvent event = new P25CallEvent.Builder(
+ CallEventType.UNIT_TO_UNIT_CALL)
+ .aliasList(getAliasList())
+ .channel(channel)
+ .details((uuvcgu.isEncrypted() ? "ENCRYPTED " : "") +
+ (uuvcgu.isEmergency() ? "EMERGENCY " : ""))
+ .frequency(uuvcgu.getDownlinkFrequency())
+ .from(from)
+ .to(to)
+ .build();
+
+ registerCallEvent(event);
+ broadcast(event);
+ }
+
+ broadcast(new TrafficChannelAllocationEvent(this,
+ mChannelCallMap.get(channel)));
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Broadcasts an update for the TO group or unit address
+ */
+ private void updateTo(final String to)
+ {
+ if(to != null && !to.contentEquals("0000") && !to.contentEquals("000000"))
+ {
+ if(mToTalkgroup == null || !mToTalkgroup.contentEquals(to))
+ {
+ mToTalkgroup = to;
+
+ broadcast(ChangedAttribute.TO_TALKGROUP);
+
+ if(hasAliasList())
+ {
+ mToAlias = getAliasList().getTalkgroupAlias(mToTalkgroup);
+ }
+ else
+ {
+ mToAlias = null;
+ }
+
+ broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS);
/* Send audio metadata update */
- broadcast( new Metadata( MetadataType.TO, mToTalkgroup, mToAlias, true ) );
+ broadcast(new Metadata(MetadataType.TO, mToTalkgroup, mToAlias, true));
- if( mCurrentCallEvent != null &&
- ( mCurrentCallEvent.getToID() == null ||
- !mCurrentCallEvent.getToID().contentEquals( to ) ) )
- {
- mCurrentCallEvent.setToID( to );
- broadcast( mCurrentCallEvent );
- }
- }
- }
- }
+ if(mCurrentCallEvent != null &&
+ (mCurrentCallEvent.getToID() == null ||
+ !mCurrentCallEvent.getToID().contentEquals(to)))
+ {
+ mCurrentCallEvent.setToID(to);
+ broadcast(mCurrentCallEvent);
+ }
+ }
+ }
+ }
- /**
- * Broadcasts an update for the FROM group or unit address
- */
- private void updateFrom( final String from )
- {
- if( from != null && !from.contentEquals( "0000" ) && !from.contentEquals( "000000" ) )
- {
- if( mFromTalkgroup == null || !mFromTalkgroup.contentEquals( from ))
- {
- mFromTalkgroup = from;
- broadcast( ChangedAttribute.FROM_TALKGROUP );
-
- if( hasAliasList() )
- {
- mFromAlias = getAliasList().getTalkgroupAlias( mFromTalkgroup );
- }
- else
- {
- mFromAlias = null;
- }
-
- broadcast( ChangedAttribute.FROM_TALKGROUP_ALIAS );
+ /**
+ * Broadcasts an update for the FROM group or unit address
+ */
+ private void updateFrom(final String from)
+ {
+ if(from != null && !from.contentEquals("0000") && !from.contentEquals("000000"))
+ {
+ if(mFromTalkgroup == null || !mFromTalkgroup.contentEquals(from))
+ {
+ mFromTalkgroup = from;
+ broadcast(ChangedAttribute.FROM_TALKGROUP);
+
+ if(hasAliasList())
+ {
+ mFromAlias = getAliasList().getTalkgroupAlias(mFromTalkgroup);
+ }
+ else
+ {
+ mFromAlias = null;
+ }
+
+ broadcast(ChangedAttribute.FROM_TALKGROUP_ALIAS);
/* Send audio metadata update */
- broadcast( new Metadata( MetadataType.FROM, mFromTalkgroup, mFromAlias, true ) );
+ broadcast(new Metadata(MetadataType.FROM, mFromTalkgroup, mFromAlias, true));
- if( mCurrentCallEvent != null &&
- ( mCurrentCallEvent.getFromID() == null ||
- !mCurrentCallEvent.getFromID().contentEquals( from ) ) )
- {
- mCurrentCallEvent.setFromID( from );
- broadcast( mCurrentCallEvent );
- }
- }
+ if(mCurrentCallEvent != null &&
+ (mCurrentCallEvent.getFromID() == null ||
+ !mCurrentCallEvent.getFromID().contentEquals(from)))
+ {
+ mCurrentCallEvent.setFromID(from);
+ broadcast(mCurrentCallEvent);
+ }
+ }
- }
- }
-
- /**
- * Broadcasts an update to the NAC
- */
- private void updateNAC( String nac )
- {
- if( mNAC == null || ( nac != null && !mNAC.contentEquals( nac ) ) )
- {
- mNAC = nac;
-
- broadcast( ChangedAttribute.NAC );
- }
- }
-
- /**
- * Updates the site information
- */
- private void updateSite( String site )
- {
- if( mSite == null || ( site != null && !mSite.contentEquals( site ) ) )
- {
- mSite = site;
-
- broadcast( ChangedAttribute.SITE );
-
- if( hasAliasList() )
- {
- Alias alias = getAliasList().getSiteID( mSite );
-
- if( alias != null )
- {
- mSiteAlias = alias.getName();
- }
- else
- {
- mSiteAlias = null;
- }
- }
+ }
+ }
- broadcast( ChangedAttribute.SITE_ALIAS );
- }
- }
-
- private void updateSystem( String system )
- {
- if( mSystem == null || ( system != null && !mSystem.contentEquals( system ) ) )
- {
- mSystem = system;
-
- broadcast( ChangedAttribute.SYSTEM );
- }
- }
-
- /**
- * Process a unit paging event message
- */
- private void processTSBKPage( TSBKMessage message )
- {
- switch( message.getOpcode() )
- {
- case CALL_ALERT:
- CallAlert ca = (CallAlert)message;
-
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .from( ca.getSourceID() )
- .to( ca.getTargetAddress() )
- .build() );
- break;
- case UNIT_TO_UNIT_ANSWER_REQUEST:
- UnitToUnitAnswerRequest utuar = (UnitToUnitAnswerRequest)message;
-
- if( mLastPageEventID == null || !mLastPageEventID
- .contentEquals( utuar.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .details( ( utuar.isEmergency() ? "EMERGENCY" : "" ) )
- .from( utuar.getSourceAddress() )
- .to( utuar.getTargetAddress() )
- .build() );
-
- mLastPageEventID = utuar.getTargetAddress();
- }
- break;
- case SNDCP_DATA_PAGE_REQUEST:
- SNDCPDataPageRequest sdpr = (SNDCPDataPageRequest)message;
-
- if( mLastPageEventID == null || !mLastPageEventID
- .contentEquals( sdpr.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .details( "SNDCP DATA DAC: " +
- sdpr.getDataAccessControl() +
- " NSAPI:" + sdpr.getNSAPI() )
- .to( sdpr.getTargetAddress() )
- .build() );
-
- mLastPageEventID = sdpr.getTargetAddress();
- }
- break;
- case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
- TelephoneInterconnectAnswerRequest tiar =
- (TelephoneInterconnectAnswerRequest)message;
+ /**
+ * Broadcasts an update to the NAC
+ */
+ private void updateNAC(String nac)
+ {
+ if(mNAC == null || (nac != null && !mNAC.contentEquals(nac)))
+ {
+ mNAC = nac;
- if( mLastPageEventID == null || !mLastPageEventID
- .contentEquals( tiar.getTargetAddress() ) )
- {
- broadcast( new P25CallEvent.Builder( CallEventType.PAGE )
- .aliasList( getAliasList() )
- .details( ( "TELEPHONE INTERCONNECT" ) )
- .from( tiar.getTelephoneNumber() )
- .to( tiar.getTargetAddress() )
- .build() );
-
- mLastPageEventID = tiar.getTargetAddress();
- }
- break;
- default:
- break;
- }
- }
-
- @Override
+ broadcast(ChangedAttribute.NAC);
+ }
+ }
+
+ /**
+ * Updates the site information
+ */
+ private void updateSite(String site)
+ {
+ if(mSite == null || (site != null && !mSite.contentEquals(site)))
+ {
+ mSite = site;
+
+ broadcast(ChangedAttribute.SITE);
+
+ if(hasAliasList())
+ {
+ Alias alias = getAliasList().getSiteID(mSite);
+
+ if(alias != null)
+ {
+ mSiteAlias = alias.getName();
+ }
+ else
+ {
+ mSiteAlias = null;
+ }
+ }
+
+ broadcast(ChangedAttribute.SITE_ALIAS);
+ }
+ }
+
+ private void updateSystem(String system)
+ {
+ if(mSystem == null || (system != null && !mSystem.contentEquals(system)))
+ {
+ mSystem = system;
+
+ broadcast(ChangedAttribute.SYSTEM);
+ }
+ }
+
+ /**
+ * Process a unit paging event message
+ */
+ private void processTSBKPage(TSBKMessage message)
+ {
+ switch(message.getOpcode())
+ {
+ case CALL_ALERT:
+ CallAlert ca = (CallAlert) message;
+
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .from(ca.getSourceID())
+ .to(ca.getTargetAddress())
+ .build());
+ break;
+ case UNIT_TO_UNIT_ANSWER_REQUEST:
+ UnitToUnitAnswerRequest utuar = (UnitToUnitAnswerRequest) message;
+
+ if(mLastPageEventID == null || !mLastPageEventID
+ .contentEquals(utuar.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .details((utuar.isEmergency() ? "EMERGENCY" : ""))
+ .from(utuar.getSourceAddress())
+ .to(utuar.getTargetAddress())
+ .build());
+
+ mLastPageEventID = utuar.getTargetAddress();
+ }
+ break;
+ case SNDCP_DATA_PAGE_REQUEST:
+ SNDCPDataPageRequest sdpr = (SNDCPDataPageRequest) message;
+
+ if(mLastPageEventID == null || !mLastPageEventID
+ .contentEquals(sdpr.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .details("SNDCP DATA DAC: " +
+ sdpr.getDataAccessControl() +
+ " NSAPI:" + sdpr.getNSAPI())
+ .to(sdpr.getTargetAddress())
+ .build());
+
+ mLastPageEventID = sdpr.getTargetAddress();
+ }
+ break;
+ case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
+ TelephoneInterconnectAnswerRequest tiar =
+ (TelephoneInterconnectAnswerRequest) message;
+
+ if(mLastPageEventID == null || !mLastPageEventID
+ .contentEquals(tiar.getTargetAddress()))
+ {
+ broadcast(new P25CallEvent.Builder(CallEventType.PAGE)
+ .aliasList(getAliasList())
+ .details(("TELEPHONE INTERCONNECT"))
+ .from(tiar.getTelephoneNumber())
+ .to(tiar.getTargetAddress())
+ .build());
+
+ mLastPageEventID = tiar.getTargetAddress();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
public String getActivitySummary()
{
- StringBuilder sb = new StringBuilder();
+ StringBuilder sb = new StringBuilder();
- sb.append( "Activity Summary\n" );
- sb.append( "Decoder:\tP25\n" );
- sb.append( "===================== THIS SITE ======================" );
-
- if( mNetworkStatus != null )
- {
- sb.append( "\nNAC:\t" + mNetworkStatus.getNAC() );
- sb.append( "\nWACN-SYS:\t" + mNetworkStatus.getWACN() );
- sb.append( "-" + mNetworkStatus.getSystemID() );
- sb.append( " [" );
- sb.append( mNetworkStatus.getNetworkCallsign() );
- sb.append( "]" );
- sb.append( "\nLRA:\t" + mNetworkStatus.getLocationRegistrationArea() );
- }
- else if( mNetworkStatusExtended != null )
- {
- sb.append( "\nNAC:\t" + mNetworkStatusExtended.getNAC() );
- sb.append( "\nWACN-SYS:\t" + mNetworkStatusExtended.getWACN() );
- sb.append( "-" + mNetworkStatusExtended.getSystemID() );
- sb.append( " [" );
- sb.append( mNetworkStatusExtended.getNetworkCallsign() );
- sb.append( "]" );
- sb.append( "\nLRA:\t" + mNetworkStatusExtended.getLocationRegistrationArea() );
- }
+ sb.append("Activity Summary\n");
+ sb.append("Decoder:\tP25\n");
+ sb.append("===================== THIS SITE ======================");
- String site = null;
-
- if( mRFSSStatusMessage != null )
- {
- site = mRFSSStatusMessage.getRFSubsystemID() + "-" + mRFSSStatusMessage.getSiteID();
- }
- else if( mRFSSStatusMessageExtended != null )
- {
- site = mRFSSStatusMessageExtended.getRFSubsystemID() + "-" +
- mRFSSStatusMessageExtended.getSiteID();
- }
+ if(mNetworkStatus != null)
+ {
+ sb.append("\nNAC:\t" + mNetworkStatus.getNAC());
+ sb.append("\nWACN-SYS:\t" + mNetworkStatus.getWACN());
+ sb.append("-" + mNetworkStatus.getSystemID());
+ sb.append(" [");
+ sb.append(mNetworkStatus.getNetworkCallsign());
+ sb.append("]");
+ sb.append("\nLRA:\t" + mNetworkStatus.getLocationRegistrationArea());
+ }
+ else if(mNetworkStatusExtended != null)
+ {
+ sb.append("\nNAC:\t" + mNetworkStatusExtended.getNAC());
+ sb.append("\nWACN-SYS:\t" + mNetworkStatusExtended.getWACN());
+ sb.append("-" + mNetworkStatusExtended.getSystemID());
+ sb.append(" [");
+ sb.append(mNetworkStatusExtended.getNetworkCallsign());
+ sb.append("]");
+ sb.append("\nLRA:\t" + mNetworkStatusExtended.getLocationRegistrationArea());
+ }
- sb.append( "\nRFSS-SITE:\t" + site );
-
- if( hasAliasList() )
- {
- Alias siteAlias = getAliasList().getSiteID( site );
-
- if( siteAlias != null )
- {
- sb.append( " " + siteAlias.getName() );
- }
- }
+ String site = null;
- if( mNetworkStatus != null )
- {
- sb.append( "\nSERVICES:\t" + SystemService.toString(
- mNetworkStatus.getSystemServiceClass() ) );
- sb.append( "\nPCCH:\tDNLINK " + mFrequencyFormatter.format(
- (double)mNetworkStatus.getDownlinkFrequency() / 1E6d ) +
- " [" + mNetworkStatus.getIdentifier() + "-" +
- mNetworkStatus.getChannel() + "]\n" );
- sb.append( "\tUPLINK " + mFrequencyFormatter.format(
- (double)mNetworkStatus.getUplinkFrequency() / 1E6d ) + " [" +
- mNetworkStatus.getIdentifier() + "-" +
- mNetworkStatus.getChannel() + "]\n" );
- }
- else if( mNetworkStatusExtended != null )
- {
- sb.append( "\nSERVICES:\t" + SystemService.toString(
- mNetworkStatusExtended.getSystemServiceClass() ) );
- sb.append( "\nPCCH:\tDNLINK " + mFrequencyFormatter.format(
- (double)mNetworkStatusExtended.getDownlinkFrequency() / 1E6d ) +
- " [" + mNetworkStatusExtended.getTransmitIdentifier() + "-" +
- mNetworkStatusExtended.getTransmitChannel() + "]\n" );
- sb.append( "\tUPLINK " + mFrequencyFormatter.format(
- (double)mNetworkStatusExtended.getUplinkFrequency() / 1E6d ) +
- " [" + mNetworkStatusExtended.getReceiveIdentifier() + "-" +
- mNetworkStatusExtended.getReceiveChannel() + "]" );
- }
-
- if( mSecondaryControlChannels.isEmpty() )
- {
- sb.append( "\nSCCH:\tNONE" );
- }
- else
- {
- for( module.decode.p25.message.tsbk.osp.control.SecondaryControlChannelBroadcast
- sec: mSecondaryControlChannels )
- {
- sb.append( "\nSCCH:\tDNLINK " + mFrequencyFormatter.format(
- (double)sec.getDownlinkFrequency1() / 1E6d ) +
- " [" + sec.getIdentifier1() + "-" + sec.getChannel1() + "]\n" );
- sb.append( "\tUPLINK " + mFrequencyFormatter.format(
- (double)sec.getUplinkFrequency1() / 1E6d ) + " [" +
- sec.getIdentifier1() + "-" + sec.getChannel1() + "]\n" );
-
- if( sec.hasChannel2() )
- {
- sb.append( "\nSCCH:\tDNLINK " + mFrequencyFormatter.format(
- (double)sec.getDownlinkFrequency2() / 1E6d ) +
- " [" + sec.getIdentifier2() + "-" + sec.getChannel2() + "]\n" );
- sb.append( "\tUPLINK " + mFrequencyFormatter.format(
- (double)sec.getUplinkFrequency2() / 1E6d ) + " [" +
- sec.getIdentifier2() + "-" + sec.getChannel2() + "]" );
- }
- }
- }
-
- if( mSNDCPDataChannel != null )
- {
- sb.append( "\nSNDCP:" );
- sb.append( "\tDNLINK " + mFrequencyFormatter.format(
- (double)mSNDCPDataChannel.getDownlinkFrequency()/1E6D ) +
- " [" + mSNDCPDataChannel.getTransmitChannel() + "]" );
- sb.append( "\tUPLINK " + mFrequencyFormatter.format(
- (double)mSNDCPDataChannel.getUplinkFrequency()/1E6D ) +
- " [" + mSNDCPDataChannel.getReceiveChannel() + "]" );
- }
-
- if( mProtectionParameterBroadcast != null )
- {
- sb.append( "\nENCRYPTION:" );
- sb.append( "\nTYPE:\t" + mProtectionParameterBroadcast
- .getEncryptionType().name() );
- sb.append( "\nALGORITHM:\t" + mProtectionParameterBroadcast
- .getAlgorithmID() );
- sb.append( "\nKEY:\t" + mProtectionParameterBroadcast.getKeyID() );
- sb.append( "\nINBOUND IV:\t" + mProtectionParameterBroadcast
- .getInboundInitializationVector() );
- sb.append( "\nOUTBOUND IV:\t" + mProtectionParameterBroadcast
- .getOutboundInitializationVector() );
- }
-
- List identifiers = new ArrayList<>( mBands.keySet() );
-
- Collections.sort( identifiers );
-
- sb.append( "\nFREQUENCY BANDS:" );
- for( Integer id: identifiers )
- {
- IBandIdentifier band = mBands.get( id );
-
- sb.append( "\n\t" + id );
- sb.append( "- BASE: " + mFrequencyFormatter.format(
- (double)band.getBaseFrequency() / 1E6d ) );
- sb.append( " CHANNEL SIZE: " + mFrequencyFormatter.format(
- (double)band.getChannelSpacing() / 1E6d ) );
- sb.append( " UPLINK OFFSET: " + mFrequencyFormatter.format(
- (double)band.getTransmitOffset() / 1E6D ) );
- }
-
- sb.append( "\n\n=================== NEIGHBORS ======================" );
-
- if( mNeighborMap.isEmpty() )
- {
- sb.append( "\n\tNONE\n" );
- sb.append( "\n----------------------------------------------------" );
- }
- else
- {
- for( IAdjacentSite neighbor: mNeighborMap.values() )
- {
- sb.append( "\nNAC:\t" + ((P25Message)neighbor).getNAC() );
- sb.append( "\nSYSTEM:\t" + neighbor.getSystemID() );
- sb.append( "\nLRA:\t" + neighbor.getLRA() );
-
- String neighborID = neighbor.getRFSS() + "-" + neighbor.getSiteID();
- sb.append( "\nRFSS-SITE:\t" + neighborID );
-
- if( hasAliasList() )
- {
- Alias siteAlias = getAliasList().getSiteID( neighborID );
-
- if( siteAlias != null )
- {
- sb.append( " " + siteAlias.getName() );
- }
- }
-
- sb.append( "\nPCCH:\tDNLINK " + mFrequencyFormatter.format(
- (double)neighbor.getDownlinkFrequency() / 1E6d ) +
- " [" + neighbor.getDownlinkChannel() + "]" );
- sb.append( "\n\tUPLINK:" + mFrequencyFormatter.format(
- (double)neighbor.getUplinkFrequency() / 1E6d ) +
- " [" + neighbor.getDownlinkChannel() + "]\n" );
- sb.append( "\nSERVICES:\t" + neighbor.getSystemServiceClass() );
- sb.append( "\n----------------------------------------------------" );
- }
- }
-
- return sb.toString();
+ if(mRFSSStatusMessage != null)
+ {
+ site = mRFSSStatusMessage.getRFSubsystemID() + "-" + mRFSSStatusMessage.getSiteID();
+ }
+ else if(mRFSSStatusMessageExtended != null)
+ {
+ site = mRFSSStatusMessageExtended.getRFSubsystemID() + "-" +
+ mRFSSStatusMessageExtended.getSiteID();
+ }
+
+ sb.append("\nRFSS-SITE:\t" + site);
+
+ if(hasAliasList())
+ {
+ Alias siteAlias = getAliasList().getSiteID(site);
+
+ if(siteAlias != null)
+ {
+ sb.append(" " + siteAlias.getName());
+ }
+ }
+
+ if(mNetworkStatus != null)
+ {
+ sb.append("\nSERVICES:\t" + SystemService.toString(
+ mNetworkStatus.getSystemServiceClass()));
+ sb.append("\nPCCH:\tDNLINK " + mFrequencyFormatter.format(
+ (double) mNetworkStatus.getDownlinkFrequency() / 1E6d) +
+ " [" + mNetworkStatus.getIdentifier() + "-" +
+ mNetworkStatus.getChannel() + "]\n");
+ sb.append("\tUPLINK " + mFrequencyFormatter.format(
+ (double) mNetworkStatus.getUplinkFrequency() / 1E6d) + " [" +
+ mNetworkStatus.getIdentifier() + "-" +
+ mNetworkStatus.getChannel() + "]\n");
+ }
+ else if(mNetworkStatusExtended != null)
+ {
+ sb.append("\nSERVICES:\t" + SystemService.toString(
+ mNetworkStatusExtended.getSystemServiceClass()));
+ sb.append("\nPCCH:\tDNLINK " + mFrequencyFormatter.format(
+ (double) mNetworkStatusExtended.getDownlinkFrequency() / 1E6d) +
+ " [" + mNetworkStatusExtended.getTransmitIdentifier() + "-" +
+ mNetworkStatusExtended.getTransmitChannel() + "]\n");
+ sb.append("\tUPLINK " + mFrequencyFormatter.format(
+ (double) mNetworkStatusExtended.getUplinkFrequency() / 1E6d) +
+ " [" + mNetworkStatusExtended.getReceiveIdentifier() + "-" +
+ mNetworkStatusExtended.getReceiveChannel() + "]");
+ }
+
+ if(mSecondaryControlChannels.isEmpty())
+ {
+ sb.append("\nSCCH:\tNONE");
+ }
+ else
+ {
+ for(module.decode.p25.message.tsbk.osp.control.SecondaryControlChannelBroadcast
+ sec : mSecondaryControlChannels)
+ {
+ sb.append("\nSCCH:\tDNLINK " + mFrequencyFormatter.format(
+ (double) sec.getDownlinkFrequency1() / 1E6d) +
+ " [" + sec.getIdentifier1() + "-" + sec.getChannel1() + "]\n");
+ sb.append("\tUPLINK " + mFrequencyFormatter.format(
+ (double) sec.getUplinkFrequency1() / 1E6d) + " [" +
+ sec.getIdentifier1() + "-" + sec.getChannel1() + "]\n");
+
+ if(sec.hasChannel2())
+ {
+ sb.append("\nSCCH:\tDNLINK " + mFrequencyFormatter.format(
+ (double) sec.getDownlinkFrequency2() / 1E6d) +
+ " [" + sec.getIdentifier2() + "-" + sec.getChannel2() + "]\n");
+ sb.append("\tUPLINK " + mFrequencyFormatter.format(
+ (double) sec.getUplinkFrequency2() / 1E6d) + " [" +
+ sec.getIdentifier2() + "-" + sec.getChannel2() + "]");
+ }
+ }
+ }
+
+ if(mSNDCPDataChannel != null)
+ {
+ sb.append("\nSNDCP:");
+ sb.append("\tDNLINK " + mFrequencyFormatter.format(
+ (double) mSNDCPDataChannel.getDownlinkFrequency() / 1E6D) +
+ " [" + mSNDCPDataChannel.getTransmitChannel() + "]");
+ sb.append("\tUPLINK " + mFrequencyFormatter.format(
+ (double) mSNDCPDataChannel.getUplinkFrequency() / 1E6D) +
+ " [" + mSNDCPDataChannel.getReceiveChannel() + "]");
+ }
+
+ if(mProtectionParameterBroadcast != null)
+ {
+ sb.append("\nENCRYPTION:");
+ sb.append("\nTYPE:\t" + mProtectionParameterBroadcast
+ .getEncryptionType().name());
+ sb.append("\nALGORITHM:\t" + mProtectionParameterBroadcast
+ .getAlgorithmID());
+ sb.append("\nKEY:\t" + mProtectionParameterBroadcast.getKeyID());
+ sb.append("\nINBOUND IV:\t" + mProtectionParameterBroadcast
+ .getInboundInitializationVector());
+ sb.append("\nOUTBOUND IV:\t" + mProtectionParameterBroadcast
+ .getOutboundInitializationVector());
+ }
+
+ List identifiers = new ArrayList<>(mBands.keySet());
+
+ Collections.sort(identifiers);
+
+ sb.append("\nFREQUENCY BANDS:");
+ for(Integer id : identifiers)
+ {
+ IBandIdentifier band = mBands.get(id);
+
+ sb.append("\n\t" + id);
+ sb.append("- BASE: " + mFrequencyFormatter.format(
+ (double) band.getBaseFrequency() / 1E6d));
+ sb.append(" CHANNEL SIZE: " + mFrequencyFormatter.format(
+ (double) band.getChannelSpacing() / 1E6d));
+ sb.append(" UPLINK OFFSET: " + mFrequencyFormatter.format(
+ (double) band.getTransmitOffset() / 1E6D));
+ }
+
+ sb.append("\n\n=================== NEIGHBORS ======================");
+
+ if(mNeighborMap.isEmpty())
+ {
+ sb.append("\n\tNONE\n");
+ sb.append("\n----------------------------------------------------");
+ }
+ else
+ {
+ for(IAdjacentSite neighbor : mNeighborMap.values())
+ {
+ sb.append("\nNAC:\t" + ((P25Message) neighbor).getNAC());
+ sb.append("\nSYSTEM:\t" + neighbor.getSystemID());
+ sb.append("\nLRA:\t" + neighbor.getLRA());
+
+ String neighborID = neighbor.getRFSS() + "-" + neighbor.getSiteID();
+ sb.append("\nRFSS-SITE:\t" + neighborID);
+
+ if(hasAliasList())
+ {
+ Alias siteAlias = getAliasList().getSiteID(neighborID);
+
+ if(siteAlias != null)
+ {
+ sb.append(" " + siteAlias.getName());
+ }
+ }
+
+ sb.append("\nPCCH:\tDNLINK " + mFrequencyFormatter.format(
+ (double) neighbor.getDownlinkFrequency() / 1E6d) +
+ " [" + neighbor.getDownlinkChannel() + "]");
+ sb.append("\n\tUPLINK:" + mFrequencyFormatter.format(
+ (double) neighbor.getUplinkFrequency() / 1E6d) +
+ " [" + neighbor.getDownlinkChannel() + "]\n");
+ sb.append("\nSERVICES:\t" + neighbor.getSystemServiceClass());
+ sb.append("\n----------------------------------------------------");
+ }
+ }
+
+ return sb.toString();
}
-
- public String getNAC()
- {
- return mNAC;
- }
-
- public String getSystem()
- {
- return mSystem;
- }
-
- public String getSiteAlias()
- {
- return mSiteAlias;
- }
-
- public String getSite()
- {
- return mSite;
- }
-
- public String getFromTalkgroup()
- {
- return mFromTalkgroup;
- }
-
- public Alias getFromAlias()
- {
- return mFromAlias;
- }
-
- public String getToTalkgroup()
- {
- return mToTalkgroup;
- }
-
- public Alias getToAlias()
- {
- return mToAlias;
- }
-
- @Override
- public void receiveDecoderStateEvent( DecoderStateEvent event )
- {
- switch( event.getEvent() )
- {
- case RESET:
- resetState();
- break;
- case SOURCE_FREQUENCY:
- mCurrentChannelFrequency = event.getFrequency();
- break;
- case TRAFFIC_CHANNEL_ALLOCATION:
- if( event.getSource() != P25DecoderState.this )
- {
- if( event instanceof TrafficChannelAllocationEvent )
- {
- TrafficChannelAllocationEvent allocationEvent =
- (TrafficChannelAllocationEvent)event;
-
- mCurrentCallEvent = (P25CallEvent)allocationEvent.getCallEvent();
- mCurrentChannel = allocationEvent.getCallEvent().getChannel();
- broadcast( ChangedAttribute.CHANNEL_NUMBER );
-
- mCurrentChannelFrequency = allocationEvent.getCallEvent().getFrequency();
- broadcast( ChangedAttribute.SOURCE );
+ public String getNAC()
+ {
+ return mNAC;
+ }
- mFromTalkgroup = allocationEvent.getCallEvent().getFromID();
- broadcast( ChangedAttribute.FROM_TALKGROUP );
-
- mToTalkgroup = allocationEvent.getCallEvent().getToID();
- broadcast( ChangedAttribute.TO_TALKGROUP );
+ public String getSystem()
+ {
+ return mSystem;
+ }
- if( allocationEvent.getCallEvent().hasAliasList() )
- {
- AliasList aliasList = allocationEvent.getCallEvent().getAliasList();
-
- mFromAlias = aliasList.getTalkgroupAlias( mFromTalkgroup );
- broadcast( ChangedAttribute.FROM_TALKGROUP_ALIAS );
-
- mToAlias = aliasList.getTalkgroupAlias( mToTalkgroup );
- broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
- }
- }
- }
- break;
- default:
- break;
- }
- }
+ public String getSiteAlias()
+ {
+ return mSiteAlias;
+ }
- @Override
- public void start( ScheduledExecutorService executor )
- {
- //Change the default (45-second) traffic channel timeout to 1 second
- if( mChannelType == ChannelType.TRAFFIC )
- {
- broadcast( new ChangeChannelTimeoutEvent( this, ChannelType.TRAFFIC, 1000 ) );
- }
- }
+ public String getSite()
+ {
+ return mSite;
+ }
+
+ public String getFromTalkgroup()
+ {
+ return mFromTalkgroup;
+ }
+
+ public Alias getFromAlias()
+ {
+ return mFromAlias;
+ }
+
+ public String getToTalkgroup()
+ {
+ return mToTalkgroup;
+ }
+
+ public Alias getToAlias()
+ {
+ return mToAlias;
+ }
+
+ @Override
+ public void receiveDecoderStateEvent(DecoderStateEvent event)
+ {
+ switch(event.getEvent())
+ {
+ case RESET:
+ resetState();
+ break;
+ case SOURCE_FREQUENCY:
+ mCurrentChannelFrequency = event.getFrequency();
+ break;
+ case TRAFFIC_CHANNEL_ALLOCATION:
+ if(event.getSource() != P25DecoderState.this)
+ {
+ if(event instanceof TrafficChannelAllocationEvent)
+ {
+ TrafficChannelAllocationEvent allocationEvent =
+ (TrafficChannelAllocationEvent) event;
+
+ mCurrentCallEvent = (P25CallEvent) allocationEvent.getCallEvent();
+
+ mCurrentChannel = allocationEvent.getCallEvent().getChannel();
+ broadcast(ChangedAttribute.CHANNEL_NUMBER);
+
+ mCurrentChannelFrequency = allocationEvent.getCallEvent().getFrequency();
+ broadcast(ChangedAttribute.SOURCE);
+
+ mFromTalkgroup = allocationEvent.getCallEvent().getFromID();
+ broadcast(ChangedAttribute.FROM_TALKGROUP);
+
+ mToTalkgroup = allocationEvent.getCallEvent().getToID();
+ broadcast(ChangedAttribute.TO_TALKGROUP);
+
+ if(allocationEvent.getCallEvent().hasAliasList())
+ {
+ AliasList aliasList = allocationEvent.getCallEvent().getAliasList();
+
+ mFromAlias = aliasList.getTalkgroupAlias(mFromTalkgroup);
+ broadcast(ChangedAttribute.FROM_TALKGROUP_ALIAS);
+
+ mToAlias = aliasList.getTalkgroupAlias(mToTalkgroup);
+ broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void start(ScheduledExecutorService executor)
+ {
+ //Change the default (45-second) traffic channel timeout to 1 second
+ if(mChannelType == ChannelType.TRAFFIC)
+ {
+ broadcast(new ChangeChannelTimeoutEvent(this, ChannelType.TRAFFIC, 1000));
+ }
+ }
}
diff --git a/src/module/decode/p25/message/tsbk/motorola/PatchGroup.java b/src/module/decode/p25/message/tsbk/motorola/PatchGroup.java
index f5c5305a..8d8c446d 100644
--- a/src/module/decode/p25/message/tsbk/motorola/PatchGroup.java
+++ b/src/module/decode/p25/message/tsbk/motorola/PatchGroup.java
@@ -4,6 +4,10 @@ import module.decode.p25.reference.DataUnitID;
import alias.AliasList;
import bits.BinaryMessage;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
public abstract class PatchGroup extends MotorolaTSBKMessage
{
public static final int[] PATCH_GROUP_ADDRESS = { 80,81,82,83,84,85,86,87,
@@ -15,6 +19,8 @@ public abstract class PatchGroup extends MotorolaTSBKMessage
public static final int[] GROUP_ADDRESS_3 = { 128,129,130,131,132,133,134,
135,136,137,138,139,140,141,142,143 };
+ private List mPatchedTalkgroups;
+
public PatchGroup( BinaryMessage message, DataUnitID duid,
AliasList aliasList )
{
@@ -28,15 +34,11 @@ public abstract class PatchGroup extends MotorolaTSBKMessage
sb.append( getMessageStub() );
- sb.append( " PATCH GROUP:" );
+ sb.append( " " );
sb.append( getPatchGroupAddress() );
- sb.append( " GRP1:" );
- sb.append( getGroupAddress1() );
- sb.append( " GRP2:" );
- sb.append( getGroupAddress2() );
- sb.append( " GRP3:" );
- sb.append( getGroupAddress3() );
-
+ sb.append(" ");
+ sb.append(getPatchedTalkgroups());
+
return sb.toString();
}
@@ -44,6 +46,35 @@ public abstract class PatchGroup extends MotorolaTSBKMessage
{
return mMessage.getHex( PATCH_GROUP_ADDRESS, 4 );
}
+
+ /**
+ * List of de-deplicated patched talkgroups contained in this message
+ */
+ public List getPatchedTalkgroups()
+ {
+ if(mPatchedTalkgroups == null)
+ {
+ mPatchedTalkgroups = new ArrayList<>();
+
+ mPatchedTalkgroups.add(getGroupAddress1());
+
+ String group2 = getGroupAddress2();
+
+ if(!mPatchedTalkgroups.contains(group2))
+ {
+ mPatchedTalkgroups.add(group2);
+ }
+
+ String group3 = getGroupAddress3();
+
+ if(!mPatchedTalkgroups.contains(group3))
+ {
+ mPatchedTalkgroups.add(group3);
+ }
+ }
+
+ return mPatchedTalkgroups;
+ }
public String getGroupAddress1()
{