- for i in range(len(self.optional_channels)):
- if self.has_channel(i):
- self.num_channels += 1
-
- if self.num_channels == 0:
- raise ChannelError('At least one channel has to be supplied.')
-
- if not self.has_channel(0):
- # CLK was not supplied, sample on ANY edge of ANY of the pins
- # (but only of those pins that were actually supplied).
- conds = []
- for i in range(1, len(self.optional_channels)):
- if self.has_channel(i):
- conds.append({i: 'e'})
- while True:
- self.handle_bits(self.wait(conds)[1:])
+ # 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.
+ conds = []
+ cond_idx_clock = None
+ cond_idx_data_0 = None
+ cond_idx_data_N = None
+ cond_idx_reset = None
+ has_clock = self.has_channel(Pin.CLOCK)
+ if has_clock:
+ cond_idx_clock = len(conds)
+ edge = {
+ 'rising': 'r',
+ 'falling': 'f',
+ 'either': 'e',
+ }.get(self.options['clock_edge'])
+ conds.append({Pin.CLOCK: edge})