/
GridConnectReply.java
249 lines (219 loc) · 6.03 KB
/
GridConnectReply.java
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package jmri.jmrix.can.adapters.gridconnect;
import jmri.jmrix.AbstractMRReply;
import jmri.jmrix.can.CanReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class for replies in a GridConnect based message/reply protocol.
* <p>
* The GridConnect protocol encodes messages as an ASCII string of up to 24
* characters of the form: :ShhhhNd0d1d2d3d4d5d6d7;
* <p>
* hhhh is the two byte (11
* useful bits) header The S indicates a standard CAN frame
* :XhhhhhhhhNd0d1d2d3d4d5d6d7; The X indicates an extended CAN frame N or R
* indicates a normal or remote frame, in position 6 or 10 d0 - d7 are the (up
* to) 8 data bytes
* <p>
*
* @author Andrew Crosland Copyright (C) 2008, 2009
* @author Bob Jacobsen Copyright (C) 2008
*/
public class GridConnectReply extends AbstractMRReply {
static final int MAXLEN = 27;
/**
* Creates a new instance of GridConnectReply.
*/
public GridConnectReply() {
_nDataChars = 0;
_dataChars = new int[MAXLEN];
}
/**
* Creates a new GridConnectReply from String.
* @param s String to use as basis for the GCReply.
*/
public GridConnectReply(String s) {
_nDataChars = s.length();
for (int i = 0; i < s.length(); i++) {
_dataChars[i] = s.charAt(i);
}
}
/**
* Create a CanReply from a GridConnectReply.
* @return new CanReply Outgoing message.
*/
public CanReply createReply() {
CanReply ret = new CanReply();
log.debug("createReply converts from {}", this);
// basic checks drop out the frame
if (!basicFormatCheck()) {
ret.setHeader(0);
ret.setNumDataElements(0);
return ret;
}
// Is it an Extended frame?
if (isExtended()) {
ret.setExtended(true);
}
// Copy the header
ret.setHeader(getHeader());
// Is it an RTR frame?
if (isRtr()) {
ret.setRtr(true);
}
// Get the data
for (int i = 0; i < getNumBytes(); i++) {
ret.setElement(i, getByte(i));
}
ret.setNumDataElements(getNumBytes());
log.debug("createReply converted to {}", ret);
return ret;
}
/**
* Check if this GCReply contains an Extended or Standard flag.
* @return true if contains a flag, else false.
*/
protected boolean basicFormatCheck() {
return !((getElement(1) != 'X') && (getElement(1) != 'S'));
}
/**
* {@inheritDoc}
*/
@Override
protected int skipPrefix(int index) {
while (_dataChars[index] == ':') {
index++;
}
return index;
}
/**
* {@inheritDoc}
*/
@Override
public int getNumDataElements() {
return _nDataChars;
}
/**
* Set Number of Data Elements.
* Max. length set by the MAXLEN constant.
* @param n Number Elements.
*/
public void setNumDataElements(int n) {
_nDataChars = (n <= MAXLEN) ? n : MAXLEN;
}
/**
* {@inheritDoc}
*/
@Override
public int getElement(int n) {
return _dataChars[n];
}
/**
* {@inheritDoc}
*/
@Override
public void setElement(int n, int v) {
if (n < MAXLEN) {
_dataChars[n] = v;
_nDataChars = Math.max(_nDataChars, n + 1);
}
}
/**
* Get if the GridConnectReply is Extended.
* @return true if extended, else false.
*/
public boolean isExtended() {
return (getElement(1) == 'X');
}
/**
* Get if the GridConnectReply is RtR.
* @return true if RtR, else false.
*/
public boolean isRtr() {
return (getElement(_RTRoffset) == 'R');
}
/**
* {@inheritDoc}
*/
@Override
public int maxSize() {
return MAXLEN;
}
/**
* Set the GridConnectReply data by Array.
* @param d data array.
*/
public void setData(int[] d) {
int len = (d.length <= MAXLEN) ? d.length : MAXLEN;
for (int i = 0; i < len; i++) {
_dataChars[i] = d[i];
}
}
// pointer to the N or R character
int _RTRoffset = -1;
/**
* Get the CAN header by using chars from 2 to up to 9.
* <p>
* Right justify standard headers that had 4 digits.
*
* @return the CAN header as an int
*/
public int getHeader() {
int val = 0;
for (int i = 2; i <= 10; i++) {
_RTRoffset = i;
if (_dataChars[i] == 'N') {
break;
}
if (_dataChars[i] == 'R') {
break;
}
val = val * 16 + getHexDigit(i);
}
return val;
}
/**
* Get the number of data bytes.
* @return number of bytes in reply.
*/
public int getNumBytes() {
// subtract framing and ID bytes, etc and each byte is two ASCII hex digits
return (_nDataChars - (_RTRoffset + 1)) / 2;
}
/**
* Get a hex data byte from the message.
* <p>
* Data bytes are encoded as two ASCII hex digits starting at byte 7 of the
* message.
*
* @param b The byte offset (0 - 7)
* @return The value
*/
public int getByte(int b) {
if ((b >= 0) && (b <= 7)) {
int index = b * 2 + _RTRoffset + 1;
int hi = getHexDigit(index++);
int lo = getHexDigit(index);
if ((hi < 16) && (lo < 16)) {
return (hi * 16 + lo);
}
}
return 0;
}
// Get a single hex digit. returns 0 if digit is invalid
private int getHexDigit(int index) {
int b = 0;
b = _dataChars[index];
if ((b >= '0') && (b <= '9')) {
b = b - '0';
} else if ((b >= 'A') && (b <= 'F')) {
b = b - 'A' + 10;
} else if ((b >= 'a') && (b <= 'f')) {
b = b - 'a' + 10;
} else {
b = 0;
}
return (byte) b;
}
private final static Logger log = LoggerFactory.getLogger(GridConnectReply.class);
}