+ if ss is None or es is None or ss >= es:
+ return
+
+ if is_mab:
+ ann = Ann.MAB
+ txts = ['MARK AFTER BREAK', 'MAB']
+ elif is_if:
+ ann = Ann.INTERFRAME
+ txts = ['INTER FRAME', 'IF']
+ elif is_ip:
+ ann = Ann.INTERPACKET
+ txts = ['INTER PACKET', 'IP']
+ else:
+ return
+ self.putg(ss, es, [ann, txts])
+
+ if self.have_samplerate():
+ duration = self.samples_to_usecs(es - ss)
+ if duration > self.options['max_mark']:
+ txts = ['Excessive MARK length', 'MARK length', 'MARK']
+ self.putg(ss, es, [Ann.ERROR, txts])
+
+ def flush_frame(self, ss, es, value, valid):
+ '''Handle UART frame content. Accumulate DMX packet.'''
+
+ if not valid:
+ txts = ['Invalid frame', 'Frame']
+ self.putg(ss, es, [Ann.ERROR, txts])
+
+ self.last_es = es
+
+ # Cease packet inspection before first BREAK.
+ if not self.last_break:
+ return
+
+ # Accumulate the sequence of bytes for the current DMX frame.
+ # Emit the annotation at the "DMX fields" level.
+ is_start = self.packet is None
+ if is_start:
+ self.packet = []
+ slot_nr = len(self.packet)
+ item = (ss, es, value, valid)
+ self.packet.append(item)
+ if is_start:
+ # Slot 0, the start code. Determines the DMX frame type.
+ self.start_code = value
+ ann = Ann.STARTCODE
+ val_text = self.format_value(value)
+ txts = [
+ 'STARTCODE {}'.format(val_text),
+ 'START {}'.format(val_text),
+ '{}'.format(val_text),
+ ]
+ else:
+ # Slot 1+, the payload bytes.
+ ann = Ann.DATABYTE
+ val_text = self.format_value(value)
+ txts = [
+ 'DATABYTE {:d}: {}'.format(slot_nr, val_text),
+ 'DATA {:d}: {}'.format(slot_nr, val_text),
+ 'DATA {}'.format(val_text),
+ '{}'.format(val_text),
+ ]
+ self.putg(ss, es, [ann, txts])
+
+ # Tell channel data for peripherals from arbitrary slot values.
+ # Can get extended for other start code types in case protocol
+ # extensions are handled here and not in stacked decoders.
+ if is_start:
+ ann = None
+ elif self.start_code == 0:
+ # Start code was 0. Slots carry values for channels.
+ # Optionally suppress zero-values to make used channels
+ # stand out, to help users focus their attention.
+ ann = Ann.CHANNEL_DATA
+ if value == 0 and self.options['show_zero'] == 'no':
+ ann = None
+ else:
+ val_text = self.format_value(value)
+ txts = [
+ 'CHANNEL {:d}: {}'.format(slot_nr, val_text),
+ 'CH {:d}: {}'.format(slot_nr, val_text),
+ 'CH {}'.format(val_text),
+ '{}'.format(val_text),
+ ]
+ else:
+ # Unhandled start code. Provide "anonymous" values.
+ ann = Ann.SLOT_DATA
+ val_text = self.format_value(value)
+ txts = [
+ 'SLOT {:d}: {}'.format(slot_nr, val_text),
+ 'SL {:d}: {}'.format(slot_nr, val_text),
+ 'SL {}'.format(val_text),
+ '{}'.format(val_text),
+ ]
+ if ann is not None:
+ self.putg(ss, es, [ann, txts])
+
+ if is_start and value == 0:
+ self.flush_reset(self.last_break, es)
+
+ def handle_break(self, ss, es):
+ '''Handle UART BREAK conditions.'''
+
+ # Check the last frame before BREAK if one was queued. It could
+ # have been "invalid" since the STOP bit check failed. If there
+ # is an invalid frame which happens to start at the start of the
+ # BREAK condition, then discard it. Otherwise flush its output.
+ last_frame = self.last_frame
+ self.last_frame = None
+ frame_invalid = last_frame and not last_frame[3]
+ frame_zero_data = last_frame and last_frame[2] == 0
+ frame_is_break = last_frame and last_frame[0] == ss
+ if frame_invalid and frame_zero_data and frame_is_break:
+ last_frame = None
+ if last_frame is not None:
+ self.flush_frame(*last_frame)
+
+ # Handle inter-packet MARK (works for zero length, too).
+ self.flush_mark(self.last_es, ss, is_ip = True)
+
+ # Handle accumulated packets.
+ self.flush_packet()
+ self.packet = None
+
+ # Annotate the BREAK condition. Start accumulation of a packet.
+ self.flush_break(ss, es)
+
+ def handle_frame(self, ss, es, value, valid):
+ '''Handle UART data frames.'''
+
+ # Flush previously deferred frame (if available). Can't have been
+ # BREAK if another data frame follows.
+ last_frame = self.last_frame
+ self.last_frame = None
+ if last_frame:
+ self.flush_frame(*last_frame)
+
+ # Handle inter-frame MARK (works for zero length, too).
+ is_mab = self.last_break and self.packet is None
+ is_if = self.packet
+ self.flush_mark(self.last_es, ss, is_mab = is_mab, is_if = is_if)
+
+ # Defer handling of invalid frames, because they may start a new
+ # BREAK which we will only learn about much later. Immediately
+ # annotate valid frames.
+ if valid:
+ self.flush_frame(ss, es, value, valid)
+ else:
+ self.last_frame = (ss, es, value, valid)