]>
Commit | Line | Data |
---|---|---|
6a44fc57 VPP |
1 | ## |
2 | ## This file is part of the libsigrokdecode project. | |
3 | ## | |
4 | ## Copyright (C) 2019 Vesa-Pekka Palmu <vpalmu@depili.fi> | |
5 | ## | |
6 | ## This program is free software; you can redistribute it and/or modify | |
7 | ## it under the terms of the GNU General Public License as published by | |
8 | ## the Free Software Foundation; either version 3 of the License, or | |
9 | ## (at your option) any later version. | |
10 | ## | |
11 | ## This program is distributed in the hope that it will be useful, | |
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ## GNU General Public License for more details. | |
15 | ## | |
16 | ## You should have received a copy of the GNU General Public License | |
17 | ## along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | ## | |
19 | ||
20 | import sigrokdecode as srd | |
21 | from math import ceil | |
22 | from .lists import * | |
23 | ||
24 | L = len(cmds) | |
25 | RX = 0 | |
26 | TX = 1 | |
6a44fc57 VPP |
27 | |
28 | # Don't forget to keep this in sync with 'cmds' is lists.py. | |
29 | class Ann: | |
30 | PAGE, GBV, GWV, GSV, GLV, GRPC, SBV, SWV, SSV, RPC, LINE, RECT, FRECT, \ | |
31 | PIXEL, GBVA, GWVA, SBVA, GBVR, GWVR, GSVR, GLVR, GRPCR, SBVR, SWVR, SSVR, \ | |
32 | RPCR, LINER, RECTR, FRECTR, PIXELR, GBVAR, GWVAR, SBVAR, ACK, NACK, SWVA, \ | |
33 | SWVAR, GCV, GCVR, SCV, SCVR, BIT, FIELD, WARN = range(L + 3) | |
34 | ||
35 | def cmd_annotation_classes(): | |
36 | return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()]) | |
37 | ||
38 | class Decoder(srd.Decoder): | |
39 | api_version = 3 | |
40 | id = 'amulet_ascii' | |
41 | name = 'Amulet ASCII' | |
42 | longname = 'Amulet LCD ASCII' | |
43 | desc = 'Amulet Technologies LCD controller ASCII protocol.' | |
44 | license = 'gplv3+' | |
45 | inputs = ['uart'] | |
46 | outputs = [] | |
47 | tags = ['Display'] | |
48 | annotations = cmd_annotation_classes() + ( | |
49 | ('bit', 'Bit'), | |
50 | ('field', 'Field'), | |
51 | ('warning', 'Warning'), | |
52 | ) | |
53 | annotation_rows = ( | |
54 | ('bits', 'Bits', (L + 0,)), | |
55 | ('fields', 'Fields', (L + 1,)), | |
56 | ('commands', 'Commands', tuple(range(len(cmds)))), | |
57 | ('warnings', 'Warnings', (L + 2,)), | |
58 | ) | |
59 | options = ( | |
60 | {'id': 'ms_chan', 'desc': 'Master -> slave channel', | |
f57bde30 | 61 | 'default': 'RX', 'values': ('RX', 'TX')}, |
6a44fc57 | 62 | {'id': 'sm_chan', 'desc': 'Slave -> master channel', |
f57bde30 | 63 | 'default': 'TX', 'values': ('RX', 'TX')}, |
6a44fc57 VPP |
64 | ) |
65 | ||
66 | def __init__(self): | |
67 | self.reset() | |
68 | ||
69 | def reset(self): | |
70 | self.state = None | |
71 | self.cmdstate = None | |
72 | ||
73 | # Build dict mapping command keys to handler functions. Each | |
74 | # command in 'cmds' (defined in lists.py) has a matching | |
75 | # handler self.handle_<shortname>. | |
76 | def get_handler(cmd): | |
77 | s = 'handle_%s' % cmds[cmd][0].lower().replace('/', '_') | |
78 | return getattr(self, s) | |
79 | self.cmd_handlers = dict((cmd, get_handler(cmd)) for cmd in cmds.keys()) | |
80 | ||
81 | def start(self): | |
82 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
83 | ||
84 | def putx(self, data): | |
85 | # Simplification, most annotations span exactly one SPI byte/packet. | |
86 | self.put(self.ss, self.es, self.out_ann, data) | |
87 | ||
88 | def putf(self, data): | |
89 | self.put(self.ss_field, self.es_field, self.out_ann, data) | |
90 | ||
91 | def putc(self, data): | |
92 | self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) | |
93 | ||
94 | def cmd_ann_list(self): | |
95 | x, s = cmds[self.state][0], cmds[self.state][1] | |
96 | return ['Command: %s (%s)' % (s, x), 'Command: %s' % s, | |
97 | 'Cmd: %s' % s, 'Cmd: %s' % x, x] | |
98 | ||
99 | def emit_cmd_byte(self): | |
100 | self.ss_cmd = self.ss | |
101 | self.putx([Ann.FIELD, self.cmd_ann_list()]) | |
102 | ||
103 | def emit_addr_bytes(self, pdata): | |
104 | if self.cmdstate == 2: | |
105 | self.ss_field = self.ss | |
106 | self.addr = chr(pdata) | |
0b137b0d UH |
107 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
108 | 'Addr high 0x%c' % pdata, 'Addr h 0x%c' % pdata]]) | |
6a44fc57 VPP |
109 | elif self.cmdstate == 3: |
110 | self.es_field = self.es | |
111 | self.addr += chr(pdata) | |
112 | self.addr = int(self.addr, 16) | |
0b137b0d UH |
113 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
114 | 'Addr low 0x%c' % pdata, 'Addr l 0x%c' % pdata]]) | |
6a44fc57 VPP |
115 | self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, |
116 | 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) | |
117 | ||
118 | def emit_cmd_end(self, data): | |
119 | self.es_cmd = self.es | |
120 | self.putc(data) | |
121 | self.state = None | |
122 | ||
123 | def handle_read(self, data): | |
124 | if self.cmdstate == 1: | |
125 | self.emit_cmd_byte() | |
126 | self.addr = 0 | |
127 | elif self.cmdstate == 2: | |
128 | self.emit_addr_bytes(pdata) | |
129 | elif self.cmdstate == 3: | |
130 | self.emit_addr_bytes(pdata) | |
131 | self.cmdstate += 1 | |
132 | ||
133 | def handle_set_common(self, pdata): | |
134 | if self.cmdstate == 1: | |
135 | self.addr = 0 | |
136 | self.emit_addr_bytes(pdata) | |
137 | ||
138 | def emit_not_implemented(self, data): | |
139 | self.es_cmd = self.es | |
140 | self.putc([Ann.WARN, ['Command not decoded', 'Not decoded']]) | |
141 | self.emit_cmd_end(data) | |
142 | ||
143 | def handle_string(self, pdata, ann_class): | |
144 | # TODO: unicode / string modifiers... | |
145 | self.handle_set_common(pdata) | |
146 | if self.cmdstate == 4: | |
147 | self.ss_field = self.ss | |
148 | self.value = '' | |
149 | if pdata == 0x00: | |
150 | # Null terminated string ends. | |
151 | self.es_field = self.es | |
152 | self.putx([Ann.BIT, ['NULL']]) | |
0b137b0d UH |
153 | self.putf([Ann.FIELD, ['Value: %s' % self.value, |
154 | 'Val: %s' % self.value, '%s' % self.value]]) | |
6a44fc57 VPP |
155 | self.emit_cmd_end([ann_class, self.cmd_ann_list()]) |
156 | return | |
157 | if self.cmdstate > 3: | |
158 | self.value += chr(pdata) | |
0b137b0d | 159 | self.putx([Ann.BIT, ['%c' % pdata]]) |
6a44fc57 VPP |
160 | self.cmdstate += 1 |
161 | ||
162 | # Command handlers | |
163 | ||
164 | # Page change 0xA0, 0x02, index_high, index_low, checksum | |
165 | def handle_page(self, pdata): | |
166 | if self.cmdstate == 2: | |
167 | if pdata == 0x02: | |
168 | self.ss_field = self.ss_cmd | |
169 | self.es_field = self.es | |
170 | self.putf([Ann.FIELD, self.cmd_ann_list()]) | |
171 | self.checksum = 0xA0 + 0x02 | |
172 | else: | |
173 | self.putx([Ann.WARN, ['Illegal second byte for page change', | |
174 | 'Illegal byte']]) | |
175 | self.state = None | |
176 | elif self.cmdstate == 3: | |
177 | self.ss_field = self.ss | |
178 | self.checksum += pdata | |
179 | self.page[0] = pdata | |
180 | elif self.cmdstate == 4: | |
181 | self.checksum += pdata | |
182 | self.page[1] = pdata | |
183 | self.es_field = self.es | |
184 | if self.page[0] == self.page [1] == 0xFF: | |
185 | # Soft reset trigger | |
186 | self.putf(Ann.WARN, ['Soft reset', 'Reset']) | |
187 | else: | |
188 | page = chr(self.page[0]) + chr(self.page[1]) | |
0b137b0d UH |
189 | self.putf(Ann.FIELD, ['Page index: 0x%s' % page, |
190 | 'Page: 0x%s' % page, '0x%s' % page]) | |
6a44fc57 VPP |
191 | elif self.cmdstate == 5: |
192 | self.checksum += pdata | |
193 | if (self.checksum & 0xFF) != 0: | |
194 | self.putx([Ann.WARN, ['Checksum error', 'Error', 'ERR']]) | |
195 | else: | |
196 | self.putx([Ann.FIELD, ['Checksum OK', 'OK']]) | |
197 | self.emit_cmd_end(Ann.PAGE) | |
198 | self.cmdstate += 1 | |
199 | ||
200 | # Value reads: command byte, address high nibble, address low nibble | |
201 | ||
202 | # Get byte value | |
203 | def handle_gbv(self, pdata): | |
204 | self.handle_read(pdata) | |
205 | self.emit_cmd_end([Ann.GBV, self.cmd_ann_list()]) | |
206 | ||
207 | # Get word value | |
208 | def handle_gwv(self, pdata): | |
209 | self.handle_read(pdata) | |
210 | self.emit_cmd_end([Ann.GWV, self.cmd_ann_list()]) | |
211 | ||
212 | # Get string value | |
213 | def handle_gsv(self, pdata): | |
214 | self.handle_read(pdata) | |
215 | self.emit_cmd_end([Ann.GSV, self.cmd_ann_list()]) | |
216 | ||
217 | # Get label value | |
218 | def handle_glv(self, pdata): | |
219 | self.handle_read(pdata) | |
220 | self.emit_cmd_end([Ann.GLV, self.cmd_ann_list()]) | |
221 | ||
222 | # Get RPC buffer | |
223 | def handle_grpc(self, pdata): | |
224 | if self.cmdstate == 2: | |
225 | self.ss_field = self.ss | |
226 | self.flags = int(chr(pdata), 16) << 4 | |
227 | elif self.cmdstate == 3: | |
228 | self.flags += int(chr(pdata), 16) | |
229 | self.es_field = self.es | |
0b137b0d | 230 | self.putf([Ann.FIELD, ['RPC flag: 0x%02X' % self.flags]]) |
6a44fc57 VPP |
231 | self.emit_cmd_end([Ann.GRPC, self.cmd_ann_list()]) |
232 | ||
233 | # Get byte value array | |
234 | def handle_gbva(self, pdata): | |
235 | self.handle_read(pdata) | |
236 | self.emit_cmd_end([Ann.GBVA, self.cmd_ann_list()]) | |
237 | ||
238 | # Get word value array | |
239 | def handle_gwva(self, pdata): | |
240 | self.handle_read(pdata) | |
241 | self.emit_cmd_end([Ann.GWVA, self.cmd_ann_list()]) | |
242 | ||
243 | # Get color variable | |
244 | def handle_gcv(self, pdata): | |
245 | self.handle_read(pdata) | |
246 | self.emit_cmd_end([Ann.GCV, self.cmd_ann_list()]) | |
247 | ||
248 | # Value setters: command byte, address high nibble, address low nibble, data bytes | |
249 | ||
250 | # Set byte value data = high nibble, low nibble | |
251 | def handle_sbv(self, pdata): | |
252 | self.handle_set_common(pdata) | |
253 | if self.cmdstate == 4: | |
254 | self.ss_field = self.ss | |
255 | self.value = chr(pdata) | |
256 | elif self.cmdstate == 5: | |
257 | self.value += chr(pdata) | |
258 | self.es_field = self.es | |
259 | self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, | |
260 | 'Val: 0x%s' % self.value, '0x%s' % self.value]]) | |
261 | self.emit_cmd_end([Ann.SBV, self.cmd_ann_list()]) | |
262 | self.cmdstate += 1 | |
263 | ||
264 | # Set word value, msb high, msb low, lsb high, lsb low | |
265 | def handle_swv(self, pdata): | |
266 | self.handle_set_common(pdata) | |
267 | if self.cmdstate > 3: | |
268 | nibble = self.cmdstate - 4 | |
269 | if nibble == 0: | |
270 | self.ss_field = self.ss | |
271 | self.value = 0 | |
272 | self.value += int(chr(pdata), 16) << 12 - (4 * nibble) | |
273 | if nibble == 3: | |
274 | self.es_field = self.es | |
275 | self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, | |
276 | 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) | |
277 | self.emit_cmd_end([Ann.SWV, self.cmd_ann_list()]) | |
278 | return | |
279 | self.cmdstate += 1 | |
280 | ||
281 | # Set string value, null terminated utf8 strings | |
282 | def handle_ssv(self, pdata): | |
283 | self.handle_string(pdata, Ann.SSV) | |
284 | ||
285 | # Set byte value array | |
286 | def handle_sbva(self, pdata): | |
287 | nibble = (self.cmdstate - 3) % 2 | |
288 | if self.cmdstate == 2: | |
289 | self.addr = int(chr(pdata), 16) << 4 | |
290 | self.ss_field = self.ss | |
0b137b0d UH |
291 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
292 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
293 | elif self.cmdstate == 3: |
294 | self.addr += int(chr(pdata), 16) | |
295 | self.es_field = self.ss | |
0b137b0d UH |
296 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
297 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
298 | self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, |
299 | 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) | |
300 | elif stage == 2: | |
301 | if pdata == 0x00: | |
302 | # Null terminated list | |
303 | self.emit_cmd_end([Ann.SBVA, self.cmd_ann_list()]) | |
304 | return | |
305 | self.value = int(chr(pdata), 16) << 4 | |
306 | else: | |
307 | self.value += int(chr(pdata), 16) | |
308 | self.es_field = self.es | |
0b137b0d UH |
309 | self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, |
310 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
311 | self.cmdstate += 1 |
312 | ||
313 | # Set word value array | |
314 | def handle_swva(self, pdata): | |
315 | nibble = (self.cmdstate - 3) % 4 | |
316 | if self.cmdstate == 2: | |
317 | self.addr = int(chr(pdata), 16) << 4 | |
318 | self.ss_field = self.ss | |
0b137b0d UH |
319 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
320 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
321 | elif self.cmdstate == 3: |
322 | self.addr += int(chr(pdata), 16) | |
323 | self.es_field = self.ss | |
0b137b0d UH |
324 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
325 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
326 | self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, |
327 | 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) | |
328 | self.value = 0 | |
329 | else: | |
330 | self.value += int(chr(pdata), 16) << 12 - (4 * nibble) | |
331 | if nibble == 0: | |
332 | if pdata == 0x00: | |
333 | # Null terminated list | |
334 | self.emit_cmd_end([Ann.SWVA, self.cmd_ann_list()]) | |
335 | return | |
336 | self.ss_field = self.ss | |
337 | if nibble == 3: | |
338 | self.es_field = self.es | |
0b137b0d UH |
339 | self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, |
340 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
341 | self.cmdstate += 1 |
342 | ||
343 | # Set color variable | |
344 | def handle_scv(self, pdata): | |
345 | if self.cmdstate == 8: | |
346 | self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) | |
347 | self.cmdstate += 1 | |
348 | ||
349 | # RPC trigger | |
350 | def handle_rpc(self, pdata): | |
351 | self.handle_read(pdata) | |
352 | self.emit_cmd_end([Ann.RPC, self.cmd_ann_list()]) | |
353 | ||
354 | # Drawing | |
355 | ||
356 | # Decode pair of (x,y) 16bit coordinates | |
357 | def decode_coords(self, pdata): | |
358 | if self.cmdstate == 1: | |
359 | self.coords[0] = 0 | |
360 | self.coords[1] = 0 | |
361 | self.coords[2] = 0 | |
362 | self.coords[3] = 0 | |
363 | if self.cmdstate < 18: | |
364 | # Coordinates | |
365 | nibble = (self.cmdstate - 1) % 4 | |
366 | i = (self.cmdstate - 1) / 4 | |
367 | self.coords[i] += int(chr(pdata), 16) << 12 - (4 * nibble) | |
368 | if nibble == 0: | |
369 | self.ss_field = self.ss | |
370 | elif nibble == 3: | |
371 | self.es_field = self.es | |
0b137b0d UH |
372 | self.putf([Ann.FIELD, ['Coordinate 0x%04X' % self.coords[i]], |
373 | ['0x%04X' % self.coords[i]]]) | |
6a44fc57 VPP |
374 | |
375 | # TODO: There are actually two protocol revisions for drawing. | |
376 | # Both use 4 bytes for 16bit x and y pairs for start and end. | |
377 | # The older follows this by a pattern selector and then line weight. | |
378 | # Newer version has 6 bytes for 8bit RGB color... | |
379 | ||
380 | # Draw line | |
381 | def handle_line(self, pdata): | |
382 | decode_coords(pdata) | |
383 | if self.cmdstate == 18: | |
384 | self.es_cmd = self.es | |
385 | self.putc([Ann.LINE, self.cmd_ann_list()]) | |
386 | self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) | |
387 | self.state = None | |
388 | self.cmdstate += 1 | |
389 | ||
390 | # Draw rectange | |
391 | def handle_rect(self, pdata): | |
392 | decode_coords(pdata) | |
393 | if self.cmdstate == 18: | |
394 | self.es_cmd = self.es | |
395 | self.putc([Ann.RECT, self.cmd_ann_list()]) | |
396 | self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) | |
397 | self.state = None | |
398 | self.cmdstate += 1 | |
399 | ||
400 | # Draw filled rectangle | |
401 | def handle_frect(self, pdata): | |
402 | decode_coords(pdata) | |
403 | if self.cmdstate == 18: | |
404 | self.es_cmd = self.es | |
405 | self.putc([Ann.FRECT, self.cmd_ann_list()]) | |
406 | self.putc([Ann.WARN, ['Fill pattern / Color not implemented']]) | |
407 | self.state = None | |
408 | self.cmdstate += 1 | |
409 | ||
410 | # Draw pixel | |
411 | def handle_pixel(self, pdata): | |
412 | self.es_cmd = self.es | |
413 | self.putc([Ann.WARN, ['Draw pixel documentation is missing.', 'Undocumented']]) | |
414 | self.state = None | |
415 | ||
416 | # Replies | |
417 | def handle_gbvr(self, pdata): | |
418 | self.emit_add_bytes(pdata) | |
419 | if self.cmdstate == 4: | |
420 | self.ss_field = self.ss | |
421 | self.value = int(chr(pdata), 16) << 4 | |
0b137b0d | 422 | self.putx([Ann.BIT, ['High nibble 0x%s' % pdata, '0x%s' % pdata]]) |
6a44fc57 VPP |
423 | elif self.cmdstate == 5: |
424 | self.value += int(chr(pdata), 16) | |
0b137b0d | 425 | self.putx([Ann.BIT, ['Low nibble 0x%s' % pdata, '0x%s' % pdata]]) |
6a44fc57 | 426 | self.es_field = self.es |
0b137b0d UH |
427 | self.putf([Ann.FIELD, ['Value: 0x%02X' % self.value, |
428 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
429 | self.emit_cmd_end([Ann.GBVR, self.cmd_ann_list()]) |
430 | self.cmdstate += 1 | |
431 | ||
432 | def handle_gwvr(self, pdata): | |
433 | self.emit_add_bytes(pdata) | |
434 | if self.cmdstate > 3: | |
435 | nibble = self.cmdstate - 3 | |
436 | if nibble == 0: | |
437 | self.value = 0 | |
438 | self.ss_field = self.ss | |
439 | self.value += int(chr(pdata), 16) << 12 - (4 * nibble) | |
0b137b0d | 440 | self.putx([Ann.BIT, ['0x%s' % pdata]]) |
6a44fc57 | 441 | if nibble == 3: |
0b137b0d UH |
442 | self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, |
443 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
444 | self.es_cmd = self.ss |
445 | self.emit_cmd_end([Ann.GWVR, self.cmd_ann_list()]) | |
446 | self.cmdstate += 1 | |
447 | ||
448 | def handle_gsvr(self, pdata): | |
449 | self.handle_string(pdata, Ann.GSVR) | |
450 | ||
451 | def handle_glvr(self, pdata): | |
452 | self.handle_string(pdata, Ann.GLVR) | |
453 | ||
454 | def handle_grpcr(self, pdata): | |
455 | self.handle_addr(pdata) | |
456 | if self.cmdstate > 3: | |
457 | nibble = (self.cmdstate - 3) % 2 | |
458 | if nibble == 0: | |
459 | if pdata == 0x00: | |
460 | self.emit_cmd_end([Ann.GRPCR, self.cmd_ann_list()]) | |
461 | return | |
462 | self.value = int(chr(pdata), 16) << 4 | |
463 | self.ss_field = self.ss | |
0b137b0d | 464 | self.putx([Ann.BIT, ['0x%s' % pdata]]) |
6a44fc57 VPP |
465 | if nibble == 2: |
466 | self.value += int(chr(pdata), 16) | |
467 | self.es_field = self.es | |
0b137b0d UH |
468 | self.putx([Ann.BIT, ['0x%s' % pdata]]) |
469 | self.putf([Ann.FIELD, ['0x%02X' % self.value]]) | |
6a44fc57 VPP |
470 | self.cmdstate += 1 |
471 | ||
472 | def handle_sbvr(self, pdata): | |
473 | self.handle_set_common(pdata) | |
474 | if self.cmdstate == 4: | |
475 | self.ss_field = self.ss | |
476 | self.value = chr(pdata) | |
477 | elif self.cmdstate == 5: | |
478 | self.value += chr(pdata) | |
479 | self.es_field = self.es | |
480 | self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, | |
481 | 'Val: 0x%s' % self.value, '0x%s' % self.value]]) | |
482 | self.emit_cmd_end([Ann.SBVR, self.cmd_ann_list()]) | |
483 | self.cmdstate += 1 | |
484 | ||
485 | def handle_swvr(self, pdata): | |
486 | self.handle_set_common(pdata) | |
487 | if self.cmdstate == 4: | |
488 | self.ss_field = self.ss | |
489 | self.value = (pdata - 0x30) << 4 | |
490 | elif self.cmdstate == 5: | |
491 | self.value += (pdata - 0x30) | |
492 | self.value = self.value << 8 | |
493 | elif self.cmdstate == 6: | |
494 | self.value += (pdata - 0x30) << 4 | |
495 | elif self.cmdstate == 7: | |
496 | self.value += (pdata - 0x30) | |
497 | self.es_field = self.es | |
498 | self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, | |
499 | 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) | |
500 | self.emit_cmd_end([Ann.SWVR, self.cmd_ann_list()]) | |
501 | self.state = None | |
502 | self.cmdstate += 1 | |
503 | ||
504 | def handle_ssvr(self, pdata): | |
505 | self.handle_string(pdata, Ann.SSVR) | |
506 | ||
507 | def handle_rpcr(self, pdata): | |
508 | self.handle_read(pdata) | |
509 | self.emit_cmd_end([Ann.RPCR, self.cmd_ann_list()]) | |
510 | ||
511 | def handle_liner(self, pdata): | |
512 | decode_coords(pdata) | |
513 | if self.cmdstate == 18: | |
514 | self.es_cmd = self.es | |
515 | self.putc([Ann.LINER, self.cmd_ann_list()]) | |
516 | self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) | |
517 | self.state = None | |
518 | self.cmdstate += 1 | |
519 | ||
520 | def handle_rectr(self, pdata): | |
521 | decode_coords(pdata) | |
522 | if self.cmdstate == 18: | |
523 | self.es_cmd = self.es | |
524 | self.putc([Ann.RECTR, self.cmd_ann_list()]) | |
525 | self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) | |
526 | self.state = None | |
527 | self.cmdstate += 1 | |
528 | ||
529 | def handle_frectr(self, pdata): | |
530 | decode_coords(pdata) | |
531 | if self.cmdstate == 18: | |
532 | self.es_cmd = self.es | |
533 | self.putc([Ann.FRECTR, self.cmd_ann_list()]) | |
534 | self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) | |
535 | self.state = None | |
536 | self.cmdstate += 1 | |
537 | ||
538 | def handle_pixelr(self, pdata): | |
539 | self.es_cmd = self.es | |
540 | self.putc([Ann.WARN,['Draw pixel documentation is missing.', 'Undocumented']]) | |
541 | self.state = None | |
542 | ||
543 | def handle_gbvar(self, pdata): | |
544 | nibble = (self.cmdstate - 3) % 2 | |
545 | if self.cmdstate == 2: | |
546 | self.addr = int(chr(pdata), 16) << 4 | |
547 | self.ss_field = self.ss | |
0b137b0d UH |
548 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
549 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
550 | elif self.cmdstate == 3: |
551 | self.addr += int(chr(pdata), 16) | |
552 | self.es_field = self.ss | |
0b137b0d UH |
553 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
554 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
555 | self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, |
556 | 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) | |
557 | elif stage == 2: | |
558 | if pdata == 0x00: | |
559 | # Null terminated list | |
560 | self.emit_cmd_end([Ann.GBVAR, self.cmd_ann_list()]) | |
561 | return | |
562 | self.value = int(chr(pdata), 16) << 4 | |
563 | else: | |
564 | self.value += int(chr(pdata), 16) | |
565 | self.es_field = self.es | |
0b137b0d UH |
566 | self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, |
567 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
568 | self.cmdstate += 1 |
569 | ||
570 | def handle_gwvar(self, pdata): | |
571 | nibble = (self.cmdstate - 3) % 4 | |
572 | if self.cmdstate == 2: | |
573 | self.addr = int(chr(pdata), 16) << 4 | |
574 | self.ss_field = self.ss | |
0b137b0d UH |
575 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
576 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
577 | elif self.cmdstate == 3: |
578 | self.addr += int(chr(pdata), 16) | |
579 | self.es_field = self.ss | |
0b137b0d UH |
580 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
581 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
582 | self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, |
583 | 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) | |
584 | self.value = 0 | |
585 | else: | |
586 | self.value += int(chr(pdata), 16) << 12 - (4 * nibble) | |
587 | if nibble == 0: | |
588 | if pdata == 0x00: | |
589 | # Null terminated list | |
590 | self.emit_cmd_end([Ann.GWVAR, self.cmd_ann_list()]) | |
591 | return | |
592 | self.ss_field = self.ss | |
593 | if nibble == 3: | |
594 | self.es_field = self.es | |
0b137b0d UH |
595 | self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, |
596 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
597 | self.cmdstate += 1 |
598 | ||
599 | # Get byte variable array reply | |
600 | def handle_sbvar(self, pdata): | |
601 | nibble = (self.cmdstate - 3) % 2 | |
602 | if self.cmdstate == 2: | |
603 | self.addr = int(chr(pdata), 16) << 4 | |
604 | self.ss_field = self.ss | |
0b137b0d UH |
605 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
606 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
607 | elif self.cmdstate == 3: |
608 | self.addr += int(chr(pdata), 16) | |
609 | self.es_field = self.ss | |
0b137b0d UH |
610 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
611 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
612 | self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, |
613 | 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) | |
614 | elif stage == 2: | |
615 | if pdata == 0x00: | |
616 | # Null terminated list | |
617 | self.emit_cmd_end([Ann.SBVAR, self.cmd_ann_list()]) | |
618 | return | |
619 | self.value = int(chr(pdata), 16) << 4 | |
620 | else: | |
621 | self.value += int(chr(pdata), 16) | |
622 | self.es_field = self.es | |
0b137b0d UH |
623 | self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, |
624 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
625 | self.cmdstate += 1 |
626 | ||
627 | # Set word variable array reply | |
628 | def handle_swvar(self, pdata): | |
629 | nibble = (self.cmdstate - 3) % 4 | |
630 | if self.cmdstate == 2: | |
631 | self.addr = int(chr(pdata), 16) << 4 | |
632 | self.ss_field = self.ss | |
0b137b0d UH |
633 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
634 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
635 | elif self.cmdstate == 3: |
636 | self.addr += int(chr(pdata), 16) | |
637 | self.es_field = self.ss | |
0b137b0d UH |
638 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
639 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
640 | self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, |
641 | 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) | |
642 | self.value = 0 | |
643 | else: | |
644 | self.value += int(chr(pdata), 16) << 12 - (4 * nibble) | |
645 | if nibble == 0: | |
646 | if pdata == 0x00: | |
647 | # Null terminated list | |
648 | self.emit_cmd_end([Ann.SWVAR, self.cmd_ann_list()]) | |
649 | return | |
650 | self.ss_field = self.ss | |
651 | if nibble == 3: | |
652 | self.es_field = self.es | |
0b137b0d UH |
653 | self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, |
654 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
655 | self.cmdstate += 1 |
656 | ||
657 | def handle_gcvr(self, pdata): | |
658 | if self.cmdstate == 8: | |
659 | self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) | |
660 | self.cmdstate += 1 | |
661 | ||
662 | def handle_scvr(self, pdata): | |
663 | if self.cmdstate == 8: | |
664 | self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) | |
665 | self.cmdstate += 1 | |
666 | ||
667 | # ACK & NACK | |
668 | ||
669 | def handle_ack(self, pdata): | |
670 | self.putx([Ann.ACK, self.cmd_ann_list()]) | |
671 | self.state = None | |
672 | ||
673 | def handle_nack(self, pdata): | |
674 | self.putx([Ann.NACK, self.cmd_ann_list()]) | |
675 | self.state = None | |
676 | ||
677 | def decode(self, ss, es, data): | |
678 | ptype, rxtx, pdata = data | |
679 | ||
680 | self.ss, self.es = ss, es | |
681 | ||
682 | if ptype != 'DATA': | |
683 | return | |
684 | ||
685 | # Handle commands. | |
686 | try: | |
687 | abort_current = (0xD0 <= pdata[0] <= 0xF7) and \ | |
688 | (not (self.state in cmds_with_high_bytes)) and \ | |
689 | self.state != None | |
690 | if abort_current: | |
691 | self.putx([Ann.WARN, ['Command aborted by invalid byte', 'Abort']]) | |
692 | self.state = pdata[0] | |
693 | self.emit_cmd_byte() | |
694 | self.cmdstate = 1 | |
0b137b0d | 695 | if self.state is None: |
6a44fc57 VPP |
696 | self.state = pdata[0] |
697 | self.emit_cmd_byte() | |
698 | self.cmdstate = 1 | |
699 | self.cmd_handlers[self.state](pdata[0]) | |
700 | except KeyError: | |
701 | self.putx([Ann.WARN, ['Unknown command: 0x%02x' % pdata[0]]]) | |
702 | self.state = None |