mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Resolves #165 - P25 decoding channel stops arbitrarily and never recovers.
Issue identified with Patch Group management and circular dependencies that can develop because of stale patch groups. Refactored all patch group management into a new PatchGroupManager. Patch groups are now automatically deleted if we don't receive any update messages within 5 seconds. The PatchGroupAlias was also updated to not roll-up attributes from subordinate patched group aliases when those aliases are also patch group aliases -- this eliminates the circular dependency chaining. Added IOverflowListener interface and updated Sources to support overflow listeners. Updated ChannelState to register as an overflow listener so that it can visually depict to the user when the channel enters/exits source overflow state. Added new color pattern for OVERFLOW with yellow text on red.
This commit is contained in:
243
src/module/decode/p25/PatchGroupManager.java
Normal file
243
src/module/decode/p25/PatchGroupManager.java
Normal file
@@ -0,0 +1,243 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package module.decode.p25;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import alias.PatchGroupAlias;
|
||||
import alias.id.talkgroup.TalkgroupID;
|
||||
import module.decode.event.CallEvent;
|
||||
import sample.Broadcaster;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class PatchGroupManager
|
||||
{
|
||||
private AliasList mAliasList;
|
||||
private List<PatchGroup> mPatchGroups = new ArrayList<>();
|
||||
private Broadcaster<CallEvent> mCallEventBroadcaster;
|
||||
|
||||
/**
|
||||
* Manages active P25 patch groups and auto-expires patch groups if not updated every 5 seconds.
|
||||
* @param aliasList to keep updated with patch group changes
|
||||
* @param broadcaster for rebroadcasting patch group related call events
|
||||
*/
|
||||
public PatchGroupManager(AliasList aliasList, Broadcaster<CallEvent> broadcaster)
|
||||
{
|
||||
mAliasList = aliasList;
|
||||
mCallEventBroadcaster = broadcaster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the patch group.
|
||||
*
|
||||
* @param patchGroupID of the patch group to remove
|
||||
*/
|
||||
public void removePatchGroup(String patchGroupID)
|
||||
{
|
||||
removePatchGroup(patchGroupID, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the patch group.
|
||||
*
|
||||
* @param patchGroupID of the patch group to remove
|
||||
* @param expired true if the patch group is being removed because it expired, false if we receive a
|
||||
* message commanding commanding a patch group delete.
|
||||
*/
|
||||
private void removePatchGroup(String patchGroupID, boolean expired)
|
||||
{
|
||||
PatchGroup patchGroup = getPatchGroup(patchGroupID);
|
||||
|
||||
if(patchGroup != null)
|
||||
{
|
||||
//Cleanup the alias list
|
||||
if(mAliasList != null)
|
||||
{
|
||||
Alias alias = mAliasList.getTalkgroupAlias(patchGroupID);
|
||||
|
||||
if(alias instanceof PatchGroupAlias)
|
||||
{
|
||||
PatchGroupAlias patchGroupAlias = (PatchGroupAlias)alias;
|
||||
|
||||
mAliasList.removeAlias(patchGroupAlias);
|
||||
|
||||
//Replace our temporary patch group alias with the original alias for the patch group ID
|
||||
if(patchGroupAlias.hasPatchGroupAlias())
|
||||
{
|
||||
mAliasList.addAlias(patchGroupAlias.getPatchGroupAlias());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mPatchGroups.remove(patchGroup);
|
||||
|
||||
if(mCallEventBroadcaster != null)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append((expired ? "EXPIRED " : "DELETED "));
|
||||
sb.append("PATCH GROUP:").append(patchGroup.getPatchGroupID());
|
||||
sb.append(" ").append(patchGroup.getPatchedGroups());
|
||||
|
||||
|
||||
mCallEventBroadcaster.broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.PATCH_GROUP_DELETE)
|
||||
.to(patchGroup.getPatchGroupID())
|
||||
.details(sb.toString())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds/updates a patch group alias to the alias list containing aliases for each of the patched talkgroups. If the
|
||||
* patch group alias already exists, any patched talkgroups will be removed from the existing patch group alias and
|
||||
* replaced with the aliases corresponding to the patched talkgroup aliases.
|
||||
*
|
||||
* @param patchGroupID for the patch group
|
||||
* @param patchedTalkgroups containing the talkgroup IDs for each of the patched talkgroups
|
||||
*/
|
||||
public void updatePatchGroup(String patchGroupID, List<String> patchedTalkgroups)
|
||||
{
|
||||
boolean updated = false;
|
||||
|
||||
PatchGroup patchGroup = getPatchGroup(patchGroupID);
|
||||
|
||||
if(patchGroup == null)
|
||||
{
|
||||
//Remove any expired patch groups before we add a new one
|
||||
cleanupPatchGroups();
|
||||
patchGroup = new PatchGroup(patchGroupID);
|
||||
mPatchGroups.add(patchGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
patchGroup.updateTimestamp();
|
||||
}
|
||||
|
||||
for(String patchedGroup: patchedTalkgroups)
|
||||
{
|
||||
if(patchGroup.addPatchedGroup(patchedGroup))
|
||||
{
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
//If we make any changes to the patch group, update the patch group alias
|
||||
if(updated)
|
||||
{
|
||||
PatchGroupAlias patchGroupAlias = null;
|
||||
|
||||
//Check for an existing alias for the patch talkgroup - do not include wildcard aliases
|
||||
if(mAliasList != null)
|
||||
{
|
||||
Alias existingAlias = mAliasList.getTalkgroupAlias(patchGroupID, false);
|
||||
|
||||
if(existingAlias instanceof PatchGroupAlias)
|
||||
{
|
||||
patchGroupAlias = (PatchGroupAlias)existingAlias;
|
||||
}
|
||||
else
|
||||
{
|
||||
patchGroupAlias = new PatchGroupAlias();
|
||||
|
||||
patchGroupAlias.addAliasID(new TalkgroupID(patchGroupID));
|
||||
|
||||
if(existingAlias != null)
|
||||
{
|
||||
mAliasList.removeAlias(existingAlias);
|
||||
|
||||
patchGroupAlias.setPatchGroupAlias(existingAlias);
|
||||
}
|
||||
|
||||
mAliasList.addAlias(patchGroupAlias);
|
||||
}
|
||||
|
||||
if(patchGroupAlias != null)
|
||||
{
|
||||
patchGroupAlias.setPatchedTalkgroupIDs(patchGroup.getPatchedGroups());
|
||||
|
||||
patchGroupAlias.clearPatchedAliases();
|
||||
|
||||
for(String patchedTalkgroup : patchGroup.getPatchedGroups())
|
||||
{
|
||||
Alias patchedAlias = mAliasList.getTalkgroupAlias(patchedTalkgroup);
|
||||
|
||||
if(patchedAlias != null)
|
||||
{
|
||||
patchGroupAlias.addPatchedAlias(patchedAlias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mCallEventBroadcaster != null)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("PATCH GROUP:").append(patchGroup.getPatchGroupID());
|
||||
sb.append(" ").append(patchGroup.getPatchedGroups());
|
||||
|
||||
mCallEventBroadcaster.broadcast(new P25CallEvent.Builder(CallEvent.CallEventType.PATCH_GROUP_ADD)
|
||||
.aliasList(mAliasList)
|
||||
.details(sb.toString())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the patch group matching the patch group ID or null
|
||||
*/
|
||||
private PatchGroup getPatchGroup(String patchGroupID)
|
||||
{
|
||||
for(PatchGroup patchGroup: mPatchGroups)
|
||||
{
|
||||
if(patchGroup.getPatchGroupID().equals(patchGroupID))
|
||||
{
|
||||
return patchGroup;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the last updated timestamp on all patch groups and removes any patch groups that have not been
|
||||
* updated in the past 5 seconds
|
||||
*/
|
||||
public void cleanupPatchGroups()
|
||||
{
|
||||
Iterator<PatchGroup> it = mPatchGroups.iterator();
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
PatchGroup patchGroup = it.next();
|
||||
|
||||
if(patchGroup.isExpired())
|
||||
{
|
||||
it.remove();
|
||||
|
||||
removePatchGroup(patchGroup.getPatchGroupID(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user