mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
1205 lines
27 KiB
Java
1205 lines
27 KiB
Java
/*******************************************************************************
|
|
* 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 <http://www.gnu.org/licenses/>
|
|
******************************************************************************/
|
|
package decode.mpt1327;
|
|
|
|
import java.text.DecimalFormat;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.BitSet;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.GregorianCalendar;
|
|
|
|
import map.Plottable;
|
|
import message.Message;
|
|
import alias.Alias;
|
|
import alias.AliasList;
|
|
import bits.BitSetBuffer;
|
|
import crc.CRC;
|
|
import crc.CRCFleetsync;
|
|
|
|
public class MPT1327Message extends Message
|
|
{
|
|
private static DecimalFormat mDecimalFormatter = new DecimalFormat("#.#####");
|
|
private static SimpleDateFormat mSDF = new SimpleDateFormat( "yyyyMMdd HHmmss" );
|
|
|
|
//Calendar to use in calculating time hacks
|
|
Calendar mCalendar = new GregorianCalendar();
|
|
|
|
//Message parts are identified in big-endian order for correct translation
|
|
private static int BLOCK_1_START = 20;
|
|
private static int BLOCK_2_START = 84;
|
|
private static int BLOCK_3_START = 148;
|
|
private static int BLOCK_4_START = 212;
|
|
private static int BLOCK_5_START = 276;
|
|
private static int BLOCK_5_END = 340;
|
|
private static int[] REVS = { 0,1,2,3 };
|
|
private static int[] SYNC = { 4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 };
|
|
|
|
/* Block 1 Fields */
|
|
private static int[] B1_PREFIX = { 21,22,23,24,25,26,27 };
|
|
private static int[] B1_IDENT1 = { 28,29,30,31,32,33,34,35,36,37,38,39,40 };
|
|
private static int[] B1_IDENT2_GTC = { 53,54,55,56,57,58,59,60,61,62,63,64,65 };
|
|
private static int[] B1_IDENT2 = { 50,51,52,53,54,55,56,57,58,59,60,61,62 };
|
|
private static int[] B1_GTC_CHAN = { 43,44,45,46,47,48,49,50,51,52 };
|
|
private static int[] B1_MESSAGE_TYPE = { 41,42,43,44,45,46,47,48,49 };
|
|
private static int[] B1_STATUS_MESSAGE = { 66,67,68,69,70 };
|
|
private static int[] B1_SYSTEM_ID = { 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
|
|
private static int[] B1_SYSDEF = { 21,22,23,24,25 };
|
|
private static int[] B1_CHANNEL = { 35,36,37,38,39,40,41,42,43,44 };
|
|
private static int[] B1_TRAFFIC_CHANNEL = { 21,22,23,24,25,26,27,28,29,30 };
|
|
private static int[] B1_CONTROL_CHANNEL = { 31,32,33,34,35,36,37,38,39,40 };
|
|
private static int[] B1_ADJSITE = { 49,50,51,52 };
|
|
private static int[] B1_SLOTS = { 63,64 };
|
|
private static int[] B1_DESCRIPTOR = { 65,66,67 };
|
|
|
|
|
|
/* Block 2 Fields */
|
|
private static int[] B2_SYSTEM_ID = { 85,86,87,88,89,90,91,92,93,94,95,96,97,98,99 };
|
|
private static int[] B2_PREFIX = { 112,113,114,115,116,117,118 };
|
|
private static int[] B2_IDENT2 = { 119,120,121,122,123,124,125,126,127,128,129,130,131 };
|
|
|
|
private BitSetBuffer mMessage;
|
|
private CRC[] mCRC = new CRC[ 5 ];
|
|
private AliasList mAliasList;
|
|
private MPTMessageType mMessageType;
|
|
|
|
public MPT1327Message( BitSetBuffer message, AliasList list )
|
|
{
|
|
mMessage = message;
|
|
mAliasList = list;
|
|
|
|
checkParity( 0, BLOCK_1_START, BLOCK_2_START );
|
|
|
|
if( isValid() )
|
|
{
|
|
mMessageType = getMessageType();
|
|
|
|
switch( mMessageType )
|
|
{
|
|
/* 1 data block messages */
|
|
case CLEAR:
|
|
case MAINT:
|
|
case MOVE:
|
|
break;
|
|
/* 2 data block messages */
|
|
case AHYQ:
|
|
case ALH:
|
|
checkParity( 1, BLOCK_2_START, BLOCK_3_START );
|
|
break;
|
|
/* 3 data block messages */
|
|
/* 4 data block messages */
|
|
case ACKT:
|
|
checkParity( 1, BLOCK_2_START, BLOCK_3_START );
|
|
checkParity( 2, BLOCK_3_START, BLOCK_4_START );
|
|
checkParity( 3, BLOCK_4_START, BLOCK_5_START );
|
|
break;
|
|
/* 5 data block messages */
|
|
case AHYC:
|
|
checkParity( 1, BLOCK_2_START, BLOCK_3_START );
|
|
checkParity( 2, BLOCK_3_START, BLOCK_4_START );
|
|
checkParity( 3, BLOCK_4_START, BLOCK_5_START );
|
|
checkParity( 4, BLOCK_5_START, BLOCK_5_END );
|
|
break;
|
|
case ACK:
|
|
case ACKB:
|
|
case ACKE:
|
|
case ACKI:
|
|
case ACKQ:
|
|
case ACKV:
|
|
case ACKX:
|
|
case AHOY:
|
|
case AHYP:
|
|
case AHYX:
|
|
case ALHD:
|
|
case ALHE:
|
|
case ALHF:
|
|
case ALHR:
|
|
case ALHS:
|
|
case ALHX:
|
|
case BCAST:
|
|
case GTC:
|
|
case MARK:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mMessageType = MPTMessageType.UNKN;
|
|
}
|
|
}
|
|
|
|
private void checkParity( int section, int start, int end )
|
|
{
|
|
mCRC[ section ] = detectAndCorrect( start, end );
|
|
}
|
|
|
|
private CRC detectAndCorrect( int start, int end )
|
|
{
|
|
BitSet original = mMessage.get( start, end );
|
|
|
|
CRC retVal = CRCFleetsync.check( original );
|
|
|
|
//Attempt to correct single-bit errors
|
|
if( retVal == CRC.FAILED_PARITY )
|
|
{
|
|
int[] errorBitPositions = CRCFleetsync.findBitErrors( original );
|
|
|
|
if( errorBitPositions != null )
|
|
{
|
|
for( int errorBitPosition: errorBitPositions )
|
|
{
|
|
mMessage.flip( start + errorBitPosition );
|
|
}
|
|
|
|
retVal = CRC.CORRECTED;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* String representing results of the parity check
|
|
*
|
|
* [P] = passes parity check
|
|
* [f] = fails parity check
|
|
* [C] = corrected message
|
|
* [-] = message section not present
|
|
*/
|
|
public String getParity()
|
|
{
|
|
return "[" + CRC.format( mCRC ) + "]";
|
|
}
|
|
|
|
public boolean isValid()
|
|
{
|
|
return mCRC[ 0 ] == CRC.PASSED ||
|
|
mCRC[ 0 ] == CRC.CORRECTED;
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
sb.append( mSDF.format( new Date() ) );
|
|
|
|
sb.append( " MPT1327 " );
|
|
|
|
sb.append( getParity() );
|
|
|
|
sb.append( " " );
|
|
|
|
sb.append( getMessage() );
|
|
|
|
sb.append( getFiller( sb, 100 ) );
|
|
|
|
sb.append( " [" + mMessage.toString() + "]" );
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
public MPTMessageType getMessageType()
|
|
{
|
|
int type = mMessage.getInt( B1_MESSAGE_TYPE );
|
|
|
|
return MPTMessageType.fromNumber( type );
|
|
}
|
|
|
|
public int getSiteID()
|
|
{
|
|
if( mMessageType == MPTMessageType.BCAST )
|
|
{
|
|
return mMessage.getInt( B1_SYSTEM_ID );
|
|
}
|
|
else if( mMessageType == MPTMessageType.ALH )
|
|
{
|
|
return mMessage.getInt( B2_SYSTEM_ID );
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public boolean hasSystemID()
|
|
{
|
|
return getSiteID() != 0;
|
|
}
|
|
|
|
public SystemDefinition getSystemDefinition()
|
|
{
|
|
int sysdef = mMessage.getInt( B1_SYSDEF );
|
|
|
|
return SystemDefinition.fromNumber( sysdef );
|
|
}
|
|
|
|
public int getChannel()
|
|
{
|
|
switch( mMessageType )
|
|
{
|
|
case CLEAR:
|
|
return mMessage.getInt( B1_TRAFFIC_CHANNEL );
|
|
case GTC:
|
|
return mMessage.getInt( B1_GTC_CHAN );
|
|
default:
|
|
return mMessage.getInt( B1_CHANNEL );
|
|
}
|
|
}
|
|
|
|
public int getReturnToChannel()
|
|
{
|
|
if( mMessageType == MPTMessageType.CLEAR )
|
|
{
|
|
return mMessage.getInt( B1_CONTROL_CHANNEL );
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public int getAdjacentSiteSerialNumber()
|
|
{
|
|
return mMessage.getInt( B1_ADJSITE );
|
|
}
|
|
|
|
public int getPrefix()
|
|
{
|
|
return mMessage.getInt( B1_PREFIX );
|
|
}
|
|
|
|
public int getBlock2Prefix()
|
|
{
|
|
return mMessage.getInt( B2_PREFIX );
|
|
}
|
|
|
|
public int getIdent1()
|
|
{
|
|
return mMessage.getInt( B1_IDENT1 );
|
|
}
|
|
|
|
public IdentType getIdent1Type()
|
|
{
|
|
return IdentType.fromIdent( getIdent1() );
|
|
}
|
|
|
|
public int getIdent2()
|
|
{
|
|
if( getMessageType() == MPTMessageType.GTC )
|
|
{
|
|
return mMessage.getInt( B1_IDENT2_GTC );
|
|
}
|
|
else
|
|
{
|
|
return mMessage.getInt( B1_IDENT2 );
|
|
}
|
|
}
|
|
|
|
public IdentType getIdent2Type()
|
|
{
|
|
return IdentType.fromIdent( getIdent2() );
|
|
}
|
|
|
|
public int getBlock2Ident2()
|
|
{
|
|
return mMessage.getInt( B2_IDENT2 );
|
|
}
|
|
|
|
public String getStatusMessage()
|
|
{
|
|
int status = mMessage.getInt( B1_STATUS_MESSAGE );
|
|
|
|
switch( status )
|
|
{
|
|
case 0:
|
|
return "STATUS: Request Speech Call";
|
|
case 31:
|
|
return "STATUS: Cancel Request Speech Call";
|
|
default:
|
|
return "STATUS: " + status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns spaces to the fill the string builder to ensure length is >= index
|
|
*/
|
|
public String getFiller( StringBuilder sb, int index )
|
|
{
|
|
if( sb.length() < index )
|
|
{
|
|
return String.format( "%" + ( index - sb.length() ) + "s", " " );
|
|
}
|
|
else
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Pads spaces onto the end of the value to make it 'places' long
|
|
*/
|
|
public String pad( String value, int places, String padCharacter )
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
sb.append( value );
|
|
|
|
while( sb.length() < places )
|
|
{
|
|
sb.append( padCharacter );
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Pads an integer value with additional zeroes to make it decimalPlaces long
|
|
*/
|
|
public String format( int number, int decimalPlaces )
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
int paddingRequired = decimalPlaces - ( String.valueOf( number ).length() );
|
|
|
|
for( int x = 0; x < paddingRequired; x++)
|
|
{
|
|
sb.append( "0" );
|
|
}
|
|
|
|
sb.append( number );
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
@Override
|
|
public String getMessage()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
sb.append( pad( mMessageType.toString(), 5, " " ) );
|
|
|
|
switch( mMessageType )
|
|
{
|
|
case ACK:
|
|
sb.append( " ACKNOWLEDGE " );
|
|
|
|
if( hasFromID() )
|
|
{
|
|
sb.append( getFromID() );
|
|
}
|
|
|
|
IdentType type = getIdent1Type();
|
|
|
|
switch( type )
|
|
{
|
|
case ALLI:
|
|
case IPFIXI:
|
|
case PABXI:
|
|
case PSTNGI:
|
|
case PSTNSI1:
|
|
case PSTNSI2:
|
|
case PSTNSI3:
|
|
case PSTNSI4:
|
|
case PSTNSI5:
|
|
case PSTNSI6:
|
|
case PSTNSI7:
|
|
case PSTNSI8:
|
|
case PSTNSI9:
|
|
case PSTNSI10:
|
|
case PSTNSI11:
|
|
case PSTNSI12:
|
|
case PSTNSI13:
|
|
case PSTNSI14:
|
|
case PSTNSI15:
|
|
case USER:
|
|
sb.append( type.getLabel() );
|
|
sb.append( " CALL REQUEST" );
|
|
break;
|
|
case TSCI:
|
|
sb.append( " RQQ or RQC TRANSACTION" );
|
|
break;
|
|
case DIVERTI:
|
|
sb.append( " CANCELLATION OF CALL DIVERSION REQUEST" );
|
|
break;
|
|
default:
|
|
sb.append( " " );
|
|
sb.append( type.getLabel() );
|
|
sb.append( " REQUEST" );
|
|
}
|
|
break;
|
|
case ACKI:
|
|
sb.append( " MESSAGE ACKNOWLEDGED - MORE TO FOLLOW" );
|
|
|
|
if( hasFromID() )
|
|
{
|
|
sb.append( " FROM:" );
|
|
sb.append( getFromID() );
|
|
}
|
|
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " TO:" );
|
|
sb.append( getToID() );
|
|
}
|
|
break;
|
|
case ACKT:
|
|
sb.append( " SITE:" );
|
|
sb.append( format( getSiteID(), 5 ) );
|
|
|
|
sb.append( " LONG ACK MESSAGE" );
|
|
|
|
if( hasFromID() )
|
|
{
|
|
sb.append( " FROM:" );
|
|
sb.append( getFromID() );
|
|
}
|
|
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " TO:" );
|
|
sb.append( getToID() );
|
|
}
|
|
|
|
sb.append( "**********************************" );
|
|
break;
|
|
case ACKQ:
|
|
sb.append( " SYSTEM:" );
|
|
sb.append( format( getSiteID(), 5 ) );
|
|
|
|
sb.append( " CALL QUEUED FROM:" );
|
|
|
|
if( hasFromID() )
|
|
{
|
|
sb.append( " FROM:" );
|
|
sb.append( getFromID() );
|
|
}
|
|
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " TO:" );
|
|
sb.append( getToID() );
|
|
}
|
|
break;
|
|
case ACKX:
|
|
sb.append( " SYSTEM:" );
|
|
sb.append( format( getSiteID(), 5 ) );
|
|
|
|
sb.append( " MESSAGE REJECTED FROM:" );
|
|
|
|
if( hasFromID() )
|
|
{
|
|
sb.append( " FROM:" );
|
|
sb.append( getFromID() );
|
|
}
|
|
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " TO:" );
|
|
sb.append( getToID() );
|
|
}
|
|
break;
|
|
case AHYC:
|
|
sb.append( " FM:" );
|
|
sb.append( getFromID() );
|
|
sb.append( " TO:" );
|
|
sb.append( getToID() );
|
|
sb.append( " " );
|
|
sb.append( getRequestString() );
|
|
break;
|
|
case AHYQ:
|
|
/* Status Message */
|
|
sb.append( " STATUS MESSAGE" );
|
|
|
|
if( hasFromID() )
|
|
{
|
|
sb.append( " FROM:" );
|
|
sb.append( getFromID() );
|
|
}
|
|
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " TO:" );
|
|
sb.append( getToID() );
|
|
}
|
|
sb.append( " " );
|
|
sb.append( getStatusMessage() );
|
|
break;
|
|
case ALH:
|
|
case ALHD:
|
|
case ALHS:
|
|
case ALHE:
|
|
case ALHR:
|
|
case ALHX:
|
|
case ALHF:
|
|
sb.append( " SYSTEM:" );
|
|
sb.append( format( getSiteID(), 5 ) );
|
|
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " ID:" );
|
|
sb.append( getToID() );
|
|
}
|
|
break;
|
|
case BCAST:
|
|
SystemDefinition sysdef = getSystemDefinition();
|
|
|
|
sb.append( " " );
|
|
sb.append( sysdef.getLabel() );
|
|
|
|
switch( sysdef )
|
|
{
|
|
case ANNOUNCE_CONTROL_CHANNEL:
|
|
case WITHDRAW_CONTROL_CHANNEL:
|
|
sb.append( " CHAN:" );
|
|
sb.append( getChannel() );
|
|
break;
|
|
case BROADCAST_ADJACENT_SITE_CONTROL_CHANNEL_NUMBER:
|
|
sb.append( " CHAN:" );
|
|
sb.append( getChannel() );
|
|
sb.append( " SER:" );
|
|
sb.append( getAdjacentSiteSerialNumber() );
|
|
//debug
|
|
sb.append( " *************************" );
|
|
break;
|
|
}
|
|
break;
|
|
case CLEAR:
|
|
sb.append( " TRAFFIC CHANNEL:" );
|
|
sb.append( getChannel() );
|
|
sb.append( " RETURN TO CONTROL CHANNEL:" );
|
|
sb.append( getReturnToChannel() );
|
|
break;
|
|
case GTC:
|
|
if( hasFromID() )
|
|
{
|
|
sb.append( " FROM:" );
|
|
sb.append( getFromID() );
|
|
}
|
|
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " TO:" );
|
|
sb.append( getToID() );
|
|
}
|
|
|
|
sb.append( " CHAN:" );
|
|
sb.append( getChannel() );
|
|
break;
|
|
case MAINT:
|
|
if( hasToID() )
|
|
{
|
|
sb.append( " ID:" );
|
|
sb.append( getToID() );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
@Override
|
|
public String getBinaryMessage()
|
|
{
|
|
return mMessage.toString();
|
|
}
|
|
|
|
@Override
|
|
public String getProtocol()
|
|
{
|
|
return "MPT-1327";
|
|
}
|
|
|
|
@Override
|
|
public String getEventType()
|
|
{
|
|
// TODO Auto-generated method stub
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Translates the AHYC request from the values in ident1 and ident2
|
|
*/
|
|
public String getRequestString()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
IdentType type2 = getIdent2Type();
|
|
|
|
if( type2 == IdentType.USER )
|
|
{
|
|
IdentType type1 = getIdent1Type();
|
|
|
|
Slots slots = getSlots();
|
|
|
|
switch( type1 )
|
|
{
|
|
case DIVERTI:
|
|
sb.append( "SEND BLOCKED ADDRESS FOR THIRD-PARTY CALL DIVERSION USING " );
|
|
sb.append( slots.getLabel() );
|
|
break;
|
|
case IPFIXI:
|
|
sb.append( "SEND INTER-PREFIX CALL EXTENDED ADDRESSING INFORMATION USING " );
|
|
sb.append( slots.getLabel() );
|
|
break;
|
|
case PABXI:
|
|
sb.append( "SEND PABX EXTENSION USING" );
|
|
sb.append( slots.getLabel() );
|
|
break;
|
|
case PSTNGI:
|
|
if( slots == Slots.SLOTS_1 )
|
|
{
|
|
sb.append( "SEND UP TO 9 PSTN DIALED DIGITS" );
|
|
}
|
|
else if( slots == Slots.SLOTS_2 )
|
|
{
|
|
sb.append( "SEND 10 TO 31 PSTN DIALED DIGITS" );
|
|
}
|
|
else
|
|
{
|
|
sb.append( "SEND PSTN DIALED DIGITS USING " );
|
|
sb.append( slots.getLabel() );
|
|
}
|
|
break;
|
|
case SDMI:
|
|
sb.append( "SEND SHORT DATA MESSAGE USING " );
|
|
sb.append( slots.getLabel() );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* MODE 2 */
|
|
sb.append( "SEND " );
|
|
sb.append( getDescriptor().getMode2Label() );
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
@Override
|
|
public String getFromID()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
int ident2 = getIdent2();
|
|
|
|
IdentType type = IdentType.fromIdent( ident2 );
|
|
|
|
/* Inter-Prefix - the from and to idents are different prefixes */
|
|
if( type == IdentType.IPFIXI )
|
|
{
|
|
sb.append( format( getBlock2Prefix(), 3 ) );
|
|
sb.append( "-" );
|
|
sb.append( format( getBlock2Ident2(), 4) );
|
|
}
|
|
else
|
|
{
|
|
sb.append( format( getPrefix(), 3 ) );
|
|
sb.append( "-" );
|
|
sb.append( format( ident2, 4) );
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
public boolean hasFromID()
|
|
{
|
|
return getFromID() != null;
|
|
}
|
|
|
|
@Override
|
|
public Alias getFromIDAlias()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public String getToID()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
int prefix = getPrefix();
|
|
int ident = getIdent1();
|
|
|
|
switch( IdentType.fromIdent( ident ) )
|
|
{
|
|
case USER:
|
|
sb.append( format( prefix, 3 ) );
|
|
sb.append( "-" );
|
|
sb.append( format( ident, 4) );
|
|
break;
|
|
case IPFIXI:
|
|
sb.append( "INTER-PREFIX" );
|
|
break;
|
|
case ALLI:
|
|
sb.append( "ALL RADIOS" );
|
|
break;
|
|
case PABXI:
|
|
sb.append( "PABX EXT" );
|
|
break;
|
|
case PSTNSI1:
|
|
case PSTNSI2:
|
|
case PSTNSI3:
|
|
case PSTNSI4:
|
|
case PSTNSI5:
|
|
case PSTNSI6:
|
|
case PSTNSI7:
|
|
case PSTNSI8:
|
|
case PSTNSI9:
|
|
case PSTNSI10:
|
|
case PSTNSI11:
|
|
case PSTNSI12:
|
|
case PSTNSI13:
|
|
case PSTNSI14:
|
|
case PSTNSI15:
|
|
sb.append( "PRE-DEFINED PSTN" );
|
|
break;
|
|
case PSTNGI:
|
|
sb.append( "PSTN GATEWAY" );
|
|
break;
|
|
case TSCI:
|
|
sb.append( "SYSTEM CONTROLLER" );
|
|
break;
|
|
case DIVERTI:
|
|
sb.append( "CALL DIVERT" );
|
|
break;
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
public boolean hasToID()
|
|
{
|
|
return getToID() != null;
|
|
}
|
|
|
|
public Descriptor getDescriptor()
|
|
{
|
|
return Descriptor.fromNumber( mMessage.getInt( B1_DESCRIPTOR ) );
|
|
}
|
|
|
|
public Slots getSlots()
|
|
{
|
|
return Slots.fromNumber( mMessage.getInt( B1_SLOTS ) );
|
|
}
|
|
|
|
@Override
|
|
public Alias getToIDAlias()
|
|
{
|
|
if( hasToID() )
|
|
{
|
|
return mAliasList.getMPT1327Alias( getToID() );
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String getErrorStatus()
|
|
{
|
|
return getParity();
|
|
}
|
|
|
|
@Override
|
|
public Plottable getPlottable()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public enum IdentType
|
|
{
|
|
ALLI( "SYSTEM-WIDE" ),
|
|
DIVERTI( "DIVERT" ),
|
|
DNI( "DATA NETWORK GATEWAY" ),
|
|
DUMMYI( "DUMMY IDENT" ),
|
|
INCI( "INCLUDE IN CALL" ),
|
|
IPFIXI( "INTER-PREFIX" ),
|
|
PABXI( "PABX GATEWAY" ),
|
|
PSTNGI( "PSTN GATEWAY" ),
|
|
PSTNSI1( "PSTN OR NETWORK 1" ),
|
|
PSTNSI2( "PSTN OR NETWORK 2" ),
|
|
PSTNSI3( "PSTN OR NETWORK 3" ),
|
|
PSTNSI4( "PSTN OR NETWORK 4" ),
|
|
PSTNSI5( "PSTN OR NETWORK 5" ),
|
|
PSTNSI6( "PSTN OR NETWORK 6" ),
|
|
PSTNSI7( "PSTN OR NETWORK 7" ),
|
|
PSTNSI8( "PSTN OR NETWORK 8" ),
|
|
PSTNSI9( "PSTN OR NETWORK 9" ),
|
|
PSTNSI10( "PSTN OR NETWORK 10" ),
|
|
PSTNSI11( "PSTN OR NETWORK 11" ),
|
|
PSTNSI12( "PSTN OR NETWORK 12" ),
|
|
PSTNSI13( "PSTN OR NETWORK 13" ),
|
|
PSTNSI14( "PSTN OR NETWORK 14" ),
|
|
PSTNSI15( "PSTN OR NETWORK 15" ),
|
|
REGI( "REGISTRATION" ),
|
|
RESERVED( "RESERVED" ),
|
|
SDMI( "SHORT DATA MESSAGE" ),
|
|
SPARE( "SPARE" ),
|
|
TSCI( "SYSTEM CONTROLLER" ),
|
|
USER( "COMMON-PREFIX IDENT" ),
|
|
UNKNOWN( "UNKNOWN" );
|
|
|
|
private String mLabel;
|
|
|
|
private IdentType( String label )
|
|
{
|
|
mLabel = label;
|
|
}
|
|
|
|
public String getLabel()
|
|
{
|
|
return mLabel;
|
|
}
|
|
|
|
public static IdentType fromIdent( int ident )
|
|
{
|
|
switch( ident )
|
|
{
|
|
case 0:
|
|
return DUMMYI;
|
|
case 8101:
|
|
return PSTNGI;
|
|
case 8102:
|
|
return PABXI;
|
|
case 8103:
|
|
return DNI;
|
|
case 8121:
|
|
return PSTNSI1;
|
|
case 8122:
|
|
return PSTNSI2;
|
|
case 8123:
|
|
return PSTNSI3;
|
|
case 8124:
|
|
return PSTNSI4;
|
|
case 8125:
|
|
return PSTNSI5;
|
|
case 8126:
|
|
return PSTNSI6;
|
|
case 8127:
|
|
return PSTNSI7;
|
|
case 8128:
|
|
return PSTNSI8;
|
|
case 8129:
|
|
return PSTNSI9;
|
|
case 8130:
|
|
return PSTNSI10;
|
|
case 8131:
|
|
return PSTNSI11;
|
|
case 8132:
|
|
return PSTNSI12;
|
|
case 8133:
|
|
return PSTNSI13;
|
|
case 8134:
|
|
return PSTNSI14;
|
|
case 8135:
|
|
return PSTNSI15;
|
|
case 8181:
|
|
case 8182:
|
|
case 8183:
|
|
case 8184:
|
|
return RESERVED;
|
|
case 8185:
|
|
return REGI;
|
|
case 8186:
|
|
return INCI;
|
|
case 8187:
|
|
return DIVERTI;
|
|
case 8188:
|
|
return SDMI;
|
|
case 8189:
|
|
return IPFIXI;
|
|
case 8190:
|
|
return TSCI;
|
|
case 8191:
|
|
return ALLI;
|
|
default:
|
|
if( 1 <= ident && ident <= 8100 )
|
|
{
|
|
return USER;
|
|
}
|
|
else if( ( 8104 <= ident && ident <= 8120 ) ||
|
|
( 8136 <= ident && ident <= 8180 ) )
|
|
{
|
|
return SPARE;
|
|
}
|
|
else
|
|
{
|
|
return UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum Descriptor
|
|
{
|
|
DESC_0( "EXTENDED ADDRESSING INFORMATION", "SERIAL NUMBER" ),
|
|
DESC_1( "PSTN DIALED DIGITS", "RESERVED" ),
|
|
DESC_2( "PABX EXTENSION", "RESERVED" ),
|
|
RESERVED( "RESERVED", "RESERVED" ),
|
|
UNKNOWN( "UNKNOWN", "UNKNOWN" );
|
|
|
|
private String mMode1Label;
|
|
private String mMode2Label;
|
|
|
|
private Descriptor( String mode1Label, String mode2Label )
|
|
{
|
|
mMode1Label = mode1Label;
|
|
mMode2Label = mode2Label;
|
|
}
|
|
|
|
public String getMode1Label()
|
|
{
|
|
return mMode1Label;
|
|
}
|
|
|
|
public String getMode2Label()
|
|
{
|
|
return mMode2Label;
|
|
}
|
|
|
|
public static Descriptor fromNumber( int number )
|
|
{
|
|
switch( number )
|
|
{
|
|
case 0:
|
|
return DESC_0;
|
|
case 1:
|
|
return DESC_1;
|
|
case 2:
|
|
return DESC_2;
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
return RESERVED;
|
|
default:
|
|
return UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum Slots
|
|
{
|
|
SLOTS_0( "RESERVED" ),
|
|
SLOTS_1( "ADDRESS CODEWORD ONLY" ),
|
|
SLOTS_2( "ADDRESS CODEWORD & 1-2 DATA CODEWORDS" ),
|
|
SLOTS_3( "ADDRESS CODEWORD & 3-4 DATA CODEWORDS" ),
|
|
UNKNOWN( "UNKNOWN" );
|
|
|
|
private String mLabel;
|
|
|
|
private Slots( String label )
|
|
{
|
|
mLabel = label;
|
|
}
|
|
|
|
public String getLabel()
|
|
{
|
|
return mLabel;
|
|
}
|
|
|
|
public static Slots fromNumber( int number )
|
|
{
|
|
switch( number )
|
|
{
|
|
case 0:
|
|
return SLOTS_0;
|
|
case 1:
|
|
return SLOTS_1;
|
|
case 2:
|
|
return SLOTS_2;
|
|
case 3:
|
|
return SLOTS_3;
|
|
default:
|
|
return UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public enum SystemDefinition
|
|
{
|
|
UNKNOWN( "UNKNOWN" ),
|
|
ANNOUNCE_CONTROL_CHANNEL( "ANNOUNCE CONTROL CHANNEL" ),
|
|
WITHDRAW_CONTROL_CHANNEL( "WITHDRAW CONTROL CHANNEL" ),
|
|
SPECIFY_CALL_MAINTENANCE_PARAMETERS( "CALL MAINT PARAMETERS" ),
|
|
SPECIFY_REGISTRATION_PARAMETERS( "REGISTRATION PARAMETERS" ),
|
|
BROADCAST_ADJACENT_SITE_CONTROL_CHANNEL_NUMBER( "NEIGHBOR" ),
|
|
VOTE_NOW_ADVICE( "VOTE NOW" );
|
|
|
|
private String mLabel;
|
|
|
|
private SystemDefinition( String label )
|
|
{
|
|
mLabel = label;
|
|
}
|
|
|
|
public String getLabel()
|
|
{
|
|
return mLabel;
|
|
}
|
|
|
|
public static SystemDefinition fromNumber( int number )
|
|
{
|
|
switch( number )
|
|
{
|
|
case 0:
|
|
return ANNOUNCE_CONTROL_CHANNEL;
|
|
case 1:
|
|
return WITHDRAW_CONTROL_CHANNEL;
|
|
case 2:
|
|
return SPECIFY_CALL_MAINTENANCE_PARAMETERS;
|
|
case 3:
|
|
return SPECIFY_REGISTRATION_PARAMETERS;
|
|
case 4:
|
|
return BROADCAST_ADJACENT_SITE_CONTROL_CHANNEL_NUMBER;
|
|
case 5:
|
|
return VOTE_NOW_ADVICE;
|
|
default:
|
|
return UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum MPTMessageType
|
|
{
|
|
UNKN( -1, "Unknown" ),
|
|
GTC( 0, "GTC - Goto Channel" ),
|
|
ALH( 256, "ALH - Aloha" ),
|
|
ALHS( 257, "ALHS - Standard Data Excluded" ),
|
|
ALHD( 258, "ALHD - Simple Calls Excluded" ),
|
|
ALHE( 259, "ALHE - Emergency Calls Only" ),
|
|
ALHR( 260, "ALHR - Emergency or Registration" ),
|
|
ALHX( 261, "ALHX - Registration Excluded" ),
|
|
ALHF( 262, "ALHF - Fallback Mode" ),
|
|
|
|
ACK( 264, "ACK - Acknowledge" ),
|
|
ACKI( 265, "ACKI - More To Follow" ),
|
|
ACKQ( 266, "ACKQ - Call Queued" ),
|
|
ACKX( 267, "ACKX - Message Rejected" ),
|
|
ACKV( 268, "ACKV - Called Unit Unavailable" ),
|
|
ACKE( 269, "ACKE - Emergency" ),
|
|
ACKT( 270, "ACKT - Try On Given Address" ),
|
|
ACKB( 271, "ACKB - Call Back/Negative Ack" ),
|
|
|
|
AHOY( 272, "AHOY - General Availability Check" ),
|
|
AHYX( 274, "AHYX - Cancel Alert/Waiting Status" ),
|
|
AHYP( 277, "AHYP - Called Unit Presence Monitoring" ),
|
|
AHYQ( 278, "AHYQ - Status Message" ),
|
|
AHYC( 279, "AHYC - Short Data Message" ),
|
|
|
|
MARK( 280, "MARK - Control Channel Marker" ),
|
|
MAINT(281, "MAINT - Call Maintenance Message"),
|
|
CLEAR(282, "CLEAR - Down From Allocated Channel" ),
|
|
MOVE( 283, "MOVE - To Specified Channel" ),
|
|
BCAST(284, "BCAST - System Parameters" );
|
|
|
|
/* There are more to fill in here */
|
|
|
|
private int mNumber;
|
|
private String mDescription;
|
|
|
|
private MPTMessageType( int number, String description )
|
|
{
|
|
mNumber = number;
|
|
mDescription = description;
|
|
}
|
|
|
|
public int getMessageNumber()
|
|
{
|
|
return mNumber;
|
|
}
|
|
|
|
public String getDescription()
|
|
{
|
|
return mDescription;
|
|
}
|
|
|
|
public static MPTMessageType fromNumber( int number )
|
|
{
|
|
if( number < 256 )
|
|
{
|
|
return GTC;
|
|
}
|
|
|
|
switch( number )
|
|
{
|
|
case 256:
|
|
return ALH;
|
|
case 257:
|
|
return ALHS;
|
|
case 258:
|
|
return ALHD;
|
|
case 259:
|
|
return ALHE;
|
|
case 260:
|
|
return ALHR;
|
|
case 261:
|
|
return ALHX;
|
|
case 262:
|
|
return ALHF;
|
|
case 264:
|
|
return ACK;
|
|
case 265:
|
|
return ACKI;
|
|
case 266:
|
|
return ACKQ;
|
|
case 267:
|
|
return ACKX;
|
|
case 268:
|
|
return ACKV;
|
|
case 269:
|
|
return ACKE;
|
|
case 270:
|
|
return ACKT;
|
|
case 271:
|
|
return ACKB;
|
|
case 272:
|
|
return AHOY;
|
|
case 274:
|
|
return AHYX;
|
|
case 277:
|
|
return AHYP;
|
|
case 278:
|
|
return AHYQ;
|
|
case 279:
|
|
return AHYC;
|
|
case 280:
|
|
return MARK;
|
|
case 281:
|
|
return MAINT;
|
|
case 282:
|
|
return CLEAR;
|
|
case 283:
|
|
return MOVE;
|
|
case 284:
|
|
return BCAST;
|
|
default:
|
|
return UNKN;
|
|
}
|
|
}
|
|
}
|
|
}
|