001package jmri.jmrix; 002 003import java.io.Serializable; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007/** 008 * Represents a single general command or response. 009 * <p> 010 * Content is represented with ints to avoid the problems with sign-extension 011 * that bytes have, and because a Java char is actually a variable number of 012 * bytes in Unicode. 013 * <p> 014 * Both a set of indexed contents, an opcode, and a length field are available. 015 * Different implementations will map the opcode and length into the contents in 016 * different ways. They may not appear at all... 017 * 018 * @author Bob Jacobsen Copyright (C) 2002 019 */ 020public abstract class NetMessage implements Serializable { 021 022 /** 023 * Create a new object, representing a specific-length message. 024 * 025 * @param len Total bytes in message, including opcode and error-detection 026 * byte. 027 */ 028 public NetMessage(int len) { 029 if (len < 0) { 030 log.error("invalid length in call to ctor: {}", len); 031 } 032 mNDataBytes = len; 033 mDataBytes = new int[len]; 034 } 035 036 public void setOpCode(int i) { 037 mOpCode = i; 038 } 039 040 public int getOpCode() { 041 return mOpCode; 042 } 043 044 /** 045 * Get a String representation of the op code in hex. 046 * @return string of Opcode, 0x format. 047 */ 048 public String getOpCodeHex() { 049 return "0x" + Integer.toHexString(getOpCode()); 050 } 051 052 /** 053 * Get length, including op code and error-detection byte 054 * @return total number of data elements. 055 */ 056 public int getNumDataElements() { 057 return mNDataBytes; 058 } 059 060 public int getElement(int n) { 061 if (n < 0 || n >= mDataBytes.length) { 062 log.error("illegal get element {} in message of {} elements: {}", n, mDataBytes.length, this.toString()); 063 } 064 return mDataBytes[n]; 065 } 066 067 public void setElement(int n, int v) { 068 if (n < 0 || n >= mDataBytes.length) { 069 log.error("illegal set element {} in message of {} elements: {}", n, mDataBytes.length, this.toString()); 070 } 071 mDataBytes[n] = v; 072 } 073 074 /** 075 * Get a String representation of the entire message in hex. This is not 076 * intended to be human-readable! 077 */ 078 @Override 079 public String toString() { 080 StringBuilder s = new StringBuilder(); 081 for (int i = 0; i < mNDataBytes; i++) { 082 s.append(Integer.toHexString(mDataBytes[i])).append(" "); 083 } 084 return s.toString(); 085 } 086 087 /** 088 * check whether the message has a valid parity 089 * @return true if parity valid, else false. 090 */ 091 public abstract boolean checkParity(); 092 093 /** 094 * Set parity to be correct for this implementation. Note that parity is 095 * really a stand-in for whatever error checking, etc needs to be done 096 */ 097 public abstract void setParity(); 098 099 // manipulate various things in a convenient way 100 static protected int lowByte(int val) { 101 return val & 0xFF; 102 } 103 104 static protected int highByte(int val) { 105 if ((val & (~0xFFFF)) != 0) { 106 log.error("highByte called with too large value: {}", Integer.toHexString(val)); 107 } 108 return (val & 0xFF00) / 256; 109 } 110 111 /** 112 * Number of contained data bytes. This is not necessarily the same as the 113 * length of the data array, depending on implementation details, so is kept 114 * separate 115 */ 116 private int mNDataBytes = 0; 117 private int mDataBytes[] = null; 118 private int mOpCode = 0; 119 120 // initialize logging 121 private final static Logger log = LoggerFactory.getLogger(NetMessage.class); 122 123}