P25 - adds SNDCP context management and data packet parsing for IPV4 and UDP/IP packets to include IP addresses and data payload bytes.

This commit is contained in:
dennis.sheirer
2015-01-23 21:06:02 +00:00
parent e5fad7ee22
commit 871705ece8
19 changed files with 1378 additions and 83 deletions

View File

@@ -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<Tap> 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 );

View File

@@ -41,6 +41,11 @@ public class P25Message extends Message
mAliasList = aliasList;
}
public CRC[] getCRCResults()
{
return mCRC;
}
public BitSetBuffer getSourceMessage()
{
return mMessage;

View File

@@ -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 ) );

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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 );
}
}

View File

@@ -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 ) );
}
}

View File

@@ -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 ) );
}
}

View File

@@ -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;
}
}

View File

@@ -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 );
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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<Dibit>
}
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<Dibit>
}
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;
}

View File

@@ -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 )

View File

@@ -55,7 +55,7 @@ public class FilteringNBFMDemodulator implements Listener<ComplexSample>
*/
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 );