]> sigrok.org Git - libsigrokdecode.git/blob - decoders/amulet_ascii/pd.py
Backport recent changes from mainline.
[libsigrokdecode.git] / decoders / amulet_ascii / pd.py
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
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',
61             'default': 'RX', 'values': ('RX', 'TX')},
62         {'id': 'sm_chan', 'desc': 'Slave -> master channel',
63             'default': 'TX', 'values': ('RX', 'TX')},
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)
107             self.putx([Ann.BIT, ['Address high nibble: %c' % pdata,
108                  'Addr high 0x%c' % pdata, 'Addr h 0x%c' % pdata]])
109         elif self.cmdstate == 3:
110             self.es_field = self.es
111             self.addr += chr(pdata)
112             self.addr = int(self.addr, 16)
113             self.putx([Ann.BIT, ['Address low nibble: %c' % pdata,
114                  'Addr low 0x%c' % pdata, 'Addr l 0x%c' % pdata]])
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']])
153             self.putf([Ann.FIELD, ['Value: %s' % self.value,
154                 'Val: %s' % self.value, '%s' % self.value]])
155             self.emit_cmd_end([ann_class, self.cmd_ann_list()])
156             return
157         if self.cmdstate > 3:
158             self.value += chr(pdata)
159             self.putx([Ann.BIT, ['%c' % pdata]])
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])
189                 self.putf(Ann.FIELD, ['Page index: 0x%s' % page,
190                                       'Page: 0x%s' % page, '0x%s' % page])
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
230             self.putf([Ann.FIELD, ['RPC flag: 0x%02X' % self.flags]])
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
291             self.putx([Ann.BIT, ['Address high nibble: %c' % pdata,
292                  'Addr high 0x%c' % pdata, '0x%c' % pdata]])
293         elif self.cmdstate == 3:
294             self.addr += int(chr(pdata), 16)
295             self.es_field = self.ss
296             self.putx([Ann.BIT, ['Address low nibble: %c' % pdata,
297                  'Addr low 0x%c' % pdata, '0x%c' % pdata]])
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
309             self.putf([Ann.FIELD, ['Value 0x%02X' % self.value,
310                                    '0x%02X' % self.value]])
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
319             self.putx([Ann.BIT, ['Address high nibble: %c' % pdata,
320                   'Addr high 0x%c' % pdata, '0x%c' % pdata]])
321         elif self.cmdstate == 3:
322             self.addr += int(chr(pdata), 16)
323             self.es_field = self.ss
324             self.putx([Ann.BIT, ['Address low nibble: %c' % pdata,
325                  'Addr low 0x%c' % pdata, '0x%c' % pdata]])
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
339                 self.putf([Ann.FIELD, ['Value 0x%04X' % self.value,
340                                        '0x%04X' % self.value]])
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
372                 self.putf([Ann.FIELD, ['Coordinate 0x%04X' % self.coords[i]],
373                                       ['0x%04X' % self.coords[i]]])
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
422             self.putx([Ann.BIT, ['High nibble 0x%s' % pdata, '0x%s' % pdata]])
423         elif self.cmdstate == 5:
424             self.value += int(chr(pdata), 16)
425             self.putx([Ann.BIT, ['Low nibble 0x%s' % pdata, '0x%s' % pdata]])
426             self.es_field = self.es
427             self.putf([Ann.FIELD, ['Value: 0x%02X' % self.value,
428                                    '0x%02X' % self.value]])
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)
440             self.putx([Ann.BIT, ['0x%s' % pdata]])
441             if nibble == 3:
442                 self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value,
443                                        '0x%04X' % self.value]])
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
464                 self.putx([Ann.BIT, ['0x%s' % pdata]])
465             if nibble == 2:
466                 self.value += int(chr(pdata), 16)
467                 self.es_field = self.es
468                 self.putx([Ann.BIT, ['0x%s' % pdata]])
469                 self.putf([Ann.FIELD, ['0x%02X' % self.value]])
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
548             self.putx([Ann.BIT, ['Address high nibble: %c' % pdata,
549                  'Addr high 0x%c' % pdata, '0x%c' % pdata]])
550         elif self.cmdstate == 3:
551             self.addr += int(chr(pdata), 16)
552             self.es_field = self.ss
553             self.putx([Ann.BIT, ['Address low nibble: %c' % pdata,
554                  'Addr low 0x%c' % pdata, '0x%c' % pdata]])
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
566             self.putf([Ann.FIELD, ['Value 0x%02X' % self.value,
567                                    '0x%02X' % self.value]])
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
575             self.putx([Ann.BIT, ['Address high nibble: %c' % pdata,
576                   'Addr high 0x%c' % pdata, '0x%c' % pdata]])
577         elif self.cmdstate == 3:
578             self.addr += int(chr(pdata), 16)
579             self.es_field = self.ss
580             self.putx([Ann.BIT, ['Address low nibble: %c' % pdata,
581                  'Addr low 0x%c' % pdata, '0x%c' % pdata]])
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
595                 self.putf([Ann.FIELD, ['Value 0x%04X' % self.value,
596                                        '0x%04X' % self.value]])
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
605             self.putx([Ann.BIT, ['Address high nibble: %c' % pdata,
606                  'Addr high 0x%c' % pdata, '0x%c' % pdata]])
607         elif self.cmdstate == 3:
608             self.addr += int(chr(pdata), 16)
609             self.es_field = self.ss
610             self.putx([Ann.BIT, ['Address low nibble: %c' % pdata,
611                  'Addr low 0x%c' % pdata, '0x%c' % pdata]])
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
623             self.putf([Ann.FIELD, ['Value 0x%02X' % self.value,
624                                    '0x%02X' % self.value]])
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
633             self.putx([Ann.BIT, ['Address high nibble: %c' % pdata,
634                   'Addr high 0x%c' % pdata, '0x%c' % pdata]])
635         elif self.cmdstate == 3:
636             self.addr += int(chr(pdata), 16)
637             self.es_field = self.ss
638             self.putx([Ann.BIT, ['Address low nibble: %c' % pdata,
639                  'Addr low 0x%c' % pdata, '0x%c' % pdata]])
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
653                 self.putf([Ann.FIELD, ['Value 0x%04X' % self.value,
654                                        '0x%04X' % self.value]])
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
695             if self.state is None:
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