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