+ def decode(self):
+ # Determine which (optional) channels have input data. Insist in
+ # a non-empty input data set. Cope with sparse connection maps.
+ # Store enough state to later "compress" sampled input data.
+ data_indices = [
+ idx if self.has_channel(idx) else None
+ for idx in range(Pin.DATA_0, Pin.DATA_N)
+ ]
+ has_data = [idx for idx in data_indices if idx is not None]
+ if not has_data:
+ raise ChannelError('Need at least one data channel.')
+ max_connected = max(has_data)
+
+ # Pre-determine which input data to strip off, the width of
+ # individual items and multiplexed words, as well as format
+ # strings here. This simplifies call sites which run in tight
+ # loops later.
+ upper_data_bound = max_connected + 1
+ num_item_bits = upper_data_bound - Pin.DATA_0
+ num_word_items = self.options['wordsize']
+ num_word_bits = num_item_bits * num_word_items
+ num_digits = (num_item_bits + 4 - 1) // 4
+ self.fmt_item = "{{:0{}x}}".format(num_digits)
+ num_digits = (num_word_bits + 4 - 1) // 4
+ self.fmt_word = "{{:0{}x}}".format(num_digits)
+
+ # Determine .wait() conditions, depending on the presence of a
+ # clock signal. Either inspect samples on the configured edge of
+ # the clock, or inspect samples upon ANY edge of ANY of the pins
+ # which provide input data.
+ has_clock = self.has_channel(Pin.CLOCK)
+ if has_clock:
+ edge = self.options['clock_edge'][0]
+ conds = [{Pin.CLOCK: edge}]
+ else:
+ conds = [{idx: 'e'} for idx in has_data]
+
+ # Keep processing the input stream. Assume "always zero" for
+ # not-connected input lines. Pass data bits (all inputs except
+ # clock) to the handle_bits() method.
+ while True:
+ pins = self.wait(conds)
+ data_bits = [0 if idx is None else pins[idx] for idx in data_indices]
+ data_bits = data_bits[:num_item_bits]
+ item = bitpack(data_bits)
+ self.handle_bits(item, num_item_bits)