001package jmri.jmrix; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006/** 007 * Abstract base class for replies in a message/reply protocol. 008 * <p> 009 * Handles the character manipulation. 010 * <p> 011 * This is a variable length reply, which can grow as needed. The length is 012 * given by the largest index written so far. 013 * 014 * @author Bob Jacobsen Copyright (C) 2003 015 */ 016abstract public class AbstractMRReply extends AbstractMessage { 017 // is this logically an abstract class? 018 019 /** 020 * Create a new AbstractMRReply instance. 021 */ 022 public AbstractMRReply() { 023 setBinary(false); 024 unsolicited = false; 025 _dataChars = new int[maxSize()]; 026 } 027 028 /** 029 * Copy a Reply to a new AbstractMRReply instance. 030 * 031 * @param m the reply to copy 032 */ 033 public AbstractMRReply(AbstractMRReply m) { 034 this(); 035 if (m == null) { 036 log.error("copy ctor of null message"); 037 } else { 038 _nDataChars = m._nDataChars; 039 if (_nDataChars >= 0) 040 System.arraycopy(m._dataChars, 0, _dataChars, 0, _nDataChars); 041 } 042 } 043 044 /** 045 * Create a new AbstractMRReply instance from a string. 046 * 047 * @param s String to use as reply content 048 */ 049 public AbstractMRReply(String s) { 050 this(); 051 _nDataChars = s.length(); 052 for (int i = 0; i < _nDataChars; i++) { 053 _dataChars[i] = s.charAt(i); 054 } 055 } 056 057 // keep track of length 058 @Override 059 public void setElement(int n, int v) { 060 _dataChars[n] = (char) v; 061 _nDataChars = Math.max(_nDataChars, n + 1); 062 } 063 064 /** 065 * Set the OpCode. 066 * Sets Element 0 to character value of integer. 067 * @param i Opcode value. 068 */ 069 public void setOpCode(int i) { 070 _dataChars[0] = (char) i; 071 } 072 073 /** 074 * Get the OpCode. 075 * @return value of Element 0. 076 */ 077 public int getOpCode() { 078 return _dataChars[0]; 079 } 080 081 /** 082 * Flush the message. 083 * Sets number of data characters to 0. 084 * Does not reset array length or data. 085 */ 086 public void flush() { 087 _nDataChars = 0; 088 } 089 090 // mode accessors 091 private boolean _isBinary; 092 093 /** 094 * Get if the Reply has Binary form flag set. 095 * @return true if binary, else false. 096 */ 097 public boolean isBinary() { 098 return _isBinary; 099 } 100 101 /** 102 * Set flag for if the Reply is Binary form. 103 * @param b true if binary, else false. 104 */ 105 public void setBinary(boolean b) { 106 _isBinary = b; 107 } 108 109 /** 110 * Set flag for Unsolicited to true. 111 */ 112 public final void setUnsolicited() { 113 unsolicited = true; 114 } 115 116 /** 117 * Get flag for Unsolicited. 118 * @return true if Unsolicited, else false. 119 */ 120 public boolean isUnsolicited() { 121 return unsolicited; 122 } 123 124 /* 125 * Override in system specific classes if required. 126 * 127 * @return 'true' if the message is an error and we can automatically 128 * recover by retransmitting the message. 129 */ 130 public boolean isRetransmittableErrorMsg() { 131 return false; 132 } 133 134 // display format 135 @Override 136 public String toString() { 137 String s = ""; 138 for (int i = 0; i < _nDataChars; i++) { 139 if (_isBinary) { 140 if (i != 0) { 141 s += " "; 142 } 143 s = jmri.util.StringUtil.appendTwoHexFromInt(_dataChars[i] & 0xFF, s); 144 } else { 145 s += (char) _dataChars[i]; 146 } 147 } 148 return s; 149 } 150 151 abstract protected int skipPrefix(int index); 152 153 public int value() { // integer value of 1st three digits 154 int index = 0; 155 index = skipWhiteSpace(index); 156 index = skipPrefix(index); 157 index = skipWhiteSpace(index); 158 String s = "" + (char) getElement(index) + (char) getElement(index + 1) + (char) getElement(index + 2); 159 int val = -1; 160 try { 161 val = Integer.parseInt(s); 162 } catch (RuntimeException e) { 163 log.error("Unable to get number from reply: \"{}\" index: {} message: \"{}\"", s, index, toString()); 164 } 165 return val; 166 } 167 168 public int pollValue() { // integer value of HHHH 169 int index = 0; 170 index = skipWhiteSpace(index); 171 index = skipPrefix(index); 172 index = skipWhiteSpace(index); 173 String s = "" + (char) getElement(index) + (char) getElement(index + 1) 174 + (char) getElement(index + 2) + (char) getElement(index + 3); 175 int val = -1; 176 try { 177 val = Integer.parseInt(s, 16); 178 } catch (RuntimeException e) { 179 log.error("Unable to get number from reply: \"{}\" index: {} message: \"{}\"", s, index, toString()); 180 } 181 return val; 182 } 183 184 public int match(String s) { 185 // loop over starting positions 186 outer: 187 for (int i = 0; i < _nDataChars - s.length() + 1; i++) { 188 // loop to check each start position 189 for (int j = 0; j < s.length(); j++) { 190 if (_dataChars[i + j] != s.charAt(j)) { 191 continue outer; 192 } 193 } 194 // here we succeed 195 return i; 196 } 197 198 return -1; 199 } 200 201 public int skipWhiteSpace(int index) { 202 // start at index, passing any whitespace & control characters at the start of the buffer 203 while (index < getNumDataElements() - 1 204 && ((char) getElement(index) <= ' ')) { 205 index++; 206 } 207 return index; 208 } 209 210 public int maxSize() { 211 return DEFAULTMAXSIZE; 212 } 213 static public final int DEFAULTMAXSIZE = 120; 214 215 // contents 216 private boolean unsolicited; 217 218 private final static Logger log = LoggerFactory.getLogger(AbstractMRReply.class); 219 220}