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