From 170688b95e9d28e9015743811ae89286891587b3 Mon Sep 17 00:00:00 2001 From: "dennis.sheirer" Date: Sun, 14 Dec 2014 02:34:19 +0000 Subject: [PATCH] P25 Work in progress. Adds CRC checking to NID/DUID. Adds limiter to trellis decoder to prevent it from decoding an excessive error message. Updates channel state with initial handling/generation of call events. --- src/controller/BaseNode.java | 2 +- .../ControllerTreeCellRenderer.java | 27 ++- src/controller/activity/CallEvent.java | 3 +- src/controller/activity/CallEventModel.java | 11 +- src/controller/channel/ChannelNode.java | 2 +- src/controller/site/SiteNode.java | 6 +- src/controller/system/SystemNode.java | 6 +- src/crc/BCH.java | 13 - src/crc/CRCP25NetworkID.java | 179 ++++++++++++++ src/decode/fleetsync2/FleetsyncCallEvent.java | 4 +- src/decode/lj1200/LJ1200CallEvent.java | 4 +- src/decode/ltrnet/LTRCallEvent.java | 10 +- src/decode/ltrnet/LTRNetChannelState.java | 8 +- src/decode/ltrstandard/LTRChannelState.java | 2 +- src/decode/mdc1200/MDCCallEvent.java | 4 +- src/decode/mpt1327/MPT1327CallEvent.java | 10 +- src/decode/mpt1327/MPT1327ChannelState.java | 12 +- src/decode/p25/P25CallEvent.java | 24 +- src/decode/p25/P25ChannelState.java | 120 +++++++++- src/decode/p25/P25Panel.java | 2 +- src/decode/p25/TrellisHalfRate.java | 68 +++--- .../message/filter/P25MessageFilterSet.java | 2 +- .../p25/message/filter/TSBKMessageFilter.java | 54 ----- .../message/filter/TSBKMessageFilterSet.java | 200 ++++++++++++++++ src/decode/p25/message/tsbk/ChannelGrant.java | 38 ++- .../p25/message/tsbk/GroupChannelGrant.java | 14 +- .../tsbk/GroupChannelGrantExplicit.java | 38 +++ src/decode/p25/message/tsbk/TSBKMessage.java | 13 +- .../p25/message/tsbk/TSBKMessageFactory.java | 4 +- .../tsbk/motorola/ChannelCWIDUpdate.java | 105 ++------ .../message/tsbk/motorola/MotorolaOpcode.java | 81 ++++++- .../message/tsbk/motorola/SystemLoading.java | 2 +- .../control/LocationRegistrationResponse.java | 2 +- .../osp/control/TimeAndDateAnnouncement.java | 3 +- .../osp/voice/GroupVoiceChannelGrant.java | 1 + ...elephoneInterconnectVoiceChannelGrant.java | 2 +- .../voice/UnitToUnitVoiceChannelGrant.java | 25 ++ .../p25/message/tsbk/vendor/VendorOpcode.java | 111 +++++++++ .../p25/reference/ServiceAccessPoint.java | 36 +-- src/decode/passport/PassportCallEvent.java | 10 +- src/decode/passport/PassportChannelState.java | 6 +- src/dsp/fsk/P25MessageFramer.java | 225 +++++++++++------- 42 files changed, 1099 insertions(+), 390 deletions(-) delete mode 100644 src/crc/BCH.java create mode 100644 src/crc/CRCP25NetworkID.java delete mode 100644 src/decode/p25/message/filter/TSBKMessageFilter.java create mode 100644 src/decode/p25/message/filter/TSBKMessageFilterSet.java create mode 100644 src/decode/p25/message/tsbk/vendor/VendorOpcode.java diff --git a/src/controller/BaseNode.java b/src/controller/BaseNode.java index 18dea516..89bbdfa6 100644 --- a/src/controller/BaseNode.java +++ b/src/controller/BaseNode.java @@ -58,7 +58,7 @@ public class BaseNode extends DefaultMutableTreeNode return null; } - public Color getForegroundColor() + public Color getBackgroundColor() { return null; } diff --git a/src/controller/ControllerTreeCellRenderer.java b/src/controller/ControllerTreeCellRenderer.java index fff54227..fc1ef590 100644 --- a/src/controller/ControllerTreeCellRenderer.java +++ b/src/controller/ControllerTreeCellRenderer.java @@ -54,11 +54,32 @@ public class ControllerTreeCellRenderer extends DefaultTreeCellRenderer setIcon( icon ); - Color foreground = node.getForegroundColor(); + Color background = node.getBackgroundColor(); - if( foreground != null ) + if( background != null ) { - setForeground( foreground ); + setBackground( background ); + setOpaque( true ); + + if( selected ) + { + if( background == Color.CYAN ) + { + setForeground( Color.ORANGE ); + } + else if( background == Color.GREEN ) + { + setForeground( Color.MAGENTA ); + } + else if( background == Color.RED ) + { + setForeground( Color.YELLOW ); + } + } + } + else + { + setOpaque( false ); } } diff --git a/src/controller/activity/CallEvent.java b/src/controller/activity/CallEvent.java index e84722f2..52a2a568 100644 --- a/src/controller/activity/CallEvent.java +++ b/src/controller/activity/CallEvent.java @@ -127,7 +127,7 @@ public abstract class CallEvent public abstract Alias getToIDAlias(); - public abstract int getChannel(); + public abstract String getChannel(); public abstract long getFrequency(); @@ -216,6 +216,7 @@ public abstract class CallEvent CALL_UNIQUE_ID( "UID Call" ), CALL_NO_TUNER( "Call - No Tuner" ), CALL_TIMEOUT( "Call Timeout" ), + DEREGISTER( "Deregister" ), EMERGENCY( "EMERGENCY" ), GPS( "GPS" ), ID_ANI( "ANI" ), diff --git a/src/controller/activity/CallEventModel.java b/src/controller/activity/CallEventModel.java index 1cee1526..5ba9da80 100644 --- a/src/controller/activity/CallEventModel.java +++ b/src/controller/activity/CallEventModel.java @@ -296,16 +296,7 @@ public class CallEventModel extends AbstractTableModel case TO_ALIAS: return mEvents.get( rowIndex ).getToIDAlias(); case CHANNEL: - int channel = mEvents.get( rowIndex ).getChannel(); - - if( channel != 0 ) - { - return channel; - } - else - { - return null; - } + return mEvents.get( rowIndex ).getChannel(); case FREQUENCY: long frequency = mEvents.get( rowIndex ).getFrequency(); diff --git a/src/controller/channel/ChannelNode.java b/src/controller/channel/ChannelNode.java index 281e2c52..de687f37 100644 --- a/src/controller/channel/ChannelNode.java +++ b/src/controller/channel/ChannelNode.java @@ -104,7 +104,7 @@ public class ChannelNode extends ConfigurableNode implements ChannelEventListene } @Override - public Color getForegroundColor() + public Color getBackgroundColor() { if( getChannel().getEnabled() ) { diff --git a/src/controller/site/SiteNode.java b/src/controller/site/SiteNode.java index f37014e8..21ec08d8 100644 --- a/src/controller/site/SiteNode.java +++ b/src/controller/site/SiteNode.java @@ -64,7 +64,7 @@ public class SiteNode extends ConfigurableNode } @Override - public Color getForegroundColor() + public Color getBackgroundColor() { @SuppressWarnings( "unchecked" ) Enumeration nodes = children(); @@ -73,9 +73,9 @@ public class SiteNode extends ConfigurableNode { ChannelNode child = (ChannelNode)nodes.nextElement(); - if( child.getForegroundColor() != null ) + if( child.getBackgroundColor() != null ) { - return Color.BLUE; + return Color.CYAN; } } diff --git a/src/controller/system/SystemNode.java b/src/controller/system/SystemNode.java index bab503e7..e5f2e13f 100644 --- a/src/controller/system/SystemNode.java +++ b/src/controller/system/SystemNode.java @@ -64,7 +64,7 @@ public class SystemNode extends ConfigurableNode } @Override - public Color getForegroundColor() + public Color getBackgroundColor() { @SuppressWarnings( "unchecked" ) Enumeration nodes = children(); @@ -73,9 +73,9 @@ public class SystemNode extends ConfigurableNode { SiteNode child = (SiteNode)nodes.nextElement(); - if( child.getForegroundColor() != null ) + if( child.getBackgroundColor() != null ) { - return Color.BLUE; + return Color.CYAN; } } diff --git a/src/crc/BCH.java b/src/crc/BCH.java deleted file mode 100644 index 470a7ae6..00000000 --- a/src/crc/BCH.java +++ /dev/null @@ -1,13 +0,0 @@ -package crc; - -import java.util.BitSet; - -public class BCH -{ - public BCH( int n, int k, int t, boolean[] polynomial, boolean sys ) - { - int[] exponents = new int[ n - k + 1 ]; - - - } -} diff --git a/src/crc/CRCP25NetworkID.java b/src/crc/CRCP25NetworkID.java new file mode 100644 index 00000000..cf4763f8 --- /dev/null +++ b/src/crc/CRCP25NetworkID.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * SDR Trunk + * Copyright (C) 2014 Dennis Sheirer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + ******************************************************************************/ +package crc; + +import java.util.BitSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import bits.BitSetBuffer; + +/** + * P25 Data Unit ID CRC check utility. Corrects any single bit errors in + * either the message or the crc checksum. + */ +public class CRCP25NetworkID +{ + private final static Logger mLog = LoggerFactory.getLogger( CRCP25NetworkID.class ); + + private static final int MESSAGE_START = 0; + private static final int CRC_START = 16; + private static final int CRC_END = 64; + + private static long[] CHECKSUMS = new long[] + { + 0xCD930BDD3B2Al, //NAC Bit 11 (MSB) + 0xAB5A8E33A6BEl, //NAC Bit 10 + 0x983E4CC4E874l, //NAC Bit 9 + 0x4C1F2662743Al, //NAC Bit 8 + 0xEB9C98EC0136l, //NAC Bit 7 + 0xB85D47AB3BB0l, //NAC Bit 6 + 0x5C2EA3D59DD8l, //NAC Bit 5 + 0x2E1751EACEECl, //NAC Bit 4 + 0x170BA8F56776l, //NAC Bit 3 + 0xC616DFA78890l, //NAC Bit 2 + 0x630B6FD3C448l, //NAC Bit 1 + 0x3185B7E9E224l, //NAC Bit 0 (LSB) + 0x18C2DBF4F112l, //DUID Bit 3 (MSB) + 0xC1F2662743A2l, //DUID Bit 2 + 0xAD6A38CE9AFBl, //DUID Bit 1 + 0x9B2617BA7657l, //DUID Bit 0 (LSB) + + //Single bit errors in the CRC Checksum + 0x800000000000l, + 0x400000000000l, + 0x200000000000l, + 0x100000000000l, + 0x080000000000l, + 0x040000000000l, + 0x020000000000l, + 0x010000000000l, + 0x008000000000l, + 0x004000000000l, + 0x002000000000l, + 0x001000000000l, + 0x000800000000l, + 0x000400000000l, + 0x000200000000l, + 0x000100000000l, + 0x000080000000l, + 0x000040000000l, + 0x000020000000l, + 0x000010000000l, + 0x000008000000l, + 0x000004000000l, + 0x000002000000l, + 0x000001000000l, + 0x000000800000l, + 0x000000400000l, + 0x000000200000l, + 0x000000100000l, + 0x000000080000l, + 0x000000040000l, + 0x000000020000l, + 0x000000010000l, + 0x000000008000l, + 0x000000004000l, + 0x000000002000l, + 0x000000001000l, + 0x000000000800l, + 0x000000000400l, + 0x000000000200l, + 0x000000000100l, + 0x000000000080l, + 0x000000000040l, + 0x000000000020l, + 0x000000000010l, + 0x000000000008l, + 0x000000000004l, + 0x000000000002l, + 0x000000000001l, + }; + + /** + * + */ + public static CRC checkAndCorrect( BitSetBuffer message ) + { + long calculated = 0; //Starting value + + /* Iterate the set bits and XOR running checksum with lookup value */ + for (int i = message.nextSetBit( MESSAGE_START ); + i >= MESSAGE_START && i < CRC_START; + i = message.nextSetBit( i+1 ) ) + { + calculated ^= CHECKSUMS[ i - MESSAGE_START ]; + } + + long checksum = getChecksum( message ); + + if( calculated == checksum ) + { + return CRC.PASSED; + } + else + { + int errorLocation = findBitError( calculated ^ checksum ); + + if( errorLocation >= 0 ) + { + message.flip( errorLocation ); + + return CRC.CORRECTED; + } + } + + return CRC.FAILED_CRC; + } + + /** + * Returns the long value of the 48 bit crc checksum and parity bit + */ + public static long getChecksum( BitSet msg ) + { + long checksum = 0; + + for( int x = CRC_START; x < CRC_END; x++ ) + { + if( msg.get( x ) ) + { + checksum += Long.rotateLeft( 1, CRC_END - 1 - x ); + } + } + + return checksum; + } + + /** + * Identifies any single bit error position that matches the checksum error. + */ + public static int findBitError( long checksumError ) + { + /* One bit errors */ + for( int x = 0; x < 64; x++ ) + { + if( CHECKSUMS[ x ] == checksumError ) + { + return x; + } + } + + return -1; + } +} diff --git a/src/decode/fleetsync2/FleetsyncCallEvent.java b/src/decode/fleetsync2/FleetsyncCallEvent.java index a15bbb0c..91b3552c 100644 --- a/src/decode/fleetsync2/FleetsyncCallEvent.java +++ b/src/decode/fleetsync2/FleetsyncCallEvent.java @@ -57,9 +57,9 @@ public class FleetsyncCallEvent extends CallEvent } @Override - public int getChannel() + public String getChannel() { - return 0; + return null; } @Override diff --git a/src/decode/lj1200/LJ1200CallEvent.java b/src/decode/lj1200/LJ1200CallEvent.java index d205f60f..670be0b2 100644 --- a/src/decode/lj1200/LJ1200CallEvent.java +++ b/src/decode/lj1200/LJ1200CallEvent.java @@ -57,9 +57,9 @@ public class LJ1200CallEvent extends CallEvent } @Override - public int getChannel() + public String getChannel() { - return 0; + return null; } @Override diff --git a/src/decode/ltrnet/LTRCallEvent.java b/src/decode/ltrnet/LTRCallEvent.java index d0690d4c..3368d26d 100644 --- a/src/decode/ltrnet/LTRCallEvent.java +++ b/src/decode/ltrnet/LTRCallEvent.java @@ -25,7 +25,7 @@ import decode.ltrstandard.LTRStandardMessage; public class LTRCallEvent extends CallEvent { - private int mChannel; + private String mChannel; private long mFrequency; private int mValidCallMessages = 1; @@ -33,7 +33,7 @@ public class LTRCallEvent extends CallEvent AliasList aliasList, String fromID, String toID, - int channel, + String channel, long frequency, String details ) { @@ -141,7 +141,7 @@ public class LTRCallEvent extends CallEvent } @Override - public int getChannel() + public String getChannel() { return mChannel; } @@ -162,7 +162,7 @@ public class LTRCallEvent extends CallEvent private String mFromID; private String mToID; private String mDetails; - private int mChannel; + private String mChannel; private long mFrequency; public Builder( CallEventType callEventType ) @@ -182,7 +182,7 @@ public class LTRCallEvent extends CallEvent return this; } - public Builder channel( int channel ) + public Builder channel( String channel ) { mChannel = channel; return this; diff --git a/src/decode/ltrnet/LTRNetChannelState.java b/src/decode/ltrnet/LTRNetChannelState.java index 6674c173..5ed71f21 100644 --- a/src/decode/ltrnet/LTRNetChannelState.java +++ b/src/decode/ltrnet/LTRNetChannelState.java @@ -166,7 +166,7 @@ public class LTRNetChannelState extends ChannelState mCallEventModel.add( new LTRCallEvent.Builder( CallEventType.CALL_DETECT ) .aliasList( mAliasList ) - .channel( ltr.getChannel() ) + .channel( String.valueOf( ltr.getChannel() ) ) .to( ltr.getTalkgroupID() ) .build() ); } @@ -288,7 +288,7 @@ public class LTRNetChannelState extends ChannelState LTRCallEvent event = new LTRCallEvent.Builder( CallEventType.REGISTER ) .aliasList( mAliasList ) - .channel( ltr.getChannel() ) + .channel( String.valueOf( ltr.getChannel() ) ) .frequency( mProcessingChain.getChannel() .getTunerChannel().getFrequency() ) .to( ltr.getTalkgroupID() ) @@ -354,7 +354,7 @@ public class LTRNetChannelState extends ChannelState { event = new LTRCallEvent.Builder( CallEventType.REGISTER ) .aliasList( mAliasList ) - .channel( message.getChannel() ) + .channel( String.valueOf( message.getChannel() ) ) .frequency( mProcessingChain.getChannel() .getTunerChannel().getFrequency() ) .to( message.getTalkgroupID() ) @@ -366,7 +366,7 @@ public class LTRNetChannelState extends ChannelState { event = new LTRCallEvent.Builder( CallEventType.CALL ) .aliasList( mAliasList ) - .channel( message.getChannel() ) + .channel( String.valueOf( message.getChannel() ) ) .frequency( mProcessingChain.getChannel() .getTunerChannel().getFrequency() ) .to( message.getTalkgroupID() ) diff --git a/src/decode/ltrstandard/LTRChannelState.java b/src/decode/ltrstandard/LTRChannelState.java index 0017c440..5563b5bf 100644 --- a/src/decode/ltrstandard/LTRChannelState.java +++ b/src/decode/ltrstandard/LTRChannelState.java @@ -120,7 +120,7 @@ public class LTRChannelState extends ChannelState new LTRCallEvent.Builder( CallEventType.CALL ) .to( ltr.getTalkgroupID() ) .aliasList( getAliasList() ) - .channel( ltr.getChannel() ) + .channel( String.valueOf( ltr.getChannel() ) ) .frequency( ( ltr.getChannel() == mChannelNumber ) ? mProcessingChain.getChannel() .getTunerChannel().getFrequency() : 0 ) diff --git a/src/decode/mdc1200/MDCCallEvent.java b/src/decode/mdc1200/MDCCallEvent.java index b34cb726..1071aba8 100644 --- a/src/decode/mdc1200/MDCCallEvent.java +++ b/src/decode/mdc1200/MDCCallEvent.java @@ -57,9 +57,9 @@ public class MDCCallEvent extends CallEvent } @Override - public int getChannel() + public String getChannel() { - return 0; + return null; } @Override diff --git a/src/decode/mpt1327/MPT1327CallEvent.java b/src/decode/mpt1327/MPT1327CallEvent.java index bca0e9c5..24ed009b 100644 --- a/src/decode/mpt1327/MPT1327CallEvent.java +++ b/src/decode/mpt1327/MPT1327CallEvent.java @@ -24,14 +24,14 @@ import decode.DecoderType; public class MPT1327CallEvent extends CallEvent { - private int mChannel; + private String mChannel; private long mFrequency; public MPT1327CallEvent( CallEventType callEventType, AliasList aliasList, String fromID, String toID, - int channel, + String channel, long frequency, String details ) { @@ -65,7 +65,7 @@ public class MPT1327CallEvent extends CallEvent } @Override - public int getChannel() + public String getChannel() { return mChannel; } @@ -86,7 +86,7 @@ public class MPT1327CallEvent extends CallEvent private String mFromID; private String mToID; private String mDetails; - private int mChannel; + private String mChannel; private long mFrequency; public Builder( CallEventType callEventType ) @@ -106,7 +106,7 @@ public class MPT1327CallEvent extends CallEvent return this; } - public Builder channel( int channel ) + public Builder channel( String channel ) { mChannel = channel; return this; diff --git a/src/decode/mpt1327/MPT1327ChannelState.java b/src/decode/mpt1327/MPT1327ChannelState.java index a4aa3ea6..8b39601c 100644 --- a/src/decode/mpt1327/MPT1327ChannelState.java +++ b/src/decode/mpt1327/MPT1327ChannelState.java @@ -115,7 +115,7 @@ public class MPT1327ChannelState extends ChannelState mCallEventModel.add( new MPT1327CallEvent.Builder( CallEventType.REGISTER ) .aliasList( getProcessingChain().getAliasList() ) - .channel( mChannelNumber ) + .channel( String.valueOf( mChannelNumber ) ) .details( "REGISTERED ON NETWORK" ) .frequency( mChannelMap.getFrequency( mChannelNumber ) ) .from( mpt.getToID() ) @@ -127,7 +127,7 @@ public class MPT1327ChannelState extends ChannelState mCallEventModel.add( new MPT1327CallEvent.Builder( CallEventType.ACKNOWLEDGE ) .aliasList( getProcessingChain().getAliasList() ) - .channel( mChannelNumber ) + .channel( String.valueOf( mChannelNumber ) ) .details( "ACK " + identType.getLabel() ) .frequency( mChannelMap.getFrequency( mChannelNumber ) ) .from( mpt.getFromID() ) @@ -139,7 +139,7 @@ public class MPT1327ChannelState extends ChannelState mCallEventModel.add( new MPT1327CallEvent.Builder( CallEventType.REQUEST ) .aliasList( getProcessingChain().getAliasList() ) - .channel( mChannelNumber ) + .channel( String.valueOf( mChannelNumber ) ) .details( ( (MPT1327Message) message ).getRequestString() ) .frequency( mChannelMap.getFrequency( mChannelNumber ) ) .from( mpt.getFromID() ) @@ -150,7 +150,7 @@ public class MPT1327ChannelState extends ChannelState mCallEventModel.add( new MPT1327CallEvent.Builder( CallEventType.STATUS ) .aliasList( getProcessingChain().getAliasList() ) - .channel( mChannelNumber ) + .channel( String.valueOf( mChannelNumber ) ) .details( mpt.getStatusMessage() ) .frequency( mChannelMap.getFrequency( mChannelNumber ) ) .from( mpt.getFromID() ) @@ -233,7 +233,7 @@ public class MPT1327ChannelState extends ChannelState MPT1327CallEvent callStartEvent = new MPT1327CallEvent.Builder( type ) .aliasList( traffic.getProcessingChain().getAliasList() ) - .channel( channelNumber ) + .channel( String.valueOf( channelNumber ) ) .frequency( mChannelMap.getFrequency( channelNumber ) ) .from( mpt.getFromID() ) .to( mpt.getToID() ) @@ -293,7 +293,7 @@ public class MPT1327ChannelState extends ChannelState mCallEventModel.add( new MPT1327CallEvent.Builder( type ) .aliasList( getAliasList() ) - .channel( mChannelNumber ) + .channel( String.valueOf( mChannelNumber ) ) .frequency( mChannelMap.getFrequency( mChannelNumber ) ) .from( mFromTalkgroup ) .to( mToTalkgroup ) diff --git a/src/decode/p25/P25CallEvent.java b/src/decode/p25/P25CallEvent.java index 22dfdaad..1796a88f 100644 --- a/src/decode/p25/P25CallEvent.java +++ b/src/decode/p25/P25CallEvent.java @@ -24,16 +24,16 @@ import decode.DecoderType; public class P25CallEvent extends CallEvent { - private int mChannel; + private String mChannel; private long mFrequency; public P25CallEvent( CallEventType callEventType, - AliasList aliasList, - String fromID, - String toID, - int channel, - long frequency, - String details ) + AliasList aliasList, + String fromID, + String toID, + String channel, + long frequency, + String details ) { super( DecoderType.MPT1327, callEventType, aliasList, fromID, toID, details ); @@ -42,11 +42,11 @@ public class P25CallEvent extends CallEvent mFrequency = frequency; } - private Alias getAlias( String mpt1327Talkgroup ) + private Alias getAlias( String talkgroup ) { if( hasAliasList() ) { - return getAliasList().getMPT1327Alias( mpt1327Talkgroup ); + return getAliasList().getTalkgroupAlias( talkgroup ); } return null; @@ -65,7 +65,7 @@ public class P25CallEvent extends CallEvent } @Override - public int getChannel() + public String getChannel() { return mChannel; } @@ -86,7 +86,7 @@ public class P25CallEvent extends CallEvent private String mFromID; private String mToID; private String mDetails; - private int mChannel; + private String mChannel; private long mFrequency; public Builder( CallEventType callEventType ) @@ -106,7 +106,7 @@ public class P25CallEvent extends CallEvent return this; } - public Builder channel( int channel ) + public Builder channel( String channel ) { mChannel = channel; return this; diff --git a/src/decode/p25/P25ChannelState.java b/src/decode/p25/P25ChannelState.java index ddcfab0f..359266be 100644 --- a/src/decode/p25/P25ChannelState.java +++ b/src/decode/p25/P25ChannelState.java @@ -22,12 +22,21 @@ import alias.Alias; import alias.AliasList; import audio.SquelchListener; import audio.SquelchListener.SquelchState; +import controller.activity.CallEvent.CallEventType; import controller.channel.ProcessingChain; import controller.state.AuxChannelState; import controller.state.ChannelState; import decode.p25.message.P25Message; import decode.p25.message.pdu.osp.control.RFSSStatusBroadcastExtended; +import decode.p25.message.tsbk.TSBKMessage; +import decode.p25.message.tsbk.osp.control.LocationRegistrationResponse; import decode.p25.message.tsbk.osp.control.RFSSStatusBroadcast; +import decode.p25.message.tsbk.osp.control.UnitDeregistrationAcknowledge; +import decode.p25.message.tsbk.osp.voice.GroupVoiceChannelGrant; +import decode.p25.message.tsbk.osp.voice.GroupVoiceChannelGrantUpdate; +import decode.p25.message.tsbk.osp.voice.GroupVoiceChannelGrantUpdateExplicit; +import decode.p25.message.tsbk.osp.voice.UnitToUnitAnswerRequest; +import decode.p25.reference.Vendor; public class P25ChannelState extends ChannelState { @@ -123,11 +132,118 @@ public class P25ChannelState extends ChannelState { mSiteAlias = alias.getName(); - broadcastChange( ChangedAttribute.SITE_ALIAS ); + } + else + { + mSiteAlias = null; } } - + broadcastChange( ChangedAttribute.SITE ); + + broadcastChange( ChangedAttribute.SITE_ALIAS ); + } + } + else if( message instanceof TSBKMessage ) + { + TSBKMessage tsbk = (TSBKMessage)message; + + setState( State.CONTROL ); + + if( tsbk.getVendor() == Vendor.STANDARD ) + { + switch( tsbk.getOpcode() ) + { + case GROUP_VOICE_CHANNEL_GRANT: + GroupVoiceChannelGrant gvcg = (GroupVoiceChannelGrant)tsbk; + + mCallEventModel.add( + new P25CallEvent.Builder( CallEventType.CALL ) + .aliasList( mAliasList ) + .channel( gvcg.getChannelIdentifier() + "-" + gvcg.getChannel() ) + .details( ( gvcg.isEncrypted() ? "ENCRYPTED" : "" ) + + ( gvcg.isEmergency() ? " EMERGENCY" : "") ) + .frequency( gvcg.getDownlinkFrequency() ) + .from( gvcg.getSourceAddress() ) + .to( gvcg.getGroupAddress() ) + .build() ); + break; + case GROUP_VOICE_CHANNEL_GRANT_UPDATE: + GroupVoiceChannelGrantUpdate gvcgu = + (GroupVoiceChannelGrantUpdate)tsbk; + mCallEventModel.add( + new P25CallEvent.Builder( CallEventType.CALL ) + .aliasList( mAliasList ) + .channel( gvcgu.getChannelID1() + "-" + gvcgu.getChannelNumber1() ) + .details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) + + ( gvcgu.isEmergency() ? " EMERGENCY" : "") ) + .frequency( gvcgu.getDownlinkFrequency() ) + .to( gvcgu.getGroupAddress1() ) + .build() ); + if( gvcgu.getChannelNumber2() != 0 ) + { + mCallEventModel.add( + new P25CallEvent.Builder( CallEventType.CALL ) + .aliasList( mAliasList ) + .channel( gvcgu.getChannelID2() + "-" + gvcgu.getChannelNumber2() ) + .details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) + + ( gvcgu.isEmergency() ? " EMERGENCY" : "") ) + .frequency( gvcgu.getDownlinkFrequency() ) + .to( gvcgu.getGroupAddress2() ) + .build() ); + } + break; + case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT: + GroupVoiceChannelGrantUpdateExplicit gvcgue = + (GroupVoiceChannelGrantUpdateExplicit)tsbk; + + mCallEventModel.add( + new P25CallEvent.Builder( CallEventType.CALL ) + .aliasList( mAliasList ) + .channel( gvcgue.getTransmitChannelID() + "-" + + gvcgue.getTransmitChannelNumber() ) + .details( ( gvcgue.isEncrypted() ? "ENCRYPTED" : "" ) + + ( gvcgue.isEmergency() ? " EMERGENCY" : "") ) + .frequency( gvcgue.getDownlinkFrequency() ) + .to( gvcgue.getGroupAddress() ) + .build() ); + break; + case UNIT_TO_UNIT_ANSWER_REQUEST: + UnitToUnitAnswerRequest utuar = + (UnitToUnitAnswerRequest)tsbk; + mCallEventModel.add( + new P25CallEvent.Builder( CallEventType.PAGE ) + .aliasList( mAliasList ) + .details( ( utuar.isEmergency() ? "EMERGENCY" : "" ) ) + .from( utuar.getSourceAddress() ) + .to( utuar.getTargetAddress() ) + .build() ); + break; + case LOCATION_REGISTRATION_RESPONSE: + LocationRegistrationResponse lrr = + (LocationRegistrationResponse)tsbk; + + mCallEventModel.add( + new P25CallEvent.Builder( CallEventType.REGISTER ) + .aliasList( mAliasList ) + .details( "REG:" + lrr.getResponse().name() + + " SITE: " + lrr.getRFSSID() + "-" + + lrr.getSiteID() ) + .from( lrr.getTargetAddress() ) + .to( lrr.getGroupAddress() ) + .build() ); + break; + case UNIT_DEREGISTRATION_ACKNOWLEDGE: + UnitDeregistrationAcknowledge udr = + (UnitDeregistrationAcknowledge)tsbk; + + mCallEventModel.add( + new P25CallEvent.Builder( CallEventType.DEREGISTER ) + .aliasList( mAliasList ) + .from( udr.getSourceID() ) + .build() ); + break; + } } } } diff --git a/src/decode/p25/P25Panel.java b/src/decode/p25/P25Panel.java index 5aa79f74..dd523423 100644 --- a/src/decode/p25/P25Panel.java +++ b/src/decode/p25/P25Panel.java @@ -45,7 +45,7 @@ public class P25Panel extends ChannelStatePanel private JLabel mSystem = new JLabel( "SYS:" ); private JLabel mSite = new JLabel( "Site:" ); - private JLabel mSiteAlias = new JLabel( "WACN:" ); + private JLabel mSiteAlias = new JLabel( "" ); public P25Panel( Channel channel ) diff --git a/src/decode/p25/TrellisHalfRate.java b/src/decode/p25/TrellisHalfRate.java index 75a37372..249b09da 100644 --- a/src/decode/p25/TrellisHalfRate.java +++ b/src/decode/p25/TrellisHalfRate.java @@ -1,17 +1,20 @@ package decode.p25; import java.util.ArrayList; +import java.util.Random; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import bits.BitSetBuffer; import dsp.fsk.Dibit; -import dsp.fsk.P25MessageFramer; public class TrellisHalfRate { - private final static Logger mLog = LoggerFactory.getLogger( TrellisHalfRate.class ); + public final static int MAX_ERROR_THRESHOLD = 7; + + private final static Logger mLog = + LoggerFactory.getLogger( TrellisHalfRate.class ); private ArrayList mConstellationNodes = new ArrayList(); @@ -94,7 +97,7 @@ public class TrellisHalfRate return sb.toString(); } - public void decode( BitSetBuffer message, int start, int end ) + public boolean decode( BitSetBuffer message, int start, int end ) { /* load each of the nodes with de-interleaved constellations */ for( int index = 0; index < 49; index++ ) @@ -104,20 +107,24 @@ public class TrellisHalfRate mConstellationNodes.get( index ).setConstellation( c ); } -// mLog.debug( constellationsToString( " LOADED: ") ); -// /* test to see if constellations are correct - otherwise correct them */ ConstellationNode firstNode = mConstellationNodes.get( 0 ); - if( !firstNode.hasStateDibit( Dibit.D00_PLUS_1 ) || !firstNode.isCorrect() ) - { - firstNode.correctTo( Dibit.D00_PLUS_1 ); - } + int errorCount = firstNode.getErrorCount(); -// mLog.debug( constellationsToString( "CORRECTD: " ) ); -// -// mLog.debug( inputsToString() ); -// + if( errorCount > 0 ) + { + if( errorCount < MAX_ERROR_THRESHOLD ) + { + /* repair the errors */ + firstNode.correctTo( Dibit.D00_PLUS_1 ); + } + else + { + return false; + } + } + /* clear constellations from original message */ message.clear( start, end ); @@ -137,6 +144,8 @@ public class TrellisHalfRate message.set( start + ( index * 2 ) + 1 ); } } + + return true; } private Constellation getConstellation( BitSetBuffer message, int index ) @@ -301,24 +310,18 @@ public class TrellisHalfRate * @return - true - all node connections to the right are correct * false - one or more nodes to the right are incorrect */ - public boolean isCorrect() + public int getErrorCount() { - if( mCorrect ) - { - return mCorrect; - } - if( mConnectedNode == null ) { mCorrect = true; + + return 0; } - else - { - mCorrect = mConnectedNode.isCorrect() && - mConstellation.getInput() == mConnectedNode.getStateDibit(); - } + + mCorrect = mConstellation.getInput() == mConnectedNode.getStateDibit(); - return mCorrect; + return mConnectedNode.getErrorCount() + ( mCorrect ? 0 : 1 ); } public Dibit getStateDibit() @@ -495,15 +498,17 @@ public class TrellisHalfRate */ public static void main( String[] args ) { - String original = "00100110000001111000101111110011111000011110100111100001000100100010110000001101100100100010001000100010001000101100111000100010111110001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000101100001110000101000110011100001110"; - - BitSetBuffer buffer = new BitSetBuffer( original.length() ); + Random random = new Random(); + + BitSetBuffer buffer = new BitSetBuffer( 196 ); try { - for( int x = 0; x < original.length(); x++ ) + for( int x = 0; x < 196; x++ ) { - if( original.substring( x, x + 1 ).contentEquals( "0" ) ) + int number = random.nextInt( 2 ); + + if( number == 1 ) { buffer.add( false ); } @@ -518,12 +523,11 @@ public class TrellisHalfRate e.printStackTrace(); } - mLog.debug( "ORIGINAL: " + original ); mLog.debug( " BUFFER: " + buffer.toString() ); TrellisHalfRate t = new TrellisHalfRate(); - t.decode( buffer, 64, original.length() ); + t.decode( buffer, 0, 196 ); mLog.debug( " DECODED: " + buffer.toString() ); mLog.debug( "Finished!" ); } diff --git a/src/decode/p25/message/filter/P25MessageFilterSet.java b/src/decode/p25/message/filter/P25MessageFilterSet.java index 86178ffe..796e0102 100644 --- a/src/decode/p25/message/filter/P25MessageFilterSet.java +++ b/src/decode/p25/message/filter/P25MessageFilterSet.java @@ -12,7 +12,7 @@ public class P25MessageFilterSet extends FilterSet addFilter( new PDUMessageFilter() ); addFilter( new TDUMessageFilter() ); - addFilter( new TSBKMessageFilter() ); + addFilter( new TSBKMessageFilterSet() ); } @Override diff --git a/src/decode/p25/message/filter/TSBKMessageFilter.java b/src/decode/p25/message/filter/TSBKMessageFilter.java deleted file mode 100644 index 1aef2724..00000000 --- a/src/decode/p25/message/filter/TSBKMessageFilter.java +++ /dev/null @@ -1,54 +0,0 @@ -package decode.p25.message.filter; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import message.Message; -import decode.p25.message.tsbk.TSBKMessage; -import decode.p25.reference.Opcode; -import filter.Filter; -import filter.FilterElement; - -public class TSBKMessageFilter extends Filter -{ - private HashMap> mFilterElements = - new HashMap>(); - - public TSBKMessageFilter() - { - super( "TSBK Trunking Signalling Block" ); - - for( Opcode opcode: Opcode.values() ) - { - mFilterElements.put( opcode, new FilterElement( opcode ) ); - } - } - - @Override - public boolean passes( Message message ) - { - if( mEnabled && canProcess( message ) ) - { - TSBKMessage tsbk = (TSBKMessage)message; - - Opcode opcode = tsbk.getOpcode(); - - return mFilterElements.get( opcode ).isEnabled(); - } - - return false; - } - - @Override - public boolean canProcess( Message message ) - { - return message instanceof TSBKMessage; - } - - @Override - public List> getFilterElements() - { - return new ArrayList>( mFilterElements.values() ); - } -} diff --git a/src/decode/p25/message/filter/TSBKMessageFilterSet.java b/src/decode/p25/message/filter/TSBKMessageFilterSet.java new file mode 100644 index 00000000..1b90bb54 --- /dev/null +++ b/src/decode/p25/message/filter/TSBKMessageFilterSet.java @@ -0,0 +1,200 @@ +package decode.p25.message.filter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import message.Message; +import decode.p25.message.tsbk.TSBKMessage; +import decode.p25.message.tsbk.motorola.MotorolaOpcode; +import decode.p25.message.tsbk.vendor.VendorOpcode; +import decode.p25.reference.Opcode; +import decode.p25.reference.Vendor; +import filter.Filter; +import filter.FilterElement; +import filter.FilterSet; + +public class TSBKMessageFilterSet extends FilterSet +{ + public TSBKMessageFilterSet() + { + super( "TSBK Trunking Signalling Block" ); + + addFilter( new StandardOpcodeFilter() ); + addFilter( new MotorolaOpcodeFilter() ); + addFilter( new VendorOpcodeFilter() ); + } + +// @Override +// public boolean passes( Message message ) +// { +// if( mEnabled && canProcess( message ) ) +// { +// TSBKMessage tsbk = (TSBKMessage)message; +// +// switch( tsbk.getVendor() ) +// { +// case STANDARD: +// return +// } +// Opcode opcode = tsbk.getOpcode(); +// +// return mFilterElements.get( opcode ).isEnabled(); +// } +// +// return false; +// } + + @Override + public boolean canProcess( Message message ) + { + return message instanceof TSBKMessage; + } + + public class StandardOpcodeFilter extends Filter + { + private HashMap> mStandardElements = + new HashMap>(); + + public StandardOpcodeFilter() + { + super( "Standard Opcode Filter" ); + + for( Opcode opcode: Opcode.values() ) + { + if( opcode != Opcode.UNKNOWN ) + { + mStandardElements.put( opcode, + new FilterElement( opcode ) ); + } + } + } + + @Override + public boolean passes( Message message ) + { + if( mEnabled && canProcess( message ) ) + { + Opcode opcode = ((TSBKMessage)message).getOpcode(); + + if( mStandardElements.containsKey( opcode ) ) + { + return mStandardElements.get( opcode ).isEnabled(); + } + } + + return false; + } + + @Override + public boolean canProcess( Message message ) + { + + return ((TSBKMessage)message).getVendor() == Vendor.STANDARD; + } + + @Override + public List> getFilterElements() + { + return new ArrayList>( mStandardElements.values() ); + } + } + + public class MotorolaOpcodeFilter extends Filter + { + private HashMap> mMotorolaElements = + new HashMap>(); + + public MotorolaOpcodeFilter() + { + super( "Motorola Opcode Filter" ); + + for( MotorolaOpcode opcode: MotorolaOpcode.values() ) + { + if( opcode != MotorolaOpcode.UNKNOWN ) + { + mMotorolaElements.put( opcode, + new FilterElement( opcode ) ); + } + } + } + + @Override + public boolean passes( Message message ) + { + if( mEnabled && canProcess( message ) ) + { + MotorolaOpcode opcode = ((TSBKMessage)message).getMotorolaOpcode(); + + if( mMotorolaElements.containsKey( opcode ) ) + { + return mMotorolaElements.get( opcode ).isEnabled(); + } + } + + return false; + } + + @Override + public boolean canProcess( Message message ) + { + return ((TSBKMessage)message).getVendor() == Vendor.MOTOROLA; + } + + @Override + public List> getFilterElements() + { + return new ArrayList>( mMotorolaElements.values() ); + } + } + + public class VendorOpcodeFilter extends Filter + { + private HashMap> mVendorElements = + new HashMap>(); + + public VendorOpcodeFilter() + { + super( "Vendor Opcode Filter" ); + + for( VendorOpcode opcode: VendorOpcode.values() ) + { + if( opcode != VendorOpcode.UNKNOWN ) + { + mVendorElements.put( opcode, + new FilterElement( opcode ) ); + } + } + } + + @Override + public boolean passes( Message message ) + { + if( mEnabled && canProcess( message ) ) + { + MotorolaOpcode opcode = ((TSBKMessage)message).getMotorolaOpcode(); + + if( mVendorElements.containsKey( opcode ) ) + { + return mVendorElements.get( opcode ).isEnabled(); + } + } + + return false; + } + + @Override + public boolean canProcess( Message message ) + { + Vendor vendor = ((TSBKMessage)message).getVendor(); + + return vendor != Vendor.STANDARD && vendor != Vendor.MOTOROLA; + } + + @Override + public List> getFilterElements() + { + return new ArrayList>( mVendorElements.values() ); + } + } +} diff --git a/src/decode/p25/message/tsbk/ChannelGrant.java b/src/decode/p25/message/tsbk/ChannelGrant.java index 575f4c3a..d4da2b8f 100644 --- a/src/decode/p25/message/tsbk/ChannelGrant.java +++ b/src/decode/p25/message/tsbk/ChannelGrant.java @@ -2,15 +2,20 @@ 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.reference.DataUnitID; -public abstract class ChannelGrant extends ServiceMessage +public abstract class ChannelGrant extends ServiceMessage + implements IdentifierUpdateReceiver { public static final int[] PRIORITY = { 85,86,87 }; public static final int[] CHANNEL_ID = { 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; + public ChannelGrant( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -26,13 +31,40 @@ public abstract class ChannelGrant extends ServiceMessage return mMessage.getInt( PRIORITY ); } - public int getChannelID() + public int getChannelIdentifier() { return mMessage.getInt( CHANNEL_ID ); } - public int getChannelNumber() + public int getChannel() { return mMessage.getInt( CHANNEL_NUMBER ); } + + + @Override + public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + { + mIdentifierUpdate = message; + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 1 ]; + identifiers[ 0 ] = getChannelIdentifier(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mIdentifierUpdate, getChannel() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mIdentifierUpdate, getChannel() ); + } + } diff --git a/src/decode/p25/message/tsbk/GroupChannelGrant.java b/src/decode/p25/message/tsbk/GroupChannelGrant.java index 847dc975..cfe94105 100644 --- a/src/decode/p25/message/tsbk/GroupChannelGrant.java +++ b/src/decode/p25/message/tsbk/GroupChannelGrant.java @@ -41,15 +41,19 @@ public abstract class GroupChannelGrant extends ChannelGrant sb.append( " EMERGENCY" ); } - sb.append( " CHAN:" ); - sb.append( getChannelID() + "/" + getChannelNumber() ); - - sb.append( " FROM:" ); + sb.append( " SOURCE UNIT:" ); sb.append( getSourceAddress() ); - sb.append( " GRP:" ); + sb.append( " GROUP:" ); sb.append( getGroupAddress() ); + sb.append( " CHAN:" ); + sb.append( getChannelIdentifier() + "-" + getChannel() ); + + sb.append( " DN:" + getDownlinkFrequency() ); + + sb.append( " UP:" + getUplinkFrequency() ); + return sb.toString(); } diff --git a/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java b/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java index 8d0a95e4..acc8a09a 100644 --- a/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java +++ b/src/decode/p25/message/tsbk/GroupChannelGrantExplicit.java @@ -2,6 +2,7 @@ package decode.p25.message.tsbk; import alias.AliasList; import bits.BitSetBuffer; +import decode.p25.message.tsbk.osp.control.IdentifierUpdate; import decode.p25.reference.DataUnitID; public abstract class GroupChannelGrantExplicit extends ChannelGrant @@ -15,6 +16,9 @@ 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; + public GroupChannelGrantExplicit( BitSetBuffer message, DataUnitID duid, AliasList aliasList ) @@ -69,4 +73,38 @@ public abstract class GroupChannelGrantExplicit extends ChannelGrant { return mMessage.getHex( GROUP_ADDRESS, 4 ); } + + @Override + public void setIdentifierMessage( int identifier, IdentifierUpdate message ) + { + if( identifier == getTransmitChannelID() ) + { + mTransmitIdentifierUpdate = message; + } + + if( identifier == getReceiveChannelID() ) + { + mReceiveIdentifierUpdate = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + identifiers[ 0 ] = getTransmitChannelID(); + identifiers[ 1 ] = getReceiveChannelID(); + + return identifiers; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mTransmitIdentifierUpdate, getChannel() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mReceiveIdentifierUpdate, getChannel() ); + } } diff --git a/src/decode/p25/message/tsbk/TSBKMessage.java b/src/decode/p25/message/tsbk/TSBKMessage.java index a0e09758..1992c99b 100644 --- a/src/decode/p25/message/tsbk/TSBKMessage.java +++ b/src/decode/p25/message/tsbk/TSBKMessage.java @@ -3,7 +3,8 @@ package decode.p25.message.tsbk; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.P25Message; -import decode.p25.message.tsbk.osp.control.IdentifierUpdate; +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; @@ -56,6 +57,16 @@ public class TSBKMessage extends P25Message return Opcode.fromValue( mMessage.getInt( OPCODE ) ); } + public MotorolaOpcode getMotorolaOpcode() + { + return MotorolaOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + + public VendorOpcode getVendorOpcode() + { + return VendorOpcode.fromValue( mMessage.getInt( OPCODE ) ); + } + @Override public String getMessage() { diff --git a/src/decode/p25/message/tsbk/TSBKMessageFactory.java b/src/decode/p25/message/tsbk/TSBKMessageFactory.java index d863a78b..8d978088 100644 --- a/src/decode/p25/message/tsbk/TSBKMessageFactory.java +++ b/src/decode/p25/message/tsbk/TSBKMessageFactory.java @@ -196,9 +196,9 @@ public class TSBKMessageFactory switch( motorolaOpcode ) { - case CHANNEL_CWID_UPDATE: + case OP0B: return new ChannelCWIDUpdate( message, duid, aliasList ); - case SYSTEM_LOADING: + case OP09: return new SystemLoading( message, duid, aliasList ); default: } diff --git a/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java b/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java index f1a91ff9..01d9bdf9 100644 --- a/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java +++ b/src/decode/p25/message/tsbk/motorola/ChannelCWIDUpdate.java @@ -34,7 +34,7 @@ public class ChannelCWIDUpdate extends MotorolaTSBKMessage @Override public String getEventType() { - return MotorolaOpcode.CHANNEL_CWID_UPDATE.getDescription(); + return MotorolaOpcode.OP0B.getDescription(); } public String getMessage() @@ -58,94 +58,31 @@ public class ChannelCWIDUpdate extends MotorolaTSBKMessage public String getCWID() { StringBuilder sb = new StringBuilder(); - - int char1 = mMessage.getInt( CHARACTER_1 ); - - if( char1 != 0 ) - { - sb.append( (char)( char1 + 46 ) ); - } - else - { - return null; - } - - int char2 = mMessage.getInt( CHARACTER_2 ); - - if( char2 != 0 ) - { - sb.append( (char)( char2 + 46 ) ); - } - else - { - return sb.toString(); - } - int char3 = mMessage.getInt( CHARACTER_3 ); - - if( char3 != 0 ) - { - sb.append( (char)( char3 + 46 ) ); - } - else - { - return sb.toString(); - } - - int char4 = mMessage.getInt( CHARACTER_4 ); - - if( char4 != 0 ) - { - sb.append( (char)( char4 + 46 ) ); - } - else - { - return sb.toString(); - } - - int char5 = mMessage.getInt( CHARACTER_5 ); - - if( char5 != 0 ) - { - sb.append( (char)( char5 + 46 ) ); - } - else - { - return sb.toString(); - } - - int char6 = mMessage.getInt( CHARACTER_6 ); - - if( char6 != 0 ) - { - sb.append( (char)( char6 + 46 ) ); - } - else - { - return sb.toString(); - } - - int char7 = mMessage.getInt( CHARACTER_7 ); - - if( char7 != 0 ) - { - sb.append( (char)( char7 + 46 ) ); - } - else - { - return sb.toString(); - } - - int char8 = mMessage.getInt( CHARACTER_8 ); - - if( char8 != 0 ) - { - sb.append( (char)( char8 + 46 ) ); - } + sb.append( getCharacter( CHARACTER_1 ) ); + sb.append( getCharacter( CHARACTER_2 ) ); + sb.append( getCharacter( CHARACTER_3 ) ); + sb.append( getCharacter( CHARACTER_4 ) ); + sb.append( getCharacter( CHARACTER_5 ) ); + sb.append( getCharacter( CHARACTER_6 ) ); + sb.append( getCharacter( CHARACTER_7 ) ); + sb.append( getCharacter( CHARACTER_8 ) ); return sb.toString(); } + private String getCharacter( int[] field ) + { + int value = mMessage.getInt( field ); + + if( value != 0 ) + { + return String.valueOf( (char)( value + 43 ) ); + } + + return null; + } + public int getIdentifier() { return mMessage.getInt( IDENTIFIER ); diff --git a/src/decode/p25/message/tsbk/motorola/MotorolaOpcode.java b/src/decode/p25/message/tsbk/motorola/MotorolaOpcode.java index b1e1b7ff..86a9f6dc 100644 --- a/src/decode/p25/message/tsbk/motorola/MotorolaOpcode.java +++ b/src/decode/p25/message/tsbk/motorola/MotorolaOpcode.java @@ -2,9 +2,70 @@ package decode.p25.message.tsbk.motorola; public enum MotorolaOpcode { - UNKNOWN_OPCODE_5( "MOTO OPCODE 05 ", "Unknown Opcode 0x05", 0x05 ), - SYSTEM_LOADING( "SYSTEM_LOADING ", "System Loading", 0x09 ), - CHANNEL_CWID_UPDATE( "CHAN_CWID_UPDATE", "Channel FCC Callsign Update", 0x0B ), + OP00( "OP00:UNKNOWN ", "Opcode 0x00 Unknown", 0x00 ), + OP01( "OP01:UNKNOWN ", "Opcode 0x01 Unknown", 0x01 ), + OP02( "OP02:UNKNOWN ", "Opcode 0x02 Unknown", 0x02 ), + OP03( "OP03:UNKNOWN ", "Opcode 0x03 Unknown", 0x03 ), + OP04( "OP04:UNKNOWN ", "Opcode 0x04 Unknown", 0x04 ), + OP05( "OP05:UNKNOWN ", "Opcode 0x05 Unknown", 0x05 ), + OP06( "OP06:UNKNOWN ", "Opcode 0x06 Unknown", 0x06 ), + OP07( "OP07:UNKNOWN ", "Opcode 0x07 Unknown", 0x07 ), + OP08( "OP08:UNKNOWN ", "Opcode 0x08 Unknown", 0x08 ), + OP09( "OP09:SYSTEM_LOAD", "Opcode 0x09 System Loading", 0x09 ), + OP0A( "OP0A:UNKNOWN ", "Opcode 0x0A Unknown", 0x0A ), + OP0B( "OP0B:CWID_UPDATE", "Opcode 0x0B FCC Callsign", 0x0B ), + OP0C( "OP0C:UNKNOWN ", "Opcode 0x0C Unknown", 0x0C ), + OP0D( "OP0D:UNKNOWN ", "Opcode 0x0D Unknown", 0x0D ), + OP0E( "OP0E:UNKNOWN ", "Opcode 0x0E Unknown", 0x0E ), + OP0F( "OP0F:UNKNOWN ", "Opcode 0x0F Unknown", 0x0F ), + OP10( "OP10:UNKNOWN ", "Opcode 0x10 Unknown", 0x10 ), + OP11( "OP11:UNKNOWN ", "Opcode 0x11 Unknown", 0x11 ), + OP12( "OP12:UNKNOWN ", "Opcode 0x12 Unknown", 0x12 ), + OP13( "OP13:UNKNOWN ", "Opcode 0x13 Unknown", 0x13 ), + OP14( "OP14:UNKNOWN ", "Opcode 0x14 Unknown", 0x14 ), + OP15( "OP15:UNKNOWN ", "Opcode 0x15 Unknown", 0x15 ), + OP16( "OP16:UNKNOWN ", "Opcode 0x16 Unknown", 0x16 ), + OP17( "OP17:UNKNOWN ", "Opcode 0x17 Unknown", 0x17 ), + OP18( "OP18:UNKNOWN ", "Opcode 0x18 Unknown", 0x18 ), + OP19( "OP19:UNKNOWN ", "Opcode 0x19 Unknown", 0x19 ), + OP1A( "OP1A:UNKNOWN ", "Opcode 0x1A Unknown", 0x1A ), + OP1B( "OP1B:UNKNOWN ", "Opcode 0x1B Unknown", 0x1B ), + OP1C( "OP1C:UNKNOWN ", "Opcode 0x1C Unknown", 0x1C ), + OP1D( "OP1D:UNKNOWN ", "Opcode 0x1D Unknown", 0x1D ), + OP1E( "OP1E:UNKNOWN ", "Opcode 0x1E Unknown", 0x1E ), + OP1F( "OP1F:UNKNOWN ", "Opcode 0x1F Unknown", 0x1F ), + OP20( "OP20:UNKNOWN ", "Opcode 0x20 Unknown", 0x20 ), + OP21( "OP21:UNKNOWN ", "Opcode 0x21 Unknown", 0x21 ), + OP22( "OP22:UNKNOWN ", "Opcode 0x22 Unknown", 0x22 ), + OP23( "OP23:UNKNOWN ", "Opcode 0x23 Unknown", 0x23 ), + OP24( "OP24:UNKNOWN ", "Opcode 0x24 Unknown", 0x24 ), + OP25( "OP25:UNKNOWN ", "Opcode 0x25 Unknown", 0x25 ), + OP26( "OP26:UNKNOWN ", "Opcode 0x26 Unknown", 0x26 ), + OP27( "OP27:UNKNOWN ", "Opcode 0x27 Unknown", 0x27 ), + OP28( "OP28:UNKNOWN ", "Opcode 0x28 Unknown", 0x28 ), + OP29( "OP29:UNKNOWN ", "Opcode 0x29 Unknown", 0x29 ), + OP2A( "OP2A:UNKNOWN ", "Opcode 0x2A Unknown", 0x2A ), + OP2B( "OP2B:UNKNOWN ", "Opcode 0x2B Unknown", 0x2B ), + OP2C( "OP2C:UNKNOWN ", "Opcode 0x2C Unknown", 0x2C ), + OP2D( "OP2D:UNKNOWN ", "Opcode 0x2D Unknown", 0x2D ), + OP2E( "OP2E:UNKNOWN ", "Opcode 0x2E Unknown", 0x2E ), + OP2F( "OP2F:UNKNOWN ", "Opcode 0x2F Unknown", 0x2F ), + OP30( "OP30:UNKNOWN ", "Opcode 0x30 Unknown", 0x30 ), + OP31( "OP31:UNKNOWN ", "Opcode 0x31 Unknown", 0x31 ), + OP32( "OP32:UNKNOWN ", "Opcode 0x32 Unknown", 0x32 ), + OP33( "OP33:UNKNOWN ", "Opcode 0x33 Unknown", 0x33 ), + OP34( "OP34:UNKNOWN ", "Opcode 0x34 Unknown", 0x34 ), + OP35( "OP35:UNKNOWN ", "Opcode 0x35 Unknown", 0x35 ), + OP36( "OP36:UNKNOWN ", "Opcode 0x36 Unknown", 0x36 ), + OP37( "OP37:UNKNOWN ", "Opcode 0x37 Unknown", 0x37 ), + OP38( "OP38:UNKNOWN ", "Opcode 0x38 Unknown", 0x38 ), + OP39( "OP39:UNKNOWN ", "Opcode 0x39 Unknown", 0x39 ), + OP3A( "OP3A:UNKNOWN ", "Opcode 0x3A Unknown", 0x3A ), + OP3B( "OP3B:UNKNOWN ", "Opcode 0x3B Unknown", 0x3B ), + OP3C( "OP3C:UNKNOWN ", "Opcode 0x3C Unknown", 0x3C ), + OP3D( "OP3D:UNKNOWN ", "Opcode 0x3D Unknown", 0x3D ), + OP3E( "OP3E:UNKNOWN ", "Opcode 0x3E Unknown", 0x3E ), + OP3F( "OP3F:UNKNOWN ", "Opcode 0x3F Unknown", 0x3F ), UNKNOWN( "UNKNOWN ", "Unknown", -1 ); private String mLabel; @@ -23,6 +84,11 @@ public enum MotorolaOpcode return mLabel; } + public String toString() + { + return getLabel(); + } + public String getDescription() { return mDescription; @@ -35,14 +101,9 @@ public enum MotorolaOpcode public static MotorolaOpcode fromValue( int value ) { - switch( value ) + if( 0 <= value && value <= 0x3F ) { - case 0x05: - return UNKNOWN_OPCODE_5; - case 0x09: - return SYSTEM_LOADING; - case 0x0B: - return CHANNEL_CWID_UPDATE; + return MotorolaOpcode.values()[ value ]; } return UNKNOWN; diff --git a/src/decode/p25/message/tsbk/motorola/SystemLoading.java b/src/decode/p25/message/tsbk/motorola/SystemLoading.java index c5885872..5059603c 100644 --- a/src/decode/p25/message/tsbk/motorola/SystemLoading.java +++ b/src/decode/p25/message/tsbk/motorola/SystemLoading.java @@ -16,7 +16,7 @@ public class SystemLoading extends MotorolaTSBKMessage @Override public String getEventType() { - return MotorolaOpcode.SYSTEM_LOADING.getLabel(); + return MotorolaOpcode.OP09.getLabel(); } @Override diff --git a/src/decode/p25/message/tsbk/osp/control/LocationRegistrationResponse.java b/src/decode/p25/message/tsbk/osp/control/LocationRegistrationResponse.java index af81697b..9111807c 100644 --- a/src/decode/p25/message/tsbk/osp/control/LocationRegistrationResponse.java +++ b/src/decode/p25/message/tsbk/osp/control/LocationRegistrationResponse.java @@ -52,7 +52,7 @@ public class LocationRegistrationResponse extends TSBKMessage public String getGroupAddress() { - return mMessage.getHex( GROUP_ADDRESS, 6 ); + return mMessage.getHex( GROUP_ADDRESS, 4 ); } public String getRFSSID() diff --git a/src/decode/p25/message/tsbk/osp/control/TimeAndDateAnnouncement.java b/src/decode/p25/message/tsbk/osp/control/TimeAndDateAnnouncement.java index d55a6548..8dc8ebd5 100644 --- a/src/decode/p25/message/tsbk/osp/control/TimeAndDateAnnouncement.java +++ b/src/decode/p25/message/tsbk/osp/control/TimeAndDateAnnouncement.java @@ -54,7 +54,8 @@ public class TimeAndDateAnnouncement extends TSBKMessage { sb.append( " DATE-TIME:" ); } - + + sb.append( " " ); sb.append( mTimeFormatter.format( new Date( getDateTimestamp() ) ) ); return sb.toString(); diff --git a/src/decode/p25/message/tsbk/osp/voice/GroupVoiceChannelGrant.java b/src/decode/p25/message/tsbk/osp/voice/GroupVoiceChannelGrant.java index c60dd62f..9bec67c9 100644 --- a/src/decode/p25/message/tsbk/osp/voice/GroupVoiceChannelGrant.java +++ b/src/decode/p25/message/tsbk/osp/voice/GroupVoiceChannelGrant.java @@ -20,4 +20,5 @@ public class GroupVoiceChannelGrant extends GroupChannelGrant { return Opcode.GROUP_VOICE_CHANNEL_GRANT.getDescription(); } + } diff --git a/src/decode/p25/message/tsbk/osp/voice/TelephoneInterconnectVoiceChannelGrant.java b/src/decode/p25/message/tsbk/osp/voice/TelephoneInterconnectVoiceChannelGrant.java index 4128c42d..2e05cbe6 100644 --- a/src/decode/p25/message/tsbk/osp/voice/TelephoneInterconnectVoiceChannelGrant.java +++ b/src/decode/p25/message/tsbk/osp/voice/TelephoneInterconnectVoiceChannelGrant.java @@ -30,7 +30,7 @@ public class TelephoneInterconnectVoiceChannelGrant extends UnitChannelGrant } sb.append( " CHAN:" ); - sb.append( getChannelID() + "/" + getChannelNumber() ); + sb.append( getChannelIdentifier() + "/" + getChannel() ); sb.append( " CALL TIMER:" ); sb.append( getCallTimer() ); diff --git a/src/decode/p25/message/tsbk/osp/voice/UnitToUnitVoiceChannelGrant.java b/src/decode/p25/message/tsbk/osp/voice/UnitToUnitVoiceChannelGrant.java index 4f263a81..930149b0 100644 --- a/src/decode/p25/message/tsbk/osp/voice/UnitToUnitVoiceChannelGrant.java +++ b/src/decode/p25/message/tsbk/osp/voice/UnitToUnitVoiceChannelGrant.java @@ -3,6 +3,7 @@ package decode.p25.message.tsbk.osp.voice; import alias.AliasList; import bits.BitSetBuffer; import decode.p25.message.tsbk.UnitChannelGrant; +import decode.p25.message.tsbk.osp.control.IdentifierUpdate; import decode.p25.reference.DataUnitID; import decode.p25.reference.Opcode; @@ -20,4 +21,28 @@ public class UnitToUnitVoiceChannelGrant extends UnitChannelGrant { return Opcode.UNIT_TO_UNIT_VOICE_CHANNEL_GRANT.getDescription(); } + + public String getMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getMessageStub() ); + + if( isEmergency() ) + { + sb.append( " EMERGENCY" ); + } + + sb.append( " SOURCE UNIT:" ); + sb.append( getSourceAddress() ); + + sb.append( " TARGET UNIT:" ); + sb.append( getTargetAddress() ); + + sb.append( " CHAN:" + getChannelIdentifier() + "-" + getChannel() ); + sb.append( " DN:" + getDownlinkFrequency() ); + sb.append( " UP:" + getUplinkFrequency() ); + + return sb.toString(); + } } diff --git a/src/decode/p25/message/tsbk/vendor/VendorOpcode.java b/src/decode/p25/message/tsbk/vendor/VendorOpcode.java new file mode 100644 index 00000000..daddb6b1 --- /dev/null +++ b/src/decode/p25/message/tsbk/vendor/VendorOpcode.java @@ -0,0 +1,111 @@ +package decode.p25.message.tsbk.vendor; + +public enum VendorOpcode +{ + OP00( "OPCODE 00 ", "VENDOR OPCODE 0x00", 0x00 ), + OP01( "OPCODE 01 ", "VENDOR OPCODE 0x01", 0x01 ), + OP02( "OPCODE 02 ", "VENDOR OPCODE 0x02", 0x02 ), + OP03( "OPCODE 03 ", "VENDOR OPCODE 0x03", 0x03 ), + OP04( "OPCODE 04 ", "VENDOR OPCODE 0x04", 0x04 ), + OP05( "OPCODE 05 ", "VENDOR OPCODE 0x05", 0x05 ), + OP06( "OPCODE 06 ", "VENDOR OPCODE 0x06", 0x06 ), + OP07( "OPCODE 07 ", "VENDOR OPCODE 0x07", 0x07 ), + OP08( "OPCODE 08 ", "VENDOR OPCODE 0x08", 0x08 ), + OP09( "OPCODE 09 ", "VENDOR OPCODE 0x09", 0x09 ), + OP0A( "OPCODE 0A ", "VENDOR OPCODE 0x0A", 0x0A ), + OP0B( "OPCODE 0B ", "VENDOR OPCODE 0x0B", 0x0B ), + OP0C( "OPCODE 0C ", "VENDOR OPCODE 0x0C", 0x0C ), + OP0D( "OPCODE 0D ", "VENDOR OPCODE 0x0D", 0x0D ), + OP0E( "OPCODE 0E ", "VENDOR OPCODE 0x0E", 0x0E ), + OP0F( "OPCODE 0F ", "VENDOR OPCODE 0x0F", 0x0F ), + OP10( "OPCODE 10 ", "VENDOR OPCODE 0x10", 0x10 ), + OP11( "OPCODE 11 ", "VENDOR OPCODE 0x11", 0x11 ), + OP12( "OPCODE 12 ", "VENDOR OPCODE 0x12", 0x12 ), + OP13( "OPCODE 13 ", "VENDOR OPCODE 0x13", 0x13 ), + OP14( "OPCODE 14 ", "VENDOR OPCODE 0x14", 0x14 ), + OP15( "OPCODE 15 ", "VENDOR OPCODE 0x15", 0x15 ), + OP16( "OPCODE 16 ", "VENDOR OPCODE 0x16", 0x16 ), + OP17( "OPCODE 17 ", "VENDOR OPCODE 0x17", 0x17 ), + OP18( "OPCODE 18 ", "VENDOR OPCODE 0x18", 0x18 ), + OP19( "OPCODE 19 ", "VENDOR OPCODE 0x19", 0x19 ), + OP1A( "OPCODE 1A ", "VENDOR OPCODE 0x1A", 0x1A ), + OP1B( "OPCODE 1B ", "VENDOR OPCODE 0x1B", 0x1B ), + OP1C( "OPCODE 1C ", "VENDOR OPCODE 0x1C", 0x1C ), + OP1D( "OPCODE 1D ", "VENDOR OPCODE 0x1D", 0x1D ), + OP1E( "OPCODE 1E ", "VENDOR OPCODE 0x1E", 0x1E ), + OP1F( "OPCODE 1F ", "VENDOR OPCODE 0x1F", 0x1F ), + OP20( "OPCODE 20 ", "VENDOR OPCODE 0x20", 0x20 ), + OP21( "OPCODE 21 ", "VENDOR OPCODE 0x21", 0x21 ), + OP22( "OPCODE 22 ", "VENDOR OPCODE 0x22", 0x22 ), + OP23( "OPCODE 23 ", "VENDOR OPCODE 0x23", 0x23 ), + OP24( "OPCODE 24 ", "VENDOR OPCODE 0x24", 0x24 ), + OP25( "OPCODE 25 ", "VENDOR OPCODE 0x25", 0x25 ), + OP26( "OPCODE 26 ", "VENDOR OPCODE 0x26", 0x26 ), + OP27( "OPCODE 27 ", "VENDOR OPCODE 0x27", 0x27 ), + OP28( "OPCODE 28 ", "VENDOR OPCODE 0x28", 0x28 ), + OP29( "OPCODE 29 ", "VENDOR OPCODE 0x29", 0x29 ), + OP2A( "OPCODE 2A ", "VENDOR OPCODE 0x2A", 0x2A ), + OP2B( "OPCODE 2B ", "VENDOR OPCODE 0x2B", 0x2B ), + OP2C( "OPCODE 2C ", "VENDOR OPCODE 0x2C", 0x2C ), + OP2D( "OPCODE 2D ", "VENDOR OPCODE 0x2D", 0x2D ), + OP2E( "OPCODE 2E ", "VENDOR OPCODE 0x2E", 0x2E ), + OP2F( "OPCODE 2F ", "VENDOR OPCODE 0x2F", 0x2F ), + OP30( "OPCODE 30 ", "VENDOR OPCODE 0x30", 0x30 ), + OP31( "OPCODE 31 ", "VENDOR OPCODE 0x31", 0x31 ), + OP32( "OPCODE 32 ", "VENDOR OPCODE 0x32", 0x32 ), + OP33( "OPCODE 33 ", "VENDOR OPCODE 0x33", 0x33 ), + OP34( "OPCODE 34 ", "VENDOR OPCODE 0x34", 0x34 ), + OP35( "OPCODE 35 ", "VENDOR OPCODE 0x35", 0x35 ), + OP36( "OPCODE 36 ", "VENDOR OPCODE 0x36", 0x36 ), + OP37( "OPCODE 37 ", "VENDOR OPCODE 0x37", 0x37 ), + OP38( "OPCODE 38 ", "VENDOR OPCODE 0x38", 0x38 ), + OP39( "OPCODE 39 ", "VENDOR OPCODE 0x39", 0x39 ), + OP3A( "OPCODE 3A ", "VENDOR OPCODE 0x3A", 0x3A ), + OP3B( "OPCODE 3B ", "VENDOR OPCODE 0x3B", 0x3B ), + OP3C( "OPCODE 3C ", "VENDOR OPCODE 0x3C", 0x3C ), + OP3D( "OPCODE 3D ", "VENDOR OPCODE 0x3D", 0x3D ), + OP3E( "OPCODE 3E ", "VENDOR OPCODE 0x3E", 0x3E ), + OP3F( "OPCODE 3F ", "VENDOR OPCODE 0x3F", 0x3F ), + UNKNOWN( "UNKNOWN ", "Unknown", -1 ); + + private String mLabel; + private String mDescription; + private int mCode; + + private VendorOpcode( String label, String description, int code ) + { + mLabel = label; + mDescription = description; + mCode = code; + } + + public String getLabel() + { + return mLabel; + } + + public String toString() + { + return getLabel(); + } + + public String getDescription() + { + return mDescription; + } + + public int getCode() + { + return mCode; + } + + public static VendorOpcode fromValue( int value ) + { + if( 0 <= value && value <= 0x3F ) + { + return VendorOpcode.values()[ value ]; + } + + return UNKNOWN; + } +} diff --git a/src/decode/p25/reference/ServiceAccessPoint.java b/src/decode/p25/reference/ServiceAccessPoint.java index d349db8b..611bdcec 100644 --- a/src/decode/p25/reference/ServiceAccessPoint.java +++ b/src/decode/p25/reference/ServiceAccessPoint.java @@ -2,13 +2,13 @@ package decode.p25.reference; public enum ServiceAccessPoint { - SAP_0( "0", 0 ), - SAP_1( "1", 1 ), - SAP_2( "2", 2 ), - SAP_3( "3", 3 ), - SAP_4( "4", 4 ), - SAP_5( "5", 5 ), - SAP_6( "6", 6 ), + UNENCRYPTED_USER_DATA( "0", 0 ), + ENCRYPTED_USER_DATA( "1", 1 ), + CIRCUIT_DATA( "2", 2 ), + CIRCUIT_DATA_CONTROL( "3", 3 ), + PACKET_DATA( "4", 4 ), + ADDRESS_RESOLUTION_PROTOCOL( "5", 5 ), + SNDCP_PACKET_DATA_CONTROL( "6", 6 ), SAP_7( "7", 7 ), SAP_8( "8", 8 ), SAP_9( "9", 9 ), @@ -33,17 +33,17 @@ public enum ServiceAccessPoint SAP_28( "28", 28 ), SAP_29( "29", 29 ), SAP_30( "30", 30 ), - SAP_31( "31", 31 ), - SAP_32( "32", 32 ), - SAP_33( "33", 33 ), - SAP_34( "34", 34 ), - SAP_35( "35", 35 ), - SAP_36( "36", 36 ), - SAP_37( "37", 37 ), - SAP_38( "38", 38 ), - SAP_39( "39", 39 ), - SAP_40( "40", 40 ), - SAP_41( "41", 41 ), + EXTENDED_ADDRESS( "31", 31 ), + REGISTRATION_AND_AUTHORIZATION( "32", 32 ), + CHANNEL_REASSIGNMENT( "33", 33 ), + SYSTEM_CONFIGURATION( "34", 34 ), + MR_LOOPBACK( "35", 35 ), + MR_STATISTICS( "36", 36 ), + MR_OUT_OF_SERVICE( "37", 37 ), + MR_PAGING( "38", 38 ), + MR_CONFIGURATION( "39", 39 ), + UNENCRYPTED_KEY_MANAGEMENT_MESSAGE( "40", 40 ), + ENCRYPTED_KEY_MANAGEMENT_MESSAGE( "41", 41 ), SAP_42( "42", 42 ), SAP_43( "43", 43 ), SAP_44( "44", 44 ), diff --git a/src/decode/passport/PassportCallEvent.java b/src/decode/passport/PassportCallEvent.java index 16a248dc..cc9ce255 100644 --- a/src/decode/passport/PassportCallEvent.java +++ b/src/decode/passport/PassportCallEvent.java @@ -24,7 +24,7 @@ import decode.DecoderType; public class PassportCallEvent extends CallEvent { - private int mChannel; + private String mChannel; private long mFrequency; private int mValidCallMessages = 1; @@ -32,7 +32,7 @@ public class PassportCallEvent extends CallEvent AliasList aliasList, String fromID, String toID, - int channel, + String channel, long frequency, String details ) { @@ -99,7 +99,7 @@ public class PassportCallEvent extends CallEvent } @Override - public int getChannel() + public String getChannel() { return mChannel; } @@ -120,7 +120,7 @@ public class PassportCallEvent extends CallEvent private String mFromID; private String mToID; private String mDetails; - private int mChannel; + private String mChannel; private long mFrequency; public Builder( CallEventType callEventType ) @@ -140,7 +140,7 @@ public class PassportCallEvent extends CallEvent return this; } - public Builder channel( int channel ) + public Builder channel( String channel ) { mChannel = channel; return this; diff --git a/src/decode/passport/PassportChannelState.java b/src/decode/passport/PassportChannelState.java index b8adf1a8..39131b3b 100644 --- a/src/decode/passport/PassportChannelState.java +++ b/src/decode/passport/PassportChannelState.java @@ -146,7 +146,7 @@ public class PassportChannelState extends ChannelState mCurrentCallEvent = new PassportCallEvent .Builder( CallEventType.CALL ) .aliasList( mAliasList ) - .channel( mChannelNumber ) + .channel( String.valueOf( mChannelNumber ) ) .frequency( passport.getLCNFrequency() ) .to( String.valueOf( passport.getTalkgroupID() ) ) .build(); @@ -179,7 +179,7 @@ public class PassportChannelState extends ChannelState PassportCallEvent event = new PassportCallEvent .Builder( CallEventType.CALL_DETECT ) .aliasList( mAliasList ) - .channel( lcn ) + .channel( String.valueOf( lcn ) ) .details( "Site: " + passport.getSite() ) .frequency( passport.getLCNFrequency() ) .to( tg ) @@ -220,7 +220,7 @@ public class PassportChannelState extends ChannelState mCallEventModel.add( new PassportCallEvent .Builder( CallEventType.REGISTER ) .aliasList( mAliasList ) - .channel( passport.getLCN() ) + .channel( String.valueOf( passport.getLCN() ) ) .frequency( passport.getLCNFrequency() ) .to( passport.getToID() ) .build() ); diff --git a/src/dsp/fsk/P25MessageFramer.java b/src/dsp/fsk/P25MessageFramer.java index 3bacc2c8..1622d7e5 100644 --- a/src/dsp/fsk/P25MessageFramer.java +++ b/src/dsp/fsk/P25MessageFramer.java @@ -12,6 +12,8 @@ import alias.AliasList; import bits.BitSetBuffer; import bits.BitSetFullException; import bits.SyncPatternMatcher; +import crc.CRC; +import crc.CRCP25NetworkID; import decode.p25.P25Interleave; import decode.p25.TrellisHalfRate; import decode.p25.message.P25Message; @@ -218,13 +220,22 @@ public class P25MessageFramer implements Listener switch( mDUID ) { case NID: - int value = mMessage.getInt( P25Message.DUID ); - - DataUnitID duid = DataUnitID.fromValue( value ); - - if( duid != DataUnitID.UNKN ) + CRC crc = CRCP25NetworkID.checkAndCorrect( mMessage ); + + if( crc != CRC.FAILED_CRC ) { - setDUID( duid ); + int value = mMessage.getInt( P25Message.DUID ); + + DataUnitID duid = DataUnitID.fromValue( value ); + + if( duid != DataUnitID.UNKN ) + { + setDUID( duid ); + } + else + { + mComplete = true; + } } else { @@ -247,155 +258,187 @@ public class P25MessageFramer implements Listener /* Remove interleaving */ P25Interleave.deinterleave( mMessage, PDU0_BEGIN, PDU0_END ); - /* Remove trellis encoding */ - mHalfRate.decode( mMessage, PDU0_BEGIN, PDU0_END ); - - setDUID( DataUnitID.PDU1 ); - - mMessage.setPointer( PDU1_BEGIN ); + /* Remove trellis encoding - abort processing if we have an + * unsuccessful decode due to excessive errors */ + if( mHalfRate.decode( mMessage, PDU0_BEGIN, PDU0_END ) ) + { + setDUID( DataUnitID.PDU1 ); + + mMessage.setPointer( PDU1_BEGIN ); + } + else + { + mComplete = true; + } break; case PDU1: /* Remove interleaving */ P25Interleave.deinterleave( mMessage, PDU1_BEGIN, PDU1_END ); - /* Remove trellis encoding */ - mHalfRate.decode( mMessage, PDU1_BEGIN, PDU1_END ); - - if( mMessage.getInt( PDUMessage.BLOCKS_TO_FOLLOW ) == 1 ) + /* Remove trellis encoding - abort processing if we have an + * unsuccessful decode due to excessive errors */ + if( mHalfRate.decode( mMessage, PDU1_BEGIN, PDU1_END ) ) { - mMessage.setSize( PDU2_BEGIN ); - - PDUMessage pduMessage1 = PDUMessageFactory.getMessage( - mMessage.copy(), DataUnitID.PDU1, mAliasList ); + if( mMessage.getInt( PDUMessage.BLOCKS_TO_FOLLOW ) == 1 ) + { + mMessage.setSize( PDU2_BEGIN ); + + PDUMessage pduMessage1 = PDUMessageFactory.getMessage( + mMessage.copy(), DataUnitID.PDU1, mAliasList ); - dispatch( pduMessage1 ); - - mComplete = true; + dispatch( pduMessage1 ); + + mComplete = true; + } + else + { + setDUID( DataUnitID.PDU2 ); + + mMessage.setPointer( PDU2_BEGIN ); + } } else { - setDUID( DataUnitID.PDU2 ); - - mMessage.setPointer( PDU2_BEGIN ); + mComplete = true; } break; case PDU2: /* Remove interleaving */ P25Interleave.deinterleave( mMessage, PDU2_BEGIN, PDU2_END ); - /* Remove trellis encoding */ - mHalfRate.decode( mMessage, PDU2_BEGIN, PDU2_END ); - - if( mMessage.getInt( PDUMessage.BLOCKS_TO_FOLLOW ) == 2 ) + /* Remove trellis encoding - abort processing if we have an + * unsuccessful decode due to excessive errors */ + if( mHalfRate.decode( mMessage, PDU2_BEGIN, PDU2_END ) ) { - mMessage.setSize( PDU3_BEGIN ); - - PDUMessage pduMessage2 = PDUMessageFactory.getMessage( - mMessage.copy(), DataUnitID.PDU2, mAliasList ); + if( mMessage.getInt( PDUMessage.BLOCKS_TO_FOLLOW ) == 2 ) + { + mMessage.setSize( PDU3_BEGIN ); + + PDUMessage pduMessage2 = PDUMessageFactory.getMessage( + mMessage.copy(), DataUnitID.PDU2, mAliasList ); - dispatch( pduMessage2 ); - - mComplete = true; + dispatch( pduMessage2 ); + + mComplete = true; + } + else + { + setDUID( DataUnitID.PDU3 ); + + mMessage.setPointer( PDU3_BEGIN ); + } } else { - setDUID( DataUnitID.PDU3 ); - - mMessage.setPointer( PDU3_BEGIN ); + mComplete = true; } break; case PDU3: /* Remove interleaving */ P25Interleave.deinterleave( mMessage, PDU3_BEGIN, PDU3_END ); - /* Remove trellis encoding */ - mHalfRate.decode( mMessage, PDU3_BEGIN, PDU3_END ); - - mMessage.setSize( PDU3_DECODED_END ); - - PDUMessage pduMessage3 = PDUMessageFactory.getMessage( - mMessage.copy(), DataUnitID.PDU3, mAliasList ); + /* Remove trellis encoding - abort processing if we have an + * unsuccessful decode due to excessive errors */ + if( mHalfRate.decode( mMessage, PDU3_BEGIN, PDU3_END ) ) + { + mMessage.setSize( PDU3_DECODED_END ); + + PDUMessage pduMessage3 = PDUMessageFactory.getMessage( + mMessage.copy(), DataUnitID.PDU3, mAliasList ); - dispatch( pduMessage3 ); + dispatch( pduMessage3 ); + } mComplete = true; break; case TDU: - mComplete = true; dispatch( new TDUMessage( mMessage.copy(), mDUID, mAliasList ) ); + mComplete = true; break; case TDULC: - mComplete = true; dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) ); + mComplete = true; break; case TSBK1: /* Remove interleaving */ P25Interleave.deinterleave( mMessage, TSBK_BEGIN, TSBK_END ); - /* Remove trellis encoding */ - mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END ); - - BitSetBuffer tsbkBuffer1 = mMessage.copy(); - tsbkBuffer1.setSize( TSBK_DECODED_END ); - - TSBKMessage tsbkMessage1 = TSBKMessageFactory.getMessage( - tsbkBuffer1, DataUnitID.TSBK1, mAliasList ); - - if( tsbkMessage1.isLastBlock() ) + /* Remove trellis encoding - abort processing if we have an + * unsuccessful decode due to excessive errors */ + if( mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END ) ) { - mComplete = true; + BitSetBuffer tsbkBuffer1 = mMessage.copy(); + tsbkBuffer1.setSize( TSBK_DECODED_END ); + + TSBKMessage tsbkMessage1 = TSBKMessageFactory.getMessage( + tsbkBuffer1, DataUnitID.TSBK1, mAliasList ); + + if( tsbkMessage1.isLastBlock() ) + { + mComplete = true; + } + else + { + setDUID( DataUnitID.TSBK2 ); + mMessage.setPointer( TSBK_BEGIN ); + } + + dispatch( tsbkMessage1 ); } else { - setDUID( DataUnitID.TSBK2 ); - mMessage.setPointer( TSBK_BEGIN ); + mComplete = true; } - - dispatch( tsbkMessage1 ); break; case TSBK2: /* Remove interleaving */ P25Interleave.deinterleave( mMessage, TSBK_BEGIN, TSBK_END ); - /* Remove trellis encoding */ - mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END ); - - BitSetBuffer tsbkBuffer2 = mMessage.copy(); - tsbkBuffer2.setSize( TSBK_DECODED_END ); - - TSBKMessage tsbkMessage2 = TSBKMessageFactory.getMessage( - tsbkBuffer2, DataUnitID.TSBK2, mAliasList ); - - if( tsbkMessage2.isLastBlock() ) + /* Remove trellis encoding - abort processing if we have an + * unsuccessful decode due to excessive errors */ + if( mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END ) ) { - mComplete = true; + BitSetBuffer tsbkBuffer2 = mMessage.copy(); + tsbkBuffer2.setSize( TSBK_DECODED_END ); + + TSBKMessage tsbkMessage2 = TSBKMessageFactory.getMessage( + tsbkBuffer2, DataUnitID.TSBK2, mAliasList ); + + if( tsbkMessage2.isLastBlock() ) + { + mComplete = true; + } + else + { + setDUID( DataUnitID.TSBK3 ); + mMessage.setPointer( TSBK_BEGIN ); + } + + dispatch( tsbkMessage2 ); } else { - setDUID( DataUnitID.TSBK3 ); - mMessage.setPointer( TSBK_BEGIN ); + mComplete = true; } - - dispatch( tsbkMessage2 ); - break; case TSBK3: /* Remove interleaving */ P25Interleave.deinterleave( mMessage, TSBK_BEGIN, TSBK_END ); - /* Remove trellis encoding */ - mHalfRate.decode( 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 ) ) + { + BitSetBuffer tsbkBuffer3 = mMessage.copy(); + tsbkBuffer3.setSize( TSBK_DECODED_END ); + + TSBKMessage tsbkMessage3 = TSBKMessageFactory.getMessage( + tsbkBuffer3, DataUnitID.TSBK3, mAliasList ); - BitSetBuffer tsbkBuffer3 = mMessage.copy(); - tsbkBuffer3.setSize( TSBK_DECODED_END ); - - TSBKMessage tsbkMessage3 = TSBKMessageFactory.getMessage( - tsbkBuffer3, DataUnitID.TSBK3, mAliasList ); + dispatch( tsbkMessage3 ); + } mComplete = true; - - dispatch( tsbkMessage3 ); - break; case UNKN: mComplete = true;