2 ## This file is part of the libsigrokdecode project.
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>
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.
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.
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/>.
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.
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.
41 import sigrokdecode as srd
42 from common.srdhelper import bitpack
45 OUTPUT_PYTHON format for stacked decoders:
47 General packet format:
48 [<ptype>, <addr>, <pdata>]
50 This is the list of <ptype>s and their respective <pdata> values:
52 Raw 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.
58 GPIB 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).
73 Extracted 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.
88 class ChannelError(Exception):
91 def _format_ann_texts(fmts, **args):
94 return [fmt.format(**args) for fmt in fmts]
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'],
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
126 def _is_listen_addr(b):
127 if b in range(0x20, 0x40):
131 def _is_talk_addr(b):
132 if b in range(0x40, 0x60):
136 def _is_secondary_addr(b):
137 if b in range(0x60, 0x80):
146 def _get_raw_byte(b, atn):
147 # "Decorate" raw byte values for stacked decoders.
148 return b | 0x100 if atn else b
150 def _get_raw_text(b, atn):
151 return ['{leader}{data:02x}'.format(leader = '/' if atn else '', data = b)]
153 def _get_command_texts(b):
154 fmts = _cmd_table.get(b, None)
155 known = fmts is not None
157 fmts = _cmd_table.get(None, None)
160 return known, _format_ann_texts(fmts, cmd = b, cmd_ord = ord('0') + b)
162 def _get_address_texts(b):
163 laddr = _is_listen_addr(b)
164 taddr = _is_talk_addr(b)
165 saddr = _is_secondary_addr(b)
168 if laddr is not None:
169 fmts = ['Listen {addr:d}', 'L {addr:d}', 'L{addr_ord:c}']
171 elif taddr is not None:
172 fmts = ['Talk {addr:d}', 'T {addr:d}', 'T{addr_ord:c}']
174 elif saddr is not None:
175 fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}']
177 elif msb is not None: # For IEC bus compat.
178 fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}']
180 return _format_ann_texts(fmts, addr = addr, addr_ord = ord('0') + addr)
182 def _get_data_text(b):
183 # TODO Move the table of ASCII control characters to a common location?
184 # TODO Move the "printable with escapes" logic to a common helper?
219 # Yes, exclude 0x7f (DEL) here. It's considered non-printable.
220 if b in range(0x20, 0x7f) and b not in ('[', ']'):
221 return '{:s}'.format(chr(b))
222 elif b in _control_codes:
223 return '[{:s}]'.format(_control_codes[b])
224 # Use a compact yet readable and unambigous presentation for bytes
225 # which contain non-printables. The format that is used here is
226 # compatible with 93xx EEPROM and UART decoders.
227 return '[{:02x}]'.format(b)
230 PIN_DIO1, PIN_DIO2, PIN_DIO3, PIN_DIO4,
231 PIN_DIO5, PIN_DIO6, PIN_DIO7, PIN_DIO8,
232 PIN_EOI, PIN_DAV, PIN_NRFD, PIN_NDAC,
233 PIN_IFC, PIN_SRQ, PIN_ATN, PIN_REN,
239 ANN_RAW_BIT, ANN_RAW_BYTE,
240 ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA,
243 # TODO Want to provide one annotation class per talker address (0-30)?
251 # TODO Want to provide one binary annotation class per talker address (0-30)?
254 class Decoder(srd.Decoder):
258 longname = 'IEEE-488 GPIB/HPIB/IEC'
259 desc = 'IEEE-488 General Purpose Interface Bus (GPIB/HPIB or IEC).'
262 outputs = ['ieee488']
263 tags = ['PC', 'Retro computing']
265 {'id': 'dio1' , 'name': 'DIO1/DATA',
266 'desc': 'Data I/O bit 1, or serial data'},
268 optional_channels = (
269 {'id': 'dio2' , 'name': 'DIO2', 'desc': 'Data I/O bit 2'},
270 {'id': 'dio3' , 'name': 'DIO3', 'desc': 'Data I/O bit 3'},
271 {'id': 'dio4' , 'name': 'DIO4', 'desc': 'Data I/O bit 4'},
272 {'id': 'dio5' , 'name': 'DIO5', 'desc': 'Data I/O bit 5'},
273 {'id': 'dio6' , 'name': 'DIO6', 'desc': 'Data I/O bit 6'},
274 {'id': 'dio7' , 'name': 'DIO7', 'desc': 'Data I/O bit 7'},
275 {'id': 'dio8' , 'name': 'DIO8', 'desc': 'Data I/O bit 8'},
276 {'id': 'eoi', 'name': 'EOI', 'desc': 'End or identify'},
277 {'id': 'dav', 'name': 'DAV', 'desc': 'Data valid'},
278 {'id': 'nrfd', 'name': 'NRFD', 'desc': 'Not ready for data'},
279 {'id': 'ndac', 'name': 'NDAC', 'desc': 'Not data accepted'},
280 {'id': 'ifc', 'name': 'IFC', 'desc': 'Interface clear'},
281 {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'},
282 {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'},
283 {'id': 'ren', 'name': 'REN', 'desc': 'Remote enable'},
284 {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock'},
287 {'id': 'iec_periph', 'desc': 'Decode Commodore IEC bus peripherals details',
288 'default': 'no', 'values': ('no', 'yes')},
289 {'id': 'delim', 'desc': 'Payload data delimiter',
290 'default': 'eol', 'values': ('none', 'eol')},
296 ('laddr', 'Listener address'),
297 ('taddr', 'Talker address'),
298 ('saddr', 'Secondary address'),
299 ('data', 'Data byte'),
301 ('text', 'Talker text'),
302 ('periph', 'IEC bus peripherals'),
306 ('bits', 'IEC bits', (ANN_RAW_BIT,)),
307 ('raws', 'Raw bytes', (ANN_RAW_BYTE,)),
308 ('gpib', 'Commands/data', (ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA,)),
309 ('eois', 'EOI', (ANN_EOI,)),
310 ('texts', 'Talker texts', (ANN_TEXT,)),
311 ('periphs', 'IEC peripherals', (ANN_IEC_PERIPH,)),
312 ('warns', 'Warnings', (ANN_WARN,)),
315 ('raw', 'Raw bytes'),
316 ('data', 'Talker bytes'),
326 self.latch_atn = None
327 self.latch_eoi = None
336 self.last_talker = None
337 self.last_listener = []
338 self.last_iec_addr = None
339 self.last_iec_sec = None
342 self.out_ann = self.register(srd.OUTPUT_ANN)
343 self.out_bin = self.register(srd.OUTPUT_BINARY)
344 self.out_python = self.register(srd.OUTPUT_PYTHON)
346 def putg(self, ss, es, data):
347 self.put(ss, es, self.out_ann, data)
349 def putbin(self, ss, es, data):
350 self.put(ss, es, self.out_bin, data)
352 def putpy(self, ss, es, ptype, addr, pdata):
353 self.put(ss, es, self.out_python, [ptype, addr, pdata])
355 def emit_eoi_ann(self, ss, es):
356 self.putg(ss, es, [ANN_EOI, ['EOI']])
358 def emit_bin_ann(self, ss, es, ann_cls, data):
359 self.putbin(ss, es, [ann_cls, bytes(data)])
361 def emit_data_ann(self, ss, es, ann_cls, data):
362 self.putg(ss, es, [ann_cls, data])
364 def emit_warn_ann(self, ss, es, data):
365 self.putg(ss, es, [ANN_WARN, data])
367 def flush_bytes_text_accu(self):
368 if self.accu_bytes and self.ss_text is not None and self.es_text is not None:
369 self.emit_bin_ann(self.ss_text, self.es_text, BIN_DATA, bytearray(self.accu_bytes))
370 self.putpy(self.ss_text, self.es_text, 'TALKER_BYTES', self.last_talker, bytearray(self.accu_bytes))
372 if self.accu_text and self.ss_text is not None and self.es_text is not None:
373 text = ''.join(self.accu_text)
374 self.emit_data_ann(self.ss_text, self.es_text, ANN_TEXT, [text])
375 self.putpy(self.ss_text, self.es_text, 'TALKER_TEXT', self.last_talker, text)
377 self.ss_text = self.es_text = None
379 def check_extra_flush(self, b):
380 # Optionally flush previously accumulated runs of payload data
381 # according to user specified conditions.
382 if self.options['delim'] == 'none':
384 if not self.accu_bytes:
387 # This implementation exlusively handles "text lines", but adding
388 # support for more variants here is straight forward.
390 # Search for the first data byte _after_ a user specified text
391 # line termination sequence was seen. The termination sequence's
392 # alphabet may be variable, and the sequence may span multiple
393 # data bytes. We accept either CR or LF, and combine the CR+LF
394 # sequence to strive for maximum length annotations for improved
395 # readability at different zoom levels. It's acceptable that this
396 # implementation would also combine multiple line terminations
398 term_chars = (10, 13)
399 is_eol = b in term_chars
400 had_eol = self.accu_bytes[-1] in term_chars
401 if had_eol and not is_eol:
402 self.flush_bytes_text_accu()
404 def handle_ifc_change(self, ifc):
405 # Track IFC line for parallel input.
406 # Assertion of IFC de-selects all talkers and listeners.
408 self.last_talker = None
409 self.last_listener = []
411 def handle_eoi_change(self, eoi):
412 # Track EOI line for parallel and serial input.
414 self.ss_eoi = self.samplenum
417 self.es_eoi = self.samplenum
418 if self.ss_eoi and self.latch_eoi:
419 self.emit_eoi_ann(self.ss_eoi, self.es_eoi)
420 self.es_text = self.es_eoi
421 self.flush_bytes_text_accu()
422 self.ss_eoi = self.es_eoi = None
425 def handle_atn_change(self, atn):
426 # Track ATN line for parallel and serial input.
429 self.flush_bytes_text_accu()
431 def handle_iec_periph(self, ss, es, addr, sec, data):
432 # The annotation is optional.
433 if self.options['iec_periph'] != 'yes':
435 # Void internal state.
436 if addr is None and sec is None and data is None:
437 self.last_iec_addr = None
438 self.last_iec_sec = None
440 # Grab and evaluate new input.
442 # TODO Add more items here. See the "Device numbering" section
443 # of the https://en.wikipedia.org/wiki/Commodore_bus page.
447 _iec_disk_range = range(8, 16)
449 self.last_iec_addr = addr
450 name = _iec_addr_names.get(addr, None)
452 self.emit_data_ann(ss, es, ANN_IEC_PERIPH, [name])
453 addr = self.last_iec_addr # Simplify subsequent logic.
455 # BEWARE! The secondary address is a full byte and includes
456 # the 0x60 offset, to also work when the MSB was set.
457 self.last_iec_sec = sec
458 subcmd, channel = sec & 0xf0, sec & 0x0f
459 channel_ord = ord('0') + channel
460 if addr is not None and addr in _iec_disk_range:
462 0x60: ['Reopen {ch:d}', 'Re {ch:d}', 'R{ch_ord:c}'],
463 0xe0: ['Close {ch:d}', 'Cl {ch:d}', 'C{ch_ord:c}'],
464 0xf0: ['Open {ch:d}', 'Op {ch:d}', 'O{ch_ord:c}'],
467 texts = _format_ann_texts(subcmd_fmts, ch = channel, ch_ord = channel_ord)
468 self.emit_data_ann(ss, es, ANN_IEC_PERIPH, texts)
469 sec = self.last_iec_sec # Simplify subsequent logic.
471 if addr is None or sec is None:
473 # TODO Process data depending on peripheral type and channel?
475 def handle_data_byte(self):
476 if not self.curr_atn:
477 self.check_extra_flush(self.curr_raw)
479 texts = _get_raw_text(b, self.curr_atn)
480 self.emit_data_ann(self.ss_raw, self.es_raw, ANN_RAW_BYTE, texts)
481 self.emit_bin_ann(self.ss_raw, self.es_raw, BIN_RAW, b.to_bytes(1, byteorder='big'))
482 self.putpy(self.ss_raw, self.es_raw, 'GPIB_RAW', None, _get_raw_byte(b, self.curr_atn))
488 is_cmd, is_unl, is_unt = _is_command(b)
489 laddr = _is_listen_addr(b)
490 taddr = _is_talk_addr(b)
491 saddr = _is_secondary_addr(b)
494 known, texts = _get_command_texts(b)
496 warn_texts = ['Unknown GPIB command', 'unknown', 'UNK']
497 self.emit_warn_ann(self.ss_raw, self.es_raw, warn_texts)
499 py_type, py_addr = 'COMMAND', None
501 self.last_listener = []
504 self.last_talker = None
507 upd_iec = True, None, None, None
508 elif laddr is not None:
510 texts = _get_address_texts(b)
512 py_type, py_addr = 'LISTEN', addr
513 if addr == self.last_talker:
514 self.last_talker = None
515 self.last_listener.append(addr)
516 upd_iec = True, addr, None, None
518 elif taddr is not None:
520 texts = _get_address_texts(b)
522 py_type, py_addr = 'TALK', addr
523 if addr in self.last_listener:
524 self.last_listener.remove(addr)
525 self.last_talker = addr
526 upd_iec = True, addr, None, None
528 elif saddr is not None:
530 texts = _get_address_texts(b)
532 upd_iec = True, None, b, None
533 py_type, py_addr = 'SECONDARY', addr
534 elif msb is not None:
535 # These are not really "secondary addresses", but they
536 # are used by the Commodore IEC bus (floppy channels).
537 texts = _get_address_texts(b)
539 upd_iec = True, None, b, None
540 py_type, py_addr = 'MSB_SET', b
541 if ann_cls is not None and texts is not None:
542 self.emit_data_ann(self.ss_raw, self.es_raw, ann_cls, texts)
544 self.handle_iec_periph(self.ss_raw, self.es_raw, upd_iec[1], upd_iec[2], upd_iec[3])
546 self.putpy(self.ss_raw, self.es_raw, py_type, py_addr, b)
548 self.last_listener.sort()
549 self.putpy(self.ss_raw, self.es_raw, 'TALK_LISTEN', self.last_talker, self.last_listener)
551 self.accu_bytes.append(b)
552 text = _get_data_text(b)
553 if not self.accu_text:
554 self.ss_text = self.ss_raw
555 self.accu_text.append(text)
556 self.es_text = self.es_raw
557 self.emit_data_ann(self.ss_raw, self.es_raw, ANN_DATA, [text])
558 self.handle_iec_periph(self.ss_raw, self.es_raw, None, None, b)
559 self.putpy(self.ss_raw, self.es_raw, 'DATA_BYTE', self.last_talker, b)
561 def handle_dav_change(self, dav, data):
563 # Data availability starts when the flag goes active.
564 self.ss_raw = self.samplenum
565 self.curr_raw = bitpack(data)
566 self.latch_atn = self.curr_atn
567 self.latch_eoi = self.curr_eoi
569 # Data availability ends when the flag goes inactive. Handle the
570 # previously captured data byte according to associated flags.
571 self.es_raw = self.samplenum
572 self.handle_data_byte()
573 self.ss_raw = self.es_raw = None
576 def inject_dav_phase(self, ss, es, data):
577 # Inspection of serial input has resulted in one raw byte which
578 # spans a given period of time. Pretend we had seen a DAV active
579 # phase, to re-use code for the parallel transmission.
581 self.curr_raw = bitpack(data)
582 self.latch_atn = self.curr_atn
583 self.latch_eoi = self.curr_eoi
585 self.handle_data_byte()
586 self.ss_raw = self.es_raw = None
589 def invert_pins(self, pins):
590 # All lines (including data bits!) are low active and thus need
591 # to get inverted to receive their logical state (high active,
592 # regular data bit values). Cope with inputs being optional.
593 return [1 - p if p in (0, 1) else p for p in pins]
595 def decode_serial(self, has_clk, has_data_1, has_atn, has_srq):
596 if not has_clk or not has_data_1 or not has_atn:
597 raise ChannelError('IEC bus needs at least ATN and serial CLK and DATA.')
599 # This is a rephrased version of decoders/iec/pd.py:decode().
600 # SRQ was not used there either. Magic numbers were eliminated.
602 STEP_WAIT_READY_TO_SEND,
603 STEP_WAIT_READY_FOR_DATA,
604 STEP_PREP_DATA_TEST_EOI,
605 STEP_CLOCK_DATA_BITS,
608 [{PIN_ATN: 'f'}, {PIN_DATA: 'l', PIN_CLK: 'h'}],
609 [{PIN_ATN: 'f'}, {PIN_DATA: 'h', PIN_CLK: 'h'}, {PIN_CLK: 'l'}],
610 [{PIN_ATN: 'f'}, {PIN_DATA: 'f'}, {PIN_CLK: 'l'}],
611 [{PIN_ATN: 'f'}, {PIN_CLK: 'e'}],
613 step = STEP_WAIT_READY_TO_SEND
618 # Sample input pin values. Keep DATA/CLK in verbatim form to
619 # re-use 'iec' decoder logic. Turn ATN to positive logic for
620 # easier processing. The data bits get handled during byte
622 pins = self.wait(step_wait_conds[step])
623 data, clk = pins[PIN_DATA], pins[PIN_CLK]
624 atn, = self.invert_pins([pins[PIN_ATN]])
627 # Falling edge on ATN, reset step.
628 step = STEP_WAIT_READY_TO_SEND
630 if step == STEP_WAIT_READY_TO_SEND:
631 # Don't use self.matched[1] here since we might come from
632 # a step with different conds due to the code above.
633 if data == 0 and clk == 1:
634 # Rising edge on CLK while DATA is low: Ready to send.
635 step = STEP_WAIT_READY_FOR_DATA
636 elif step == STEP_WAIT_READY_FOR_DATA:
637 if data == 1 and clk == 1:
638 # Rising edge on DATA while CLK is high: Ready for data.
639 ss_byte = self.samplenum
640 self.handle_atn_change(atn)
642 self.handle_eoi_change(False)
644 step = STEP_PREP_DATA_TEST_EOI
646 # CLK low again, transfer aborted.
647 step = STEP_WAIT_READY_TO_SEND
648 elif step == STEP_PREP_DATA_TEST_EOI:
649 if data == 0 and clk == 1:
650 # DATA goes low while CLK is still high, EOI confirmed.
651 self.handle_eoi_change(True)
653 step = STEP_CLOCK_DATA_BITS
654 ss_bit = self.samplenum
655 elif step == STEP_CLOCK_DATA_BITS:
658 # Rising edge on CLK; latch DATA.
661 # Falling edge on CLK; end of bit.
662 es_bit = self.samplenum
663 self.emit_data_ann(ss_bit, es_bit, ANN_RAW_BIT, ['{:d}'.format(bits[-1])])
664 self.putpy(ss_bit, es_bit, 'IEC_BIT', None, bits[-1])
665 ss_bit = self.samplenum
667 es_byte = self.samplenum
668 self.inject_dav_phase(ss_byte, es_byte, bits)
670 self.handle_eoi_change(False)
671 step = STEP_WAIT_READY_TO_SEND
673 def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq):
675 if False in has_data_n or not has_dav or not has_atn:
676 raise ChannelError('IEEE-488 needs at least ATN and DAV and eight DIO lines.')
677 has_ifc = self.has_channel(PIN_IFC)
679 # Capture data lines at the falling edge of DAV, process their
680 # values at rising DAV edge (when data validity ends). Also make
681 # sure to start inspection when the capture happens to start with
682 # low signal levels, i.e. won't include the initial falling edge.
683 # Scan for ATN/EOI edges as well (including the trick which works
684 # around initial pin state).
685 # Map low-active physical transport lines to positive logic here,
686 # to simplify logical inspection/decoding of communicated data,
687 # and to avoid redundancy and inconsistency in later code paths.
689 idx_dav = len(waitcond)
690 waitcond.append({PIN_DAV: 'l'})
691 idx_atn = len(waitcond)
692 waitcond.append({PIN_ATN: 'l'})
695 idx_eoi = len(waitcond)
696 waitcond.append({PIN_EOI: 'l'})
699 idx_ifc = len(waitcond)
700 waitcond.append({PIN_IFC: 'l'})
702 pins = self.wait(waitcond)
703 pins = self.invert_pins(pins)
705 # BEWARE! Order of evaluation does matter. For low samplerate
706 # captures, many edges fall onto the same sample number. So
707 # we process active edges of flags early (before processing
708 # data bits), and inactive edges late (after data got processed).
709 if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 1:
710 self.handle_ifc_change(pins[PIN_IFC])
711 if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 1:
712 self.handle_eoi_change(pins[PIN_EOI])
713 if self.matched[idx_atn] and pins[PIN_ATN] == 1:
714 self.handle_atn_change(pins[PIN_ATN])
715 if self.matched[idx_dav]:
716 self.handle_dav_change(pins[PIN_DAV], pins[PIN_DIO1:PIN_DIO8 + 1])
717 if self.matched[idx_atn] and pins[PIN_ATN] == 0:
718 self.handle_atn_change(pins[PIN_ATN])
719 if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 0:
720 self.handle_eoi_change(pins[PIN_EOI])
721 if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 0:
722 self.handle_ifc_change(pins[PIN_IFC])
724 waitcond[idx_dav][PIN_DAV] = 'e'
725 waitcond[idx_atn][PIN_ATN] = 'e'
727 waitcond[idx_eoi][PIN_EOI] = 'e'
729 waitcond[idx_ifc][PIN_IFC] = 'e'
732 # The decoder's boilerplate declares some of the input signals as
733 # optional, but only to support both serial and parallel variants.
734 # The CLK signal discriminates the two. For either variant some
735 # of the "optional" signals are not really optional for proper
736 # operation of the decoder. Check these conditions here.
737 has_clk = self.has_channel(PIN_CLK)
738 has_data_1 = self.has_channel(PIN_DIO1)
739 has_data_n = [bool(self.has_channel(pin) for pin in range(PIN_DIO1, PIN_DIO8 + 1))]
740 has_dav = self.has_channel(PIN_DAV)
741 has_atn = self.has_channel(PIN_ATN)
742 has_eoi = self.has_channel(PIN_EOI)
743 has_srq = self.has_channel(PIN_SRQ)
745 self.decode_serial(has_clk, has_data_1, has_atn, has_srq)
747 self.decode_parallel(has_data_n, has_dav, has_atn, has_eoi, has_srq)