From 871705ece84aad50ce35594d42f759028714f9b4 Mon Sep 17 00:00:00 2001 From: "dennis.sheirer" Date: Fri, 23 Jan 2015 21:06:02 +0000 Subject: [PATCH] P25 - adds SNDCP context management and data packet parsing for IPV4 and UDP/IP packets to include IP addresses and data payload bytes. --- src/decode/p25/P25Decoder.java | 11 +- src/decode/p25/message/P25Message.java | 5 + src/decode/p25/message/pdu/PDUMessage.java | 5 + .../{ => confirmed}/PDUConfirmedMessage.java | 104 ++--- .../confirmed/PDUConfirmedMessageFactory.java | 80 ++++ .../SNDCPActivateTDSContextAccept.java | 252 +++++++++++++ .../SNDCPActivateTDSContextReject.java | 54 +++ .../SNDCPActivateTDSContextRequest.java | 149 ++++++++ .../confirmed/SNDCPDeactivateTDSContext.java | 61 +++ .../message/pdu/confirmed/SNDCPUserData.java | 356 ++++++++++++++++++ .../p25/reference/IPHeaderCompression.java | 38 ++ src/decode/p25/reference/IPProtocol.java | 178 +++++++++ .../p25/reference/MDPConfigurationOption.java | 38 ++ src/decode/p25/reference/PDUType.java | 50 +++ .../SNDCPActivationRejectReason.java | 53 +++ src/dsp/fsk/C4FMSymbolFilter.java | 2 +- src/dsp/fsk/P25MessageFramer.java | 19 +- src/dsp/gain/DirectGainControl.java | 4 - src/dsp/nbfm/FilteringNBFMDemodulator.java | 2 +- 19 files changed, 1378 insertions(+), 83 deletions(-) rename src/decode/p25/message/pdu/{ => confirmed}/PDUConfirmedMessage.java (72%) create mode 100644 src/decode/p25/message/pdu/confirmed/PDUConfirmedMessageFactory.java create mode 100644 src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextAccept.java create mode 100644 src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextReject.java create mode 100644 src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextRequest.java create mode 100644 src/decode/p25/message/pdu/confirmed/SNDCPDeactivateTDSContext.java create mode 100644 src/decode/p25/message/pdu/confirmed/SNDCPUserData.java create mode 100644 src/decode/p25/reference/IPHeaderCompression.java create mode 100644 src/decode/p25/reference/IPProtocol.java create mode 100644 src/decode/p25/reference/MDPConfigurationOption.java create mode 100644 src/decode/p25/reference/PDUType.java create mode 100644 src/decode/p25/reference/SNDCPActivationRejectReason.java diff --git a/src/decode/p25/P25Decoder.java b/src/decode/p25/P25Decoder.java index df883f86..cd1b8b84 100644 --- a/src/decode/p25/P25Decoder.java +++ b/src/decode/p25/P25Decoder.java @@ -37,12 +37,14 @@ import decode.Decoder; import decode.DecoderType; import dsp.filter.ComplexFIRFilter; import dsp.filter.FilterFactory; +import dsp.filter.FloatFIRFilter; import dsp.filter.Window.WindowType; import dsp.fsk.C4FMSlicer; import dsp.fsk.C4FMSymbolFilter; import dsp.fsk.P25MessageFramer; import dsp.gain.DirectGainControl; import dsp.nbfm.FMDiscriminator; +import dsp.nbfm.FilteringNBFMDemodulator; public class P25Decoder extends Decoder implements DirectFrequencyController, Instrumentable @@ -57,9 +59,11 @@ public class P25Decoder extends Decoder private List mAvailableTaps; private ComplexFIRFilter mBasebandFilter = new ComplexFIRFilter( - FilterFactory.getLowPass( 48000, 5000, 31, WindowType.HAMMING ), 1.0 ); - + FilterFactory.getLowPass( 48000, 6000, 7000, 48, WindowType.HANNING, true ), 1.0 ); private FMDiscriminator mDemodulator = new FMDiscriminator( 1 ); + private FloatFIRFilter mAudioFilter = new FloatFIRFilter( + FilterFactory.getLowPass( 48000, 3000, 4000, 48, WindowType.HAMMING, true ), 1.0 ); + private DirectGainControl mGainControl = new DirectGainControl( 15.0f, 0.1f, 25.0f, 0.3f ); private C4FMSymbolFilter mSymbolFilter; @@ -97,7 +101,8 @@ public class P25Decoder extends Decoder mDemodulator.setListener( getRealReceiver() ); } - addRealSampleListener( mGainControl ); + addRealSampleListener( mAudioFilter ); + mAudioFilter.setListener( mGainControl ); mGainControl.setListener( mSymbolFilter ); mSymbolFilter.setListener( mSlicer ); diff --git a/src/decode/p25/message/P25Message.java b/src/decode/p25/message/P25Message.java index b2088ee9..5d312332 100644 --- a/src/decode/p25/message/P25Message.java +++ b/src/decode/p25/message/P25Message.java @@ -41,6 +41,11 @@ public class P25Message extends Message mAliasList = aliasList; } + public CRC[] getCRCResults() + { + return mCRC; + } + public BitSetBuffer getSourceMessage() { return mMessage; diff --git a/src/decode/p25/message/pdu/PDUMessage.java b/src/decode/p25/message/pdu/PDUMessage.java index 5bb0fe9b..065901a2 100644 --- a/src/decode/p25/message/pdu/PDUMessage.java +++ b/src/decode/p25/message/pdu/PDUMessage.java @@ -106,6 +106,11 @@ public class PDUMessage extends P25Message return mMessage.get( PACKET_DIRECTION_INDICATOR ) ? "OSP" : "ISP"; } + public boolean isOutbound() + { + return mMessage.get( PACKET_DIRECTION_INDICATOR ); + } + public PDUFormat getFormat() { return PDUFormat.fromValue( mMessage.getInt( FORMAT ) ); diff --git a/src/decode/p25/message/pdu/PDUConfirmedMessage.java b/src/decode/p25/message/pdu/confirmed/PDUConfirmedMessage.java similarity index 72% rename from src/decode/p25/message/pdu/PDUConfirmedMessage.java rename to src/decode/p25/message/pdu/confirmed/PDUConfirmedMessage.java index f2cc67be..ffe42fc8 100644 --- a/src/decode/p25/message/pdu/PDUConfirmedMessage.java +++ b/src/decode/p25/message/pdu/confirmed/PDUConfirmedMessage.java @@ -1,11 +1,13 @@ -package decode.p25.message.pdu; +package decode.p25.message.pdu.confirmed; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; +import decode.p25.reference.PDUType; import decode.p25.reference.Vendor; import edac.CRC; import edac.CRCP25; @@ -19,17 +21,28 @@ public class PDUConfirmedMessage extends PDUMessage public static final int[] PACKET_SEQUENCE_NUMBER = { 129,130,131 }; public static final int FINAL_FRAGMENT_FLAG = 132; public static final int[] FRAGMENT_SEQUENCE_NUMBER = { 133,134,135 }; - public static final int PACKET_DATA_START = 176; + public static final int[] PDU_TYPE = { 176,177,178,179 }; - public PDUConfirmedMessage( BitSetBuffer message, DataUnitID duid, - AliasList aliasList ) + public PDUConfirmedMessage( BitSetBuffer message, AliasList aliasList ) { - super( message, duid, aliasList ); + super( message, DataUnitID.PDUC, aliasList ); checkCRC(); - - mLog.debug( toString() ); } + + /** + * Constructor to support subclassing of this message. Initial construction + * of the message enables CRC checks to be calculated and message type to + * be inspected so that we can construct an accurate subclass message, + * without having to recalculate CRC checksums. + */ + protected PDUConfirmedMessage( PDUConfirmedMessage message ) + { + super( message.getSourceMessage(), DataUnitID.PDUC, message.getAliasList() ); + mCRC = message.getCRCResults(); + + mLog.debug( toString() ); + } private void checkCRC() { @@ -60,6 +73,7 @@ public class PDUConfirmedMessage extends PDUMessage { StringBuilder sb = new StringBuilder(); + sb.append( "[" + this.getClass() + "]" ); sb.append( "NAC:" ); sb.append( getNAC() ); sb.append( " " ); @@ -100,15 +114,25 @@ public class PDUConfirmedMessage extends PDUMessage } } - sb.append( " " ); - sb.append( getPacket() ); - sb.append( " BLOCKS:" ); sb.append( getBlocksToFollowCount() ); + sb.append( " " ); + sb.append( mMessage.toString() ); + return sb.toString(); } + /** + * Packet Data Unit Type + */ + public PDUType getPDUType() + { + return PDUType.fromValue( mMessage.getInt( PDU_TYPE ), isOutbound() ); + } + + + /** * Number of bytes/octets contained in the message, exclusive of the data * header. @@ -179,66 +203,8 @@ public class PDUConfirmedMessage extends PDUMessage return mMessage.getInt( FRAGMENT_SEQUENCE_NUMBER ); } - /** - * Hex string representation of the packet data, including packet header - * data if present. - */ - public String getPacket() - { - StringBuilder sb = new StringBuilder(); - - int dataHeaderOffset = getDataHeaderOffset(); - - if( dataHeaderOffset > 0 ) - { - sb.append( "HDR:" ); - - for( int x = 0; x < dataHeaderOffset; x++ ) - { - sb.append( getPacketOctet( x ) ); - } - - sb.append( " " ); - } - - int counter = 0; - - /* Append octets inserting a space between each 32-bit value */ - for( int x = 0; x < getOctetCount(); x++ ) - { - sb.append( getPacketOctet( x + dataHeaderOffset ) ); - - counter++; - - if( counter >= 4 ) - { - sb.append( " " ); - counter = 0; - } - } - - return sb.toString(); - } - - /** - * Returns the octet identified by the 0-indexed 'octet' argument location. - * If there is a Data Header Offset, the 0 index points to the first octet - * of the data header. Otherwise, the 0 index points to the first octet - * of the packet. You must account for the data header offset when - * specifying the octet. - */ - public String getPacketOctet( int octet ) - { - int block = (int)( octet / 16 ); - int offset = octet % 16; - - int start = PACKET_DATA_START + ( block * 144 ) + ( offset * 8 ); - - return mMessage.getHex( start, start + 7, 2 ); - } - public String toString() { - return super.toString() + " " + mMessage.toString(); + return getMessage(); } } diff --git a/src/decode/p25/message/pdu/confirmed/PDUConfirmedMessageFactory.java b/src/decode/p25/message/pdu/confirmed/PDUConfirmedMessageFactory.java new file mode 100644 index 00000000..379f09de --- /dev/null +++ b/src/decode/p25/message/pdu/confirmed/PDUConfirmedMessageFactory.java @@ -0,0 +1,80 @@ +package decode.p25.message.pdu.confirmed; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class PDUConfirmedMessageFactory +{ + public final static Logger mLog = + LoggerFactory.getLogger( PDUConfirmedMessage.class ); + + public static PDUConfirmedMessage getMessage( PDUConfirmedMessage message ) + { + switch( message.getServiceAccessPoint() ) + { + case ADDRESS_RESOLUTION_PROTOCOL: + break; + case CHANNEL_REASSIGNMENT: + break; + case CIRCUIT_DATA: + break; + case CIRCUIT_DATA_CONTROL: + break; + case ENCRYPTED_KEY_MANAGEMENT_MESSAGE: + break; + case ENCRYPTED_TRUNKING_CONTROL: + break; + case ENCRYPTED_USER_DATA: + break; + case EXTENDED_ADDRESS: + break; + case MR_CONFIGURATION: + break; + case MR_LOOPBACK: + break; + case MR_OUT_OF_SERVICE: + break; + case MR_PAGING: + break; + case MR_STATISTICS: + break; + case PACKET_DATA: + break; + case REGISTRATION_AND_AUTHORIZATION: + break; + /* Deliberate fall-through */ + case SNDCP_PACKET_DATA_CONTROL: + case UNENCRYPTED_USER_DATA: + switch( message.getPDUType() ) + { + case SN_ACTIVATE_TDS_CONTEXT_ACCEPT: + return new SNDCPActivateTDSContextAccept( message ); + case SN_ACTIVATE_TDS_CONTEXT_REJECT: + return new SNDCPActivateTDSContextReject( message ); + case SN_ACTIVATE_TDS_CONTEXT_REQUEST: + return new SNDCPActivateTDSContextRequest( message ); + case SN_DEACTIVATE_TDS_CONTEXT_ACCEPT: + case SN_DEACTIVATE_TDS_CONTEXT_REQUEST: + return new SNDCPDeactivateTDSContext( message ); + case SN_RF_CONFIRMED_DATA: + return new SNDCPUserData( message ); + case SN_RF_UNCONFIRMED_DATA: + break; + default: + break; + } + break; + case SYSTEM_CONFIGURATION: + break; + case UNENCRYPTED_KEY_MANAGEMENT_MESSAGE: + break; + case UNENCRYPTED_TRUNKING_CONTROL: + break; + default: + + } + + return message; + } +} diff --git a/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextAccept.java b/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextAccept.java new file mode 100644 index 00000000..4b4019f8 --- /dev/null +++ b/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextAccept.java @@ -0,0 +1,252 @@ +package decode.p25.message.pdu.confirmed; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import alias.AliasList; +import bits.BitSetBuffer; +import decode.p25.message.pdu.PDUMessage; +import decode.p25.reference.DataUnitID; +import decode.p25.reference.MDPConfigurationOption; +import decode.p25.reference.PDUType; +import decode.p25.reference.SNDCPActivationRejectReason; +import decode.p25.reference.Vendor; +import edac.CRC; +import edac.CRCP25; + +public class SNDCPActivateTDSContextAccept extends PDUConfirmedMessage +{ + public final static Logger mLog = + LoggerFactory.getLogger( SNDCPActivateTDSContextAccept.class ); + + /* SN-Activate TDS Context Accept */ + public static final int[] NSAPI = { 180,181,182,183 }; + public static final int[] PDUPM = { 184,185,186,187 }; + public static final int[] READY = { 188,189,190,191 }; + public static final int[] STANDBY = { 192,193,194,195 }; + public static final int[] NAT = { 196,197,198,199 }; + public static final int[] IP_1 = { 200,201,202,203,204,205,206,207 }; + public static final int[] IP_2 = { 208,209,210,211,212,213,214,215 }; + public static final int[] IP_3 = { 216,217,218,219,220,221,222,223 }; + public static final int[] IP_4 = { 224,225,226,227,228,229,230,231 }; + public static final int[] IPHC = { 232,233,234,235,236,237,238,239 }; + public static final int[] TCPSS = { 240,241,242,243 }; + public static final int[] UDPSS = { 244,245,246,247 }; + public static final int[] MTU = { 248,249,250,251 }; + public static final int[] UDPC = { 252,253,254,255 }; + public static final int[] MDPCO = { 256,257,258,259,260,261,262,263 }; + public static final int[] DATA_ACCESS_CONTROL = { 264,265,266,267,268, + 269,270,271,272,273,274,275,276,277,278,279 }; + + public SNDCPActivateTDSContextAccept( PDUConfirmedMessage message ) + { + super( message ); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " LLID:" ); + sb.append( getLogicalLinkID() ); + sb.append( " ACCEPT SNDCP PACKET DATA ACTIVATE " ); + sb.append( getNetworkAddressType() ); + sb.append( " " ); + sb.append( getIPAddress() ); + sb.append( " NSAPI:" ); + sb.append( getNSAPI() ); + sb.append( " MTU:" ); + sb.append( getMaximumTransmissionUnit() ); + sb.append( " CRC[" ); + sb.append( getErrorStatus() ); + sb.append( "]" ); + + sb.append( " PACKET #" ); + sb.append( getPacketSequenceNumber() ); + + if( isFinalFragment() && getFragmentSequenceNumber() == 0 ) + { + sb.append( ".C" ); + } + else + { + sb.append( "." ); + sb.append( getFragmentSequenceNumber() ); + + if( isFinalFragment() ) + { + sb.append( "C" ); + } + } + + sb.append( " " ); + + return sb.toString(); + } + + /** + * Network Service Access Point Identifier - up to 14 NSAPI's can be + * allocated to the mobile with each NSAPI to be used for a specific + * protocol layer. + */ + public int getNSAPI() + { + return mMessage.getInt( NSAPI ); + } + + public int getPDUPriorityMaximum() + { + return mMessage.getInt( PDUPM ); + } + + public String getReadyTimer() + { + switch( mMessage.getInt( READY ) ) + { + case 1: + return "1 Second"; + case 2: + return "2 Seconds"; + case 3: + return "4 Seconds"; + case 4: + return "6 Seconds"; + case 5: + return "8 Seconds"; + case 6: + return "10 Seconds"; + case 7: + return "15 Seconds"; + case 8: + return "20 Seconds"; + case 9: + return "25 Seconds"; + case 10: + return "30 Seconds"; + case 11: + return "60 Seconds"; + case 12: + return "120 Seconds"; + case 13: + return "180 Seconds"; + case 14: + return "300 Seconds"; + case 15: + return "Always in Ready"; + } + + return "UNKNOWN"; + } + + + public String getStandbyTimer() + { + switch( mMessage.getInt( STANDBY ) ) + { + case 1: + return "10 Seconds"; + case 2: + return "30 Seconds"; + case 3: + return "1 Minutes"; + case 4: + return "5 Minutes"; + case 5: + return "10 Minutes"; + case 6: + return "30 Minutes"; + case 7: + return "1 Hour"; + case 8: + return "2 Hours"; + case 9: + return "4 Hours"; + case 10: + return "8 Hours"; + case 11: + return "12 Hours"; + case 12: + return "24 Hours"; + case 13: + return "48 Hours"; + case 14: + return "72 Hours"; + case 15: + return "Always in Ready"; + } + + return "Unknown"; + } + + public String getNetworkAddressType() + { + return mMessage.getInt( NAT ) == 0 ? "IPV4 STATIC" : "IPV4 DYNAMIC"; + } + + public String getIPAddress() + { + StringBuilder sb = new StringBuilder(); + + sb.append( mMessage.getInt( IP_1 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( IP_2 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( IP_3 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( IP_4 ) ); + + return sb.toString(); + } + + public boolean hasIPHeaderCompression() + { + return mMessage.getInt( IPHC ) == 1; + } + + public boolean hasUserDataPayloadCompression() + { + return mMessage.getInt( UDPC ) == 1; + } + + public int getTCPStateSlots() + { + return mMessage.getInt( TCPSS ); + } + + public int getUDPStateSlots() + { + return mMessage.getInt( UDPSS ); + } + + public String getMaximumTransmissionUnit() + { + int mtu = mMessage.getInt( MTU ); + + switch( mtu ) + { + case 1: + return "296 BYTES"; + case 2: + return "510 BYTES"; + case 3: + return "1020 BYTES"; + case 4: + return "1500 BYTES"; + default: + return "UNK-" + mtu; + } + } + + public MDPConfigurationOption getMDPConfigurationOption() + { + return MDPConfigurationOption.fromValue( mMessage.getInt( MDPCO ) ); + } + + public String getDataAccessControl() + { + return mMessage.getHex( DATA_ACCESS_CONTROL, 4 ); + } +} diff --git a/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextReject.java b/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextReject.java new file mode 100644 index 00000000..f98071d3 --- /dev/null +++ b/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextReject.java @@ -0,0 +1,54 @@ +package decode.p25.message.pdu.confirmed; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.SNDCPActivationRejectReason; + +public class SNDCPActivateTDSContextReject extends PDUConfirmedMessage +{ + public final static Logger mLog = + LoggerFactory.getLogger( SNDCPActivateTDSContextReject.class ); + + public static final int[] NSAPI = { 180,181,182,183 }; + public static final int[] REJECT_CODE = { 184,185,186,187,188,189,190,191 }; + + public SNDCPActivateTDSContextReject( PDUConfirmedMessage message ) + { + super( message ); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " LLID:" ); + sb.append( getLogicalLinkID() ); + sb.append( " REJECT SNDCP PACKET DATA ACTIVATE - REASON:" ); + sb.append( getReason().getLabel() ); + sb.append( " CRC[" ); + sb.append( getErrorStatus() ); + sb.append( "] " ); + sb.append( mMessage.toString() ); + + return sb.toString(); + } + + /** + * Network Service Access Point Identifier - up to 14 NSAPI's can be + * allocated to the mobile with each NSAPI to be used for a specific + * protocol layer. + */ + public int getNSAPI() + { + return mMessage.getInt( NSAPI ); + } + + public SNDCPActivationRejectReason getReason() + { + return SNDCPActivationRejectReason.fromValue( mMessage.getInt( REJECT_CODE ) ); + } +} diff --git a/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextRequest.java b/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextRequest.java new file mode 100644 index 00000000..37052212 --- /dev/null +++ b/src/decode/p25/message/pdu/confirmed/SNDCPActivateTDSContextRequest.java @@ -0,0 +1,149 @@ +package decode.p25.message.pdu.confirmed; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.MDPConfigurationOption; + +public class SNDCPActivateTDSContextRequest extends PDUConfirmedMessage +{ + public final static Logger mLog = + LoggerFactory.getLogger( SNDCPActivateTDSContextRequest.class ); + + public static final int[] SNDCP_VERSION = { 180,181,182,183 }; + public static final int[] NSAPI = { 184,185,186,187 }; + public static final int[] NAT = { 188,189,190,191 }; + public static final int[] IP_1 = { 192,193,194,195,196,197,198,199 }; + public static final int[] IP_2 = { 200,201,202,203,204,205,206,207 }; + public static final int[] IP_3 = { 208,209,210,211,212,213,214,215 }; + public static final int[] IP_4 = { 216,217,218,219,220,221,222,223 }; + public static final int[] DSUT = { 224,225,226,227 }; + public static final int[] UDPC = { 228,229,230,231 }; + public static final int[] IPHC = { 232,233,234,235,236,237,238,239 }; + public static final int[] TCPSS = { 240,241,242,243 }; + public static final int[] UDPSS = { 244,245,246,247 }; + public static final int[] MDPCO = { 248,249,250,251,252,253,254,255 }; + + public SNDCPActivateTDSContextRequest( PDUConfirmedMessage message ) + { + super( message ); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " LLID:" ); + sb.append( getLogicalLinkID() ); + sb.append( " REQUEST SNDCP PACKET DATA ACTIVATE " ); + sb.append( getNetworkAddressType() ); + sb.append( " " ); + sb.append( getIPAddress() ); + sb.append( " NSAPI:" ); + sb.append( getNSAPI() ); + sb.append( " CRC[" ); + sb.append( getErrorStatus() ); + sb.append( "]" ); + + sb.append( " PACKET #" ); + sb.append( getPacketSequenceNumber() ); + + if( isFinalFragment() && getFragmentSequenceNumber() == 0 ) + { + sb.append( ".C" ); + } + else + { + sb.append( "." ); + sb.append( getFragmentSequenceNumber() ); + + if( isFinalFragment() ) + { + sb.append( "C" ); + } + } + + sb.append( " " ); + + return sb.toString(); + } + + /** + * SNDCP Version: 1 = P25 SNDCP Version 1 + */ + public int getSNDCPVersion() + { + return mMessage.getInt( SNDCP_VERSION ); + } + + /** + * Network Service Access Point Identifier - up to 14 NSAPI's can be + * allocated to the mobile with each NSAPI to be used for a specific + * protocol layer. + */ + public int getNSAPI() + { + return mMessage.getInt( NSAPI ); + } + + public String getNetworkAddressType() + { + return mMessage.getInt( NAT ) == 0 ? "IPV4 STATIC" : "IPV4 DYNAMIC"; + } + + public String getIPAddress() + { + StringBuilder sb = new StringBuilder(); + + sb.append( mMessage.getInt( IP_1 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( IP_2 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( IP_3 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( IP_4 ) ); + + return sb.toString(); + } + + public String getDataSubscriberUnitType() + { + switch( mMessage.getInt( DSUT ) ) + { + case 0: + return "DATA ONLY MRC"; + case 1: + return "DATA AND VOICE MRC"; + } + + return "UNKNOWN"; + } + + public boolean hasIPHeaderCompression() + { + return mMessage.getInt( IPHC ) == 1; + } + + public boolean hasUserDataPayloadCompression() + { + return mMessage.getInt( UDPC ) == 1; + } + + public int getTCPStateSlots() + { + return mMessage.getInt( TCPSS ); + } + + public int getUDPStateSlots() + { + return mMessage.getInt( UDPSS ); + } + + public MDPConfigurationOption getMDPConfigurationOption() + { + return MDPConfigurationOption.fromValue( mMessage.getInt( MDPCO ) ); + } +} diff --git a/src/decode/p25/message/pdu/confirmed/SNDCPDeactivateTDSContext.java b/src/decode/p25/message/pdu/confirmed/SNDCPDeactivateTDSContext.java new file mode 100644 index 00000000..f704ef6c --- /dev/null +++ b/src/decode/p25/message/pdu/confirmed/SNDCPDeactivateTDSContext.java @@ -0,0 +1,61 @@ +package decode.p25.message.pdu.confirmed; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.PDUType; +import decode.p25.reference.SNDCPActivationRejectReason; + +public class SNDCPDeactivateTDSContext extends PDUConfirmedMessage +{ + public final static Logger mLog = + LoggerFactory.getLogger( SNDCPDeactivateTDSContext.class ); + + public static final int[] NSAPI = { 180,181,182,183 }; + public static final int[] DEACTIVATION_TYPE = { 184,185,186,187,188,189, + 190,191 }; + + public SNDCPDeactivateTDSContext( PDUConfirmedMessage message ) + { + super( message ); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " LLID:" ); + sb.append( getLogicalLinkID() ); + sb.append( " REQUEST SNDCP PACKET DATA DEACTIVATE " ); + sb.append( getDeactivationType() ); + sb.append( " CRC[" ); + sb.append( getErrorStatus() ); + sb.append( "] " ); + + return sb.toString(); + } + + /** + * Network Service Access Point Identifier - up to 14 NSAPI's can be + * allocated to the mobile with each NSAPI to be used for a specific + * protocol layer. + */ + public int getNSAPI() + { + return mMessage.getInt( NSAPI ); + } + + public String getDeactivationType() + { + if( getPDUType() == PDUType.SN_DEACTIVATE_TDS_CONTEXT_REQUEST ) + { + return mMessage.getInt( DEACTIVATION_TYPE ) == 0 ? + "ALL NSAPIS" : "THIS NSAPI"; + } + + return null; + } +} diff --git a/src/decode/p25/message/pdu/confirmed/SNDCPUserData.java b/src/decode/p25/message/pdu/confirmed/SNDCPUserData.java new file mode 100644 index 00000000..b8adccba --- /dev/null +++ b/src/decode/p25/message/pdu/confirmed/SNDCPUserData.java @@ -0,0 +1,356 @@ +package decode.p25.message.pdu.confirmed; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.IPHeaderCompression; +import decode.p25.reference.IPProtocol; + +public class SNDCPUserData extends PDUConfirmedMessage +{ + public final static Logger mLog = + LoggerFactory.getLogger( SNDCPUserData.class ); + + public static final int DATA_BLOCK_START = 176; + + public static final int[] NSAPI = { 180,181,182,183 }; + public static final int[] PCOMP = { 184,185,186,187 }; + public static final int[] DCOMP = { 188,189,190,191 }; + + /* IP Packet Header */ + public static final int[] IP_VERSION = { 192,193,194,195 }; + public static final int[] IHL = { 196,197,198,199 }; + public static final int[] DSCP = { 200,201,202,203,204,205 }; + public static final int[] ECN = { 206,207 }; + public static final int[] TOTAL_LENGTH = { 208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223 }; + public static final int[] IDENTIFICATION = { 224,225,226,227,228,229,230,231, + 232,233,234,235,236,237,238,239 }; + public static final int[] FLAGS = { 240,241,242 }; + public static final int[] FRAGMENT_OFFSET = { 243,244,245,246,247,248,249, + 250,251,252,253,254,255 }; + public static final int[] TTL = { 256,257,258,259,260,261,262,263 }; + public static final int[] PROTOCOL = { 264,265,266,267,268,269,270,271 }; + public static final int[] HEADER_CHECKSUM = { 272,273,274,275,276,277,278, + 279,280,281,282,283,284,285,286,287 }; + public static final int[] SOURCE_IP_1 = { 288,289,290,291,292,293,294,295 }; + public static final int[] SOURCE_IP_2 = { 296,297,298,299,300,301,302,303 }; + public static final int[] BLOCK_SERIAL_2 = { 304,305,306,307,308,309,310 }; + public static final int[] BLOCK_CRC9_2 = { 311,312,313,314,315,316,317,318, + 319 }; + public static final int[] SOURCE_IP_3 = { 320,321,322,323,324,325,326,327 }; + public static final int[] SOURCE_IP_4 = { 328,329,330,331,332,333,334,335 }; + public static final int[] DESTINATION_IP_1 = { 336,337,338,339,340,341,342,343 }; + public static final int[] DESTINATION_IP_2 = { 344,345,346,347,348,349,350,351 }; + public static final int[] DESTINATION_IP_3 = { 352,353,354,355,356,357,358,359 }; + public static final int[] DESTINATION_IP_4 = { 360,361,362,363,364,365,366,367 }; + + public static final int IP_DATA_START = 368; + + /* User Datagram Protocol */ + public static final int[] UDP_SOURCE_PORT = { 368,369,370,371,372,373,374, + 375 }; + public static final int[] UDP_DESTINATION_PORT = { 376,377,378,379,380,381, + 382,383 }; + public static final int[] UDP_LENGTH = { 384,385,386,387,388,389,390,391, + 392,393,394,395,396,397,398,399 }; + public static final int[] UDP_CHECKSUM = { 400,401,402,403,404,405,406,407, + 408,409,410,411,412,413,414,415 }; + public static final int UDP_DATA_START = 416; + + public SNDCPUserData( PDUConfirmedMessage message ) + { + super( message ); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " LLID:" ); + sb.append( getLogicalLinkID() ); + sb.append( " SNDCP NSAPI:" ); + sb.append( getNSAPI() ); + sb.append( " " ); + IPProtocol protocol = getIPProtocol(); + + sb.append( protocol.getLabel() ); + sb.append( "/IP" ); + + sb.append( " FM:" ); + sb.append( getSourceIPAddress() ); + + if( protocol == IPProtocol.UDP ) + { + sb.append( ":" ); + sb.append( getUDPSourcePort() ); + } + + sb.append( " TO:" ); + sb.append( getDestinationIPAddress() ); + + if( protocol == IPProtocol.UDP ) + { + sb.append( ":" ); + sb.append( getUDPDestinationPort() ); + } + + sb.append( " DATA:" ); + sb.append( getPayload() ); + + sb.append( " CRC[" ); + sb.append( getErrorStatus() ); + sb.append( "]" ); + + sb.append( " PACKET #" ); + sb.append( getPacketSequenceNumber() ); + + if( isFinalFragment() && getFragmentSequenceNumber() == 0 ) + { + sb.append( ".C" ); + } + else + { + sb.append( "." ); + sb.append( getFragmentSequenceNumber() ); + + if( isFinalFragment() ) + { + sb.append( "C" ); + } + } + + sb.append( " " ); + + sb.append( mMessage.toString() ); + + return sb.toString(); + } + + /** + * Network Service Access Point Identifier - up to 14 NSAPI's can be + * allocated to the mobile with each NSAPI to be used for a specific + * protocol layer. + */ + public int getNSAPI() + { + return mMessage.getInt( NSAPI ); + } + + public IPHeaderCompression getIPHeaderCompressionState() + { + return IPHeaderCompression.fromValue( mMessage.getInt( PCOMP ) ); + } + + /** + * No enum values were defined for this + */ + public boolean hasUserDataCompression() + { + return mMessage.getInt( DCOMP ) > 0; + } + + /** + * IP Version - should always be 4 (IPV4) + */ + public int getIPVersion() + { + return mMessage.getInt( IP_VERSION ); + } + + /** + * IP packet header length in 32-bit words + */ + public int getInternetHeaderLength() + { + return mMessage.getInt( IHL ); + } + + /** + * IP packet DSCP + */ + public int getDifferentiatedServicesCodePoint() + { + return mMessage.getInt( DSCP ); + } + + /** + * IP packet ECN + */ + public int getExplicitCongestionNotification() + { + return mMessage.getInt( ECN ); + } + + /** + * IP packet size in bytes, including header and data + */ + public int getTotalLength() + { + return mMessage.getInt( TOTAL_LENGTH ); + } + + /** + * IP packet identification + */ + public int getIdentification() + { + return mMessage.getInt( IDENTIFICATION ); + } + + /** + * IP packet flags. 0-Reserved, 1-Don't Fragment, 2-More Fragments + */ + public int getFlags() + { + return mMessage.getInt( FLAGS ); + } + + public boolean isFragment() + { + return getFlags() > 0; + } + + /** + * IP packet - identifies the offset value in 8-byte blocks (64-bit blocks) + * for this packet fragment from the beginning. + */ + public int getFragmentOffset() + { + return mMessage.getInt( FRAGMENT_OFFSET ); + } + + /** + * IP packet time (hops) to live + */ + public int getTimeToLive() + { + return mMessage.getInt( TTL ); + } + + /** + * Identifies the IP protocol carried by the IP packet + */ + public IPProtocol getIPProtocol() + { + return IPProtocol.fromValue( mMessage.getInt( PROTOCOL ) ); + } + + /** + * Source IPV4 address + */ + public String getSourceIPAddress() + { + StringBuilder sb = new StringBuilder(); + + sb.append( mMessage.getInt( SOURCE_IP_1 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( SOURCE_IP_2 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( SOURCE_IP_3 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( SOURCE_IP_4 ) ); + + return sb.toString(); + } + + /** + * Destination IPV4 address + */ + public String getDestinationIPAddress() + { + StringBuilder sb = new StringBuilder(); + + sb.append( mMessage.getInt( DESTINATION_IP_1 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( DESTINATION_IP_2 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( DESTINATION_IP_3 ) ); + sb.append( "." ); + sb.append( mMessage.getInt( DESTINATION_IP_4 ) ); + + return sb.toString(); + } + + /** + * UDP source port + */ + public int getUDPSourcePort() + { + return mMessage.getInt( UDP_SOURCE_PORT ); + } + + /** + * UDP destination port + */ + public int getUDPDestinationPort() + { + return mMessage.getInt( UDP_DESTINATION_PORT ); + } + + /** + * UDP data payload size in bytes + */ + public int getUDPDataLength() + { + return mMessage.getInt( UDP_LENGTH ); + } + /** + * Hex string representation of the packet data, including packet header + * data if present. + */ + public String getPayload() + { + StringBuilder sb = new StringBuilder(); + + /* Adjust for PDU header (2 bytes) plus IP Packet header (20 bytes) */ + int start = 22; + + if( getIPProtocol() == IPProtocol.UDP ) + { + /* Adjust for UDP header (8 bytes) */ + start = 30; + } + + int spacingCounter = 0; + + /* Append octets inserting a space between each 32-bit value */ + int octets = getOctetCount() + getDataHeaderOffset(); + + for( int x = start; x < octets; x++ ) + { + sb.append( getPacketOctet( x ) ); + + spacingCounter++; + + if( spacingCounter >= 4 ) + { + sb.append( " " ); + spacingCounter = 0; + } + } + + return sb.toString(); + } + + /** + * Returns the octet identified by the 0-indexed 'octet' argument location. + * If there is a Data Header Offset, the 0 index points to the first octet + * of the data header. Otherwise, the 0 index points to the first octet + * of the packet. You must account for the data header offset when + * specifying the octet. + */ + public String getPacketOctet( int octet ) + { + int block = (int)( octet / 16 ); + int offset = octet % 16; + + int start = DATA_BLOCK_START + ( block * 144 ) + ( offset * 8 ); + + return mMessage.getHex( start, start + 7, 2 ); + } + +} diff --git a/src/decode/p25/reference/IPHeaderCompression.java b/src/decode/p25/reference/IPHeaderCompression.java new file mode 100644 index 00000000..9418f678 --- /dev/null +++ b/src/decode/p25/reference/IPHeaderCompression.java @@ -0,0 +1,38 @@ +package decode.p25.reference; + +public enum IPHeaderCompression +{ + NONE( 0, "NONE" ), + RFC1144_COMPRESSED( 1, "RFC-1144 COMPRESSED" ), + RFC1144_UNCOMPRESSED( 2, "RFC-1144 UNCOMPRESSED" ), + UNKNOWN( -1, "UNKNOWN" ); + + private int mValue; + private String mLabel; + + private IPHeaderCompression( int value, String label ) + { + mValue = value; + mLabel = label; + } + + public int getValue() + { + return mValue; + } + + public String getLabel() + { + return mLabel; + } + + public static IPHeaderCompression fromValue( int value ) + { + if( 0 <= value && value <= 2 ) + { + return values()[ value ]; + } + + return IPHeaderCompression.UNKNOWN; + } +} diff --git a/src/decode/p25/reference/IPProtocol.java b/src/decode/p25/reference/IPProtocol.java new file mode 100644 index 00000000..8a384502 --- /dev/null +++ b/src/decode/p25/reference/IPProtocol.java @@ -0,0 +1,178 @@ +package decode.p25.reference; + +public enum IPProtocol +{ + HOPOPT( 0, "IPV6 HOP-BY-HOP" ), + ICMP( 1, "ICMP" ), + IGMP( 2, "IGMP" ), + GGP( 3, "GGP" ), + IPinIP( 4, "IPinIP" ), + ST( 5, "ST" ), + TCP( 6, "TCP" ), + CBT( 7, "CBT" ), + EGP( 8, "EGP" ), + IGP( 9, "IGP" ), + BBN( 10, "BBN" ), + NVP( 11, "NVP" ), + PUP( 12, "PUP" ), + ARGUS( 13, "ARGUS" ), + EMCON( 14, "EMCON" ), + XNET( 15, "XNET" ), + CHAOS( 16, "CHAOS" ), + UDP( 17, "UDP" ), + MUX( 18, "MUX" ), + DCN( 19, "DCN" ), + HMP( 20, "HMP" ), + PRM( 21, "PRM" ), + XNS_IDP( 22, "XNS-IDP" ), + TRUNK_1( 23, "TRUNK-1" ), + TRUNK_2( 24, "TRUNK-2" ), + LEAF_1( 25, "LEAF-1" ), + LEAF_2( 26, "LEAF-2" ), + RDP( 27, "RDP" ), + IRTP( 28, "IRTP" ), + ISO_TP4( 29, "ISO-TP4" ), + NETBLT( 30, "NETBLT" ), + MFE_NSP( 31, "MFE-NSP" ), + MERIT_INP( 32, "MERIT-INP" ), + DCCP( 33, "DCCP" ), + _3PC( 34, "3PC" ), + IDPR( 35, "IDPR" ), + XTP( 36, "XTP" ), + DDP( 37, "DDP" ), + IDPR_CMTP( 38, "IDPR-CMTP" ), + TPPP( 39, "TP++" ), + IL( 40, "IL" ), + IPV6( 41, "IPV6" ), + SDRP( 42, "SDRP" ), + IPV6_ROUTE( 43, "IPV6-ROUTE" ), + IPV6_FRAG( 44, "IPV6-FRAG" ), + IDRP( 45, "IDRP" ), + RSVP( 46, "RSVP" ), + GRE( 47, "GRE" ), + MHRP( 48, "MHRP" ), + BNA( 49, "BNA" ), + ESP( 50, "ESP" ), + AH( 51, "AH" ), + INLSP( 52, "I-NLSP" ), + SWIPE( 53, "SWIPE" ), + NARP( 54, "NARP" ), + MOBILE( 55, "MOBILE" ), + TLSP( 56, "TLSP" ), + SKIP( 57, "SKIP" ), + IPV6_ICMP( 58, "IPV6-ICMP" ), + IPV6_NONXT( 59, "IPV6-NoNXT" ), + IPV6_OPTS( 60, "IPV6-OPTS" ), + ANY_HOST( 61, "ANY HOST" ), + CFTP( 62, "CFTP" ), + ANY_NETWORK( 63, "ANY NETWORK" ), + SAT_EXPAK( 64, "SAT_EXPAK" ), + KRYPTOLAN( 65, "KRYPTOLAN" ), + RVD( 66, "RVD" ), + IPPC( 67, "IPPC" ), + ANY_DIST( 68, "ANY DISTRIBUTED" ), + SAT_MON( 69, "SAT-MON" ), + VISA( 70, "VISA" ), + IPCU( 71, "IPCU" ), + CPNX( 72, "CPNX" ), + CPHB( 73, "CPHB" ), + WSN( 74, "WSN" ), + PVP( 75, "PVP" ), + BR_SAT_MON( 76, "BR-SAT-MON" ), + SUN_ND( 77, "SUN-ND" ), + WB_MON( 78, "WB-MON" ), + WB_EXPAK( 79, "WB-EXPAK" ), + ISO_IP( 80, "ISO-IP" ), + VMTP( 81, "VMTP" ), + SECURE_VMTP( 82, "SECURE-VMTP" ), + VINES( 83, "VINES" ), + TTP( 84, "TTP" ), + NSFNET_IGP( 85, "NSFNET-IGP" ), + DGP( 86, "DGP" ), + TCF( 87, "TCF" ), + EIGRP( 88, "EIGRP" ), + OSPF( 89, "OSPF" ), + SPRITE_RPC( 90, "SPRITE-RPC" ), + LARP( 91, "LARP" ), + MTP( 92, "MTP" ), + AX25( 93, "AX-25" ), + IPIP( 94, "IPIP" ), + MICP( 95, "MICP" ), + SCC_SP( 96, "SCC-SP" ), + ETHERIP( 97, "ETHER-IP" ), + ENCAP( 98, "ENCAP" ), + ANY_PRIVATE( 99, "ANY PRIVATE" ), + GMTP( 100, "GMTP" ), + IFMP( 101, "IFMP" ), + PNNI( 102, "PNNI" ), + PIM( 103, "PIM" ), + ARIS( 104, "ARIS" ), + SCPS( 105, "SCPS" ), + QNX( 106, "QNX" ), + A_N( 107, "A-N" ), + IPCOMP( 108, "IPCOMP" ), + SNP( 109, "SNP" ), + COMPAQ_PEER( 110, "COMPAQ-PEER" ), + IPXinIP( 111, "IPX-in-IP" ), + VRRP( 112, "VRRP" ), + PGM( 113, "PGM" ), + ANY_0_HOP( 114, "ANY 0-HOP" ), + L2TP( 115, "L2TP" ), + DDX( 116, "DDX" ), + IATP( 117, "IATP" ), + STP( 118, "STP" ), + SRP( 119, "SRP" ), + UTI( 120, "UTI" ), + SMP( 121, "SMP" ), + SM( 122, "SM" ), + PTP( 123, "PTP" ), + ISIS( 124, "IS-IS OVER IPV4" ), + FIRE( 125, "FIRE" ), + CRTP( 126, "CRTP" ), + CRUDP( 127, "CRUDP" ), + SSCOPMCE( 128, "SSCOPMCE" ), + IPLT( 129, "IPLT" ), + SPS( 130, "SPS" ), + PIPE( 131, "PIPE" ), + SCTP( 132, "SCTP" ), + FC( 133, "FC" ), + RSVP_E2E( 134, "RSVP E2E" ), + MOBILITY( 135, "MOBILITY HDR" ), + UDPLITE( 136, "UDP LITE" ), + MPLSinIP( 137, "MPLS-IN-IP" ), + MANET( 138, "MANET" ), + HIP( 139, "HIP" ), + SHIM6( 140, "SHIM6" ), + WESP( 141, "WESP" ), + ROHC( 142, "ROHC" ), + UNKNOWN( -1, "UNKNOWN" ); + + private int mValue; + private String mLabel; + + private IPProtocol( int value, String label ) + { + mValue = value; + mLabel = label; + } + + public int getValue() + { + return mValue; + } + + public String getLabel() + { + return mLabel; + } + + public static IPProtocol fromValue( int value ) + { + if( 0 <= value && value <= 142 ) + { + return values()[ value ]; + } + + return IPProtocol.UNKNOWN; + } +} diff --git a/src/decode/p25/reference/MDPConfigurationOption.java b/src/decode/p25/reference/MDPConfigurationOption.java new file mode 100644 index 00000000..d1356380 --- /dev/null +++ b/src/decode/p25/reference/MDPConfigurationOption.java @@ -0,0 +1,38 @@ +package decode.p25.reference; + +public enum MDPConfigurationOption +{ + INTERNAL( "INTERNAL INTERFACE", 0 ), + MDP_SLIP( "MDP SLIP", 1 ), + MDP_PPP( "MDP PPP", 2 ), + UNKNOWN( "UNKNOWN", -1 ); + + private String mLabel; + private int mValue; + + private MDPConfigurationOption( String label, int value ) + { + mLabel = label; + mValue = value; + } + + public String getLabel() + { + return mLabel; + } + + public int getValue() + { + return mValue; + } + + public static MDPConfigurationOption fromValue( int value ) + { + if( 0 <= value && value <= 2 ) + { + return values()[ value ]; + } + + return UNKNOWN; + } +} diff --git a/src/decode/p25/reference/PDUType.java b/src/decode/p25/reference/PDUType.java new file mode 100644 index 00000000..bb200c55 --- /dev/null +++ b/src/decode/p25/reference/PDUType.java @@ -0,0 +1,50 @@ +package decode.p25.reference; + +public enum PDUType +{ + /* Outbound */ + SN_ACTIVATE_TDS_CONTEXT_ACCEPT( "SN-ACTIVATE TDS CONTEXT ACCEPT", 0 ), + SN_DEACTIVATE_TDS_CONTEXT_ACCEPT( "SN-DEACTIVATE TDS CONTEXT ACCEPT", 1 ), + SN_DEACTIVATE_TDS_CONTEXT_REQUEST( "SN-DEACTIVATE TDS CONTEXT REQUEST", 2 ), + SN_ACTIVATE_TDS_CONTEXT_REJECT( "SN-ACTIVATE TDS CONTEXT REJECT", 3 ), + SN_RF_UNCONFIRMED_DATA( "SN-RF UNCONFIRMED DATA", 4 ), + SN_RF_CONFIRMED_DATA( "SN-RF CONFIRMED DATA", 5 ), + + /* Inbound */ + SN_ACTIVATE_TDS_CONTEXT_REQUEST( "SN-ACTIVATE TDS CONTEXT REQUEST", 0 ), + + UNKNOWN( "UNKNOWN", -1 ); + + private String mLabel; + private int mValue; + + private PDUType( String label, int value ) + { + mLabel = label; + mValue = value; + } + + public String getLabel() + { + return mLabel; + } + + public int getValue() + { + return mValue; + } + + public static PDUType fromValue( int value, boolean outbound ) + { + if( outbound && 0 <= value && value <= 5 ) + { + return values()[ value ]; + } + else if( value == 0 && !outbound ) + { + return SN_ACTIVATE_TDS_CONTEXT_REQUEST; + } + + return UNKNOWN; + } +} diff --git a/src/decode/p25/reference/SNDCPActivationRejectReason.java b/src/decode/p25/reference/SNDCPActivationRejectReason.java new file mode 100644 index 00000000..904045cb --- /dev/null +++ b/src/decode/p25/reference/SNDCPActivationRejectReason.java @@ -0,0 +1,53 @@ +package decode.p25.reference; + +public enum SNDCPActivationRejectReason +{ + R0( 0, "ANY REASON" ), + R1( 1, "MRC NOT PROVISIONED FOR TDS" ), + R2( 2, "MRC DSUT NOT SUPPORTED" ), + R3( 3, "MAX TDS CONTEXTS EXCEEDED" ), + R4( 4, "SNDCP VERSION NOT SUPPORTED" ), + R5( 5, "TDS NOT SUPPORTED BY FNE" ), + R6( 6, "TDS NOT SUPPORTED BY THIS SYSTEM" ), + R7( 7, "IPV4 STATIC ADDRESS NOT CORRECT" ), + R8( 8, "IPV4 STATIC ADDRESS NOT ALLOWED" ), + R9( 9, "IPV4 STATIC ADDRESS IN USE" ), + R10( 10, "IPV4 NOT SUPPORTED" ), + R11( 11, "IPV4 DYNAMIC ADDRESS POOL EMPTY" ), + R12( 12, "IPV4 DYNAMIC ADDRESS NOT SUPPORTED" ), + UNKNOWN( -1, "UNKNOWN" ); + + private int mValue; + public String mLabel; + + private SNDCPActivationRejectReason( int value, String label ) + { + mValue = value; + mLabel = label; + } + + public int getValue() + { + return mValue; + } + + public String getLabel() + { + return mLabel; + } + + public String toString() + { + return getLabel(); + } + + public static SNDCPActivationRejectReason fromValue( int value ) + { + if( 0 <= value && value <= 12 ) + { + return values()[ value ]; + } + + return UNKNOWN; + } +} diff --git a/src/dsp/fsk/C4FMSymbolFilter.java b/src/dsp/fsk/C4FMSymbolFilter.java index af6e4072..e3ebd0de 100644 --- a/src/dsp/fsk/C4FMSymbolFilter.java +++ b/src/dsp/fsk/C4FMSymbolFilter.java @@ -202,7 +202,7 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster, private RealSampleListener mListener; - public static final long MAX_FREQUENCY_CORRECTION = 7000; + public static final long MAX_FREQUENCY_CORRECTION = 3000; private FrequencyChangeListener mFrequencyChangeListener; private long mFrequencyCorrection; diff --git a/src/dsp/fsk/P25MessageFramer.java b/src/dsp/fsk/P25MessageFramer.java index 53814f00..28892678 100644 --- a/src/dsp/fsk/P25MessageFramer.java +++ b/src/dsp/fsk/P25MessageFramer.java @@ -20,9 +20,10 @@ import decode.p25.message.hdu.HDUMessage; import decode.p25.message.ldu.LDU1Message; import decode.p25.message.ldu.LDU2Message; import decode.p25.message.ldu.lc.LDULCMessageFactory; -import decode.p25.message.pdu.PDUConfirmedMessage; import decode.p25.message.pdu.PDUMessage; import decode.p25.message.pdu.PDUMessageFactory; +import decode.p25.message.pdu.confirmed.PDUConfirmedMessage; +import decode.p25.message.pdu.confirmed.PDUConfirmedMessageFactory; import decode.p25.message.tdu.TDUMessage; import decode.p25.message.tdu.lc.TDULCMessageFactory; import decode.p25.message.tdu.lc.TDULinkControlMessage; @@ -415,8 +416,12 @@ public class P25MessageFramer implements Listener } else { - dispatch( new PDUConfirmedMessage( mMessage.copy(), - mDUID, mAliasList ) ); + PDUConfirmedMessage pducm = + new PDUConfirmedMessage( mMessage.copy(), + mAliasList ); + + /* Translate into correct subclass */ + dispatch( PDUConfirmedMessageFactory.getMessage( pducm ) ); mComplete = true; } @@ -424,8 +429,12 @@ public class P25MessageFramer implements Listener } else { - dispatch( new PDUConfirmedMessage( mMessage.copy(), - mDUID, mAliasList ) ); + PDUConfirmedMessage pducm = + new PDUConfirmedMessage( mMessage.copy(), + mAliasList ); + + /* Translate into correct subclass */ + dispatch( PDUConfirmedMessageFactory.getMessage( pducm ) ); mComplete = true; } diff --git a/src/dsp/gain/DirectGainControl.java b/src/dsp/gain/DirectGainControl.java index 1ee5df38..78223427 100644 --- a/src/dsp/gain/DirectGainControl.java +++ b/src/dsp/gain/DirectGainControl.java @@ -71,8 +71,6 @@ public class DirectGainControl implements GainController, RealSampleListener { mGain = mMaximum; } - - mLog.debug( "Gain Increased: " + mGain ); } @Override @@ -84,8 +82,6 @@ public class DirectGainControl implements GainController, RealSampleListener { mGain = mMinimum; } - - mLog.debug( "Gain Decreased: " + mGain ); } public void setListener( RealSampleListener listener ) diff --git a/src/dsp/nbfm/FilteringNBFMDemodulator.java b/src/dsp/nbfm/FilteringNBFMDemodulator.java index 5d730266..e20063ed 100644 --- a/src/dsp/nbfm/FilteringNBFMDemodulator.java +++ b/src/dsp/nbfm/FilteringNBFMDemodulator.java @@ -55,7 +55,7 @@ public class FilteringNBFMDemodulator implements Listener */ public FilteringNBFMDemodulator() { - this( FilterFactory.getLowPass( 48000, 4000, 6000, 48, WindowType.HAMMING, true ), + this( FilterFactory.getLowPass( 48000, 5000, 7000, 48, WindowType.HAMMING, true ), 1.0002, FilterFactory.getLowPass( 48000, 3000, 6000, 48, WindowType.HAMMING, true ), 2 );