mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
#2007 P25 Call events tracking. P25 Traffic channel manager now uses event trackers to deconflict between control channel and traffic channel event updates. Protects against Motorola ISSI FQSUID that's all zeros. Resolves issue with running out of traffic channels after losing the control channel and going into CC hunt mode a few times. (#2010)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -222,7 +222,7 @@ public class P25P2Viewer extends VBox
|
||||
|
||||
ThreadPool.CACHED.submit(() -> {
|
||||
List<MessagePackage> messages = new ArrayList<>();
|
||||
P25P2MessageFramer messageFramer = new P25P2MessageFramer(null, 9600);
|
||||
P25P2MessageFramer messageFramer = new P25P2MessageFramer(null);
|
||||
messageFramer.setScrambleParameters(scrambleParameters);
|
||||
P25P2MessageProcessor messageProcessor = new P25P2MessageProcessor();
|
||||
messageFramer.setListener(messageProcessor);
|
||||
|
||||
@@ -363,6 +363,15 @@ public class IdentifierCollection
|
||||
return to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an encryption key identiier or null.
|
||||
* @return key or null.
|
||||
*/
|
||||
public Identifier getEncryptionIdentifier()
|
||||
{
|
||||
return getIdentifier(IdentifierClass.USER, Form.ENCRYPTION_KEY, Role.ANY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
||||
@@ -188,10 +188,10 @@ public class DecoderFactory
|
||||
processPassport(channel, modules, aliasList, decodeConfig);
|
||||
break;
|
||||
case P25_PHASE1:
|
||||
processP25Phase1(channel, userPreferences, modules, aliasList, trafficChannelManager);
|
||||
processP25Phase1(channel, userPreferences, modules, aliasList, trafficChannelManager, channelDescriptor);
|
||||
break;
|
||||
case P25_PHASE2:
|
||||
processP25Phase2(channel, userPreferences, modules, aliasList, trafficChannelManager);
|
||||
processP25Phase2(channel, userPreferences, modules, aliasList, trafficChannelManager, channelDescriptor);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown decoder type [" + decodeConfig.getDecoderType().toString() + "]");
|
||||
@@ -210,7 +210,8 @@ public class DecoderFactory
|
||||
* will be created automatically.
|
||||
*/
|
||||
private static void processP25Phase2(Channel channel, UserPreferences userPreferences, List<Module> modules,
|
||||
AliasList aliasList, TrafficChannelManager trafficChannelManager)
|
||||
AliasList aliasList, TrafficChannelManager trafficChannelManager,
|
||||
IChannelDescriptor channelDescriptor)
|
||||
{
|
||||
|
||||
modules.add(new P25P2DecoderHDQPSK((DecodeConfigP25Phase2)channel.getDecodeConfiguration()));
|
||||
@@ -236,22 +237,25 @@ public class DecoderFactory
|
||||
modules.add(p25TrafficChannelManager);
|
||||
}
|
||||
|
||||
//A single patch group manager is shared across both timeslots
|
||||
PatchGroupManager patchGroupManager = new PatchGroupManager();
|
||||
modules.add(new P25P2DecoderState(channel, P25P2Message.TIMESLOT_1, p25TrafficChannelManager, patchGroupManager));
|
||||
modules.add(new P25P2DecoderState(channel, P25P2Message.TIMESLOT_2, p25TrafficChannelManager, patchGroupManager));
|
||||
|
||||
P25P2DecoderState decoderState1 = new P25P2DecoderState(channel, P25P2Message.TIMESLOT_1, p25TrafficChannelManager, patchGroupManager);
|
||||
decoderState1.setCurrentChannel(channelDescriptor);
|
||||
P25P2DecoderState decoderState2 = new P25P2DecoderState(channel, P25P2Message.TIMESLOT_2, p25TrafficChannelManager, patchGroupManager);
|
||||
decoderState2.setCurrentChannel(channelDescriptor);
|
||||
modules.add(decoderState1);
|
||||
modules.add(decoderState2);
|
||||
modules.add(new P25P2AudioModule(userPreferences, P25P2Message.TIMESLOT_1, aliasList));
|
||||
modules.add(new P25P2AudioModule(userPreferences, P25P2Message.TIMESLOT_2, aliasList));
|
||||
|
||||
|
||||
//Add a channel rotation monitor when we have multiple control channel frequencies specified
|
||||
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency &&
|
||||
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).hasMultipleFrequencies())
|
||||
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency sctmf &&
|
||||
sctmf.hasMultipleFrequencies())
|
||||
{
|
||||
List<State> activeStates = new ArrayList<>();
|
||||
activeStates.add(State.CONTROL);
|
||||
modules.add(new ChannelRotationMonitor(activeStates,
|
||||
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencyRotationDelay(),
|
||||
userPreferences));
|
||||
modules.add(new ChannelRotationMonitor(activeStates, sctmf.getFrequencyRotationDelay(), userPreferences));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +267,8 @@ public class DecoderFactory
|
||||
* @param aliasList for the channel
|
||||
*/
|
||||
private static void processP25Phase1(Channel channel, UserPreferences userPreferences, List<Module> modules,
|
||||
AliasList aliasList, TrafficChannelManager trafficChannelManager)
|
||||
AliasList aliasList, TrafficChannelManager trafficChannelManager,
|
||||
IChannelDescriptor channelDescriptor)
|
||||
{
|
||||
if(channel.getDecodeConfiguration() instanceof DecodeConfigP25Phase1 p1)
|
||||
{
|
||||
@@ -288,7 +293,9 @@ public class DecoderFactory
|
||||
}
|
||||
else if(trafficChannelManager instanceof P25TrafficChannelManager parentTCM)
|
||||
{
|
||||
modules.add(new P25P1DecoderState(channel, parentTCM));
|
||||
P25P1DecoderState decoderState = new P25P1DecoderState(channel, parentTCM);
|
||||
decoderState.setCurrentChannel(channelDescriptor);
|
||||
modules.add(decoderState);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -466,6 +473,7 @@ public class DecoderFactory
|
||||
* @param aliasList for the audio module
|
||||
* @param decodeConfig for the DMR configuration
|
||||
* @param trafficChannelManager optional traffic channel manager to re-use
|
||||
* @param channelDescriptor for the channel.
|
||||
*/
|
||||
private static void processDMR(Channel channel, UserPreferences userPreferences, List<Module> modules,
|
||||
AliasList aliasList, DecodeConfigDMR decodeConfig,
|
||||
|
||||
@@ -95,7 +95,7 @@ public enum DecodeEventType
|
||||
/**
|
||||
* Voice call event types for filtering
|
||||
*/
|
||||
public static final EnumSet<DecodeEventType> VOICE_CALLS = EnumSet.of(DecodeEventType.CALL_GROUP,
|
||||
public static final EnumSet<DecodeEventType> VOICE_CALLS = EnumSet.of(DecodeEventType.CALL, DecodeEventType.CALL_GROUP,
|
||||
DecodeEventType.CALL_PATCH_GROUP, DecodeEventType.CALL_ALERT, DecodeEventType.CALL_DETECT,
|
||||
DecodeEventType.CALL_DO_NOT_MONITOR, DecodeEventType.CALL_END, DecodeEventType.CALL_INTERCONNECT,
|
||||
DecodeEventType.CALL_UNIQUE_ID, DecodeEventType.CALL_UNIT_TO_UNIT, DecodeEventType.CALL_NO_TUNER,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
* Copyright (C) 2014-2024 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
|
||||
@@ -80,6 +80,7 @@ public class P25ChannelGrantEvent extends P25DecodeEvent
|
||||
protected IChannelDescriptor mChannelDescriptor;
|
||||
protected String mDetails;
|
||||
private ServiceOptions mServiceOptions;
|
||||
private int mTimeslot = -1;
|
||||
|
||||
/**
|
||||
* Constructs a builder instance with the specified start time in milliseconds
|
||||
@@ -144,6 +145,16 @@ public class P25ChannelGrantEvent extends P25DecodeEvent
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timeslot for the event
|
||||
* @param timeslot
|
||||
*/
|
||||
public P25ChannelGrantDecodeEventBuilder timeslot(int timeslot)
|
||||
{
|
||||
mTimeslot = timeslot;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the decode event
|
||||
*/
|
||||
@@ -156,6 +167,7 @@ public class P25ChannelGrantEvent extends P25DecodeEvent
|
||||
decodeEvent.setDuration(mDuration);
|
||||
decodeEvent.setIdentifierCollection(mIdentifierCollection);
|
||||
decodeEvent.setServiceOptions(mServiceOptions);
|
||||
decodeEvent.setTimeslot(mTimeslot);
|
||||
return decodeEvent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||
import io.github.dsheirer.identifier.MutableIdentifierCollection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Wrapper to track the state of a traffic channel event to manage updates from the control channel and the traffic
|
||||
* channel and to assist in determining when the communicants of a traffic channel have changed, indicating the need
|
||||
* for a new event.
|
||||
*/
|
||||
public class P25TrafficChannelEventTracker
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(P25TrafficChannelEventTracker.class);
|
||||
private static final long STALE_EVENT_THRESHOLD_MS = 2000;
|
||||
private P25ChannelGrantEvent mEvent;
|
||||
private boolean mStarted = false;
|
||||
private boolean mComplete = false;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param event to track for the traffic channel.
|
||||
*/
|
||||
public P25TrafficChannelEventTracker(P25ChannelGrantEvent event)
|
||||
{
|
||||
mEvent = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the underlying traffic channel event that is being tracked.
|
||||
* @return event.
|
||||
*/
|
||||
public P25ChannelGrantEvent getEvent()
|
||||
{
|
||||
return mEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this event is stale relative to the provided timestamp. Staleness is determined by the time delta
|
||||
* between the event's end time and timestamp argument.
|
||||
* @param timestamp to check for staleness
|
||||
* @return true if the delta time exceeds a threshold.
|
||||
*/
|
||||
public boolean isStale(long timestamp)
|
||||
{
|
||||
if(getEvent().getTimeEnd() > 0)
|
||||
{
|
||||
return timestamp - getEvent().getTimeEnd() > STALE_EVENT_THRESHOLD_MS;
|
||||
}
|
||||
|
||||
return timestamp - getEvent().getTimeStart() > STALE_EVENT_THRESHOLD_MS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the identifier to the tracked event if the event's identifier collection does not already have it.
|
||||
* @param identifier to add
|
||||
*/
|
||||
public void addIdentifierIfMissing(Identifier identifier)
|
||||
{
|
||||
if(identifier != null && !getEvent().getIdentifierCollection().hasIdentifier(identifier))
|
||||
{
|
||||
MutableIdentifierCollection mic = new MutableIdentifierCollection(getEvent().getIdentifierCollection()
|
||||
.getIdentifiers());
|
||||
mic.update(identifier);
|
||||
getEvent().setIdentifierCollection(mic);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the additional details to the tracked event if the current event details are null or if they do not contain
|
||||
* the additional details.
|
||||
* @param additionalDetails
|
||||
*/
|
||||
public void addDetailsIfMissing(String additionalDetails)
|
||||
{
|
||||
if(additionalDetails != null && !additionalDetails.isEmpty())
|
||||
{
|
||||
if(getEvent().getDetails() == null)
|
||||
{
|
||||
getEvent().setDetails(additionalDetails);
|
||||
}
|
||||
else if(!getEvent().getDetails().endsWith(additionalDetails))
|
||||
{
|
||||
getEvent().setDetails(getEvent().getDetails() + " " + additionalDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the TO role identifier(s) from the tracked event and the identifier collection argument for equality
|
||||
* and also checks this event for staleness.
|
||||
*
|
||||
* @param toCompare containing a TO identifier
|
||||
* @param timestamp to check for staleness
|
||||
* @return true if both collections contain a TO identifier and the TO identifiers are the same value
|
||||
*/
|
||||
public boolean isSameCallCheckingToOnly(IdentifierCollection toCompare, long timestamp)
|
||||
{
|
||||
Identifier currentTO = getEvent().getIdentifierCollection().getToIdentifier();
|
||||
Identifier nextTO = toCompare.getToIdentifier();
|
||||
return currentTO != null && currentTO.equals(nextTO) && !isStale(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the tracked event from identifier is non null and that it is different to the from argument.
|
||||
* @param fromToCompare against the current event from identifier.
|
||||
* @return true if they are different.
|
||||
*/
|
||||
public boolean isDifferentTalker(Identifier fromToCompare)
|
||||
{
|
||||
if(fromToCompare == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Identifier fromCurrent = getEvent().getIdentifierCollection().getFromIdentifier();
|
||||
return fromCurrent != null && !fromCurrent.equals(fromToCompare);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks the call for staleness and verifies that the call event TO identifier is equal to the TO identifier
|
||||
* in the provided identifier collection.
|
||||
* @param toCompareIC containing a TO and optionally a FROM identifier to compare.
|
||||
* @param timestamp to check for staleness
|
||||
* @return true if the call identifiers are the same and the call is not stale.
|
||||
*/
|
||||
public boolean isSameCallCheckingToAndFrom(IdentifierCollection toCompareIC, long timestamp)
|
||||
{
|
||||
if(!isStale(timestamp))
|
||||
{
|
||||
Identifier currentTO = getEvent().getIdentifierCollection().getToIdentifier();
|
||||
Identifier nextTO = toCompareIC.getToIdentifier();
|
||||
|
||||
if(currentTO != null && currentTO.equals(nextTO))
|
||||
{
|
||||
Identifier existingFROM = getEvent().getIdentifierCollection().getFromIdentifier();
|
||||
|
||||
//If the FROM identifier hasn't yet been established, then this is the same call. We also ignore the
|
||||
//talker alias as a call identifier since on L3Harris systems they can transmit the talker alias before
|
||||
//they transmit the radio ID.
|
||||
if(existingFROM == null || existingFROM.getForm() == Form.TALKER_ALIAS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Identifier nextFROM = toCompareIC.getFromIdentifier();
|
||||
|
||||
//Sometime the GROUP_VOICE_CHANNEL_USER has a zero valued FROM address which is not valid, so if the
|
||||
//nextFROM is null, we consider the call to be the same. Likewise, if the nextFROM is a talker alias,
|
||||
//that's also the same call.
|
||||
if(nextFROM == null || (nextFROM != null && nextFROM.getForm() == Form.TALKER_ALIAS))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return existingFROM.equals(nextFROM);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the event has been marked as complete by traffic channel signalling.
|
||||
* @return complete status.
|
||||
*/
|
||||
public boolean isComplete()
|
||||
{
|
||||
return mComplete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the event has been marked as started by the traffic channel for HDU or LDU signalling.
|
||||
* @return started status.
|
||||
*/
|
||||
public boolean isStarted()
|
||||
{
|
||||
return mStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the event duration using signalling from the control channel.
|
||||
*
|
||||
* Note: once the traffic channel starts updating the event timing, attempts to update timing from the control
|
||||
* channel are ignored.
|
||||
*
|
||||
* @param timestamp to use as the current end timestamp for the event.
|
||||
* @return true if the timestamp was updated.
|
||||
*/
|
||||
public boolean updateDurationControl(long timestamp)
|
||||
{
|
||||
if(!isStarted())
|
||||
{
|
||||
getEvent().update(timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the event duration using signalling from the traffic channel.
|
||||
*
|
||||
* Note: once the event is being updated from the traffic channel, any attempts to update from the control channel
|
||||
* are ignored.
|
||||
* @param timestamp to assign.
|
||||
*/
|
||||
public void updateDurationTraffic(long timestamp)
|
||||
{
|
||||
if(!isComplete())
|
||||
{
|
||||
mStarted = true;
|
||||
getEvent().update(timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Attempt to update event call event duration from traffic channel against an event that is marked as complete");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the event as complete and assign final end timestamp to the event.
|
||||
*
|
||||
* Note: further attempts to complete an already complete event are ignored.
|
||||
* @param timestamp to assign.
|
||||
* @return true if the timestamp was updated
|
||||
*/
|
||||
public boolean completeTraffic(long timestamp)
|
||||
{
|
||||
if(!isComplete())
|
||||
{
|
||||
mComplete = true;
|
||||
getEvent().end(timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the details for the tracked event.
|
||||
* @param details to update
|
||||
*/
|
||||
public void setDetails(String details)
|
||||
{
|
||||
getEvent().setDetails(details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel descriptor for the tracked event.
|
||||
* @param channelDescriptor to update.
|
||||
*/
|
||||
public void addChannelDescriptorIfMissing(IChannelDescriptor channelDescriptor)
|
||||
{
|
||||
if(channelDescriptor != null && getEvent().getChannelDescriptor() == null)
|
||||
{
|
||||
getEvent().setChannelDescriptor(channelDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,20 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * (at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* * *****************************************************************************
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25.identifier.channel;
|
||||
|
||||
@@ -112,6 +109,36 @@ public class APCO25Channel extends Identifier<P25Channel> implements IChannelDes
|
||||
return new APCO25Channel(new P25Channel(frequencyBand, channelNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new APCO-25 identifier with the same frequencyBand, and a different channelNumber representing the
|
||||
* requested timeslot.
|
||||
* @param requestedTimeslot to decorate as.
|
||||
* @return decorated channel.
|
||||
*/
|
||||
public APCO25Channel decorateAs(int requestedTimeslot)
|
||||
{
|
||||
if(getTimeslot() == requestedTimeslot)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
P25Channel existing = getValue();
|
||||
|
||||
int channelNumber = existing.getChannelNumber();
|
||||
if(requestedTimeslot == 1)
|
||||
{
|
||||
channelNumber--;
|
||||
}
|
||||
else
|
||||
{
|
||||
channelNumber++;
|
||||
}
|
||||
|
||||
P25Channel decoratedChannel = new P25Channel(existing.getBandIdentifier(), channelNumber);
|
||||
decoratedChannel.setFrequencyBand(existing.getFrequencyBand());
|
||||
return new APCO25Channel(decoratedChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
|
||||
@@ -42,6 +42,22 @@ public class P25Channel implements IChannelDescriptor
|
||||
return Protocol.APCO25;
|
||||
}
|
||||
|
||||
/**
|
||||
* Band identifier for this channel.
|
||||
*/
|
||||
public int getBandIdentifier()
|
||||
{
|
||||
return mBandIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel number for this channel.
|
||||
*/
|
||||
public int getChannelNumber()
|
||||
{
|
||||
return mChannelNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency band information that backs this channel
|
||||
*/
|
||||
|
||||
@@ -66,15 +66,12 @@ import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris.LCHarrisReturnToControlChannel;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris.LCHarrisTalkerAliasComplete;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaEmergencyAlarmActivation;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaGroupRegroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaTalkComplete;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaUnitGPS;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.MotorolaTalkerAliasComplete;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCCallTermination;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCExtendedFunctionCommandExtended;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCMessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCMessageUpdateExtended;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCNetworkStatusBroadcast;
|
||||
@@ -346,43 +343,42 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
mTrafficChannelManager.getTalkerAliasManager().update(radioIdentifier, talkerAlias.getTalkerAlias());
|
||||
}
|
||||
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), talkerAlias.getTalkerAlias(), talkerAlias.getTimestamp());
|
||||
mTrafficChannelManager.processP1TrafficCurrentUser(getCurrentFrequency(), talkerAlias.getTalkerAlias(), talkerAlias.getTimestamp(), talkerAlias.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Commands the traffic channel manager to process a traffic channel grant and allocate a decoder to process the
|
||||
* traffic channel.
|
||||
* @param apco25Channel to allocate
|
||||
* Processes a control channel directed traffic channel grant.
|
||||
* @param channel to allocate
|
||||
* @param serviceOptions for the channel
|
||||
* @param identifiers to add to the current identifier collection
|
||||
* @param opcode that identifies the type of channel grant
|
||||
* @param timestamp when the channel grant occurred.
|
||||
*/
|
||||
private void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions,
|
||||
List<Identifier> identifiers, Opcode opcode, long timestamp)
|
||||
private void processControlTrafficGrant(APCO25Channel channel, ServiceOptions serviceOptions,
|
||||
List<Identifier> identifiers, Opcode opcode, long timestamp, String context)
|
||||
{
|
||||
if(apco25Channel.getValue().getDownlinkFrequency() > 0)
|
||||
if(channel.getValue().getDownlinkFrequency() > 0)
|
||||
{
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(identifiers, timestamp);
|
||||
mTrafficChannelManager.getTalkerAliasManager().enrichMutable(mic);
|
||||
mTrafficChannelManager.processP1ChannelGrant(apco25Channel, serviceOptions, mic, opcode, timestamp);
|
||||
mTrafficChannelManager.processP1ControlDirectedChannelGrant(channel, serviceOptions, mic, opcode, timestamp, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an update for another channel and send it to the traffic channel manager.
|
||||
* Processes a control channel announced update to a traffic channel
|
||||
* @param channel where the call activity is happening.
|
||||
* @param serviceOptions for the call, optional null.
|
||||
* @param identifiers involved in the call
|
||||
* @param opcode for the update
|
||||
* @param timestamp of the message
|
||||
*/
|
||||
private void processChannelUpdate(APCO25Channel channel, ServiceOptions serviceOptions, List<Identifier> identifiers,
|
||||
Opcode opcode, long timestamp)
|
||||
private void processControlAnnouncedTrafficUpdate(APCO25Channel channel, ServiceOptions serviceOptions,
|
||||
List<Identifier> identifiers, Opcode opcode, long timestamp, String context)
|
||||
{
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(identifiers, timestamp);
|
||||
mTrafficChannelManager.getTalkerAliasManager().enrichMutable(mic);
|
||||
mTrafficChannelManager.processP1ChannelUpdate(channel, serviceOptions, mic, opcode, timestamp);
|
||||
mTrafficChannelManager.processP1ControlAnnouncedTrafficUpdate(channel, serviceOptions, mic, opcode, timestamp, context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,8 +430,9 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
}
|
||||
|
||||
mTrafficChannelManager.getTalkerAliasManager().enrichMutable(getIdentifierCollection());
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), getCurrentChannel(), decodeEventType,
|
||||
serviceOptions, getIdentifierCollection(), timestamp, null );
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(getIdentifierCollection().getIdentifiers(), timestamp);
|
||||
mTrafficChannelManager.processP1TrafficCurrentUser(getCurrentFrequency(), getCurrentChannel(), decodeEventType,
|
||||
serviceOptions, mic, timestamp, null, lcw.toString());
|
||||
|
||||
if(serviceOptions.isEncrypted())
|
||||
{
|
||||
@@ -760,15 +757,15 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
if(ambtc instanceof AMBTCUnitToUnitVoiceServiceChannelGrantUpdate upd)
|
||||
{
|
||||
processChannelUpdate(upd.getChannel(), upd.getServiceOptions(), upd.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(upd.getChannel(), upd.getServiceOptions(), upd.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
if(ambtc instanceof AMBTCTelephoneInterconnectChannelGrantUpdate upd)
|
||||
{
|
||||
processChannelUpdate(upd.getChannel(), upd.getServiceOptions(), upd.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(upd.getChannel(), upd.getServiceOptions(), upd.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -784,64 +781,59 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case OSP_GROUP_DATA_CHANNEL_GRANT:
|
||||
if(ambtc instanceof AMBTCGroupDataChannelGrant gdcg)
|
||||
{
|
||||
processChannelGrant(gdcg.getChannel(), gdcg.getServiceOptions(), gdcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlTrafficGrant(gdcg.getChannel(), gdcg.getServiceOptions(), gdcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_VOICE_CHANNEL_GRANT:
|
||||
if(ambtc instanceof AMBTCGroupVoiceChannelGrant gvcg)
|
||||
{
|
||||
processChannelGrant(gvcg.getChannel(), gvcg.getServiceOptions(), gvcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlTrafficGrant(gvcg.getChannel(), gvcg.getServiceOptions(), gvcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_INDIVIDUAL_DATA_CHANNEL_GRANT:
|
||||
if(ambtc instanceof AMBTCIndividualDataChannelGrant idcg)
|
||||
{
|
||||
processChannelGrant(idcg.getChannel(), idcg.getServiceOptions(), idcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlTrafficGrant(idcg.getChannel(), idcg.getServiceOptions(), idcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
|
||||
if(ambtc instanceof AMBTCTelephoneInterconnectChannelGrant ticg)
|
||||
{
|
||||
processChannelGrant(ticg.getChannel(), ticg.getServiceOptions(), ticg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlTrafficGrant(ticg.getChannel(), ticg.getServiceOptions(), ticg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
|
||||
if(ambtc instanceof AMBTCUnitToUnitVoiceServiceChannelGrant uuvscg)
|
||||
{
|
||||
processChannelGrant(uuvscg.getChannel(), uuvscg.getServiceOptions(), uuvscg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlTrafficGrant(uuvscg.getChannel(), uuvscg.getServiceOptions(), uuvscg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
case MOTOROLA_OSP_GROUP_REGROUP_CHANNEL_GRANT:
|
||||
if(ambtc instanceof AMBTCMotorolaGroupRegroupChannelGrant mgrcg)
|
||||
{
|
||||
processChannelGrant(mgrcg.getChannel(), mgrcg.getServiceOptions(), mgrcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp());
|
||||
processControlTrafficGrant(mgrcg.getChannel(), mgrcg.getServiceOptions(), mgrcg.getIdentifiers(),
|
||||
ambtc.getHeader().getOpcode(), ambtc.getTimestamp(), ambtc.toString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a Header Data Unit message and starts a new call event.
|
||||
* Processes a Header Data Unit message
|
||||
*/
|
||||
private void processHDU(IMessage message)
|
||||
{
|
||||
if(message.isValid() && message instanceof HDUMessage hdu)
|
||||
{
|
||||
HeaderData headerData = hdu.getHeaderData();
|
||||
ServiceOptions serviceOptions = headerData.isEncryptedAudio() ?
|
||||
VoiceServiceOptions.createEncrypted() : VoiceServiceOptions.createUnencrypted();
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(hdu.getIdentifiers(), message.getTimestamp());
|
||||
String details = headerData.isEncryptedAudio() ? headerData.getEncryptionKey().toString() : null;
|
||||
DecodeEventType type = headerData.isEncryptedAudio() ? DecodeEventType.CALL_ENCRYPTED : DecodeEventType.CALL;
|
||||
mTrafficChannelManager.getTalkerAliasManager().enrichMutable(mic);
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), getCurrentChannel(), type,
|
||||
serviceOptions, mic, message.getTimestamp(), details);
|
||||
//Run the talkgroup through the patch group manager so we don't get a plain talkgroup in addition to the patch
|
||||
Identifier talkgroup = mPatchGroupManager.update(headerData.getTalkgroup(), message.getTimestamp());
|
||||
mTrafficChannelManager.processP1TrafficCurrentUser(getCurrentFrequency(), talkgroup, hdu.getTimestamp(), message.toString());
|
||||
|
||||
if(headerData.isEncryptedAudio())
|
||||
{
|
||||
@@ -881,24 +873,19 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
if(esp.isEncryptedAudio())
|
||||
{
|
||||
getIdentifierCollection().update(esp.getIdentifiers());
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), esp.getEncryptionKey(),
|
||||
message.getTimestamp());
|
||||
mTrafficChannelManager.processP1TrafficCurrentUser(getCurrentFrequency(), esp.getEncryptionKey(),
|
||||
message.getTimestamp(), ldu2.toString());
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.ENCRYPTED));
|
||||
}
|
||||
else
|
||||
{
|
||||
getIdentifierCollection().remove(Form.ENCRYPTION_KEY);
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), null,
|
||||
message.getTimestamp());
|
||||
mTrafficChannelManager.processP1TrafficCurrentUser(getCurrentFrequency(), null,
|
||||
message.getTimestamp(), ldu2.toString());
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), null, message.getTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -906,8 +893,12 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
*/
|
||||
private void processTDU(P25P1Message message)
|
||||
{
|
||||
mTrafficChannelManager.closeP1CallEvent(getCurrentFrequency(), message.getTimestamp());
|
||||
getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM);
|
||||
//If the TCM indicates that it closed the traffic call event, then remove the FROM users
|
||||
if(mTrafficChannelManager.processP1TrafficCallEnd(getCurrentFrequency(), message.getTimestamp(), "TDU:" + message))
|
||||
{
|
||||
getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM);
|
||||
}
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.DECODE, State.ACTIVE));
|
||||
}
|
||||
|
||||
@@ -919,8 +910,12 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
*/
|
||||
private void processTDULC(P25P1Message message)
|
||||
{
|
||||
mTrafficChannelManager.closeP1CallEvent(getCurrentFrequency(), message.getTimestamp());
|
||||
getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM);
|
||||
boolean completed = mTrafficChannelManager.processP1TrafficCallEnd(getCurrentFrequency(), message.getTimestamp(), "TDULC:" + message);
|
||||
|
||||
if(completed)
|
||||
{
|
||||
getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM);
|
||||
}
|
||||
|
||||
if(message instanceof TDULinkControlMessage tdulc)
|
||||
{
|
||||
@@ -931,6 +926,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
//Set the state to ACTIVE while the call continues in hangtime. The processLC() method will signal
|
||||
// the channel teardown when that happens.
|
||||
broadcast(new DecoderStateEvent(this, Event.DECODE, State.ACTIVE));
|
||||
//Don't signal call end to the TCM or remove FROM identifiers unless the call has started on this traffic channel.
|
||||
processLC(lcw, message.getTimestamp(), true);
|
||||
}
|
||||
}
|
||||
@@ -1724,48 +1720,48 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case MOTOROLA_OSP_GROUP_REGROUP_CHANNEL_UPDATE:
|
||||
if(tsbk instanceof MotorolaGroupRegroupChannelUpdate pgvcgu)
|
||||
{
|
||||
processChannelUpdate(pgvcgu.getChannel1(), null, Collections.singletonList(pgvcgu.getPatchGroup1()),
|
||||
tsbk.getOpcode(), pgvcgu.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(pgvcgu.getChannel1(), null, Collections.singletonList(pgvcgu.getPatchGroup1()),
|
||||
tsbk.getOpcode(), pgvcgu.getTimestamp(), tsbk.toString());
|
||||
|
||||
if(pgvcgu.hasPatchGroup2())
|
||||
{
|
||||
processChannelUpdate(pgvcgu.getChannel2(), null, Collections.singletonList(pgvcgu.getPatchGroup2()),
|
||||
tsbk.getOpcode(), pgvcgu.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(pgvcgu.getChannel2(), null, Collections.singletonList(pgvcgu.getPatchGroup2()),
|
||||
tsbk.getOpcode(), pgvcgu.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
if(tsbk instanceof GroupVoiceChannelGrantUpdate gvcgu)
|
||||
{
|
||||
processChannelUpdate(gvcgu.getChannelA(), null, Collections.singletonList(gvcgu.getGroupAddressA()),
|
||||
tsbk.getOpcode(), gvcgu.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(gvcgu.getChannelA(), null, Collections.singletonList(gvcgu.getGroupAddressA()),
|
||||
tsbk.getOpcode(), gvcgu.getTimestamp(), tsbk.toString());
|
||||
|
||||
if(gvcgu.hasGroupB())
|
||||
{
|
||||
processChannelGrant(gvcgu.getChannelB(), null, Collections.singletonList(gvcgu.getGroupAddressB()),
|
||||
tsbk.getOpcode(), gvcgu.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(gvcgu.getChannelB(), null, Collections.singletonList(gvcgu.getGroupAddressB()),
|
||||
tsbk.getOpcode(), gvcgu.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
if(tsbk instanceof GroupVoiceChannelGrantUpdateExplicit gvcgue)
|
||||
{
|
||||
processChannelUpdate(gvcgue.getChannel(), gvcgue.getServiceOptions(), gvcgue.getIdentifiers(),
|
||||
tsbk.getOpcode(), gvcgue.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(gvcgue.getChannel(), gvcgue.getServiceOptions(), gvcgue.getIdentifiers(),
|
||||
tsbk.getOpcode(), gvcgue.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
if(tsbk instanceof TelephoneInterconnectVoiceChannelGrantUpdate tivcgu)
|
||||
{
|
||||
processChannelUpdate(tivcgu.getChannel(), tivcgu.getServiceOptions(), tivcgu.getIdentifiers(),
|
||||
tsbk.getOpcode(), tivcgu.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(tivcgu.getChannel(), tivcgu.getServiceOptions(), tivcgu.getIdentifiers(),
|
||||
tsbk.getOpcode(), tivcgu.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
if(tsbk instanceof UnitToUnitVoiceChannelGrantUpdate uuvcgu)
|
||||
{
|
||||
processChannelUpdate(uuvcgu.getChannel(), null, uuvcgu.getIdentifiers(), tsbk.getOpcode(),
|
||||
uuvcgu.getTimestamp());
|
||||
processControlAnnouncedTrafficUpdate(uuvcgu.getChannel(), null, uuvcgu.getIdentifiers(), tsbk.getOpcode(),
|
||||
uuvcgu.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1781,43 +1777,43 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case MOTOROLA_OSP_GROUP_REGROUP_CHANNEL_GRANT:
|
||||
if(tsbk instanceof MotorolaGroupRegroupChannelGrant mgrcg)
|
||||
{
|
||||
processChannelGrant(mgrcg.getChannel(), mgrcg.getServiceOptions(), mgrcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
mgrcg.getTimestamp());
|
||||
processControlTrafficGrant(mgrcg.getChannel(), mgrcg.getServiceOptions(), mgrcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
mgrcg.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_DATA_CHANNEL_GRANT:
|
||||
if(tsbk instanceof GroupDataChannelGrant gdcg)
|
||||
{
|
||||
processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(), gdcg.getIdentifiers(),
|
||||
tsbk.getOpcode(), gdcg.getTimestamp());
|
||||
processControlTrafficGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(), gdcg.getIdentifiers(),
|
||||
tsbk.getOpcode(), gdcg.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_VOICE_CHANNEL_GRANT:
|
||||
if(tsbk instanceof GroupVoiceChannelGrant gvcg)
|
||||
{
|
||||
processChannelGrant(gvcg.getChannel(), gvcg.getServiceOptions(), gvcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
gvcg.getTimestamp());
|
||||
processControlTrafficGrant(gvcg.getChannel(), gvcg.getServiceOptions(), gvcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
gvcg.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_SNDCP_DATA_CHANNEL_GRANT:
|
||||
if(tsbk instanceof SNDCPDataChannelGrant dcg)
|
||||
{
|
||||
processChannelGrant(dcg.getChannel(), dcg.getServiceOptions(), dcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
dcg.getTimestamp());
|
||||
processControlTrafficGrant(dcg.getChannel(), dcg.getServiceOptions(), dcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
dcg.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
|
||||
if(tsbk instanceof UnitToUnitVoiceChannelGrant uuvcg)
|
||||
{
|
||||
processChannelGrant(uuvcg.getChannel(), null, uuvcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
uuvcg.getTimestamp());
|
||||
processControlTrafficGrant(uuvcg.getChannel(), null, uuvcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
uuvcg.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
|
||||
if(tsbk instanceof TelephoneInterconnectVoiceChannelGrant tivcg)
|
||||
{
|
||||
processChannelGrant(tivcg.getChannel(), tivcg.getServiceOptions(), tivcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
tivcg.getTimestamp());
|
||||
processControlTrafficGrant(tivcg.getChannel(), tivcg.getServiceOptions(), tivcg.getIdentifiers(), tsbk.getOpcode(),
|
||||
tivcg.getTimestamp(), tsbk.toString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1843,7 +1839,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1854,14 +1850,14 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
if(lcw instanceof LCMotorolaTalkComplete tc)
|
||||
{
|
||||
getIdentifierCollection().update(tc.getAddress());
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), tc.getAddress(), timestamp);
|
||||
closeCurrentCallEvent(timestamp);
|
||||
//Note: don't update the traffic channel manager because the current event is already in closeout
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
break;
|
||||
|
||||
//Call termination
|
||||
case CALL_TERMINATION_OR_CANCELLATION:
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
|
||||
//Note: we only broadcast an END state if this is a network-commanded channel teardown
|
||||
if(lcw instanceof LCCallTermination lcct && lcct.isNetworkCommandedTeardown())
|
||||
@@ -1870,38 +1866,17 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
}
|
||||
break;
|
||||
|
||||
//Calls in-progress on another channel
|
||||
//Voice Channel Update messages - indicates calls in-progress on another channel - ignored
|
||||
case GROUP_VOICE_CHANNEL_UPDATE:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
}
|
||||
|
||||
if(lcw instanceof LCGroupVoiceChannelUpdate vcu)
|
||||
{
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(vcu.getGroupAddressA(), timestamp);
|
||||
mTrafficChannelManager.processP1ChannelUpdate(vcu.getChannelA(), null, mic,
|
||||
null, timestamp);
|
||||
|
||||
if(vcu.hasChannelB())
|
||||
{
|
||||
MutableIdentifierCollection micB = getMutableIdentifierCollection(vcu.getGroupAddressB(), timestamp);
|
||||
mTrafficChannelManager.processP1ChannelUpdate(vcu.getChannelB(), null, micB,
|
||||
null, timestamp);
|
||||
}
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
break;
|
||||
case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
}
|
||||
|
||||
if(lcw instanceof LCGroupVoiceChannelUpdateExplicit vcu)
|
||||
{
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(vcu.getGroupAddress(), timestamp);
|
||||
mTrafficChannelManager.processP1ChannelUpdate(vcu.getChannel(), vcu.getServiceOptions(), mic,
|
||||
null, timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1923,7 +1898,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
|
||||
mNetworkConfigurationMonitor.process(lcw);
|
||||
@@ -1945,7 +1920,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
|
||||
mNetworkConfigurationMonitor.process(lcw);
|
||||
@@ -1968,7 +1943,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
|
||||
mNetworkConfigurationMonitor.process(lcw);
|
||||
@@ -1990,7 +1965,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
|
||||
mNetworkConfigurationMonitor.process(lcw);
|
||||
@@ -2006,7 +1981,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case SYSTEM_SERVICE_BROADCAST:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
mNetworkConfigurationMonitor.process(lcw);
|
||||
break;
|
||||
@@ -2019,23 +1994,17 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
mPatchGroupManager.removePatchGroups(lcw.getIdentifiers());
|
||||
break;
|
||||
case MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_UPDATE:
|
||||
//Voice Channel Update message - indicates calls in-progress on another channel - ignored
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
}
|
||||
|
||||
if(lcw instanceof LCMotorolaGroupRegroupVoiceChannelUpdate vcu)
|
||||
{
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(vcu.getSupergroupAddress(), timestamp);
|
||||
mTrafficChannelManager.processP1ChannelUpdate(vcu.getChannel(), vcu.getServiceOptions(), mic,
|
||||
null, timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
break;
|
||||
case MOTOROLA_TALKER_ALIAS_HEADER:
|
||||
case MOTOROLA_TALKER_ALIAS_DATA_BLOCK:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2043,14 +2012,14 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case CALL_ALERT:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
broadcastEvent(lcw.getIdentifiers(), timestamp, DecodeEventType.PAGE, "Call Alert");
|
||||
break;
|
||||
case EXTENDED_FUNCTION_COMMAND:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
if(lcw instanceof LCExtendedFunctionCommand efc)
|
||||
{
|
||||
@@ -2062,7 +2031,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case EXTENDED_FUNCTION_COMMAND_EXTENDED:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
if(lcw instanceof LCExtendedFunctionCommandExtended efce)
|
||||
{
|
||||
@@ -2072,14 +2041,14 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case GROUP_AFFILIATION_QUERY:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
broadcastEvent(lcw.getIdentifiers(), timestamp, DecodeEventType.QUERY, "Group Affiliation");
|
||||
break;
|
||||
case MESSAGE_UPDATE:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
if(lcw instanceof LCMessageUpdate mu)
|
||||
{
|
||||
@@ -2090,7 +2059,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case MESSAGE_UPDATE_EXTENDED:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
if(lcw instanceof LCMessageUpdateExtended mue)
|
||||
{
|
||||
@@ -2101,14 +2070,14 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case STATUS_QUERY:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
broadcastEvent(lcw.getIdentifiers(), timestamp, DecodeEventType.QUERY, "Status");
|
||||
break;
|
||||
case STATUS_UPDATE:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
if(lcw instanceof LCStatusUpdate su)
|
||||
{
|
||||
@@ -2119,7 +2088,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case STATUS_UPDATE_EXTENDED:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
if(lcw instanceof LCStatusUpdateExtended sue)
|
||||
{
|
||||
@@ -2130,7 +2099,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
if(lcw instanceof LCTelephoneInterconnectAnswerRequest tiar)
|
||||
{
|
||||
@@ -2141,21 +2110,21 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case UNIT_AUTHENTICATION_COMMAND:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
broadcastEvent(lcw.getIdentifiers(), timestamp, DecodeEventType.COMMAND, "Authenticate Unit");
|
||||
break;
|
||||
case UNIT_REGISTRATION_COMMAND:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
broadcastEvent(lcw.getIdentifiers(), timestamp, DecodeEventType.COMMAND, "Unit Registration");
|
||||
break;
|
||||
case UNIT_TO_UNIT_ANSWER_REQUEST:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
broadcastEvent(lcw.getIdentifiers(), timestamp, DecodeEventType.PAGE, "Unit-to-Unit Answer Request");
|
||||
break;
|
||||
@@ -2174,7 +2143,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
case MOTOROLA_UNIT_GPS:
|
||||
if(lcw instanceof LCMotorolaUnitGPS gps)
|
||||
{
|
||||
mTrafficChannelManager.processP1CurrentUser(getCurrentFrequency(), gps.getLocation(), timestamp);
|
||||
mTrafficChannelManager.processP1TrafficCurrentUser(getCurrentFrequency(), gps.getLocation(), timestamp, lcw.toString());
|
||||
MutableIdentifierCollection mic = getMutableIdentifierCollection(gps.getIdentifiers(), timestamp);
|
||||
|
||||
PlottableDecodeEvent event = PlottableDecodeEvent.plottableBuilder(DecodeEventType.GPS, timestamp)
|
||||
@@ -2190,7 +2159,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
break;
|
||||
case SOURCE_ID_EXTENSION:
|
||||
@@ -2199,7 +2168,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
default:
|
||||
if(isTerminator)
|
||||
{
|
||||
closeCurrentCallEvent(timestamp);
|
||||
closeCurrentCallEvent(timestamp, lcw.toString());
|
||||
}
|
||||
|
||||
// if(lcw.getVendor().isLoggable())
|
||||
@@ -2215,11 +2184,11 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
/**
|
||||
* Closes the call event on the current channel.
|
||||
* @param timestamp
|
||||
* @param timestamp for the closure
|
||||
*/
|
||||
private void closeCurrentCallEvent(long timestamp)
|
||||
private void closeCurrentCallEvent(long timestamp, String context)
|
||||
{
|
||||
mTrafficChannelManager.closeP1CallEvent(getCurrentFrequency(), timestamp);
|
||||
mTrafficChannelManager.processP1TrafficCallEnd(getCurrentFrequency(), timestamp, context);
|
||||
getIdentifierCollection().remove(IdentifierClass.USER);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ public class LCGroupVoiceChannelUser extends VoiceLinkControlMessage implements
|
||||
{
|
||||
if(mSourceAddress == null)
|
||||
{
|
||||
if(isExtensionRequired() && mSourceIdExtension != null)
|
||||
if(isExtensionRequired() && mSourceIdExtension != null && mSourceIdExtension.isValidExtendedSource())
|
||||
{
|
||||
mSourceAddress = APCO25FullyQualifiedRadioIdentifier.createFrom(getInt(SOURCE_ADDRESS),
|
||||
mSourceIdExtension.getWACN(), mSourceIdExtension.getSystem(), mSourceIdExtension.getId());
|
||||
|
||||
@@ -65,6 +65,16 @@ public class LCSourceIDExtension extends LinkControlWord implements IExtendedSou
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that at least one of the WACN, System, or ID values are non-zero.
|
||||
* @return
|
||||
*/
|
||||
public boolean isValidExtendedSource()
|
||||
{
|
||||
return getWACN() != 0 && getSystem() != 0 && getId() != 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isTerminator()
|
||||
{
|
||||
|
||||
@@ -38,7 +38,6 @@ import io.github.dsheirer.identifier.IdentifierUpdateListener;
|
||||
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
|
||||
import io.github.dsheirer.identifier.patch.PatchGroupManager;
|
||||
import io.github.dsheirer.module.ProcessingChain;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager;
|
||||
import io.github.dsheirer.module.decode.p25.audio.P25P2AudioModule;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters;
|
||||
@@ -123,7 +122,7 @@ public class P25P2DecoderHDQPSK extends P25P2Decoder implements IdentifierUpdate
|
||||
|
||||
//The Costas Loop receives symbol-inversion correction requests when detected.
|
||||
//The PLL gain monitor receives sync detect/loss signals from the message framer
|
||||
mMessageFramer = new P25P2MessageFramer(mCostasLoop, DecoderType.P25_PHASE2.getProtocol().getBitRate());
|
||||
mMessageFramer = new P25P2MessageFramer(mCostasLoop);
|
||||
|
||||
if(mDecodeConfigP25Phase2 !=null)
|
||||
{
|
||||
@@ -146,8 +145,6 @@ public class P25P2DecoderHDQPSK extends P25P2Decoder implements IdentifierUpdate
|
||||
@Override
|
||||
public void receive(ComplexSamples samples)
|
||||
{
|
||||
mMessageFramer.setCurrentTime(System.currentTimeMillis());
|
||||
|
||||
float[] i = mIBasebandFilter.filter(samples.i());
|
||||
float[] q = mQBasebandFilter.filter(samples.q());
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2024 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
|
||||
@@ -58,8 +58,6 @@ public class P25P2DecoderHDQPSKInstrumented extends P25P2DecoderHDQPSK
|
||||
@Override
|
||||
public void receive(ComplexSamples samples)
|
||||
{
|
||||
mMessageFramer.setCurrentTime(System.currentTimeMillis());
|
||||
|
||||
float[] i = mIBasebandFilter.filter(samples.i());
|
||||
float[] q = mQBasebandFilter.filter(samples.q());
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.MotorolaT
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.EncryptionSynchronizationSequence;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.IP25ChannelGrantDetailProvider;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacOpcode;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacPduType;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.AcknowledgeResponseFNEAbbreviated;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.AcknowledgeResponseFNEExtended;
|
||||
@@ -127,7 +126,6 @@ import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorol
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUserExtended;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaQueuedResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot;
|
||||
import io.github.dsheirer.module.decode.p25.reference.ServiceOptions;
|
||||
import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
import java.util.Collections;
|
||||
@@ -191,7 +189,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
protected void resetState()
|
||||
{
|
||||
super.resetState();
|
||||
closeCurrentCallEvent(true, false);
|
||||
mTrafficChannelManager.processP2TrafficCallEnd(getCurrentFrequency(), getTimeslot(), System.currentTimeMillis(), "RESET STATE INVOKED");
|
||||
mEndPttOnFacchCounter = 0;
|
||||
}
|
||||
|
||||
@@ -238,13 +236,16 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot()));
|
||||
}
|
||||
|
||||
//If we're tracking the call event, update the duration on it
|
||||
mTrafficChannelManager.processP2TrafficVoice(getCurrentFrequency(), getTimeslot(), message.getTimestamp());
|
||||
}
|
||||
else if(message instanceof EncryptionSynchronizationSequence ess)
|
||||
{
|
||||
//We don't send any state events for this message since it can only occur in conjunction with
|
||||
//an audio frame that already sends the call state event
|
||||
getIdentifierCollection().update(message.getIdentifiers());
|
||||
mTrafficChannelManager.processP2CurrentUser(getCurrentFrequency(), getTimeslot(), ess.getEncryptionKey(), ess.getTimestamp());
|
||||
mTrafficChannelManager.processP2TrafficCurrentUser(getCurrentFrequency(), getTimeslot(), ess.getEncryptionKey(), ess.getTimestamp());
|
||||
|
||||
if(ess.isEncrypted())
|
||||
{
|
||||
@@ -257,11 +258,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
}
|
||||
else if(message instanceof MotorolaTalkerAliasComplete tac)
|
||||
{
|
||||
//Debug
|
||||
// if(!mTrafficChannelManager.getTalkerAliasManager().hasAlias(tac.getRadio()))
|
||||
// {
|
||||
// System.out.println(tac);
|
||||
// }
|
||||
mTrafficChannelManager.getTalkerAliasManager().update(tac.getRadio(), tac.getAlias());
|
||||
}
|
||||
}
|
||||
@@ -279,6 +275,11 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case MAC_0_SIGNAL:
|
||||
continueState(State.CONTROL);
|
||||
break;
|
||||
case MAC_6_HANGTIME:
|
||||
//During hangtime, the from talker is no longer involved in the call ... remove it because sometimes
|
||||
//we don't get the end PTT to signal the end.
|
||||
getIdentifierCollection().remove(Role.FROM);
|
||||
break;
|
||||
}
|
||||
|
||||
MacStructure mac = message.getMacStructure();
|
||||
@@ -302,9 +303,19 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case TDMA_01_GROUP_VOICE_CHANNEL_USER_ABBREVIATED:
|
||||
case TDMA_02_UNIT_TO_UNIT_VOICE_CHANNEL_USER_ABBREVIATED:
|
||||
case TDMA_03_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
|
||||
case TDMA_21_GROUP_VOICE_CHANNEL_USER_EXTENDED:
|
||||
case TDMA_22_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
|
||||
processChannelUser(message, mac);
|
||||
break;
|
||||
case TDMA_05_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE_IMPLICIT:
|
||||
case TDMA_25_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE_EXPLICIT:
|
||||
case PHASE1_42_GROUP_VOICE_CHANNEL_GRANT_UPDATE_IMPLICIT:
|
||||
case PHASE1_46_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_ABBREVIATED:
|
||||
case PHASE1_49_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE_IMPLICIT:
|
||||
case PHASE1_C3_GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
case PHASE1_C6_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED_VCH:
|
||||
case PHASE1_C7_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED_LCCH:
|
||||
case PHASE1_C9_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case TDMA_08_NULL_AVOID_ZERO_BIAS:
|
||||
@@ -317,13 +328,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case TDMA_12_INDIVIDUAL_PAGING_WITH_PRIORITY:
|
||||
processPaging(message, mac);
|
||||
break;
|
||||
case TDMA_21_GROUP_VOICE_CHANNEL_USER_EXTENDED:
|
||||
case TDMA_22_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
|
||||
processChannelUser(message, mac);
|
||||
break;
|
||||
case TDMA_25_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE_EXPLICIT:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case TDMA_30_POWER_CONTROL_SIGNAL_QUALITY:
|
||||
processPowerControl(message, mac);
|
||||
break;
|
||||
@@ -337,33 +341,29 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case PHASE1_PARTITION_1_UNKNOWN_OPCODE:
|
||||
break;
|
||||
case PHASE1_40_GROUP_VOICE_CHANNEL_GRANT_IMPLICIT:
|
||||
case PHASE1_44_UNIT_TO_UNIT_VOICE_SERVICE_CHANNEL_GRANT_ABBREVIATED:
|
||||
case PHASE1_48_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_IMPLICIT:
|
||||
case PHASE1_54_SNDCP_DATA_CHANNEL_GRANT:
|
||||
case PHASE1_C8_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_EXPLICIT:
|
||||
case PHASE1_C0_GROUP_VOICE_CHANNEL_GRANT_EXPLICIT:
|
||||
case PHASE1_C4_UNIT_TO_UNIT_VOICE_SERVICE_CHANNEL_GRANT_EXTENDED_VCH:
|
||||
case PHASE1_CF_UNIT_TO_UNIT_VOICE_SERVICE_CHANNEL_GRANT_EXTENDED_LCCH:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_41_GROUP_VOICE_SERVICE_REQUEST:
|
||||
//Inbound only.
|
||||
break;
|
||||
case PHASE1_42_GROUP_VOICE_CHANNEL_GRANT_UPDATE_IMPLICIT:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_44_UNIT_TO_UNIT_VOICE_SERVICE_CHANNEL_GRANT_ABBREVIATED:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_45_UNIT_TO_UNIT_ANSWER_REQUEST_ABBREVIATED:
|
||||
processAnswer(message, mac);
|
||||
break;
|
||||
case PHASE1_46_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_ABBREVIATED:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_48_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_IMPLICIT:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_49_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE_IMPLICIT:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_4A_TELEPHONE_INTERCONNECT_ANSWER_RESPONSE:
|
||||
case PHASE1_C5_UNIT_TO_UNIT_ANSWER_REQUEST_EXTENDED:
|
||||
processAnswer(message, mac);
|
||||
break;
|
||||
case PHASE1_4C_RADIO_UNIT_MONITOR_COMMAND_ABBREVIATED:
|
||||
case PHASE1_5D_RADIO_UNIT_MONITOR_COMMAND_OBSOLETE:
|
||||
case PHASE1_5E_RADIO_UNIT_MONITOR_ENHANCED_COMMAND_ABBREVIATED:
|
||||
case PHASE1_CC_RADIO_UNIT_MONITOR_COMMAND_EXTENDED_VCH:
|
||||
case PHASE1_CD_RADIO_UNIT_MONITOR_COMMAND_EXTENDED_LCCH:
|
||||
case PHASE1_DE_RADIO_UNIT_MONITOR_ENHANCED_COMMAND_EXTENDED:
|
||||
processRadioUnitMonitor(message, mac);
|
||||
break;
|
||||
case PHASE1_52_SNDCP_DATA_CHANNEL_REQUEST:
|
||||
@@ -372,35 +372,37 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case PHASE1_53_SNDCP_DATA_PAGE_RESPONSE:
|
||||
//Ignore - this is an inbound request by the SU
|
||||
break;
|
||||
case PHASE1_54_SNDCP_DATA_CHANNEL_GRANT:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_55_SNDCP_DATA_PAGE_REQUEST:
|
||||
processDataPageRequest(message, mac);
|
||||
break;
|
||||
case PHASE1_58_STATUS_UPDATE_ABBREVIATED:
|
||||
processStatus(message, mac);
|
||||
break;
|
||||
case PHASE1_5A_STATUS_QUERY_ABBREVIATED:
|
||||
case PHASE1_D8_STATUS_UPDATE_EXTENDED_VCH:
|
||||
case PHASE1_D9_STATUS_UPDATE_EXTENDED_LCCH:
|
||||
case PHASE1_DA_STATUS_QUERY_EXTENDED_VCH:
|
||||
case PHASE1_DB_STATUS_QUERY_EXTENDED_LCCH:
|
||||
processStatus(message, mac);
|
||||
break;
|
||||
case PHASE1_5C_MESSAGE_UPDATE_ABBREVIATED:
|
||||
case PHASE1_CE_MESSAGE_UPDATE_EXTENDED_LCCH:
|
||||
case PHASE1_DC_MESSAGE_UPDATE_EXTENDED_VCH:
|
||||
processMessageUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_5D_RADIO_UNIT_MONITOR_COMMAND_OBSOLETE:
|
||||
case PHASE1_5E_RADIO_UNIT_MONITOR_ENHANCED_COMMAND_ABBREVIATED:
|
||||
processRadioUnitMonitor(message, mac);
|
||||
break;
|
||||
case PHASE1_5F_CALL_ALERT_ABBREVIATED:
|
||||
case PHASE1_CB_CALL_ALERT_EXTENDED_LCCH:
|
||||
case PHASE1_DF_CALL_ALERT_EXTENDED_VCH:
|
||||
processCallAlert(message, mac);
|
||||
break;
|
||||
case PHASE1_60_ACKNOWLEDGE_RESPONSE_FNE_ABBREVIATED:
|
||||
case PHASE1_E0_ACKNOWLEDGE_RESPONSE_FNE_EXTENDED:
|
||||
processAcknowledge(message, mac);
|
||||
break;
|
||||
case PHASE1_61_QUEUED_RESPONSE:
|
||||
processQueued(message, mac);
|
||||
break;
|
||||
case PHASE1_64_EXTENDED_FUNCTION_COMMAND_ABBREVIATED:
|
||||
case PHASE1_E4_EXTENDED_FUNCTION_COMMAND_EXTENDED_VCH:
|
||||
case PHASE1_E5_EXTENDED_FUNCTION_COMMAND_EXTENDED_LCCH:
|
||||
processExtendedFunctionCommand(message, mac);
|
||||
break;
|
||||
case PHASE1_67_DENY_RESPONSE:
|
||||
@@ -408,6 +410,8 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
break;
|
||||
case PHASE1_68_GROUP_AFFILIATION_RESPONSE_ABBREVIATED:
|
||||
case PHASE1_6A_GROUP_AFFILIATION_QUERY_ABBREVIATED:
|
||||
case PHASE1_E8_GROUP_AFFILIATION_RESPONSE_EXTENDED:
|
||||
case PHASE1_EA_GROUP_AFFILIATION_QUERY_EXTENDED:
|
||||
processAffiliation(message, mac);
|
||||
break;
|
||||
case PHASE1_6B_LOCATION_REGISTRATION_RESPONSE:
|
||||
@@ -416,6 +420,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case PHASE1_6C_UNIT_REGISTRATION_RESPONSE_ABBREVIATED:
|
||||
case PHASE1_6D_UNIT_REGISTRATION_COMMAND_ABBREVIATED:
|
||||
case PHASE1_6F_DEREGISTRATION_ACKNOWLEDGE:
|
||||
case PHASE1_EC_UNIT_REGISTRATION_RESPONSE_EXTENDED:
|
||||
processUnitRegistration(message, mac);
|
||||
break;
|
||||
case PHASE1_70_SYNCHRONIZATION_BROADCAST:
|
||||
@@ -423,6 +428,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
break;
|
||||
case PHASE1_71_AUTHENTICATION_DEMAND:
|
||||
case PHASE1_72_AUTHENTICATION_FNE_RESPONSE_ABBREVIATED:
|
||||
case PHASE1_F2_AUTHENTICATION_FNE_RESPONSE_EXTENDED:
|
||||
processAuthentication(message, mac);
|
||||
break;
|
||||
case PHASE1_76_ROAMING_ADDRESS_COMMAND:
|
||||
@@ -431,19 +437,24 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
break;
|
||||
case PHASE1_73_IDENTIFIER_UPDATE_TDMA_ABBREVIATED:
|
||||
case PHASE1_74_IDENTIFIER_UPDATE_V_UHF:
|
||||
processNetwork(message, mac);
|
||||
break;
|
||||
case PHASE1_75_TIME_AND_DATE_ANNOUNCEMENT:
|
||||
//Ignore
|
||||
break;
|
||||
case PHASE1_78_SYSTEM_SERVICE_BROADCAST:
|
||||
case PHASE1_79_SECONDARY_CONTROL_CHANNEL_BROADCAST_IMPLICIT:
|
||||
case PHASE1_7A_RFSS_STATUS_BROADCAST_IMPLICIT:
|
||||
case PHASE1_7B_NETWORK_STATUS_BROADCAST_IMPLICIT:
|
||||
case PHASE1_7C_ADJACENT_STATUS_BROADCAST_IMPLICIT:
|
||||
case PHASE1_7D_IDENTIFIER_UPDATE:
|
||||
case PHASE1_D6_SNDCP_DATA_CHANNEL_ANNOUNCEMENT:
|
||||
case PHASE1_E9_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
|
||||
case PHASE1_F3_IDENTIFIER_UPDATE_TDMA_EXTENDED:
|
||||
case PHASE1_FA_RFSS_STATUS_BROADCAST_EXPLICIT:
|
||||
case PHASE1_FB_NETWORK_STATUS_BROADCAST_EXPLICIT:
|
||||
case PHASE1_FC_ADJACENT_STATUS_BROADCAST_EXPLICIT:
|
||||
case PHASE1_FE_ADJACENT_STATUS_BROADCAST_EXTENDED_EXPLICIT:
|
||||
processNetwork(message, mac);
|
||||
break;
|
||||
case PHASE1_75_TIME_AND_DATE_ANNOUNCEMENT:
|
||||
//Ignore
|
||||
break;
|
||||
|
||||
/**
|
||||
* Partition 3 Opcodes
|
||||
@@ -458,88 +469,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
}
|
||||
processChannelUser(message, mac);
|
||||
break;
|
||||
case PHASE1_C0_GROUP_VOICE_CHANNEL_GRANT_EXPLICIT:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_C3_GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_C4_UNIT_TO_UNIT_VOICE_SERVICE_CHANNEL_GRANT_EXTENDED_VCH:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_C5_UNIT_TO_UNIT_ANSWER_REQUEST_EXTENDED:
|
||||
processAnswer(message, mac);
|
||||
break;
|
||||
case PHASE1_C6_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED_VCH:
|
||||
case PHASE1_C7_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED_LCCH:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_C8_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_EXPLICIT:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_C9_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
processChannelGrantUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_CB_CALL_ALERT_EXTENDED_LCCH:
|
||||
processCallAlert(message, mac);
|
||||
break;
|
||||
case PHASE1_CC_RADIO_UNIT_MONITOR_COMMAND_EXTENDED_VCH:
|
||||
case PHASE1_CD_RADIO_UNIT_MONITOR_COMMAND_EXTENDED_LCCH:
|
||||
processRadioUnitMonitor(message, mac);
|
||||
break;
|
||||
case PHASE1_CE_MESSAGE_UPDATE_EXTENDED_LCCH:
|
||||
processMessageUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_CF_UNIT_TO_UNIT_VOICE_SERVICE_CHANNEL_GRANT_EXTENDED_LCCH:
|
||||
processChannelGrant(message, mac);
|
||||
break;
|
||||
case PHASE1_D6_SNDCP_DATA_CHANNEL_ANNOUNCEMENT:
|
||||
processNetwork(message, mac);
|
||||
break;
|
||||
case PHASE1_D8_STATUS_UPDATE_EXTENDED_VCH:
|
||||
case PHASE1_D9_STATUS_UPDATE_EXTENDED_LCCH:
|
||||
case PHASE1_DA_STATUS_QUERY_EXTENDED_VCH:
|
||||
case PHASE1_DB_STATUS_QUERY_EXTENDED_LCCH:
|
||||
processStatus(message, mac);
|
||||
break;
|
||||
case PHASE1_DC_MESSAGE_UPDATE_EXTENDED_VCH:
|
||||
processMessageUpdate(message, mac);
|
||||
break;
|
||||
case PHASE1_DE_RADIO_UNIT_MONITOR_ENHANCED_COMMAND_EXTENDED:
|
||||
processRadioUnitMonitor(message, mac);
|
||||
break;
|
||||
case PHASE1_DF_CALL_ALERT_EXTENDED_VCH:
|
||||
processCallAlert(message, mac);
|
||||
break;
|
||||
case PHASE1_E0_ACKNOWLEDGE_RESPONSE_FNE_EXTENDED:
|
||||
processAcknowledge(message, mac);
|
||||
break;
|
||||
case PHASE1_E4_EXTENDED_FUNCTION_COMMAND_EXTENDED_VCH:
|
||||
case PHASE1_E5_EXTENDED_FUNCTION_COMMAND_EXTENDED_LCCH:
|
||||
processExtendedFunctionCommand(message, mac);
|
||||
break;
|
||||
case PHASE1_E8_GROUP_AFFILIATION_RESPONSE_EXTENDED:
|
||||
processAffiliation(message, mac);
|
||||
break;
|
||||
case PHASE1_E9_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
|
||||
processNetwork(message, mac);
|
||||
break;
|
||||
case PHASE1_EA_GROUP_AFFILIATION_QUERY_EXTENDED:
|
||||
processAffiliation(message, mac);
|
||||
break;
|
||||
case PHASE1_EC_UNIT_REGISTRATION_RESPONSE_EXTENDED:
|
||||
processUnitRegistration(message, mac);
|
||||
break;
|
||||
case PHASE1_F2_AUTHENTICATION_FNE_RESPONSE_EXTENDED:
|
||||
processAuthentication(message, mac);
|
||||
break;
|
||||
case PHASE1_F3_IDENTIFIER_UPDATE_TDMA_EXTENDED:
|
||||
case PHASE1_FA_RFSS_STATUS_BROADCAST_EXPLICIT:
|
||||
case PHASE1_FB_NETWORK_STATUS_BROADCAST_EXPLICIT:
|
||||
case PHASE1_FC_ADJACENT_STATUS_BROADCAST_EXPLICIT:
|
||||
case PHASE1_FE_ADJACENT_STATUS_BROADCAST_EXTENDED_EXPLICIT:
|
||||
processNetwork(message, mac);
|
||||
break;
|
||||
|
||||
/**
|
||||
* Partition 2 Opcodes
|
||||
@@ -835,7 +764,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
//Add the traffic channel to the IC
|
||||
ic.update(cgdp.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelGrant(cgdp.getChannel(), cgdp.getServiceOptions(), ic, mac.getOpcode(),
|
||||
message.getTimestamp());
|
||||
message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -864,7 +793,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUser(cgu.getGroupAddress1(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel1());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel1(), cgu.getServiceOptions1(), mic,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
|
||||
if(cgu.hasGroup2())
|
||||
@@ -876,7 +805,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic2 = getIdentifierCollectionForUser(cgu.getGroupAddress2(), message.getTimestamp());
|
||||
mic2.update(cgu.getChannel1());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel1(), cgu.getServiceOptions2(), mic2,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -889,7 +818,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic3 = getIdentifierCollectionForUser(cgu.getGroupAddress3(), message.getTimestamp());
|
||||
mic3.update(cgu.getChannel1());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel1(), cgu.getServiceOptions3(), mic3,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -904,7 +833,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUser(cgu.getGroupAddress1(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel1());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel1(), cgu.getServiceOptions1(), mic,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
|
||||
if(cgu.hasGroup2())
|
||||
@@ -916,7 +845,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic2 = getIdentifierCollectionForUser(cgu.getGroupAddress2(), message.getTimestamp());
|
||||
mic2.update(cgu.getChannel1());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel1(), cgu.getServiceOptions2(), mic2,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -934,7 +863,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUser(cgu.getGroupAddress1(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel1());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel1(), serviceOptions, mic, mac.getOpcode(),
|
||||
message.getTimestamp());
|
||||
message.getTimestamp(), mac.toString());
|
||||
}
|
||||
|
||||
if(cgu.hasGroup2())
|
||||
@@ -946,7 +875,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic2 = getIdentifierCollectionForUser(cgu.getGroupAddress2(), message.getTimestamp());
|
||||
mic2.update(cgu.getChannel1());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel1(), serviceOptions, mic2,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -963,7 +892,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUsers(cgu.getIdentifiers(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel(), serviceOptions, mic, mac.getOpcode(),
|
||||
message.getTimestamp());
|
||||
message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -979,7 +908,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUsers(cgu.getIdentifiers(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel(), serviceOptions, mic, mac.getOpcode(),
|
||||
message.getTimestamp());
|
||||
message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -993,7 +922,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUser(cgu.getGroupAddress(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel(), cgu.getServiceOptions(), mic,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1009,7 +938,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUsers(cgu.getIdentifiers(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel(), serviceOptions, mic, mac.getOpcode(),
|
||||
message.getTimestamp());
|
||||
message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1023,7 +952,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUsers(cgu.getIdentifiers(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel(), cgu.getServiceOptions(), mic,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1037,7 +966,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUsers(cgu.getIdentifiers(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel(), cgu.getServiceOptions(), mic,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1052,7 +981,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUser(cgu.getPatchgroup(), message.getTimestamp());
|
||||
mic.update(cgu.getChannel());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannel(), cgu.getServiceOptions(), mic,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1070,7 +999,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic = getIdentifierCollectionForUser(cgu.getPatchgroupA(), message.getTimestamp());
|
||||
mic.update(cgu.getChannelA());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannelA(), serviceOptions, mic, mac.getOpcode(),
|
||||
message.getTimestamp());
|
||||
message.getTimestamp(), mac.toString());
|
||||
}
|
||||
|
||||
if(cgu.hasPatchgroupB())
|
||||
@@ -1083,7 +1012,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
MutableIdentifierCollection mic2 = getIdentifierCollectionForUser(cgu.getPatchgroupB(), message.getTimestamp());
|
||||
mic2.update(cgu.getChannelB());
|
||||
mTrafficChannelManager.processP2ChannelUpdate(cgu.getChannelB(), serviceOptions, mic2,
|
||||
mac.getOpcode(), message.getTimestamp());
|
||||
mac.getOpcode(), message.getTimestamp(), mac.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1129,6 +1058,22 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentChannel(IChannelDescriptor channel)
|
||||
{
|
||||
if(channel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(channel instanceof APCO25Channel apco25Channel && apco25Channel.getTimeslot() != getTimeslot())
|
||||
{
|
||||
channel = apco25Channel.decorateAs(getTimeslot());
|
||||
}
|
||||
|
||||
super.setCurrentChannel(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel user (ie current user on this channel).
|
||||
*
|
||||
@@ -1152,7 +1097,9 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
if(mac instanceof IServiceOptionsProvider sop)
|
||||
{
|
||||
IChannelDescriptor currentChannel = mTrafficChannelManager.processP2CurrentUser(getCurrentFrequency(), getTimeslot(), getCurrentChannel(), sop.getServiceOptions(), mac.getOpcode(), getIdentifierCollection().copyOf(), message.getTimestamp(), null);
|
||||
IChannelDescriptor currentChannel = mTrafficChannelManager.processP2TrafficCurrentUser(getCurrentFrequency(),
|
||||
getTimeslot(), getCurrentChannel(), sop.getServiceOptions(), mac.getOpcode(),
|
||||
getIdentifierCollection().copyOf(), message.getTimestamp(), null, message.toString());
|
||||
|
||||
if(getCurrentChannel() == null)
|
||||
{
|
||||
@@ -1195,9 +1142,14 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
if(mac instanceof PushToTalk ptt)
|
||||
{
|
||||
VoiceServiceOptions vso = ptt.isEncrypted() ? VoiceServiceOptions.createEncrypted() : VoiceServiceOptions.createUnencrypted();
|
||||
mTrafficChannelManager.processP2CurrentUser(getCurrentFrequency(), getTimeslot(), getCurrentChannel(), vso,
|
||||
|
||||
//First TCM call creates the tracked event and second call starts the call and updates the duration
|
||||
mTrafficChannelManager.processP2TrafficCurrentUser(getCurrentFrequency(), getTimeslot(), getCurrentChannel(), vso,
|
||||
mac.getOpcode(), getIdentifierCollection().copyOf(), message.getTimestamp(),
|
||||
ptt.isEncrypted() ? ptt.getEncryptionKey().toString() : null);
|
||||
ptt.isEncrypted() ? ptt.getEncryptionKey().toString() : null, message.toString());
|
||||
|
||||
mTrafficChannelManager.processP2TrafficVoice(getCurrentFrequency(), getTimeslot(), message.getTimestamp());
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.START, ptt.isEncrypted() ? State.ENCRYPTED : State.CALL, getTimeslot()));
|
||||
}
|
||||
}
|
||||
@@ -1256,7 +1208,16 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
if(mac instanceof EndPushToTalk)
|
||||
{
|
||||
closeCurrentCallEvent(true, false);
|
||||
//No matter what, remove the FROM identifier on end PTT.
|
||||
getIdentifierCollection().remove(Role.FROM);
|
||||
|
||||
//Only reset the identifiers if the call event is closed out, otherwise we might have a timing issue
|
||||
//between the control channel and the traffic channel.
|
||||
if(mTrafficChannelManager.processP2TrafficEndPushToTalk(getCurrentFrequency(), getTimeslot(),
|
||||
message.getTimestamp(), "END PUSH TO TALK - " + message))
|
||||
{
|
||||
getIdentifierCollection().remove(IdentifierClass.USER);
|
||||
}
|
||||
|
||||
if(message.getDataUnitID().isFACCH())
|
||||
{
|
||||
@@ -1269,8 +1230,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
return; //don't issue a reset state after this.
|
||||
}
|
||||
}
|
||||
|
||||
continueState(State.RESET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,7 +1473,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.build();
|
||||
broadcast(decodeEvent);
|
||||
mTrafficChannelManager.broadcast(decodeEvent);
|
||||
mTrafficChannelManager.processP2CurrentUser(getCurrentFrequency(), getTimeslot(), gps.getLocation(),
|
||||
mTrafficChannelManager.processP2TrafficCurrentUser(getCurrentFrequency(), getTimeslot(), gps.getLocation(),
|
||||
message.getTimestamp());
|
||||
}
|
||||
}
|
||||
@@ -1543,7 +1502,8 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
if(mac instanceof MacRelease mr)
|
||||
{
|
||||
closeCurrentCallEvent(true, false);
|
||||
mTrafficChannelManager.processP2TrafficCallEnd(getCurrentFrequency(), getTimeslot(), message.getTimestamp(), "MAC RELEASE: " + mac.toString());
|
||||
getIdentifierCollection().remove(IdentifierClass.USER);
|
||||
broadcast(message, mac, DecodeEventType.COMMAND,
|
||||
(mr.isForcedPreemption() ? "FORCED " : "") + "CALL PREEMPTION" +
|
||||
(mr.isTalkerPreemption() ? " BY USER" : " BY CONTROLLER"));
|
||||
@@ -1746,7 +1706,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
P25TalkerAliasIdentifier alias = talkerAlias.getAlias();
|
||||
getIdentifierCollection().update(alias);
|
||||
mTrafficChannelManager.processP2CurrentUser(getCurrentFrequency(), getTimeslot(), alias, message.getTimestamp());
|
||||
mTrafficChannelManager.processP2TrafficCurrentUser(getCurrentFrequency(), getTimeslot(), alias, message.getTimestamp());
|
||||
|
||||
//Add the alias to the talker alias manager if we know the associated radio
|
||||
Identifier from = getIdentifierCollection().getFromIdentifier();
|
||||
@@ -1839,50 +1799,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates or creates a current call event.
|
||||
*
|
||||
* @param macOpcode for the update
|
||||
* @param serviceOptions for the call
|
||||
* @param details of the call (optional)
|
||||
* @param timestamp of the message indicating a call or continuation
|
||||
*/
|
||||
private void updateCurrentCall(MacOpcode macOpcode, ServiceOptions serviceOptions, String details, long timestamp)
|
||||
{
|
||||
mTrafficChannelManager.processP2CurrentUser(getCurrentFrequency(), getTimeslot(), getCurrentChannel(), serviceOptions, macOpcode, getIdentifierCollection().copyOf(), timestamp, details);
|
||||
|
||||
if(isEncrypted())
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.ENCRYPTED, getTimeslot()));
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.CALL, getTimeslot()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends/closes the current call event.
|
||||
*
|
||||
* @param resetIdentifiers to reset the FROM/TO identifiers (true) or reset just the FROM identifiers (false)
|
||||
* @param isIdleNull to indicate if the calling trigger is an IDLE/NULL message
|
||||
*/
|
||||
private void closeCurrentCallEvent(boolean resetIdentifiers, boolean isIdleNull)
|
||||
{
|
||||
mTrafficChannelManager.closeP2CallEvent(getCurrentFrequency(), getTimeslot(), isIdleNull);
|
||||
|
||||
if(resetIdentifiers)
|
||||
{
|
||||
getIdentifierCollection().remove(IdentifierClass.USER);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Only clear the from identifier(s) at this point ... the channel may still be allocated to the TO talkgroup
|
||||
getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the current set of identifiers contains an encryption key indicating that the communication is
|
||||
* encrypted.
|
||||
|
||||
@@ -20,7 +20,6 @@ package io.github.dsheirer.module.decode.p25.phase2;
|
||||
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.alias.AliasModel;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
|
||||
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||
@@ -30,11 +29,8 @@ import io.github.dsheirer.log.ApplicationLog;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.message.MessageProviderModule;
|
||||
import io.github.dsheirer.module.ProcessingChain;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager;
|
||||
import io.github.dsheirer.module.decode.p25.audio.P25P2AudioModule;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.P25P2Message;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
@@ -59,23 +55,15 @@ import org.slf4j.LoggerFactory;
|
||||
public class P25P2MessageFramer implements Listener<Dibit>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P2MessageFramer.class);
|
||||
|
||||
private P25P2SuperFrameDetector mSuperFrameDetector;
|
||||
private boolean mAssemblingMessage = false;
|
||||
private CorrectedBinaryMessage mBinaryMessage;
|
||||
private DataUnitID mDataUnitID;
|
||||
private PDUSequence mPDUSequence;
|
||||
private int[] mCorrectedNID;
|
||||
private int mNAC;
|
||||
private int mStatusSymbolDibitCounter = 0;
|
||||
private int mTrailingDibitsToSuppress = 0;
|
||||
private double mBitRate;
|
||||
private long mCurrentTime = System.currentTimeMillis();
|
||||
|
||||
public P25P2MessageFramer(IPhaseLockedLoop phaseLockedLoop, int bitRate)
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param phaseLockedLoop for use with the super frame detector
|
||||
*/
|
||||
public P25P2MessageFramer(IPhaseLockedLoop phaseLockedLoop)
|
||||
{
|
||||
mSuperFrameDetector = new P25P2SuperFrameDetector(phaseLockedLoop);
|
||||
mBitRate = bitRate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,41 +97,6 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
mSuperFrameDetector.setSyncDetectListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current timestamp or timestamp of incoming message buffers that is continuously updated to as
|
||||
* close as possible to the bits processed for the expected baud rate.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private long getTimestamp()
|
||||
{
|
||||
return mCurrentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current time. This should be invoked by an incoming message buffer stream.
|
||||
*
|
||||
* @param currentTime
|
||||
*/
|
||||
public void setCurrentTime(long currentTime)
|
||||
{
|
||||
mCurrentTime = currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current timestamp based on the number of bits processed versus the bit rate per second
|
||||
* in order to keep an accurate running timestamp to use for timestamped message creation.
|
||||
*
|
||||
* @param bitsProcessed thus far
|
||||
*/
|
||||
private void updateBitsProcessed(int bitsProcessed)
|
||||
{
|
||||
if(bitsProcessed > 0)
|
||||
{
|
||||
mCurrentTime += (long)((double)bitsProcessed / mBitRate * 1000.0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener for messages produced by this message framer
|
||||
*
|
||||
@@ -154,11 +107,6 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
mSuperFrameDetector.setListener(messageListener);
|
||||
}
|
||||
|
||||
public P25P2SuperFrameDetector getSuperFrameDetector()
|
||||
{
|
||||
return mSuperFrameDetector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary method for streaming decoded symbol dibits for message framing.
|
||||
*
|
||||
@@ -170,18 +118,6 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
mSuperFrameDetector.receive(dibit);
|
||||
}
|
||||
|
||||
private void reset(int bitsProcessed)
|
||||
{
|
||||
updateBitsProcessed(bitsProcessed);
|
||||
mPDUSequence = null;
|
||||
mBinaryMessage = null;
|
||||
mAssemblingMessage = false;
|
||||
mDataUnitID = null;
|
||||
mNAC = 0;
|
||||
mSuperFrameDetector.reset();
|
||||
mStatusSymbolDibitCounter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary method for streaming decoded symbol byte arrays.
|
||||
*
|
||||
@@ -266,7 +202,7 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
|
||||
processingChain.start();
|
||||
|
||||
P25P2MessageFramer messageFramer = new P25P2MessageFramer(null, DecoderType.P25_PHASE2.getProtocol().getBitRate());
|
||||
P25P2MessageFramer messageFramer = new P25P2MessageFramer(null);
|
||||
messageFramer.setScrambleParameters(scrambleParameters);
|
||||
P25P2MessageProcessor messageProcessor = new P25P2MessageProcessor();
|
||||
messageFramer.setListener(messageProcessor);
|
||||
|
||||
@@ -25,7 +25,7 @@ package io.github.dsheirer.module.decode.p25.reference;
|
||||
public abstract class ServiceOptions
|
||||
{
|
||||
protected static final int EMERGENCY_FLAG = 0x80;
|
||||
protected static final int ENCRYPTION_FLAG = 0x40;
|
||||
public static final int ENCRYPTION_FLAG = 0x40;
|
||||
protected static final int DUPLEX = 0x20;
|
||||
protected static final int SESSION_MODE = 0x10;
|
||||
protected int mServiceOptions;
|
||||
|
||||
Reference in New Issue
Block a user