diff options
-rw-r--r-- | decoders/amulet_ascii/__init__.py | 28 | ||||
-rw-r--r-- | decoders/amulet_ascii/lists.py | 73 | ||||
-rw-r--r-- | decoders/amulet_ascii/pd.py | 703 |
3 files changed, 804 insertions, 0 deletions
diff --git a/decoders/amulet_ascii/__init__.py b/decoders/amulet_ascii/__init__.py new file mode 100644 index 0000000..7d2c8c3 --- /dev/null +++ b/decoders/amulet_ascii/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Vesa-Pekka Palmu <vpalmu@depili.fi> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +''' +This decoder stacks on top of the 'uart' PD and decodes the ASCII protocol +for Amulet LCD display controllers. + +Currently the decoder treats both RX and TX the same way, decoding all +message types. +''' + +from .pd import Decoder diff --git a/decoders/amulet_ascii/lists.py b/decoders/amulet_ascii/lists.py new file mode 100644 index 0000000..92e27a9 --- /dev/null +++ b/decoders/amulet_ascii/lists.py @@ -0,0 +1,73 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Vesa-Pekka Palmu <vpalmu@depili.fi> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +from collections import OrderedDict + +# OrderedDict which maps command IDs to their names and descriptions. +cmds = OrderedDict([ + (0xA0, ('PAGE', 'Jump to page')), + (0xD0, ('GBV', 'Get byte variable')), + (0xD1, ('GWV', 'Get word variable')), + (0xD2, ('GSV', 'Get string variable')), + (0xD3, ('GLV', 'Get label variable')), + (0xD4, ('GRPC', 'Get RPC buffer')), + (0xD5, ('SBV', 'Set byte variable')), + (0xD6, ('SWV', 'Set word variable')), + (0xD7, ('SSV', 'Set string variable')), + (0xD8, ('RPC', 'Invoke RPC')), + (0xD9, ('LINE', 'Draw line')), + (0xDA, ('RECT', 'Draw rectangle')), + (0xDB, ('FRECT', 'Draw filled rectangle')), + (0xDC, ('PIXEL', 'Draw pixel')), + (0xDD, ('GBVA', 'Get byte variable array')), + (0xDE, ('GWVA', 'Get word variable array')), + (0xDF, ('SBVA', 'Set byte variable array')), + (0xE0, ('GBVR', 'Get byte variable reply')), + (0xE1, ('GWVR', 'Get word variable reply')), + (0xE2, ('GSVR', 'Get string variable reply')), + (0xE3, ('GLVR', 'Get label variable reply')), + (0xE4, ('GRPCR', 'Get RPC buffer reply')), + (0xE5, ('SBVR', 'Set byte variable reply')), + (0xE6, ('SWVR', 'Set word variable reply')), + (0xE7, ('SSVR', 'Set string variable reply')), + (0xE8, ('RPCR', 'Invoke RPC reply')), + (0xE9, ('LINER', 'Draw line reply')), + (0xEA, ('RECTR', 'Draw rectangle')), + (0xEB, ('FRECTR', 'Draw filled rectangle reply')), + (0xEC, ('PIXELR', 'Draw pixel reply')), + (0xED, ('GBVAR', 'Get byte variable array reply')), + (0xEE, ('GWVAR', 'Get word variable array reply')), + (0xEF, ('SBVAR', 'Set byte variable array reply')), + (0xF0, ('ACK', 'Acknowledgment')), + (0xF1, ('NACK', 'Negative acknowledgment')), + (0xF2, ('SWVA', 'Set word variable array')), + (0xF3, ('SWVAR', 'Set word variable array reply')), + (0xF4, ('GCV', 'Get color variable')), + (0xF5, ('GCVR', 'Get color variable reply')), + (0xF6, ('SCV', 'Set color variable')), + (0xF7, ('SCVR', 'Set color variable reply')), +]) + +cmds_with_high_bytes = [ + 0xA0, # PAGE - Page change + 0xD7, # SVV - Set string variable + 0xE7, # SVVR - Set string variable reply + 0xE2, # GSVR - Get string variable reply + 0xE3, # GLVR - Get label variable reply +] diff --git a/decoders/amulet_ascii/pd.py b/decoders/amulet_ascii/pd.py new file mode 100644 index 0000000..bd8c4d0 --- /dev/null +++ b/decoders/amulet_ascii/pd.py @@ -0,0 +1,703 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Vesa-Pekka Palmu <vpalmu@depili.fi> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sigrokdecode as srd +from math import ceil +from .lists import * + +L = len(cmds) +RX = 0 +TX = 1 +rxtx_channels = ('RX', 'TX') + +# Don't forget to keep this in sync with 'cmds' is lists.py. +class Ann: + PAGE, GBV, GWV, GSV, GLV, GRPC, SBV, SWV, SSV, RPC, LINE, RECT, FRECT, \ + PIXEL, GBVA, GWVA, SBVA, GBVR, GWVR, GSVR, GLVR, GRPCR, SBVR, SWVR, SSVR, \ + RPCR, LINER, RECTR, FRECTR, PIXELR, GBVAR, GWVAR, SBVAR, ACK, NACK, SWVA, \ + SWVAR, GCV, GCVR, SCV, SCVR, BIT, FIELD, WARN = range(L + 3) + +def cmd_annotation_classes(): + return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()]) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'amulet_ascii' + name = 'Amulet ASCII' + longname = 'Amulet LCD ASCII' + desc = 'Amulet Technologies LCD controller ASCII protocol.' + license = 'gplv3+' + inputs = ['uart'] + outputs = [] + tags = ['Display'] + annotations = cmd_annotation_classes() + ( + ('bit', 'Bit'), + ('field', 'Field'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('bits', 'Bits', (L + 0,)), + ('fields', 'Fields', (L + 1,)), + ('commands', 'Commands', tuple(range(len(cmds)))), + ('warnings', 'Warnings', (L + 2,)), + ) + options = ( + {'id': 'ms_chan', 'desc': 'Master -> slave channel', + 'default': rxtx_channels[0], 'values': rxtx_channels}, + {'id': 'sm_chan', 'desc': 'Slave -> master channel', + 'default': rxtx_channels[1], 'values': rxtx_channels}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = None + self.cmdstate = None + + # Build dict mapping command keys to handler functions. Each + # command in 'cmds' (defined in lists.py) has a matching + # handler self.handle_<shortname>. + def get_handler(cmd): + s = 'handle_%s' % cmds[cmd][0].lower().replace('/', '_') + return getattr(self, s) + self.cmd_handlers = dict((cmd, get_handler(cmd)) for cmd in cmds.keys()) + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + # Simplification, most annotations span exactly one SPI byte/packet. + self.put(self.ss, self.es, self.out_ann, data) + + def putf(self, data): + self.put(self.ss_field, self.es_field, self.out_ann, data) + + def putc(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def cmd_ann_list(self): + x, s = cmds[self.state][0], cmds[self.state][1] + return ['Command: %s (%s)' % (s, x), 'Command: %s' % s, + 'Cmd: %s' % s, 'Cmd: %s' % x, x] + + def emit_cmd_byte(self): + self.ss_cmd = self.ss + self.putx([Ann.FIELD, self.cmd_ann_list()]) + + def emit_addr_bytes(self, pdata): + if self.cmdstate == 2: + self.ss_field = self.ss + self.addr = chr(pdata) + self.putx([Ann.BIT, ['Address high nibble: %c' % (pdata), + 'Addr high 0x%c' % (pdata), 'Addr h 0x%c' % (pdata)]]) + elif self.cmdstate == 3: + self.es_field = self.es + self.addr += chr(pdata) + self.addr = int(self.addr, 16) + self.putx([Ann.BIT, ['Address low nibble: %c' % (pdata), + 'Addr low 0x%c' % (pdata), 'Addr l 0x%c' % (pdata)]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + + def emit_cmd_end(self, data): + self.es_cmd = self.es + self.putc(data) + self.state = None + + def handle_read(self, data): + if self.cmdstate == 1: + self.emit_cmd_byte() + self.addr = 0 + elif self.cmdstate == 2: + self.emit_addr_bytes(pdata) + elif self.cmdstate == 3: + self.emit_addr_bytes(pdata) + self.cmdstate += 1 + + def handle_set_common(self, pdata): + if self.cmdstate == 1: + self.addr = 0 + self.emit_addr_bytes(pdata) + + def emit_not_implemented(self, data): + self.es_cmd = self.es + self.putc([Ann.WARN, ['Command not decoded', 'Not decoded']]) + self.emit_cmd_end(data) + + def handle_string(self, pdata, ann_class): + # TODO: unicode / string modifiers... + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = '' + if pdata == 0x00: + # Null terminated string ends. + self.es_field = self.es + self.putx([Ann.BIT, ['NULL']]) + self.putf([Ann.FIELD, ['Value: %s' % (self.value), + 'Val: %s' % (self.value), '%s' % (self.value)]]) + self.emit_cmd_end([ann_class, self.cmd_ann_list()]) + return + if self.cmdstate > 3: + self.value += chr(pdata) + self.putx([Ann.BIT, ['%c' % (pdata)]]) + self.cmdstate += 1 + + # Command handlers + + # Page change 0xA0, 0x02, index_high, index_low, checksum + def handle_page(self, pdata): + if self.cmdstate == 2: + if pdata == 0x02: + self.ss_field = self.ss_cmd + self.es_field = self.es + self.putf([Ann.FIELD, self.cmd_ann_list()]) + self.checksum = 0xA0 + 0x02 + else: + self.putx([Ann.WARN, ['Illegal second byte for page change', + 'Illegal byte']]) + self.state = None + elif self.cmdstate == 3: + self.ss_field = self.ss + self.checksum += pdata + self.page[0] = pdata + elif self.cmdstate == 4: + self.checksum += pdata + self.page[1] = pdata + self.es_field = self.es + if self.page[0] == self.page [1] == 0xFF: + # Soft reset trigger + self.putf(Ann.WARN, ['Soft reset', 'Reset']) + else: + page = chr(self.page[0]) + chr(self.page[1]) + self.putf(Ann.FIELD, ['Page index: 0x%s' % (page), + 'Page: 0x%s' % (page), '0x%s' % (page)]) + elif self.cmdstate == 5: + self.checksum += pdata + if (self.checksum & 0xFF) != 0: + self.putx([Ann.WARN, ['Checksum error', 'Error', 'ERR']]) + else: + self.putx([Ann.FIELD, ['Checksum OK', 'OK']]) + self.emit_cmd_end(Ann.PAGE) + self.cmdstate += 1 + + # Value reads: command byte, address high nibble, address low nibble + + # Get byte value + def handle_gbv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GBV, self.cmd_ann_list()]) + + # Get word value + def handle_gwv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GWV, self.cmd_ann_list()]) + + # Get string value + def handle_gsv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GSV, self.cmd_ann_list()]) + + # Get label value + def handle_glv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GLV, self.cmd_ann_list()]) + + # Get RPC buffer + def handle_grpc(self, pdata): + if self.cmdstate == 2: + self.ss_field = self.ss + self.flags = int(chr(pdata), 16) << 4 + elif self.cmdstate == 3: + self.flags += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['RPC flag: 0x%02X' % (self.flags)]]) + self.emit_cmd_end([Ann.GRPC, self.cmd_ann_list()]) + + # Get byte value array + def handle_gbva(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GBVA, self.cmd_ann_list()]) + + # Get word value array + def handle_gwva(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GWVA, self.cmd_ann_list()]) + + # Get color variable + def handle_gcv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GCV, self.cmd_ann_list()]) + + # Value setters: command byte, address high nibble, address low nibble, data bytes + + # Set byte value data = high nibble, low nibble + def handle_sbv(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = chr(pdata) + elif self.cmdstate == 5: + self.value += chr(pdata) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, + 'Val: 0x%s' % self.value, '0x%s' % self.value]]) + self.emit_cmd_end([Ann.SBV, self.cmd_ann_list()]) + self.cmdstate += 1 + + # Set word value, msb high, msb low, lsb high, lsb low + def handle_swv(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate > 3: + nibble = self.cmdstate - 4 + if nibble == 0: + self.ss_field = self.ss + self.value = 0 + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, + 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) + self.emit_cmd_end([Ann.SWV, self.cmd_ann_list()]) + return + self.cmdstate += 1 + + # Set string value, null terminated utf8 strings + def handle_ssv(self, pdata): + self.handle_string(pdata, Ann.SSV) + + # Set byte value array + def handle_sbva(self, pdata): + nibble = (self.cmdstate - 3) % 2 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % (pdata), + 'Addr high 0x%c' % (pdata), '0x%c' % (pdata)]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % (pdata), + 'Addr low 0x%c' % (pdata), '0x%c' % (pdata)]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + elif stage == 2: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SBVA, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + else: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%02X' % (self.value), + '0x%02X' % (self.value)]]) + self.cmdstate += 1 + + # Set word value array + def handle_swva(self, pdata): + nibble = (self.cmdstate - 3) % 4 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % (pdata), + 'Addr high 0x%c' % (pdata), '0x%c' % (pdata)]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % (pdata), + 'Addr low 0x%c' % (pdata), '0x%c' % (pdata)]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + self.value = 0 + else: + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SWVA, self.cmd_ann_list()]) + return + self.ss_field = self.ss + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%04X' % (self.value), + '0x%04X' % (self.value)]]) + self.cmdstate += 1 + + # Set color variable + def handle_scv(self, pdata): + if self.cmdstate == 8: + self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) + self.cmdstate += 1 + + # RPC trigger + def handle_rpc(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.RPC, self.cmd_ann_list()]) + + # Drawing + + # Decode pair of (x,y) 16bit coordinates + def decode_coords(self, pdata): + if self.cmdstate == 1: + self.coords[0] = 0 + self.coords[1] = 0 + self.coords[2] = 0 + self.coords[3] = 0 + if self.cmdstate < 18: + # Coordinates + nibble = (self.cmdstate - 1) % 4 + i = (self.cmdstate - 1) / 4 + self.coords[i] += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + self.ss_field = self.ss + elif nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Coordinate 0x%04X' % (self.coords[i])], + ['0x%04X' % (self.coords[i])]]) + + # TODO: There are actually two protocol revisions for drawing. + # Both use 4 bytes for 16bit x and y pairs for start and end. + # The older follows this by a pattern selector and then line weight. + # Newer version has 6 bytes for 8bit RGB color... + + # Draw line + def handle_line(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.LINE, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + # Draw rectange + def handle_rect(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.RECT, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + # Draw filled rectangle + def handle_frect(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.FRECT, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Fill pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + # Draw pixel + def handle_pixel(self, pdata): + self.es_cmd = self.es + self.putc([Ann.WARN, ['Draw pixel documentation is missing.', 'Undocumented']]) + self.state = None + + # Replies + def handle_gbvr(self, pdata): + self.emit_add_bytes(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = int(chr(pdata), 16) << 4 + self.putx([Ann.BIT, ['High nibble 0x%s' % (pdata), '0x%s' % (pdata)]]) + elif self.cmdstate == 5: + self.value += int(chr(pdata), 16) + self.putx([Ann.BIT, ['Low nibble 0x%s' % (pdata), '0x%s' % (pdata)]]) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%02X' % (self.value), + '0x%02X' % (self.value)]]) + self.emit_cmd_end([Ann.GBVR, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_gwvr(self, pdata): + self.emit_add_bytes(pdata) + if self.cmdstate > 3: + nibble = self.cmdstate - 3 + if nibble == 0: + self.value = 0 + self.ss_field = self.ss + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + self.putx([Ann.BIT, ['0x%s' % (pdata)]]) + if nibble == 3: + self.putf([Ann.FIELD, ['Value: 0x%04x' % (self.value), + '0x%04X' % (self.value)]]) + self.es_cmd = self.ss + self.emit_cmd_end([Ann.GWVR, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_gsvr(self, pdata): + self.handle_string(pdata, Ann.GSVR) + + def handle_glvr(self, pdata): + self.handle_string(pdata, Ann.GLVR) + + def handle_grpcr(self, pdata): + self.handle_addr(pdata) + if self.cmdstate > 3: + nibble = (self.cmdstate - 3) % 2 + if nibble == 0: + if pdata == 0x00: + self.emit_cmd_end([Ann.GRPCR, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['0x%s' % (pdata)]]) + if nibble == 2: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putx([Ann.BIT, ['0x%s' % (pdata)]]) + self.putf([Ann.FIELD, ['0x%02X' % (self.value)]]) + self.cmdstate += 1 + + def handle_sbvr(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = chr(pdata) + elif self.cmdstate == 5: + self.value += chr(pdata) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, + 'Val: 0x%s' % self.value, '0x%s' % self.value]]) + self.emit_cmd_end([Ann.SBVR, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_swvr(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = (pdata - 0x30) << 4 + elif self.cmdstate == 5: + self.value += (pdata - 0x30) + self.value = self.value << 8 + elif self.cmdstate == 6: + self.value += (pdata - 0x30) << 4 + elif self.cmdstate == 7: + self.value += (pdata - 0x30) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, + 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) + self.emit_cmd_end([Ann.SWVR, self.cmd_ann_list()]) + self.state = None + self.cmdstate += 1 + + def handle_ssvr(self, pdata): + self.handle_string(pdata, Ann.SSVR) + + def handle_rpcr(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.RPCR, self.cmd_ann_list()]) + + def handle_liner(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.LINER, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + def handle_rectr(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.RECTR, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + def handle_frectr(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.FRECTR, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + def handle_pixelr(self, pdata): + self.es_cmd = self.es + self.putc([Ann.WARN,['Draw pixel documentation is missing.', 'Undocumented']]) + self.state = None + + def handle_gbvar(self, pdata): + nibble = (self.cmdstate - 3) % 2 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % (pdata), + 'Addr high 0x%c' % (pdata), '0x%c' % (pdata)]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % (pdata), + 'Addr low 0x%c' % (pdata), '0x%c' % (pdata)]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + elif stage == 2: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.GBVAR, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + else: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%02X' % (self.value), + '0x%02X' % (self.value)]]) + self.cmdstate += 1 + + def handle_gwvar(self, pdata): + nibble = (self.cmdstate - 3) % 4 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % (pdata), + 'Addr high 0x%c' % (pdata), '0x%c' % (pdata)]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % (pdata), + 'Addr low 0x%c' % (pdata), '0x%c' % (pdata)]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + self.value = 0 + else: + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.GWVAR, self.cmd_ann_list()]) + return + self.ss_field = self.ss + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%04X' % (self.value), + '0x%04X' % (self.value)]]) + self.cmdstate += 1 + + # Get byte variable array reply + def handle_sbvar(self, pdata): + nibble = (self.cmdstate - 3) % 2 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % (pdata), + 'Addr high 0x%c' % (pdata), '0x%c' % (pdata)]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % (pdata), + 'Addr low 0x%c' % (pdata), '0x%c' % (pdata)]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + elif stage == 2: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SBVAR, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + else: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%02X' % (self.value), + '0x%02X' % (self.value)]]) + self.cmdstate += 1 + + # Set word variable array reply + def handle_swvar(self, pdata): + nibble = (self.cmdstate - 3) % 4 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % (pdata), + 'Addr high 0x%c' % (pdata), '0x%c' % (pdata)]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % (pdata), + 'Addr low 0x%c' % (pdata), '0x%c' % (pdata)]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + self.value = 0 + else: + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SWVAR, self.cmd_ann_list()]) + return + self.ss_field = self.ss + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%04X' % (self.value), + '0x%04X' % (self.value)]]) + self.cmdstate += 1 + + def handle_gcvr(self, pdata): + if self.cmdstate == 8: + self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_scvr(self, pdata): + if self.cmdstate == 8: + self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) + self.cmdstate += 1 + + # ACK & NACK + + def handle_ack(self, pdata): + self.putx([Ann.ACK, self.cmd_ann_list()]) + self.state = None + + def handle_nack(self, pdata): + self.putx([Ann.NACK, self.cmd_ann_list()]) + self.state = None + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + self.ss, self.es = ss, es + + if ptype != 'DATA': + return + + # Handle commands. + try: + abort_current = (0xD0 <= pdata[0] <= 0xF7) and \ + (not (self.state in cmds_with_high_bytes)) and \ + self.state != None + if abort_current: + self.putx([Ann.WARN, ['Command aborted by invalid byte', 'Abort']]) + self.state = pdata[0] + self.emit_cmd_byte() + self.cmdstate = 1 + if (self.state is None): + self.state = pdata[0] + self.emit_cmd_byte() + self.cmdstate = 1 + self.cmd_handlers[self.state](pdata[0]) + except KeyError: + self.putx([Ann.WARN, ['Unknown command: 0x%02x' % pdata[0]]]) + self.state = None |