diff --git a/src/decode/p25/P25ActivitySummary.java b/src/decode/p25/P25ActivitySummary.java
new file mode 100644
index 00000000..62e32f98
--- /dev/null
+++ b/src/decode/p25/P25ActivitySummary.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * SDR Trunk
+ * Copyright (C) 2014 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
+ ******************************************************************************/
+package decode.p25;
+
+import java.util.HashMap;
+import java.util.Set;
+import java.util.TreeSet;
+
+import message.Message;
+import sample.Listener;
+import alias.AliasList;
+import controller.activity.ActivitySummaryProvider;
+import decode.p25.message.P25Message;
+import decode.p25.message.pdu.NetworkStatusBroadcastExtended;
+import decode.p25.message.pdu.PDUMessage;
+import decode.p25.message.pdu.RFSSStatusBroadcastExtended;
+import decode.p25.message.tsbk.TSBKMessage;
+import decode.p25.message.tsbk.osp.control.AdjacentStatusBroadcast;
+import decode.p25.message.tsbk.osp.control.NetworkStatusBroadcast;
+import decode.p25.message.tsbk.osp.control.RFSSStatusBroadcast;
+import decode.p25.message.tsbk.osp.control.SecondaryControlChannelBroadcast;
+import decode.p25.message.tsbk.osp.control.SystemService;
+import decode.p25.reference.Service;
+
+public class P25ActivitySummary implements ActivitySummaryProvider,
+ Listener
+{
+ private static final int sINT_NULL_VALUE = -1;
+
+ private AliasList mAliasList;
+
+ private NetworkStatusBroadcast mNetworkStatus;
+ private NetworkStatusBroadcastExtended mNetworkStatusExtended;
+ private RFSSStatusBroadcast mRFSSStatusMessage;
+ private RFSSStatusBroadcastExtended mRFSSStatusMessageExtended;
+ private HashMap mNeighborMap =
+ new HashMap();
+
+ private Set mSecondaryControlChannels =
+ new TreeSet();
+
+ public P25ActivitySummary( AliasList list )
+ {
+ mAliasList = list;
+ }
+
+ /**
+ * Cleanup method
+ */
+ public void dispose()
+ {
+ }
+
+ @Override
+ public void receive( Message message )
+ {
+ if( message instanceof TSBKMessage )
+ {
+ if( message instanceof AdjacentStatusBroadcast )
+ {
+ AdjacentStatusBroadcast neighborMessage =
+ (AdjacentStatusBroadcast)message;
+
+ mNeighborMap.put( neighborMessage.getUniqueID(), neighborMessage );
+ }
+ else if( message instanceof SecondaryControlChannelBroadcast )
+ {
+ SecondaryControlChannelBroadcast sccb =
+ (SecondaryControlChannelBroadcast)message;
+
+ if( sccb.getDownlinkFrequency1() > 0 )
+ {
+ mSecondaryControlChannels.add(
+ (SecondaryControlChannelBroadcast)message );
+ }
+ }
+ else if( message instanceof NetworkStatusBroadcast )
+ {
+ mNetworkStatus = (NetworkStatusBroadcast)message;
+ }
+ else if( message instanceof RFSSStatusBroadcast )
+ {
+ mRFSSStatusMessage = (RFSSStatusBroadcast)message;
+ }
+ }
+ else if( message instanceof PDUMessage )
+ {
+ if( message instanceof NetworkStatusBroadcastExtended )
+ {
+ mNetworkStatusExtended = (NetworkStatusBroadcastExtended)message;
+ }
+ else if( message instanceof RFSSStatusBroadcastExtended )
+ {
+ mRFSSStatusMessageExtended = (RFSSStatusBroadcastExtended)message;
+ }
+ }
+ }
+
+ @Override
+ public String getSummary()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( "Activity Summary\n" );
+ sb.append( "Decoder:\tP25\n" );
+ sb.append( "---------- THIS SITE --------------" );
+
+ if( mNetworkStatus != null )
+ {
+ sb.append( "\nNAC:\t" + mNetworkStatus.getNAC() );
+ sb.append( "\nSYSTEM:\t" + mNetworkStatus.getSystemID() );
+ sb.append( "\nWACN:\t" + mNetworkStatus.getWACN() );
+ sb.append( "\nLRA:\t" + mNetworkStatus.getLocationRegistrationArea() );
+ sb.append( "\nSERVICES:\t" + SystemService.toString(
+ mNetworkStatus.getSystemServiceClass() ) );
+ sb.append( "\nPCCH:\tDNLINK " + mNetworkStatus.getDownlinkFrequency() +
+ " [" + mNetworkStatus.getIdentifier() + "-" +
+ mNetworkStatus.getChannel() + "]\n" );
+ sb.append( "\tUPLINK " + mNetworkStatus.getUplinkFrequency() + " [" +
+ mNetworkStatus.getIdentifier() + "-" +
+ mNetworkStatus.getChannel() + "]\n" );
+ }
+ else if( mNetworkStatusExtended != null )
+ {
+ sb.append( "\nNAC:\t" + mNetworkStatusExtended.getNAC() );
+ sb.append( "\nSYSTEM:\t" + mNetworkStatusExtended.getSystemID() );
+ sb.append( "\nWACN:\t" + mNetworkStatusExtended.getWACN() );
+ sb.append( "\nLRA:\t" + mNetworkStatusExtended.getLocationRegistrationArea() );
+ sb.append( "\nSERVICES:\t" + SystemService.toString(
+ mNetworkStatusExtended.getSystemServiceClass() ) );
+ sb.append( "\nPCCH:\tDNLINK " + mNetworkStatusExtended.getDownlinkFrequency() +
+ " [" + mNetworkStatusExtended.getTransmitIdentifier() + "-" +
+ mNetworkStatusExtended.getTransmitChannel() + "]\n" );
+ sb.append( "\tUPLINK " + mNetworkStatusExtended.getUplinkFrequency() + " [" +
+ mNetworkStatusExtended.getReceiveIdentifier() + "-" +
+ mNetworkStatusExtended.getReceiveChannel() + "]" );
+ }
+
+ if( mSecondaryControlChannels.isEmpty() )
+ {
+ sb.append( "\nSCCH:\tNONE" );
+ }
+ else
+ {
+ for( SecondaryControlChannelBroadcast sec: mSecondaryControlChannels )
+ {
+ sb.append( "\nSCCH:\tDNLINK " + sec.getDownlinkFrequency1() +
+ " [" + sec.getIdentifier1() + "-" + sec.getChannel1() + "]\n" );
+ sb.append( "\tUPLINK " + sec.getUplinkFrequency1() + " [" +
+ sec.getIdentifier1() + "-" + sec.getChannel1() + "]\n" );
+
+ if( sec.hasChannel2() )
+ {
+ sb.append( "\nSCCH:\tDNLINK " + sec.getDownlinkFrequency2() +
+ " [" + sec.getIdentifier2() + "-" + sec.getChannel2() + "]\n" );
+ sb.append( "\tUPLINK " + sec.getUplinkFrequency2() + " [" +
+ sec.getIdentifier2() + "-" + sec.getChannel2() + "]" );
+ }
+ }
+ }
+
+ if( mRFSSStatusMessage != null )
+ {
+ sb.append( "\nRFSS:\t" + mRFSSStatusMessage.getRFSubsystemID() );
+ sb.append( "\nSITE:\t" + mRFSSStatusMessage.getSiteID() );
+
+ if( mAliasList != null )
+ {
+ /* Add site alias here */
+ }
+
+ }
+ else if( mRFSSStatusMessageExtended != null )
+ {
+ sb.append( "\nRFSS:\t" + mRFSSStatusMessageExtended.getRFSubsystemID() );
+ sb.append( "\nSITE:\t" + mRFSSStatusMessageExtended.getSiteID() );
+ }
+
+
+ sb.append( "\n\n----------- NEIGHBORS -------------" );
+
+ if( mNeighborMap.isEmpty() )
+ {
+ sb.append( "\n\tNONE\n" );
+ sb.append( "------------------------\n" );
+ }
+ else
+ {
+ for( AdjacentStatusBroadcast neighbor: mNeighborMap.values() )
+ {
+ sb.append( "\nNAC:\t" + neighbor.getNAC() );
+ sb.append( "\nSYSTEM:\t" + neighbor.getSystemID() );
+ sb.append( "\nLRA:\t" + neighbor.getLocationRegistrationArea() );
+ sb.append( "\nRFSS:\t" + neighbor.getRFSS() );
+ sb.append( "\nSITE:\t" + neighbor.getSiteID() );
+ sb.append( "\nPCCH:\tDNLINK " + neighbor.getDownlinkFrequency() +
+ " [" + neighbor.getIdentifier() + "-" + neighbor.getChannel() + "]" );
+ sb.append( "\n\tUPLINK:" + neighbor.getUplinkFrequency() + "\n" );
+ sb.append( "\nSERVICES:\t" + Service.getServices( neighbor.getSystemServiceClass() ) );
+ sb.append( "\n----------------------------------------------------" );
+ }
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/src/decode/p25/P25ChannelState.java b/src/decode/p25/P25ChannelState.java
index bc23528b..c9bc3cdb 100644
--- a/src/decode/p25/P25ChannelState.java
+++ b/src/decode/p25/P25ChannelState.java
@@ -28,9 +28,13 @@ import decode.p25.message.P25Message;
public class P25ChannelState extends ChannelState
{
+ private P25ActivitySummary mActivitySummary;
+
public P25ChannelState( ProcessingChain chain, AliasList aliasList )
{
super( chain, aliasList );
+
+ mActivitySummary = new P25ActivitySummary( aliasList );
}
public void addListener( SquelchListener listener )
@@ -43,10 +47,10 @@ public class P25ChannelState extends ChannelState
public void receive( Message message )
{
super.receive( message );
-
+
if( message instanceof P25Message )
{
-
+ mActivitySummary.receive( (P25Message)message );
}
}
@@ -61,9 +65,8 @@ public class P25ChannelState extends ChannelState
public String getActivitySummary()
{
StringBuilder sb = new StringBuilder();
-
- sb.append( "Activity Summary\n" );
- sb.append( "\tDecoder:\tP25\n\n" );
+
+ sb.append( mActivitySummary.getSummary() );
for( AuxChannelState state: mAuxChannelStates )
{
diff --git a/src/decode/p25/P25MessageProcessor.java b/src/decode/p25/P25MessageProcessor.java
index 2afb8536..0f534a8f 100644
--- a/src/decode/p25/P25MessageProcessor.java
+++ b/src/decode/p25/P25MessageProcessor.java
@@ -63,14 +63,14 @@ public class P25MessageProcessor implements Listener
mIdentifierMap.put( identifierUpdate.getIdentifier(), identifierUpdate );
}
- if( message instanceof TSBKMessage )
- {
- mLog.debug( message.getMessage() );
- }
- else
- {
- mLog.debug( message.getMessage() + "\t" + message.getBinaryMessage() );
- }
+// if( message instanceof TSBKMessage )
+// {
+// mLog.debug( message.getMessage() );
+// }
+// else
+// {
+// mLog.debug( message.getMessage() + "\t" + message.getBinaryMessage() );
+// }
mBroadcaster.broadcast( message );
}
diff --git a/src/decode/p25/message/P25Message.java b/src/decode/p25/message/P25Message.java
index ddaa2435..832f9d06 100644
--- a/src/decode/p25/message/P25Message.java
+++ b/src/decode/p25/message/P25Message.java
@@ -5,6 +5,7 @@ import message.Message;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
+import decode.p25.message.tsbk.osp.control.IdentifierUpdate;
import decode.p25.reference.DataUnitID;
public class P25Message extends Message
@@ -128,4 +129,44 @@ public class P25Message extends Message
{
return true;
}
+
+ /**
+ * Calculates the frequency of the uplink channel using the channel number
+ * and the IdentifierUpdate message.
+ *
+ * @param iden - Identifier Update message
+ * @param channel - channel number
+ * @return - frequency in Hertz
+ */
+ protected static long calculateUplink( IdentifierUpdate iden, int channel )
+ {
+ long downlink = calculateDownlink( iden, channel );
+
+ if( downlink > 0 && iden != null )
+ {
+ return downlink + iden.getTransmitOffset();
+ }
+
+ return 0;
+ }
+
+ /**
+ * Calculates the frequency of the downlink channel using the channel number
+ * and the IdentifierUpdate message.
+ *
+ * @param iden - Identifier Update message
+ * @param channel - channel number
+ * @return - frequency in Hertz
+ */
+ protected static long calculateDownlink( IdentifierUpdate iden, int channel )
+ {
+ if( iden != null )
+ {
+ return iden.getBaseFrequency() +
+ ( channel * iden.getChannelSpacing() );
+ }
+
+ return 0;
+ }
+
}
diff --git a/src/decode/p25/message/pdu/NetworkStatusBroadcastExtended.java b/src/decode/p25/message/pdu/NetworkStatusBroadcastExtended.java
new file mode 100644
index 00000000..e92dc61b
--- /dev/null
+++ b/src/decode/p25/message/pdu/NetworkStatusBroadcastExtended.java
@@ -0,0 +1,146 @@
+package decode.p25.message.pdu;
+
+import alias.AliasList;
+import bits.BitSetBuffer;
+import decode.p25.message.tsbk.osp.control.IdentifierUpdate;
+import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver;
+import decode.p25.message.tsbk.osp.control.SystemService;
+import decode.p25.reference.DataUnitID;
+import decode.p25.reference.Opcode;
+
+public class NetworkStatusBroadcastExtended extends PDUMessage
+ implements IdentifierUpdateReceiver
+{
+ public static final int[] LRA = { 88,89,90,91,92,93,94,95 };
+ public static final int[] SYSTEM_ID = { 100,101,102,103,104,105,106,107,108,
+ 109,110,111 };
+ public static final int[] WACN = { 160,161,162,163,164,165,166,167,168,169,
+ 170,171,172,173,174,175,176,177,178,179 };
+ public static final int[] TRANSMIT_IDENTIFIER = { 184,185,186,187 };
+ public static final int[] TRANSMIT_CHANNEL = { 188,189,190,191,192,193,194,
+ 195,196,197,198,199 };
+ public static final int[] RECEIVE_IDENTIFIER = { 200,201,202,203 };
+ public static final int[] RECEIVE_CHANNEL = { 204,205,206,207,208,209,210,
+ 211,212,213,214,215 };
+ public static final int[] SYSTEM_SERVICE_CLASS = { 216,217,218,219,220,221,
+ 222,223 };
+ public static final int[] MULTIPLE_BLOCK_CRC = { 224,225,226,227,228,229,
+ 230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255 };
+
+ private IdentifierUpdate mTransmitIdentifierUpdate;
+ private IdentifierUpdate mReceiveIdentifierUpdate;
+
+ public NetworkStatusBroadcastExtended( BitSetBuffer message,
+ DataUnitID duid, AliasList aliasList )
+ {
+ super( message, duid, aliasList );
+ }
+
+ @Override
+ public String getEventType()
+ {
+ return Opcode.NETWORK_STATUS_BROADCAST.getDescription();
+ }
+
+ public String getMessage()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( getMessageStub() );
+
+ sb.append( " LRA:" + getLocationRegistrationArea() );
+
+ sb.append( " WACN:" + getWACN() );
+
+ sb.append( " SYS:" + getSystemID() );
+
+ sb.append( " CTRL CHAN:" + getReceiveIdentifier() + "-" + getReceiveChannel() );
+
+ sb.append( " DN:" + getDownlinkFrequency() );
+
+ sb.append( " " + getTransmitIdentifier() + "-" + getTransmitChannel() );
+
+ sb.append( " UP:" + getUplinkFrequency() );
+
+ sb.append( " SYS SVC CLASS:" +
+ SystemService.toString( getSystemServiceClass() ) );
+
+ return sb.toString();
+ }
+
+
+ public String getLocationRegistrationArea()
+ {
+ return mMessage.getHex( LRA, 2 );
+ }
+
+ public String getSystemID()
+ {
+ return mMessage.getHex( SYSTEM_ID, 3 );
+ }
+
+ public String getWACN()
+ {
+ return mMessage.getHex( WACN, 6 );
+ }
+
+ public int getTransmitIdentifier()
+ {
+ return mMessage.getInt( TRANSMIT_IDENTIFIER );
+ }
+
+ public int getTransmitChannel()
+ {
+ return mMessage.getInt( TRANSMIT_CHANNEL );
+ }
+
+ public int getReceiveIdentifier()
+ {
+ return mMessage.getInt( RECEIVE_IDENTIFIER );
+ }
+
+ public int getReceiveChannel()
+ {
+ return mMessage.getInt( RECEIVE_CHANNEL );
+ }
+
+ public int getSystemServiceClass()
+ {
+ return mMessage.getInt( SYSTEM_SERVICE_CLASS );
+ }
+
+ public long getDownlinkFrequency()
+ {
+ return calculateDownlink( mTransmitIdentifierUpdate, getTransmitChannel() );
+ }
+
+ public long getUplinkFrequency()
+ {
+ return calculateUplink( mReceiveIdentifierUpdate, getReceiveChannel() );
+ }
+
+ @Override
+ public void setIdentifierMessage( int identifier, IdentifierUpdate message )
+ {
+ if( identifier == getTransmitIdentifier() )
+ {
+ mTransmitIdentifierUpdate = message;
+ }
+
+ if( identifier == getReceiveIdentifier() )
+ {
+ mReceiveIdentifierUpdate = message;
+ }
+ }
+
+ public int[] getIdentifiers()
+ {
+ int[] idens = new int[ 2 ];
+
+ idens[ 0 ] = getTransmitIdentifier();
+ idens[ 1 ] = getReceiveIdentifier();
+
+ return idens;
+ }
+}
diff --git a/src/decode/p25/message/pdu/PDUMessage.java b/src/decode/p25/message/pdu/PDUMessage.java
index 6a078bb8..72c59329 100644
--- a/src/decode/p25/message/pdu/PDUMessage.java
+++ b/src/decode/p25/message/pdu/PDUMessage.java
@@ -4,156 +4,157 @@ import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.message.P25Message;
import decode.p25.reference.DataUnitID;
+import decode.p25.reference.Opcode;
import decode.p25.reference.PDUFormat;
import decode.p25.reference.ServiceAccessPoint;
import decode.p25.reference.Vendor;
public class PDUMessage extends P25Message
{
- public static final int PDU_HEADER_DUMMY1 = 66; //Always 0
- public static final int PDU_HEADER_CONFIRMATION_REQUIRED = 67;
- public static final int PDU_HEADER_DIRECTION_FLAG = 68;
- public static final int[] PDU_HEADER_FORMAT = { 69,70,71,72,73 };
- public static final int PDU_HEADER_DUMMY2 = 74; //Always 1
- public static final int PDU_HEADER_DUMMY3 = 75; //Always 1
- public static final int[] PDU_HEADER_SAP_ID = { 76,77,78,79,80 };
- public static final int[] PDU_HEADER_VENDOR_ID = { 81,82,83,84,85,86,87,88 };
- public static final int[] PDU_HEADER_LOGICAL_LINK_ID = { 89,90,91,92,93,94,
- 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114 };
- public static final int PDU_HEADER_FULL_MESSAGE_FLAG = 115;
- public static final int[] PDU_HEADER_BLOCKS_TO_FOLLOW = { 116,117,118,119,
- 120,121,122 };
- public static final int PDU_HEADER_DUMMY4 = 123; //Always 0
- public static final int PDU_HEADER_DUMMY5 = 124; //Always 0
- public static final int PDU_HEADER_DUMMY6 = 125; //Always 0
- public static final int[] PDU_HEADER_PAD_BLOCKS = { 126,127,128,129,130 };
- public static final int PDU_HEADER_RESYNCHRONIZE_FLAG = 131;
- public static final int[] PDU_HEADER_SEQUENCE_NUMBER = { 132,133,134 };
- public static final int[] PDU_HEADER_FRAGMENT_SEQUENCE_NUMBER = { 135,136,
- 137,138 };
- public static final int PDU_HEADER_DUMMY7 = 139; //Always 0
- public static final int PDU_HEADER_DUMMY8 = 140; //Always 0
- public static final int[] PDU_HEADER_DATA_HEADER_OFFSET = { 141,142,143,
- 144,145,146 };
- public static final int[] PDU_HEADER_CRC = { 147,148,149,150,151,152,153,154,
- 155,156,157,158,159,160,161,162 };
+ public static final int CONFIRMATION_REQUIRED_INDICATOR = 65;
+ public static final int PACKET_DIRECTION_INDICATOR = 66;
+ public static final int[] FORMAT = { 67,68,69,70,71 };
+ public static final int[] SAP_ID = { 74,75,76,77,78,79 };
+ public static final int[] VENDOR_ID = { 80,81,82,83,84,85,86,87 };
+ public static final int[] LOGICAL_LINK_ID = { 88,89,90,91,92,93,94,95,96,97,
+ 98,99,100,101,102,103,104,105,106,107,108,109,110,111 };
+ public static final int[] BLOCKS_TO_FOLLOW = { 113,114,115,116,117,118,119 };
+ public static final int[] PAD_OCTET_COUNT = { 123,124,125,126,127 };
+ public static final int[] OPCODE = { 122,123,124,125,126,127 };
+ public static final int[] DATA_HEADER_OFFSET = { 138,139,140,141,142,143 };
+ public static final int[] PDU_CRC = { 144,145,146,147,148,149,150,151,152,
+ 153,154,155,156,157,158,159 };
- //status 166,167
public PDUMessage( BitSetBuffer message, DataUnitID duid, AliasList aliasList )
{
super( message, duid, aliasList );
}
- public String getConfirmation()
+ protected String getMessageStub()
{
- return mMessage.get( PDU_HEADER_CONFIRMATION_REQUIRED ) ? "CON" : "UNC";
- }
-
- public String getDirection()
- {
- return mMessage.get( PDU_HEADER_DIRECTION_FLAG ) ? "OSP" : "ISP";
- }
-
- public PDUFormat getFormat()
- {
- return PDUFormat.fromValue( mMessage.getInt( PDU_HEADER_FORMAT ) );
- }
-
- public ServiceAccessPoint getServiceAccessPoint()
- {
- return ServiceAccessPoint.fromValue( mMessage.getInt( PDU_HEADER_SAP_ID ) );
- }
-
- public Vendor getVendor()
- {
- return Vendor.fromValue( mMessage.getInt( PDU_HEADER_VENDOR_ID ) );
- }
-
- public String getLogicalLinkID()
- {
- return mMessage.getHex( PDU_HEADER_LOGICAL_LINK_ID, 6 );
- }
-
- public boolean isFullMessage()
- {
- return mMessage.get( PDU_HEADER_FULL_MESSAGE_FLAG );
- }
-
- public int getBlockCount()
- {
- return mMessage.getInt( PDU_HEADER_BLOCKS_TO_FOLLOW );
- }
-
- public int getPadBlockCount()
- {
- return mMessage.getInt( PDU_HEADER_PAD_BLOCKS );
- }
-
- public boolean isResync()
- {
- return mMessage.get( PDU_HEADER_RESYNCHRONIZE_FLAG );
- }
-
- public int getSequenceNumber()
- {
- return mMessage.getInt( PDU_HEADER_SEQUENCE_NUMBER );
- }
-
- public int getFragmentSequenceNumber()
- {
- return mMessage.getInt( PDU_HEADER_FRAGMENT_SEQUENCE_NUMBER );
- }
-
- public int getDataHeaderOffset()
- {
- return mMessage.getInt( PDU_HEADER_DATA_HEADER_OFFSET );
- }
-
- @Override
- public String getMessage()
- {
StringBuilder sb = new StringBuilder();
+
+ Vendor vendor = getVendor();
sb.append( "NAC:" );
sb.append( getNAC() );
sb.append( " " );
sb.append( getDUID().getLabel() );
+
+ if( vendor == Vendor.STANDARD )
+ {
+ sb.append( " " );
+ sb.append( getOpcode().getLabel() );
+ }
+ else
+ {
+ sb.append( " " );
+ sb.append( vendor.getLabel() );
+ sb.append( " OPCD:" );
+ sb.append( mMessage.getHex( OPCODE, 2 ) );
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public String getMessage()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( getMessageStub() );
+
+ switch( getFormat() )
+ {
+ case ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL:
+ break;
+ case UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL:
+ sb.append( " PAD OCTETS:" + getPadOctetCount() );
+ sb.append( " DATA HDR OFFSET:" + getDataHeaderOffset() );
+ break;
+ default:
+ }
+
sb.append( " " );
sb.append( getConfirmation() );
sb.append( " " );
sb.append( getDirection() );
sb.append( " FMT:" );
sb.append( getFormat().getLabel() );
-
- switch( getFormat() )
- {
- case ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL:
- case UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL:
- sb.append( " SAP:" );
- sb.append( getServiceAccessPoint().getLabel() );
- sb.append( " VEND:" );
- sb.append( getVendor().getLabel() );
- sb.append( " LLID:" );
- sb.append( getLogicalLinkID() );
- sb.append( " FMF:" );
- sb.append( isFullMessage() ? "1" : "0" );
- sb.append( " BLKS:" );
- sb.append( getBlockCount() );
- sb.append( " PAD:" );
- sb.append( getPadBlockCount() );
- sb.append( " RESYNC:" );
- sb.append( isResync() ? "1" : "0" );
- sb.append( " SEQ:" );
- sb.append( getSequenceNumber() );
- sb.append( " FRAG:" );
- sb.append( getFragmentSequenceNumber() );
- sb.append( " DHO:" );
- sb.append( getDataHeaderOffset() );
- break;
- default:
- }
+ sb.append( " SAP:" );
+ sb.append( getServiceAccessPoint().getLabel() );
+ sb.append( " VEND:" );
+ sb.append( getVendor().getLabel() );
+ sb.append( " LLID:" );
+ sb.append( getLogicalLinkID() );
+ sb.append( " BLKS TO FOLLOW:" );
+ sb.append( getBlocksToFollowCount() );
return sb.toString();
}
+ public String getConfirmation()
+ {
+ return mMessage.get( CONFIRMATION_REQUIRED_INDICATOR ) ? "CON" : "UNC";
+ }
+
+ public String getDirection()
+ {
+ return mMessage.get( PACKET_DIRECTION_INDICATOR ) ? "OSP" : "ISP";
+ }
+
+ public PDUFormat getFormat()
+ {
+ return PDUFormat.fromValue( mMessage.getInt( FORMAT ) );
+ }
+
+ public ServiceAccessPoint getServiceAccessPoint()
+ {
+ return ServiceAccessPoint.fromValue( mMessage.getInt( SAP_ID ) );
+ }
+
+ public Vendor getVendor()
+ {
+ return Vendor.fromValue( mMessage.getInt( VENDOR_ID ) );
+ }
+
+ public String getLogicalLinkID()
+ {
+ return mMessage.getHex( LOGICAL_LINK_ID, 6 );
+ }
+
+ public int getBlocksToFollowCount()
+ {
+ return mMessage.getInt( BLOCKS_TO_FOLLOW );
+ }
+
+ public int getPadOctetCount()
+ {
+ if( getFormat() == PDUFormat.UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL )
+ {
+ return mMessage.getInt( PAD_OCTET_COUNT );
+ }
+
+ return 0;
+ }
+
+ public Opcode getOpcode()
+ {
+ if( getFormat() == PDUFormat.ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL )
+ {
+ return Opcode.fromValue( mMessage.getInt( OPCODE ) );
+ }
+
+ return Opcode.UNKNOWN;
+ }
+
+ public int getDataHeaderOffset()
+ {
+ if( getFormat() == PDUFormat.UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL )
+ {
+ return mMessage.getInt( DATA_HEADER_OFFSET );
+ }
+
+ return 0;
+ }
}
diff --git a/src/decode/p25/message/pdu/PDUMessageFactory.java b/src/decode/p25/message/pdu/PDUMessageFactory.java
new file mode 100644
index 00000000..99c81343
--- /dev/null
+++ b/src/decode/p25/message/pdu/PDUMessageFactory.java
@@ -0,0 +1,57 @@
+package decode.p25.message.pdu;
+
+import alias.AliasList;
+import bits.BitSetBuffer;
+import decode.p25.reference.DataUnitID;
+import decode.p25.reference.Opcode;
+import decode.p25.reference.PDUFormat;
+import decode.p25.reference.Vendor;
+
+public class PDUMessageFactory
+{
+ public static PDUMessage getMessage( BitSetBuffer message,
+ DataUnitID duid,
+ AliasList aliasList )
+ {
+ PDUFormat format = PDUFormat.fromValue(
+ message.getInt( PDUMessage.FORMAT ) );
+
+ switch( format )
+ {
+ case ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL:
+ Vendor vendor = Vendor.fromValue(
+ message.getInt( PDUMessage.VENDOR_ID ) );
+
+ switch( vendor )
+ {
+ case STANDARD:
+ Opcode opcode = Opcode.fromValue(
+ message.getInt( PDUMessage.OPCODE ) );
+
+ switch( opcode )
+ {
+ case NETWORK_STATUS_BROADCAST:
+ return new NetworkStatusBroadcastExtended(
+ message, duid, aliasList );
+ case RFSS_STATUS_BROADCAST:
+ return new RFSSStatusBroadcastExtended( message,
+ duid, aliasList );
+ default:
+ break;
+ }
+ case MOTOROLA:
+ break;
+ default:
+ break;
+ }
+
+ return new PDUMessage( message, duid, aliasList );
+
+ case UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL:
+ return new PDUMessage( message, duid, aliasList );
+
+ default:
+ return new PDUMessage( message, duid, aliasList );
+ }
+ }
+}
diff --git a/src/decode/p25/message/pdu/RFSSStatusBroadcastExtended.java b/src/decode/p25/message/pdu/RFSSStatusBroadcastExtended.java
new file mode 100644
index 00000000..db48177c
--- /dev/null
+++ b/src/decode/p25/message/pdu/RFSSStatusBroadcastExtended.java
@@ -0,0 +1,157 @@
+package decode.p25.message.pdu;
+
+import alias.AliasList;
+import bits.BitSetBuffer;
+import decode.p25.message.tsbk.osp.control.IdentifierUpdate;
+import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver;
+import decode.p25.message.tsbk.osp.control.SystemService;
+import decode.p25.reference.DataUnitID;
+import decode.p25.reference.Opcode;
+
+public class RFSSStatusBroadcastExtended extends PDUMessage
+ implements IdentifierUpdateReceiver
+{
+ public static final int[] LRA = { 88,89,90,91,92,93,94,95 };
+ public static final int ACTIVE_NETWORK_CONNECTION_INDICATOR = 99;
+ public static final int[] SYSTEM_ID = { 100,101,102,103,104,105,106,107,108,
+ 109,110,111 };
+ public static final int[] RFSS_ID = { 160,161,162,163,164,165,166,167 };
+ public static final int[] SITE_ID = { 168,169,170,171,172,173,174,175 };
+ public static final int[] TRANSMIT_IDENTIFIER = { 184,185,186,187 };
+ public static final int[] TRANSMIT_CHANNEL = { 188,189,190,191,192,193,194,
+ 195,196,197,198,199 };
+ public static final int[] RECEIVE_IDENTIFIER = { 200,201,202,203 };
+ public static final int[] RECEIVE_CHANNEL = { 204,205,206,207,208,209,210,
+ 211,212,213,214,215 };
+ public static final int[] SYSTEM_SERVICE_CLASS = { 216,217,218,219,220,221,
+ 222,223 };
+ public static final int[] MULTIPLE_BLOCK_CRC = { 224,225,226,227,228,229,
+ 230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255 };
+
+ private IdentifierUpdate mTransmitIdentifierUpdate;
+ private IdentifierUpdate mReceiveIdentifierUpdate;
+
+ public RFSSStatusBroadcastExtended( BitSetBuffer message,
+ DataUnitID duid, AliasList aliasList )
+ {
+ super( message, duid, aliasList );
+ }
+
+ @Override
+ public String getEventType()
+ {
+ return Opcode.NETWORK_STATUS_BROADCAST.getDescription();
+ }
+
+ public String getMessage()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( getMessageStub() );
+
+ sb.append( " LRA:" + getLocationRegistrationArea() );
+
+ sb.append( " SYS:" + getSystemID() );
+
+ sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() );
+
+ sb.append( " CTRL CHAN:" + getReceiveIdentifier() + "-" + getReceiveChannel() );
+
+ sb.append( " DN:" + getDownlinkFrequency() );
+
+ sb.append( " " + getTransmitIdentifier() + "-" + getTransmitChannel() );
+
+ sb.append( " UP:" + getUplinkFrequency() );
+
+ sb.append( " SYS SVC CLASS:" +
+ SystemService.toString( getSystemServiceClass() ) );
+
+ return sb.toString();
+ }
+
+
+ public String getLocationRegistrationArea()
+ {
+ return mMessage.getHex( LRA, 2 );
+ }
+
+ public boolean hasActiveNetworkConnection()
+ {
+ return mMessage.get( ACTIVE_NETWORK_CONNECTION_INDICATOR );
+ }
+
+ public String getSystemID()
+ {
+ return mMessage.getHex( SYSTEM_ID, 3 );
+ }
+
+ public String getRFSubsystemID()
+ {
+ return mMessage.getHex( RFSS_ID, 2 );
+ }
+
+ public String getSiteID()
+ {
+ return mMessage.getHex( SITE_ID, 2 );
+ }
+
+ public int getTransmitIdentifier()
+ {
+ return mMessage.getInt( TRANSMIT_IDENTIFIER );
+ }
+
+ public int getTransmitChannel()
+ {
+ return mMessage.getInt( TRANSMIT_CHANNEL );
+ }
+
+ public int getReceiveIdentifier()
+ {
+ return mMessage.getInt( RECEIVE_IDENTIFIER );
+ }
+
+ public int getReceiveChannel()
+ {
+ return mMessage.getInt( RECEIVE_CHANNEL );
+ }
+
+ public int getSystemServiceClass()
+ {
+ return mMessage.getInt( SYSTEM_SERVICE_CLASS );
+ }
+
+ public long getDownlinkFrequency()
+ {
+ return calculateDownlink( mTransmitIdentifierUpdate, getTransmitChannel() );
+ }
+
+ public long getUplinkFrequency()
+ {
+ return calculateUplink( mReceiveIdentifierUpdate, getReceiveChannel() );
+ }
+
+ @Override
+ public void setIdentifierMessage( int identifier, IdentifierUpdate message )
+ {
+ if( identifier == getTransmitIdentifier() )
+ {
+ mTransmitIdentifierUpdate = message;
+ }
+
+ if( identifier == getReceiveIdentifier() )
+ {
+ mReceiveIdentifierUpdate = message;
+ }
+ }
+
+ public int[] getIdentifiers()
+ {
+ int[] idens = new int[ 2 ];
+
+ idens[ 0 ] = getTransmitIdentifier();
+ idens[ 1 ] = getReceiveIdentifier();
+
+ return idens;
+ }
+}
diff --git a/src/decode/p25/message/tsbk/TSBKMessage.java b/src/decode/p25/message/tsbk/TSBKMessage.java
index 42b0f025..a0e09758 100644
--- a/src/decode/p25/message/tsbk/TSBKMessage.java
+++ b/src/decode/p25/message/tsbk/TSBKMessage.java
@@ -74,8 +74,8 @@ public class TSBKMessage extends P25Message
Vendor vendor = getVendor();
- sb.append( "SYS:" );
- sb.append( getNAC() ); /* NAC is the system id for TSBK messages */
+ sb.append( "NAC:" );
+ sb.append( getNAC() );
sb.append( " " );
sb.append( getDUID().getLabel() );
@@ -129,27 +129,4 @@ public class TSBKMessage extends P25Message
return sb.toString();
}
-
- protected static long calculateUplink( IdentifierUpdate iden, int channel )
- {
- long downlink = calculateDownlink( iden, channel );
-
- if( downlink > 0 && iden != null )
- {
- return downlink + iden.getTransmitOffset();
- }
-
- return 0;
- }
-
- protected static long calculateDownlink( IdentifierUpdate iden, int channel )
- {
- if( iden != null )
- {
- return iden.getBaseFrequency() +
- ( channel * iden.getChannelSpacing() );
- }
-
- return 0;
- }
}
diff --git a/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java b/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java
index b40b0b60..0b7cd475 100644
--- a/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java
+++ b/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java
@@ -47,11 +47,9 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierUp
sb.append( " LRA:" + getLocationRegistrationArea() );
- sb.append( " SYSID:" + getSystemID() );
+ sb.append( " SYS:" + getSystemID() );
- sb.append( " RFSS:" + getRFSS() );
-
- sb.append( " SITE:" + getSiteID() );
+ sb.append( " SITE:" + getRFSS() + "-" + getSiteID() );
sb.append( " CHAN:" + getIdentifier() + "-" + getChannel() );
@@ -109,6 +107,19 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierUp
return mMessage.get( ACTIVE_NETWORK_CONNECTION_FLAG );
}
+ public String getUniqueID()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( getSystemID() );
+ sb.append( ":" );
+ sb.append( getRFSS() );
+ sb.append( ":" );
+ sb.append( getSiteID() );
+
+ return sb.toString();
+ }
+
public String getSystemID()
{
return mMessage.getHex( SYSTEM_ID, 3 );
diff --git a/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java b/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java
index 728c376b..06560cdb 100644
--- a/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java
+++ b/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java
@@ -46,7 +46,7 @@ public class RFSSStatusBroadcast extends TSBKMessage implements IdentifierUpdate
sb.append( " SYSID:" + getSystemID() );
- sb.append( " RFSS:" + getRFSS() );
+ sb.append( " RFSS:" + getRFSubsystemID() );
sb.append( " SITE:" + getSiteID() );
@@ -81,7 +81,7 @@ public class RFSSStatusBroadcast extends TSBKMessage implements IdentifierUpdate
return mMessage.getHex( SYSTEM_ID, 3 );
}
- public String getRFSS()
+ public String getRFSubsystemID()
{
return mMessage.getHex( RFSS_ID, 2 );
}
diff --git a/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java b/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java
index 75cc0e9a..f7509660 100644
--- a/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java
+++ b/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java
@@ -10,7 +10,7 @@ import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class SecondaryControlChannelBroadcast extends TSBKMessage
- implements IdentifierUpdateReceiver
+ implements IdentifierUpdateReceiver, Comparable
{
private final static Logger mLog =
LoggerFactory.getLogger( SecondaryControlChannelBroadcast.class );
@@ -50,9 +50,7 @@ public class SecondaryControlChannelBroadcast extends TSBKMessage
sb.append( getMessageStub() );
- sb.append( " RFSS:" + getRFSS() );
-
- sb.append( " SITE:" + getSiteID() );
+ sb.append( " SITE:" + getRFSS() + "-" + getSiteID() );
sb.append( " CHAN1:" + getIdentifier1() + "-" + getChannel1() );
@@ -151,15 +149,11 @@ public class SecondaryControlChannelBroadcast extends TSBKMessage
{
mIdentifierUpdate1 = message;
}
- else if( identifier == getIdentifier2() )
+
+ if( identifier == getIdentifier2() )
{
mIdentifierUpdate2 = message;
}
- else
- {
- throw new IllegalArgumentException( "Unexpected identifier update "
- + "message for identifier [" + identifier + "]" );
- }
}
public int[] getIdentifiers()
@@ -182,4 +176,29 @@ public class SecondaryControlChannelBroadcast extends TSBKMessage
return idens;
}
+
+ @Override
+ public int compareTo( SecondaryControlChannelBroadcast other )
+ {
+ if( other.getSiteID().contentEquals( getSiteID() ) &&
+ other.getIdentifier1() == getIdentifier1() &&
+ other.getChannel1() == getChannel1() &&
+ other.getChannel2() == getChannel2() &&
+ other.getIdentifier2() == getIdentifier2() &&
+ other.getDownlinkFrequency1() == getDownlinkFrequency1() &&
+ other.getUplinkFrequency1() == getUplinkFrequency1() &&
+ other.getDownlinkFrequency2() == getDownlinkFrequency2() &&
+ other.getUplinkFrequency2() == getUplinkFrequency2() )
+ {
+ return 0;
+ }
+ else if( other.getIdentifier1() < getIdentifier1() )
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
}
diff --git a/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcastExplicit.java b/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcastExplicit.java
index 6d7aa2f6..42cd2c76 100644
--- a/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcastExplicit.java
+++ b/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcastExplicit.java
@@ -32,9 +32,7 @@ public class SecondaryControlChannelBroadcastExplicit
sb.append( getMessageStub() );
- sb.append( " RFSS:" + getRFSS() );
-
- sb.append( " SITE:" + getSiteID() );
+ sb.append( " SITE:" + getRFSS() + "-" + getSiteID() );
sb.append( " DOWNLINK:" + getIdentifier1() + "-" + getChannel1() );
diff --git a/src/decode/p25/message/tsbk/osp/control/SystemService.java b/src/decode/p25/message/tsbk/osp/control/SystemService.java
index 2002d19b..b87c0d7e 100644
--- a/src/decode/p25/message/tsbk/osp/control/SystemService.java
+++ b/src/decode/p25/message/tsbk/osp/control/SystemService.java
@@ -41,7 +41,7 @@ public class SystemService
{
StringBuilder sb = new StringBuilder();
- sb.append( "CONTROL CHAN:" );
+ sb.append( "CONTROL CHAN[" );
if( isCompositeControlChannel( service ) )
{
@@ -58,7 +58,7 @@ public class SystemService
sb.append( " BACKUP" );
}
- sb.append( " SERVICES:" );
+ sb.append( " ] SERVICES[" );
if( providesAuthenticationServices( service ) )
{
@@ -79,6 +79,8 @@ public class SystemService
{
sb.append( " VOICE" );
}
+
+ sb.append( " ]" );
return sb.toString();
}
diff --git a/src/decode/p25/reference/DataUnitID.java b/src/decode/p25/reference/DataUnitID.java
index 2b189ad1..e39f57d2 100644
--- a/src/decode/p25/reference/DataUnitID.java
+++ b/src/decode/p25/reference/DataUnitID.java
@@ -14,9 +14,10 @@ public enum DataUnitID
TSBK2( 7, 260, false, "TSBK2", "Trunking Signaling Block" ),
TSBK3( 7, 260, false, "TSBK3", "Trunking Signaling Block" ),
LDU2 ( 10, 1632, true, "LDU2 ", "Logical Link Data Unit 2" ),
- PDU1 ( 12, 456, false, "PDU1 ", "Packet Data Unit" ),
- PDU2 ( 12, 652, false, "PDU2 ", "Packet Data Unit" ),
- PDU3 ( 12, 848, false, "PDU3 ", "Packet Data Unit" ),
+ PDU0 ( 12, 260, false, "PDU0 ", "Packet Header Data Unit" ),
+ PDU1 ( 12, 356, false, "PDU1 ", "Packet Data Unit" ),
+ PDU2 ( 12, 452, false, "PDU2 ", "Packet Data Unit" ),
+ PDU3 ( 12, 548, false, "PDU3 ", "Packet Data Unit" ),
TDULC( 15, 372, false, "TDULC", "Terminator Data Unit With Link Control" ),
UNKN ( -1, 0, false, "UNKWN", "Unknown" );
@@ -76,7 +77,7 @@ public enum DataUnitID
case 10:
return LDU2;
case 12:
- return PDU1;
+ return PDU0;
case 15:
return TDULC;
default:
diff --git a/src/decode/p25/reference/PDUFormat.java b/src/decode/p25/reference/PDUFormat.java
index 43a61f09..244f9b86 100644
--- a/src/decode/p25/reference/PDUFormat.java
+++ b/src/decode/p25/reference/PDUFormat.java
@@ -23,9 +23,9 @@ public enum PDUFormat
F18( "F18", 18 ),
F19( "F19", 19 ),
F20( "F20", 20 ),
- UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL( "UMBTC", 21 ),
- ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL( "AMBTC", 22 ),
- F23( "F23", 23 ),
+ UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL( "UNCONFIRMED MBTC", 21 ),
+ F22( "F22", 22 ),
+ ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL( "ALTERNATE MBTC", 23 ),
F24( "F24", 24 ),
F25( "F25", 25 ),
F26( "F26", 26 ),
diff --git a/src/decode/p25/reference/Service.java b/src/decode/p25/reference/Service.java
index fd3baae6..8ca2da92 100644
--- a/src/decode/p25/reference/Service.java
+++ b/src/decode/p25/reference/Service.java
@@ -58,7 +58,10 @@ public enum Service
{
if( isSupported( service, serviceBitmap ) )
{
- services.add( service );
+ if( service != Service.UNKNOWN )
+ {
+ services.add( service );
+ }
}
}
diff --git a/src/decode/p25/reference/ServiceAccessPoint.java b/src/decode/p25/reference/ServiceAccessPoint.java
index 566202a6..d349db8b 100644
--- a/src/decode/p25/reference/ServiceAccessPoint.java
+++ b/src/decode/p25/reference/ServiceAccessPoint.java
@@ -63,9 +63,9 @@ public enum ServiceAccessPoint
SAP_58( "58", 58 ),
SAP_59( "59", 59 ),
SAP_60( "60", 60 ),
- UNENCRYPTED_TRUNKING_CONTROL( "OPEN TRUNK", 61 ),
+ UNENCRYPTED_TRUNKING_CONTROL( "UNENCRYPTED TRUNKING CONTROL", 61 ),
SAP_62( "62", 62 ),
- ENCRYPTED_TRUNKING_CONTROL( "ENC TRUNK", 63 ),
+ ENCRYPTED_TRUNKING_CONTROL( "ENCRYPTED TRUNKING CONTROL", 63 ),
UKNOWN( "UNKN", -1 );
private String mLabel;
diff --git a/src/dsp/fsk/P25MessageFramer.java b/src/dsp/fsk/P25MessageFramer.java
index b681a10e..0d64bf74 100644
--- a/src/dsp/fsk/P25MessageFramer.java
+++ b/src/dsp/fsk/P25MessageFramer.java
@@ -16,6 +16,7 @@ import decode.p25.P25Interleave;
import decode.p25.TrellisHalfRate;
import decode.p25.message.P25Message;
import decode.p25.message.pdu.PDUMessage;
+import decode.p25.message.pdu.PDUMessageFactory;
import decode.p25.message.tsbk.TSBKMessage;
import decode.p25.message.tsbk.TSBKMessageFactory;
import decode.p25.reference.DataUnitID;
@@ -31,6 +32,16 @@ public class P25MessageFramer implements Listener
public static final int TSBK_BEGIN = 64;
public static final int TSBK_END = 260;
public static final int TSBK_DECODED_END = 160;
+
+ public static final int PDU0_BEGIN = 64;
+ public static final int PDU0_END = 260;
+ public static final int PDU1_BEGIN = 160;
+ public static final int PDU1_END = 356;
+ public static final int PDU2_BEGIN = 256;
+ public static final int PDU2_END = 452;
+ public static final int PDU3_BEGIN = 352;
+ public static final int PDU3_END = 548;
+ public static final int PDU3_DECODED_END = 448;
private Listener mListener;
private AliasList mAliasList;
@@ -133,7 +144,7 @@ public class P25MessageFramer implements Listener
private class P25MessageAssembler
{
/* Starting position of the status symbol counter is 24 symbols to
- * account for the 48-bit sync pattern */
+ * account for the 48-bit sync pattern which is not included in message */
private int mStatusSymbolPointer = 24;
private BitSetBuffer mMessage;
private int mMessageLength;
@@ -231,31 +242,82 @@ public class P25MessageFramer implements Listener
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
- case PDU1:
- int blocks = mMessage.getInt(
- PDUMessage.PDU_HEADER_BLOCKS_TO_FOLLOW );
- int padBlocks = mMessage.getInt( PDUMessage.PDU_HEADER_PAD_BLOCKS );
-
- int blockCount = blocks + padBlocks;
+ case PDU0:
+ /* Remove interleaving */
+ P25Interleave.deinterleave( mMessage, PDU0_BEGIN, PDU0_END );
+
+ /* Remove trellis encoding */
+ mHalfRate.decode( mMessage, PDU0_BEGIN, PDU0_END );
- if( blockCount == 24 || blockCount == 32 )
+ setDUID( DataUnitID.PDU1 );
+
+ mMessage.setPointer( PDU1_BEGIN );
+ break;
+ case PDU1:
+ /* Remove interleaving */
+ P25Interleave.deinterleave( mMessage, PDU1_BEGIN, PDU1_END );
+
+ /* Remove trellis encoding */
+ mHalfRate.decode( mMessage, PDU1_BEGIN, PDU1_END );
+
+ if( mMessage.getInt( PDUMessage.BLOCKS_TO_FOLLOW ) == 1 )
{
- setDUID( DataUnitID.PDU2 );
- }
- else if( blockCount == 36 || blockCount == 48 )
- {
- setDUID( DataUnitID.PDU3 );
+ mMessage.setSize( PDU2_BEGIN );
+
+ PDUMessage pduMessage1 = PDUMessageFactory.getMessage(
+ mMessage.copy(), DataUnitID.PDU1, mAliasList );
+
+ dispatch( pduMessage1 );
+
+ mComplete = true;
}
else
{
- dispatch( new PDUMessage( mMessage.copy(), mDUID, mAliasList ) );
- mComplete = true;
+ setDUID( DataUnitID.PDU2 );
+
+ mMessage.setPointer( PDU2_BEGIN );
}
break;
case PDU2:
+ /* Remove interleaving */
+ P25Interleave.deinterleave( mMessage, PDU2_BEGIN, PDU2_END );
+
+ /* Remove trellis encoding */
+ mHalfRate.decode( mMessage, PDU2_BEGIN, PDU2_END );
+
+ if( mMessage.getInt( PDUMessage.BLOCKS_TO_FOLLOW ) == 2 )
+ {
+ mMessage.setSize( PDU3_BEGIN );
+
+ PDUMessage pduMessage2 = PDUMessageFactory.getMessage(
+ mMessage.copy(), DataUnitID.PDU2, mAliasList );
+
+ dispatch( pduMessage2 );
+
+ mComplete = true;
+ }
+ else
+ {
+ setDUID( DataUnitID.PDU3 );
+
+ mMessage.setPointer( PDU3_BEGIN );
+ }
+ break;
case PDU3:
+ /* Remove interleaving */
+ P25Interleave.deinterleave( mMessage, PDU3_BEGIN, PDU3_END );
+
+ /* Remove trellis encoding */
+ mHalfRate.decode( mMessage, PDU3_BEGIN, PDU3_END );
+
+ mMessage.setSize( PDU3_DECODED_END );
+
+ PDUMessage pduMessage3 = PDUMessageFactory.getMessage(
+ mMessage.copy(), DataUnitID.PDU3, mAliasList );
+
+ dispatch( pduMessage3 );
+
mComplete = true;
- dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case TDU:
mComplete = true;
@@ -266,18 +328,12 @@ public class P25MessageFramer implements Listener
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case TSBK1:
-// mLog.debug( "NEW: " + mMessage.toString() );
-
/* Remove interleaving */
P25Interleave.deinterleave( mMessage, TSBK_BEGIN, TSBK_END );
-
-// mLog.debug( "DEI: " + mMessage.toString() );
/* Remove trellis encoding */
mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END );
-// mLog.debug( "DEC: " + mMessage.toString() );
-
BitSetBuffer tsbkBuffer1 = mMessage.copy();
tsbkBuffer1.setSize( TSBK_DECODED_END );