From 03460eeb19899c8d1c77aa3909770ae426224fdf Mon Sep 17 00:00:00 2001 From: "dennis.sheirer" Date: Fri, 2 Jan 2015 14:08:22 +0000 Subject: [PATCH] P25 work in progress --- src/bits/BitSetBuffer.java | 94 ++- src/decode/DecoderType.java | 4 +- src/decode/fleetsync2/FleetsyncMessage.java | 4 +- src/decode/lj1200/LJ1200Message.java | 4 +- .../lj1200/LJ1200TransponderMessage.java | 4 +- src/decode/ltrnet/LTRNetISWMessage.java | 4 +- src/decode/ltrnet/LTRNetMessage.java | 4 +- .../ltrstandard/LTRStandardMessage.java | 4 +- src/decode/mpt1327/MPT1327Message.java | 4 +- src/decode/p25/P25ActivitySummary.java | 3 +- src/decode/p25/P25ChannelState.java | 4 +- src/decode/p25/P25Interleave.java | 87 ++- src/decode/p25/P25MessageProcessor.java | 6 +- .../p25/message/IdentifierProvider.java | 32 ++ src/decode/p25/message/P25Message.java | 17 +- .../p25/message/filter/HDUMessageFilter.java | 36 ++ .../p25/message/filter/LDUMessageFilter.java | 35 ++ .../message/filter/P25MessageFilterSet.java | 3 + .../message/filter/TDULCMessageFilter.java | 36 ++ src/decode/p25/message/hdu/HDUMessage.java | 63 +- src/decode/p25/message/ldu/LDU1Message.java | 127 +++- src/decode/p25/message/ldu/LDU2Message.java | 4 +- .../TDULCMessage.java => ldu/LDUMessage.java} | 8 +- .../ldu/lc/AdjacentSiteStatusBroadcast.java | 127 ++++ .../AdjacentSiteStatusBroadcastExplicit.java | 98 ++++ src/decode/p25/message/ldu/lc/CallAlert.java | 50 ++ .../p25/message/ldu/lc/CallTermination.java | 43 ++ .../ldu/lc/ChannelIdentifierUpdate.java | 89 +++ .../message/ldu/lc/GroupVoiceChannelUser.java | 87 +++ .../message/ldu/lc/LDULCMessageFactory.java | 52 ++ .../p25/message/pdu/PDUConfirmedMessage.java | 33 ++ src/decode/p25/message/pdu/PDUMessage.java | 8 +- .../pdu/UnitToUnitChannelGrantExtended.java | 14 +- .../AdjacentStatusBroadcastExtended.java | 22 +- .../pdu/osp/control/CallAlertExtended.java | 2 +- .../GroupAffiliationQueryExtended.java | 2 +- .../GroupAffiliationResponseExtended.java | 2 +- .../osp/control/MessageUpdateExtended.java | 2 +- .../NetworkStatusBroadcastExtended.java | 14 +- .../control/ProtectionParameterBroadcast.java | 2 +- .../control/RFSSStatusBroadcastExtended.java | 14 +- .../control/RoamingAddressUpdateExtended.java | 2 +- .../pdu/osp/control/StatusQueryExtended.java | 2 +- .../pdu/osp/control/StatusUpdateExtended.java | 2 +- .../UnitRegistrationResponseExtended.java | 2 +- .../data/GroupDataChannelGrantExtended.java | 14 +- .../IndividualDataChannelGrantExtended.java | 4 +- .../voice/GroupVoiceChannelGrantExplicit.java | 14 +- ...phoneInterconnectChannelGrantExplicit.java | 14 +- .../UnitToUnitAnswerRequestExplicit.java | 2 +- .../UnitToUnitVoiceChannelGrantExtended.java | 4 +- ...ToUnitVoiceChannelGrantUpdateExtended.java | 14 +- .../message/tdu/TDULinkControlMessage.java | 265 +++++++++ src/decode/p25/message/tdu/TDUMessage.java | 2 +- .../tdu/lc/AdjacentSiteStatusBroadcast.java | 127 ++++ .../AdjacentSiteStatusBroadcastExplicit.java | 98 ++++ src/decode/p25/message/tdu/lc/CallAlert.java | 49 ++ .../p25/message/tdu/lc/CallTermination.java | 42 ++ .../tdu/lc/ChannelIdentifierUpdate.java | 88 +++ .../lc/ChannelIdentifierUpdateExplicit.java | 88 +++ .../tdu/lc/ExtendedFunctionCommand.java | 86 +++ .../message/tdu/lc/GroupAffiliationQuery.java | 51 ++ .../tdu/lc/GroupVoiceChannelUpdate.java | 158 +++++ .../lc/GroupVoiceChannelUpdateExplicit.java | 156 +++++ .../message/tdu/lc/GroupVoiceChannelUser.java | 86 +++ .../p25/message/tdu/lc/MessageUpdate.java | 57 ++ .../tdu/lc/NetworkStatusBroadcast.java | 109 ++++ .../lc/NetworkStatusBroadcastExplicit.java | 131 +++++ .../tdu/lc/ProtectionParameterBroadcast.java | 58 ++ .../message/tdu/lc/RFSSStatusBroadcast.java | 132 +++++ .../tdu/lc/RFSSStatusBroadcastExplicit.java | 152 +++++ .../lc/SecondaryControlChannelBroadcast.java | 159 +++++ ...ondaryControlChannelBroadcastExplicit.java | 140 +++++ .../p25/message/tdu/lc/StatusQuery.java | 51 ++ .../p25/message/tdu/lc/StatusUpdate.java | 64 +++ .../tdu/lc/SystemServiceBroadcast.java | 63 ++ .../message/tdu/lc/TDULCMessageFactory.java | 95 +++ .../message/tdu/lc/TDULinkControlMessage.java | 265 +++++++++ .../TelephoneInterconnectAnswerRequest.java | 80 +++ ...TelephoneInterconnectVoiceChannelUser.java | 93 +++ .../tdu/lc/UnitAuthenticationCommand.java | 58 ++ .../tdu/lc/UnitRegistrationCommand.java | 58 ++ .../tdu/lc/UnitToUnitAnswerRequest.java | 86 +++ .../tdu/lc/UnitToUnitVoiceChannelUser.java | 86 +++ src/decode/p25/message/tsbk/ChannelGrant.java | 10 +- .../tsbk/GroupChannelGrantExplicit.java | 8 +- .../message/tsbk/GroupMultiChannelGrant.java | 12 +- src/decode/p25/message/tsbk/TSBKMessage.java | 3 +- .../tsbk/motorola/ChannelCWIDUpdate.java | 10 +- .../osp/control/AdjacentStatusBroadcast.java | 7 +- .../control/IdentifierProviderReceiver.java | 15 + .../tsbk/osp/control/IdentifierUpdate.java | 17 +- .../osp/control/IdentifierUpdateReceiver.java | 4 +- .../tsbk/osp/control/MessageUpdate.java | 10 +- .../osp/control/NetworkStatusBroadcast.java | 7 +- .../tsbk/osp/control/RFSSStatusBroadcast.java | 7 +- .../SecondaryControlChannelBroadcast.java | 9 +- .../tsbk/osp/control/StatusUpdate.java | 14 +- .../SNDCPDataChannelAnnouncementExplicit.java | 12 +- .../tsbk/osp/data/SNDCPDataChannelGrant.java | 12 +- src/decode/p25/reference/DataUnitID.java | 9 +- .../p25/reference/LinkControlOpcode.java | 106 ++++ src/decode/p25/reference/Opcode.java | 2 +- src/decode/p25/reference/PDUFormat.java | 2 +- .../reference/VendorLinkControlOpcode.java | 106 ++++ src/decode/passport/PassportMessage.java | 4 +- src/dsp/fsk/P25MessageFramer.java | 75 ++- src/{crc => edac}/CRC.java | 2 +- src/{crc => edac}/CRCFleetsync.java | 2 +- src/{crc => edac}/CRCLJ.java | 2 +- src/{crc => edac}/CRCLTR.java | 2 +- src/{crc => edac}/CRCP25.java | 32 +- src/{crc => edac}/CRCPassport.java | 2 +- src/{crc => edac}/CRCUtil.java | 2 +- src/{crc => edac}/Checksum.java | 2 +- src/{crc => edac}/ChecksumTest.java | 2 +- src/{crc => edac}/ChecksumType.java | 2 +- src/{crc => edac}/Galois24.java | 7 +- src/edac/ReedSolomon.java | 543 ++++++++++++++++++ src/edac/ReedSolomon_24_12_13.java | 31 + src/instrument/gui/DecoderViewFrame.java | 2 +- src/test/TestCRC.java | 2 +- 122 files changed, 5372 insertions(+), 279 deletions(-) create mode 100644 src/decode/p25/message/IdentifierProvider.java create mode 100644 src/decode/p25/message/filter/HDUMessageFilter.java create mode 100644 src/decode/p25/message/filter/LDUMessageFilter.java create mode 100644 src/decode/p25/message/filter/TDULCMessageFilter.java rename src/decode/p25/message/{tdu/TDULCMessage.java => ldu/LDUMessage.java} (83%) create mode 100644 src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java create mode 100644 src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java create mode 100644 src/decode/p25/message/ldu/lc/CallAlert.java create mode 100644 src/decode/p25/message/ldu/lc/CallTermination.java create mode 100644 src/decode/p25/message/ldu/lc/ChannelIdentifierUpdate.java create mode 100644 src/decode/p25/message/ldu/lc/GroupVoiceChannelUser.java create mode 100644 src/decode/p25/message/ldu/lc/LDULCMessageFactory.java create mode 100644 src/decode/p25/message/pdu/PDUConfirmedMessage.java create mode 100644 src/decode/p25/message/tdu/TDULinkControlMessage.java create mode 100644 src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java create mode 100644 src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java create mode 100644 src/decode/p25/message/tdu/lc/CallAlert.java create mode 100644 src/decode/p25/message/tdu/lc/CallTermination.java create mode 100644 src/decode/p25/message/tdu/lc/ChannelIdentifierUpdate.java create mode 100644 src/decode/p25/message/tdu/lc/ChannelIdentifierUpdateExplicit.java create mode 100644 src/decode/p25/message/tdu/lc/ExtendedFunctionCommand.java create mode 100644 src/decode/p25/message/tdu/lc/GroupAffiliationQuery.java create mode 100644 src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdate.java create mode 100644 src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdateExplicit.java create mode 100644 src/decode/p25/message/tdu/lc/GroupVoiceChannelUser.java create mode 100644 src/decode/p25/message/tdu/lc/MessageUpdate.java create mode 100644 src/decode/p25/message/tdu/lc/NetworkStatusBroadcast.java create mode 100644 src/decode/p25/message/tdu/lc/NetworkStatusBroadcastExplicit.java create mode 100644 src/decode/p25/message/tdu/lc/ProtectionParameterBroadcast.java create mode 100644 src/decode/p25/message/tdu/lc/RFSSStatusBroadcast.java create mode 100644 src/decode/p25/message/tdu/lc/RFSSStatusBroadcastExplicit.java create mode 100644 src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcast.java create mode 100644 src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcastExplicit.java create mode 100644 src/decode/p25/message/tdu/lc/StatusQuery.java create mode 100644 src/decode/p25/message/tdu/lc/StatusUpdate.java create mode 100644 src/decode/p25/message/tdu/lc/SystemServiceBroadcast.java create mode 100644 src/decode/p25/message/tdu/lc/TDULCMessageFactory.java create mode 100644 src/decode/p25/message/tdu/lc/TDULinkControlMessage.java create mode 100644 src/decode/p25/message/tdu/lc/TelephoneInterconnectAnswerRequest.java create mode 100644 src/decode/p25/message/tdu/lc/TelephoneInterconnectVoiceChannelUser.java create mode 100644 src/decode/p25/message/tdu/lc/UnitAuthenticationCommand.java create mode 100644 src/decode/p25/message/tdu/lc/UnitRegistrationCommand.java create mode 100644 src/decode/p25/message/tdu/lc/UnitToUnitAnswerRequest.java create mode 100644 src/decode/p25/message/tdu/lc/UnitToUnitVoiceChannelUser.java create mode 100644 src/decode/p25/message/tsbk/osp/control/IdentifierProviderReceiver.java create mode 100644 src/decode/p25/reference/LinkControlOpcode.java create mode 100644 src/decode/p25/reference/VendorLinkControlOpcode.java rename src/{crc => edac}/CRC.java (99%) rename src/{crc => edac}/CRCFleetsync.java (99%) rename src/{crc => edac}/CRCLJ.java (99%) rename src/{crc => edac}/CRCLTR.java (99%) rename src/{crc => edac}/CRCP25.java (96%) rename src/{crc => edac}/CRCPassport.java (99%) rename src/{crc => edac}/CRCUtil.java (99%) rename src/{crc => edac}/Checksum.java (99%) rename src/{crc => edac}/ChecksumTest.java (99%) rename src/{crc => edac}/ChecksumType.java (99%) rename src/{crc => edac}/Galois24.java (97%) create mode 100644 src/edac/ReedSolomon.java create mode 100644 src/edac/ReedSolomon_24_12_13.java diff --git a/src/bits/BitSetBuffer.java b/src/bits/BitSetBuffer.java index c5951313..75149e84 100644 --- a/src/bits/BitSetBuffer.java +++ b/src/bits/BitSetBuffer.java @@ -381,58 +381,102 @@ public class BitSetBuffer extends BitSet } /** - * Returns the integer value represented by the bit range - * @param start - MSB of the integer - * @param end - LSB of the integer - * @return - integer value of the bit range + * Returns the int value represented by the bit range. This method will + * parse the bits in big endian or little endian format. The start value + * represents the MSB and the end value represents the LSB of the value. + * + * start < end: little endian interpretation + * end < start: big endian interpretation + * + * @param start - MSB of the value + * @param end - LSB of the value + * + * @return - int value of the bit range */ public int getInt( int start, int end ) { - if( end - start > 32 ) + if( Math.abs( end - start ) > 32 ) { throw new IllegalArgumentException( "Overflow - must be 32 bits " + "or less to fit into a primitive integer value" ); } int value = 0; - - for( int x = start; x <= end; x++ ) - { - value = Integer.rotateLeft( value, 1 ); - if( get( x ) ) - { - value++;; - } + if( start < end ) + { + for( int x = start; x <= end; x++ ) + { + value = Integer.rotateLeft( value, 1 ); + + if( get( x ) ) + { + value++;; + } + } + } + else + { + for( int x = end; x >= start; x-- ) + { + value = Integer.rotateLeft( value, 1 ); + + if( get( x ) ) + { + value++;; + } + } } return value; } /** - * Returns the long value represented by the bit range - * @param start - MSB of the long - * @param end - LSB of the long + * Returns the long value represented by the bit range. This method will + * parse the bits in big endian or little endian format. The start value + * represents the MSB and the end value represents the LSB of the value. + * + * start < end: little endian interpretation + * end < start: big endian interpretation + * + * @param start - MSB of the value + * @param end - LSB of the value + * * @return - long value of the bit range */ public long getLong( int start, int end ) { - if( end - start > 64 ) + if( Math.abs( end - start ) > 64 ) { throw new IllegalArgumentException( "Overflow - must be 64 bits " + "or less to fit into a primitive long value" ); } long value = 0; - - for( int x = start; x <= end; x++ ) + + if( start < end ) { - value = Long.rotateLeft( value, 1 ); - - if( get( x ) ) - { - value++; - } + for( int x = start; x <= end; x++ ) + { + value = Long.rotateLeft( value, 1 ); + + if( get( x ) ) + { + value++; + } + } + } + else + { + for( int x = end; x >= start; x-- ) + { + value = Long.rotateLeft( value, 1 ); + + if( get( x ) ) + { + value++; + } + } } return value; diff --git a/src/decode/DecoderType.java b/src/decode/DecoderType.java index c300b6e2..844360e4 100644 --- a/src/decode/DecoderType.java +++ b/src/decode/DecoderType.java @@ -67,7 +67,7 @@ public enum DecoderType DecoderType.LTR_STANDARD, DecoderType.MPT1327, DecoderType.NBFM, -// DecoderType.P25_PHASE1, + DecoderType.P25_PHASE1, DecoderType.PASSPORT ); } @@ -86,7 +86,7 @@ public enum DecoderType } /** - * Returns listing of auxiliary decoders. + * Available auxiliary decoders. */ public static ArrayList getAuxDecoders() { diff --git a/src/decode/fleetsync2/FleetsyncMessage.java b/src/decode/fleetsync2/FleetsyncMessage.java index 8dff9001..656e3d80 100644 --- a/src/decode/fleetsync2/FleetsyncMessage.java +++ b/src/decode/fleetsync2/FleetsyncMessage.java @@ -32,8 +32,8 @@ import org.jdesktop.swingx.mapviewer.GeoPosition; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCFleetsync; +import edac.CRC; +import edac.CRCFleetsync; public class FleetsyncMessage extends Message { diff --git a/src/decode/lj1200/LJ1200Message.java b/src/decode/lj1200/LJ1200Message.java index 7a10784b..0c144ef0 100644 --- a/src/decode/lj1200/LJ1200Message.java +++ b/src/decode/lj1200/LJ1200Message.java @@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCLJ; +import edac.CRC; +import edac.CRCLJ; public class LJ1200Message extends Message { diff --git a/src/decode/lj1200/LJ1200TransponderMessage.java b/src/decode/lj1200/LJ1200TransponderMessage.java index 5d14ec29..7f76676c 100644 --- a/src/decode/lj1200/LJ1200TransponderMessage.java +++ b/src/decode/lj1200/LJ1200TransponderMessage.java @@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCLJ; +import edac.CRC; +import edac.CRCLJ; public class LJ1200TransponderMessage extends Message { diff --git a/src/decode/ltrnet/LTRNetISWMessage.java b/src/decode/ltrnet/LTRNetISWMessage.java index ded45ebc..28ea3715 100644 --- a/src/decode/ltrnet/LTRNetISWMessage.java +++ b/src/decode/ltrnet/LTRNetISWMessage.java @@ -25,8 +25,8 @@ import message.MessageType; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCLTR; +import edac.CRC; +import edac.CRCLTR; public class LTRNetISWMessage extends LTRNetMessage { diff --git a/src/decode/ltrnet/LTRNetMessage.java b/src/decode/ltrnet/LTRNetMessage.java index 8e86f3f8..fea6aefc 100644 --- a/src/decode/ltrnet/LTRNetMessage.java +++ b/src/decode/ltrnet/LTRNetMessage.java @@ -26,9 +26,9 @@ import message.MessageType; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCLTR; import decode.DecoderType; +import edac.CRC; +import edac.CRCLTR; public abstract class LTRNetMessage extends Message { diff --git a/src/decode/ltrstandard/LTRStandardMessage.java b/src/decode/ltrstandard/LTRStandardMessage.java index b8dd577e..cba8609b 100644 --- a/src/decode/ltrstandard/LTRStandardMessage.java +++ b/src/decode/ltrstandard/LTRStandardMessage.java @@ -26,9 +26,9 @@ import message.MessageType; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCLTR; import decode.DecoderType; +import edac.CRC; +import edac.CRCLTR; public abstract class LTRStandardMessage extends Message { diff --git a/src/decode/mpt1327/MPT1327Message.java b/src/decode/mpt1327/MPT1327Message.java index 947b29bd..30c41c84 100644 --- a/src/decode/mpt1327/MPT1327Message.java +++ b/src/decode/mpt1327/MPT1327Message.java @@ -30,8 +30,8 @@ import message.Message; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCFleetsync; +import edac.CRC; +import edac.CRCFleetsync; public class MPT1327Message extends Message { diff --git a/src/decode/p25/P25ActivitySummary.java b/src/decode/p25/P25ActivitySummary.java index e5ad2815..be6fa42d 100644 --- a/src/decode/p25/P25ActivitySummary.java +++ b/src/decode/p25/P25ActivitySummary.java @@ -34,6 +34,7 @@ import sample.Listener; import alias.Alias; import alias.AliasList; import controller.activity.ActivitySummaryProvider; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; import decode.p25.message.pdu.osp.control.NetworkStatusBroadcastExtended; import decode.p25.message.pdu.osp.control.ProtectionParameterBroadcast; @@ -295,7 +296,7 @@ public class P25ActivitySummary implements ActivitySummaryProvider, sb.append( "\nFREQUENCY BANDS:" ); for( Integer id: identifiers ) { - IdentifierUpdate band = mBands.get( id ); + IdentifierProvider band = mBands.get( id ); sb.append( "\n\t" + id ); sb.append( "- BASE: " + mFrequencyFormatter.format( diff --git a/src/decode/p25/P25ChannelState.java b/src/decode/p25/P25ChannelState.java index 84057a6c..c720ba0c 100644 --- a/src/decode/p25/P25ChannelState.java +++ b/src/decode/p25/P25ChannelState.java @@ -20,6 +20,7 @@ package decode.p25; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -104,7 +105,8 @@ public class P25ChannelState extends ChannelState private String mLastRegistrationEventID; private String mLastResponseEventID; - private ArrayList mActiveCalls = new ArrayList(); + private CopyOnWriteArrayList mActiveCalls = + new CopyOnWriteArrayList(); private P25ActivitySummary mActivitySummary; private String mNAC; diff --git a/src/decode/p25/P25Interleave.java b/src/decode/p25/P25Interleave.java index 3e896185..8d70ecd4 100644 --- a/src/decode/p25/P25Interleave.java +++ b/src/decode/p25/P25Interleave.java @@ -8,27 +8,27 @@ import org.slf4j.LoggerFactory; import bits.BitSetBuffer; /** - * Utility class to process interleave of P25 196-bit packet blocks. + * Utility class to process interleave of P25 Voice and Data messages. */ public class P25Interleave { private final static Logger mLog = LoggerFactory.getLogger( P25Interleave.class ); - private static int[] INTERLEAVE = new int[] { 0,1,2,3,52,53,54,55,100,101, - 102,103,148,149,150,151,4,5,6,7,56,57,58,59,104,105,106,107,152,153,154, - 155,8,9,10,11,60,61,62,63,108,109,110,111,156,157,158,159,12,13,14,15, - 64,65,66,67,112,113,114,115,160,161,162,163,16,17,18,19,68,69,70,71,116, - 117,118,119,164,165,166,167,20,21,22,23,72,73,74,75,120,121,122,123,168, - 169,170,171,24,25,26,27,76,77,78,79,124,125,126,127,172,173,174,175,28, - 29,30,31,80,81,82,83,128,129,130,131,176,177,178,179,32,33,34,35,84,85, - 86,87,132,133,134,135,180,181,182,183,36,37,38,39,88,89,90,91,136,137, - 138,139,184,185,186,187,40,41,42,43,92,93,94,95,140,141,142,143,188,189, - 190,191,44,45,46,47,96,97,98,99,144,145,146,147,192,193,194,195,48,49, - 50,51 }; + private static int[] DATA_INTERLEAVE = new int[] { 0,1,2,3,52,53,54,55,100, + 101,102,103,148,149,150,151,4,5,6,7,56,57,58,59,104,105,106,107,152,153, + 154,155,8,9,10,11,60,61,62,63,108,109,110,111,156,157,158,159,12,13,14, + 15,64,65,66,67,112,113,114,115,160,161,162,163,16,17,18,19,68,69,70,71, + 116,117,118,119,164,165,166,167,20,21,22,23,72,73,74,75,120,121,122,123, + 168,169,170,171,24,25,26,27,76,77,78,79,124,125,126,127,172,173,174,175, + 28,29,30,31,80,81,82,83,128,129,130,131,176,177,178,179,32,33,34,35,84, + 85,86,87,132,133,134,135,180,181,182,183,36,37,38,39,88,89,90,91,136, + 137,138,139,184,185,186,187,40,41,42,43,92,93,94,95,140,141,142,143,188, + 189,190,191,44,45,46,47,96,97,98,99,144,145,146,147,192,193,194,195,48, + 49,50,51 }; - private static int[] DEINTERLEAVE = new int[] { 0,1,2,3,16,17,18,19,32,33, - 34,35,48,49,50,51,64,65,66,67,80,81,82,83,96,97,98,99,112,113,114,115, + private static int[] DATA_DEINTERLEAVE = new int[] { 0,1,2,3,16,17,18,19,32, + 33,34,35,48,49,50,51,64,65,66,67,80,81,82,83,96,97,98,99,112,113,114,115, 128,129,130,131,144,145,146,147,160,161,162,163,176,177,178,179,192,193, 194,195,4,5,6,7,20,21,22,23,36,37,38,39,52,53,54,55,68,69,70,71,84,85, 86,87,100,101,102,103,116,117,118,119,132,133,134,135,148,149,150,151, @@ -38,7 +38,24 @@ public class P25Interleave 29,30,31,44,45,46,47,60,61,62,63,76,77,78,79,92,93,94,95,108,109,110, 111,124,125,126,127,140,141,142,143,156,157,158,159,172,173,174,175,188, 189,190,191 }; + + private static int[] VOICE_DEINTERLEAVE = new int[] { 0,24,48,72,96,120,25, + 1,73,49,121,97,2,26,50,74,98,122,27,3,75,51,123,99,4,28,52,76,100,124, + 29,5,77,53,125,101,6,30,54,78,102,126,31,7,79,55,127,103,8,32,56,80,104, + 128,33,9,81,57,129,105,10,34,58,82,106,130,35,11,83,59,131,107,12,36,60, + 84,108,132,37,13,85,61,133,109,14,38,62,86,110,134,39,87,15,63,135,111, + 16,40,64,88,112,136,41,17,89,65,137,113,18,42,66,90,114,138,43,19,91, + 67,139,115,20,44,68,92,116,140,45,21,93,69,141,117,22,46,70,94,119,142, + 47,23,95,71,143,118 }; + private static int[] VOICE_INTERLEAVE = new int[] { 0,7,12,19,24,31,36,43, + 48,55,60,67,72,79,84,91,96,103,108,115,120,127,132,139,1,6,13,18,25,30, + 37,42,49,54,61,66,73,78,85,90,97,102,109,114,121,126,133,138,2,9,14,21, + 26,33,38,45,50,57,62,69,74,81,86,93,98,105,110,117,122,129,134,141,3,8, + 15,20,27,32,39,44,51,56,63,68,75,80,87,92,99,104,111,116,123,128,135, + 140,4,11,16,23,28,35,40,47,52,59,64,71,76,83,88,95,100,107,112,119,124, + 131,143,136,5,10,17,22,29,34,41,46,53,58,65,70,77,82,89,94,101,106,113, + 118,125,130,137,142 }; /** * Deinterleaves the 196-bit block in message, identified by start and end * bit positions. Note: end index (exclusive) should be one more than the @@ -48,7 +65,20 @@ public class P25Interleave * @param start - starting bit index for the block * @param end - ending bit index for the block, plus 1 */ - public static BitSetBuffer deinterleave( BitSetBuffer message, int start, int end ) + public static BitSetBuffer deinterleaveData( BitSetBuffer message, + int start, int end ) + { + return deinterleave( DATA_DEINTERLEAVE, message, start, end ); + } + + public static BitSetBuffer deinterleaveVoice( BitSetBuffer message, + int start, int end ) + { + return deinterleave( VOICE_DEINTERLEAVE, message, start, end ); + } + + public static BitSetBuffer deinterleave( int[] pattern, BitSetBuffer message, + int start, int end ) { BitSet original = message.get( start, end ); @@ -58,10 +88,10 @@ public class P25Interleave /* Iterate only the set bits in the original message and apply * the deinterleave -- we don't have to evaluate the 0 bits */ for (int i = original.nextSetBit( 0 ); - i >= 0 && i < DEINTERLEAVE.length; + i >= 0 && i < pattern.length; i = original.nextSetBit( i + 1 ) ) { - message.set( start + DEINTERLEAVE[ i ] ); + message.set( start + pattern[ i ] ); } return message; @@ -76,7 +106,20 @@ public class P25Interleave * @param start - starting bit index for the block * @param end - ending bit index for the block, plus 1 */ - public static BitSetBuffer interleave( BitSetBuffer message, int start, int end ) + public static BitSetBuffer interleaveData( BitSetBuffer message, + int start, int end ) + { + return interleave( DATA_INTERLEAVE, message, start, end ); + } + + public static BitSetBuffer interleaveVoice( BitSetBuffer message, + int start, int end ) + { + return interleave( VOICE_INTERLEAVE, message, start, end ); + } + + public static BitSetBuffer interleave( int[] pattern, BitSetBuffer message, + int start, int end ) { BitSet original = message.get( start, end ); @@ -86,15 +129,15 @@ public class P25Interleave /* Iterate only the set bits in the original message and apply * the deinterleave -- we don't have to evaluate the 0 bits */ for (int i = original.nextSetBit( 0 ); - i >= 0 && i < INTERLEAVE.length; + i >= 0 && i < pattern.length; i = original.nextSetBit( i + 1 ) ) { - message.set( start + INTERLEAVE[ i ] ); + message.set( start + pattern[ i ] ); } return message; } - + public static void main( String[] args ) { TrellisHalfRate halfrate = new TrellisHalfRate(); @@ -116,7 +159,7 @@ public class P25Interleave mLog.debug( "Interleaved:" + interleaved ); mLog.debug( " Buffer:" + b.toString() ); - P25Interleave.deinterleave( b, start, end ); + P25Interleave.deinterleaveData( b, start, end ); mLog.debug( "Deinterleav:" + b.toString() ); diff --git a/src/decode/p25/P25MessageProcessor.java b/src/decode/p25/P25MessageProcessor.java index fb7eaca6..a41f93b1 100644 --- a/src/decode/p25/P25MessageProcessor.java +++ b/src/decode/p25/P25MessageProcessor.java @@ -11,7 +11,7 @@ import sample.Broadcaster; import sample.Listener; import alias.AliasList; import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; public class P25MessageProcessor implements Listener { @@ -39,9 +39,9 @@ public class P25MessageProcessor implements Listener if( message.isValid() ) { /* Insert band identifier update messages into channel-type messages */ - if( message instanceof IdentifierUpdateReceiver ) + if( message instanceof IdentifierProviderReceiver ) { - IdentifierUpdateReceiver receiver = (IdentifierUpdateReceiver)message; + IdentifierProviderReceiver receiver = (IdentifierProviderReceiver)message; int[] identifiers = receiver.getIdentifiers(); diff --git a/src/decode/p25/message/IdentifierProvider.java b/src/decode/p25/message/IdentifierProvider.java new file mode 100644 index 00000000..f61b15d6 --- /dev/null +++ b/src/decode/p25/message/IdentifierProvider.java @@ -0,0 +1,32 @@ +package decode.p25.message; + +public interface IdentifierProvider +{ + + /** + * (Band) Identifier + */ + public abstract int getIdentifier(); + + /** + * Channel spacing in hertz + */ + public abstract long getChannelSpacing(); + + /** + * Base frequency in hertz + */ + public abstract long getBaseFrequency(); + + + /** + * Channel bandwidth in hertz + */ + public abstract int getBandwidth(); + + /** + * Transmit offset in hertz + */ + public abstract long getTransmitOffset(); + +} \ No newline at end of file diff --git a/src/decode/p25/message/P25Message.java b/src/decode/p25/message/P25Message.java index 50324ccc..b2088ee9 100644 --- a/src/decode/p25/message/P25Message.java +++ b/src/decode/p25/message/P25Message.java @@ -7,9 +7,8 @@ import message.Message; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; import decode.p25.reference.DataUnitID; +import edac.CRC; public class P25Message extends Message { @@ -42,6 +41,16 @@ public class P25Message extends Message mAliasList = aliasList; } + public BitSetBuffer getSourceMessage() + { + return mMessage; + } + + public AliasList getAliasList() + { + return mAliasList; + } + public String getNAC() { return mMessage.getHex( NAC, 3 ); @@ -165,7 +174,7 @@ public class P25Message extends Message * @param channel - channel number * @return - frequency in Hertz */ - protected static long calculateUplink( IdentifierUpdate iden, int channel ) + protected static long calculateUplink( IdentifierProvider iden, int channel ) { long downlink = calculateDownlink( iden, channel ); @@ -185,7 +194,7 @@ public class P25Message extends Message * @param channel - channel number * @return - frequency in Hertz */ - protected static long calculateDownlink( IdentifierUpdate iden, int channel ) + protected static long calculateDownlink( IdentifierProvider iden, int channel ) { if( iden != null ) { diff --git a/src/decode/p25/message/filter/HDUMessageFilter.java b/src/decode/p25/message/filter/HDUMessageFilter.java new file mode 100644 index 00000000..78c5deee --- /dev/null +++ b/src/decode/p25/message/filter/HDUMessageFilter.java @@ -0,0 +1,36 @@ +package decode.p25.message.filter; + +import java.util.Collections; +import java.util.List; + +import message.Message; +import decode.p25.message.hdu.HDUMessage; +import decode.p25.message.tdu.lc.TDULinkControlMessage; +import filter.Filter; +import filter.FilterElement; + +public class HDUMessageFilter extends Filter +{ + public HDUMessageFilter() + { + super( "Header Data Unit" ); + } + + @Override + public boolean passes( Message message ) + { + return mEnabled && canProcess( message ); + } + + @Override + public boolean canProcess( Message message ) + { + return message instanceof HDUMessage; + } + + @Override + public List> getFilterElements() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/decode/p25/message/filter/LDUMessageFilter.java b/src/decode/p25/message/filter/LDUMessageFilter.java new file mode 100644 index 00000000..85a95a1f --- /dev/null +++ b/src/decode/p25/message/filter/LDUMessageFilter.java @@ -0,0 +1,35 @@ +package decode.p25.message.filter; + +import java.util.Collections; +import java.util.List; + +import message.Message; +import decode.p25.message.ldu.LDUMessage; +import filter.Filter; +import filter.FilterElement; + +public class LDUMessageFilter extends Filter +{ + public LDUMessageFilter() + { + super( "Link Data Unit" ); + } + + @Override + public boolean passes( Message message ) + { + return mEnabled && canProcess( message ); + } + + @Override + public boolean canProcess( Message message ) + { + return message instanceof LDUMessage; + } + + @Override + public List> getFilterElements() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/decode/p25/message/filter/P25MessageFilterSet.java b/src/decode/p25/message/filter/P25MessageFilterSet.java index 796e0102..cb93aaba 100644 --- a/src/decode/p25/message/filter/P25MessageFilterSet.java +++ b/src/decode/p25/message/filter/P25MessageFilterSet.java @@ -10,8 +10,11 @@ public class P25MessageFilterSet extends FilterSet { super( "P25 Message Filter" ); + addFilter( new HDUMessageFilter() ); + addFilter( new LDUMessageFilter() ); addFilter( new PDUMessageFilter() ); addFilter( new TDUMessageFilter() ); + addFilter( new TDULCMessageFilter() ); addFilter( new TSBKMessageFilterSet() ); } diff --git a/src/decode/p25/message/filter/TDULCMessageFilter.java b/src/decode/p25/message/filter/TDULCMessageFilter.java new file mode 100644 index 00000000..43473a3f --- /dev/null +++ b/src/decode/p25/message/filter/TDULCMessageFilter.java @@ -0,0 +1,36 @@ +package decode.p25.message.filter; + +import java.util.Collections; +import java.util.List; + +import message.Message; +import decode.p25.message.tdu.TDUMessage; +import decode.p25.message.tdu.lc.TDULinkControlMessage; +import filter.Filter; +import filter.FilterElement; + +public class TDULCMessageFilter extends Filter +{ + public TDULCMessageFilter() + { + super( "TDU Terminator Data Unit with Link Control" ); + } + + @Override + public boolean passes( Message message ) + { + return mEnabled && canProcess( message ); + } + + @Override + public boolean canProcess( Message message ) + { + return message instanceof TDULinkControlMessage; + } + + @Override + public List> getFilterElements() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/decode/p25/message/hdu/HDUMessage.java b/src/decode/p25/message/hdu/HDUMessage.java index b2ab952b..e8c249ed 100644 --- a/src/decode/p25/message/hdu/HDUMessage.java +++ b/src/decode/p25/message/hdu/HDUMessage.java @@ -2,12 +2,26 @@ package decode.p25.message.hdu; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; import decode.p25.message.P25Message; import decode.p25.reference.DataUnitID; +import decode.p25.reference.Encryption; +import edac.CRC; public class HDUMessage extends P25Message { + public static final int[] MESSAGE_INDICATOR_A = { 64,65,66,67,68,69,82,83, + 84,85,86,87,100,101,102,103,104,105,118,119,120,121,122,123,136,137,138, + 139,140,141,154,155,156,157,158,159 }; + public static final int[] MESSAGE_INDICATOR_B = { 172,173,174,175,176,177, + 190,191,192,193,194,195,208,209,210,211,212,213,226,227,228,229,230,231, + 244,245,246,247,248,249,262,263,264,265,266,267 }; + public static final int[] VENDOR_ID = { 280,281,282,283,284,285,298,299 }; + public static final int[] ALGORITHM_ID = { 300,301,302,303,316,317,318,319 }; + public static final int[] KEY_ID = { 320,321,334,335,336,337,338,339,352, + 353,354,355,356,357,370,371 }; + public static final int[] TALKGROUP_ID = { 372,373,374,375,388,389,390,391, + 392,393,406,407,408,409,410,411 }; + public HDUMessage( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) { @@ -17,8 +31,16 @@ public class HDUMessage extends P25Message * means it passed the CRC */ mCRC = new CRC[ 2 ]; mCRC[ 0 ] = CRC.PASSED; + + checkCRC(); } + private void checkCRC() + { + /* Do Golay(18,6,8) check here */ + /* Do RS(36,20,17) check here */ + } + @Override public String getMessage() { @@ -28,13 +50,50 @@ public class HDUMessage extends P25Message sb.append( getNAC() ); sb.append( " " ); sb.append( getDUID().getLabel() ); - sb.append( " " ); + + sb.append( " TALKGROUP:" + getTalkgroupID() ); + Encryption encryption = getEncryption(); + + if( encryption != Encryption.UNENCRYPTED ) + { + sb.append( " ENCRYPTION:" ); + sb.append( encryption.name() ); + sb.append( " KEY ID:" + getKeyID() ); + sb.append( " IV:" + getEncryptionInitializationVector() ); + } + + sb.append( " " ); sb.append( mMessage.toString() ); return sb.toString(); } + public String getEncryptionInitializationVector() + { + StringBuilder sb = new StringBuilder(); + + sb.append( mMessage.getHex( MESSAGE_INDICATOR_A, 9 ) ); + sb.append( mMessage.getHex( MESSAGE_INDICATOR_B, 9 ) ); + + return sb.toString(); + } + + public Encryption getEncryption() + { + return Encryption.fromValue( mMessage.getInt( ALGORITHM_ID ) ); + } + + public int getKeyID() + { + return mMessage.getInt( KEY_ID ); + } + + public String getTalkgroupID() + { + return mMessage.getHex( TALKGROUP_ID, 4 ); + } + /* Temporary override */ public boolean isValid() { diff --git a/src/decode/p25/message/ldu/LDU1Message.java b/src/decode/p25/message/ldu/LDU1Message.java index d5c74ec5..b4952ea1 100644 --- a/src/decode/p25/message/ldu/LDU1Message.java +++ b/src/decode/p25/message/ldu/LDU1Message.java @@ -2,25 +2,95 @@ package decode.p25.message.ldu; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import decode.p25.message.P25Message; +import decode.p25.P25Interleave; import decode.p25.reference.DataUnitID; +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Vendor; +import decode.p25.reference.VendorLinkControlOpcode; +import edac.CRC; -public class LDU1Message extends P25Message +public class LDU1Message extends LDUMessage { + public static final int IMBE_1 = 64; + public static final int IMBE_2 = 208; + public static final int IMBE_3 = 392; + public static final int IMBE_4 = 576; + public static final int IMBE_5 = 760; + public static final int IMBE_6 = 944; + public static final int IMBE_7 = 1128; + public static final int IMBE_8 = 1312; + public static final int IMBE_9 = 1488; + + public static final int ENCRYPTION_FLAG = 352; + public static final int IMPLICIT_VENDOR_FLAG = 353; + public static final int[] OPCODE = { 354,355,356,357,362,363 }; + public static final int[] VENDOR = { 364,365,366,367,372,373,374,375 }; + + public static final int[] OCTET_1 = { 364,365,366,367,372,373,374,375 }; + public static final int[] OCTET_2 = { 376,377,382,383,384,385,386,387 }; + public static final int[] OCTET_3 = { 536,537,538,539,540,541,546,547 }; + public static final int[] OCTET_4 = { 548,549,550,551,556,557,558,559 }; + public static final int[] OCTET_5 = { 560,561,566,567,568,569,570,571 }; + public static final int[] OCTET_6 = { 720,721,722,723,724,725,730,731 }; + public static final int[] OCTET_7 = { 732,733,734,735,740,741,742,743 }; + public static final int[] OCTET_8 = { 744,745,750,751,752,753,754,755 }; + public LDU1Message( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) { super( message, duid, aliasList ); + deinterleaveVoiceFrames(); + /* NID CRC is checked in the message framer, thus a constructed message * means it passed the CRC */ mCRC = new CRC[ 2 ]; mCRC[ 0 ] = CRC.PASSED; + + checkCRC(); } + + /** + * Subclass constructor from an existing LDU1Message + */ + protected LDU1Message( LDU1Message message ) + { + super( message.getSourceMessage(), DataUnitID.LDU1, message.getAliasList() ); + + mCRC = message.mCRC; + } + + private void deinterleaveVoiceFrames() + { + P25Interleave.deinterleaveVoice( mMessage, IMBE_1, IMBE_1 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_2, IMBE_2 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_3, IMBE_3 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_4, IMBE_4 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_5, IMBE_5 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_6, IMBE_6 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_7, IMBE_7 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_8, IMBE_8 + 144 ); + P25Interleave.deinterleaveVoice( mMessage, IMBE_9, IMBE_9 + 144 ); + } + + private void checkCRC() + { + + } @Override - public String getMessage() + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + sb.append( " " ); + sb.append( mMessage.toString() ); + + return sb.toString(); + } + + public String getMessageStub() { StringBuilder sb = new StringBuilder(); @@ -30,10 +100,55 @@ public class LDU1Message extends P25Message sb.append( getDUID().getLabel() ); sb.append( " " ); - sb.append( mMessage.toString() ); - + if( isEncrypted() ) + { + sb.append( "ENCRYPTED" ); + } + else + { + if( isImplicitFormat() || getVendor() == Vendor.STANDARD ) + { + sb.append( getOpcode().getLabel() ); + } + else + { + sb.append( "VENDOR:" + getVendor().getLabel() + " " ); + sb.append( getVendorOpcode().getLabel() ); + } + } + return sb.toString(); } + + public boolean isEncrypted() + { + return mMessage.get( ENCRYPTION_FLAG ); + } + + public boolean isImplicitFormat() + { + return mMessage.get( IMPLICIT_VENDOR_FLAG ); + } + + public LinkControlOpcode getOpcode() + { + return LinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + + public VendorLinkControlOpcode getVendorOpcode() + { + return VendorLinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + + public Vendor getVendor() + { + if( isImplicitFormat() ) + { + return Vendor.STANDARD; + } + + return Vendor.fromValue( mMessage.getInt( VENDOR ) ); + } /* Temporary override */ public boolean isValid() diff --git a/src/decode/p25/message/ldu/LDU2Message.java b/src/decode/p25/message/ldu/LDU2Message.java index 40a05f69..d609824d 100644 --- a/src/decode/p25/message/ldu/LDU2Message.java +++ b/src/decode/p25/message/ldu/LDU2Message.java @@ -2,11 +2,11 @@ package decode.p25.message.ldu; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; import decode.p25.message.P25Message; import decode.p25.reference.DataUnitID; +import edac.CRC; -public class LDU2Message extends P25Message +public class LDU2Message extends LDUMessage { public LDU2Message( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) diff --git a/src/decode/p25/message/tdu/TDULCMessage.java b/src/decode/p25/message/ldu/LDUMessage.java similarity index 83% rename from src/decode/p25/message/tdu/TDULCMessage.java rename to src/decode/p25/message/ldu/LDUMessage.java index 0c35ae84..aa0892f8 100644 --- a/src/decode/p25/message/tdu/TDULCMessage.java +++ b/src/decode/p25/message/ldu/LDUMessage.java @@ -1,14 +1,14 @@ -package decode.p25.message.tdu; +package decode.p25.message.ldu; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; import decode.p25.message.P25Message; import decode.p25.reference.DataUnitID; +import edac.CRC; -public class TDULCMessage extends P25Message +public class LDUMessage extends P25Message { - public TDULCMessage( BitSetBuffer message, DataUnitID duid, + public LDUMessage( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) { super( message, duid, aliasList ); diff --git a/src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java b/src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java new file mode 100644 index 00000000..f9dd605e --- /dev/null +++ b/src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java @@ -0,0 +1,127 @@ +package decode.p25.message.ldu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.ldu.LDU1Message; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Service; + +public class AdjacentSiteStatusBroadcast extends LDU1Message + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( AdjacentSiteStatusBroadcast.class ); + + public static final int[] LRA = { 364,365,366,367,372,373,374,375 }; + public static final int[] SYSTEM_ID = { 384,385,386,387,536,537,538,539,540, + 541,546,547 }; + public static final int[] RFSS_ID = { 548,549,550,551,556,557,558,559 }; + public static final int[] SITE_ID = { 560,561,566,567,568,569,570,571 }; + public static final int[] IDENTIFIER = { 720,721,722,723 }; + public static final int[] CHANNEL = { 724,725,730,731,732,733,734,735,740, + 741,742,743 }; + public static final int[] SYSTEM_SERVICE_CLASS = { 744,745,750,751,752,753, + 754,755 }; + + private IdentifierProvider mIdentifierUpdate; + + public AdjacentSiteStatusBroadcast( LDU1Message message ) + { + super( message ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.ADJACENT_SITE_STATUS_BROADCAST.getDescription(); + } + + @Override + 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( " CHAN:" + getChannel() ); + + sb.append( " " + Service.getServices( getSystemServiceClass() ).toString() ); + + return sb.toString(); + } + + public String getLocationRegistrationArea() + { + return mMessage.getHex( LRA, 2 ); + } + + 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 getIdentifier() + { + return mMessage.getInt( IDENTIFIER ); + } + + public String getChannel() + { + return getIdentifier() + "-" + getChannelNumber(); + } + + public int getChannelNumber() + { + return mMessage.getInt( CHANNEL ); + } + + public int getSystemServiceClass() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + mIdentifierUpdate = message; + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 1 ]; + + identifiers[ 0 ] = getIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mIdentifierUpdate, getChannelNumber() ); + } + + public long getUplinkFrequencyB() + { + return calculateUplink( mIdentifierUpdate, getChannelNumber() ); + } +} diff --git a/src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java b/src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java new file mode 100644 index 00000000..2b5d6628 --- /dev/null +++ b/src/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java @@ -0,0 +1,98 @@ +package decode.p25.message.ldu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.ldu.LDU1Message; +import decode.p25.reference.LinkControlOpcode; + +public class AdjacentSiteStatusBroadcastExplicit extends LDU1Message +{ + private final static Logger mLog = + LoggerFactory.getLogger( AdjacentSiteStatusBroadcastExplicit.class ); + + public static final int[] LRA = { 364,365,366,367,372,373,374,375 }; + public static final int[] TRANSMIT_IDENTIFIER = { 376,377,382,383 }; + public static final int[] TRANSMIT_CHANNEL = { 384,385,386,387,536,537,538, + 539,540,541,546,547 }; + public static final int[] RFSS_ID = { 548,549,550,551,556,557,558,559 }; + public static final int[] SITE_ID = { 560,561,566,567,568,569,570,571 }; + + public static final int[] RECEIVE_IDENTIFIER = { 720,721,722,723 }; + public static final int[] RECEIVE_CHANNEL = { 724,725,730,731,732,733,734, + 735,740,741,742,743 }; + + public AdjacentSiteStatusBroadcastExplicit( LDU1Message message ) + { + super( message ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " LRA:" + getLocationRegistrationArea() ); + + sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + + sb.append( " DNLINK:" + getTransmitChannelNumber() ); + + sb.append( " UPLINK:" + getReceiveChannelNumber() ); + + return sb.toString(); + } + + public String getLocationRegistrationArea() + { + return mMessage.getHex( LRA, 2 ); + } + + 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 String getTransmitChannelNumber() + { + return getTransmitIdentifier() + "-" + getTransmitChannel(); + } + + public int getReceiveIdentifier() + { + return mMessage.getInt( RECEIVE_IDENTIFIER ); + } + + public int getReceiveChannel() + { + return mMessage.getInt( RECEIVE_CHANNEL ); + } + + public String getReceiveChannelNumber() + { + return getReceiveIdentifier() + "-" + getReceiveChannel(); + } +} diff --git a/src/decode/p25/message/ldu/lc/CallAlert.java b/src/decode/p25/message/ldu/lc/CallAlert.java new file mode 100644 index 00000000..b564d230 --- /dev/null +++ b/src/decode/p25/message/ldu/lc/CallAlert.java @@ -0,0 +1,50 @@ +package decode.p25.message.ldu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.ldu.LDU1Message; +import decode.p25.reference.LinkControlOpcode; + +public class CallAlert extends LDU1Message +{ + private final static Logger mLog = + LoggerFactory.getLogger( CallAlert.class ); + public static final int[] TARGET_ADDRESS = { 536,537,538,539,540,541,546, + 547,548,549,550,551,556,557,558,559,560,561,566,567,568,569,570,571 }; + public static final int[] SOURCE_ADDRESS = { 720,721,722,723,724,725,730, + 731,732,733,734,735,740,741,742,743,744,745,750,751,752,753,754,755 }; + + public CallAlert( LDU1Message message ) + { + super( message ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.CALL_ALERT.getDescription(); + } + + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " SRC ADDR: " + getSourceAddress() ); + sb.append( " TGT ADDR: " + getTargetAddress() ); + + return sb.toString(); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/ldu/lc/CallTermination.java b/src/decode/p25/message/ldu/lc/CallTermination.java new file mode 100644 index 00000000..8eaeace1 --- /dev/null +++ b/src/decode/p25/message/ldu/lc/CallTermination.java @@ -0,0 +1,43 @@ +package decode.p25.message.ldu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.ldu.LDU1Message; +import decode.p25.reference.LinkControlOpcode; + +public class CallTermination extends LDU1Message +{ + private final static Logger mLog = LoggerFactory.getLogger( CallTermination.class ); + + public static final int[] SOURCE_ADDRESS = { 720,721,722,723,724,725,730, + 731,732,733,734,735,740,741,742,743,744,745,750,751,752,753,754,755 }; + + public CallTermination( LDU1Message message ) + { + super( message ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.CALL_TERMINATION_OR_CANCELLATION.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " FROM:" + getSourceAddress() ); + + return sb.toString(); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/ldu/lc/ChannelIdentifierUpdate.java b/src/decode/p25/message/ldu/lc/ChannelIdentifierUpdate.java new file mode 100644 index 00000000..457a3dba --- /dev/null +++ b/src/decode/p25/message/ldu/lc/ChannelIdentifierUpdate.java @@ -0,0 +1,89 @@ +package decode.p25.message.ldu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.ldu.LDU1Message; +import decode.p25.reference.LinkControlOpcode; + +public class ChannelIdentifierUpdate extends LDU1Message + implements IdentifierProvider +{ + private final static Logger mLog = + LoggerFactory.getLogger( ChannelIdentifierUpdate.class ); + + public static final int[] IDENTIFIER = { 364,365,366,367 }; + public static final int[] BANDWIDTH = { 372,373,374,375,376,377,382,383,384 }; + public static final int[] TRANSMIT_OFFSET = { 385,386,387,536,537,538,539, + 540,541 }; + public static final int[] CHANNEL_SPACING = { 546,547,548,549,550,551,556, + 557,558,559 }; + public static final int[] BASE_FREQUENCY = { 560,561,566,567,568,569,570, + 571,720,721,722,723,724,725,730,731,732,733,734,735,740,741,742,743,744, + 745,750,751,752,753,754,755 }; + + public ChannelIdentifierUpdate( LDU1Message message ) + { + super( message ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.CHANNEL_IDENTIFIER_UPDATE.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " IDEN:" + getIdentifier() ); + + sb.append( " BASE:" + getBaseFrequency() ); + + sb.append( " BW:" + getBandwidth() ); + + sb.append( " SPACING:" + getChannelSpacing() ); + + sb.append( " OFFSET:" + getTransmitOffset() ); + + return sb.toString(); + } + + @Override + public int getIdentifier() + { + return mMessage.getInt( IDENTIFIER ); + } + + /** + * Channel bandwidth in hertz + */ + @Override + public int getBandwidth() + { + return mMessage.getInt( BANDWIDTH ) * 125; + } + + @Override + public long getChannelSpacing() + { + return mMessage.getLong( CHANNEL_SPACING ) * 125l; + } + + @Override + public long getBaseFrequency() + { + return mMessage.getLong( BASE_FREQUENCY ) * 5l; + } + + @Override + public long getTransmitOffset() + { + return -1 * mMessage.getLong( TRANSMIT_OFFSET ) * 250000l; + } +} diff --git a/src/decode/p25/message/ldu/lc/GroupVoiceChannelUser.java b/src/decode/p25/message/ldu/lc/GroupVoiceChannelUser.java new file mode 100644 index 00000000..bc5578ac --- /dev/null +++ b/src/decode/p25/message/ldu/lc/GroupVoiceChannelUser.java @@ -0,0 +1,87 @@ +package decode.p25.message.ldu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.ldu.LDU1Message; +import decode.p25.reference.LinkControlOpcode; + +public class GroupVoiceChannelUser extends LDU1Message +{ + private final static Logger mLog = + LoggerFactory.getLogger( GroupVoiceChannelUser.class ); + /* Service Options */ + public static final int EMERGENCY_FLAG = 376; + public static final int ENCRYPTED_CHANNEL_FLAG = 377; + public static final int DUPLEX_MODE = 378; + public static final int SESSION_MODE = 379; + public static final int[] GROUP_ADDRESS = { 548,549,550,551,556,557,558,559, + 560,561,566,567,568,569,570,571 }; + public static final int[] SOURCE_ADDRESS = { 720,721,722,723,724,725,730, + 731,732,733,734,735,740,741,742,743,744,745,750,751,752,753,754,755 }; + + public GroupVoiceChannelUser( LDU1Message message ) + { + super( message ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.GROUP_VOICE_CHANNEL_USER.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + if( isEmergency() ) + { + sb.append( " EMERGENCY" ); + } + if( isEncryptedChannel() ) + { + sb.append( " ENCRYPTED CHANNEL" ); + } + + sb.append( " FROM:" + getSourceAddress() ); + + sb.append( " TO:" + getGroupAddress() ); + + return sb.toString(); + } + + public boolean isEmergency() + { + return mMessage.get( EMERGENCY_FLAG ); + } + + public boolean isEncryptedChannel() + { + return mMessage.get( ENCRYPTED_CHANNEL_FLAG ); + } + + public DuplexMode getDuplexMode() + { + return mMessage.get( DUPLEX_MODE ) ? DuplexMode.FULL : DuplexMode.HALF; + } + + public SessionMode getSessionMode() + { + return mMessage.get( SESSION_MODE ) ? + SessionMode.CIRCUIT : SessionMode.PACKET; + } + + public String getGroupAddress() + { + return mMessage.getHex( GROUP_ADDRESS, 4 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/ldu/lc/LDULCMessageFactory.java b/src/decode/p25/message/ldu/lc/LDULCMessageFactory.java new file mode 100644 index 00000000..a9cd802d --- /dev/null +++ b/src/decode/p25/message/ldu/lc/LDULCMessageFactory.java @@ -0,0 +1,52 @@ +package decode.p25.message.ldu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.ldu.LDU1Message; +import decode.p25.reference.Vendor; + + +public class LDULCMessageFactory +{ + private final static Logger mLog = + LoggerFactory.getLogger( LDULCMessageFactory.class ); + + /** + * Constructs a new sub-class of the TDULC message if the opcode is recognized + * or returns the original message. + */ + public static LDU1Message getMessage( LDU1Message message ) + { + if( message.isImplicitFormat() || message.getVendor() == Vendor.STANDARD ) + { + switch( message.getOpcode() ) + { + case ADJACENT_SITE_STATUS_BROADCAST: + return new AdjacentSiteStatusBroadcast( message ); + case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT: + return new AdjacentSiteStatusBroadcastExplicit( message ); + case CALL_ALERT: + return new CallAlert( message ); + case CALL_TERMINATION_OR_CANCELLATION: + return new CallTermination( message ); + case CHANNEL_IDENTIFIER_UPDATE: + return new ChannelIdentifierUpdate( message ); + case GROUP_VOICE_CHANNEL_USER: + return new GroupVoiceChannelUser( message ); + default: + break; + } + } + else + { + switch( message.getVendor() ) + { + default: + break; + } + } + + return message; + } +} diff --git a/src/decode/p25/message/pdu/PDUConfirmedMessage.java b/src/decode/p25/message/pdu/PDUConfirmedMessage.java new file mode 100644 index 00000000..37495028 --- /dev/null +++ b/src/decode/p25/message/pdu/PDUConfirmedMessage.java @@ -0,0 +1,33 @@ +package decode.p25.message.pdu; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import alias.AliasList; +import bits.BitSetBuffer; +import decode.p25.reference.DataUnitID; + +public class PDUConfirmedMessage extends PDUMessage +{ + public final static Logger mLog = + LoggerFactory.getLogger( PDUConfirmedMessage.class ); + + public PDUConfirmedMessage( BitSetBuffer message, DataUnitID duid, + AliasList aliasList ) + { + super( message, duid, aliasList ); + + mLog.debug( toString() ); + } + + /* Override for now */ + public boolean isValid() + { + return true; + } + + public String toString() + { + return super.toString() + " " + mMessage.toString(); + } +} diff --git a/src/decode/p25/message/pdu/PDUMessage.java b/src/decode/p25/message/pdu/PDUMessage.java index 6b34bf2e..97a5cce0 100644 --- a/src/decode/p25/message/pdu/PDUMessage.java +++ b/src/decode/p25/message/pdu/PDUMessage.java @@ -2,13 +2,13 @@ package decode.p25.message.pdu; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; 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; +import edac.CRC; public class PDUMessage extends P25Message { @@ -55,8 +55,6 @@ public class PDUMessage extends P25Message { sb.append( " " ); sb.append( vendor.getLabel() ); - sb.append( " OPCD:" ); - sb.append( mMessage.getHex( OPCODE, 2 ) ); } return sb.toString(); @@ -87,7 +85,7 @@ public class PDUMessage extends P25Message sb.append( " FMT:" ); sb.append( getFormat().getLabel() ); sb.append( " SAP:" ); - sb.append( getServiceAccessPoint().getLabel() ); + sb.append( getServiceAccessPoint().name() ); sb.append( " VEND:" ); sb.append( getVendor().getLabel() ); sb.append( " LLID:" ); @@ -100,7 +98,7 @@ public class PDUMessage extends P25Message public String getConfirmation() { - return mMessage.get( CONFIRMATION_REQUIRED_INDICATOR ) ? "CON" : "UNC"; + return mMessage.get( CONFIRMATION_REQUIRED_INDICATOR ) ? "CONFIRMED" : "UNCONFIRMED"; } public String getDirection() diff --git a/src/decode/p25/message/pdu/UnitToUnitChannelGrantExtended.java b/src/decode/p25/message/pdu/UnitToUnitChannelGrantExtended.java index 0b241b2a..c4d5ff37 100644 --- a/src/decode/p25/message/pdu/UnitToUnitChannelGrantExtended.java +++ b/src/decode/p25/message/pdu/UnitToUnitChannelGrantExtended.java @@ -1,15 +1,15 @@ package decode.p25.message.pdu; -import crc.CRCP25; 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.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public abstract class UnitToUnitChannelGrantExtended extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { /* Service Options */ public static final int EMERGENCY_FLAG = 128; @@ -39,8 +39,8 @@ public abstract class UnitToUnitChannelGrantExtended extends PDUMessage 326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342, 343,344,345,346,347,348,349,350,351 }; - private IdentifierUpdate mTransmitIdentifierUpdate; - private IdentifierUpdate mReceiveIdentifierUpdate; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public UnitToUnitChannelGrantExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -174,7 +174,7 @@ public abstract class UnitToUnitChannelGrantExtended extends PDUMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java b/src/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java index fff8fe6a..3e0bb020 100644 --- a/src/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java +++ b/src/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java @@ -1,17 +1,17 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.message.tsbk.osp.control.SystemService; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class AdjacentStatusBroadcastExtended extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { 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, @@ -31,8 +31,8 @@ public class AdjacentStatusBroadcastExtended extends PDUMessage 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; + private IdentifierProvider mTransmitIdentifierProvider; + private IdentifierProvider mReceiveIdentifierProvider; public AdjacentStatusBroadcastExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -126,25 +126,25 @@ public class AdjacentStatusBroadcastExtended extends PDUMessage public long getDownlinkFrequency() { - return calculateDownlink( mTransmitIdentifierUpdate, getTransmitChannel() ); + return calculateDownlink( mTransmitIdentifierProvider, getTransmitChannel() ); } public long getUplinkFrequency() { - return calculateUplink( mReceiveIdentifierUpdate, getReceiveChannel() ); + return calculateUplink( mReceiveIdentifierProvider, getReceiveChannel() ); } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitIdentifier() ) { - mTransmitIdentifierUpdate = message; + mTransmitIdentifierProvider = message; } if( identifier == getReceiveIdentifier() ) { - mReceiveIdentifierUpdate = message; + mReceiveIdentifierProvider = message; } } diff --git a/src/decode/p25/message/pdu/osp/control/CallAlertExtended.java b/src/decode/p25/message/pdu/osp/control/CallAlertExtended.java index cd3ab369..bf062c03 100644 --- a/src/decode/p25/message/pdu/osp/control/CallAlertExtended.java +++ b/src/decode/p25/message/pdu/osp/control/CallAlertExtended.java @@ -1,11 +1,11 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class CallAlertExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/GroupAffiliationQueryExtended.java b/src/decode/p25/message/pdu/osp/control/GroupAffiliationQueryExtended.java index 92fc465a..cfaea4ae 100644 --- a/src/decode/p25/message/pdu/osp/control/GroupAffiliationQueryExtended.java +++ b/src/decode/p25/message/pdu/osp/control/GroupAffiliationQueryExtended.java @@ -1,11 +1,11 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class GroupAffiliationQueryExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/GroupAffiliationResponseExtended.java b/src/decode/p25/message/pdu/osp/control/GroupAffiliationResponseExtended.java index 36a5e425..2ccd57fd 100644 --- a/src/decode/p25/message/pdu/osp/control/GroupAffiliationResponseExtended.java +++ b/src/decode/p25/message/pdu/osp/control/GroupAffiliationResponseExtended.java @@ -1,12 +1,12 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; import decode.p25.reference.Response; +import edac.CRCP25; public class GroupAffiliationResponseExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/MessageUpdateExtended.java b/src/decode/p25/message/pdu/osp/control/MessageUpdateExtended.java index feb1467a..43bf8a64 100644 --- a/src/decode/p25/message/pdu/osp/control/MessageUpdateExtended.java +++ b/src/decode/p25/message/pdu/osp/control/MessageUpdateExtended.java @@ -1,11 +1,11 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class MessageUpdateExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/NetworkStatusBroadcastExtended.java b/src/decode/p25/message/pdu/osp/control/NetworkStatusBroadcastExtended.java index ea23fe51..4e4c7b6c 100644 --- a/src/decode/p25/message/pdu/osp/control/NetworkStatusBroadcastExtended.java +++ b/src/decode/p25/message/pdu/osp/control/NetworkStatusBroadcastExtended.java @@ -1,18 +1,18 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.message.tsbk.osp.control.SystemService; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; import decode.p25.reference.P25NetworkCallsign; +import edac.CRCP25; public class NetworkStatusBroadcastExtended extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { 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, @@ -31,8 +31,8 @@ public class NetworkStatusBroadcastExtended extends PDUMessage 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; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public NetworkStatusBroadcastExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -134,7 +134,7 @@ public class NetworkStatusBroadcastExtended extends PDUMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitIdentifier() ) { diff --git a/src/decode/p25/message/pdu/osp/control/ProtectionParameterBroadcast.java b/src/decode/p25/message/pdu/osp/control/ProtectionParameterBroadcast.java index 2d951462..c2c921c2 100644 --- a/src/decode/p25/message/pdu/osp/control/ProtectionParameterBroadcast.java +++ b/src/decode/p25/message/pdu/osp/control/ProtectionParameterBroadcast.java @@ -1,12 +1,12 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Encryption; import decode.p25.reference.Opcode; +import edac.CRCP25; public class ProtectionParameterBroadcast extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/RFSSStatusBroadcastExtended.java b/src/decode/p25/message/pdu/osp/control/RFSSStatusBroadcastExtended.java index 1f2ffd71..5793e043 100644 --- a/src/decode/p25/message/pdu/osp/control/RFSSStatusBroadcastExtended.java +++ b/src/decode/p25/message/pdu/osp/control/RFSSStatusBroadcastExtended.java @@ -1,17 +1,17 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.message.tsbk.osp.control.SystemService; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class RFSSStatusBroadcastExtended extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { public static final int[] LRA = { 88,89,90,91,92,93,94,95 }; public static final int ACTIVE_NETWORK_CONNECTION_INDICATOR = 99; @@ -31,8 +31,8 @@ public class RFSSStatusBroadcastExtended extends PDUMessage 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; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public RFSSStatusBroadcastExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -138,7 +138,7 @@ public class RFSSStatusBroadcastExtended extends PDUMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitIdentifier() ) { diff --git a/src/decode/p25/message/pdu/osp/control/RoamingAddressUpdateExtended.java b/src/decode/p25/message/pdu/osp/control/RoamingAddressUpdateExtended.java index 413efde9..bf366a93 100644 --- a/src/decode/p25/message/pdu/osp/control/RoamingAddressUpdateExtended.java +++ b/src/decode/p25/message/pdu/osp/control/RoamingAddressUpdateExtended.java @@ -1,12 +1,12 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; import dsp.fsk.P25MessageFramer; +import edac.CRCP25; public class RoamingAddressUpdateExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/StatusQueryExtended.java b/src/decode/p25/message/pdu/osp/control/StatusQueryExtended.java index 6f03664d..4828a994 100644 --- a/src/decode/p25/message/pdu/osp/control/StatusQueryExtended.java +++ b/src/decode/p25/message/pdu/osp/control/StatusQueryExtended.java @@ -1,11 +1,11 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class StatusQueryExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/StatusUpdateExtended.java b/src/decode/p25/message/pdu/osp/control/StatusUpdateExtended.java index 61869731..0e5b0b20 100644 --- a/src/decode/p25/message/pdu/osp/control/StatusUpdateExtended.java +++ b/src/decode/p25/message/pdu/osp/control/StatusUpdateExtended.java @@ -1,11 +1,11 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class StatusUpdateExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/control/UnitRegistrationResponseExtended.java b/src/decode/p25/message/pdu/osp/control/UnitRegistrationResponseExtended.java index f796a282..58fc3f56 100644 --- a/src/decode/p25/message/pdu/osp/control/UnitRegistrationResponseExtended.java +++ b/src/decode/p25/message/pdu/osp/control/UnitRegistrationResponseExtended.java @@ -1,12 +1,12 @@ package decode.p25.message.pdu.osp.control; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; import decode.p25.reference.Response; +import edac.CRCP25; public class UnitRegistrationResponseExtended extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/data/GroupDataChannelGrantExtended.java b/src/decode/p25/message/pdu/osp/data/GroupDataChannelGrantExtended.java index 54e7cde7..11816a1e 100644 --- a/src/decode/p25/message/pdu/osp/data/GroupDataChannelGrantExtended.java +++ b/src/decode/p25/message/pdu/osp/data/GroupDataChannelGrantExtended.java @@ -2,17 +2,17 @@ package decode.p25.message.pdu.osp.data; import java.util.Date; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class GroupDataChannelGrantExtended extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { /* Service Options */ public static final int EMERGENCY_FLAG = 128; @@ -36,8 +36,8 @@ public class GroupDataChannelGrantExtended extends PDUMessage 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; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public GroupDataChannelGrantExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -153,7 +153,7 @@ public class GroupDataChannelGrantExtended extends PDUMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/message/pdu/osp/data/IndividualDataChannelGrantExtended.java b/src/decode/p25/message/pdu/osp/data/IndividualDataChannelGrantExtended.java index 31e2d366..7c757264 100644 --- a/src/decode/p25/message/pdu/osp/data/IndividualDataChannelGrantExtended.java +++ b/src/decode/p25/message/pdu/osp/data/IndividualDataChannelGrantExtended.java @@ -3,13 +3,13 @@ package decode.p25.message.pdu.osp.data; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.UnitToUnitChannelGrantExtended; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; public class IndividualDataChannelGrantExtended extends UnitToUnitChannelGrantExtended - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { public IndividualDataChannelGrantExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) diff --git a/src/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java b/src/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java index f7ae8c92..1e4454f5 100644 --- a/src/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java +++ b/src/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java @@ -1,16 +1,16 @@ package decode.p25.message.pdu.osp.voice; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class GroupVoiceChannelGrantExplicit extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { /* Service Options */ public static final int EMERGENCY_FLAG = 128; @@ -34,8 +34,8 @@ public class GroupVoiceChannelGrantExplicit extends PDUMessage 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; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public GroupVoiceChannelGrantExplicit( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -151,7 +151,7 @@ public class GroupVoiceChannelGrantExplicit extends PDUMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/message/pdu/osp/voice/TelephoneInterconnectChannelGrantExplicit.java b/src/decode/p25/message/pdu/osp/voice/TelephoneInterconnectChannelGrantExplicit.java index abbeb96c..08d46678 100644 --- a/src/decode/p25/message/pdu/osp/voice/TelephoneInterconnectChannelGrantExplicit.java +++ b/src/decode/p25/message/pdu/osp/voice/TelephoneInterconnectChannelGrantExplicit.java @@ -2,17 +2,17 @@ package decode.p25.message.pdu.osp.voice; import java.util.Date; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class TelephoneInterconnectChannelGrantExplicit extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { /* Service Options */ public static final int EMERGENCY_FLAG = 128; @@ -36,8 +36,8 @@ public class TelephoneInterconnectChannelGrantExplicit extends PDUMessage 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; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public TelephoneInterconnectChannelGrantExplicit( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -158,7 +158,7 @@ public class TelephoneInterconnectChannelGrantExplicit extends PDUMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/message/pdu/osp/voice/UnitToUnitAnswerRequestExplicit.java b/src/decode/p25/message/pdu/osp/voice/UnitToUnitAnswerRequestExplicit.java index d7706ff8..108b5341 100644 --- a/src/decode/p25/message/pdu/osp/voice/UnitToUnitAnswerRequestExplicit.java +++ b/src/decode/p25/message/pdu/osp/voice/UnitToUnitAnswerRequestExplicit.java @@ -1,11 +1,11 @@ package decode.p25.message.pdu.osp.voice; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.PDUMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class UnitToUnitAnswerRequestExplicit extends PDUMessage { diff --git a/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantExtended.java b/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantExtended.java index 80e785bd..2c615109 100644 --- a/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantExtended.java +++ b/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantExtended.java @@ -3,13 +3,13 @@ package decode.p25.message.pdu.osp.voice; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.pdu.UnitToUnitChannelGrantExtended; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; public class UnitToUnitVoiceChannelGrantExtended extends UnitToUnitChannelGrantExtended - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { public UnitToUnitVoiceChannelGrantExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) diff --git a/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantUpdateExtended.java b/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantUpdateExtended.java index 1460a96d..65d6de8a 100644 --- a/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantUpdateExtended.java +++ b/src/decode/p25/message/pdu/osp/voice/UnitToUnitVoiceChannelGrantUpdateExtended.java @@ -1,16 +1,16 @@ package decode.p25.message.pdu.osp.voice; -import crc.CRCP25; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.pdu.PDUMessage; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; -import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; +import edac.CRCP25; public class UnitToUnitVoiceChannelGrantUpdateExtended extends PDUMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { /* Service Options */ public static final int EMERGENCY_FLAG = 128; @@ -40,8 +40,8 @@ public class UnitToUnitVoiceChannelGrantUpdateExtended extends PDUMessage 326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342, 343,344,345,346,347,348,349,350,351 }; - private IdentifierUpdate mTransmitIdentifierUpdate; - private IdentifierUpdate mReceiveIdentifierUpdate; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public UnitToUnitVoiceChannelGrantUpdateExtended( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -181,7 +181,7 @@ public class UnitToUnitVoiceChannelGrantUpdateExtended extends PDUMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/message/tdu/TDULinkControlMessage.java b/src/decode/p25/message/tdu/TDULinkControlMessage.java new file mode 100644 index 00000000..cb6d7c36 --- /dev/null +++ b/src/decode/p25/message/tdu/TDULinkControlMessage.java @@ -0,0 +1,265 @@ +package decode.p25.message.tdu; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import alias.AliasList; +import bits.BitSetBuffer; +import decode.p25.message.P25Message; +import decode.p25.reference.DataUnitID; +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Vendor; +import decode.p25.reference.VendorLinkControlOpcode; +import edac.CRC; +import edac.Galois24; +import edac.ReedSolomon_24_12_13; + +public class TDULinkControlMessage extends P25Message +{ + public final static Logger mLog = LoggerFactory.getLogger( TDULinkControlMessage.class ); + + public static final int[] LC_HEX_0 = { 64,65,66,67,68,69 }; + public static final int[] LC_HEX_1 = { 70,71,72,73,74,75 }; + public static final int[] LC_HEX_2 = { 88,89,90,91,92,93 }; + public static final int[] LC_HEX_3 = { 94,95,96,97,98,99 }; + public static final int[] LC_HEX_4 = { 112,113,114,115,116,117 }; + public static final int[] LC_HEX_5 = { 118,119,120,121,122,123 }; + public static final int[] LC_HEX_6 = { 136,137,138,139,140,141 }; + public static final int[] LC_HEX_7 = { 142,143,144,145,146,147 }; + public static final int[] LC_HEX_8 = { 160,161,162,163,164,165 }; + public static final int[] LC_HEX_9 = { 166,167,168,169,170,171 }; + public static final int[] LC_HEX_10 = { 184,185,186,187,188,189 }; + public static final int[] LC_HEX_11 = { 190,191,192,193,194,195 }; + public static final int[] RS_HEX_0 = { 208,209,210,211,212,213 }; + public static final int[] RS_HEX_1 = { 214,215,216,217,218,219 }; + public static final int[] RS_HEX_2 = { 232,233,234,235,236,237 }; + public static final int[] RS_HEX_3 = { 238,239,240,241,242,243 }; + public static final int[] RS_HEX_4 = { 256,257,258,259,260,261 }; + public static final int[] RS_HEX_5 = { 262,263,264,265,266,267 }; + public static final int[] RS_HEX_6 = { 280,281,282,283,284,285 }; + public static final int[] RS_HEX_7 = { 286,287,288,289,290,291 }; + public static final int[] RS_HEX_8 = { 304,305,306,307,308,309 }; + public static final int[] RS_HEX_9 = { 310,311,312,313,314,315 }; + public static final int[] RS_HEX_10 = { 328,329,330,331,332,333 }; + public static final int[] RS_HEX_11 = { 334,335,336,337,338,339 }; + + public static final int ENCRYPTION_FLAG = 64; + public static final int IMPLICIT_VENDOR_FLAG = 65; + public static final int[] OPCODE = { 66,67,68,69,70,71 }; + public static final int[] VENDOR = { 72,73,74,75,88,89,90,91 }; + + public static final ReedSolomon_24_12_13 mReedSolomonDecoder = + new ReedSolomon_24_12_13(); + + public TDULinkControlMessage( BitSetBuffer message, DataUnitID duid, + AliasList aliasList ) + { + super( message, duid, aliasList ); + + /* NID CRC is checked in the message framer so a constructed message + * means it passed the CRC */ + mCRC = new CRC[ 3 ]; + mCRC[ 0 ] = CRC.PASSED; + + checkCRC(); + } + + /** + * Constructs a TDULinkControl message from an existing message and bypasses + * the CRC calculation. + */ + protected TDULinkControlMessage( TDULinkControlMessage message ) + { + super( message.getSourceMessage(), DataUnitID.TDULC, message.getAliasList() ); + + mCRC = message.getCRC(); + } + + public CRC[] getCRC() + { + return mCRC; + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + sb.append( " " ); + sb.append( mMessage.toString() ); + + return sb.toString(); + } + + public String getMessageStub() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " " ); + sb.append( getDUID().getLabel() ); + sb.append( " " ); + + if( isEncrypted() ) + { + sb.append( "ENCRYPTED" ); + } + else + { + if( isImplicitFormat() || getVendor() == Vendor.STANDARD ) + { + sb.append( getOpcode().getLabel() ); + } + else + { + sb.append( "VENDOR:" + getVendor().getLabel() + " " ); + sb.append( getVendorOpcode().getLabel() ); + } + } + + return sb.toString(); + } + + public boolean isEncrypted() + { + return mMessage.get( ENCRYPTION_FLAG ); + } + + public boolean isImplicitFormat() + { + return mMessage.get( IMPLICIT_VENDOR_FLAG ); + } + + public LinkControlOpcode getOpcode() + { + return LinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + + public VendorLinkControlOpcode getVendorOpcode() + { + return VendorLinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + + public Vendor getVendor() + { + if( isImplicitFormat() ) + { + return Vendor.STANDARD; + } + + return Vendor.fromValue( mMessage.getInt( VENDOR ) ); + } + + + /** + * Checks and repairs the 12 x 24-bit golay(24,12,8) codewords and then + * checks and repairs the 24 x 6-bit link control and reed-solomon + * RS(24,12,13) parity codewords + */ + private void checkCRC() + { + /* Check the Golay codewords */ + int x = 64; + + mCRC[ 1 ] = CRC.PASSED; + + while( x < mMessage.size() ) + { + boolean passes = Galois24.checkAndCorrect( mMessage, x ); + + if( !passes ) + { + mCRC[ 1 ] = CRC.FAILED_CRC; + } + + x += 24; + } + + /* Check the Reed-Solomon parity bits. The RS decoder expects the link + * control data and reed solomon parity hex codewords in reverse order. + * The RS(24,12,13) code used by P25 removes the left-hand 47 data hex + * words, so we replace them with zeros. */ + int[] input = new int [63]; + int[] output = new int [63]; + + input[ 0 ] = mMessage.getInt( RS_HEX_11 ); + input[ 1 ] = mMessage.getInt( RS_HEX_10 ); + input[ 2 ] = mMessage.getInt( RS_HEX_9 ); + input[ 3 ] = mMessage.getInt( RS_HEX_8 ); + input[ 4 ] = mMessage.getInt( RS_HEX_7 ); + input[ 5 ] = mMessage.getInt( RS_HEX_6 ); + input[ 6 ] = mMessage.getInt( RS_HEX_5 ); + input[ 7 ] = mMessage.getInt( RS_HEX_4 ); + input[ 8 ] = mMessage.getInt( RS_HEX_3 ); + input[ 9 ] = mMessage.getInt( RS_HEX_2 ); + input[ 10 ] = mMessage.getInt( RS_HEX_1 ); + input[ 11 ] = mMessage.getInt( RS_HEX_0 ); + input[ 12 ] = mMessage.getInt( LC_HEX_11 ); + input[ 13 ] = mMessage.getInt( LC_HEX_10 ); + input[ 14 ] = mMessage.getInt( LC_HEX_9 ); + input[ 15 ] = mMessage.getInt( LC_HEX_8 ); + input[ 16 ] = mMessage.getInt( LC_HEX_7 ); + input[ 17 ] = mMessage.getInt( LC_HEX_6 ); + input[ 18 ] = mMessage.getInt( LC_HEX_5 ); + input[ 19 ] = mMessage.getInt( LC_HEX_4 ); + input[ 20 ] = mMessage.getInt( LC_HEX_3 ); + input[ 21 ] = mMessage.getInt( LC_HEX_2 ); + input[ 22 ] = mMessage.getInt( LC_HEX_1 ); + input[ 23 ] = mMessage.getInt( LC_HEX_0 ); + /* indexes 24 - 62 are defaulted to zero */ + + boolean irrecoverableErrors = mReedSolomonDecoder.decode( input, output ); + + if( irrecoverableErrors ) + { + mCRC[ 2 ] = CRC.FAILED_CRC; + } + else + { + mCRC[ 2 ] = CRC.PASSED; + + /* Only fix the link control data hex codewords */ + repairHexCodeword( input, output, 12, LC_HEX_11 ); + repairHexCodeword( input, output, 13, LC_HEX_10 ); + repairHexCodeword( input, output, 14, LC_HEX_9 ); + repairHexCodeword( input, output, 15, LC_HEX_8 ); + repairHexCodeword( input, output, 16, LC_HEX_7 ); + repairHexCodeword( input, output, 17, LC_HEX_6 ); + repairHexCodeword( input, output, 18, LC_HEX_5 ); + repairHexCodeword( input, output, 19, LC_HEX_4 ); + repairHexCodeword( input, output, 20, LC_HEX_3 ); + repairHexCodeword( input, output, 21, LC_HEX_2 ); + repairHexCodeword( input, output, 22, LC_HEX_1 ); + repairHexCodeword( input, output, 23, LC_HEX_0 ); + + /* If the golay check failed, mark it as corrected too */ + if( mCRC[ 1 ] == CRC.FAILED_CRC ) + { + mCRC[ 1 ] = CRC.CORRECTED; + } + } + } + + private void repairHexCodeword( int[] input, int[] output, int index, int[] indexSet ) + { + if( input[ index ] != output[ index ] ) + { + mMessage.load( indexSet[ 0 ], 6, output[ index ] ); + mCRC[ 2 ] = CRC.CORRECTED; + } + } + + /** + * Indicates if the message passed the golay and reed-solomon parity checks + * or was corrected. + */ + public boolean isValid() + { + // mCRC[ 0 ] - always passes (otherwise message wouldn't be constructed ) + // mCRC[ 1 ] - golay - always passes or corrected if mCRC[2] is valid + + return mCRC[ 2 ] == CRC.PASSED || mCRC[ 2 ] == CRC.CORRECTED; + } +} diff --git a/src/decode/p25/message/tdu/TDUMessage.java b/src/decode/p25/message/tdu/TDUMessage.java index addd3c17..0c31c8d2 100644 --- a/src/decode/p25/message/tdu/TDUMessage.java +++ b/src/decode/p25/message/tdu/TDUMessage.java @@ -2,9 +2,9 @@ package decode.p25.message.tdu; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; import decode.p25.message.P25Message; import decode.p25.reference.DataUnitID; +import edac.CRC; public class TDUMessage extends P25Message { diff --git a/src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java b/src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java new file mode 100644 index 00000000..b0bac516 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java @@ -0,0 +1,127 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.message.tsbk.osp.control.SystemService; +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Service; + +public class AdjacentSiteStatusBroadcast extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( AdjacentSiteStatusBroadcast.class ); + + public static final int[] LRA = { 72,73,74,75,88,89,90,91 }; + public static final int[] SYSTEM_ID = { 96,97,98,99,112,113,114,115, + 116,117,118,119 }; + public static final int[] RFSS_ID = { 120,121,122,123,136,137,138,139 }; + public static final int[] SITE_ID = { 140,141,142,143,144,145,146,147 }; + public static final int[] IDENTIFIER = { 160,161,162,163 }; + public static final int[] CHANNEL = { 164,165,166,167,168,169,170, + 171,184,185,186,187 }; + public static final int[] SYSTEM_SERVICE_CLASS = { 188,189,190,191,192,193, + 194,195 }; + + private IdentifierProvider mIdentifierUpdate; + + public AdjacentSiteStatusBroadcast( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.ADJACENT_SITE_STATUS_BROADCAST.getDescription(); + } + + @Override + 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( " CHAN:" + getChannel() ); + + sb.append( " " + Service.getServices( getSystemServiceClass() ).toString() ); + + return sb.toString(); + } + + public String getLocationRegistrationArea() + { + return mMessage.getHex( LRA, 2 ); + } + + 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 getIdentifier() + { + return mMessage.getInt( IDENTIFIER ); + } + + public String getChannel() + { + return getIdentifier() + "-" + getChannelNumber(); + } + + public int getChannelNumber() + { + return mMessage.getInt( CHANNEL ); + } + + public int getSystemServiceClass() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + mIdentifierUpdate = message; + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 1 ]; + + identifiers[ 0 ] = getIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mIdentifierUpdate, getChannelNumber() ); + } + + public long getUplinkFrequencyB() + { + return calculateUplink( mIdentifierUpdate, getChannelNumber() ); + } +} diff --git a/src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java b/src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java new file mode 100644 index 00000000..7e3ff089 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java @@ -0,0 +1,98 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.tsbk.osp.control.SystemService; +import decode.p25.reference.LinkControlOpcode; + +public class AdjacentSiteStatusBroadcastExplicit extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( AdjacentSiteStatusBroadcastExplicit.class ); + + public static final int[] LRA = { 72,73,74,75,88,89,90,91 }; + public static final int[] TRANSMIT_IDENTIFIER = { 92,93,94,95 }; + public static final int[] TRANSMIT_CHANNEL = { 96,97,98,99,112,113,114,115, + 116,117,118,119 }; + public static final int[] RFSS_ID = { 120,121,122,123,136,137,138,139 }; + public static final int[] SITE_ID = { 140,141,142,143,144,145,146,147 }; + + public static final int[] RECEIVE_IDENTIFIER = { 160,161,162,163 }; + public static final int[] RECEIVE_CHANNEL = { 164,165,166,167,168,169,170, + 171,184,185,186,187 }; + + public AdjacentSiteStatusBroadcastExplicit( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " LRA:" + getLocationRegistrationArea() ); + + sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + + sb.append( " DNLINK:" + getTransmitChannelNumber() ); + + sb.append( " UPLINK:" + getReceiveChannelNumber() ); + + return sb.toString(); + } + + public String getLocationRegistrationArea() + { + return mMessage.getHex( LRA, 2 ); + } + + 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 String getTransmitChannelNumber() + { + return getTransmitIdentifier() + "-" + getTransmitChannel(); + } + + public int getReceiveIdentifier() + { + return mMessage.getInt( RECEIVE_IDENTIFIER ); + } + + public int getReceiveChannel() + { + return mMessage.getInt( RECEIVE_CHANNEL ); + } + + public String getReceiveChannelNumber() + { + return getReceiveIdentifier() + "-" + getReceiveChannel(); + } +} diff --git a/src/decode/p25/message/tdu/lc/CallAlert.java b/src/decode/p25/message/tdu/lc/CallAlert.java new file mode 100644 index 00000000..4980933b --- /dev/null +++ b/src/decode/p25/message/tdu/lc/CallAlert.java @@ -0,0 +1,49 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class CallAlert extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( CallAlert.class ); + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,190,192,193,194,195 }; + + public CallAlert( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.CALL_ALERT.getDescription(); + } + + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " SRC ADDR: " + getSourceAddress() ); + sb.append( " TGT ADDR: " + getTargetAddress() ); + + return sb.toString(); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/CallTermination.java b/src/decode/p25/message/tdu/lc/CallTermination.java new file mode 100644 index 00000000..f1218c95 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/CallTermination.java @@ -0,0 +1,42 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class CallTermination extends TDULinkControlMessage +{ + private final static Logger mLog = LoggerFactory.getLogger( CallTermination.class ); + + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public CallTermination( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.CALL_TERMINATION_OR_CANCELLATION.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " FROM:" + getSourceAddress() ); + + return sb.toString(); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/ChannelIdentifierUpdate.java b/src/decode/p25/message/tdu/lc/ChannelIdentifierUpdate.java new file mode 100644 index 00000000..a17627a7 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/ChannelIdentifierUpdate.java @@ -0,0 +1,88 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.reference.LinkControlOpcode; + +public class ChannelIdentifierUpdate extends TDULinkControlMessage + implements IdentifierProvider +{ + private final static Logger mLog = + LoggerFactory.getLogger( ChannelIdentifierUpdate.class ); + + public static final int[] IDENTIFIER = { 72,73,74,75 }; + public static final int[] BANDWIDTH = { 88,89,90,91,92,93,94,95,96 }; + public static final int[] TRANSMIT_OFFSET = { 97,98,99,112,113,114,115,116, + 117 }; + public static final int[] CHANNEL_SPACING = { 118,119,120,121,122,123,136, + 137,138,139 }; + public static final int[] BASE_FREQUENCY = { 140,141,142,143,144,145,146, + 147,160,161,162,163,164,165,166,167,168,169,170,171,184,185,186, + 187,188,189,190,191,192,193,194,195 }; + + public ChannelIdentifierUpdate( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.CHANNEL_IDENTIFIER_UPDATE.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " IDEN:" + getIdentifier() ); + + sb.append( " BASE:" + getBaseFrequency() ); + + sb.append( " BW:" + getBandwidth() ); + + sb.append( " SPACING:" + getChannelSpacing() ); + + sb.append( " OFFSET:" + getTransmitOffset() ); + + return sb.toString(); + } + + @Override + public int getIdentifier() + { + return mMessage.getInt( IDENTIFIER ); + } + + /** + * Channel bandwidth in hertz + */ + @Override + public int getBandwidth() + { + return mMessage.getInt( BANDWIDTH ) * 125; + } + + @Override + public long getChannelSpacing() + { + return mMessage.getLong( CHANNEL_SPACING ) * 125l; + } + + @Override + public long getBaseFrequency() + { + return mMessage.getLong( BASE_FREQUENCY ) * 5l; + } + + @Override + public long getTransmitOffset() + { + return -1 * mMessage.getLong( TRANSMIT_OFFSET ) * 250000l; + } +} diff --git a/src/decode/p25/message/tdu/lc/ChannelIdentifierUpdateExplicit.java b/src/decode/p25/message/tdu/lc/ChannelIdentifierUpdateExplicit.java new file mode 100644 index 00000000..4d001db3 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/ChannelIdentifierUpdateExplicit.java @@ -0,0 +1,88 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.reference.LinkControlOpcode; + +public class ChannelIdentifierUpdateExplicit extends TDULinkControlMessage + implements IdentifierProvider +{ + private final static Logger mLog = + LoggerFactory.getLogger( ChannelIdentifierUpdateExplicit.class ); + + public static final int[] IDENTIFIER = { 72,73,74,75 }; + public static final int[] BANDWIDTH = { 88,89,90,91 }; + public static final int[] TRANSMIT_OFFSET = { 92,93,94,95,96,97,98,99,112, + 113,114,115,116,117 }; + public static final int[] CHANNEL_SPACING = { 118,119,120,121,122, + 123,136,137,138,139 }; + public static final int[] BASE_FREQUENCY = { 140,141,142,143,144,145,146, + 147,160,161,162,163,164,165,166,167,168,169,170,171,184,185,186, + 187,188,189,190,191,192,193,194,195 }; + + public ChannelIdentifierUpdateExplicit( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.CHANNEL_IDENTIFIER_UPDATE_EXPLICIT.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " IDEN:" + getIdentifier() ); + + sb.append( " BASE:" + getBaseFrequency() ); + + sb.append( " BW:" + getBandwidth() ); + + sb.append( " SPACING:" + getChannelSpacing() ); + + sb.append( " OFFSET:" + getTransmitOffset() ); + + return sb.toString(); + } + + @Override + public int getIdentifier() + { + return mMessage.getInt( IDENTIFIER ); + } + + /** + * Channel bandwidth in hertz + */ + @Override + public int getBandwidth() + { + return mMessage.getInt( BANDWIDTH ) * 125; + } + + @Override + public long getChannelSpacing() + { + return mMessage.getLong( CHANNEL_SPACING ) * 125l; + } + + @Override + public long getBaseFrequency() + { + return mMessage.getLong( BASE_FREQUENCY ) * 5l; + } + + @Override + public long getTransmitOffset() + { + return -1 * mMessage.getLong( TRANSMIT_OFFSET ) * 250000l; + } +} diff --git a/src/decode/p25/message/tdu/lc/ExtendedFunctionCommand.java b/src/decode/p25/message/tdu/lc/ExtendedFunctionCommand.java new file mode 100644 index 00000000..7e9e6061 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/ExtendedFunctionCommand.java @@ -0,0 +1,86 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.ExtendedFunction; +import decode.p25.reference.LinkControlOpcode; + +public class ExtendedFunctionCommand extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( ExtendedFunctionCommand.class ); + public static final int[] EXTENDED_FUNCTION = { 72,73,74,75,88,89,90,91,92, + 93,94,95,96,97,98,99 }; + public static final int[] ARGUMENT = { 112,113,114,115,116,117,118,119,120, + 121,122,123,136,137,138,139,140,141,142,143,144,145,145,147 }; + public static final int[] TARGET_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,190,192,193,194,195 }; + + public ExtendedFunctionCommand( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.EXTENDED_FUNCTION_COMMAND.getDescription(); + } + + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " EXTENDED FUNCTION:" + getExtendedFunction().getLabel() ); + + sb.append( " ARGUMENT: " + getTargetAddress() ); + + sb.append( " TGT ADDR: " + getTargetAddress() ); + + return sb.toString(); + } + + public ExtendedFunction getExtendedFunction() + { + return ExtendedFunction.fromValue( mMessage.getInt( EXTENDED_FUNCTION ) ); + } + + public String getArgument() + { + return mMessage.getHex( ARGUMENT, 6 ); + } + + public String getSourceAddress() + { + switch( getExtendedFunction() ) + { + case RADIO_CHECK: + case RADIO_CHECK_ACK: + case RADIO_DETACH: + case RADIO_DETACH_ACK: + case RADIO_INHIBIT: + case RADIO_INHIBIT_ACK: + case RADIO_UNINHIBIT: + case RADIO_UNINHIBIT_ACK: + return getArgument(); + default: + break; + } + + return null; + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + @Override + public String getToID() + { + return getTargetAddress(); + } +} diff --git a/src/decode/p25/message/tdu/lc/GroupAffiliationQuery.java b/src/decode/p25/message/tdu/lc/GroupAffiliationQuery.java new file mode 100644 index 00000000..ef8e56b5 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/GroupAffiliationQuery.java @@ -0,0 +1,51 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class GroupAffiliationQuery extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( GroupAffiliationQuery.class ); + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public GroupAffiliationQuery( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.GROUP_AFFILIATION_QUERY.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " FROM:" + getSourceAddress() ); + + sb.append( " TO:" + getTargetAddress() ); + + return sb.toString(); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdate.java b/src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdate.java new file mode 100644 index 00000000..f70dbfad --- /dev/null +++ b/src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdate.java @@ -0,0 +1,158 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.reference.LinkControlOpcode; + +public class GroupVoiceChannelUpdate extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( GroupVoiceChannelUpdate.class ); + + public static final int[] IDENTIFIER_A = { 72,73,74,75 }; + public static final int[] CHANNEL_A = { 88,89,90,91,92,93,94,95,96,97,98,99 }; + public static final int[] GROUP_ADDRESS_A = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139 }; + public static final int[] IDENTIFIER_B = { 140,141,142,143 }; + public static final int[] CHANNEL_B = { 144,145,146,147,160,161,162,163,164, + 165,166,167 }; + public static final int[] GROUP_ADDRESS_B = { 168,169,170,171,184,185,186, + 187,188,189,190,191,192,193,194,195 }; + + private IdentifierProvider mIdentifierUpdateA; + private IdentifierProvider mIdentifierUpdateB; + + public GroupVoiceChannelUpdate( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.GROUP_VOICE_CHANNEL_UPDATE.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " CHAN A:" + getChannelA() ); + + sb.append( " GRP A:" + getGroupAddressA() ); + + if( hasChannelB() ) + { + sb.append( " CHAN B:" + getChannelA() ); + + sb.append( " GRP B:" + getGroupAddressA() ); + } + + return sb.toString(); + } + + public int getChannelIdentifierA() + { + return mMessage.getInt( IDENTIFIER_A ); + } + + public int getChannelNumberA() + { + return mMessage.getInt( CHANNEL_A ); + } + + public String getChannelA() + { + return getChannelIdentifierA() + "-" + getChannelNumberA(); + } + + public int getChannelIdentifierB() + { + return mMessage.getInt( IDENTIFIER_B ); + } + + public int getChannelNumberB() + { + return mMessage.getInt( CHANNEL_B ); + } + + public String getChannelB() + { + return getChannelIdentifierB() + "-" + getChannelNumberB(); + } + + public boolean hasChannelB() + { + return getChannelNumberB() != 0; + } + + public String getGroupAddressA() + { + return mMessage.getHex( GROUP_ADDRESS_A, 4 ); + } + + public String getGroupAddressB() + { + return mMessage.getHex( GROUP_ADDRESS_B, 4 ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + if( identifier == getChannelIdentifierA() ) + { + mIdentifierUpdateA = message; + } + if( identifier == getChannelIdentifierB() ) + { + mIdentifierUpdateB = message; + } + } + + @Override + public int[] getIdentifiers() + { + if( hasChannelB() ) + { + int[] identifiers = new int[ 2 ]; + identifiers[ 0 ] = getChannelIdentifierA(); + identifiers[ 1 ] = getChannelIdentifierB(); + + return identifiers; + } + else + { + int[] identifiers = new int[ 1 ]; + identifiers[ 0 ] = getChannelIdentifierA(); + + return identifiers; + } + } + + public long getDownlinkFrequencyA() + { + return calculateDownlink( mIdentifierUpdateA, getChannelNumberA() ); + } + + public long getUplinkFrequencyA() + { + return calculateUplink( mIdentifierUpdateA, getChannelNumberA() ); + } + + public long getDownlinkFrequencyB() + { + return calculateDownlink( mIdentifierUpdateB, getChannelNumberA() ); + } + + public long getUplinkFrequencyB() + { + return calculateUplink( mIdentifierUpdateB, getChannelNumberA() ); + } +} diff --git a/src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdateExplicit.java b/src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdateExplicit.java new file mode 100644 index 00000000..194647e0 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/GroupVoiceChannelUpdateExplicit.java @@ -0,0 +1,156 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.P25Message.DuplexMode; +import decode.p25.message.P25Message.SessionMode; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.reference.LinkControlOpcode; + +public class GroupVoiceChannelUpdateExplicit extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( GroupVoiceChannelUpdateExplicit.class ); + + public static final int EMERGENCY_FLAG = 92; + public static final int ENCRYPTED_CHANNEL_FLAG = 93; + public static final int DUPLEX_MODE = 94; + public static final int SESSION_MODE = 95; + public static final int[] GROUP_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139 }; + public static final int[] TRANSMIT_IDENTIFIER = { 140,141,142,143 }; + public static final int[] TRANSMIT_CHANNEL = { 144,145,146,147,160,161,162, + 163,164,165,166,167 }; + public static final int[] RECEIVE_IDENTIFIER = { 168,169,170,171 }; + public static final int[] RECEIVE_CHANNEL = { 184,185,186,187,188,189,190, + 191,192,193,194,195,196,197,198,199 }; + + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; + + public GroupVoiceChannelUpdateExplicit( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + if( isEmergency() ) + { + sb.append( " EMERGENCY" ); + } + if( isEncryptedChannel() ) + { + sb.append( " ENCRYPTED CHANNEL" ); + } + + + return sb.toString(); + } + + public boolean isEmergency() + { + return mMessage.get( EMERGENCY_FLAG ); + } + + public boolean isEncryptedChannel() + { + return mMessage.get( ENCRYPTED_CHANNEL_FLAG ); + } + + public DuplexMode getDuplexMode() + { + return mMessage.get( DUPLEX_MODE ) ? DuplexMode.FULL : DuplexMode.HALF; + } + + public SessionMode getSessionMode() + { + return mMessage.get( SESSION_MODE ) ? + SessionMode.CIRCUIT : SessionMode.PACKET; + } + + public int getTransmitChannelIdentifier() + { + return mMessage.getInt( TRANSMIT_IDENTIFIER ); + } + + public int getTransmitChannelNumber() + { + return mMessage.getInt( TRANSMIT_CHANNEL ); + } + + public String getTransmitChannel() + { + return getTransmitChannelIdentifier() + "-" + getTransmitChannelNumber(); + } + + public int getReceiveChannelIdentifier() + { + return mMessage.getInt( RECEIVE_IDENTIFIER ); + } + + public int getReceiveChannelNumber() + { + return mMessage.getInt( RECEIVE_CHANNEL ); + } + + public String getReceiveChannel() + { + return getReceiveChannelIdentifier() + "-" + getReceiveChannelNumber(); + } + + public String getGroupAddress() + { + return mMessage.getHex( GROUP_ADDRESS, 4 ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + if( identifier == getTransmitChannelIdentifier() ) + { + mTransmitIdentifierUpdate = message; + } + if( identifier == getReceiveChannelIdentifier() ) + { + mReceiveIdentifierUpdate = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + + identifiers[ 0 ] = getTransmitChannelIdentifier(); + identifiers[ 1 ] = getReceiveChannelIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mTransmitIdentifierUpdate, + getTransmitChannelNumber() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mReceiveIdentifierUpdate, + getReceiveChannelNumber() ); + } +} diff --git a/src/decode/p25/message/tdu/lc/GroupVoiceChannelUser.java b/src/decode/p25/message/tdu/lc/GroupVoiceChannelUser.java new file mode 100644 index 00000000..b4268dc8 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/GroupVoiceChannelUser.java @@ -0,0 +1,86 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class GroupVoiceChannelUser extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( GroupVoiceChannelUser.class ); + /* Service Options */ + public static final int EMERGENCY_FLAG = 92; + public static final int ENCRYPTED_CHANNEL_FLAG = 93; + public static final int DUPLEX_MODE = 94; + public static final int SESSION_MODE = 95; + public static final int[] GROUP_ADDRESS = { 120,121,122,123,136,137,138,139, + 140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public GroupVoiceChannelUser( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.GROUP_VOICE_CHANNEL_USER.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + if( isEmergency() ) + { + sb.append( " EMERGENCY" ); + } + if( isEncryptedChannel() ) + { + sb.append( " ENCRYPTED CHANNEL" ); + } + + sb.append( " FROM:" + getSourceAddress() ); + + sb.append( " TO:" + getGroupAddress() ); + + return sb.toString(); + } + + public boolean isEmergency() + { + return mMessage.get( EMERGENCY_FLAG ); + } + + public boolean isEncryptedChannel() + { + return mMessage.get( ENCRYPTED_CHANNEL_FLAG ); + } + + public DuplexMode getDuplexMode() + { + return mMessage.get( DUPLEX_MODE ) ? DuplexMode.FULL : DuplexMode.HALF; + } + + public SessionMode getSessionMode() + { + return mMessage.get( SESSION_MODE ) ? + SessionMode.CIRCUIT : SessionMode.PACKET; + } + + public String getGroupAddress() + { + return mMessage.getHex( GROUP_ADDRESS, 4 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/MessageUpdate.java b/src/decode/p25/message/tdu/lc/MessageUpdate.java new file mode 100644 index 00000000..6e719b2a --- /dev/null +++ b/src/decode/p25/message/tdu/lc/MessageUpdate.java @@ -0,0 +1,57 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class MessageUpdate extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( MessageUpdate.class ); + public static final int[] SHORT_DATA_MESSAGE = { 72,73,74,75,88,89,90,91,92, + 93,94,95,96,97,98,99 }; + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,190,192,193,194,195 }; + + public MessageUpdate( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.MESSAGE_UPDATE.getDescription(); + } + + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " MSG:" + getShortDataMessage() ); + sb.append( " SRC ADDR: " + getSourceAddress() ); + sb.append( " TGT ADDR: " + getTargetAddress() ); + + return sb.toString(); + } + + public String getShortDataMessage() + { + return mMessage.getHex( SHORT_DATA_MESSAGE, 4 ); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/NetworkStatusBroadcast.java b/src/decode/p25/message/tdu/lc/NetworkStatusBroadcast.java new file mode 100644 index 00000000..afdeb88d --- /dev/null +++ b/src/decode/p25/message/tdu/lc/NetworkStatusBroadcast.java @@ -0,0 +1,109 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Service; + +public class NetworkStatusBroadcast extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( NetworkStatusBroadcast.class ); + public static final int[] NETWORK_ID = { 72,73,74,75,88,89,90,91,92,93,94, + 95,96,97,98,99,112,113,114,115,116,117,118,119,120,121,122,123 }; + public static final int[] SYSTEM_ID = { 136,137,138,139,140,141,142,143,144, + 145,146,147 }; + public static final int[] IDENTIFIER = { 160,161,162,163 }; + public static final int[] CHANNEL = { 164,165,166,167,168,169,170,171,184, + 185,186,187 }; + public static final int[] SYSTEM_SERVICE_CLASS = { 188,189,190,191,192,193, + 194,195 }; + + private IdentifierProvider mIdentifierUpdate; + + public NetworkStatusBroadcast( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.NETWORK_STATUS_BROADCAST.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " NETWORK:" + getNetworkID() ); + sb.append( " SYS:" + getSystemID() ); + sb.append( " CHAN:" + getChannel() ); + sb.append( " " + Service.getServices( getSystemServiceClass() ).toString() ); + + return sb.toString(); + } + + public String getNetworkID() + { + return mMessage.getHex( NETWORK_ID, 5 ); + } + + public String getSystemID() + { + return mMessage.getHex( SYSTEM_ID, 3 ); + } + + public int getIdentifier() + { + return mMessage.getInt( IDENTIFIER ); + } + + public int getChannelNumber() + { + return mMessage.getInt( CHANNEL ); + } + + public String getChannel() + { + return getIdentifier() + "-" + getChannelNumber(); + } + + public int getSystemServiceClass() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + mIdentifierUpdate = message; + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 1 ]; + + identifiers[ 0 ] = getIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mIdentifierUpdate, getChannelNumber() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mIdentifierUpdate, getChannelNumber() ); + } +} diff --git a/src/decode/p25/message/tdu/lc/NetworkStatusBroadcastExplicit.java b/src/decode/p25/message/tdu/lc/NetworkStatusBroadcastExplicit.java new file mode 100644 index 00000000..b4604c72 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/NetworkStatusBroadcastExplicit.java @@ -0,0 +1,131 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Service; + +public class NetworkStatusBroadcastExplicit extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( NetworkStatusBroadcastExplicit.class ); + public static final int[] NETWORK_ID = { 72,73,74,75,88,89,90,91,92,93,94, + 95,96,97,98,99,112,113,114,115 }; + public static final int[] SYSTEM_ID = { 116,117,118,119,120,121,122,123,136, + 137,138,139 }; + public static final int[] TRANSMIT_IDENTIFIER = { 140,141,142,143 }; + public static final int[] TRANSMIT_CHANNEL = { 144,145,146,147,160,161,162, + 163,164,165,166,167 }; + public static final int[] RECEIVE_IDENTIFIER = { 168,169,170,171 }; + public static final int[] RECEIVE_CHANNEL = { 184,185,186,187,188,189,190, + 191,192,193,194,195 }; + + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; + + public NetworkStatusBroadcastExplicit( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.NETWORK_STATUS_BROADCAST_EXPLICIT.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " NETWORK:" + getNetworkID() ); + sb.append( " SYS:" + getSystemID() ); + sb.append( " TRANSMIT:" + getTransmitChannel() ); + sb.append( " RECEIVE:" + getReceiveChannel() ); + + return sb.toString(); + } + + public String getNetworkID() + { + return mMessage.getHex( NETWORK_ID, 5 ); + } + + public String getSystemID() + { + return mMessage.getHex( SYSTEM_ID, 3 ); + } + + public int getTransmitIdentifier() + { + return mMessage.getInt( TRANSMIT_IDENTIFIER ); + } + + public int getTransmitChannelNumber() + { + return mMessage.getInt( TRANSMIT_CHANNEL ); + } + + public String getTransmitChannel() + { + return getTransmitIdentifier() + "-" + getTransmitChannelNumber(); + } + + public int getReceiveIdentifier() + { + return mMessage.getInt( RECEIVE_IDENTIFIER ); + } + + public int getReceiveChannelNumber() + { + return mMessage.getInt( RECEIVE_CHANNEL ); + } + + public String getReceiveChannel() + { + return getReceiveIdentifier() + "-" + getReceiveChannelNumber(); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + if( identifier == getTransmitIdentifier() ) + { + mTransmitIdentifierUpdate = message; + } + if( identifier == getReceiveIdentifier() ) + { + mReceiveIdentifierUpdate = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + + identifiers[ 0 ] = getTransmitIdentifier(); + identifiers[ 1 ] = getReceiveIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mTransmitIdentifierUpdate, + getTransmitChannelNumber() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mReceiveIdentifierUpdate, + getReceiveChannelNumber() ); + } +} diff --git a/src/decode/p25/message/tdu/lc/ProtectionParameterBroadcast.java b/src/decode/p25/message/tdu/lc/ProtectionParameterBroadcast.java new file mode 100644 index 00000000..3d5a98d6 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/ProtectionParameterBroadcast.java @@ -0,0 +1,58 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.Encryption; +import decode.p25.reference.LinkControlOpcode; + +public class ProtectionParameterBroadcast extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( ProtectionParameterBroadcast.class ); + + public final static int[] ALGORITHM_ID = { 112,113,114,115,116,117,118,119 }; + public final static int[] KEY_ID = { 120,121,122,123,136,137,138,139,140, + 141,142,143,144,145,146,147 }; + public static final int[] TARGET_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,190,192,193,194,195 }; + + public ProtectionParameterBroadcast( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.PROTECTION_PARAMETER_BROADCAST.getDescription(); + } + + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " ENCRYPTION:" + getEncryption().name() ); + sb.append( " KEY:" + getEncryptionKey() ); + sb.append( " ADDRESSS:" + getTargetAddress() ); + + return sb.toString(); + } + + public Encryption getEncryption() + { + return Encryption.fromValue( mMessage.getInt( ALGORITHM_ID ) ); + } + + public int getEncryptionKey() + { + return mMessage.getInt( KEY_ID ); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/RFSSStatusBroadcast.java b/src/decode/p25/message/tdu/lc/RFSSStatusBroadcast.java new file mode 100644 index 00000000..d973655b --- /dev/null +++ b/src/decode/p25/message/tdu/lc/RFSSStatusBroadcast.java @@ -0,0 +1,132 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.message.tsbk.osp.control.SystemService; +import decode.p25.reference.LinkControlOpcode; + +public class RFSSStatusBroadcast extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( RFSSStatusBroadcast.class ); + + public static final int[] LRA = { 72,73,74,75,88,89, + 90,91 }; + public static final int[] SYSTEM_ID = { 96,97,98,99,112,113,114,115,116,117, + 118,119 }; + public static final int[] RFSS_ID = { 120,121,122,123,136,137,138, + 139 }; + public static final int[] SITE_ID = { 140,141,142,143,144,145,146,147 }; + + public static final int[] IDENTIFIER = { 160,161,162,163 }; + public static final int[] CHANNEL = { 164,165,166,167,168,169,170, + 171,184,185,186,187 }; + public static final int[] SYSTEM_SERVICE_CLASS = { 188,189,190,191,192,193, + 194,195 }; + + private IdentifierProvider mIdentifierUpdate; + + public RFSSStatusBroadcast( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.RFSS_STATUS_BROADCAST.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " LRA:" + getLocationRegistrationArea() ); + + sb.append( " SYS:" + getSystem() ); + + sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + + sb.append( " CHAN:" + getChannelNumber() ); + + sb.append( " " + SystemService.toString( getSystemServiceClass() ) ); + + sb.append( " " + mMessage.toString() ); + + return sb.toString(); + } + + public String getLocationRegistrationArea() + { + return mMessage.getHex( LRA, 2 ); + } + + public String getSystem() + { + 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 getIdentifier() + { + return mMessage.getInt( IDENTIFIER ); + } + + public String getChannel() + { + return getIdentifier() + "-" + getChannelNumber(); + } + + public int getChannelNumber() + { + return mMessage.getInt( CHANNEL ); + } + + public int getSystemServiceClass() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + mIdentifierUpdate = message; + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 1 ]; + + identifiers[ 0 ] = getIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mIdentifierUpdate, getChannelNumber() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mIdentifierUpdate, getChannelNumber() ); + } + +} diff --git a/src/decode/p25/message/tdu/lc/RFSSStatusBroadcastExplicit.java b/src/decode/p25/message/tdu/lc/RFSSStatusBroadcastExplicit.java new file mode 100644 index 00000000..bce824ac --- /dev/null +++ b/src/decode/p25/message/tdu/lc/RFSSStatusBroadcastExplicit.java @@ -0,0 +1,152 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.message.tsbk.osp.control.SystemService; +import decode.p25.reference.LinkControlOpcode; + +public class RFSSStatusBroadcastExplicit extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( RFSSStatusBroadcastExplicit.class ); + + public static final int[] LRA = { 72,73,74,75,88,89,90,91 }; + public static final int[] RECEIVE_IDENTIFIER = { 92,93,94,95 }; + public static final int[] RECEIVE_CHANNEL = { 96,97,98,99,112,113,114,115, + 116,117,118,119 }; + public static final int[] RFSS_ID = { 120,121,122,123,136,137,138, + 139 }; + public static final int[] SITE_ID = { 140,141,142,143,144,145,146,147 }; + + public static final int[] TRANSMIT_IDENTIFIER = { 160,161,162,163 }; + public static final int[] TRANSMIT_CHANNEL = { 164,165,166,167,168,169,170, + 171,184,185,186,187 }; + public static final int[] SYSTEM_SERVICE_CLASS = { 188,189,190,191,192,193, + 194,195 }; + + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; + + public RFSSStatusBroadcastExplicit( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.RFSS_STATUS_BROADCAST_EXPLICIT.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " LRA:" + getLocationRegistrationArea() ); + + sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + + sb.append( " TRANSMIT:" + getTransmitChannelNumber() ); + + sb.append( " RECEIVE:" + getReceiveChannelNumber() ); + + sb.append( " " + SystemService.toString( getSystemServiceClass() ) ); + + sb.append( " " + mMessage.toString() ); + + return sb.toString(); + } + + public String getLocationRegistrationArea() + { + return mMessage.getHex( LRA, 2 ); + } + + 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 String getTransmitChannel() + { + return getTransmitIdentifier() + "-" + getTransmitChannelNumber(); + } + + public int getTransmitChannelNumber() + { + return mMessage.getInt( TRANSMIT_CHANNEL ); + } + + public int getReceiveIdentifier() + { + return mMessage.getInt( RECEIVE_IDENTIFIER ); + } + + public String getReceiveChannel() + { + return getReceiveIdentifier() + "-" + getReceiveChannelNumber(); + } + + public int getReceiveChannelNumber() + { + return mMessage.getInt( RECEIVE_CHANNEL ); + } + + public int getSystemServiceClass() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + if( identifier == getTransmitIdentifier() ) + { + mTransmitIdentifierUpdate = message; + } + + if( identifier == getReceiveIdentifier() ) + { + mReceiveIdentifierUpdate = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + + identifiers[ 0 ] = getTransmitIdentifier(); + identifiers[ 1 ] = getReceiveIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mTransmitIdentifierUpdate, getTransmitChannelNumber() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mReceiveIdentifierUpdate, getReceiveChannelNumber() ); + } + +} diff --git a/src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcast.java b/src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcast.java new file mode 100644 index 00000000..906ad67d --- /dev/null +++ b/src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcast.java @@ -0,0 +1,159 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.message.tsbk.osp.control.SystemService; +import decode.p25.reference.LinkControlOpcode; + +public class SecondaryControlChannelBroadcast extends TDULinkControlMessage + implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( SecondaryControlChannelBroadcast.class ); + + public static final int[] RFSS_ID = { 72,73,74,75,88,89,90,91 }; + public static final int[] SITE_ID = { 92,93,94,95,96,97,98,99 }; + public static final int[] IDENTIFIER_A = { 112,113,114,115 }; + public static final int[] CHANNEL_A = { 116,117,118,119,120,121,122, + 123,136,137,138,139 }; + + public static final int[] SYSTEM_SERVICE_CLASS_A = { 140,141,142,143,144, + 145,146,147 }; + + public static final int[] IDENTIFIER_B = { 160,161,162,163 }; + public static final int[] CHANNEL_B = { 164,165,166,167,168,169,170, + 171,184,185,186,187 }; + public static final int[] SYSTEM_SERVICE_CLASS_B = { 188,189,190,191,192, + 193,194,195 }; + + private IdentifierProvider mIdentifierProviderA; + private IdentifierProvider mIdentifierProviderB; + + public SecondaryControlChannelBroadcast( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.SECONDARY_CONTROL_CHANNEL_BROADCAST.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + + sb.append( " CHAN A:" + getChannelA() ); + + sb.append( " " + SystemService.toString( getSystemServiceClassA() ) ); + + sb.append( " CHAN B:" + getChannelB() ); + + sb.append( " " + SystemService.toString( getSystemServiceClassB() ) ); + + return sb.toString(); + } + + public String getRFSubsystemID() + { + return mMessage.getHex( RFSS_ID, 2 ); + } + + public String getSiteID() + { + return mMessage.getHex( SITE_ID, 2 ); + } + + public int getIdentifierA() + { + return mMessage.getInt( IDENTIFIER_A ); + } + + public int getChannelA() + { + return mMessage.getInt( CHANNEL_A ); + } + + public String getChannelNumberA() + { + return getIdentifierA() + "-" + getChannelA(); + } + + public int getIdentifierB() + { + return mMessage.getInt( IDENTIFIER_B ); + } + + public int getChannelB() + { + return mMessage.getInt( CHANNEL_B ); + } + + public String getChannelNumberB() + { + return getIdentifierB() + "-" + getChannelB(); + } + + public int getSystemServiceClassA() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS_A ); + } + + public int getSystemServiceClassB() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS_B ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + if( identifier == getIdentifierA() ) + { + mIdentifierProviderA = message; + } + if( identifier == getIdentifierB() ) + { + mIdentifierProviderB = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + + identifiers[ 0 ] = getIdentifierA(); + identifiers[ 1 ] = getIdentifierB(); + + return identifiers; + } + + public long getDownlinkFrequencyA() + { + return calculateDownlink( mIdentifierProviderA, getChannelA() ); + } + + public long getUplinkFrequencyA() + { + return calculateUplink( mIdentifierProviderA, getChannelA() ); + } + + public long getDownlinkFrequencyB() + { + return calculateDownlink( mIdentifierProviderB, getChannelB() ); + } + + public long getUplinkFrequencyB() + { + return calculateUplink( mIdentifierProviderB, getChannelB() ); + } +} diff --git a/src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcastExplicit.java b/src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcastExplicit.java new file mode 100644 index 00000000..1fa58744 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/SecondaryControlChannelBroadcastExplicit.java @@ -0,0 +1,140 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.message.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; +import decode.p25.message.tsbk.osp.control.SystemService; +import decode.p25.reference.LinkControlOpcode; + +public class SecondaryControlChannelBroadcastExplicit + extends TDULinkControlMessage implements IdentifierProviderReceiver +{ + private final static Logger mLog = + LoggerFactory.getLogger( SecondaryControlChannelBroadcastExplicit.class ); + + public static final int[] RFSS_ID = { 72,73,74,75,88,89,90,91 }; + public static final int[] SITE_ID = { 92,93,94,95,96,97,98,99 }; + public static final int[] TRANSMIT_IDENTIFIER = { 112,113,114,115 }; + public static final int[] TRANSMIT_CHANNEL = { 116,117,118,119,120,121,122, + 123,136,137,138,139 }; + public static final int[] RECEIVE_IDENTIFIER = { 140,141,142,143 }; + public static final int[] RECEIVE_CHANNEL = { 144,145,146,147,160,161,162, + 163,164,165,166,167 }; + public static final int[] SYSTEM_SERVICE_CLASS = { 168,169,170,171,184, + 185,186,187 }; + + private IdentifierProvider mTransmitIdentifierProvider; + private IdentifierProvider mReceiveIdentifierProvider; + + public SecondaryControlChannelBroadcastExplicit( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + + sb.append( " TRANSMIT:" + getTransmitChannel() ); + + sb.append( " RECEIVE:" + getReceiveChannel() ); + + sb.append( " " + SystemService.toString( getSystemServiceClass() ) ); + + return sb.toString(); + } + + 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 getTransmitChannelNumber() + { + return mMessage.getInt( TRANSMIT_CHANNEL ); + } + + public String getTransmitChannel() + { + return getTransmitIdentifier() + "-" + getTransmitChannelNumber(); + } + + public int getReceiveIdentifier() + { + return mMessage.getInt( RECEIVE_IDENTIFIER ); + } + + public int getReceiveChannelNumber() + { + return mMessage.getInt( RECEIVE_CHANNEL ); + } + + public String getReceiveChannel() + { + return getReceiveIdentifier() + "-" + getReceiveChannelNumber(); + } + + public int getSystemServiceClass() + { + return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + } + + @Override + public void setIdentifierMessage( int identifier, IdentifierProvider message ) + { + if( identifier == getTransmitIdentifier() ) + { + mTransmitIdentifierProvider = message; + } + if( identifier == getReceiveIdentifier() ) + { + mReceiveIdentifierProvider = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + + identifiers[ 0 ] = getTransmitIdentifier(); + identifiers[ 1 ] = getReceiveIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mTransmitIdentifierProvider, + getTransmitChannelNumber() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mReceiveIdentifierProvider, + getReceiveChannelNumber() ); + } +} diff --git a/src/decode/p25/message/tdu/lc/StatusQuery.java b/src/decode/p25/message/tdu/lc/StatusQuery.java new file mode 100644 index 00000000..c0e4da8a --- /dev/null +++ b/src/decode/p25/message/tdu/lc/StatusQuery.java @@ -0,0 +1,51 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class StatusQuery extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( StatusQuery.class ); + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public StatusQuery( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.STATUS_QUERY.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " FROM:" + getSourceAddress() ); + + sb.append( " TO:" + getTargetAddress() ); + + return sb.toString(); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/StatusUpdate.java b/src/decode/p25/message/tdu/lc/StatusUpdate.java new file mode 100644 index 00000000..949687da --- /dev/null +++ b/src/decode/p25/message/tdu/lc/StatusUpdate.java @@ -0,0 +1,64 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class StatusUpdate extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( StatusUpdate.class ); + public static final int[] USER_STATUS = { 80,81,82,83,84,85,86,87 }; + public static final int[] UNIT_STATUS = { 88,89,90,91,92,93,94,95 }; + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public StatusUpdate( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.STATUS_UPDATE.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " STATUS USER:" + getUserStatus() ); + sb.append( " UNIT:" + getUnitStatus() ); + sb.append( " FROM:" + getSourceAddress() ); + sb.append( " TO:" + getTargetAddress() ); + + return sb.toString(); + } + + public String getUserStatus() + { + return mMessage.getHex( USER_STATUS, 2 ); + } + + public String getUnitStatus() + { + return mMessage.getHex( UNIT_STATUS, 2 ); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/SystemServiceBroadcast.java b/src/decode/p25/message/tdu/lc/SystemServiceBroadcast.java new file mode 100644 index 00000000..4a13d385 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/SystemServiceBroadcast.java @@ -0,0 +1,63 @@ +package decode.p25.message.tdu.lc; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Service; + +public class SystemServiceBroadcast extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( SystemServiceBroadcast.class ); + public static final int[] REQUEST_PRIORITY_LEVEL = { 96,97,98,99 }; + public static final int[] AVAILABLE_SERVICES = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SUPPORTED_SERVICES = { 160,161,162,163,164,165, + 166,167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public SystemServiceBroadcast( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.SYSTEM_SERVICE_BROADCAST.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " SERVICES AVAILABLE " ); + + sb.append( getAvailableServices() ); + + sb.append( " SUPPORTED " ); + + sb.append( getSupportedServices() ); + + return sb.toString(); + } + + public List getAvailableServices() + { + long bitmap = mMessage.getLong( AVAILABLE_SERVICES ); + + return Service.getServices( bitmap ); + } + + public List getSupportedServices() + { + long bitmap = mMessage.getLong( SUPPORTED_SERVICES ); + + return Service.getServices( bitmap ); + } +} diff --git a/src/decode/p25/message/tdu/lc/TDULCMessageFactory.java b/src/decode/p25/message/tdu/lc/TDULCMessageFactory.java new file mode 100644 index 00000000..3ee2d77a --- /dev/null +++ b/src/decode/p25/message/tdu/lc/TDULCMessageFactory.java @@ -0,0 +1,95 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.Vendor; + + +public class TDULCMessageFactory +{ + private final static Logger mLog = + LoggerFactory.getLogger( TDULCMessageFactory.class ); + + /** + * Constructs a new sub-class of the TDULC message if the opcode is recognized + * or returns the original message. + */ + public static TDULinkControlMessage getMessage( TDULinkControlMessage message ) + { + if( message.isImplicitFormat() || message.getVendor() == Vendor.STANDARD ) + { + switch( message.getOpcode() ) + { + case ADJACENT_SITE_STATUS_BROADCAST: + return new AdjacentSiteStatusBroadcast( message ); + case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT: + return new AdjacentSiteStatusBroadcastExplicit( message ); + case CALL_ALERT: + return new CallAlert( message ); + case CALL_TERMINATION_OR_CANCELLATION: + return new CallTermination( message ); + case CHANNEL_IDENTIFIER_UPDATE: + return new ChannelIdentifierUpdate( message ); + case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT: + return new ChannelIdentifierUpdateExplicit( message ); + case EXTENDED_FUNCTION_COMMAND: + return new ExtendedFunctionCommand( message ); + case GROUP_AFFILIATION_QUERY: + return new GroupAffiliationQuery( message ); + case GROUP_VOICE_CHANNEL_UPDATE: + return new GroupVoiceChannelUpdate( message ); + case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT: + return new GroupVoiceChannelUpdateExplicit( message ); + case GROUP_VOICE_CHANNEL_USER: + return new GroupVoiceChannelUser( message ); + case MESSAGE_UPDATE: + return new MessageUpdate( message ); + case NETWORK_STATUS_BROADCAST: + return new NetworkStatusBroadcast( message ); + case NETWORK_STATUS_BROADCAST_EXPLICIT: + return new NetworkStatusBroadcastExplicit( message ); + case PROTECTION_PARAMETER_BROADCAST: + return new ProtectionParameterBroadcast( message ); + case RFSS_STATUS_BROADCAST: + return new RFSSStatusBroadcast( message ); + case RFSS_STATUS_BROADCAST_EXPLICIT: + return new RFSSStatusBroadcastExplicit( message ); + case SECONDARY_CONTROL_CHANNEL_BROADCAST: + return new SecondaryControlChannelBroadcast( message ); + case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT: + return new SecondaryControlChannelBroadcastExplicit( message ); + case STATUS_QUERY: + return new StatusQuery( message ); + case STATUS_UPDATE: + return new StatusUpdate( message ); + case SYSTEM_SERVICE_BROADCAST: + return new SystemServiceBroadcast( message ); + case TELEPHONE_INTERCONNECT_ANSWER_REQUEST: + return new TelephoneInterconnectAnswerRequest( message ); + case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER: + return new TelephoneInterconnectVoiceChannelUser( message ); + case UNIT_AUTHENTICATION_COMMAND: + return new UnitAuthenticationCommand( message ); + case UNIT_REGISTRATION_COMMAND: + return new UnitRegistrationCommand( message ); + case UNIT_TO_UNIT_ANSWER_REQUEST: + return new UnitToUnitAnswerRequest( message ); + case UNIT_TO_UNIT_VOICE_CHANNEL_USER: + return new UnitToUnitVoiceChannelUser( message ); + default: + break; + } + } + else + { + switch( message.getVendor() ) + { + default: + break; + } + } + + return message; + } +} diff --git a/src/decode/p25/message/tdu/lc/TDULinkControlMessage.java b/src/decode/p25/message/tdu/lc/TDULinkControlMessage.java new file mode 100644 index 00000000..5f9f2983 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/TDULinkControlMessage.java @@ -0,0 +1,265 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import alias.AliasList; +import bits.BitSetBuffer; +import decode.p25.message.P25Message; +import decode.p25.reference.DataUnitID; +import decode.p25.reference.LinkControlOpcode; +import decode.p25.reference.Vendor; +import decode.p25.reference.VendorLinkControlOpcode; +import edac.CRC; +import edac.Galois24; +import edac.ReedSolomon_24_12_13; + +public class TDULinkControlMessage extends P25Message +{ + public final static Logger mLog = LoggerFactory.getLogger( TDULinkControlMessage.class ); + + public static final int[] LC_HEX_0 = { 64,65,66,67,68,69 }; + public static final int[] LC_HEX_1 = { 70,71,72,73,74,75 }; + public static final int[] LC_HEX_2 = { 88,89,90,91,92,93 }; + public static final int[] LC_HEX_3 = { 94,95,96,97,98,99 }; + public static final int[] LC_HEX_4 = { 112,113,114,115,116,117 }; + public static final int[] LC_HEX_5 = { 118,119,120,121,122,123 }; + public static final int[] LC_HEX_6 = { 136,137,138,139,140,141 }; + public static final int[] LC_HEX_7 = { 142,143,144,145,146,147 }; + public static final int[] LC_HEX_8 = { 160,161,162,163,164,165 }; + public static final int[] LC_HEX_9 = { 166,167,168,169,170,171 }; + public static final int[] LC_HEX_10 = { 184,185,186,187,188,189 }; + public static final int[] LC_HEX_11 = { 190,191,192,193,194,195 }; + public static final int[] RS_HEX_0 = { 208,209,210,211,212,213 }; + public static final int[] RS_HEX_1 = { 214,215,216,217,218,219 }; + public static final int[] RS_HEX_2 = { 232,233,234,235,236,237 }; + public static final int[] RS_HEX_3 = { 238,239,240,241,242,243 }; + public static final int[] RS_HEX_4 = { 256,257,258,259,260,261 }; + public static final int[] RS_HEX_5 = { 262,263,264,265,266,267 }; + public static final int[] RS_HEX_6 = { 280,281,282,283,284,285 }; + public static final int[] RS_HEX_7 = { 286,287,288,289,290,291 }; + public static final int[] RS_HEX_8 = { 304,305,306,307,308,309 }; + public static final int[] RS_HEX_9 = { 310,311,312,313,314,315 }; + public static final int[] RS_HEX_10 = { 328,329,330,331,332,333 }; + public static final int[] RS_HEX_11 = { 334,335,336,337,338,339 }; + + public static final int ENCRYPTION_FLAG = 64; + public static final int IMPLICIT_VENDOR_FLAG = 65; + public static final int[] OPCODE = { 66,67,68,69,70,71 }; + public static final int[] VENDOR = { 72,73,74,75,88,89,90,91 }; + + public static final ReedSolomon_24_12_13 mReedSolomonDecoder = + new ReedSolomon_24_12_13(); + + public TDULinkControlMessage( BitSetBuffer message, DataUnitID duid, + AliasList aliasList ) + { + super( message, duid, aliasList ); + + /* NID CRC is checked in the message framer so a constructed message + * means it passed the CRC */ + mCRC = new CRC[ 3 ]; + mCRC[ 0 ] = CRC.PASSED; + + checkCRC(); + } + + /** + * Constructs a TDULinkControl message from an existing message and bypasses + * the CRC calculation. + */ + protected TDULinkControlMessage( TDULinkControlMessage message ) + { + super( message.getSourceMessage(), DataUnitID.TDULC, message.getAliasList() ); + + mCRC = message.getCRC(); + } + + public CRC[] getCRC() + { + return mCRC; + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + sb.append( " " ); + sb.append( mMessage.toString() ); + + return sb.toString(); + } + + public String getMessageStub() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "NAC:" ); + sb.append( getNAC() ); + sb.append( " " ); + sb.append( getDUID().getLabel() ); + sb.append( " " ); + + if( isEncrypted() ) + { + sb.append( "ENCRYPTED" ); + } + else + { + if( isImplicitFormat() || getVendor() == Vendor.STANDARD ) + { + sb.append( getOpcode().getLabel() ); + } + else + { + sb.append( "VENDOR:" + getVendor().getLabel() + " " ); + sb.append( getVendorOpcode().getLabel() ); + } + } + + return sb.toString(); + } + + public boolean isEncrypted() + { + return mMessage.get( ENCRYPTION_FLAG ); + } + + public boolean isImplicitFormat() + { + return mMessage.get( IMPLICIT_VENDOR_FLAG ); + } + + public LinkControlOpcode getOpcode() + { + return LinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + + public VendorLinkControlOpcode getVendorOpcode() + { + return VendorLinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + + public Vendor getVendor() + { + if( isImplicitFormat() ) + { + return Vendor.STANDARD; + } + + return Vendor.fromValue( mMessage.getInt( VENDOR ) ); + } + + + /** + * Checks and repairs the 12 x 24-bit golay(24,12,8) codewords and then + * checks and repairs the 24 x 6-bit link control and reed-solomon + * RS(24,12,13) parity codewords + */ + private void checkCRC() + { + /* Check the Golay codewords */ + int x = 64; + + mCRC[ 1 ] = CRC.PASSED; + + while( x < mMessage.size() ) + { + boolean passes = Galois24.checkAndCorrect( mMessage, x ); + + if( !passes ) + { + mCRC[ 1 ] = CRC.FAILED_CRC; + } + + x += 24; + } + + /* Check the Reed-Solomon parity bits. The RS decoder expects the link + * control data and reed solomon parity hex codewords in reverse order. + * The RS(24,12,13) code used by P25 removes the left-hand 47 data hex + * words, so we replace them with zeros. */ + int[] input = new int [63]; + int[] output = new int [63]; + + input[ 0 ] = mMessage.getInt( RS_HEX_11 ); + input[ 1 ] = mMessage.getInt( RS_HEX_10 ); + input[ 2 ] = mMessage.getInt( RS_HEX_9 ); + input[ 3 ] = mMessage.getInt( RS_HEX_8 ); + input[ 4 ] = mMessage.getInt( RS_HEX_7 ); + input[ 5 ] = mMessage.getInt( RS_HEX_6 ); + input[ 6 ] = mMessage.getInt( RS_HEX_5 ); + input[ 7 ] = mMessage.getInt( RS_HEX_4 ); + input[ 8 ] = mMessage.getInt( RS_HEX_3 ); + input[ 9 ] = mMessage.getInt( RS_HEX_2 ); + input[ 10 ] = mMessage.getInt( RS_HEX_1 ); + input[ 11 ] = mMessage.getInt( RS_HEX_0 ); + input[ 12 ] = mMessage.getInt( LC_HEX_11 ); + input[ 13 ] = mMessage.getInt( LC_HEX_10 ); + input[ 14 ] = mMessage.getInt( LC_HEX_9 ); + input[ 15 ] = mMessage.getInt( LC_HEX_8 ); + input[ 16 ] = mMessage.getInt( LC_HEX_7 ); + input[ 17 ] = mMessage.getInt( LC_HEX_6 ); + input[ 18 ] = mMessage.getInt( LC_HEX_5 ); + input[ 19 ] = mMessage.getInt( LC_HEX_4 ); + input[ 20 ] = mMessage.getInt( LC_HEX_3 ); + input[ 21 ] = mMessage.getInt( LC_HEX_2 ); + input[ 22 ] = mMessage.getInt( LC_HEX_1 ); + input[ 23 ] = mMessage.getInt( LC_HEX_0 ); + /* indexes 24 - 62 are defaulted to zero */ + + boolean irrecoverableErrors = mReedSolomonDecoder.decode( input, output ); + + if( irrecoverableErrors ) + { + mCRC[ 2 ] = CRC.FAILED_CRC; + } + else + { + mCRC[ 2 ] = CRC.PASSED; + + /* Only fix the link control data hex codewords */ + repairHexCodeword( input, output, 12, LC_HEX_11 ); + repairHexCodeword( input, output, 13, LC_HEX_10 ); + repairHexCodeword( input, output, 14, LC_HEX_9 ); + repairHexCodeword( input, output, 15, LC_HEX_8 ); + repairHexCodeword( input, output, 16, LC_HEX_7 ); + repairHexCodeword( input, output, 17, LC_HEX_6 ); + repairHexCodeword( input, output, 18, LC_HEX_5 ); + repairHexCodeword( input, output, 19, LC_HEX_4 ); + repairHexCodeword( input, output, 20, LC_HEX_3 ); + repairHexCodeword( input, output, 21, LC_HEX_2 ); + repairHexCodeword( input, output, 22, LC_HEX_1 ); + repairHexCodeword( input, output, 23, LC_HEX_0 ); + + /* If the golay check failed, mark it as corrected too */ + if( mCRC[ 1 ] == CRC.FAILED_CRC ) + { + mCRC[ 1 ] = CRC.CORRECTED; + } + } + } + + private void repairHexCodeword( int[] input, int[] output, int index, int[] indexSet ) + { + if( input[ index ] != output[ index ] ) + { + mMessage.load( indexSet[ 0 ], 6, output[ index ] ); + mCRC[ 2 ] = CRC.CORRECTED; + } + } + + /** + * Indicates if the message passed the golay and reed-solomon parity checks + * or was corrected. + */ + public boolean isValid() + { + // mCRC[ 0 ] - always passes (otherwise message wouldn't be constructed ) + // mCRC[ 1 ] - golay - always passes or corrected if mCRC[2] is valid + + return mCRC[ 2 ] == CRC.PASSED || mCRC[ 2 ] == CRC.CORRECTED; + } +} diff --git a/src/decode/p25/message/tdu/lc/TelephoneInterconnectAnswerRequest.java b/src/decode/p25/message/tdu/lc/TelephoneInterconnectAnswerRequest.java new file mode 100644 index 00000000..1efc2d83 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/TelephoneInterconnectAnswerRequest.java @@ -0,0 +1,80 @@ +package decode.p25.message.tdu.lc; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.Digit; +import decode.p25.reference.LinkControlOpcode; + +public class TelephoneInterconnectAnswerRequest extends TDULinkControlMessage +{ + private final static Logger mLog = LoggerFactory.getLogger( TelephoneInterconnectAnswerRequest.class ); + + public static final int[] DIGIT_1 = { 72,73,74,75 }; + public static final int[] DIGIT_2 = { 88,89,90,91 }; + public static final int[] DIGIT_3 = { 92,93,94,95 }; + public static final int[] DIGIT_4 = { 96,97,98,99 }; + public static final int[] DIGIT_5 = { 112,113,114,115 }; + public static final int[] DIGIT_6 = { 116,117,118,119 }; + public static final int[] DIGIT_7 = { 120,121,122,123 }; + public static final int[] DIGIT_8 = { 136,137,138,139 }; + public static final int[] DIGIT_9 = { 140,141,142,143 }; + public static final int[] DIGIT_10 = { 144,145,146,147 }; + + public static final int[] TARGET_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public TelephoneInterconnectAnswerRequest( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.TELEPHONE_INTERCONNECT_ANSWER_REQUEST.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " TO:" ); + sb.append( getTargetAddress() ); + + sb.append( " TEL:" ); + sb.append( getTelephoneNumber() ); + + return sb.toString(); + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getTelephoneNumber() + { + List digits = new ArrayList(); + + digits.add( mMessage.getInt( DIGIT_1 ) ); + digits.add( mMessage.getInt( DIGIT_2 ) ); + digits.add( mMessage.getInt( DIGIT_3 ) ); + digits.add( mMessage.getInt( DIGIT_4 ) ); + digits.add( mMessage.getInt( DIGIT_5 ) ); + digits.add( mMessage.getInt( DIGIT_6 ) ); + digits.add( mMessage.getInt( DIGIT_7 ) ); + digits.add( mMessage.getInt( DIGIT_8 ) ); + digits.add( mMessage.getInt( DIGIT_9 ) ); + digits.add( mMessage.getInt( DIGIT_10 ) ); + + return Digit.decode( digits ); + } + +} diff --git a/src/decode/p25/message/tdu/lc/TelephoneInterconnectVoiceChannelUser.java b/src/decode/p25/message/tdu/lc/TelephoneInterconnectVoiceChannelUser.java new file mode 100644 index 00000000..6589339c --- /dev/null +++ b/src/decode/p25/message/tdu/lc/TelephoneInterconnectVoiceChannelUser.java @@ -0,0 +1,93 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class TelephoneInterconnectVoiceChannelUser extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( TelephoneInterconnectVoiceChannelUser.class ); + /* Service Options */ + public static final int EMERGENCY_FLAG = 92; + public static final int ENCRYPTED_CHANNEL_FLAG = 93; + public static final int DUPLEX_MODE = 94; + public static final int SESSION_MODE = 95; + + public static final int[] CALL_TIMER = { 120,121,122,123,136,137,138,139, + 140,141,142,143,144,145,146,147 }; + public static final int[] ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public TelephoneInterconnectVoiceChannelUser( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + if( isEmergency() ) + { + sb.append( " EMERGENCY" ); + } + if( isEncryptedChannel() ) + { + sb.append( " ENCRYPTED CHANNEL" ); + } + + sb.append( " TIMER:" + getCallTimer() + " SECS" ); + + sb.append( " ADDR:" + getAddress() ); + + return sb.toString(); + } + + public boolean isEmergency() + { + return mMessage.get( EMERGENCY_FLAG ); + } + + public boolean isEncryptedChannel() + { + return mMessage.get( ENCRYPTED_CHANNEL_FLAG ); + } + + public DuplexMode getDuplexMode() + { + return mMessage.get( DUPLEX_MODE ) ? DuplexMode.FULL : DuplexMode.HALF; + } + + public SessionMode getSessionMode() + { + return mMessage.get( SESSION_MODE ) ? + SessionMode.CIRCUIT : SessionMode.PACKET; + } + + public String getAddress() + { + return mMessage.getHex( ADDRESS, 6 ); + } + + /** + * Call timer in seconds + */ + public int getCallTimer() + { + int units = mMessage.getInt( CALL_TIMER ); + + return (int)( units / 10 ); + } + +} diff --git a/src/decode/p25/message/tdu/lc/UnitAuthenticationCommand.java b/src/decode/p25/message/tdu/lc/UnitAuthenticationCommand.java new file mode 100644 index 00000000..b0138bf3 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/UnitAuthenticationCommand.java @@ -0,0 +1,58 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class UnitAuthenticationCommand extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( UnitAuthenticationCommand.class ); + public static final int[] NETWORK_ID = { 72,73,74,75,88,89,90,91,92,93,94, + 95,96,97,98,99,112,113,114,115 }; + public static final int[] SYSTEM_ID = { 116,117,118,119,120,121,122,123, + 136,137,138,139 }; + public static final int[] SOURCE_ID = { 140,141,142,143,144,145,146,147, + 160,161,162,163,164,165,166,167,168,169,170,171,184,185,186,187 }; + + public UnitAuthenticationCommand( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.UNIT_AUTHENTICATION_COMMAND.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " NETWORK:" + getNetworkID() ); + sb.append( " SYS:" + getSystemID() ); + sb.append( " ID:" + getSourceID() ); + + return sb.toString(); + } + + public String getNetworkID() + { + return mMessage.getHex( NETWORK_ID, 5 ); + } + + public String getSystemID() + { + return mMessage.getHex( SYSTEM_ID, 3 ); + } + + public String getSourceID() + { + return mMessage.getHex( SOURCE_ID, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/UnitRegistrationCommand.java b/src/decode/p25/message/tdu/lc/UnitRegistrationCommand.java new file mode 100644 index 00000000..9759f082 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/UnitRegistrationCommand.java @@ -0,0 +1,58 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class UnitRegistrationCommand extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( UnitRegistrationCommand.class ); + public static final int[] NETWORK_ID = { 72,73,74,75,88,89,90,91,92,93,94, + 95,96,97,98,99,112,113,114,115 }; + public static final int[] SYSTEM_ID = { 116,117,118,119,120,121,122,123, + 136,137,138,139 }; + public static final int[] SOURCE_ID = { 140,141,142,143,144,145,146,147, + 160,161,162,163,164,165,166,167,168,169,170,171,184,185,186,187 }; + + public UnitRegistrationCommand( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.UNIT_REGISTRATION_COMMAND.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + sb.append( " NETWORK:" + getNetworkID() ); + sb.append( " SYS:" + getSystemID() ); + sb.append( " ID:" + getSourceID() ); + + return sb.toString(); + } + + public String getNetworkID() + { + return mMessage.getHex( NETWORK_ID, 5 ); + } + + public String getSystemID() + { + return mMessage.getHex( SYSTEM_ID, 3 ); + } + + public String getSourceID() + { + return mMessage.getHex( SOURCE_ID, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/UnitToUnitAnswerRequest.java b/src/decode/p25/message/tdu/lc/UnitToUnitAnswerRequest.java new file mode 100644 index 00000000..880bccea --- /dev/null +++ b/src/decode/p25/message/tdu/lc/UnitToUnitAnswerRequest.java @@ -0,0 +1,86 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class UnitToUnitAnswerRequest extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( UnitToUnitAnswerRequest.class ); + /* Service Options */ + public static final int EMERGENCY_FLAG = 92; + public static final int ENCRYPTED_CHANNEL_FLAG = 93; + public static final int DUPLEX_MODE = 94; + public static final int SESSION_MODE = 95; + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public UnitToUnitAnswerRequest( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.UNIT_TO_UNIT_ANSWER_REQUEST.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + if( isEmergency() ) + { + sb.append( " EMERGENCY" ); + } + if( isEncryptedChannel() ) + { + sb.append( " ENCRYPTED CHANNEL" ); + } + + sb.append( " FROM:" + getSourceAddress() ); + + sb.append( " TO:" + getTargetAddress() ); + + return sb.toString(); + } + + public boolean isEmergency() + { + return mMessage.get( EMERGENCY_FLAG ); + } + + public boolean isEncryptedChannel() + { + return mMessage.get( ENCRYPTED_CHANNEL_FLAG ); + } + + public DuplexMode getDuplexMode() + { + return mMessage.get( DUPLEX_MODE ) ? DuplexMode.FULL : DuplexMode.HALF; + } + + public SessionMode getSessionMode() + { + return mMessage.get( SESSION_MODE ) ? + SessionMode.CIRCUIT : SessionMode.PACKET; + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tdu/lc/UnitToUnitVoiceChannelUser.java b/src/decode/p25/message/tdu/lc/UnitToUnitVoiceChannelUser.java new file mode 100644 index 00000000..b1430222 --- /dev/null +++ b/src/decode/p25/message/tdu/lc/UnitToUnitVoiceChannelUser.java @@ -0,0 +1,86 @@ +package decode.p25.message.tdu.lc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import decode.p25.reference.LinkControlOpcode; + +public class UnitToUnitVoiceChannelUser extends TDULinkControlMessage +{ + private final static Logger mLog = + LoggerFactory.getLogger( UnitToUnitVoiceChannelUser.class ); + /* Service Options */ + public static final int EMERGENCY_FLAG = 92; + public static final int ENCRYPTED_CHANNEL_FLAG = 93; + public static final int DUPLEX_MODE = 94; + public static final int SESSION_MODE = 95; + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 }; + + public UnitToUnitVoiceChannelUser( TDULinkControlMessage source ) + { + super( source ); + } + + @Override + public String getEventType() + { + return LinkControlOpcode.UNIT_TO_UNIT_VOICE_CHANNEL_USER.getDescription(); + } + + @Override + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + if( isEmergency() ) + { + sb.append( " EMERGENCY" ); + } + if( isEncryptedChannel() ) + { + sb.append( " ENCRYPTED CHANNEL" ); + } + + sb.append( " FROM:" + getSourceAddress() ); + + sb.append( " TO:" + getTargetAddress() ); + + return sb.toString(); + } + + public boolean isEmergency() + { + return mMessage.get( EMERGENCY_FLAG ); + } + + public boolean isEncryptedChannel() + { + return mMessage.get( ENCRYPTED_CHANNEL_FLAG ); + } + + public DuplexMode getDuplexMode() + { + return mMessage.get( DUPLEX_MODE ) ? DuplexMode.FULL : DuplexMode.HALF; + } + + public SessionMode getSessionMode() + { + return mMessage.get( SESSION_MODE ) ? + SessionMode.CIRCUIT : SessionMode.PACKET; + } + + public String getTargetAddress() + { + return mMessage.getHex( TARGET_ADDRESS, 6 ); + } + + public String getSourceAddress() + { + return mMessage.getHex( SOURCE_ADDRESS, 6 ); + } +} diff --git a/src/decode/p25/message/tsbk/ChannelGrant.java b/src/decode/p25/message/tsbk/ChannelGrant.java index 75ad811a..4e26914f 100644 --- a/src/decode/p25/message/tsbk/ChannelGrant.java +++ b/src/decode/p25/message/tsbk/ChannelGrant.java @@ -2,19 +2,19 @@ package decode.p25.message.tsbk; 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.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; public abstract class ChannelGrant extends ServiceMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { public static final int[] PRIORITY = { 85,86,87 }; public static final int[] CHANNEL_IDENTIFIER = { 88,89,90,91 }; public static final int[] CHANNEL_NUMBER = { 92,93,94,95,96,97,98,99,100, 101,102,103 }; - private IdentifierUpdate mIdentifierUpdate; + private IdentifierProvider mIdentifierUpdate; public ChannelGrant( BitSetBuffer message, DataUnitID duid, @@ -47,7 +47,7 @@ public abstract class ChannelGrant extends ServiceMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { mIdentifierUpdate = message; } diff --git a/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java b/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java index deb47589..99d6e2ce 100644 --- a/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java +++ b/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java @@ -2,7 +2,7 @@ package decode.p25.message.tsbk; import alias.AliasList; import bits.BitSetBuffer; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; +import decode.p25.message.IdentifierProvider; import decode.p25.reference.DataUnitID; public abstract class GroupChannelGrantExplicit extends ChannelGrant @@ -16,8 +16,8 @@ public abstract class GroupChannelGrantExplicit extends ChannelGrant public static final int[] GROUP_ADDRESS = { 128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143 }; - private IdentifierUpdate mTransmitIdentifierUpdate; - private IdentifierUpdate mReceiveIdentifierUpdate; + private IdentifierProvider mTransmitIdentifierUpdate; + private IdentifierProvider mReceiveIdentifierUpdate; public GroupChannelGrantExplicit( BitSetBuffer message, DataUnitID duid, @@ -85,7 +85,7 @@ public abstract class GroupChannelGrantExplicit extends ChannelGrant } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/message/tsbk/GroupMultiChannelGrant.java b/src/decode/p25/message/tsbk/GroupMultiChannelGrant.java index c70cd54f..e07427e5 100644 --- a/src/decode/p25/message/tsbk/GroupMultiChannelGrant.java +++ b/src/decode/p25/message/tsbk/GroupMultiChannelGrant.java @@ -2,12 +2,12 @@ package decode.p25.message.tsbk; 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.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; public abstract class GroupMultiChannelGrant extends ChannelGrant - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { public static final int[] CHANNEL_IDENTIFIER_1 = { 80,81,82,83 }; public static final int[] CHANNEL_NUMBER_1 = { 84,85,86,87, @@ -21,8 +21,8 @@ public abstract class GroupMultiChannelGrant extends ChannelGrant public static final int[] GROUP_ADDRESS_2 = { 128,129,130,131,132,133,134, 135,136,137,138,139,140,141,142,143 }; - private IdentifierUpdate mIdentifierUpdate1; - private IdentifierUpdate mIdentifierUpdate2; + private IdentifierProvider mIdentifierUpdate1; + private IdentifierProvider mIdentifierUpdate2; public GroupMultiChannelGrant( BitSetBuffer message, DataUnitID duid, @@ -114,7 +114,7 @@ public abstract class GroupMultiChannelGrant extends ChannelGrant } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getChannelIdentifier1() ) { diff --git a/src/decode/p25/message/tsbk/TSBKMessage.java b/src/decode/p25/message/tsbk/TSBKMessage.java index 18f67861..74e57d5b 100644 --- a/src/decode/p25/message/tsbk/TSBKMessage.java +++ b/src/decode/p25/message/tsbk/TSBKMessage.java @@ -2,14 +2,13 @@ package decode.p25.message.tsbk; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCP25; import decode.p25.message.P25Message; import decode.p25.message.tsbk.motorola.MotorolaOpcode; import decode.p25.message.tsbk.vendor.VendorOpcode; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; import decode.p25.reference.Vendor; +import edac.CRC; public class TSBKMessage extends P25Message { diff --git a/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java b/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java index 01d9bdf9..5d126d03 100644 --- a/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java +++ b/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java @@ -2,12 +2,12 @@ package decode.p25.message.tsbk.motorola; 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.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; public class ChannelCWIDUpdate extends MotorolaTSBKMessage - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { public static final int[] CHARACTER_1 = { 80,81,82,83,84,85 }; public static final int[] CHARACTER_2 = { 86,87,88,89,90,91 }; @@ -22,7 +22,7 @@ public class ChannelCWIDUpdate extends MotorolaTSBKMessage public static final int[] CHANNEL = { 132,133,134,135,136,137,138,139,140, 141,142,143 }; - private IdentifierUpdate mIdentifierUpdate; + private IdentifierProvider mIdentifierUpdate; public ChannelCWIDUpdate( BitSetBuffer message, DataUnitID duid, @@ -104,7 +104,7 @@ public class ChannelCWIDUpdate extends MotorolaTSBKMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { mIdentifierUpdate = message; } diff --git a/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java b/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java index 0b7cd475..ae688465 100644 --- a/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java +++ b/src/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java @@ -2,11 +2,12 @@ package decode.p25.message.tsbk.osp.control; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.tsbk.TSBKMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; -public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierUpdateReceiver +public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierProviderReceiver { public static final int[] LOCATION_REGISTRATION_AREA = { 80,81,82,83,84,85, 86,87 }; @@ -24,7 +25,7 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierUp public static final int[] SYSTEM_SERVICE_CLASS = { 136,137,138,139,140,141, 142,143 }; - private IdentifierUpdate mIdentifierUpdate; + private IdentifierProvider mIdentifierUpdate; public AdjacentStatusBroadcast( BitSetBuffer message, DataUnitID duid, @@ -161,7 +162,7 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierUp } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { /* we're only expecting 1 identifier, so use whatever is received */ mIdentifierUpdate = message; diff --git a/src/decode/p25/message/tsbk/osp/control/IdentifierProviderReceiver.java b/src/decode/p25/message/tsbk/osp/control/IdentifierProviderReceiver.java new file mode 100644 index 00000000..e93db470 --- /dev/null +++ b/src/decode/p25/message/tsbk/osp/control/IdentifierProviderReceiver.java @@ -0,0 +1,15 @@ +package decode.p25.message.tsbk.osp.control; + +import decode.p25.message.IdentifierProvider; + +/** + * Interface to allow messages to be augmented with IdentiferUpdateXXX type + * messages that provide the channel information necessary to calculate the + * uplink and downlink frequency for the channel. + */ +public interface IdentifierProviderReceiver +{ + public void setIdentifierMessage( int identifier, IdentifierProvider message ); + + public int[] getIdentifiers(); +} diff --git a/src/decode/p25/message/tsbk/osp/control/IdentifierUpdate.java b/src/decode/p25/message/tsbk/osp/control/IdentifierUpdate.java index 5481954b..8ca820c8 100644 --- a/src/decode/p25/message/tsbk/osp/control/IdentifierUpdate.java +++ b/src/decode/p25/message/tsbk/osp/control/IdentifierUpdate.java @@ -2,10 +2,12 @@ package decode.p25.message.tsbk.osp.control; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.tsbk.TSBKMessage; import decode.p25.reference.DataUnitID; -public abstract class IdentifierUpdate extends TSBKMessage +public abstract class IdentifierUpdate extends TSBKMessage + implements IdentifierProvider { public static final int[] IDENTIFIER = { 80,81,82,83 }; @@ -23,29 +25,24 @@ public abstract class IdentifierUpdate extends TSBKMessage super( message, duid, aliasList ); } - /** - * (Band) Identifier - */ + @Override public int getIdentifier() { return mMessage.getInt( IDENTIFIER ); } - /** - * Channel spacing in hertz - */ + @Override public long getChannelSpacing() { return mMessage.getLong( CHANNEL_SPACING ) * 125l; } - /** - * Base frequency in hertz - */ + @Override public long getBaseFrequency() { return mMessage.getLong( BASE_FREQUENCY ) * 5l; } + @Override public abstract long getTransmitOffset(); } diff --git a/src/decode/p25/message/tsbk/osp/control/IdentifierUpdateReceiver.java b/src/decode/p25/message/tsbk/osp/control/IdentifierUpdateReceiver.java index 6c5ca26e..32c280af 100644 --- a/src/decode/p25/message/tsbk/osp/control/IdentifierUpdateReceiver.java +++ b/src/decode/p25/message/tsbk/osp/control/IdentifierUpdateReceiver.java @@ -1,5 +1,7 @@ package decode.p25.message.tsbk.osp.control; +import decode.p25.message.IdentifierProvider; + /** * Interface to allow messages to be augmented with IdentiferUpdateXXX type * messages that provide the channel information necessary to calculate the @@ -7,7 +9,7 @@ package decode.p25.message.tsbk.osp.control; */ public interface IdentifierUpdateReceiver { - public void setIdentifierMessage( int identifier, IdentifierUpdate message ); + public void setIdentifierMessage( int identifier, IdentifierProvider message ); public int[] getIdentifiers(); } diff --git a/src/decode/p25/message/tsbk/osp/control/MessageUpdate.java b/src/decode/p25/message/tsbk/osp/control/MessageUpdate.java index 34f74bb5..7dd33641 100644 --- a/src/decode/p25/message/tsbk/osp/control/MessageUpdate.java +++ b/src/decode/p25/message/tsbk/osp/control/MessageUpdate.java @@ -8,13 +8,13 @@ import decode.p25.reference.Opcode; public class MessageUpdate extends TSBKMessage { - public static final int[] SHORT_DATA_MESSAGE = { 80,81,82,83,84,85,86,87,88,89,90,91, - 92,93,94,95 }; + public static final int[] SHORT_DATA_MESSAGE = { 80,81,82,83,84,85,86,87,88,89,90,91, + 92,93,94,95 }; public static final int[] TARGET_ADDRESS = { 96,97,98,99,100,101,102,103, - 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119 }; + 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119 }; public static final int[] SOURCE_ADDRESS = { 120,121,122,123,124,125,126, - 127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143 }; - + 127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143 }; + public MessageUpdate( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) diff --git a/src/decode/p25/message/tsbk/osp/control/NetworkStatusBroadcast.java b/src/decode/p25/message/tsbk/osp/control/NetworkStatusBroadcast.java index 3445cb01..cd21e449 100644 --- a/src/decode/p25/message/tsbk/osp/control/NetworkStatusBroadcast.java +++ b/src/decode/p25/message/tsbk/osp/control/NetworkStatusBroadcast.java @@ -2,12 +2,13 @@ package decode.p25.message.tsbk.osp.control; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.tsbk.TSBKMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; import decode.p25.reference.P25NetworkCallsign; -public class NetworkStatusBroadcast extends TSBKMessage implements IdentifierUpdateReceiver +public class NetworkStatusBroadcast extends TSBKMessage implements IdentifierProviderReceiver { public static final int[] LOCATION_REGISTRATION_AREA = { 80,81,82,83,84,85, 86,87 }; @@ -21,7 +22,7 @@ public class NetworkStatusBroadcast extends TSBKMessage implements IdentifierUpd public static final int[] SYSTEM_SERVICE_CLASS = { 136,137,138,139,140,141, 142,143 }; - private IdentifierUpdate mIdentifierUpdate; + private IdentifierProvider mIdentifierUpdate; public NetworkStatusBroadcast( BitSetBuffer message, DataUnitID duid, @@ -107,7 +108,7 @@ public class NetworkStatusBroadcast extends TSBKMessage implements IdentifierUpd } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { /* we're only expecting 1 identifier, so use whatever is received */ mIdentifierUpdate = message; diff --git a/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java b/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java index 06560cdb..e9c960e1 100644 --- a/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java +++ b/src/decode/p25/message/tsbk/osp/control/RFSSStatusBroadcast.java @@ -2,11 +2,12 @@ package decode.p25.message.tsbk.osp.control; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.tsbk.TSBKMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; -public class RFSSStatusBroadcast extends TSBKMessage implements IdentifierUpdateReceiver +public class RFSSStatusBroadcast extends TSBKMessage implements IdentifierProviderReceiver { public static final int[] LOCATION_REGISTRATION_AREA = { 80,81,82,83,84,85, 86,87 }; @@ -21,7 +22,7 @@ public class RFSSStatusBroadcast extends TSBKMessage implements IdentifierUpdate public static final int[] SYSTEM_SERVICE_CLASS = { 136,137,138,139,140,141, 142,143 }; - private IdentifierUpdate mIdentifierUpdate; + private IdentifierProvider mIdentifierUpdate; public RFSSStatusBroadcast( BitSetBuffer message, DataUnitID duid, @@ -117,7 +118,7 @@ public class RFSSStatusBroadcast extends TSBKMessage implements IdentifierUpdate } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { /* we're only expecting 1 identifier, so use whatever is received */ mIdentifierUpdate = message; diff --git a/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java b/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java index f7509660..1d58d1be 100644 --- a/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java +++ b/src/decode/p25/message/tsbk/osp/control/SecondaryControlChannelBroadcast.java @@ -5,12 +5,13 @@ import org.slf4j.LoggerFactory; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.IdentifierProvider; import decode.p25.message.tsbk.TSBKMessage; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; public class SecondaryControlChannelBroadcast extends TSBKMessage - implements IdentifierUpdateReceiver, Comparable + implements IdentifierProviderReceiver, Comparable { private final static Logger mLog = LoggerFactory.getLogger( SecondaryControlChannelBroadcast.class ); @@ -28,8 +29,8 @@ public class SecondaryControlChannelBroadcast extends TSBKMessage public static final int[] SYSTEM_SERVICE_CLASS_2 = { 136,137,138,139,140, 141,142,143 }; - private IdentifierUpdate mIdentifierUpdate1; - private IdentifierUpdate mIdentifierUpdate2; + private IdentifierProvider mIdentifierUpdate1; + private IdentifierProvider mIdentifierUpdate2; public SecondaryControlChannelBroadcast( BitSetBuffer message, DataUnitID duid, @@ -143,7 +144,7 @@ public class SecondaryControlChannelBroadcast extends TSBKMessage } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getIdentifier1() ) { diff --git a/src/decode/p25/message/tsbk/osp/control/StatusUpdate.java b/src/decode/p25/message/tsbk/osp/control/StatusUpdate.java index 091557c4..dfce3b1f 100644 --- a/src/decode/p25/message/tsbk/osp/control/StatusUpdate.java +++ b/src/decode/p25/message/tsbk/osp/control/StatusUpdate.java @@ -8,12 +8,12 @@ import decode.p25.reference.Opcode; public class StatusUpdate extends TSBKMessage { - public static final int[] USER_STATUS = { 80,81,82,83,84,85,86,87 }; - public static final int[] UNIT_STATUS = { 88,89,90,91,92,93,94,95 }; - public static final int[] TARGET_ADDRESS = { 96,97,98,99,100,101,102,103, - 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119 }; - public static final int[] SOURCE_ADDRESS = { 120,121,122,123,124,125,126, - 127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143 }; + public static final int[] USER_STATUS = { 72,73,74,75,88,89,90,91 }; + public static final int[] UNIT_STATUS = { 92,93,94,95,96,97,98,99 }; + public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118, + 119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 }; + public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166, + 167,168,169,170,171,184,185,186,187,188,189,190,190,192,193,194,195 }; public StatusUpdate( BitSetBuffer message, DataUnitID duid, @@ -25,7 +25,7 @@ public class StatusUpdate extends TSBKMessage @Override public String getEventType() { - return Opcode.STATUS_QUERY.getDescription(); + return Opcode.STATUS_UPDATE.getDescription(); } public String getMessage() diff --git a/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelAnnouncementExplicit.java b/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelAnnouncementExplicit.java index 35972a24..4929cead 100644 --- a/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelAnnouncementExplicit.java +++ b/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelAnnouncementExplicit.java @@ -2,12 +2,12 @@ package decode.p25.message.tsbk.osp.data; 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.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; public class SNDCPDataChannelAnnouncementExplicit extends SNDCPData - implements IdentifierUpdateReceiver + implements IdentifierProviderReceiver { public static final int AUTONOMOUS_ACCESS_AVAILABLE_INDICATOR = 88; public static final int REQUESTED_ACCESS_AVAILABLE_INDICATOR = 89; @@ -22,8 +22,8 @@ public class SNDCPDataChannelAnnouncementExplicit extends SNDCPData public static final int[] DATA_ACCESS_CONTROL = { 128,129,130,131,132,133, 134,135,136,137,138,139,140,141,142,143 }; - private IdentifierUpdate mIdentifierUpdateTransmit; - private IdentifierUpdate mIdentifierUpdateReceive; + private IdentifierProvider mIdentifierUpdateTransmit; + private IdentifierProvider mIdentifierUpdateReceive; public SNDCPDataChannelAnnouncementExplicit( BitSetBuffer message, DataUnitID duid, @@ -118,7 +118,7 @@ public class SNDCPDataChannelAnnouncementExplicit extends SNDCPData } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelGrant.java b/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelGrant.java index 4d15b678..ce2abe4d 100644 --- a/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelGrant.java +++ b/src/decode/p25/message/tsbk/osp/data/SNDCPDataChannelGrant.java @@ -2,11 +2,11 @@ package decode.p25.message.tsbk.osp.data; 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.IdentifierProvider; +import decode.p25.message.tsbk.osp.control.IdentifierProviderReceiver; import decode.p25.reference.DataUnitID; -public class SNDCPDataChannelGrant extends SNDCPData implements IdentifierUpdateReceiver +public class SNDCPDataChannelGrant extends SNDCPData implements IdentifierProviderReceiver { public static final int[] TRANSMIT_IDENTIFIER = { 88,89,90,91 }; public static final int[] TRANSMIT_NUMBER = { 92,93,94,95,96,97,98,99,100, @@ -18,8 +18,8 @@ public class SNDCPDataChannelGrant extends SNDCPData implements IdentifierUpdate public static final int[] TARGET_ADDRESS = { 120,121,122,123,124,125,126, 127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143 }; - private IdentifierUpdate mIdentifierUpdateTransmit; - private IdentifierUpdate mIdentifierUpdateReceive; + private IdentifierProvider mIdentifierUpdateTransmit; + private IdentifierProvider mIdentifierUpdateReceive; public SNDCPDataChannelGrant( BitSetBuffer message, DataUnitID duid, @@ -91,7 +91,7 @@ public class SNDCPDataChannelGrant extends SNDCPData implements IdentifierUpdate } @Override - public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + public void setIdentifierMessage( int identifier, IdentifierProvider message ) { if( identifier == getTransmitChannelIdentifier() ) { diff --git a/src/decode/p25/reference/DataUnitID.java b/src/decode/p25/reference/DataUnitID.java index 54e1ce0a..4e318b2e 100644 --- a/src/decode/p25/reference/DataUnitID.java +++ b/src/decode/p25/reference/DataUnitID.java @@ -7,7 +7,7 @@ package decode.p25.reference; public enum DataUnitID { NID ( -1, 64, false, "NID ", "Network and Data Unit ID" ), - HDU ( 0, 722, false, "HDU ", "Header Data Unit" ), + HDU ( 0, 712, false, "HDU ", "Header Data Unit" ), TDU ( 3, 64, false, "TDU ", "Simple Terminator Data Unit" ), LDU1 ( 5, 1630, true, "LDU1 ", "Logical Link Data Unit 1" ), TSBK1( 7, 260, false, "TSBK1", "Trunking Signaling Block" ), @@ -15,9 +15,10 @@ public enum DataUnitID TSBK3( 7, 260, false, "TSBK3", "Trunking Signaling Block" ), LDU2 ( 10, 1632, true, "LDU2 ", "Logical Link Data Unit 2" ), 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" ), + PDU1 ( 12, 356, false, "PDU1 ", "Packet Data Unit-Unconfirmed" ), + PDU2 ( 12, 452, false, "PDU2 ", "Packet Data Unit-Unconfirmed" ), + PDU3 ( 12, 548, false, "PDU3 ", "Packet Data Unit-Unconfirmed" ), + PDUC ( 12, 356, false, "PDUC", "Packet Data Unit-Confirmed" ), TDULC( 15, 352, false, "TDULC", "Terminator Data Unit With Link Control" ), UNKN ( -1, 0, false, "UNKWN", "Unknown" ); diff --git a/src/decode/p25/reference/LinkControlOpcode.java b/src/decode/p25/reference/LinkControlOpcode.java new file mode 100644 index 00000000..00262831 --- /dev/null +++ b/src/decode/p25/reference/LinkControlOpcode.java @@ -0,0 +1,106 @@ +package decode.p25.reference; + +public enum LinkControlOpcode +{ + GROUP_VOICE_CHANNEL_USER( "GRP_VCH_USER ", "Group Voice Channel User", 0 ), + RESERVED_01( "RESERVED_01 ", "Reserved", 1 ), + GROUP_VOICE_CHANNEL_UPDATE( "GRP_VCH_UPDATE ", "Group Voice Channel Grant Update", 2 ), + UNIT_TO_UNIT_VOICE_CHANNEL_USER( "UU_VCH_USER ", "Unit-to-Unit Voice Channel User", 3 ), + GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT( "GRP_VCH_UPD_EXPL", "Group Voice Channel Update Explicit", 4 ), + UNIT_TO_UNIT_ANSWER_REQUEST( "UU_ANS_REQ ", "Unit-to-Unit Answer Request", 5 ), + TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER( "TEL_INT_VCH_USER", "Telephone Interconnect Voice Channel User", 6 ), + TELEPHONE_INTERCONNECT_ANSWER_REQUEST( "TEL_INT_ANS_RQST", "Telephone Interconnect Answer Request", 7 ), + RESERVED_08( "RESERVED_08 ", "Reserved", 8 ), + RESERVED_09( "RESERVED_09 ", "Reserved", 9 ), + RESERVED_0A( "RESERVED_0A ", "Reserved", 10 ), + RESERVED_0B( "RESERVED_0B ", "Reserved", 11 ), + RESERVED_0C( "RESERVED_0C ", "Reserved", 12 ), + RESERVED_0D( "RESERVED_0D ", "Reserved", 13 ), + RESERVED_0E( "RESERVED_0E ", "Reserved", 14 ), + CALL_TERMINATION_OR_CANCELLATION( "CALL TERMINATION", "Call Termination Cancellation", 15 ), + GROUP_AFFILIATION_QUERY( "GRP_AFFIL_QUERY ", "Group Affiliation Query", 16 ), + UNIT_REGISTRATION_COMMAND( "UNIT_REG_COMMAND", "Unit Registration Command", 17 ), + UNIT_AUTHENTICATION_COMMAND( "UNIT_AUTHEN_CMD ", "Unit Authentication Command", 18 ), + STATUS_QUERY( "STATUS QUERY ", "Status Query", 19 ), + STATUS_UPDATE( "STATUS_UPDATE ", "Status Update", 20 ), + MESSAGE_UPDATE( "MESSAGE UPDATE ", "Message Update", 21 ), + CALL_ALERT( "CALL ALERT", "Call Alert", 22 ), + EXTENDED_FUNCTION_COMMAND( "EXT FUNC COMMAND", "Extended Function Command", 23 ), + CHANNEL_IDENTIFIER_UPDATE( "CHAN IDEN UPDATE", "Channel Identifier Update", 24 ), + CHANNEL_IDENTIFIER_UPDATE_EXPLICIT( "CHAN IDEN UPD EX", "Channel Identifier Update Explicit", 25 ), + RESERVED_1A( "RESERVED_1A ", "Reserved", 26 ), + RESERVED_1B( "RESERVED_1B ", "Reserved", 27 ), + RESERVED_1C( "RESERVED_1C ", "Reserved", 28 ), + RESERVED_1D( "RESERVED_1D ", "Reserved", 29 ), + RESERVED_1E( "RESERVED_1E ", "Reserved", 30 ), + RESERVED_1F( "RESERVED_1F ", "Reserved", 31 ), + SYSTEM_SERVICE_BROADCAST( "SYS_SVC_BCAST ", "System Service Broadcast", 32 ), + SECONDARY_CONTROL_CHANNEL_BROADCAST( "SEC_CCH_BROADCST", "Secondary Control Channel Broadcast", 33 ), + ADJACENT_SITE_STATUS_BROADCAST( "ADJ SITE STATUS ", "Adjacent Site Status Broadcast", 34 ), + RFSS_STATUS_BROADCAST( "RFSS_STATUS_BCST", "RFSS Status Broadcast", 35 ), + NETWORK_STATUS_BROADCAST( "NET_STATUS_BCAST", "Network Status Broadcast", 36 ), + PROTECTION_PARAMETER_BROADCAST( "ENCRYPT_PAR_BCST", "Protection Parameter Broadcast", 37 ), + SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT( "SCCB_CCH_BCST_EX", "Secondary Control Channel Broadcast-Explicit", 38 ), + ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT( "ADJ SITE STAT EX", "Adjacent Site Status Broadcast Explicit", 39 ), + RFSS_STATUS_BROADCAST_EXPLICIT( "RFSS STAT BCST E", "RFSS Status Broadcast Explicit", 40 ), + NETWORK_STATUS_BROADCAST_EXPLICIT( "NET STAT BCAST E", "Network Status Broadcast", 41 ), + RESERVED_2A( "RESERVED_2A ", "Reserved", 42 ), + RESERVED_2B( "RESERVED_2B ", "Reserved", 43 ), + RESERVED_2C( "RESERVED_2C ", "Reserved", 44 ), + RESERVED_2D( "RESERVED_2D ", "Reserved", 45 ), + RESERVED_2E( "RESERVED_2E ", "Reserved", 46 ), + RESERVED_2F( "RESERVED_2F ", "Reserved", 47 ), + RESERVED_30( "RESERVED_30 ", "Reserved", 48 ), + RESERVED_31( "RESERVED_31 ", "Reserved", 49 ), + RESERVED_32( "RESERVED_32 ", "Reserved", 50 ), + RESERVED_33( "RESERVED_33 ", "Reserved", 51 ), + RESERVED_34( "RESERVED_34 ", "Reserved", 52 ), + RESERVED_35( "RESERVED_35 ", "Reserved", 53 ), + RESERVED_36( "RESERVED_36 ", "Reserved", 54 ), + RESERVED_37( "RESERVED_37 ", "Reserved", 55 ), + RESERVED_38( "RESERVED_38 ", "Reserved", 56 ), + RESERVED_39( "RESERVED_39 ", "Reserved", 57 ), + RESERVED_3A( "RESERVED_3A ", "Reserved", 58 ), + RESERVED_3B( "RESERVED_3B ", "Reserved", 59 ), + RESERVED_3C( "RESERVED_3C ", "Reserved", 60 ), + RESERVED_3D( "RESERVED_3D ", "Reserved", 61 ), + RESERVED_3E( "RESERVED_3E ", "Reserved", 62 ), + RESERVED_3F( "RESERVED_3F ", "Reserved", 63 ), + UNKNOWN( "UNKNOWN ", "Unknown", -1 ); + + private String mLabel; + private String mDescription; + private int mCode; + + private LinkControlOpcode( String label, String description, int code ) + { + mLabel = label; + mDescription = description; + mCode = code; + } + + public String getLabel() + { + return mLabel; + } + + public String getDescription() + { + return mDescription; + } + + public int getCode() + { + return mCode; + } + + public static LinkControlOpcode fromValue( int value ) + { + if( 0 <= value && value <= 63 ) + { + return values()[ value ]; + } + + return UNKNOWN; + } +} diff --git a/src/decode/p25/reference/Opcode.java b/src/decode/p25/reference/Opcode.java index d5b09c5e..f76c8f21 100644 --- a/src/decode/p25/reference/Opcode.java +++ b/src/decode/p25/reference/Opcode.java @@ -62,7 +62,7 @@ public enum Opcode SECONDARY_CONTROL_CHANNEL_BROADCAST( "SEC_CCH_BROADCST", "Secondary Control Channel Broadcast", 57 ), RFSS_STATUS_BROADCAST( "RFSS_STATUS_BCST", "RFSS Status Broadcast", 58 ), NETWORK_STATUS_BROADCAST( "NET_STATUS_BCAST", "Network Status Broadcast", 59 ), - ADJACENT_STATUS_BROADCAST( "NGHBR_STAT_BCAST", "Adjacent Status Broadcast", 60 ), + ADJACENT_STATUS_BROADCAST( "ADJ SITE STATUS ", "Adjacent Site Status Broadcast", 60 ), IDENTIFIER_UPDATE_NON_VUHF( "IDEN_UPDATE ", "Identifier Update", 61 ), PROTECTION_PARAMETER_BROADCAST( "ENCRYPT_PAR_BCST", "Protection Parameter Broadcast", 62 ), PROTECTION_PARAMETER_UPDATE( "ENCRYPT_PAR_UPDT", "Protection Parameter Update", 63 ), diff --git a/src/decode/p25/reference/PDUFormat.java b/src/decode/p25/reference/PDUFormat.java index 244f9b86..fdec7b7c 100644 --- a/src/decode/p25/reference/PDUFormat.java +++ b/src/decode/p25/reference/PDUFormat.java @@ -24,7 +24,7 @@ public enum PDUFormat F19( "F19", 19 ), F20( "F20", 20 ), UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL( "UNCONFIRMED MBTC", 21 ), - F22( "F22", 22 ), + PACKET_DATA( "PACKET DATA", 22 ), ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL( "ALTERNATE MBTC", 23 ), F24( "F24", 24 ), F25( "F25", 25 ), diff --git a/src/decode/p25/reference/VendorLinkControlOpcode.java b/src/decode/p25/reference/VendorLinkControlOpcode.java new file mode 100644 index 00000000..886a49cf --- /dev/null +++ b/src/decode/p25/reference/VendorLinkControlOpcode.java @@ -0,0 +1,106 @@ +package decode.p25.reference; + +public enum VendorLinkControlOpcode +{ + RESERVED_00( "RESERVED_00 ", "Reserved", 0 ), + RESERVED_01( "RESERVED_01 ", "Reserved", 1 ), + RESERVED_02( "RESERVED_02 ", "Reserved", 2 ), + RESERVED_03( "RESERVED_03 ", "Reserved", 3 ), + RESERVED_04( "RESERVED_04 ", "Reserved", 4 ), + RESERVED_05( "RESERVED_05 ", "Reserved", 5 ), + RESERVED_06( "RESERVED_06 ", "Reserved", 6 ), + RESERVED_07( "RESERVED_07 ", "Reserved", 7 ), + RESERVED_08( "RESERVED_0B ", "Reserved", 8 ), + RESERVED_09( "RESERVED_0B ", "Reserved", 9 ), + RESERVED_0A( "RESERVED_0B ", "Reserved", 10 ), + RESERVED_0B( "RESERVED_0B ", "Reserved", 11 ), + RESERVED_0C( "RESERVED_0C ", "Reserved", 12 ), + RESERVED_0D( "RESERVED_0D ", "Reserved", 13 ), + RESERVED_0E( "RESERVED_0E ", "Reserved", 14 ), + RESERVED_0F( "RESERVED_0F ", "Reserved", 15 ), + RESERVED_10( "RESERVED_10 ", "Reserved", 16 ), + RESERVED_11( "RESERVED_11 ", "Reserved", 17 ), + RESERVED_12( "RESERVED_12 ", "Reserved", 18 ), + RESERVED_13( "RESERVED_13 ", "Reserved", 19 ), + RESERVED_14( "RESERVED_14 ", "Reserved", 20 ), + RESERVED_15( "RESERVED_15 ", "Reserved", 21 ), + RESERVED_16( "RESERVED_16 ", "Reserved", 22 ), + RESERVED_17( "RESERVED_17 ", "Reserved", 23 ), + RESERVED_18( "RESERVED_18 ", "Reserved", 24 ), + RESERVED_19( "RESERVED_19 ", "Reserved", 25 ), + RESERVED_1A( "RESERVED_1A ", "Reserved", 26 ), + RESERVED_1B( "RESERVED_1B ", "Reserved", 27 ), + RESERVED_1C( "RESERVED_1C ", "Reserved", 28 ), + RESERVED_1D( "RESERVED_1D ", "Reserved", 29 ), + RESERVED_1E( "RESERVED_1E ", "Reserved", 30 ), + RESERVED_1F( "RESERVED_1F ", "Reserved", 31 ), + RESERVED_20( "RESERVED_20 ", "Reserved", 32 ), + RESERVED_21( "RESERVED_21 ", "Reserved", 33 ), + RESERVED_22( "RESERVED_22 ", "Reserved", 34 ), + RESERVED_23( "RESERVED_23 ", "Reserved", 35 ), + RESERVED_24( "RESERVED_24 ", "Reserved", 36 ), + RESERVED_25( "RESERVED_25 ", "Reserved", 37 ), + RESERVED_26( "RESERVED_26 ", "Reserved", 38 ), + RESERVED_27( "RESERVED_27 ", "Reserved", 39 ), + RESERVED_28( "RESERVED_28 ", "Reserved", 40 ), + RESERVED_29( "RESERVED_29 ", "Reserved", 41 ), + RESERVED_2A( "RESERVED_2A ", "Reserved", 42 ), + RESERVED_2B( "RESERVED_2B ", "Reserved", 43 ), + RESERVED_2C( "RESERVED_2C ", "Reserved", 44 ), + RESERVED_2D( "RESERVED_2D ", "Reserved", 45 ), + RESERVED_2E( "RESERVED_2E ", "Reserved", 46 ), + RESERVED_2F( "RESERVED_2F ", "Reserved", 47 ), + RESERVED_30( "RESERVED_30 ", "Reserved", 48 ), + RESERVED_31( "RESERVED_31 ", "Reserved", 49 ), + RESERVED_32( "RESERVED_32 ", "Reserved", 50 ), + RESERVED_33( "RESERVED_33 ", "Reserved", 51 ), + RESERVED_34( "RESERVED_34 ", "Reserved", 52 ), + RESERVED_35( "RESERVED_35 ", "Reserved", 53 ), + RESERVED_36( "RESERVED_36 ", "Reserved", 54 ), + RESERVED_37( "RESERVED_37 ", "Reserved", 55 ), + RESERVED_38( "RESERVED_38 ", "Reserved", 56 ), + RESERVED_39( "RESERVED_39 ", "Reserved", 57 ), + RESERVED_3A( "RESERVED_3A ", "Reserved", 58 ), + RESERVED_3B( "RESERVED_3B ", "Reserved", 59 ), + RESERVED_3C( "RESERVED_3C ", "Reserved", 60 ), + RESERVED_3D( "RESERVED_3D ", "Reserved", 61 ), + RESERVED_3E( "RESERVED_3E ", "Reserved", 62 ), + RESERVED_3F( "RESERVED_3F ", "Reserved", 63 ), + UNKNOWN( "UNKNOWN ", "Unknown", -1 ); + + private String mLabel; + private String mDescription; + private int mCode; + + private VendorLinkControlOpcode( String label, String description, int code ) + { + mLabel = label; + mDescription = description; + mCode = code; + } + + public String getLabel() + { + return mLabel; + } + + public String getDescription() + { + return mDescription; + } + + public int getCode() + { + return mCode; + } + + public static VendorLinkControlOpcode fromValue( int value ) + { + if( 0 <= value && value <= 63 ) + { + return values()[ value ]; + } + + return UNKNOWN; + } +} diff --git a/src/decode/passport/PassportMessage.java b/src/decode/passport/PassportMessage.java index 801be7de..29ace89e 100644 --- a/src/decode/passport/PassportMessage.java +++ b/src/decode/passport/PassportMessage.java @@ -27,9 +27,9 @@ import message.MessageType; import alias.Alias; import alias.AliasList; import bits.BitSetBuffer; -import crc.CRC; -import crc.CRCPassport; import decode.DecoderType; +import edac.CRC; +import edac.CRCPassport; public class PassportMessage extends Message { diff --git a/src/dsp/fsk/P25MessageFramer.java b/src/dsp/fsk/P25MessageFramer.java index 7d64c6e1..0e54d66d 100644 --- a/src/dsp/fsk/P25MessageFramer.java +++ b/src/dsp/fsk/P25MessageFramer.java @@ -12,21 +12,24 @@ import alias.AliasList; import bits.BitSetBuffer; import bits.BitSetFullException; import bits.SyncPatternMatcher; -import crc.CRC; -import crc.CRCP25; import decode.p25.P25Interleave; import decode.p25.TrellisHalfRate; import decode.p25.message.P25Message; 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.tdu.TDULCMessage; import decode.p25.message.tdu.TDUMessage; +import decode.p25.message.tdu.lc.TDULCMessageFactory; +import decode.p25.message.tdu.lc.TDULinkControlMessage; import decode.p25.message.tsbk.TSBKMessage; import decode.p25.message.tsbk.TSBKMessageFactory; import decode.p25.reference.DataUnitID; +import edac.CRC; +import edac.CRCP25; public class P25MessageFramer implements Listener { @@ -227,13 +230,13 @@ public class P25MessageFramer implements Listener { case NID: CRC crc = CRCP25.correctNID( mMessage ); - + if( crc != CRC.FAILED_CRC ) { int value = mMessage.getInt( P25Message.DUID ); DataUnitID duid = DataUnitID.fromValue( value ); - + if( duid != DataUnitID.UNKN ) { setDUID( duid ); @@ -254,7 +257,12 @@ public class P25MessageFramer implements Listener break; case LDU1: mComplete = true; - dispatch( new LDU1Message( mMessage.copy(), mDUID, mAliasList ) ); + + LDU1Message ldu1 = new LDU1Message( mMessage.copy(), + mDUID, mAliasList ); + + /* Convert the LDU1 message into a link control LDU1 message */ + dispatch( LDULCMessageFactory.getMessage( ldu1 ) ); break; case LDU2: mComplete = true; @@ -262,7 +270,7 @@ public class P25MessageFramer implements Listener break; case PDU0: /* Remove interleaving */ - P25Interleave.deinterleave( mMessage, PDU0_BEGIN, PDU0_END ); + P25Interleave.deinterleaveData( mMessage, PDU0_BEGIN, PDU0_END ); /* Remove trellis encoding - abort processing if we have an * unsuccessful decode due to excessive errors */ @@ -271,9 +279,21 @@ public class P25MessageFramer implements Listener CRC pduCRC = CRCP25.correctCCITT80( mMessage, PDU0_BEGIN, PDU0_CRC_BEGIN ); + if( pduCRC != CRC.FAILED_CRC ) { - setDUID( DataUnitID.PDU1 ); + boolean confirmed = mMessage.get( + PDUMessage.CONFIRMATION_REQUIRED_INDICATOR ); + + if( confirmed ) + { + setDUID( DataUnitID.PDUC ); + + } + else + { + setDUID( DataUnitID.PDU1 ); + } mMessage.setPointer( PDU1_BEGIN ); } @@ -289,7 +309,7 @@ public class P25MessageFramer implements Listener break; case PDU1: /* Remove interleaving */ - P25Interleave.deinterleave( mMessage, PDU1_BEGIN, PDU1_END ); + P25Interleave.deinterleaveData( mMessage, PDU1_BEGIN, PDU1_END ); /* Remove trellis encoding - abort processing if we have an * unsuccessful decode due to excessive errors */ @@ -320,7 +340,7 @@ public class P25MessageFramer implements Listener break; case PDU2: /* Remove interleaving */ - P25Interleave.deinterleave( mMessage, PDU2_BEGIN, PDU2_END ); + P25Interleave.deinterleaveData( mMessage, PDU2_BEGIN, PDU2_END ); /* Remove trellis encoding - abort processing if we have an * unsuccessful decode due to excessive errors */ @@ -351,7 +371,7 @@ public class P25MessageFramer implements Listener break; case PDU3: /* Remove interleaving */ - P25Interleave.deinterleave( mMessage, PDU3_BEGIN, PDU3_END ); + P25Interleave.deinterleaveData( mMessage, PDU3_BEGIN, PDU3_END ); /* Remove trellis encoding - abort processing if we have an * unsuccessful decode due to excessive errors */ @@ -367,20 +387,45 @@ public class P25MessageFramer implements Listener mComplete = true; break; + case PDUC: + int blocks = mMessage.getInt( PDUMessage.BLOCKS_TO_FOLLOW ); + + int current = ( mMessage.size() - 260 ) / 196; + + if( current < blocks ) + { + mMessageLength += 196; + mMessage.setSize( mMessage.size() + 196 ); + } + else + { + dispatch( new PDUConfirmedMessage( mMessage.copy(), + mDUID, mAliasList ) ); + + mComplete = true; + } + break; case TDU: dispatch( new TDUMessage( mMessage.copy(), mDUID, mAliasList ) ); mComplete = true; break; case TDULC: - dispatch( new TDULCMessage( mMessage.copy(), mDUID, mAliasList ) ); + TDULinkControlMessage tdulc = new TDULinkControlMessage( + mMessage.copy(), mDUID, mAliasList ); + + /* Convert to an appropriate link control message */ + tdulc = TDULCMessageFactory.getMessage( tdulc ); + + dispatch( tdulc ); mComplete = true; break; case TSBK1: /* Remove interleaving */ - P25Interleave.deinterleave( mMessage, TSBK_BEGIN, TSBK_END ); + P25Interleave.deinterleaveData( mMessage, TSBK_BEGIN, TSBK_END ); /* Remove trellis encoding - abort processing if we have an * unsuccessful decode due to excessive errors */ + if( mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END ) ) { CRC tsbkCRC = CRCP25.correctCCITT80( mMessage, @@ -418,7 +463,7 @@ public class P25MessageFramer implements Listener break; case TSBK2: /* Remove interleaving */ - P25Interleave.deinterleave( mMessage, TSBK_BEGIN, TSBK_END ); + P25Interleave.deinterleaveData( mMessage, TSBK_BEGIN, TSBK_END ); /* Remove trellis encoding - abort processing if we have an * unsuccessful decode due to excessive errors */ @@ -459,7 +504,7 @@ public class P25MessageFramer implements Listener break; case TSBK3: /* Remove interleaving */ - P25Interleave.deinterleave( mMessage, TSBK_BEGIN, TSBK_END ); + P25Interleave.deinterleaveData( mMessage, TSBK_BEGIN, TSBK_END ); /* Remove trellis encoding - abort processing if we have an * unsuccessful decode due to excessive errors */ diff --git a/src/crc/CRC.java b/src/edac/CRC.java similarity index 99% rename from src/crc/CRC.java rename to src/edac/CRC.java index a1f95764..c81f7b80 100644 --- a/src/crc/CRC.java +++ b/src/edac/CRC.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; public enum CRC { diff --git a/src/crc/CRCFleetsync.java b/src/edac/CRCFleetsync.java similarity index 99% rename from src/crc/CRCFleetsync.java rename to src/edac/CRCFleetsync.java index f04a83ac..1533e2ca 100644 --- a/src/crc/CRCFleetsync.java +++ b/src/edac/CRCFleetsync.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import java.util.BitSet; diff --git a/src/crc/CRCLJ.java b/src/edac/CRCLJ.java similarity index 99% rename from src/crc/CRCLJ.java rename to src/edac/CRCLJ.java index ece41bea..51f3e425 100644 --- a/src/crc/CRCLJ.java +++ b/src/edac/CRCLJ.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import java.util.BitSet; diff --git a/src/crc/CRCLTR.java b/src/edac/CRCLTR.java similarity index 99% rename from src/crc/CRCLTR.java rename to src/edac/CRCLTR.java index 34bc07da..1440a7f5 100644 --- a/src/crc/CRCLTR.java +++ b/src/edac/CRCLTR.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import java.util.BitSet; diff --git a/src/crc/CRCP25.java b/src/edac/CRCP25.java similarity index 96% rename from src/crc/CRCP25.java rename to src/edac/CRCP25.java index 8d4a407d..913ee651 100644 --- a/src/crc/CRCP25.java +++ b/src/edac/CRCP25.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +31,7 @@ public class CRCP25 private static final int NID_MESSAGE_START = 0; private static final int NID_CRC_START = 16; - private static final int NID_CRC_LENGTH = 48; + private static final int NID_CRC_END = 48; /** * Network ID and Data Unit ID checksums @@ -241,7 +241,7 @@ public class CRCP25 calculated ^= NID_DUID_CHECKSUMS[ i - NID_MESSAGE_START ]; } - long checksum = getLongChecksum( message, NID_CRC_START, NID_CRC_LENGTH ); + long checksum = getLongChecksum( message, NID_CRC_START, NID_CRC_END ); if( calculated == checksum ) { @@ -367,6 +367,28 @@ public class CRCP25 return CRC.FAILED_CRC; } + + /** + * Performs Galois 24/12/7 error detection and correction against the 12 + * encoded 24-bit message segments following the 64-bit NID in the message + * + * @return - true if all 12 segments of the message can be checked/corrected + */ + public static boolean correctGalois24( BitSetBuffer tdulc ) + { + boolean passes = true; + + int x = 64; + + while( x < tdulc.size() && passes ) + { + passes = Galois24.checkAndCorrect( tdulc, x ); + + x += 24; + } + + return passes; + } /** @@ -375,7 +397,7 @@ public class CRCP25 public static long getLongChecksum( BitSetBuffer message, int crcStart, int crcLength ) { - return message.getLong( crcStart, crcStart + crcLength ); + return message.getLong( crcStart, crcStart + crcLength - 1 ); } /** @@ -384,7 +406,7 @@ public class CRCP25 public static int getIntChecksum( BitSetBuffer message, int crcStart, int crcLength ) { - return message.getInt( crcStart, crcStart + crcLength ); + return message.getInt( crcStart, crcStart + crcLength - 1 ); } /** diff --git a/src/crc/CRCPassport.java b/src/edac/CRCPassport.java similarity index 99% rename from src/crc/CRCPassport.java rename to src/edac/CRCPassport.java index d5bb9dee..7546835e 100644 --- a/src/crc/CRCPassport.java +++ b/src/edac/CRCPassport.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import java.util.BitSet; diff --git a/src/crc/CRCUtil.java b/src/edac/CRCUtil.java similarity index 99% rename from src/crc/CRCUtil.java rename to src/edac/CRCUtil.java index 3d33f037..2c47ce52 100644 --- a/src/crc/CRCUtil.java +++ b/src/edac/CRCUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/crc/Checksum.java b/src/edac/Checksum.java similarity index 99% rename from src/crc/Checksum.java rename to src/edac/Checksum.java index bf7d8b27..a80b5841 100644 --- a/src/crc/Checksum.java +++ b/src/edac/Checksum.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import java.util.BitSet; diff --git a/src/crc/ChecksumTest.java b/src/edac/ChecksumTest.java similarity index 99% rename from src/crc/ChecksumTest.java rename to src/edac/ChecksumTest.java index bd0bd1dc..0d645f5e 100644 --- a/src/crc/ChecksumTest.java +++ b/src/edac/ChecksumTest.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; import java.util.BitSet; diff --git a/src/crc/ChecksumType.java b/src/edac/ChecksumType.java similarity index 99% rename from src/crc/ChecksumType.java rename to src/edac/ChecksumType.java index 42d9d6d1..af47d73b 100644 --- a/src/crc/ChecksumType.java +++ b/src/edac/ChecksumType.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ -package crc; +package edac; public enum ChecksumType { diff --git a/src/crc/Galois24.java b/src/edac/Galois24.java similarity index 97% rename from src/crc/Galois24.java rename to src/edac/Galois24.java index e84bc70d..b5553919 100644 --- a/src/crc/Galois24.java +++ b/src/edac/Galois24.java @@ -1,4 +1,4 @@ -package crc; +package edac; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,7 +82,6 @@ public class Galois24 int index = -1; int syndromeWeight = 3; - int maskBit = 0; int errors = 0; while( index < 23 ) @@ -92,10 +91,10 @@ public class Galois24 /* restore the previous flipped bit */ if( index > 0 ) { - message.flip( maskBit - 1 ); + message.flip( index - 1 ); } - message.flip( maskBit ); + message.flip( index ); syndromeWeight = 2; } diff --git a/src/edac/ReedSolomon.java b/src/edac/ReedSolomon.java new file mode 100644 index 00000000..f37628f7 --- /dev/null +++ b/src/edac/ReedSolomon.java @@ -0,0 +1,543 @@ +package edac; + +/******************************************************************************* + * 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 + * + * -------------------------------------------------------------------- + * Based on Ed Fuentetaja's DSD RS decoder, May 2014, at: + * https://github.com/szechyjs/dsd/blob/master/ReedSolomon.hpp + * -------------------------------------------------------------------- + * Adapted from Mr. Simon Rockliff's version at: http://www.eccpage.com/rs.c + * + * Simon Rockliff, University of Adelaide 21/9/89 + * 26/6/91 Slight modifications to remove a compiler dependent bug which + * hadn't previously surfaced. A few extra comments added for clarity. + * Appears to all work fine, ready for posting to net! + * + * Notice + * -------- + * This program may be freely modified and/or given to whoever wants it. + * A condition of such distribution is that the author's contribution be + * acknowledged by his name being left in the comments heading the program, + * however no responsibility is accepted for any financial or other loss which + * may result from some unforseen errors or malfunctioning of the program + * during use. + * Simon Rockliff, 26th June 1991 + ******************************************************************************/ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReedSolomon +{ + public final static Logger mLog = LoggerFactory.getLogger( ReedSolomon.class ); + + /* Golay field size GF( 2 ** MM ) */ + private static final int MM = 6; + + /* Codeword Length: NN = 2 ** MM - 1 */ + private static final int NN = 63; + + /* Hamming distance between codewords: NN - KK + 1 = 2 * TT + 1 */ + private static int KK; + + /* Maximum number of errors that can be corrected */ + int TT; + + int[] alpha_to; + int[] index_of; + int[] gg; + + public ReedSolomon( int tt ) + { + TT = tt; + KK = NN - 2 * TT; + + alpha_to = new int[ NN + 1 ]; + index_of = new int[ NN + 1 ]; + gg = new int[ NN - KK + 1 ]; + + /* P25 generator polynomial */ + int generator_polinomial[] = { 1, 1, 0, 0, 0, 0, 1 }; + + generate_gf( generator_polinomial ); + + gen_poly(); + } + + /** + * Generates the Golay Field. + * + * Generates a GF( 2**mm ) from the irreducible polynomial + * p(X) in pp[0]..pp[mm] + * + * Lookup tables: + * index_of[] = polynomial form + * alpha_to[] = contains j=alpha**i; + * + * Polynomial form -> Index form index_of[j=alpha**i] = i + * + * alpha_to = 2 is the primitive element of GF( 2**mm ) + * + * @param generator_polinomial + */ + private void generate_gf( int[] generator_polinomial ) + { + int i; + int mask = 1; + + alpha_to[ MM ] = 0; + + for( i = 0; i < MM; i++ ) + { + alpha_to[ i ] = mask; + index_of[ alpha_to[ i ] ] = i; + + if( generator_polinomial[ i ] != 0 ) + { + alpha_to[ MM ] ^= mask; + } + + mask <<= 1; + } + + index_of[ alpha_to[ MM ] ] = MM; + + mask >>= 1; + + for ( i = MM + 1; i < NN; i++ ) + { + if( alpha_to[ i - 1 ] >= mask ) + { + alpha_to[ i ] = alpha_to[ MM ] ^ ( ( alpha_to[ i - 1 ] ^ mask ) << 1 ); + } + else + { + alpha_to[ i ] = alpha_to[ i - 1 ] << 1; + } + + index_of[ alpha_to[ i ] ] = i; + } + + index_of[ 0 ] = -1; + } + + /** + * Generates the polynomial for a TT-error correction code. + * + * Length NN = ( 2 ** MM -1 ) Reed Solomon code from the product of + * (X+alpha**i), i=1..2*tt + */ + private void gen_poly() + { + int i, j; + + gg[ 0 ] = 2; /* primitive element alpha = 2 for GF(2**mm) */ + gg[ 1 ] = 1; /* g(x) = (X+alpha) initially */ + for( i = 2; i <= NN - KK; i++ ) + { + gg[ i ] = 1; + + for( j = i - 1; j > 0; j-- ) + { + if( gg[ j ] != 0 ) + { + gg[ j ] = gg[ j - 1 ] ^ alpha_to[ ( index_of[ gg[ j ] ] + i ) % NN ]; + } + else + { + gg[ j ] = gg[ j - 1 ]; + } + } + + /* gg[0] can never be zero */ + gg[ 0 ] = alpha_to[ ( index_of[ gg[ 0 ] ] + i ) % NN ]; + } + + /* convert gg[] to index form for quicker encoding */ + for( i = 0; i <= NN - KK; i++ ) + { + gg[ i ] = index_of[ gg[ i ] ]; + } + } + + /** + * Decodes + * @param input + * @param recd + * @return + */ + /* assume we have received bits grouped into mm-bit symbols in recd[i], + i=0..(nn-1), and recd[i] is polynomial form. + We first compute the 2*tt syndromes by substituting alpha**i into rec(X) and + evaluating, storing the syndromes in s[i], i=1..2tt (leave s[0] zero) . + Then we use the Berlekamp iteration to find the error location polynomial + elp[i]. If the degree of the elp is >tt, we cannot correct all the errors + and hence just put out the information symbols uncorrected. If the degree of + elp is <=tt, we substitute alpha**i , i=1..n into the elp to get the roots, + hence the inverse roots, the error location numbers. If the number of errors + located does not equal the degree of the elp, we have more than tt errors + and cannot correct them. Otherwise, we then solve for the error value at + the error location and correct the error. The procedure is that found in + Lin and Costello. For the cases where the number of errors is known to be too + large to correct, the information symbols as received are output (the + advantage of systematic encoding is that hopefully some of the information + symbols will be okay and that if we are in luck, the errors are in the + parity part of the transmitted codeword). Of course, these insoluble cases + can be returned as error flags to the calling routine if desired. */ + public boolean decode( final int[] input, int[] recd ) //input, output + { + int u, q; + int[][] elp = new int[ NN - KK + 2 ][ NN - KK ]; + int[] d = new int[ NN - KK + 2 ]; + int[] l = new int[ NN - KK + 2 ]; + int[] u_lu = new int[ NN - KK + 2 ]; + int[] s = new int[ NN - KK + 1 ]; + int count = 0; + boolean syn_error = false; + int[] root = new int[ TT ]; + int[] loc = new int[ TT ]; + int[] z = new int[ TT + 1 ]; + int[] err = new int[ NN ]; + int[] reg = new int[ TT + 1 ]; + + boolean irrecoverable_error = false; + + /* put recd[i] into index form (ie as powers of alpha) */ + for( int i = 0; i < NN; i++ ) + { + recd[ i ] = index_of[ input[ i ] ]; + } + + /* first form the syndromes */ + for( int i = 1; i <= NN - KK; i++ ) + { + s[ i ] = 0; + + for( int j = 0; j < NN; j++ ) + { + if( recd[ j ] != -1 ) + { + /* recd[j] in index form */ + s[ i ] ^= alpha_to[ ( recd[ j ] + i * j ) % NN ]; + } + } + + /* convert syndrome from polynomial form to index form */ + if( s[ i ] != 0 ) + { + /* set flag if non-zero syndrome => error */ + syn_error = true; + } + + s[ i ] = index_of[ s[ i ] ]; + } + + if( syn_error ) /* if errors, try and correct */ + { + /* compute the error location polynomial via the Berlekamp iterative algorithm, + following the terminology of Lin and Costello : d[u] is the 'mu'th + discrepancy, where u='mu'+1 and 'mu' (the Greek letter!) is the step number + ranging from -1 to 2*tt (see L&C), l[u] is the + degree of the elp at that step, and u_l[u] is the difference between the + step number and the degree of the elp. + */ + + /* initialise table entries */ + d[ 0 ] = 0; /* index form */ + d[ 1 ] = s[ 1 ]; /* index form */ + elp[ 0 ][ 0 ] = 0; /* index form */ + elp[ 1 ][ 0 ] = 1; /* polynomial form */ + + for( int i = 1; i < NN - KK; i++ ) + { + elp[ 0 ][ i ] = -1; /* index form */ + elp[ 1 ][ i ] = 0; /* polynomial form */ + } + + l[ 0 ] = 0; + l[ 1 ] = 0; + u_lu[ 0 ] = -1; + u_lu[ 1 ] = 0; + u = 0; + + do + { + u++; + + if( d[ u ] == -1 ) + { + l[ u + 1 ] = l[ u ]; + + for( int i = 0; i <= l[ u ]; i++ ) + { + elp[ u + 1 ][ i ] = elp[ u ][ i ]; + elp[ u ][ i ] = index_of[ elp[ u ][ i ] ]; + } + } + else + /* search for words with greatest u_lu[q] for which d[q]!=0 */ + { + q = u - 1; + + while( ( d[ q ] == -1 ) && ( q > 0 ) ) + { + q--; + } + + /* have found first non-zero d[q] */ + if( q > 0 ) + { + int j = q; + + do + { + j--; + + if( ( d[ j ] != -1 ) && ( u_lu[ q ] < u_lu[ j ] ) ) + { + q = j; + } + } + while( j > 0 ); + }; + + /* have now found q such that d[u]!=0 and u_lu[q] is maximum */ + /* store degree of new elp polynomial */ + if( l[ u ] > l[ q ] + u - q ) + { + l[ u + 1 ] = l[ u ]; + } + else + { + l[ u + 1 ] = l[ q ] + u - q; + } + + /* form new elp(x) */ + for( int i = 0; i < NN - KK; i++ ) + { + elp[ u + 1 ][ i ] = 0; + } + + for( int i = 0; i <= l[q]; i++ ) + { + if( elp[ q ][ i ] != -1 ) + { + elp[ u + 1 ][ i + u - q ] = + alpha_to[ ( d[ u ] + NN - d[ q ] + + elp[ q ][ i ]) % NN ]; + } + } + for( int i = 0; i <= l[u]; i++ ) + { + elp[ u + 1 ][ i ] ^= elp[ u ][ i ]; + elp[ u ][ i ] = index_of[ elp[ u ][ i ] ]; /*convert old elp value to index*/ + } + } + + u_lu[ u + 1 ] = u - l[ u + 1 ]; + + /* form (u+1)th discrepancy */ + if( u < NN - KK ) /* no discrepancy computed on last iteration */ + { + if ( s[ u + 1 ] != -1 ) + { + d[ u + 1 ] = alpha_to[ s[ u + 1 ] ]; + } + else + { + d[ u + 1 ] = 0; + } + for( int i = 1; i <= l[ u + 1 ]; i++ ) + { + if( ( s[ u + 1 - i ] != -1 ) && ( elp[ u + 1 ][ i] != 0 ) ) + { + d[ u + 1 ] ^= alpha_to[ ( s[ u + 1 - i ] + + index_of[ elp[ u + 1 ][ i ] ] ) % NN ]; + } + } + + d[ u + 1 ] = index_of[ d[ u + 1 ] ]; /* put d[u+1] into index form */ + } + } + while( ( u < NN - KK ) && ( l[ u + 1 ] <= TT) ); + + u++; + + if( l[ u ] <= TT ) /* can correct error */ + { + /* put elp into index form */ + for( int i = 0; i <= l[u]; i++ ) + { + elp[ u ][ i ] = index_of[ elp[ u ][ i ] ]; + } + + /* find roots of the error location polynomial */ + for( int i = 1; i <= l[u]; i++ ) + { + reg[ i ] = elp[ u ][ i ]; + } + + count = 0; + + for( int i = 1; i <= NN; i++ ) + { + q = 1; + + for( int j = 1; j <= l[u]; j++ ) + { + if( reg[ j ] != -1 ) + { + reg[ j ] = ( reg[ j ] + j ) % NN; + q ^= alpha_to[ reg[ j ] ]; + }; + } + + if( q == 0 ) /* store root and error location number indices */ + { + root[ count ] = i; + loc[ count ] = NN - i; + count++; + }; + }; + + if( count == l[ u ] ) /* no. roots = degree of elp hence <= tt errors */ + { + /* form polynomial z(x) */ + for( int i = 1; i <= l[ u ]; i++ ) /* Z[0] = 1 always - do not need */ + { + if( ( s[ i ] != -1 ) && ( elp[ u ][ i ] != -1 ) ) + { + z[ i ] = alpha_to[ s[ i ] ] ^ alpha_to[ elp[ u ][ i ] ]; + } + else if( ( s[ i ] != -1 ) && ( elp[ u ][ i ] == -1 ) ) + { + z[ i ] = alpha_to[ s[ i ] ]; + } + else if( ( s[ i ] == -1 ) && ( elp[ u ][ i ] != -1 ) ) + { + z[ i ] = alpha_to[ elp[ u ][ i ] ]; + } + else + { + z[ i ] = 0; + } + + for( int j = 1; j < i; j++ ) + { + if( ( s[ j ] != -1 ) && ( elp[ u ][ i - j ] != -1 ) ) + { + z[ i ] ^= alpha_to[ ( elp[ u ][ i - j ] + s[ j ] ) % NN ]; + } + } + + z[ i ] = index_of[ z[ i ] ]; /* put into index form */ + }; + + /* evaluate errors at locations given by error location numbers loc[i] */ + for( int i = 0; i < NN; i++ ) + { + err[ i ] = 0; + + if( recd[ i ] != -1 ) /* convert recd[] to polynomial form */ + { + recd[ i ] = alpha_to[ recd[ i ] ]; + } + else + { + recd[ i ] = 0; + } + } + + for( int i = 0; i < l[ u ]; i++ ) /* compute numerator of error term first */ + { + err[ loc[ i ] ] = 1; /* accounts for z[0] */ + + for( int j = 1; j <= l[ u ]; j++ ) + { + if( z[ j ] != -1 ) + { + err[ loc[ i ] ] ^= alpha_to[ ( z[ j ] + j * root[ i ] ) % NN ]; + } + } + + if( err[ loc[ i ] ] != 0 ) + { + err[ loc[ i ] ] = index_of[ err[ loc[ i ] ] ]; + + q = 0; /* form denominator of error term */ + + for (int j = 0; j < l[u]; j++) + { + if (j != i) + { + q += index_of[1 ^ alpha_to[(loc[j] + root[i]) % NN]]; + } + } + + q = q % NN; + err[loc[i]] = alpha_to[(err[loc[i]] - q + NN) % NN]; + recd[loc[i]] ^= err[loc[i]]; /*recd[i] must be in polynomial form */ + } + } + } + else + { + /* no. roots != degree of elp => >tt errors and cannot solve */ + irrecoverable_error = true; + } + + } + else + { + /* elp has degree >tt hence cannot solve */ + irrecoverable_error = true; + } + } + else + { + /* no non-zero syndromes => no errors: output received codeword */ + for (int i = 0; i < NN; i++) + { + if (recd[i] != -1) /* convert recd[] to polynomial form */ + { + recd[i] = alpha_to[recd[i]]; + } + else + { + recd[i] = 0; + } + } + } + + if( irrecoverable_error ) + { + for (int i = 0; i < NN; i++) /* could return error flag if desired */ + { + if (recd[i] != -1) /* convert recd[] to polynomial form */ + { + recd[i] = alpha_to[recd[i]]; + } + else + { + recd[i] = 0; /* just output received codeword as is */ + } + } + } + + return irrecoverable_error; + } +} diff --git a/src/edac/ReedSolomon_24_12_13.java b/src/edac/ReedSolomon_24_12_13.java new file mode 100644 index 00000000..00da4573 --- /dev/null +++ b/src/edac/ReedSolomon_24_12_13.java @@ -0,0 +1,31 @@ +package edac; + +/******************************************************************************* + * 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 + ******************************************************************************/ + +public class ReedSolomon_24_12_13 extends ReedSolomon +{ + /** + * Reed-Solomon RS(24,12,13) decoder + */ + public ReedSolomon_24_12_13() + { + /* TT = 6 = maximum correctable bit errors */ + super( 6 ); + } +} diff --git a/src/instrument/gui/DecoderViewFrame.java b/src/instrument/gui/DecoderViewFrame.java index 939f8788..ecd3c993 100644 --- a/src/instrument/gui/DecoderViewFrame.java +++ b/src/instrument/gui/DecoderViewFrame.java @@ -282,6 +282,6 @@ public class DecoderViewFrame extends JInternalFrame @Override public void receive( Message message ) { - mLog.info( "Decoder message: " + message.toString() ); + mLog.info( message.toString() ); } } diff --git a/src/test/TestCRC.java b/src/test/TestCRC.java index e09bdb0a..46c54f01 100644 --- a/src/test/TestCRC.java +++ b/src/test/TestCRC.java @@ -19,7 +19,7 @@ package test; import java.util.BitSet; -import crc.CRCLTR; +import edac.CRCLTR; public class TestCRC