P25 Decoder work in progress

This commit is contained in:
dennis.sheirer
2014-11-14 12:53:32 +00:00
parent 46e3594c07
commit eee28a3449
28 changed files with 1033 additions and 97 deletions

View File

@@ -86,15 +86,16 @@ public class P25Decoder extends Decoder implements Instrumentable
mMessageProcessor = new P25MessageProcessor( mAliasList );
mNormalFramer = new P25MessageFramer(
FrameSync.P25_PHASE1.getSync(), 64, false );
mSlicer.addListener( mNormalFramer );
mNormalFramer.setListener( mMessageProcessor );
mNormalFramer = new P25MessageFramer(
FrameSync.P25_PHASE1.getSync(), 64, false, mAliasList );
mSlicer.addListener( mNormalFramer );
mNormalFramer.setListener( mMessageProcessor );
mInvertedFramer = new P25MessageFramer(
FrameSync.P25_PHASE1_INVERTED.getSync(), 64, true, mAliasList );
mSlicer.addListener( mInvertedFramer );
mInvertedFramer.setListener( mMessageProcessor );
mInvertedFramer = new P25MessageFramer(
FrameSync.P25_PHASE1_INVERTED.getSync(), 64, true );
mSlicer.addListener( mInvertedFramer );
mInvertedFramer.setListener( mMessageProcessor );
}
@Override

View File

@@ -1,10 +1,11 @@
package decode.p25.message;
import decode.p25.reference.DataUnitID;
import map.Plottable;
import message.Message;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
public class P25Message extends Message
{
@@ -16,13 +17,17 @@ public class P25Message extends Message
protected BitSetBuffer mMessage;
protected DataUnitID mDUID;
protected AliasList mAliasList;
public P25Message( BitSetBuffer message, DataUnitID duid )
public P25Message( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super();
mMessage = message;
mDUID = duid;
mAliasList = aliasList;
}
public String getNAC()

View File

@@ -1,31 +0,0 @@
package decode.p25.message;
import bits.BitSetBuffer;
import decode.p25.reference.Opcode;
import decode.p25.reference.Vendor;
public class TSBKMessageFactory
{
public static TSBKMessage getMessage( int system, BitSetBuffer buffer )
{
int opcode = buffer.getInt( TSBKMessage.OPCODE );
Vendor vendor = Vendor.fromValue(
buffer.getInt( TSBKMessage.VENDOR_ID ) );
switch( vendor )
{
case STANDARD:
switch( Opcode.fromValue( opcode ) )
{
}
return new TSBKMessage( system, buffer );
case MOTOROLA:
default:
return new TSBKMessage( system, buffer );
}
}
}

View File

@@ -1,10 +1,12 @@
package decode.p25.message;
package decode.p25.message.pdu;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.message.P25Message;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.PDUFormat;
import decode.p25.reference.ServiceAccessPoint;
import decode.p25.reference.Vendor;
import bits.BitSetBuffer;
public class PDUMessage extends P25Message
{
@@ -37,9 +39,9 @@ public class PDUMessage extends P25Message
155,156,157,158,159,160,161,162 };
//status 166,167
public PDUMessage( BitSetBuffer message, DataUnitID duid )
public PDUMessage( BitSetBuffer message, DataUnitID duid, AliasList aliasList )
{
super( message, duid );
super( message, duid, aliasList );
}
public String getConfirmation()

View File

@@ -0,0 +1,67 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
public abstract class ChannelGrant extends TSBKMessage
{
/* Service Options */
public static final int EMERGENCY_FLAG = 80;
public static final int ENCRYPTED_CHANNEL_FLAG = 81;
public static final int DUPLEX_MODE = 82;
public static final int SESSION_MODE = 83;
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 };
public enum DuplexMode { HALF, FULL };
public enum SessionMode { PACKET, CIRCUIT };
public ChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
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;
}
/**
* 1 = Lowest, 4 = Default, 7 = Highest
*/
public int getPriority()
{
return mMessage.getInt( PRIORITY );
}
public int getChannelID()
{
return mMessage.getInt( CHANNEL_ID );
}
public int getChannelNumber()
{
return mMessage.getInt( CHANNEL_NUMBER );
}
}

