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
20import sigrokdecode as srd
21from math import ceil
22from .lists import *
23
24L = len(cmds)
25RX = 0
26TX = 1
27
28# Don't forget to keep this in sync with 'cmds' is lists.py.
29class 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
35def cmd_annotation_classes():
36    return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()])
37
38class 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
703