mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
#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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user