]> sigrok.org Git - libsigrokdecode.git/blame - decoders/ieee488/pd.py
ieee488: introduce unified IEEE-488 decoder (supports GPIB and IEC)
[libsigrokdecode.git] / decoders / ieee488 / pd.py
CommitLineData
92ee3b28
GS
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2016 Rudolf Reuter <reuterru@arcor.de>
5## Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
6## Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
7##
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, see <http://www.gnu.org/licenses/>.
20##
21
22# This file was created from earlier implementations of the 'gpib' and
23# the 'iec' protocol decoders. It combines the parallel and the serial
24# transmission variants in a single instance with optional inputs for
25# maximum code re-use.
26
27# TODO
28# - Extend annotations for improved usability.
29# - Keep talkers' data streams on separate annotation rows? Is this useful
30# here at the GPIB level, or shall stacked decoders dispatch these? May
31# depend on how often captures get inspected which involve multiple peers.
32# - Make serial bit annotations optional? Could slow down interactive
33# exploration for long captures (see USB).
34# - Move the inlined Commodore IEC peripherals support to a stacked decoder
35# when more peripherals get added.
36# - SCPI over GPIB may "represent somewhat naturally" here already when
37# text lines are a single run of data at the GPIB layer (each line between
38# the address spec and either EOI or ATN). So a stacked SCPI decoder may
39# only become necessary when the text lines' content shall get inspected.
40
41import sigrokdecode as srd
42from common.srdhelper import bitpack
43
44'''
45OUTPUT_PYTHON format for stacked decoders:
46
47General packet format:
48[<ptype>, <addr>, <pdata>]
49
50This is the list of <ptype>s and their respective <pdata> values:
51
52Raw bits and bytes at the physical transport level:
53 - 'IEC_BIT': <addr> is not applicable, <pdata> is the transport's bit value.
54 - 'GPIB_RAW': <addr> is not applicable, <pdata> is the transport's
55 byte value. Data bytes are in the 0x00-0xff range, command/address
56 bytes are in the 0x100-0x1ff range.
57
58GPIB level byte fields (commands, addresses, pieces of data):
59 - 'COMMAND': <addr> is not applicable, <pdata> is the command's byte value.
60 - 'LISTEN': <addr> is the listener address (0-30), <pdata> is the raw
61 byte value (including the 0x20 offset).
62 - 'TALK': <addr> is the talker address (0-30), <pdata> is the raw byte
63 value (including the 0x40 offset).
64 - 'SECONDARY': <addr> is the secondary address (0-31), <pdata> is the
65 raw byte value (including the 0x60 offset).
66 - 'MSB_SET': <addr> as well as <pdata> are the raw byte value (including
67 the 0x80 offset). This usually does not happen for GPIB bytes with ATN
68 active, but was observed with the IEC bus and Commodore floppy drives,
69 when addressing channels within the device.
70 - 'DATA_BYTE': <addr> is the talker address (when available), <pdata>
71 is the raw data byte (transport layer, ATN inactive).
72
73Extracted payload information (peers and their communicated data):
74 - 'TALK_LISTEN': <addr> is the current talker, <pdata> is the list of
75 current listeners. These updates for the current "connected peers"
76 are sent when the set of peers changes, i.e. after talkers/listeners
77 got selected or deselected. Of course the data only covers what could
78 be gathered from the input data. Some controllers may not explicitly
79 address themselves, or captures may not include an early setup phase.
80 - 'TALKER_BYTES': <addr> is the talker address (when available), <pdata>
81 is the accumulated byte sequence between addressing a talker and EOI,
82 or the next command/address.
83 - 'TALKER_TEXT': <addr> is the talker address (when available), <pdata>
84 is the accumulated text sequence between addressing a talker and EOI,
85 or the next command/address.
86'''
87
88class ChannelError(Exception):
89 pass
90
91def _format_ann_texts(fmts, **args):
92 if not fmts:
93 return None
94 return [fmt.format(**args) for fmt in fmts]
95
96_cmd_table = {
97 # Command codes in the 0x00-0x1f range.
98 0x01: ['Go To Local', 'GTL'],
99 0x04: ['Selected Device Clear', 'SDC'],
100 0x05: ['Parallel Poll Configure', 'PPC'],
101 0x08: ['Global Execute Trigger', 'GET'],
102 0x09: ['Take Control', 'TCT'],
103 0x11: ['Local Lock Out', 'LLO'],
104 0x14: ['Device Clear', 'DCL'],
105 0x15: ['Parallel Poll Unconfigure', 'PPU'],
106 0x18: ['Serial Poll Enable', 'SPE'],
107 0x19: ['Serial Poll Disable', 'SPD'],
108 # Unknown type of command.
109 None: ['Unknown command 0x{cmd:02x}', 'command 0x{cmd:02x}', 'cmd {cmd:02x}', 'C{cmd_ord:c}'],
110 # Special listener/talker "addresses" (deselecting previous peers).
111 0x3f: ['Unlisten', 'UNL'],
112 0x5f: ['Untalk', 'UNT'],
113}
114
115def _is_command(b):
116 # Returns a tuple of booleans (or None when not applicable) whether
117 # the raw GPIB byte is: a command, an un-listen, an un-talk command.
118 if b in range(0x00, 0x20):
119 return True, None, None
120 if b in range(0x20, 0x40) and (b & 0x1f) == 31:
121 return True, True, False
122 if b in range(0x40, 0x60) and (b & 0x1f) == 31:
123 return True, False, True
124 return False, None, None
125
126def _is_listen_addr(b):
127 if b in range(0x20, 0x40):
128 return b & 0x1f
129 return None
130
131def _is_talk_addr(b):
132 if b in range(0x40, 0x60):
133 return b & 0x1f
134 return None
135
136def _is_secondary_addr(b):
137 if b in range(0x60, 0x80):
138 return b & 0x1f
139 return None
140
141def _is_msb_set(b):
142 if b & 0x80:
143 return b
144 return None
145
146def _get_raw_byte(b, atn):
147 # "Decorate" raw byte values for stacked decoders.
148 raw_byte = b
149 if atn:
150 raw_byte |= 0x100
151 return raw_byte
152
153def _get_raw_text(b, atn):
154 return ['{leader}{data:02x}'.format(leader = '/' if atn else '', data = b)]
155
156def _get_command_texts(b):
157 fmts = _cmd_table.get(b, None)
158 known = fmts is not None
159 if not fmts:
160 fmts = _cmd_table.get(None, None)
161 if not fmts:
162 return known, None
163 return known, _format_ann_texts(fmts, cmd = b, cmd_ord = ord('0') + b)
164
165def _get_address_texts(b):
166 laddr = _is_listen_addr(b)
167 taddr = _is_talk_addr(b)
168 saddr = _is_secondary_addr(b)
169 msb = _is_msb_set(b)
170 fmts = None
171 if laddr is not None:
172 fmts = ['Listen {addr:d}', 'L {addr:d}', 'L{addr_ord:c}']
173 addr = laddr
174 elif taddr is not None:
175 fmts = ['Talk {addr:d}', 'T {addr:d}', 'T{addr_ord:c}']
176 addr = taddr
177 elif saddr is not None:
178 fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}']
179 addr = saddr
180 elif msb is not None: # For IEC bus compat.
181 fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}']
182 addr = msb
183 return _format_ann_texts(fmts, addr = addr, addr_ord = ord('0') + addr)
184
185def _get_data_text(b):
186 # TODO Move the table of ASCII control characters to a common location?
187 # TODO Move the "printable with escapes" logic to a common helper?
188 _control_codes = {
189 0x00: 'NUL',
190 0x01: 'SOH',
191 0x02: 'STX',
192 0x03: 'ETX',
193 0x04: 'EOT',
194 0x05: 'ENQ',
195 0x06: 'ACK',
196 0x07: 'BEL',
197 0x08: 'BS',
198 0x09: 'TAB',
199 0x0a: 'LF',
200 0x0b: 'VT',
201 0x0c: 'FF',
202 0x0d: 'CR',
203 0x0e: 'SO',
204 0x0f: 'SI',
205 0x10: 'DLE',
206 0x11: 'DC1',
207 0x12: 'DC2',
208 0x13: 'DC3',
209 0x14: 'DC4',
210 0x15: 'NAK',
211 0x16: 'SYN',
212 0x17: 'ETB',
213 0x18: 'CAN',
214 0x19: 'EM',
215 0x1a: 'SUB',
216 0x1b: 'ESC',
217 0x1c: 'FS',
218 0x1d: 'GS',
219 0x1e: 'RS',
220 0x1f: 'US',
221 }
222 # Yes, exclude 0x7f (DEL) here. It's considered non-printable.
223 if b in range(0x20, 0x7f) and b not in ('[', ']'):
224 return '{:s}'.format(chr(b))
225 elif b in _control_codes:
226 return '[{:s}]'.format(_control_codes[b])
227 # Use a compact yet readable and unambigous presentation for bytes
228 # which contain non-printables. The format that is used here is
229 # compatible with 93xx EEPROM and UART decoders.
230 return '[{:02x}]'.format(b)
231
232(
233 PIN_DIO1, PIN_DIO2, PIN_DIO3, PIN_DIO4,
234 PIN_DIO5, PIN_DIO6, PIN_DIO7, PIN_DIO8,
235 PIN_EOI, PIN_DAV, PIN_NRFD, PIN_NDAC,
236 PIN_IFC, PIN_SRQ, PIN_ATN, PIN_REN,
237 PIN_CLK,
238) = range(17)
239PIN_DATA = PIN_DIO1
240
241(
242 ANN_RAW_BIT, ANN_RAW_BYTE,
243 ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA,
244 ANN_EOI,
245 ANN_TEXT,
246 # TODO Want to provide one annotation class per talker address (0-30)?
247 ANN_IEC_PERIPH,
248 ANN_WARN,
249) = range(11)
250
251(
252 BIN_RAW,
253 BIN_DATA,
254 # TODO Want to provide one binary annotation class per talker address (0-30)?
255) = range(2)
256
257class Decoder(srd.Decoder):
258 api_version = 3
259 id = 'ieee488'
260 name = 'IEEE-488'
261 longname = 'General Purpose Interface Bus'
262 desc = 'IEEE-488 General Purpose Interface Bus (GPIB/HPIB or IEC).'
263 license = 'gplv2+'
264 inputs = ['logic']
265 outputs = ['ieee488']
266 tags = ['PC', 'Retro computing']
267 channels = (
268 {'id': 'dio1' , 'name': 'DIO1/DATA',
269 'desc': 'Data I/O bit 1, or serial data'},
270 )
271 optional_channels = (
272 {'id': 'dio2' , 'name': 'DIO2', 'desc': 'Data I/O bit 2'},
273 {'id': 'dio3' , 'name': 'DIO3', 'desc': 'Data I/O bit 3'},
274 {'id': 'dio4' , 'name': 'DIO4', 'desc': 'Data I/O bit 4'},
275 {'id': 'dio5' , 'name': 'DIO5', 'desc': 'Data I/O bit 5'},
276 {'id': 'dio6' , 'name': 'DIO6', 'desc': 'Data I/O bit 6'},
277 {'id': 'dio7' , 'name': 'DIO7', 'desc': 'Data I/O bit 7'},
278 {'id': 'dio8' , 'name': 'DIO8', 'desc': 'Data I/O bit 8'},
279 {'id': 'eoi', 'name': 'EOI', 'desc': 'End or identify'},
280 {'id': 'dav', 'name': 'DAV', 'desc': 'Data valid'},
281 {'id': 'nrfd', 'name': 'NRFD', 'desc': 'Not ready for data'},
282 {'id': 'ndac', 'name': 'NDAC', 'desc': 'Not data accepted'},
283 {'id': 'ifc', 'name': 'IFC', 'desc': 'Interface clear'},
284 {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'},
285 {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'},
286 {'id': 'ren', 'name': 'REN', 'desc': 'Remote enable'},
287 {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock'},
288 )
289 options = (
290 {'id': 'iec_periph', 'desc': 'Decode Commodore IEC bus peripherals details',
291 'default': 'no', 'values': ('no', 'yes')},
292 )
293 annotations = (
294 ('bit', 'IEC bit'),
295 ('raw', 'Raw byte'),
296 ('cmd', 'Command'),
297 ('laddr', 'Listener address'),
298 ('taddr', 'Talker address'),
299 ('saddr', 'Secondary address'),
300 ('data', 'Data byte'),
301 ('eoi', 'EOI'),
302 ('text', 'Talker text'),
303 ('periph', 'IEC bus peripherals'),
304 ('warn', 'Warning'),
305 )
306 annotation_rows = (
307 ('bits', 'IEC bits', (ANN_RAW_BIT,)),
308 ('raws', 'Raw bytes', (ANN_RAW_BYTE,)),
309 ('gpib', 'Commands/data', (ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA,)),
310 ('eois', 'EOI', (ANN_EOI,)),
311 ('texts', 'Talker texts', (ANN_TEXT,)),
312 ('periphs', 'IEC peripherals', (ANN_IEC_PERIPH,)),
313 ('warns', 'Warnings', (ANN_WARN,)),
314 )
315 binary = (
316 ('raw', 'Raw bytes'),
317 ('data', 'Talker bytes'),
318 )
319
320 def __init__(self):
321 self.reset()
322
323 def reset(self):
324 self.curr_raw = None
325 self.curr_atn = None
326 self.curr_eoi = None
327 self.latch_atn = None
328 self.latch_eoi = None
329 self.accu_bytes = []
330 self.accu_text = []
331 self.ss_raw = None
332 self.es_raw = None
333 self.ss_eoi = None
334 self.es_eoi = None
335 self.ss_text = None
336 self.es_text = None
337 self.last_talker = None
338 self.last_listener = []
339 self.last_iec_addr = None
340 self.last_iec_sec = None
341
342 def start(self):
343 self.out_ann = self.register(srd.OUTPUT_ANN)
344 self.out_bin = self.register(srd.OUTPUT_BINARY)
345 self.out_python = self.register(srd.OUTPUT_PYTHON)
346
347 def putg(self, ss, es, data):
348 self.put(ss, es, self.out_ann, data)
349
350 def putbin(self, ss, es, data):
351 self.put(ss, es, self.out_bin, data)
352
353 def putpy(self, ss, es, ptype, addr, pdata):
354 self.put(ss, es, self.out_python, [ptype, addr, pdata])
355
356 def emit_eoi_ann(self, ss, es):
357 self.putg(ss, es, [ANN_EOI, ['EOI']])
358
359 def emit_bin_ann(self, ss, es, ann_cls, data):
360 self.putbin(ss, es, [ann_cls, bytes(data)])
361
362 def emit_data_ann(self, ss, es, ann_cls, data):
363 self.putg(ss, es, [ann_cls, data])
364
365 def emit_warn_ann(self, ss, es, data):
366 self.putg(ss, es, [ANN_WARN, data])
367
368 def flush_bytes_text_accu(self):
369 if self.accu_bytes and self.ss_text is not None and self.es_text is not None:
370 self.emit_bin_ann(self.ss_text, self.es_text, BIN_DATA, bytearray(self.accu_bytes))
371 self.putpy(self.ss_text, self.es_text, 'TALKER_BYTES', self.last_talker, bytearray(self.accu_bytes))
372 self.accu_bytes = []
373 if self.accu_text and self.ss_text is not None and self.es_text is not None:
374 text = ''.join(self.accu_text)
375 self.emit_data_ann(self.ss_text, self.es_text, ANN_TEXT, [text])
376 self.putpy(self.ss_text, self.es_text, 'TALKER_TEXT', self.last_talker, text)
377 self.accu_text = []
378 self.ss_text = self.es_text = None
379
380 def handle_ifc_change(self, ifc):
381 # Track IFC line for parallel input.
382 # Assertion of IFC de-selects all talkers and listeners.
383 if ifc:
384 self.last_talker = None
385 self.last_listener = []
386
387 def handle_eoi_change(self, eoi):
388 # Track EOI line for parallel and serial input.
389 if eoi:
390 self.ss_eoi = self.samplenum
391 self.curr_eoi = eoi
392 else:
393 self.es_eoi = self.samplenum
394 if self.ss_eoi and self.latch_eoi:
395 self.emit_eoi_ann(self.ss_eoi, self.es_eoi)
396 self.es_text = self.es_eoi
397 self.flush_bytes_text_accu()
398 self.ss_eoi = self.es_eoi = None
399 self.curr_eoi = None
400
401 def handle_atn_change(self, atn):
402 # Track ATN line for parallel and serial input.
403 self.curr_atn = atn
404 if atn:
405 self.flush_bytes_text_accu()
406
407 def handle_iec_periph(self, ss, es, addr, sec, data):
408 # The annotation is optional.
409 if self.options['iec_periph'] != 'yes':
410 return
411 # Void internal state.
412 if addr is None and sec is None and data is None:
413 self.last_iec_addr = None
414 self.last_iec_sec = None
415 return
416 # Grab and evaluate new input.
417 _iec_addr_names = {
418 # TODO Add more items here. See the "Device numbering" section
419 # of the https://en.wikipedia.org/wiki/Commodore_bus page.
420 8: 'Disk 0',
421 9: 'Disk 1',
422 }
423 _iec_disk_range = range(8, 16)
424 if addr is not None:
425 self.last_iec_addr = addr
426 name = _iec_addr_names.get(addr, None)
427 if name:
428 self.emit_data_ann(ss, es, ANN_IEC_PERIPH, [name])
429 addr = self.last_iec_addr # Simplify subsequent logic.
430 if sec is not None:
431 # BEWARE! The secondary address is a full byte and includes
432 # the 0x60 offset, to also work when the MSB was set.
433 self.last_iec_sec = sec
434 subcmd, channel = sec & 0xf0, sec & 0x0f
435 channel_ord = ord('0') + channel
436 if addr is not None and addr in _iec_disk_range:
437 subcmd_fmts = {
438 0x60: ['Reopen {ch:d}', 'Re {ch:d}', 'R{ch_ord:c}'],
439 0xe0: ['Close {ch:d}', 'Cl {ch:d}', 'C{ch_ord:c}'],
440 0xf0: ['Open {ch:d}', 'Op {ch:d}', 'O{ch_ord:c}'],
441 }.get(subcmd, None)
442 if subcmd_fmts:
443 texts = _format_ann_texts(subcmd_fmts, ch = channel, ch_ord = channel_ord)
444 self.emit_data_ann(ss, es, ANN_IEC_PERIPH, texts)
445 sec = self.last_iec_sec # Simplify subsequent logic.
446 if data is not None:
447 if addr is None or sec is None:
448 return
449 # TODO Process data depending on peripheral type and channel?
450
451 def handle_data_byte(self):
452 b = self.curr_raw
453 texts = _get_raw_text(b, self.curr_atn)
454 self.emit_data_ann(self.ss_raw, self.es_raw, ANN_RAW_BYTE, texts)
455 self.emit_bin_ann(self.ss_raw, self.es_raw, BIN_RAW, b.to_bytes(1, byteorder='big'))
456 self.putpy(self.ss_raw, self.es_raw, 'GPIB_RAW', None, _get_raw_byte(b, self.curr_atn))
457 if self.curr_atn:
458 ann_cls = None
459 upd_iec = False,
460 py_type = None
461 py_peers = False
462 is_cmd, is_unl, is_unt = _is_command(b)
463 laddr = _is_listen_addr(b)
464 taddr = _is_talk_addr(b)
465 saddr = _is_secondary_addr(b)
466 msb = _is_msb_set(b)
467 if is_cmd:
468 known, texts = _get_command_texts(b)
469 if not known:
470 warn_texts = ['Unknown GPIB command', 'unknown', 'UNK']
471 self.emit_warn_ann(self.ss_raw, self.es_raw, warn_texts)
472 ann_cls = ANN_CMD
473 py_type, py_addr = 'COMMAND', None
474 if is_unl:
475 self.last_listener = []
476 py_peers = True
477 if is_unt:
478 self.last_talker = None
479 py_peers = True
480 if is_unl or is_unt:
481 upd_iec = True, None, None, None
482 elif laddr is not None:
483 addr = laddr
484 texts = _get_address_texts(b)
485 ann_cls = ANN_LADDR
486 py_type, py_addr = 'LISTEN', addr
487 if addr == self.last_talker:
488 self.last_talker = None
489 self.last_listener.append(addr)
490 upd_iec = True, addr, None, None
491 py_peers = True
492 elif taddr is not None:
493 addr = taddr
494 texts = _get_address_texts(b)
495 ann_cls = ANN_TADDR
496 py_type, py_addr = 'TALK', addr
497 if addr in self.last_listener:
498 self.last_listener.remove(addr)
499 self.last_talker = addr
500 upd_iec = True, addr, None, None
501 py_peers = True
502 elif saddr is not None:
503 addr = saddr
504 texts = _get_address_texts(b)
505 ann_cls = ANN_SADDR
506 upd_iec = True, None, b, None
507 py_type, py_addr = 'SECONDARY', addr
508 elif msb is not None:
509 # These are not really "secondary addresses", but they
510 # are used by the Commodore IEC bus (floppy channels).
511 texts = _get_address_texts(b)
512 ann_cls = ANN_SADDR
513 upd_iec = True, None, b, None
514 py_type, py_addr = 'MSB_SET', b
515 if ann_cls is not None and texts is not None:
516 self.emit_data_ann(self.ss_raw, self.es_raw, ann_cls, texts)
517 if upd_iec[0]:
518 self.handle_iec_periph(self.ss_raw, self.es_raw, upd_iec[1], upd_iec[2], upd_iec[3])
519 if py_type:
520 self.putpy(self.ss_raw, self.es_raw, py_type, py_addr, b)
521 if py_peers:
522 self.last_listener.sort()
523 self.putpy(self.ss_raw, self.es_raw, 'TALK_LISTEN', self.last_talker, self.last_listener)
524 else:
525 self.accu_bytes.append(b)
526 text = _get_data_text(b)
527 if not self.accu_text:
528 self.ss_text = self.ss_raw
529 self.accu_text.append(text)
530 self.es_text = self.es_raw
531 self.emit_data_ann(self.ss_raw, self.es_raw, ANN_DATA, [text])
532 self.handle_iec_periph(self.ss_raw, self.es_raw, None, None, b)
533 self.putpy(self.ss_raw, self.es_raw, 'DATA_BYTE', self.last_talker, b)
534
535 def handle_dav_change(self, dav, data):
536 if dav:
537 # Data availability starts when the flag goes active.
538 self.ss_raw = self.samplenum
539 self.curr_raw = bitpack(data)
540 self.latch_atn = self.curr_atn
541 self.latch_eoi = self.curr_eoi
542 return
543 # Data availability ends when the flag goes inactive. Handle the
544 # previously captured data byte according to associated flags.
545 self.es_raw = self.samplenum
546 self.handle_data_byte()
547 self.ss_raw = self.es_raw = None
548 self.curr_raw = None
549
550 def inject_dav_phase(self, ss, es, data):
551 # Inspection of serial input has resulted in one raw byte which
552 # spans a given period of time. Pretend we had seen a DAV active
553 # phase, to re-use code for the parallel transmission.
554 self.ss_raw = ss
555 self.curr_raw = bitpack(data)
556 self.latch_atn = self.curr_atn
557 self.latch_eoi = self.curr_eoi
558 self.es_raw = es
559 self.handle_data_byte()
560 self.ss_raw = self.es_raw = None
561 self.curr_raw = None
562
563 def invert_pins(self, pins):
564 # All lines (including data bits!) are low active and thus need
565 # to get inverted to receive their logical state (high active,
566 # regular data bit values). Cope with inputs being optional.
567 return [1 - p if p in (0, 1) else p for p in pins]
568
569 def decode_serial(self, has_clk, has_data_1, has_atn, has_srq):
570 if not has_clk or not has_data_1 or not has_atn:
571 raise ChannelError('IEC bus needs at least ATN and serial CLK and DATA.')
572
573 # This is a rephrased version of decoders/iec/pd.py:decode().
574 # SRQ was not used there either. Magic numbers were eliminated.
575 (
576 STEP_WAIT_READY_TO_SEND,
577 STEP_WAIT_READY_FOR_DATA,
578 STEP_PREP_DATA_TEST_EOI,
579 STEP_CLOCK_DATA_BITS,
580 ) = range(4)
581 step_wait_conds = (
582 [{PIN_ATN: 'f'}, {PIN_DATA: 'l', PIN_CLK: 'h'}],
583 [{PIN_ATN: 'f'}, {PIN_DATA: 'h', PIN_CLK: 'h'}, {PIN_CLK: 'l'}],
584 [{PIN_ATN: 'f'}, {PIN_DATA: 'f'}, {PIN_CLK: 'l'}],
585 [{PIN_ATN: 'f'}, {PIN_CLK: 'e'}],
586 )
587 step = STEP_WAIT_READY_TO_SEND
588 bits = []
589
590 while True:
591
592 # Sample input pin values. Keep DATA/CLK in verbatim form to
593 # re-use 'iec' decoder logic. Turn ATN to positive logic for
594 # easier processing. The data bits get handled during byte
595 # accumulation.
596 pins = self.wait(step_wait_conds[step])
597 data, clk = pins[PIN_DATA], pins[PIN_CLK]
598 atn, = self.invert_pins([pins[PIN_ATN]])
599
600 if self.matched[0]:
601 # Falling edge on ATN, reset step.
602 step = STEP_WAIT_READY_TO_SEND
603
604 if step == STEP_WAIT_READY_TO_SEND:
605 # Don't use self.matched[1] here since we might come from
606 # a step with different conds due to the code above.
607 if data == 0 and clk == 1:
608 # Rising edge on CLK while DATA is low: Ready to send.
609 step = STEP_WAIT_READY_FOR_DATA
610 elif step == STEP_WAIT_READY_FOR_DATA:
611 if data == 1 and clk == 1:
612 # Rising edge on DATA while CLK is high: Ready for data.
613 ss_byte = self.samplenum
614 self.handle_atn_change(atn)
615 if self.curr_eoi:
616 self.handle_eoi_change(False)
617 bits = []
618 step = STEP_PREP_DATA_TEST_EOI
619 elif clk == 0:
620 # CLK low again, transfer aborted.
621 step = STEP_WAIT_READY_TO_SEND
622 elif step == STEP_PREP_DATA_TEST_EOI:
623 if data == 0 and clk == 1:
624 # DATA goes low while CLK is still high, EOI confirmed.
625 self.handle_eoi_change(True)
626 elif clk == 0:
627 step = STEP_CLOCK_DATA_BITS
628 ss_bit = self.samplenum
629 elif step == STEP_CLOCK_DATA_BITS:
630 if self.matched[1]:
631 if clk == 1:
632 # Rising edge on CLK; latch DATA.
633 bits.append(data)
634 elif clk == 0:
635 # Falling edge on CLK; end of bit.
636 es_bit = self.samplenum
637 self.emit_data_ann(ss_bit, es_bit, ANN_RAW_BIT, ['{:d}'.format(bits[-1])])
638 self.putpy(ss_bit, es_bit, 'IEC_BIT', None, bits[-1])
639 ss_bit = self.samplenum
640 if len(bits) == 8:
641 es_byte = self.samplenum
642 self.inject_dav_phase(ss_byte, es_byte, bits)
643 if self.curr_eoi:
644 self.handle_eoi_change(False)
645 step = STEP_WAIT_READY_TO_SEND
646
647 def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq):
648
649 if False in has_data_n or not has_dav or not has_atn:
650 raise ChannelError('IEEE-488 needs at least ATN and DAV and eight DIO lines.')
651 has_ifc = self.has_channel(PIN_IFC)
652
653 # Capture data lines at the falling edge of DAV, process their
654 # values at rising DAV edge (when data validity ends). Also make
655 # sure to start inspection when the capture happens to start with
656 # low signal levels, i.e. won't include the initial falling edge.
657 # Scan for ATN/EOI edges as well (including the trick which works
658 # around initial pin state).
659 # Map low-active physical transport lines to positive logic here,
660 # to simplify logical inspection/decoding of communicated data,
661 # and to avoid redundancy and inconsistency in later code paths.
662 waitcond = []
663 idx_dav = len(waitcond)
664 waitcond.append({PIN_DAV: 'l'})
665 idx_atn = len(waitcond)
666 waitcond.append({PIN_ATN: 'l'})
667 idx_eoi = None
668 if has_eoi:
669 idx_eoi = len(waitcond)
670 waitcond.append({PIN_EOI: 'l'})
671 idx_ifc = None
672 if has_ifc:
673 idx_ifc = len(waitcond)
674 waitcond.append({PIN_IFC: 'l'})
675 while True:
676 pins = self.wait(waitcond)
677 pins = self.invert_pins(pins)
678
679 # BEWARE! Order of evaluation does matter. For low samplerate
680 # captures, many edges fall onto the same sample number. So
681 # we process active edges of flags early (before processing
682 # data bits), and inactive edges late (after data got processed).
683 if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 1:
684 self.handle_ifc_change(pins[PIN_IFC])
685 if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 1:
686 self.handle_eoi_change(pins[PIN_EOI])
687 if self.matched[idx_atn] and pins[PIN_ATN] == 1:
688 self.handle_atn_change(pins[PIN_ATN])
689 if self.matched[idx_dav]:
690 self.handle_dav_change(pins[PIN_DAV], pins[PIN_DIO1:PIN_DIO8 + 1])
691 if self.matched[idx_atn] and pins[PIN_ATN] == 0:
692 self.handle_atn_change(pins[PIN_ATN])
693 if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 0:
694 self.handle_eoi_change(pins[PIN_EOI])
695 if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 0:
696 self.handle_ifc_change(pins[PIN_IFC])
697
698 waitcond[idx_dav][PIN_DAV] = 'e'
699 waitcond[idx_atn][PIN_ATN] = 'e'
700 if has_eoi:
701 waitcond[idx_eoi][PIN_EOI] = 'e'
702 if has_ifc:
703 waitcond[idx_ifc][PIN_IFC] = 'e'
704
705 def decode(self):
706 # The decoder's boilerplate declares some of the input signals as
707 # optional, but only to support both serial and parallel variants.
708 # The CLK signal discriminates the two. For either variant some
709 # of the "optional" signals are not really optional for proper
710 # operation of the decoder. Check these conditions here.
711 has_clk = self.has_channel(PIN_CLK)
712 has_data_1 = self.has_channel(PIN_DIO1)
713 has_data_n = [bool(self.has_channel(pin) for pin in range(PIN_DIO1, PIN_DIO8 + 1))]
714 has_dav = self.has_channel(PIN_DAV)
715 has_atn = self.has_channel(PIN_ATN)
716 has_eoi = self.has_channel(PIN_EOI)
717 has_srq = self.has_channel(PIN_SRQ)
718 if has_clk:
719 self.decode_serial(has_clk, has_data_1, has_atn, has_srq)
720 else:
721 self.decode_parallel(has_data_n, has_dav, has_atn, has_eoi, has_srq)