View File

@@ -0,0 +1,89 @@
package decode.p25.message.tsbk;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
public abstract class GroupChannelGrant extends ChannelGrant
{
public static final int[] GROUP_ADDRESS = { 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 GroupChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
public String getGroupAddress()
{
return mMessage.getHex( GROUP_ADDRESS, 4 );
}
public String getSourceAddress()
{
return mMessage.getHex( SOURCE_ADDRESS, 6 );
}
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( super.getMessage() );
if( isEmergency() )
{
sb.append( " EMERGENCY" );
}
sb.append( " CHAN:" );
sb.append( getChannelID() + "/" + getChannelNumber() );
sb.append( " FROM:" );
sb.append( getSourceAddress() );
sb.append( " GRP:" );
sb.append( getGroupAddress() );
return sb.toString();
}
@Override
public String getFromID()
{
return getSourceAddress();
}
@Override
public Alias getFromIDAlias()
{
if( mAliasList != null )
{
return mAliasList.getTalkgroupAlias( getFromID() );
}
return null;
}
@Override
public String getToID()
{
return getGroupAddress();
}
@Override
public Alias getToIDAlias()
{
if( mAliasList != null )
{
return mAliasList.getTalkgroupAlias( getGroupAddress() );
}
return null;
}
}

View File

@@ -0,0 +1,72 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
public abstract class GroupChannelGrantExplicit extends ChannelGrant
{
public static final int[] TRANSMIT_CHANNEL_ID = { 96,97,98,99 };
public static final int[] TRANSMIT_CHANNEL_NUMBER = { 100,101,102,103,
104,105,106,107,108,109,110,111 };
public static final int[] RECEIVE_CHANNEL_ID = { 112,113,114,115 };
public static final int[] RECEIVE_CHANNEL_NUMBER = { 116,117,118,119,
120,121,122,123,124,125,126,127 };
public static final int[] GROUP_ADDRESS = { 128,129,130,131,132,133,134,135,
136,137,138,139,140,141,142,143 };
public GroupChannelGrantExplicit( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( super.getMessage() );
if( isEmergency() )
{
sb.append( " EMERGENCY" );
}
sb.append( " XMIT:" );
sb.append( getTransmitChannelID() + "/" + getTransmitChannelNumber() );
sb.append( " RCV:" );
sb.append( getReceiveChannelID() + "/" + getReceiveChannelNumber() );
sb.append( " GRP:" );
sb.append( getGroupAddress() );
return sb.toString();
}
public int getTransmitChannelID()
{
return mMessage.getInt( TRANSMIT_CHANNEL_ID );
}
public int getTransmitChannelNumber()
{
return mMessage.getInt( TRANSMIT_CHANNEL_NUMBER );
}
public int getReceiveChannelID()
{
return mMessage.getInt( RECEIVE_CHANNEL_ID );
}
public int getReceiveChannelNumber()
{
return mMessage.getInt( RECEIVE_CHANNEL_NUMBER );
}
public String getGroupAddress()
{
return mMessage.getHex( GROUP_ADDRESS, 4 );
}
}

View File

@@ -0,0 +1,22 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class GroupDataChannelAnnouncement extends GroupMultiChannelGrant
{
public GroupDataChannelAnnouncement( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.GROUP_DATA_CHANNEL_ANNOUNCEMENT.getDescription();
}
}

View File

@@ -0,0 +1,22 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class GroupDataChannelAnnouncementExplicit extends GroupChannelGrantExplicit
{
public GroupDataChannelAnnouncementExplicit( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.GROUP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT.getDescription();
}
}

View File

