From 86899e8a772324a430ead54a026a338f8b1534b8 Mon Sep 17 00:00:00 2001 From: "dennis.sheirer" Date: Wed, 26 Nov 2014 03:42:22 +0000 Subject: [PATCH] P25 work in progress. --- src/decode/p25/P25ActivitySummary.java | 221 ++++++++++++++++ src/decode/p25/P25ChannelState.java | 13 +- src/decode/p25/P25MessageProcessor.java | 16 +- src/decode/p25/message/P25Message.java | 41 +++ .../pdu/NetworkStatusBroadcastExtended.java | 146 +++++++++++ src/decode/p25/message/pdu/PDUMessage.java | 247 +++++++++--------- .../p25/message/pdu/PDUMessageFactory.java | 57 ++++ .../pdu/RFSSStatusBroadcastExtended.java | 157 +++++++++++ src/decode/p25/message/tsbk/TSBKMessage.java | 27 +- .../osp/control/AdjacentStatusBroadcast.java | 19 +- .../tsbk/osp/control/RFSSStatusBroadcast.java | 4 +- .../SecondaryControlChannelBroadcast.java | 39 ++- ...ondaryControlChannelBroadcastExplicit.java | 4 +- .../tsbk/osp/control/SystemService.java | 6 +- src/decode/p25/reference/DataUnitID.java | 9 +- src/decode/p25/reference/PDUFormat.java | 6 +- src/decode/p25/reference/Service.java | 5 +- .../p25/reference/ServiceAccessPoint.java | 4 +- src/dsp/fsk/P25MessageFramer.java | 100 +++++-- 19 files changed, 907 insertions(+), 214 deletions(-) create mode 100644 src/decode/p25/P25ActivitySummary.java create mode 100644 src/decode/p25/message/pdu/NetworkStatusBroadcastExtended.java create mode 100644 src/decode/p25/message/pdu/PDUMessageFactory.java create mode 100644 src/decode/p25/message/pdu/RFSSStatusBroadcastExtended.java 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 );