/******************************************************************************* * 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 module.decode.mdc1200; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import map.Plottable; import message.Message; import alias.Alias; import alias.AliasList; import bits.BinaryMessage; public class MDCMessage extends Message { private static SimpleDateFormat mSDF = new SimpleDateFormat( "yyyyMMdd HHmmss" ); private static int[] sSYNC1 = { 0,1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18,19, 20,21,22,23,24,25,26,27,28,29, 30,31,32,33,34,35,36,37,38,39 }; private static int[] sOPCODE = { 47,46,45,44,43,42,41,40 }; private static int sANI_FLAG = 40; private static int sDIRECTION_FLAG = 45; private static int sACKNOWLEDGE_REQUIRED_FLAG = 46; private static int sPACKET_TYPE_FLAG = 47; private static int sEMERGENCY_FLAG = 48; private static int[] sARGUMENT = { 49,50,51,52,53,54 }; private static int sBOT_EOT_FLAG = 55; private static int[] sDIGIT_2 = { 59,58,57,56 }; private static int[] sDIGIT_1 = { 63,62,61,60 }; private static int[] sDIGIT_4 = { 67,66,65,64 }; private static int[] sDIGIT_3 = { 71,70,69,68 }; private BinaryMessage mMessage; private AliasList mAliasList; public MDCMessage( BinaryMessage message, AliasList list ) { mMessage = message; mAliasList = list; } public boolean isValid() { //TODO: add CRC and/or convolution decoding/repair return true; } public PacketType getPacketType() { if( mMessage.get( sPACKET_TYPE_FLAG ) ) { return PacketType.DATA; } else { return PacketType.CMND; } } public Acknowledge getResponse() { if( mMessage.get( sACKNOWLEDGE_REQUIRED_FLAG ) ) { return Acknowledge.YES; } else { return Acknowledge.NO; } } public Direction getDirection() { if( mMessage.get( sDIRECTION_FLAG ) ) { return Direction.OUT; } else { return Direction.IN; } } public int getOpcode() { return mMessage.getInt( sOPCODE ); } public int getArgument() { return mMessage.getInt( sARGUMENT ); } public boolean isEmergency() { return mMessage.get( sEMERGENCY_FLAG ); } public boolean isANI() { return mMessage.get( sANI_FLAG ); } public boolean isBOT() { return mMessage.get( sBOT_EOT_FLAG ); } public boolean isEOT() { return !mMessage.get( sBOT_EOT_FLAG ); } public String getUnitID() { StringBuilder sb = new StringBuilder(); sb.append( Integer.toHexString( mMessage.getInt( sDIGIT_1 ) ).toUpperCase() ); sb.append( Integer.toHexString( mMessage.getInt( sDIGIT_2 ) ).toUpperCase() ); sb.append( Integer.toHexString( mMessage.getInt( sDIGIT_3 ) ).toUpperCase() ); sb.append( Integer.toHexString( mMessage.getInt( sDIGIT_4 ) ).toUpperCase() ); return sb.toString(); } public MDCMessageType getMessageType() { switch( getOpcode() ) { case 0: if( isEmergency() ) { return MDCMessageType.EMERGENCY; } case 1: return MDCMessageType.ANI; default: return MDCMessageType.UNKNOWN; } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append( mSDF.format( new Date( System.currentTimeMillis() ) ) ); sb.append( getMessage() ); sb.append( " [" + mMessage.toString() + "]" ); return sb.toString(); } /** * 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(); } @SuppressWarnings( "unused" ) private int getInt( int[] bits ) { int retVal = 0; for( int x = 0; x < bits.length; x++ ) { if( mMessage.get( bits[ x ] ) ) { retVal += 1<<x; } } return retVal; } @Override public String getBinaryMessage() { return mMessage.toString(); } @Override public String getProtocol() { return "MDC-1200"; } @Override public String getEventType() { // TODO Auto-generated method stub return null; } @Override public String getFromID() { return getUnitID(); } @Override public Alias getFromIDAlias() { return mAliasList.getMDC1200Alias( getFromID() ); } @Override public String getToID() { // TODO Auto-generated method stub return null; } @Override public Alias getToIDAlias() { // TODO Auto-generated method stub return null; } @Override public String getMessage() { StringBuilder sb = new StringBuilder(); sb.append( "MDC1200 UNIT:" + getUnitID() ); if( isEmergency() ) { sb.append( " **EMERGENCY**" ); } if( isBOT() ) { sb.append( " BOT" ); } if( isEOT() ) { sb.append( " EOT" ); } sb.append( " OPCODE:" + format( getOpcode(), 2 ) ); sb.append( " ARG:" + format( getArgument(), 3 ) ); sb.append( " TYPE:" + getPacketType().toString() ); sb.append( " ACK:" + getResponse().toString() ); sb.append( " DIR:" + pad( getDirection().toString(), 3, " " ) ); return sb.toString(); } @Override public String getErrorStatus() { // TODO Auto-generated method stub return null; } @Override public Plottable getPlottable() { // TODO Auto-generated method stub return null; } /** * Provides a listing of aliases contained in the message. */ public List<Alias> getAliases() { List<Alias> aliases = new ArrayList<Alias>(); Alias from = getFromIDAlias(); if( from != null ) { aliases.add( from ); } Alias to = getToIDAlias(); if( to != null ) { aliases.add( to ); } return aliases; } private enum PacketType { CMND, DATA }; private enum Acknowledge { YES, NO }; private enum Direction { IN, OUT }; }