@@ -0,0 +1,23 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class GroupDataChannelGrant extends GroupChannelGrant
{
public GroupDataChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.GROUP_DATA_CHANNEL_GRANT.getDescription();
}
}

View File

@@ -0,0 +1,112 @@
package decode.p25.message.tsbk;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
public abstract class GroupMultiChannelGrant extends ChannelGrant
{
public static final int[] CHANNEL_ID_1 = { 80,81,82,83 };
public static final int[] CHANNEL_NUMBER_1 = { 84,85,86,87,
88,89,90,91,92,93,94,95 };
public static final int[] GROUP_ADDRESS_1 = { 96,97,98,99,100,101,102,103 };
public static final int[] CHANNEL_ID_2 = { 104,105,106,107 };
public static final int[] CHANNEL_NUMBER_2 = { 108,109,110,111,
112,113,114,115,116,117,118,119 };
public static final int[] GROUP_ADDRESS_2 = { 120,121,122,123,124,125,126,
127,128,129,130,131,132,133,134,135 };
public GroupMultiChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( super.getMessage() );
sb.append( " CHAN1:" );
sb.append( getChannelID1() + "/" + getChannelNumber1() );
sb.append( " GRP1:" );
sb.append( getGroupAddress1() );
sb.append( " CHAN2:" );
sb.append( getChannelID2() + "/" + getChannelNumber2() );
sb.append( " GRP2:" );
sb.append( getGroupAddress2() );
return sb.toString();
}
public int getChannelID1()
{
return mMessage.getInt( CHANNEL_ID_1 );
}
public int getChannelNumber1()
{
return mMessage.getInt( CHANNEL_NUMBER_1 );
}
public String getGroupAddress1()
{
return mMessage.getHex( GROUP_ADDRESS_1, 4 );
}
public int getChannelID2()
{
return mMessage.getInt( CHANNEL_ID_2 );
}
public int getChannelNumber2()
{
return mMessage.getInt( CHANNEL_NUMBER_2 );
}
public String getGroupAddress2()
{
return mMessage.getHex( GROUP_ADDRESS_2, 4 );
}
@Override
public String getFromID()
{
return getGroupAddress1();
}
@Override
public Alias getFromIDAlias()
{
if( mAliasList != null )
{
return mAliasList.getTalkgroupAlias( getFromID() );
}
return null;
}
@Override
public String getToID()
{
return getGroupAddress2();
}
@Override
public Alias getToIDAlias()
{
if( mAliasList != null )
{
return mAliasList.getTalkgroupAlias( getToID() );
}
return null;
}
}

View File

@@ -0,0 +1,23 @@
package decode.p25.message.tsbk;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class GroupVoiceChannelGrant extends GroupChannelGrant
{
public GroupVoiceChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.GROUP_VOICE_CHANNEL_GRANT.getDescription();
}
}

View File

@@ -0,0 +1,22 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class GroupVoiceChannelGrantUpdate extends GroupMultiChannelGrant
{
public GroupVoiceChannelGrantUpdate( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.GROUP_VOICE_CHANNEL_GRANT.getDescription();
}
}

View File

@@ -0,0 +1,22 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class GroupVoiceChannelGrantUpdateExplicit extends GroupChannelGrantExplicit
{
public GroupVoiceChannelGrantUpdateExplicit( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT.getDescription();
}
}

View File

@@ -0,0 +1,22 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class IndividualDataChannelGrant extends UnitChannelGrant
{
public IndividualDataChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.INDIVIDUAL_DATA_CHANNEL_GRANT.getDescription();
}
}

View File

