]>
Commit | Line | Data |
---|---|---|
6a44fc57 VPP |
1 | ## |
2 | ## This file is part of the libsigrokdecode project. | |
3 | ## | |
4 | ## Copyright (C) 2019 Vesa-Pekka Palmu <vpalmu@depili.fi> | |
5 | ## | |
6 | ## This program is free software; you can redistribute it and/or modify | |
7 | ## it under the terms of the GNU General Public License as published by | |
8 | ## the Free Software Foundation; either version 3 of the License, or | |
9 | ## (at your option) any later version. | |
10 | ## | |
11 | ## This program is distributed in the hope that it will be useful, | |
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ## GNU General Public License for more details. | |
15 | ## | |
16 | ## You should have received a copy of the GNU General Public License | |
17 | ## along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | ## | |
19 | ||
20 | import sigrokdecode as srd | |
21 | from math import ceil | |
22 | from .lists import * | |
23 | ||
24 | L = len(cmds) | |
25 | RX = 0 | |
26 | TX = 1 | |
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) | |
0b137b0d UH |
108 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
109 | 'Addr high 0x%c' % pdata, 'Addr h 0x%c' % pdata]]) | |
6a44fc57 VPP |
110 | elif self.cmdstate == 3: |
111 | self.es_field = self.es | |
112 | self.addr += chr(pdata) | |
113 | self.addr = int(self.addr, 16) | |
0b137b0d UH |
114 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
115 | 'Addr low 0x%c' % pdata, 'Addr l 0x%c' % pdata]]) | |
6a44fc57 VPP |
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']]) | |
0b137b0d UH |
154 | self.putf([Ann.FIELD, ['Value: %s' % self.value, |
155 | 'Val: %s' % self.value, '%s' % self.value]]) | |
6a44fc57 VPP |
156 | self.emit_cmd_end([ann_class, self.cmd_ann_list()]) |
157 | return | |
158 | if self.cmdstate > 3: | |
159 | self.value += chr(pdata) | |
0b137b0d | 160 | self.putx([Ann.BIT, ['%c' % pdata]]) |
6a44fc57 VPP |
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]) | |
0b137b0d UH |
190 | self.putf(Ann.FIELD, ['Page index: 0x%s' % page, |
191 | 'Page: 0x%s' % page, '0x%s' % page]) | |
6a44fc57 VPP |
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 | |
0b137b0d | 231 | self.putf([Ann.FIELD, ['RPC flag: 0x%02X' % self.flags]]) |
6a44fc57 VPP |
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 | |
0b137b0d UH |
292 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
293 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
294 | elif self.cmdstate == 3: |
295 | self.addr += int(chr(pdata), 16) | |
296 | self.es_field = self.ss | |
0b137b0d UH |
297 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
298 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
310 | self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, |
311 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
320 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
321 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
322 | elif self.cmdstate == 3: |
323 | self.addr += int(chr(pdata), 16) | |
324 | self.es_field = self.ss | |
0b137b0d UH |
325 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
326 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
340 | self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, |
341 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
373 | self.putf([Ann.FIELD, ['Coordinate 0x%04X' % self.coords[i]], |
374 | ['0x%04X' % self.coords[i]]]) | |
6a44fc57 VPP |
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 | |
0b137b0d | 423 | self.putx([Ann.BIT, ['High nibble 0x%s' % pdata, '0x%s' % pdata]]) |
6a44fc57 VPP |
424 | elif self.cmdstate == 5: |
425 | self.value += int(chr(pdata), 16) | |
0b137b0d | 426 | self.putx([Ann.BIT, ['Low nibble 0x%s' % pdata, '0x%s' % pdata]]) |
6a44fc57 | 427 | self.es_field = self.es |
0b137b0d UH |
428 | self.putf([Ann.FIELD, ['Value: 0x%02X' % self.value, |
429 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
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) | |
0b137b0d | 441 | self.putx([Ann.BIT, ['0x%s' % pdata]]) |
6a44fc57 | 442 | if nibble == 3: |
0b137b0d UH |
443 | self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, |
444 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d | 465 | self.putx([Ann.BIT, ['0x%s' % pdata]]) |
6a44fc57 VPP |
466 | if nibble == 2: |
467 | self.value += int(chr(pdata), 16) | |
468 | self.es_field = self.es | |
0b137b0d UH |
469 | self.putx([Ann.BIT, ['0x%s' % pdata]]) |
470 | self.putf([Ann.FIELD, ['0x%02X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
549 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
550 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
551 | elif self.cmdstate == 3: |
552 | self.addr += int(chr(pdata), 16) | |
553 | self.es_field = self.ss | |
0b137b0d UH |
554 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
555 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
567 | self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, |
568 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
576 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
577 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
578 | elif self.cmdstate == 3: |
579 | self.addr += int(chr(pdata), 16) | |
580 | self.es_field = self.ss | |
0b137b0d UH |
581 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
582 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
596 | self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, |
597 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
606 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
607 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
608 | elif self.cmdstate == 3: |
609 | self.addr += int(chr(pdata), 16) | |
610 | self.es_field = self.ss | |
0b137b0d UH |
611 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
612 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
624 | self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, |
625 | '0x%02X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
634 | self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, |
635 | 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
636 | elif self.cmdstate == 3: |
637 | self.addr += int(chr(pdata), 16) | |
638 | self.es_field = self.ss | |
0b137b0d UH |
639 | self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, |
640 | 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) | |
6a44fc57 VPP |
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 | |
0b137b0d UH |
654 | self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, |
655 | '0x%04X' % self.value]]) | |
6a44fc57 VPP |
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 | |
0b137b0d | 696 | if self.state is None: |
6a44fc57 VPP |
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 |