#818 Resolves P25 duplicate traffic channel issue where duplicate traffic channels were being allocated for the same frequency. (#834)

Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
Denny Sheirer
2020-05-25 06:29:56 -04:00
committed by GitHub
parent 2bb5082943
commit ad194d1bab

View File

@@ -67,7 +67,6 @@ import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Consumer;
/**
* Monitors channel grant and channel grant update messages to allocate traffic channels to capture
@@ -98,10 +97,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
private Queue<Channel> mAvailablePhase2TrafficChannelQueue = new ConcurrentLinkedQueue<>();
private List<Channel> mManagedPhase2TrafficChannels;
private Map<APCO25Channel,Channel> mAllocatedTrafficChannelMap = new ConcurrentHashMap<>();
private Map<APCO25Channel,P25ChannelGrantEvent> mPhase1ChannelGrantEventMap = new ConcurrentHashMap<>();
private Map<APCO25Channel,P25ChannelGrantEvent> mPhase2TS0ChannelGrantEventMap = new ConcurrentHashMap<>();
private Map<APCO25Channel,P25ChannelGrantEvent> mPhase2TS1ChannelGrantEventMap = new ConcurrentHashMap<>();
private Map<Long,Channel> mAllocatedTrafficChannelMap = new ConcurrentHashMap<>();
private Map<Long,P25ChannelGrantEvent> mTS0ChannelGrantEventMap = new ConcurrentHashMap<>();
private Map<Long,P25ChannelGrantEvent> mTS1ChannelGrantEventMap = new ConcurrentHashMap<>();
private Listener<ChannelEvent> mChannelEventListener;
private Listener<IDecodeEvent> mDecodeEventListener;
@@ -114,10 +112,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
private boolean mIgnoreDataCalls;
/**
* Monitors call events and allocates traffic decoder channels in response
* to traffic channel allocation call events. Manages a pool of reusable
* traffic channel allocations.
*
* Constructs an instance.
* @param parentChannel that owns this traffic channel manager
*/
public P25TrafficChannelManager(Channel parentChannel)
@@ -273,8 +268,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
private void processPhase1ChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions,
IdentifierCollection identifierCollection, Opcode opcode, long timestamp)
{
long frequency = apco25Channel.getDownlinkFrequency();
P25ChannelGrantEvent event = mPhase1ChannelGrantEventMap.get(apco25Channel);
P25ChannelGrantEvent event = mTS0ChannelGrantEventMap.get(frequency);
if(event != null && isSameCall(identifierCollection, event.getIdentifierCollection()))
{
@@ -294,7 +290,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
.identifiers(identifierCollection)
.build();
mPhase1ChannelGrantEventMap.put(apco25Channel, continuationGrantEvent);
mTS0ChannelGrantEventMap.put(frequency, continuationGrantEvent);
broadcast(continuationGrantEvent);
}
}
@@ -305,7 +301,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
//Even though we have an event, the initial channel grant may have been rejected. Check to see if there
//is a traffic channel allocated. If not, allocate one and update the event description.
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel) && !(mIgnoreDataCalls && opcode.isDataChannelGrant()))
if(!mAllocatedTrafficChannelMap.containsKey(frequency) && !(mIgnoreDataCalls && opcode.isDataChannelGrant()))
{
Channel trafficChannel = mAvailablePhase1TrafficChannelQueue.poll();
@@ -316,9 +312,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
event.setChannelDescriptor(apco25Channel);
broadcast(event);
SourceConfigTuner sourceConfig = new SourceConfigTuner();
sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency());
sourceConfig.setFrequency(frequency);
trafficChannel.setSourceConfiguration(sourceConfig);
mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel);
mAllocatedTrafficChannelMap.put(frequency, trafficChannel);
broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection));
}
}
@@ -335,8 +331,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
.identifiers(identifierCollection)
.build();
mPhase1ChannelGrantEventMap.put(apco25Channel, channelGrantEvent);
mTS0ChannelGrantEventMap.put(frequency, channelGrantEvent);
broadcast(channelGrantEvent);
return;
}
@@ -348,11 +343,10 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
.identifiers(identifierCollection)
.build();
mPhase1ChannelGrantEventMap.put(apco25Channel, channelGrantEvent);
mTS0ChannelGrantEventMap.put(frequency, channelGrantEvent);
//Allocate a traffic channel for the downlink frequency if one isn't already allocated
//NOTE: we could also allocate a traffic channel for the uplink frequency here, in the future
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel))
if(!mAllocatedTrafficChannelMap.containsKey(frequency))
{
Channel trafficChannel = mAvailablePhase1TrafficChannelQueue.poll();
@@ -364,9 +358,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
}
SourceConfigTuner sourceConfig = new SourceConfigTuner();
sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency());
sourceConfig.setFrequency(frequency);
trafficChannel.setSourceConfiguration(sourceConfig);
mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel);
mAllocatedTrafficChannelMap.put(frequency, trafficChannel);
broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection));
}
@@ -392,16 +386,17 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
}
int timeslot = apco25Channel.getTimeslot();
long frequency = apco25Channel.getDownlinkFrequency();
P25ChannelGrantEvent event = null;
if(timeslot == 0)
{
event = mPhase2TS0ChannelGrantEventMap.get(apco25Channel);
event = mTS0ChannelGrantEventMap.get(frequency);
}
else if(timeslot == 1)
{
event = mPhase2TS1ChannelGrantEventMap.get(apco25Channel);
event = mTS1ChannelGrantEventMap.get(frequency);
}
else
{
@@ -431,11 +426,11 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
if(timeslot == 0)
{
mPhase2TS0ChannelGrantEventMap.put(apco25Channel, continuationGrantEvent);
mTS0ChannelGrantEventMap.put(frequency, continuationGrantEvent);
}
else
{
mPhase2TS1ChannelGrantEventMap.put(apco25Channel, continuationGrantEvent);
mTS1ChannelGrantEventMap.put(frequency, continuationGrantEvent);
}
broadcast(continuationGrantEvent);
@@ -448,8 +443,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
//Even though we have an event, the initial channel grant may have been rejected. Check to see if there
//is a traffic channel allocated. If not, allocate one and update the event description.
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel) &&
!(mIgnoreDataCalls && opcode.isDataChannelGrant()))
if(!mAllocatedTrafficChannelMap.containsKey(frequency) && !(mIgnoreDataCalls && opcode.isDataChannelGrant()))
{
Channel trafficChannel = mAvailablePhase2TrafficChannelQueue.poll();
@@ -460,9 +454,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
event.setChannelDescriptor(apco25Channel);
broadcast(event);
SourceConfigTuner sourceConfig = new SourceConfigTuner();
sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency());
sourceConfig.setFrequency(frequency);
trafficChannel.setSourceConfiguration(sourceConfig);
mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel);
mAllocatedTrafficChannelMap.put(frequency, trafficChannel);
//If we have valid scramble/randomizer parameters, set them in the decode config
if(mPhase2ScrambleParameters != null)
@@ -487,7 +481,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
.identifiers(identifierCollection)
.build();
mPhase1ChannelGrantEventMap.put(apco25Channel, channelGrantEvent);
mTS0ChannelGrantEventMap.put(frequency, channelGrantEvent);
broadcast(channelGrantEvent);
return;
@@ -502,16 +496,15 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
if(timeslot == 0)
{
mPhase2TS0ChannelGrantEventMap.put(apco25Channel, channelGrantEvent);
mTS0ChannelGrantEventMap.put(frequency, channelGrantEvent);
}
else
{
mPhase2TS1ChannelGrantEventMap.put(apco25Channel, channelGrantEvent);
mTS1ChannelGrantEventMap.put(frequency, channelGrantEvent);
}
//Allocate a traffic channel for the downlink frequency if one isn't already allocated
//NOTE: we could also allocate a traffic channel for the uplink frequency here, in the future
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel))
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel.getDownlinkFrequency()))
{
Channel trafficChannel = mAvailablePhase2TrafficChannelQueue.poll();
@@ -523,9 +516,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
}
SourceConfigTuner sourceConfig = new SourceConfigTuner();
sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency());
sourceConfig.setFrequency(frequency);
trafficChannel.setSourceConfiguration(sourceConfig);
mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel);
mAllocatedTrafficChannelMap.put(frequency, trafficChannel);
broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection));
}
@@ -660,6 +653,11 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
{
broadcast(new ChannelEvent(trafficChannel, Event.REQUEST_DISABLE));
}
for(Channel trafficChannel : mAvailablePhase2TrafficChannelQueue)
{
broadcast(new ChannelEvent(trafficChannel, Event.REQUEST_DISABLE));
}
}
/**
@@ -701,6 +699,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
mLog.info("Stopping traffic channel: " + channel);
broadcast(new ChannelEvent(channel, Event.REQUEST_DISABLE));
}
mTS0ChannelGrantEventMap.clear();
mTS1ChannelGrantEventMap.clear();
}
/**
@@ -715,21 +716,16 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
{
if(mMessageListener == null)
{
mMessageListener = new Listener<IMessage>()
{
@Override
public void receive(IMessage message)
mMessageListener = message -> {
if(mPhase2ScrambleParameters == null && message.isValid())
{
if(mPhase2ScrambleParameters == null && message.isValid())
if(message instanceof NetworkStatusBroadcast)
{
if(message instanceof NetworkStatusBroadcast)
{
mPhase2ScrambleParameters = ((NetworkStatusBroadcast)message).getScrambleParameters();
}
else if(message instanceof AMBTCNetworkStatusBroadcast)
{
mPhase2ScrambleParameters = ((AMBTCNetworkStatusBroadcast)message).getScrambleParameters();
}
mPhase2ScrambleParameters = ((NetworkStatusBroadcast)message).getScrambleParameters();
}
else if(message instanceof AMBTCNetworkStatusBroadcast)
{
mPhase2ScrambleParameters = ((AMBTCNetworkStatusBroadcast)message).getScrambleParameters();
}
}
};
@@ -770,24 +766,22 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
public class TrafficChannelTeardownMonitor implements Listener<ChannelEvent>
{
/**
* Removes any call events that are associated with the specified channel.
* @param channel that was removed
* Removes an allocated traffic channel and adds it to the available channel queue
* @param channel to reset
* @param frequency of the channel
* @param isPhase1 true or false if it is a phase 2 channel
*/
private void cleanupCallEvents(Channel channel)
private void resetTrafficChannel(Channel channel, long frequency, boolean isPhase1)
{
if(channel.getSourceConfiguration() instanceof SourceConfigTuner)
{
long frequency = ((SourceConfigTuner)channel.getSourceConfiguration()).getFrequency();
mAllocatedTrafficChannelMap.remove(frequency);
if(channel.getDecodeConfiguration().getDecoderType() == DecoderType.P25_PHASE1)
{
mPhase1ChannelGrantEventMap.entrySet().removeIf(entry -> entry.getKey().getDownlinkFrequency() == frequency);
}
else
{
mPhase2TS0ChannelGrantEventMap.entrySet().removeIf(entry -> entry.getKey().getDownlinkFrequency() == frequency);
mPhase2TS1ChannelGrantEventMap.entrySet().removeIf(entry -> entry.getKey().getDownlinkFrequency() == frequency);
}
if(isPhase1)
{
mAvailablePhase1TrafficChannelQueue.add(channel);
}
else
{
mAvailablePhase2TrafficChannelQueue.add(channel);
}
}
@@ -810,48 +804,43 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
.filter(entry -> entry.getValue() == channel)
.map(Map.Entry::getKey)
.findFirst()
.ifPresent(toRemove -> {
mAllocatedTrafficChannelMap.remove(toRemove);
if (isPhase1) {
mAvailablePhase1TrafficChannelQueue.add(channel);
} else {
mAvailablePhase2TrafficChannelQueue.add(channel);
}
.ifPresent(frequencyToRemove -> {
resetTrafficChannel(channel, frequencyToRemove, isPhase1);
mTS0ChannelGrantEventMap.remove(frequencyToRemove);
mTS1ChannelGrantEventMap.remove(frequencyToRemove);
});
cleanupCallEvents(channel);
break;
case NOTIFICATION_PROCESSING_START_REJECTED:
mAllocatedTrafficChannelMap.entrySet().stream()
.filter(entry -> entry.getValue() == channel)
.map(Map.Entry::getKey)
.findFirst()
.ifPresent(rejected -> {
mAllocatedTrafficChannelMap.remove(rejected);
.ifPresent(rejectedFrequency -> {
resetTrafficChannel(channel, rejectedFrequency, isPhase1);
if (isPhase1) {
mAvailablePhase1TrafficChannelQueue.add(channel);
} else {
mAvailablePhase2TrafficChannelQueue.add(channel);
P25ChannelGrantEvent event = mTS0ChannelGrantEventMap.remove(rejectedFrequency);
if(event == null)
{
event = mTS1ChannelGrantEventMap.remove(rejectedFrequency);
}
P25ChannelGrantEvent event = mPhase1ChannelGrantEventMap.get(rejected);
if (event != null) {
if (event != null)
{
event.setEventDescription(event.getEventDescription() + " - Rejected");
if (channelEvent.getDescription() != null) {
if (channelEvent.getDescription() != null)
{
event.setDetails(channelEvent.getDescription() + " - " + event.getDetails());
} else {
}
else
{
event.setDetails(CHANNEL_START_REJECTED + " - " + event.getDetails());
}
broadcast(event);
}
});
cleanupCallEvents(channel);
break;
}
}