Files
sdrtrunk/src/decode/mpt1327/MPT1327Message.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;
}
}
}
}