@@ -1,20 +1,24 @@
package decode.p25.message;
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.message.P25Message;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
import decode.p25.reference.Vendor;
import bits.BitSetBuffer;
public class TSBKMessage extends P25Message
{
public static final int LAST_BLOCK_FLAG = 0;
public static final int ENCRYPTED_FLAG = 1;
public static final int[] OPCODE = { 2,3,4,5,6,7 };
public static final int[] VENDOR_ID = { 8,9,10,11,12,13,14,15 };
public TSBKMessage( int system, BitSetBuffer message )
public static final int LAST_BLOCK_FLAG = 64;
public static final int ENCRYPTED_FLAG = 65;
public static final int[] OPCODE = { 66,67,68,69,70,71 };
public static final int[] VENDOR_ID = { 72,73,74,75,76,77,78,79 };
public static final int[] CRC = { 144,145,146,147,148,149,150,151,152,153,
154,155,156,157,158,159 };
public TSBKMessage( BitSetBuffer message, DataUnitID duid, AliasList aliasList )
{
super( message, DataUnitID.TSBK1 );
super( message, duid, aliasList );
}
public boolean isLastBlock()

View File

@@ -0,0 +1,57 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
import decode.p25.reference.Vendor;
public class TSBKMessageFactory
{
public static TSBKMessage getMessage( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
int opcode = message.getInt( TSBKMessage.OPCODE );
Vendor vendor = Vendor.fromValue(
message.getInt( TSBKMessage.VENDOR_ID ) );
switch( vendor )
{
case STANDARD:
switch( Opcode.fromValue( opcode ) )
{
case GROUP_VOICE_CHANNEL_GRANT:
return new GroupVoiceChannelGrant( message, duid,
aliasList );
case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
return new GroupVoiceChannelGrantUpdate( message, duid,
aliasList );
case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
return new GroupVoiceChannelGrantUpdateExplicit( message,
duid, aliasList );
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
return new TelephoneInterconnectVoiceChannelGrant(
message, duid, aliasList );
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
return new TelephoneInterconnectAnswerRequest(
message, duid, aliasList );
case UNIT_TO_UNIT_ANSWER_REQUEST:
return new UnitToUnitAnswerRequest( message, duid,
aliasList );
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
return new UnitToUnitVoiceChannelGrant( message,
duid, aliasList );
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
return new UnitToUnitVoiceChannelGrantUpdate( message,
duid, aliasList );
default:
return new TSBKMessage( message, duid, aliasList );
}
case MOTOROLA:
default:
return new TSBKMessage( message, duid, aliasList );
}
}
}

View File

@@ -0,0 +1,96 @@
package decode.p25.message.tsbk;
import java.util.ArrayList;
import java.util.List;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Digit;
import decode.p25.reference.Opcode;
public class TelephoneInterconnectAnswerRequest extends TSBKMessage
{
public static final int[] DIGIT_1 = { 80,81,82,83 };
public static final int[] DIGIT_2 = { 84,85,86,87 };
public static final int[] DIGIT_3 = { 88,89,90,91 };
public static final int[] DIGIT_4 = { 92,93,94,95 };
public static final int[] DIGIT_5 = { 96,97,98,99 };
public static final int[] DIGIT_6 = { 100,101,102,103 };
public static final int[] DIGIT_7 = { 104,105,106,107 };
public static final int[] DIGIT_8 = { 108,109,110,111 };
public static final int[] DIGIT_9 = { 112,113,114,115 };
public static final int[] DIGIT_10 = { 116,117,118,119 };
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 };
public TelephoneInterconnectAnswerRequest( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( super.getMessage() );
sb.append( " TO:" );
sb.append( getTargetAddress() );
sb.append( " TEL:" );
sb.append( getTelephoneNumber() );
return sb.toString();
}
public String getTelephoneNumber()
{
List<Integer> digits = new ArrayList<Integer>();
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 );
}
public String getTargetAddress()
{
return mMessage.getHex( TARGET_ADDRESS, 6 );
}
@Override
public String getEventType()
{
return Opcode.TELEPHONE_INTERCONNECT_ANSWER_REQUEST.getDescription();
}
@Override
public String getToID()
{
return getTargetAddress();
}
@Override
public Alias getToIDAlias()
{
if( mAliasList != null )
{
return mAliasList.getTalkgroupAlias( getToID() );
}
return null;
}
}

