mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 09:37:36 -05:00
#1977 P25 FQSUID handling improvements. P25 fully qualified radio/talkgroup identifiers we're being flagged as invalid when ISSI patch assigned a local address/ID of zero. Changes format of FQSUID and FQTGID to use a value of zero for the local alias when the call type is an ISSI patch and suppress display of the 0 alias value. If the identifier represents a roaming user, then the local address value is displayed with the FQSUID appended in parenthesis. (#1978)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -21,12 +21,15 @@ package io.github.dsheirer.gui.viewer;
|
|||||||
|
|
||||||
import io.github.dsheirer.identifier.Identifier;
|
import io.github.dsheirer.identifier.Identifier;
|
||||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
import javafx.scene.control.TableView;
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JavaFX identifier collection viewer
|
* JavaFX identifier collection viewer
|
||||||
@@ -82,7 +85,19 @@ public class IdentifierCollectionViewer extends VBox
|
|||||||
valueColumn.setText("Value");
|
valueColumn.setText("Value");
|
||||||
valueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
|
valueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
|
||||||
|
|
||||||
mIdentifierTableView.getColumns().addAll(classColumn, formColumn, roleColumn, valueColumn);
|
TableColumn textColumn = new TableColumn();
|
||||||
|
textColumn.setPrefWidth(160);
|
||||||
|
textColumn.setText("Text");
|
||||||
|
textColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<Identifier<?>, String>, ObservableValue>) param -> {
|
||||||
|
if(param.getValue() != null)
|
||||||
|
{
|
||||||
|
return new SimpleStringProperty(param.getValue().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
mIdentifierTableView.getColumns().addAll(classColumn, formColumn, roleColumn, valueColumn, textColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mIdentifierTableView;
|
return mIdentifierTableView;
|
||||||
|
|||||||
@@ -72,12 +72,22 @@ public abstract class FullyQualifiedRadioIdentifier extends RadioIdentifier
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if the radio identify is aliased with a persona value that is different from the radio ID.
|
* Indicates if the radio identity is aliased with a persona value that is different from the radio ID.
|
||||||
* @return true if aliased.
|
* @return true if aliased.
|
||||||
*/
|
*/
|
||||||
public boolean isAliased()
|
public boolean isAliased()
|
||||||
{
|
{
|
||||||
return getValue() != mRadio;
|
return getValue() != 0 && getValue() != mRadio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the default behavior of RadioIdentifier.isValid() to allow for fully qualified SUID's with a local
|
||||||
|
* ID of zero which indicates an ISSI patch.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -71,12 +71,22 @@ public abstract class FullyQualifiedTalkgroupIdentifier extends TalkgroupIdentif
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if the talkgroup identify is aliased with a persona value that is different from the talkgroup ID.
|
* Indicates if the talkgroup identity is aliased with a persona value that is different from the talkgroup ID.
|
||||||
* @return true if aliased.
|
* @return true if aliased.
|
||||||
*/
|
*/
|
||||||
public boolean isAliased()
|
public boolean isAliased()
|
||||||
{
|
{
|
||||||
return getValue() != mTalkgroup;
|
return getValue() != 0 && getValue() != mTalkgroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the default behavior of TalkgroupIdentifier.isValid() to allow for fully qualified TGID's with a local
|
||||||
|
* ID of zero which indicates an ISSI patch.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import io.github.dsheirer.identifier.IdentifierCollection;
|
|||||||
import io.github.dsheirer.identifier.MutableIdentifierCollection;
|
import io.github.dsheirer.identifier.MutableIdentifierCollection;
|
||||||
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
|
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
|
||||||
import io.github.dsheirer.identifier.patch.PatchGroupPreLoadDataContent;
|
import io.github.dsheirer.identifier.patch.PatchGroupPreLoadDataContent;
|
||||||
import io.github.dsheirer.identifier.radio.RadioIdentifier;
|
|
||||||
import io.github.dsheirer.identifier.scramble.ScrambleParameterIdentifier;
|
import io.github.dsheirer.identifier.scramble.ScrambleParameterIdentifier;
|
||||||
import io.github.dsheirer.log.LoggingSuppressor;
|
import io.github.dsheirer.log.LoggingSuppressor;
|
||||||
import io.github.dsheirer.message.IMessage;
|
import io.github.dsheirer.message.IMessage;
|
||||||
@@ -307,7 +306,7 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I
|
|||||||
* @param timeslot for the channel.
|
* @param timeslot for the channel.
|
||||||
* @param isIdleNull to indicate if this close event is trigged by an IDLE/NULL message
|
* @param isIdleNull to indicate if this close event is trigged by an IDLE/NULL message
|
||||||
*/
|
*/
|
||||||
public void closeP2CallEvent(long frequency, int timeslot, long timestamp, boolean isIdleNull)
|
public void closeP2CallEvent(long frequency, int timeslot, boolean isIdleNull)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Hack: L3Harris systems can issue a channel grant on control/TS1 which creates an event for TS2 and then the
|
* Hack: L3Harris systems can issue a channel grant on control/TS1 which creates an event for TS2 and then the
|
||||||
@@ -325,21 +324,13 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DecodeEvent event;
|
|
||||||
|
|
||||||
if(timeslot == P25P1Message.TIMESLOT_0 || timeslot == P25P1Message.TIMESLOT_1)
|
if(timeslot == P25P1Message.TIMESLOT_0 || timeslot == P25P1Message.TIMESLOT_1)
|
||||||
{
|
{
|
||||||
event = mTS1ChannelGrantEventMap.remove(frequency);
|
mTS1ChannelGrantEventMap.remove(frequency);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event = mTS2ChannelGrantEventMap.remove(frequency);
|
mTS2ChannelGrantEventMap.remove(frequency);
|
||||||
}
|
|
||||||
|
|
||||||
if(event != null)
|
|
||||||
{
|
|
||||||
event.end(timestamp);
|
|
||||||
broadcast(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -1410,55 +1401,50 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I
|
|||||||
* Compares the TO role identifier(s) from each collection for equality. This is normally used to compare a call
|
* Compares the TO role identifier(s) from each collection for equality. This is normally used to compare a call
|
||||||
* update where we only compare the TO role.
|
* update where we only compare the TO role.
|
||||||
*
|
*
|
||||||
* @param collection1 containing a TO identifier
|
* @param existingIC containing a TO identifier
|
||||||
* @param collection2 containing a TO identifier
|
* @param nextIC containing a TO identifier
|
||||||
* @return true if both collections contain a TO identifier and the TO identifiers are the same value
|
* @return true if both collections contain a TO identifier and the TO identifiers are the same value
|
||||||
*/
|
*/
|
||||||
private boolean isSameCallUpdate(IdentifierCollection collection1, IdentifierCollection collection2)
|
private boolean isSameCallUpdate(IdentifierCollection existingIC, IdentifierCollection nextIC)
|
||||||
{
|
{
|
||||||
Identifier toIdentifier1 = collection1.getToIdentifier();
|
Identifier existingTO = existingIC.getToIdentifier();
|
||||||
Identifier toIdentifier2 = collection2.getToIdentifier();
|
Identifier nextTO = nextIC.getToIdentifier();
|
||||||
return toIdentifier1 != null && toIdentifier1.equals(toIdentifier2);
|
return existingTO != null && existingTO.equals(nextTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares the TO role identifier(s) from each collection for equality. This is normally used to compare a call
|
* Compares the TO role identifier(s) from each collection for equality. This is normally used to compare a call
|
||||||
* update where we only compare the TO role.
|
* update where we only compare the TO role.
|
||||||
*
|
*
|
||||||
* @param collection1 containing a TO identifier
|
* @param existingIC for the existing/previous event containing a TO identifier
|
||||||
* @param collection2 containing a TO identifier
|
* @param nextIC for the next event containing a TO identifier
|
||||||
* @return true if both collections contain a TO identifier and the TO identifiers are the same value
|
* @return true if both collections contain a TO identifier and the TO identifiers are the same value
|
||||||
*/
|
*/
|
||||||
private boolean isSameCallFull(IdentifierCollection collection1, IdentifierCollection collection2)
|
private boolean isSameCallFull(IdentifierCollection existingIC, IdentifierCollection nextIC)
|
||||||
{
|
{
|
||||||
Identifier to1 = collection1.getToIdentifier();
|
Identifier existingTO = existingIC.getToIdentifier();
|
||||||
Identifier to2 = collection2.getToIdentifier();
|
Identifier nextTO = nextIC.getToIdentifier();
|
||||||
|
|
||||||
if(to1 != null && to1.equals(to2))
|
if(existingTO != null && existingTO.equals(nextTO))
|
||||||
{
|
{
|
||||||
Identifier from1 = collection1.getFromIdentifier();
|
Identifier existingFROM = existingIC.getFromIdentifier();
|
||||||
|
|
||||||
//If the FROM identifier hasn't yet been established, then this is the same call. We also ignore the
|
//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
|
//talker alias as a call identifier since on L3Harris systems they can transmit the talker alias before
|
||||||
//they transmit the radio ID.
|
//they transmit the radio ID.
|
||||||
if(from1 == null || from1.getForm() == Form.TALKER_ALIAS)
|
if(existingFROM == null || existingFROM.getForm() == Form.TALKER_ALIAS)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Identifier from2 = collection2.getFromIdentifier();
|
Identifier nextFROM = nextIC.getFromIdentifier();
|
||||||
|
|
||||||
if(from2 != null && from2.getForm() == Form.TALKER_ALIAS)
|
if(nextFROM != null && nextFROM.getForm() == Form.TALKER_ALIAS)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(from2 instanceof RadioIdentifier radio && radio.getValue() == 0)
|
return existingFROM.equals(nextFROM);
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return from1.equals(from2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
|||||||
protected void resetState()
|
protected void resetState()
|
||||||
{
|
{
|
||||||
super.resetState();
|
super.resetState();
|
||||||
closeCurrentCallEvent(System.currentTimeMillis(), true, false);
|
closeCurrentCallEvent(true, false);
|
||||||
mEndPttOnFacchCounter = 0;
|
mEndPttOnFacchCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1274,7 +1274,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
|||||||
{
|
{
|
||||||
if(mac instanceof EndPushToTalk)
|
if(mac instanceof EndPushToTalk)
|
||||||
{
|
{
|
||||||
closeCurrentCallEvent(message.getTimestamp(), true, false);
|
closeCurrentCallEvent(true, false);
|
||||||
|
|
||||||
if(message.getDataUnitID().isFACCH())
|
if(message.getDataUnitID().isFACCH())
|
||||||
{
|
{
|
||||||
@@ -1561,7 +1561,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
|||||||
{
|
{
|
||||||
if(mac instanceof MacRelease mr)
|
if(mac instanceof MacRelease mr)
|
||||||
{
|
{
|
||||||
closeCurrentCallEvent(message.getTimestamp(), true, false);
|
closeCurrentCallEvent(true, false);
|
||||||
broadcast(message, mac, DecodeEventType.COMMAND,
|
broadcast(message, mac, DecodeEventType.COMMAND,
|
||||||
(mr.isForcedPreemption() ? "FORCED " : "") + "CALL PREEMPTION" +
|
(mr.isForcedPreemption() ? "FORCED " : "") + "CALL PREEMPTION" +
|
||||||
(mr.isTalkerPreemption() ? " BY USER" : " BY CONTROLLER"));
|
(mr.isTalkerPreemption() ? " BY USER" : " BY CONTROLLER"));
|
||||||
@@ -1882,13 +1882,12 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
|||||||
/**
|
/**
|
||||||
* Ends/closes the current call event.
|
* Ends/closes the current call event.
|
||||||
*
|
*
|
||||||
* @param timestamp of the message that indicates the event has ended.
|
|
||||||
* @param resetIdentifiers to reset the FROM/TO identifiers (true) or reset just the FROM identifiers (false)
|
* @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
|
* @param isIdleNull to indicate if the calling trigger is an IDLE/NULL message
|
||||||
*/
|
*/
|
||||||
private void closeCurrentCallEvent(long timestamp, boolean resetIdentifiers, boolean isIdleNull)
|
private void closeCurrentCallEvent(boolean resetIdentifiers, boolean isIdleNull)
|
||||||
{
|
{
|
||||||
mTrafficChannelManager.closeP2CallEvent(getCurrentFrequency(), getTimeslot(), timestamp, isIdleNull);
|
mTrafficChannelManager.closeP2CallEvent(getCurrentFrequency(), getTimeslot(), isIdleNull);
|
||||||
|
|
||||||
if(resetIdentifiers)
|
if(resetIdentifiers)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -136,11 +136,11 @@ import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorol
|
|||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupChannelGrantUpdate;
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupChannelGrantUpdate;
|
||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupDeleteCommand;
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupDeleteCommand;
|
||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupExtendedFunctionCommand;
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupExtendedFunctionCommand;
|
||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupOpcode145;
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupTalkerAlias;
|
||||||
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupTalkerAliasContinuation;
|
||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUpdate;
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUpdate;
|
||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUserAbbreviated;
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUserAbbreviated;
|
||||||
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.MotorolaGroupRegroupVoiceChannelUserExtended;
|
||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaOpcode149;
|
|
||||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaQueuedResponse;
|
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaQueuedResponse;
|
||||||
import io.github.dsheirer.module.decode.p25.reference.Vendor;
|
import io.github.dsheirer.module.decode.p25.reference.Vendor;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -585,9 +585,9 @@ public class MacMessageFactory
|
|||||||
case MOTOROLA_89_GROUP_REGROUP_DELETE:
|
case MOTOROLA_89_GROUP_REGROUP_DELETE:
|
||||||
return new MotorolaGroupRegroupDeleteCommand(message, offset);
|
return new MotorolaGroupRegroupDeleteCommand(message, offset);
|
||||||
case MOTOROLA_91_GROUP_REGROUP_UNKNOWN:
|
case MOTOROLA_91_GROUP_REGROUP_UNKNOWN:
|
||||||
return new MotorolaGroupRegroupOpcode145(message, offset);
|
return new MotorolaGroupRegroupTalkerAlias(message, offset);
|
||||||
case MOTOROLA_95_UNKNOWN_149:
|
case MOTOROLA_95_UNKNOWN_149:
|
||||||
return new MotorolaOpcode149(message, offset);
|
return new MotorolaGroupRegroupTalkerAliasContinuation(message, offset);
|
||||||
case MOTOROLA_A0_GROUP_REGROUP_VOICE_CHANNEL_USER_EXTENDED:
|
case MOTOROLA_A0_GROUP_REGROUP_VOICE_CHANNEL_USER_EXTENDED:
|
||||||
return new MotorolaGroupRegroupVoiceChannelUserExtended(message, offset);
|
return new MotorolaGroupRegroupVoiceChannelUserExtended(message, offset);
|
||||||
case MOTOROLA_A3_GROUP_REGROUP_CHANNEL_GRANT_IMPLICIT:
|
case MOTOROLA_A3_GROUP_REGROUP_CHANNEL_GRANT_IMPLICIT:
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Motorola Group Regroup Unknown Opcode 145 - 17-bytes long
|
* Motorola Group Regroup Talker Alias - 17-bytes long
|
||||||
*/
|
*/
|
||||||
public class MotorolaGroupRegroupOpcode145 extends MacStructureVendor
|
public class MotorolaGroupRegroupTalkerAlias extends MacStructureVendor
|
||||||
{
|
{
|
||||||
private static final IntField TALKGROUP = IntField.length16(24);
|
private static final IntField TALKGROUP = IntField.length16(24);
|
||||||
private static final IntField UNKNOWN = IntField.length32(40);
|
private static final IntField UNKNOWN = IntField.length32(40);
|
||||||
@@ -49,7 +49,7 @@ public class MotorolaGroupRegroupOpcode145 extends MacStructureVendor
|
|||||||
* @param message containing the message bits
|
* @param message containing the message bits
|
||||||
* @param offset into the message for this structure
|
* @param offset into the message for this structure
|
||||||
*/
|
*/
|
||||||
public MotorolaGroupRegroupOpcode145(CorrectedBinaryMessage message, int offset)
|
public MotorolaGroupRegroupTalkerAlias(CorrectedBinaryMessage message, int offset)
|
||||||
{
|
{
|
||||||
super(message, offset);
|
super(message, offset);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ public class MotorolaGroupRegroupOpcode145 extends MacStructureVendor
|
|||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("MOTOROLA GROUP REGROUP UNKNOWN OPCODE 145 TALKGROUP:").append(getTalkgroup());
|
sb.append("MOTOROLA GROUP REGROUP TALKER ALIAS TALKGROUP:").append(getTalkgroup());
|
||||||
sb.append(" SOURCE SUID RADIO:").append(getRadio());
|
sb.append(" SOURCE SUID RADIO:").append(getRadio());
|
||||||
sb.append(" UNK:").append(Integer.toHexString(getInt(UNKNOWN)).toUpperCase());
|
sb.append(" UNK:").append(Integer.toHexString(getInt(UNKNOWN)).toUpperCase());
|
||||||
sb.append(" MSG:").append(getMessage().get(getOffset(), getMessage().length()).toHexString());
|
sb.append(" MSG:").append(getMessage().get(getOffset(), getMessage().length()).toHexString());
|
||||||
@@ -26,19 +26,30 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Motorola Unknown Opcode 149 (0x95)
|
* Motorola Unknown Opcode 149 (0x95) Talker Alias continuation message.
|
||||||
*
|
*
|
||||||
* This was observed at the end of a Group Regroup call sequence during HANGTIME, so it seems more of an announcement
|
* This was observed at the end of a Group Regroup call sequence during HANGTIME. Each radio doesn't know the alias
|
||||||
* type message and less as something relevant to the call.
|
* until it receives it once and then queues the alias for subsequent use.
|
||||||
|
*
|
||||||
|
* This opcode is observed following an Opcode 145 message and seems to be a continuation message.
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
* 959011 018E58B82BAB4D3B70E9A8457F9D C67
|
* 959011 018E58B82BAB4D3B70E9A8457F9D C67
|
||||||
* 959011 0287000000000000000000000000 E26
|
* 959011 0287000000000000000000000000 E26
|
||||||
*
|
*
|
||||||
* The opcode, vendor and length octets are consistent. The first octet seems to be an identifier, 01, 02, etc.
|
* Example 2:
|
||||||
|
* 9190110BCD02010026BEE004A403151724FD9 Opcode 145
|
||||||
|
* 959011012436C4C022EC902A9943EDAA69E76 Opcode 149
|
||||||
|
* 95901102298FAA77683FAE0000000000000AB Opcode 149
|
||||||
|
* (immediately followed in the same call sequence by a slight variation)
|
||||||
|
* 9190110BCD02010036BEE004A403151724513 Opcode 145
|
||||||
|
* 959011013436C4C022EC902A9943EDAA699F6 Opcode 149
|
||||||
|
* 95901102398FAA77683FAE00000000000072B Opcode 149
|
||||||
|
*
|
||||||
|
* The opcode, vendor and length octets are consistent. The first octet seems to be a sequence identifier, 01, 02, etc.
|
||||||
* Nothing else seems to match any of the other identifiers that were active at call time.
|
* Nothing else seems to match any of the other identifiers that were active at call time.
|
||||||
*/
|
*/
|
||||||
public class MotorolaOpcode149 extends MacStructureVendor
|
public class MotorolaGroupRegroupTalkerAliasContinuation extends MacStructureVendor
|
||||||
{
|
{
|
||||||
private List<Identifier> mIdentifiers;
|
private List<Identifier> mIdentifiers;
|
||||||
|
|
||||||
@@ -48,7 +59,7 @@ public class MotorolaOpcode149 extends MacStructureVendor
|
|||||||
* @param message containing the message bits
|
* @param message containing the message bits
|
||||||
* @param offset into the message for this structure
|
* @param offset into the message for this structure
|
||||||
*/
|
*/
|
||||||
public MotorolaOpcode149(CorrectedBinaryMessage message, int offset)
|
public MotorolaGroupRegroupTalkerAliasContinuation(CorrectedBinaryMessage message, int offset)
|
||||||
{
|
{
|
||||||
super(message, offset);
|
super(message, offset);
|
||||||
}
|
}
|
||||||
@@ -59,7 +70,7 @@ public class MotorolaOpcode149 extends MacStructureVendor
|
|||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("MOTOROLA UNKNOWN OPCODE 149");
|
sb.append("MOTOROLA TALKER ALIAS CONTINUATION");
|
||||||
sb.append(" MSG:").append(getMessage().get(getOffset(), getMessage().length()).toHexString());
|
sb.append(" MSG:").append(getMessage().get(getOffset(), getMessage().length()).toHexString());
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
@@ -227,16 +227,30 @@ public class APCO25TalkgroupFormatter extends AbstractIntegerFormatter
|
|||||||
{
|
{
|
||||||
case DECIMAL:
|
case DECIMAL:
|
||||||
case FORMATTED:
|
case FORMATTED:
|
||||||
sb.append(toDecimal(id, RADIO_DECIMAL_WIDTH));
|
if(id > 0)
|
||||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
{
|
||||||
|
sb.append(toDecimal(id, RADIO_DECIMAL_WIDTH)).append(" (");
|
||||||
|
}
|
||||||
|
sb.append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(toDecimal(radio, RADIO_DECIMAL_WIDTH)).append(")");
|
sb.append(".").append(toDecimal(radio, RADIO_DECIMAL_WIDTH));
|
||||||
|
if(id > 0)
|
||||||
|
{
|
||||||
|
sb.append(")");
|
||||||
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
case HEXADECIMAL:
|
case HEXADECIMAL:
|
||||||
sb.append(toHex(id, RADIO_HEXADECIMAL_WIDTH));
|
if(id > 0)
|
||||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
{
|
||||||
|
sb.append(toHex(id, RADIO_HEXADECIMAL_WIDTH)).append(" (");
|
||||||
|
}
|
||||||
|
sb.append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(toHex(radio, RADIO_HEXADECIMAL_WIDTH)).append(")");
|
sb.append(".").append(toHex(radio, RADIO_HEXADECIMAL_WIDTH));
|
||||||
|
if(id > 0)
|
||||||
|
{
|
||||||
|
sb.append(")");
|
||||||
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unrecognized integer format: " + format);
|
throw new IllegalArgumentException("Unrecognized integer format: " + format);
|
||||||
@@ -248,16 +262,30 @@ public class APCO25TalkgroupFormatter extends AbstractIntegerFormatter
|
|||||||
{
|
{
|
||||||
case DECIMAL:
|
case DECIMAL:
|
||||||
case FORMATTED:
|
case FORMATTED:
|
||||||
sb.append(id);
|
if(id > 0)
|
||||||
|
{
|
||||||
|
sb.append(id).append(" (");
|
||||||
|
}
|
||||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(radio).append(")");
|
sb.append(".").append(radio);
|
||||||
|
if(id > 0)
|
||||||
|
{
|
||||||
|
sb.append(")");
|
||||||
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
case HEXADECIMAL:
|
case HEXADECIMAL:
|
||||||
sb.append(toHex(id));
|
if(id > 0)
|
||||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
{
|
||||||
|
sb.append(toHex(id)).append(" (");
|
||||||
|
}
|
||||||
|
sb.append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||||
sb.append(".").append(toHex(radio)).append(")");
|
sb.append(".").append(toHex(radio));
|
||||||
|
if(id > 0)
|
||||||
|
{
|
||||||
|
sb.append(")");
|
||||||
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unrecognized integer format: " + format);
|
throw new IllegalArgumentException("Unrecognized integer format: " + format);
|
||||||
|
|||||||
@@ -300,15 +300,18 @@ public class FrequencyController
|
|||||||
*/
|
*/
|
||||||
public void removeSourceEventProcessor(ISourceEventProcessor processor)
|
public void removeSourceEventProcessor(ISourceEventProcessor processor)
|
||||||
{
|
{
|
||||||
mTunable.getLock().lock();
|
if(mTunable != null)
|
||||||
|
{
|
||||||
|
mTunable.getLock().lock();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mProcessors.remove(processor);
|
mProcessors.remove(processor);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
mTunable.getLock().unlock();
|
mTunable.getLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user