Skip to content

Commit

Permalink
#1914 P25 P1 & P2 Talker Alias Support for Motorola and L3Harris. Tal…
Browse files Browse the repository at this point in the history
…ker alias manager caches aliases and applies to future events. Active (cached) talker aliases now listed in the channel Details tab. Enables multi-select in message viewer for all supported protocols. Note: decoding of Motorola's talker alias format not yet implemented - only recognition and reassembly of the encoded sequence is currently supported. (#2001)

Co-authored-by: Dennis Sheirer <[email protected]>
  • Loading branch information
DSheirer and Dennis Sheirer authored Oct 5, 2024
1 parent 600db3f commit 3c8cd03
Show file tree
Hide file tree
Showing 42 changed files with 2,047 additions and 445 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.identifier.Form;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierUpdateListener;
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
Expand Down Expand Up @@ -57,6 +58,7 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
private DecoderTypeConfigurationIdentifier mDecoderTypeConfigurationIdentifier;
private Identifier mFromIdentifier;
private List<Alias> mFromIdentifierAliases;
private Identifier mTalkerAliasIdentifier;
private Identifier mToIdentifier;
private List<Alias> mToIdentifierAliases;
private Integer mTimeslot;
Expand Down Expand Up @@ -238,6 +240,22 @@ public List<Alias> getFromIdentifierAliases()
return mFromIdentifierAliases;
}

/**
* Optional talker alias identifier
*/
public Identifier getTalkerAliasIdentifier()
{
return mTalkerAliasIdentifier;
}

/**
* Indicates if we have a non-null talker alias identifier
*/
public boolean hasTalkerAliasIdentifier()
{
return mTalkerAliasIdentifier != null;
}

/**
* Current call event TO identifier
*/
Expand Down Expand Up @@ -409,15 +427,22 @@ public void receive(IdentifierUpdateNotification update)
case USER:
if(identifier.getRole() == Role.FROM)
{
mFromIdentifier = update.isAdd() ? identifier : null;

if(mAliasList != null && mFromIdentifier != null)
if(identifier.getForm() == Form.TALKER_ALIAS)
{
mFromIdentifierAliases = mAliasList.getAliases(mFromIdentifier);
mTalkerAliasIdentifier = identifier;
}
else
{
mFromIdentifierAliases = Collections.EMPTY_LIST;
mFromIdentifier = update.isAdd() ? identifier : null;

if(mAliasList != null && mFromIdentifier != null)
{
mFromIdentifierAliases = mAliasList.getAliases(mFromIdentifier);
}
else
{
mFromIdentifierAliases = Collections.EMPTY_LIST;
}
}

broadcastUpdate(ChannelMetadataField.USER_FROM);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 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
Expand Down Expand Up @@ -38,6 +38,14 @@
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -52,14 +60,6 @@
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

public class ChannelMetadataPanel extends JPanel implements ListSelectionListener
{
Expand Down Expand Up @@ -294,6 +294,10 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
{
text = EMPTY_VALUE;
}
else if(hasAdditionalIdentifier(channelMetadata))
{
text = text + " " + getAdditionalIdentifier(channelMetadata);
}

label.setText(text);
}
Expand All @@ -306,6 +310,8 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
}

public abstract Identifier getIdentifier(ChannelMetadata channelMetadata);
public abstract boolean hasAdditionalIdentifier(ChannelMetadata channelMetadata);
public abstract Identifier getAdditionalIdentifier(ChannelMetadata channelMetadata);
}