View File

@@ -0,0 +1,58 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class TelephoneInterconnectVoiceChannelGrant extends UnitChannelGrant
{
public static final int[] CALL_TIMER = { 96,97,98,99,100,101,102,103,
104,105,106,107,108,109,110,111 };
public TelephoneInterconnectVoiceChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( super.getMessage() );
if( isEmergency() )
{
sb.append( " EMERGENCY" );
}
sb.append( " CHAN:" );
sb.append( getChannelID() + "/" + getChannelNumber() );
sb.append( " CALL TIMER:" );
sb.append( getCallTimer() );
sb.append( " SECS TO:" );
sb.append( getToID() );
return sb.toString();
}
/**
* Call timer in seconds
*/
public int getCallTimer()
{
int units = mMessage.getInt( CALL_TIMER );
return (int)( units / 10 );
}
@Override
public String getEventType()
{
return Opcode.TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT.getDescription();
}
}

View File

@@ -0,0 +1,23 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class TelephoneInterconnectVoiceChannelGrantUpdate
extends TelephoneInterconnectVoiceChannelGrant
{
public TelephoneInterconnectVoiceChannelGrantUpdate( BitSetBuffer message,
DataUnitID duid, AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE.getDescription();
}
}

View File

@@ -0,0 +1,86 @@
package decode.p25.message.tsbk;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
public abstract class UnitChannelGrant extends ChannelGrant
{
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 UnitChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( super.getMessage() );
if( isEmergency() )
{
sb.append( " EMERGENCY" );
}
sb.append( " FROM:" );
sb.append( getSourceAddress() );
sb.append( " TO:" );
sb.append( getTargetAddress() );
return sb.toString();
}
public String getTargetAddress()
{
return mMessage.getHex( TARGET_ADDRESS, 6 );
}
public String getSourceAddress()
{
return mMessage.getHex( SOURCE_ADDRESS, 6 );
}
@Override
public String getFromID()
{
return getSourceAddress();
}
@Override
public Alias getFromIDAlias()
{
if( mAliasList != null )
{
return mAliasList.getTalkgroupAlias( getFromID() );
}
return null;
}
@Override
public String getToID()
{
return getTargetAddress();
}
@Override
public Alias getToIDAlias()
{
if( mAliasList != null )
{
return mAliasList.getTalkgroupAlias( getToID() );
}
return null;
}
}

View File

@@ -0,0 +1,22 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class UnitToUnitAnswerRequest extends UnitChannelGrant
{
public UnitToUnitAnswerRequest( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.UNIT_TO_UNIT_ANSWER_REQUEST.getDescription();
}
}

View File

@@ -0,0 +1,22 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class UnitToUnitVoiceChannelGrant extends UnitChannelGrant
{
public UnitToUnitVoiceChannelGrant( BitSetBuffer message,
DataUnitID duid,
AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.UNIT_TO_UNIT_VOICE_CHANNEL_GRANT.getDescription();
}
}

View File

