001package jmri.jmrix.qsi; 002 003/** 004 * Carries the reply to an QsiMessage. 005 * 006 * @author Bob Jacobsen Copyright (C) 2007 007 */ 008public class QsiReply extends jmri.jmrix.AbstractMessage { 009 010 static final int MAXREPLYLENGTH = 200; 011 012 // create a new one 013 public QsiReply() { 014 super(MAXREPLYLENGTH); 015 _isBoot = false; 016 _nDataChars = 0; 017 } 018 019 // copy one 020 public QsiReply(QsiReply m) { 021 super(m); 022 _isBoot = m._isBoot; 023 } 024 025 // from String 026 public QsiReply(String s) { 027 super(s); 028 } 029 030 public QsiReply(String s, boolean b) { 031 super(s); 032 _isBoot = b; 033 } 034 035 public void setOpCode(int i) { 036 _dataChars[0] = (char) i; 037 } 038 039 public int getOpCode() { 040 return _dataChars[0]; 041 } 042 043 // accessors to the bulk data 044 @Override 045 public void setElement(int n, int v) { 046 _dataChars[n] = v; 047 _nDataChars = Math.max(_nDataChars, n + 1); 048 } 049 050 static public QsiMessage getAck(QsiReply r) { 051 // send ack to received (unsolicited) message m 052 QsiMessage m = new QsiMessage(1); 053 m.setElement(0, r.getElement(1)); 054 return m; 055 } 056 057 // Check and strip framing characters and DLE from a QSI bootloader reply 058 public boolean strip() { 059 int tmp[] = new int[_nDataChars]; 060 int j = 0; 061 _isBoot = true; // definitely a boot message 062 // Check framing characters 063 if (_dataChars[0] != QsiMessage.STX) { 064 return false; 065 } 066 if (_dataChars[1] != QsiMessage.STX) { 067 return false; 068 } 069 if (_dataChars[_nDataChars - 1] != QsiMessage.ETX) { 070 return false; 071 } 072 073 // Ignore framing characters and strip DLEs 074 for (int i = 2; i < _nDataChars - 1; i++) { 075 if (_dataChars[i] == QsiMessage.DLE) { 076 i++; 077 } 078 tmp[j++] = _dataChars[i]; 079 } 080 081 // Copy back to original QsiReply 082 System.arraycopy(tmp, 0, _dataChars, 0, j); 083 _nDataChars = j; 084 return true; 085 } 086 087 // Check and strip checksum from a QSI bootloader reply 088 // Assumes framing and DLE chars have been stripped 089 public boolean getChecksum() { 090 int checksum = 0; 091 for (int i = 0; i < _nDataChars; i++) { 092 checksum += _dataChars[i] & 0xff; 093 } 094 _nDataChars--; 095 return ((checksum & 0xff) == 0); 096 } 097 098 // display format 099 @Override 100 public String toString() { 101 QsiSystemConnectionMemo memo = jmri.InstanceManager.getDefault(jmri.jmrix.qsi.QsiSystemConnectionMemo.class); 102 return toString(memo.getQsiTrafficController()); 103 } 104 105 public String toString(QsiTrafficController controller) { 106 StringBuilder s = new StringBuilder(); 107 if (_dataChars == null) { 108 return "<none>"; 109 } 110 if (controller == null || controller.isSIIBootMode()) { 111 for (int i = 0; i < _nDataChars; i++) { 112 s.append(jmri.util.StringUtil.twoHexFromInt(_dataChars[i])); 113 s.append(" "); 114 } 115 } else { 116 for (int i = 0; i < _nDataChars; i++) { 117 s.append("<"); 118 s.append(_dataChars[i]); 119 s.append(">"); 120 } 121 } 122 return new String(s); 123 } 124 125 /** 126 * Extracts Read-CV returned value from a message. 127 * <p> 128 * QSI is assumed to not be echoing commands. A reply to a command may 129 * include the prompt that was printed after the previous command Reply to a 130 * CV read is of the form " = hvv" where vv is the CV value in hex. 131 * 132 * @return the value of the read CV or -1 if the reply cannot be parsed. 133 */ 134 public int value() { 135 return getElement(5) & 0xFF; 136 } 137 138 int match(String s) { 139 // find a specific string in the reply 140 String rep = new String(_dataChars, 0, _nDataChars); 141 return rep.indexOf(s); 142 } 143 144 int skipWhiteSpace(int index) { 145 // start at index, passing any whitespace & control characters at the start of the buffer 146 while (index < getNumDataElements() - 1 147 && ((char) getElement(index) <= ' ')) { 148 index++; 149 } 150 return index; 151 } 152 153 int skipEqual(int index) { 154 // start at index, skip over the equals and hex prefix 155 int len = "= h".length(); 156 if (getNumDataElements() >= index + len - 1 157 && '=' == (char) getElement(index) 158 && ' ' == (char) getElement(index + 1) 159 && 'h' == (char) getElement(index + 2)) { 160 index += len; 161 } 162 return index; 163 } 164 165 // Longest boot reply is 256bytes each preceded by DLE + 2xSTX + ETX 166 static public final int MAXSIZE = 515; 167 168 // contents (private) 169 private boolean _isBoot = false; 170 171}