+ def handle_break(self, rxtx, ss, es):
+ self.putpse(ss, es, ['BREAK', rxtx, 0])
+ self.putgse(ss, es, [Ann.RX_BREAK + rxtx,
+ ['Break condition', 'Break', 'Brk', 'B']])
+ self.state[rxtx] = 'WAIT FOR START BIT'
+
+ def get_wait_cond(self, rxtx, inv):
+ # Return condititions that are suitable for Decoder.wait(). Those
+ # conditions either match the falling edge of the START bit, or
+ # the sample point of the next bit time.
+ state = self.state[rxtx]
+ if state == 'WAIT FOR START BIT':
+ return {rxtx: 'r' if inv else 'f'}
+ if state in ('GET START BIT', 'GET DATA BITS',
+ 'GET PARITY BIT', 'GET STOP BITS'):
+ bitnum = self.cur_frame_bit[rxtx]
+ # TODO: Currently does not support half STOP bits.
+ want_num = ceil(self.get_sample_point(rxtx, bitnum))
+ return {'skip': want_num - self.samplenum}
+
+ def get_idle_cond(self, rxtx, inv):
+ # Return a condition that corresponds to the (expected) end of
+ # the next frame, assuming that it will be an "idle frame"
+ # (constant high input level for the frame's length).
+ if self.idle_start[rxtx] is None:
+ return None
+ end_of_frame = self.idle_start[rxtx] + self.frame_len_sample_count
+ if end_of_frame < self.samplenum:
+ return None
+ return {'skip': end_of_frame - self.samplenum}
+
+ def inspect_sample(self, rxtx, signal, inv):
+ # Inspect a sample returned by .wait() for the specified UART line.
+ if inv:
+ signal = not signal
+
+ state = self.state[rxtx]
+ if state == 'WAIT FOR START BIT':
+ self.wait_for_start_bit(rxtx, signal)
+ elif state == 'GET START BIT':
+ self.get_start_bit(rxtx, signal)
+ elif state == 'GET DATA BITS':
+ self.get_data_bits(rxtx, signal)
+ elif state == 'GET PARITY BIT':
+ self.get_parity_bit(rxtx, signal)
+ elif state == 'GET STOP BITS':
+ self.get_stop_bits(rxtx, signal)
+
+ def inspect_edge(self, rxtx, signal, inv):
+ # Inspect edges, independently from traffic, to detect break conditions.
+ if inv:
+ signal = not signal
+ if not signal:
+ # Signal went low. Start another interval.
+ self.break_start[rxtx] = self.samplenum
+ return
+ # Signal went high. Was there an extended period with low signal?
+ if self.break_start[rxtx] is None:
+ return
+ diff = self.samplenum - self.break_start[rxtx]
+ if diff >= self.break_min_sample_count:
+ ss, es = self.frame_start[rxtx], self.samplenum
+ self.handle_break(rxtx, ss, es)
+ self.break_start[rxtx] = None
+
+ def inspect_idle(self, rxtx, signal, inv):
+ # Check each edge and each period of stable input (either level).
+ # Can derive the "idle frame period has passed" condition.
+ if inv:
+ signal = not signal
+ if not signal:
+ # Low input, cease inspection.
+ self.idle_start[rxtx] = None
+ return
+ # High input, either just reached, or still stable.
+ if self.idle_start[rxtx] is None:
+ self.idle_start[rxtx] = self.samplenum
+ diff = self.samplenum - self.idle_start[rxtx]
+ if diff < self.frame_len_sample_count:
+ return
+ ss, es = self.idle_start[rxtx], self.samplenum
+ self.handle_idle(rxtx, ss, es)
+ self.idle_start[rxtx] = es
+
+ def decode(self):
+ if not self.samplerate:
+ raise SamplerateError('Cannot decode without samplerate.')
+
+ has_pin = [self.has_channel(ch) for ch in (RX, TX)]
+ if not True in has_pin:
+ raise ChannelError('Need at least one of TX or RX pins.')
+
+ opt = self.options
+ inv = [opt['invert_rx'] == 'yes', opt['invert_tx'] == 'yes']
+ cond_data_idx = [None] * len(has_pin)
+
+ # Determine the number of samples for a complete frame's time span.
+ # A period of low signal (at least) that long is a break condition.
+ frame_samples = 1 # START
+ frame_samples += self.options['data_bits']
+ frame_samples += 0 if self.options['parity'] == 'none' else 1
+ frame_samples += self.options['stop_bits']
+ frame_samples *= self.bit_width
+ self.frame_len_sample_count = ceil(frame_samples)
+ self.break_min_sample_count = self.frame_len_sample_count
+ cond_edge_idx = [None] * len(has_pin)
+ cond_idle_idx = [None] * len(has_pin)
+
+ while True:
+ conds = []
+ if has_pin[RX]:
+ cond_data_idx[RX] = len(conds)
+ conds.append(self.get_wait_cond(RX, inv[RX]))
+ cond_edge_idx[RX] = len(conds)
+ conds.append({RX: 'e'})
+ cond_idle_idx[RX] = None
+ idle_cond = self.get_idle_cond(RX, inv[RX])
+ if idle_cond:
+ cond_idle_idx[RX] = len(conds)
+ conds.append(idle_cond)
+ if has_pin[TX]:
+ cond_data_idx[TX] = len(conds)
+ conds.append(self.get_wait_cond(TX, inv[TX]))
+ cond_edge_idx[TX] = len(conds)
+ conds.append({TX: 'e'})
+ cond_idle_idx[TX] = None
+ idle_cond = self.get_idle_cond(TX, inv[TX])
+ if idle_cond:
+ cond_idle_idx[TX] = len(conds)
+ conds.append(idle_cond)
+ (rx, tx) = self.wait(conds)
+ if cond_data_idx[RX] is not None and self.matched[cond_data_idx[RX]]:
+ self.inspect_sample(RX, rx, inv[RX])
+ if cond_edge_idx[RX] is not None and self.matched[cond_edge_idx[RX]]:
+ self.inspect_edge(RX, rx, inv[RX])
+ self.inspect_idle(RX, rx, inv[RX])
+ if cond_idle_idx[RX] is not None and self.matched[cond_idle_idx[RX]]:
+ self.inspect_idle(RX, rx, inv[RX])
+ if cond_data_idx[TX] is not None and self.matched[cond_data_idx[TX]]:
+ self.inspect_sample(TX, tx, inv[TX])
+ if cond_edge_idx[TX] is not None and self.matched[cond_edge_idx[TX]]:
+ self.inspect_edge(TX, tx, inv[TX])
+ self.inspect_idle(TX, tx, inv[TX])
+ if cond_idle_idx[TX] is not None and self.matched[cond_idle_idx[TX]]:
+ self.inspect_idle(TX, tx, inv[TX])