@@ -0,0 +1,21 @@
package decode.p25.message.tsbk;
import alias.AliasList;
import bits.BitSetBuffer;
import decode.p25.reference.DataUnitID;
import decode.p25.reference.Opcode;
public class UnitToUnitVoiceChannelGrantUpdate extends UnitChannelGrant
{
public UnitToUnitVoiceChannelGrantUpdate( BitSetBuffer message,
DataUnitID duid, AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getEventType()
{
return Opcode.UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE.getDescription();
}
}

View File

@@ -0,0 +1,81 @@
package decode.p25.reference;
import java.util.List;
public enum Digit
{
D0( "0", "A" ),
D1( "1", "B" ),
D2( "2", "C" ),
D3( "3", "D" ),
D4( "4", "-" ),
D5( "5", "-" ),
D6( "6", "-" ),
D7( "7", "-" ),
D8( "8", "-" ),
D9( "9", "-" ),
D10( "*", "-" ),
D11( "#", "-" ),
D12( "-", "-" ),
D13( "HOOK FLASH", "-" ),
D14( "PAUSE", "-" ),
D15( "ESC", "NULL" ),
DUNK( "?", "?" );
private String mValue;
private String mEscapedValue;
private Digit( String value, String escapedValue )
{
mValue = value;
mEscapedValue = escapedValue;
}
public String getValue()
{
return mValue;
}
public String getEscapedValue()
{
return mEscapedValue;
}
public static Digit fromValue( int value )
{
if( 0 <= value && value <= 15 )
{
return values()[ value ];
}
return DUNK;
}
public static String decode( List<Integer> values )
{
StringBuilder sb = new StringBuilder();
boolean escape = false;
for( Integer value: values )
{
Digit d = Digit.fromValue( value );
if( d == Digit.D15 )
{
escape = true;
}
else if( escape )
{
sb.append( d.getEscapedValue() );
escape = false;
}
else
{
sb.append( d.getValue() );
}
}
return sb.toString();
}
}

View File

@@ -4,14 +4,14 @@ public enum Opcode
{
GROUP_VOICE_CHANNEL_GRANT( "Group Voice Channel Grant", 0 ),
RESERVED_01( "Reserved", 1 ),
GROUP_VOICE_CHANNLE_GRANT_UPDATE( "Group Voice Channel Grant Update", 2 ),
GROUP_VOICE_CHANNEL_GRANT_UPDATE( "Group Voice Channel Grant Update", 2 ),
GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT( "Group Voice Channel Grant Update - Explicit", 3 ),
UNIT_TO_UNIT_VOICE_CHANNEL_GRANT( "Unit-to-Unit Voice Channel Grant", 4 ),
UNIT_TO_UNIT_ANSWER_REQUEST( "Unit-to-Unit Answer Request", 5 ),
UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE( "Unit-to-Unit Voice Channel Grant Update", 6 ),
RESERVED_07( "Reserved", 7 ),
TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT( "Telephone Interconnect Voice Channel Grant", 8 ),
RESERVED_09( "Reserved", 9 ),
TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE( "Telephone Interconnect Voice Channel Grant Update", 9 ),
TELEPHONE_INTERCONNECT_ANSWER_REQUEST( "Telephone Interconnect Answer Request", 10 ),
RESERVED_0B( "Reserved", 11 ),
RESERVED_0C( "Reserved", 12 ),

View File

@@ -1,7 +1,6 @@
package dsp.fsk;
import java.util.ArrayList;
import java.util.BitSet;
import message.Message;
@@ -9,15 +8,16 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import alias.AliasList;
import bits.BitSetBuffer;
import bits.BitSetFullException;
import bits.SyncPatternMatcher;
import decode.p25.P25Interleave;
import decode.p25.TrellisHalfRate;
import decode.p25.message.P25Message;
import decode.p25.message.PDUMessage;
import decode.p25.message.TSBKMessage;
import decode.p25.message.TSBKMessageFactory;
import decode.p25.message.pdu.PDUMessage;
import decode.p25.message.tsbk.TSBKMessage;
import decode.p25.message.tsbk.TSBKMessageFactory;
import decode.p25.reference.DataUnitID;
public class P25MessageFramer implements Listener<C4FMSymbol>
@@ -36,6 +36,7 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
public static final int TSBK_DECODED_END = 162;
private Listener<Message> mListener;
private AliasList mAliasList;
private SyncPatternMatcher mMatcher;
private boolean mInverted = false;
private TrellisHalfRate mHalfRate = new TrellisHalfRate();
@@ -51,10 +52,14 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
* @param inverted - optional flag to indicate the symbol stream should be
* uninverted prior to processing
*/
public P25MessageFramer( long sync, int messageLength, boolean inverted )
public P25MessageFramer( long sync,
int messageLength,
boolean inverted,
AliasList aliasList )
{
mMatcher = new SyncPatternMatcher( sync );
mInverted = inverted;
mAliasList = aliasList;
/**
* We use two message assemblers to catch any sync detections, so that
@@ -218,15 +223,15 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
break;
case HDU:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case LDU1:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case LDU2:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case PDU1:
int blocks = mMessage.getInt(
@@ -245,22 +250,22 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
}
else
{
dispatch( new PDUMessage( mMessage.copy(), mDUID ) );
dispatch( new PDUMessage( mMessage.copy(), mDUID, mAliasList ) );
mComplete = true;
}
break;
case PDU2:
case PDU3:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case TDU:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case TDULC:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case TSBK1:
/* Remove interleaving */
@@ -269,14 +274,10 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
/* Remove trellis encoding */
mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END );
/* Construct the message */
int tsbkSystem1 = mMessage.getInt( P25Message.NAC );
BitSetBuffer tsbkBuffer1 = new BitSetBuffer( mMessage.get(
TSBK_BEGIN, TSBK_DECODED_END ), 96 );
BitSetBuffer tsbkBuffer1 = mMessage.copy();
TSBKMessage tsbkMessage1 =
TSBKMessageFactory.getMessage( tsbkSystem1, tsbkBuffer1 );
TSBKMessage tsbkMessage1 = TSBKMessageFactory.getMessage(
tsbkBuffer1, DataUnitID.TSBK1, mAliasList );
if( tsbkMessage1.isLastBlock() )
{
@@ -297,14 +298,10 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
/* Remove trellis encoding */
mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END );
/* Construct the message */
int tsbkSystem2 = mMessage.getInt( P25Message.NAC );
BitSetBuffer tsbkBuffer2 = new BitSetBuffer( mMessage.get(
TSBK_BEGIN, TSBK_DECODED_END ), 98 );
BitSetBuffer tsbkBuffer2 = mMessage.copy();
TSBKMessage tsbkMessage2 =
TSBKMessageFactory.getMessage( tsbkSystem2, tsbkBuffer2 );
TSBKMessage tsbkMessage2 = TSBKMessageFactory.getMessage(
tsbkBuffer2, DataUnitID.TSBK2, mAliasList );
if( tsbkMessage2.isLastBlock() )
{
@@ -326,14 +323,10 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
/* Remove trellis encoding */
mHalfRate.decode( mMessage, TSBK_BEGIN, TSBK_END );
/* Construct the message */
int tsbkSystem3 = mMessage.getInt( P25Message.NAC );
BitSetBuffer tsbkBuffer3 = new BitSetBuffer( mMessage.get(
TSBK_BEGIN, TSBK_DECODED_END ), 96 );
TSBKMessage tsbkMessage3 =
TSBKMessageFactory.getMessage( tsbkSystem3, tsbkBuffer3 );
BitSetBuffer tsbkBuffer3 = mMessage.copy();
TSBKMessage tsbkMessage3 = TSBKMessageFactory.getMessage(
tsbkBuffer3, DataUnitID.TSBK3, mAliasList );
mComplete = true;
@@ -342,7 +335,7 @@ public class P25MessageFramer implements Listener<C4FMSymbol>
break;
case UNKN:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
break;
default:
mComplete = true;

View File

@@ -363,12 +363,12 @@ public abstract class FCDTunerController extends TunerController
throw new LibUsbException( "error writing byte buffer",
result );
}
else if( transferred.get() != buffer.capacity() )
{
throw new LibUsbException( "transferred bytes [" +
transferred.get( 0 ) + "] is not what was expected [" +
buffer.capacity() + "]", result );
}
// else if( transferred.get() != buffer.capacity() )
// {
// throw new LibUsbException( "transferred bytes [" +
// transferred.get( 0 ) + "] is not what was expected [" +
// buffer.capacity() + "]", result );
// }
}
else
{