/**
Expand All @@ -323,6 +329,18 @@ public Identifier getIdentifier(ChannelMetadata channelMetadata)
{
return channelMetadata.getFromIdentifier();
}

@Override
public Identifier getAdditionalIdentifier(ChannelMetadata channelMetadata)
{
return channelMetadata.getTalkerAliasIdentifier();
}

@Override
public boolean hasAdditionalIdentifier(ChannelMetadata channelMetadata)
{
return channelMetadata.hasTalkerAliasIdentifier();
}
}

/**
Expand All @@ -340,6 +358,11 @@ public Identifier getIdentifier(ChannelMetadata channelMetadata)
{
return channelMetadata.getToIdentifier();
}

@Override
public Identifier getAdditionalIdentifier(ChannelMetadata channelMetadata) {return null;}
@Override
public boolean hasAdditionalIdentifier(ChannelMetadata channelMetadata) {return false;}
}

public class ColoredStateCellRenderer extends DefaultTableCellRenderer
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/io/github/dsheirer/gui/viewer/DmrViewer.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -46,6 +46,7 @@
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
Expand Down Expand Up @@ -284,6 +285,7 @@ private TableView<IMessage> getMessageTableView()
if(mMessageTableView == null)
{
mMessageTableView = new TableView<>();
mMessageTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
mMessageTableView.setPlaceholder(getLoadingIndicator());
SortedList<IMessage> sortedList = new SortedList<>(mFilteredMessages);
sortedList.comparatorProperty().bind(mMessageTableView.comparatorProperty());
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/github/dsheirer/gui/viewer/P25P1Viewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
Expand Down Expand Up @@ -380,6 +381,7 @@ private TableView<MessagePackage> getMessagePackageTableView()
if(mMessagePackageTableView == null)
{
mMessagePackageTableView = new TableView<>();
mMessagePackageTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
mMessagePackageTableView.setPlaceholder(getLoadingIndicator());
SortedList<MessagePackage> sortedList = new SortedList<>(mFilteredMessagePackages);
sortedList.comparatorProperty().bind(mMessagePackageTableView.comparatorProperty());
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/github/dsheirer/gui/viewer/P25P2Viewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
Expand Down Expand Up @@ -459,6 +460,7 @@ private TableView<MessagePackage> getMessagePackageTableView()
if(mMessagePackageTableView == null)
{
mMessagePackageTableView = new TableView<>();
mMessagePackageTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
mMessagePackageTableView.setPlaceholder(getLoadingIndicator());
SortedList<MessagePackage> sortedList = new SortedList<>(mFilteredMessagePackages);
sortedList.comparatorProperty().bind(mMessagePackageTableView.comparatorProperty());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* *****************************************************************************
* 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.identifier.alias;

import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.identifier.MutableIdentifierCollection;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.radio.RadioIdentifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Talker alias cache manager. Collects observed talker aliases and inserts them into an identifier collection when
* the corresponding radio is active in a FROM role.
*
* This implementation is thread safe and is intended to be used across control and traffic channels.
*/
public class TalkerAliasManager
{
private Map<Integer,TalkerAliasIdentifier> mAliasMap = new ConcurrentHashMap<>();

/**
* Constructs an instance
*/
public TalkerAliasManager()
{
}

/**
* Updates the alias for the
* @param identifier
* @param alias
*/
public void update(RadioIdentifier identifier, TalkerAliasIdentifier alias)
{
if(identifier.getRole() == Role.FROM)
{
mAliasMap.put(identifier.getValue(), alias);
}
}

/**
* Indicates if an alias exists for the identifier
* @param radioIdentifier to test
* @return true if an alias exists.
*/
public boolean hasAlias(RadioIdentifier radioIdentifier)
{
return mAliasMap.containsKey(radioIdentifier.getValue());
}

/**
* Enriches the immutable identifier collection by detecting a radio identifier with the FROM role, lookup a
* matching alias, and insert the alias into a new mutable identifier collection.
* @param originalIC to enrich
* @return enriched identifier collection or the original identifier collection if we don't have an alias.
*/
public synchronized IdentifierCollection enrich(IdentifierCollection originalIC)
{
Identifier fromRadio = originalIC.getFromIdentifier();

if(fromRadio instanceof RadioIdentifier rid)
{
TalkerAliasIdentifier alias = mAliasMap.get(rid.getValue());

if(alias != null)
{
MutableIdentifierCollection enrichedIC = new MutableIdentifierCollection(originalIC.getIdentifiers());
enrichedIC.update(alias);
return enrichedIC;
}
}

return originalIC;
}

/**
* Enriches the mutable identifier collection by detecting a radio identifier with the FROM role, lookup a
* matching alias, and insert the alias into the mutable identifier collection argument.
* @param mic to enrich
*/
public synchronized void enrichMutable(MutableIdentifierCollection mic)
{
Identifier fromRadio = mic.getFromIdentifier();

if(fromRadio instanceof RadioIdentifier rid)
{
TalkerAliasIdentifier alias = mAliasMap.get(rid.getValue());

if(alias != null)
{
mic.update(alias);
}
}
}

/**
* Creates a summary listing of talker aliases
* @return summary.
*/
public synchronized String getAliasSummary()
{
StringBuilder sb = new StringBuilder();
sb.append("Active System Radio Aliases\n");
List<Integer> radios = new ArrayList<>(mAliasMap.keySet());

if(radios.size() > 0)
{
Collections.sort(radios);
for(Integer radio : radios)
{
sb.append(" ").append(radio);
sb.append("\t").append(mAliasMap.get(radio).getValue());
sb.append("\n");
}
}
else
{
sb.append(" None\n");
}

return sb.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ public String getPatchGroupSummary()

if(trackers.isEmpty())
{
sb.append("None");
sb.append(" None\n");
}
else
{
for(PatchGroupTracker tracker : trackers)
{
sb.append(" ").append(tracker.mPatchGroupIdentifier).append("\n");
sb.append(" ").append(tracker.mPatchGroupIdentifier).append("\n");
}
}

Expand Down
Loading

0 comments on commit 3c8cd03

Please sign in to comment.