def test_uart_speed(self): bits = 8 baud = 9600 polarity = uart.UARTConfig.IdleHigh parity = None stop_bits = 1 char_count = 1000 data = [random.randint(0, 255) for _ in xrange(char_count)] edges = list( uart.uart_synth(data, bits, baud, parity=parity, stop_bits=stop_bits)) iterations = 10 self._t_start = time.time() for _ in xrange(iterations): records = list(uart.uart_decode(iter(edges), bits=bits, polarity=polarity, parity=parity, stop_bits=stop_bits, \ stream_type=stream.StreamType.Edges, baud_rate=baud)) characters_processed = iterations * char_count return (iterations, characters_processed, 'characters')
def test_uart_hello(self): bits = 8 polarity = uart.UARTConfig.IdleLow parity = 'even' stop_bits = 2 message = 'Hello, world!' samples, sample_period, start_time = tsup.read_bin_file('test/data/uart_hello_8e2.bin') txd = stream.samples_to_sample_stream(samples, sample_period, start_time) frames = list(uart.uart_decode(txd, bits=bits, polarity=polarity, parity=parity, stop_bits=stop_bits)) ok_status = True for f in frames: if f.nested_status() != stream.StreamStatus.Ok: ok_status = False break self.assertTrue(ok_status, 'Decoded data has non-Ok status') # Check the message bytes dmsg = ''.join([chr(d.data) for d in frames]) self.assertEqual(message, dmsg, 'Message mismatch. Expected: "{}" Got: "{}"'.format(message, dmsg)) bits = 8 polarity = uart.UARTConfig.IdleLow parity = None stop_bits = 1 message = 'Hello, world!' samples, sample_period, start_time = tsup.read_bin_file('test/data/uart_hello.bin') txd = stream.samples_to_sample_stream(samples, sample_period, start_time) frames = list(uart.uart_decode(txd, bits=bits, polarity=polarity, parity=parity, stop_bits=stop_bits)) ok_status = True for f in frames: if f.nested_status() != stream.StreamStatus.Ok: ok_status = False break self.assertTrue(ok_status, 'Decoded data has non-Ok status') # Check the message bytes dmsg = ''.join([chr(d.data) for d in frames]) self.assertEqual(message, dmsg, 'Message 2 mismatch. Expected: "{}" Got: "{}"'.format(message, dmsg))
def test_uart_decode(self): self.test_name = 'UART message' self.trial_count = 10 for i in xrange(self.trial_count): self.update_progress(i + 1) msg = [] for _ in xrange(20): msg.append(chr(random.choice(xrange(ord('0'), ord('z'))))) msg = ''.join(msg) baud = random.choice((110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, \ 56000, 57600, 115200, 128000, 153600, 230400, 256000, 460800, 921600)) sample_rate = baud * 100.0 rise_time = sigp.min_rise_time( sample_rate) * 10.0 # 10x min rise time parity = random.choice((None, 'even', 'odd')) bits = random.choice((7, 8, 9)) #print('\nTRIAL {}: msg="{}", baud={}, parity={}, bits={}'.format(i, msg, baud, parity, bits)) edges = uart.uart_synth(bytearray(msg.encode('utf-8')), bits, baud, parity=parity, idle_start=100.0 / sample_rate) samples = sigp.synth_wave(edges, sample_rate, rise_time, ripple_db=60) noisy = sigp.amplify(sigp.noisify(samples, snr_db=20), gain=-15.0) waveform = list(noisy) frames = uart.uart_decode(iter(waveform), bits=bits, polarity=uart.UARTConfig.IdleLow, parity=parity, baud_rate=None) frames = list(frames) #print(''.join(str(d) for d in frames)) decoded_msg = ''.join(str(d) for d in frames) self.assertEqual(msg, decoded_msg, \ "Message not decoded successfully msg:'{0}', baud:{1}, parity:{2}, bits:{3}".format(msg, \ baud, parity, bits))
def test_uart_speed(self): bits = 8 baud = 9600 polarity = uart.UARTConfig.IdleHigh parity = None stop_bits = 1 char_count = 1000 data = [random.randint(0,255) for _ in xrange(char_count)] edges = list(uart.uart_synth(data, bits, baud, parity=parity, stop_bits=stop_bits)) iterations = 10 self._t_start = time.time() for _ in xrange(iterations): records = list(uart.uart_decode(iter(edges), bits=bits, polarity=polarity, parity=parity, stop_bits=stop_bits, \ stream_type=stream.StreamType.Edges, baud_rate=baud)) characters_processed = iterations * char_count return (iterations, characters_processed, 'characters')
def test_uart_decode(self): self.test_name = 'UART message' self.trial_count = 10 for i in xrange(self.trial_count): self.update_progress(i+1) msg = [] for _ in xrange(20): msg.append(chr(random.choice(xrange(ord('0'), ord('z')) ))) msg = ''.join(msg) baud = random.choice((110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, \ 56000, 57600, 115200, 128000, 153600, 230400, 256000, 460800, 921600)) sample_rate = baud * 100.0 rise_time = sigp.min_rise_time(sample_rate) * 10.0 # 10x min rise time parity = random.choice((None, 'even', 'odd')) bits = random.choice((7, 8, 9)) #print('\nTRIAL {}: msg="{}", baud={}, parity={}, bits={}'.format(i, msg, baud, parity, bits)) edges = uart.uart_synth(bytearray(msg.encode('utf-8')), bits, baud, parity=parity, idle_start=100.0 / sample_rate) samples = sigp.synth_wave(edges, sample_rate, rise_time, ripple_db=60) noisy = sigp.amplify(sigp.noisify(samples, snr_db=20), gain=-15.0) waveform = list(noisy) frames = uart.uart_decode(iter(waveform), bits=bits, polarity=uart.UARTConfig.IdleLow, parity=parity, baud_rate=None) frames = list(frames) #print(''.join(str(d) for d in frames)) decoded_msg = ''.join(str(d) for d in frames) self.assertEqual(msg, decoded_msg, \ "Message not decoded successfully msg:'{0}', baud:{1}, parity:{2}, bits:{3}".format(msg, \ baud, parity, bits))
def iso_k_line_decode(stream_data, min_message_interval=7.0e-3, logic_levels=None, stream_type=stream.StreamType.Samples): '''Decode ISO9141 and ISO14230 data streams This is a generator function that can be used in a pipeline of waveform procesing operations. Sample streams are a sequence of SampleChunk Objects. Edge streams are a sequence of 2-tuples of (time, int) pairs. The type of stream is identified by the stream_type parameter. Sample streams will be analyzed to find edge transitions representing 0 and 1 logic states of the waveforms. With sample streams, an initial block of data is consumed to determine the most likely logic levels in the signal. stream_data (iterable of SampleChunk objects or (float, int) pairs) A sample stream or edge stream of K-line messages. min_message_interval (float) The minimum time between bytes for identifying the end and start of messages. For ISO14230 this is used in addition to the message length encoded in the header. logic_levels ((float, float) or None) Optional pair that indicates (low, high) logic levels of the sample stream. When present, auto level detection is disabled. This has no effect on edge streams. stream_type (streaming.StreamType) A StreamType value indicating that the stream parameter represents either Samples or Edges Yields a series of KLineStreamMessage objects. Raises AutoLevelError if stream_type = Samples and the logic levels cannot be determined. ''' if stream_type == stream.StreamType.Samples: if logic_levels is None: samp_it, logic_levels = check_logic_levels(stream_data) else: samp_it = stream_data edges = find_edges(samp_it, logic_levels, hysteresis=0.4) else: # the stream is already a list of edges edges = stream_data bits = 8 parity = None stop_bits = 1 polarity = uart.UARTConfig.IdleHigh baud_rate = 10400 records_it = uart.uart_decode(edges, bits, parity, stop_bits, lsb_first=True, \ polarity=polarity, baud_rate=baud_rate, logic_levels=logic_levels, stream_type=stream.StreamType.Edges) S_WAKEUP = 0 S_INIT = 1 S_START_MSG = 2 S_GET_MSG = 3 state = S_GET_MSG wakeup_edges = [] init_bytes = [] protocol = KLineProtocol.Unknown msg_bytes = [] prev_byte_end = 0.0 total_length = None def get_msg_len(msg_bytes): # Try to determine message length if len(msg_bytes) > 0: if msg_bytes[0].data & 0x80: #ISO14230 # Get length from first byte length = msg_bytes[0].data & 0x3F total_length = 3 + length + 1 if length == 0: # Header is 4-bytes long if len(msg_bytes) >= 2: # 2nd byte is present length = msg_bytes[1].data total_length = 4 + length + 1 else: return None return total_length else: #ISO9141 return None else: return None def build_msg(protocol, msg_bytes): # determine header length header_length = 3 if protocol == KLineProtocol.ISO14230 and msg_bytes[0].data == 0x80: header_length = 4 # Message must be at least h_l + 1 + 1 = 5 or 6 bytes long if len(msg_bytes) >= header_length + 2: sid_byte = msg_bytes[header_length] msg_type = obd.OBD2MsgType.Request if sid_byte.data <= 0x3F else obd.OBD2MsgType.Response if protocol == KLineProtocol.ISO9141: header = ISO9141Header(option=msg_bytes[0], target=msg_bytes[1], source=msg_bytes[2]) elif protocol == KLineProtocol.ISO14230: if header_length == 4: length = msg_bytes[1] target = msg_bytes[2] source = msg_bytes[3] else: length = None target = msg_bytes[1] source = msg_bytes[2] header = ISO14230Header(option=msg_bytes[0], target=target, source=source, \ length=length) else: # Unknown protocol header = ISO9141Header(option=msg_bytes[0], target=msg_bytes[1], source=msg_bytes[2]) msg = KLineMessage(msg_type, header, msg_bytes[header_length:-1], msg_bytes[-1]) status = KLineStreamStatus.ChecksumError if not msg.checksum_good() else stream.StreamStatus.Ok obd_msg = KLineStreamMessage(msg, status) obd_msg.annotate('frame', {}, stream.AnnotationFormat.Hidden) for b in msg_bytes: obd_msg.subrecords.append(b.subrecords[1]) obd_msg.subrecords[-1].annotate('data', {'_bits':8}, stream.AnnotationFormat.General) obd_msg.subrecords[-1].kind = 'data' for sr in obd_msg.subrecords[0:header_length]: sr.style = 'addr' sr.kind = 'header' obd_msg.subrecords[-1].style = 'check' obd_msg.subrecords[-1].status = status obd_msg.subrecords[-1].kind = 'checksum' else: # Not enough bytes for proper K-line message msg = KLineMessage(obd.OBD2MsgType.Unknown, None, msg_bytes, None) obd_msg = KLineStreamMessage(msg, KLineStreamStatus.InvalidMessageError) for b in msg_bytes: obd_msg.subrecords.append(b.subrecords[1]) obd_msg.subrecords[-1].annotate('misc', {'_bits':8}, stream.AnnotationFormat.General) return obd_msg for r in records_it: if r.data == 0x00 and r.status == uart.UARTStreamStatus.FramingError: state = S_WAKEUP wakeup_edges.append(r.start_time) continue if state == S_WAKEUP: if not (r.data == 0x00 and r.status == uart.UARTStreamStatus.FramingError): # not a BRK byte; wakeup has ended bounds = (wakeup_edges[0], r.start_time) wu = KLineWakeup(bounds, wakeup_edges) wu.annotate('frame', {}, stream.AnnotationFormat.Hidden) yield wu wakeup_edges = [] if r.data == 0x55: # ISO9141 sync byte protocol = KLineProtocol.ISO9141 init_bytes.append(r) init_bytes_left = 4 state = S_INIT elif r.data == 0xc1: # KWP2000 start comm. format byte protocol = KLineProtocol.ISO14230 msg_bytes.append(r) state = S_GET_MSG prev_byte_end = r.end_time else: # Unexpected data se = stream.StreamEvent(r.start_time, kind='Bad init', \ status=KLineStreamStatus.BadInitError) yield se # We will just assume this is the start of a new message msg_bytes.append(r) state = S_GET_MSG prev_byte_end = r.end_time elif state == S_INIT: # After 0x55 there are 4 more bytes remaining in the init sequence # Key 1, Key 2, ~Key 2, ~Wakeup (0xCC typ.) init_bytes.append(r) init_bytes_left -= 1 if init_bytes_left == 0: yield ISO9141Init(init_bytes) init_bytes = [] state = S_START_MSG prev_byte_end = r.end_time elif state == S_START_MSG: protocol = KLineProtocol.ISO14230 if r.data & 0x80 else KLineProtocol.ISO9141 msg_bytes.append(r) state = S_GET_MSG prev_byte_end = r.end_time elif state == S_GET_MSG: if len(msg_bytes) == 2: total_length = get_msg_len(msg_bytes) #print('### byte:', eng.eng_si(r.start_time, 's'), \ # eng.eng_si(r.start_time - prev_byte_end, 's'), hex(r.data)) if (r.start_time - prev_byte_end > min_message_interval and len(msg_bytes) > 0) or \ (total_length is not None and len(msg_bytes) == total_length): # Previous message ended msg = build_msg(protocol, msg_bytes) yield msg msg_bytes = [] total_length = None # Determine the protocol of the next message protocol = KLineProtocol.ISO14230 if r.data & 0x80 else KLineProtocol.ISO9141 msg_bytes.append(r) prev_byte_end = r.end_time # Handle final message if len(msg_bytes) > 0: msg = build_msg(protocol, msg_bytes) yield msg msg_bytes = [] # There may have been a partial wakeup pattern at the end of the stream if len(wakeup_edges) > 0: bounds = (wakeup_edges[0], prev_byte_end) wu = KLineWakeup(bounds, wakeup_edges) wu.annotate('frame', {}, stream.AnnotationFormat.Hidden) yield wu
def test_uart_hello(self): bits = 8 polarity = uart.UARTConfig.IdleLow parity = 'even' stop_bits = 2 message = 'Hello, world!' samples, sample_period, start_time = tsup.read_bin_file( 'test/data/uart_hello_8e2.bin') txd = stream.samples_to_sample_stream(samples, sample_period, start_time) frames = list( uart.uart_decode(txd, bits=bits, polarity=polarity, parity=parity, stop_bits=stop_bits)) ok_status = True for f in frames: if f.nested_status() != stream.StreamStatus.Ok: ok_status = False break self.assertTrue(ok_status, 'Decoded data has non-Ok status') # Check the message bytes dmsg = ''.join([chr(d.data) for d in frames]) self.assertEqual( message, dmsg, 'Message mismatch. Expected: "{}" Got: "{}"'.format(message, dmsg)) bits = 8 polarity = uart.UARTConfig.IdleLow parity = None stop_bits = 1 message = 'Hello, world!' samples, sample_period, start_time = tsup.read_bin_file( 'test/data/uart_hello.bin') txd = stream.samples_to_sample_stream(samples, sample_period, start_time) frames = list( uart.uart_decode(txd, bits=bits, polarity=polarity, parity=parity, stop_bits=stop_bits)) ok_status = True for f in frames: if f.nested_status() != stream.StreamStatus.Ok: ok_status = False break self.assertTrue(ok_status, 'Decoded data has non-Ok status') # Check the message bytes dmsg = ''.join([chr(d.data) for d in frames]) self.assertEqual( message, dmsg, 'Message 2 mismatch. Expected: "{}" Got: "{}"'.format( message, dmsg))
def iso_k_line_decode(stream_data, min_message_interval=7.0e-3, logic_levels=None, stream_type=stream.StreamType.Samples): '''Decode ISO9141 and ISO14230 data streams This is a generator function that can be used in a pipeline of waveform procesing operations. Sample streams are a sequence of SampleChunk Objects. Edge streams are a sequence of 2-tuples of (time, int) pairs. The type of stream is identified by the stream_type parameter. Sample streams will be analyzed to find edge transitions representing 0 and 1 logic states of the waveforms. With sample streams, an initial block of data is consumed to determine the most likely logic levels in the signal. stream_data (iterable of SampleChunk objects or (float, int) pairs) A sample stream or edge stream of K-line messages. min_message_interval (float) The minimum time between bytes for identifying the end and start of messages. For ISO14230 this is used in addition to the message length encoded in the header. logic_levels ((float, float) or None) Optional pair that indicates (low, high) logic levels of the sample stream. When present, auto level detection is disabled. This has no effect on edge streams. stream_type (streaming.StreamType) A StreamType value indicating that the stream parameter represents either Samples or Edges Yields a series of KLineStreamMessage objects. Raises AutoLevelError if stream_type = Samples and the logic levels cannot be determined. ''' if stream_type == stream.StreamType.Samples: if logic_levels is None: samp_it, logic_levels = check_logic_levels(stream_data) else: samp_it = stream_data edges = find_edges(samp_it, logic_levels, hysteresis=0.4) else: # the stream is already a list of edges edges = stream_data bits = 8 parity = None stop_bits = 1 polarity = uart.UARTConfig.IdleHigh baud_rate = 10400 records_it = uart.uart_decode(edges, bits, parity, stop_bits, lsb_first=True, \ polarity=polarity, baud_rate=baud_rate, logic_levels=logic_levels, stream_type=stream.StreamType.Edges) S_WAKEUP = 0 S_INIT = 1 S_START_MSG = 2 S_GET_MSG = 3 state = S_GET_MSG wakeup_edges = [] init_bytes = [] protocol = KLineProtocol.Unknown msg_bytes = [] prev_byte_end = 0.0 total_length = None def get_msg_len(msg_bytes): # Try to determine message length if len(msg_bytes) > 0: if msg_bytes[0].data & 0x80: #ISO14230 # Get length from first byte length = msg_bytes[0].data & 0x3F total_length = 3 + length + 1 if length == 0: # Header is 4-bytes long if len(msg_bytes) >= 2: # 2nd byte is present length = msg_bytes[1].data total_length = 4 + length + 1 else: return None return total_length else: #ISO9141 return None else: return None def build_msg(protocol, msg_bytes): # determine header length header_length = 3 if protocol == KLineProtocol.ISO14230 and msg_bytes[0].data == 0x80: header_length = 4 # Message must be at least h_l + 1 + 1 = 5 or 6 bytes long if len(msg_bytes) >= header_length + 2: sid_byte = msg_bytes[header_length] msg_type = obd.OBD2MsgType.Request if sid_byte.data <= 0x3F else obd.OBD2MsgType.Response if protocol == KLineProtocol.ISO9141: header = ISO9141Header(option=msg_bytes[0], target=msg_bytes[1], source=msg_bytes[2]) elif protocol == KLineProtocol.ISO14230: if header_length == 4: length = msg_bytes[1] target = msg_bytes[2] source = msg_bytes[3] else: length = None target = msg_bytes[1] source = msg_bytes[2] header = ISO14230Header(option=msg_bytes[0], target=target, source=source, \ length=length) else: # Unknown protocol header = ISO9141Header(option=msg_bytes[0], target=msg_bytes[1], source=msg_bytes[2]) msg = KLineMessage(msg_type, header, msg_bytes[header_length:-1], msg_bytes[-1]) status = KLineStreamStatus.ChecksumError if not msg.checksum_good( ) else stream.StreamStatus.Ok obd_msg = KLineStreamMessage(msg, status) obd_msg.annotate('frame', {}, stream.AnnotationFormat.Hidden) for b in msg_bytes: obd_msg.subrecords.append(b.subrecords[1]) obd_msg.subrecords[-1].annotate( 'data', {'_bits': 8}, stream.AnnotationFormat.General) obd_msg.subrecords[-1].kind = 'data' for sr in obd_msg.subrecords[0:header_length]: sr.style = 'addr' sr.kind = 'header' obd_msg.subrecords[-1].style = 'check' obd_msg.subrecords[-1].status = status obd_msg.subrecords[-1].kind = 'checksum' else: # Not enough bytes for proper K-line message msg = KLineMessage(obd.OBD2MsgType.Unknown, None, msg_bytes, None) obd_msg = KLineStreamMessage(msg, KLineStreamStatus.InvalidMessageError) for b in msg_bytes: obd_msg.subrecords.append(b.subrecords[1]) obd_msg.subrecords[-1].annotate( 'misc', {'_bits': 8}, stream.AnnotationFormat.General) return obd_msg for r in records_it: if r.data == 0x00 and r.status == uart.UARTStreamStatus.FramingError: state = S_WAKEUP wakeup_edges.append(r.start_time) continue if state == S_WAKEUP: if not (r.data == 0x00 and r.status == uart.UARTStreamStatus.FramingError): # not a BRK byte; wakeup has ended bounds = (wakeup_edges[0], r.start_time) wu = KLineWakeup(bounds, wakeup_edges) wu.annotate('frame', {}, stream.AnnotationFormat.Hidden) yield wu wakeup_edges = [] if r.data == 0x55: # ISO9141 sync byte protocol = KLineProtocol.ISO9141 init_bytes.append(r) init_bytes_left = 4 state = S_INIT elif r.data == 0xc1: # KWP2000 start comm. format byte protocol = KLineProtocol.ISO14230 msg_bytes.append(r) state = S_GET_MSG prev_byte_end = r.end_time else: # Unexpected data se = stream.StreamEvent(r.start_time, kind='Bad init', \ status=KLineStreamStatus.BadInitError) yield se # We will just assume this is the start of a new message msg_bytes.append(r) state = S_GET_MSG prev_byte_end = r.end_time elif state == S_INIT: # After 0x55 there are 4 more bytes remaining in the init sequence # Key 1, Key 2, ~Key 2, ~Wakeup (0xCC typ.) init_bytes.append(r) init_bytes_left -= 1 if init_bytes_left == 0: yield ISO9141Init(init_bytes) init_bytes = [] state = S_START_MSG prev_byte_end = r.end_time elif state == S_START_MSG: protocol = KLineProtocol.ISO14230 if r.data & 0x80 else KLineProtocol.ISO9141 msg_bytes.append(r) state = S_GET_MSG prev_byte_end = r.end_time elif state == S_GET_MSG: if len(msg_bytes) == 2: total_length = get_msg_len(msg_bytes) #print('### byte:', eng.eng_si(r.start_time, 's'), \ # eng.eng_si(r.start_time - prev_byte_end, 's'), hex(r.data)) if (r.start_time - prev_byte_end > min_message_interval and len(msg_bytes) > 0) or \ (total_length is not None and len(msg_bytes) == total_length): # Previous message ended msg = build_msg(protocol, msg_bytes) yield msg msg_bytes = [] total_length = None # Determine the protocol of the next message protocol = KLineProtocol.ISO14230 if r.data & 0x80 else KLineProtocol.ISO9141 msg_bytes.append(r) prev_byte_end = r.end_time # Handle final message if len(msg_bytes) > 0: msg = build_msg(protocol, msg_bytes) yield msg msg_bytes = [] # There may have been a partial wakeup pattern at the end of the stream if len(wakeup_edges) > 0: bounds = (wakeup_edges[0], prev_byte_end) wu = KLineWakeup(bounds, wakeup_edges) wu.annotate('frame', {}, stream.AnnotationFormat.Hidden) yield wu
def lin_decode(stream_data, enhanced_ids=None, baud_rate=None, logic_levels=None,\ stream_type=stream.StreamType.Samples, param_info=None): '''Decode a LIN data stream This is a generator function that can be used in a pipeline of waveform procesing operations. Sample streams are a sequence of SampleChunk Objects. Edge streams are a sequence of 2-tuples of (time, int) pairs. The type of stream is identified by the stream_type parameter. Sample streams will be analyzed to find edge transitions representing 0 and 1 logic states of the waveforms. With sample streams, an initial block of data is consumed to determine the most likely logic levels in the signal. stream_data (iterable of SampleChunk objects or (float, int) pairs) A sample stream or edge stream representing a LIN signal. enhanced_ids (sequence of int or None) An optional sequence of frame IDs that are to use LIN 2.x enhanced checksums. If None, the checksum type is guessed by trying both methods to see if one matches decoded checksum. baud_rate (int or None) The baud rate of the stream. If None, the first 50 edges will be analyzed to automatically determine the most likely baud rate for the stream. On average 50 edges will occur after 11 bytes have been captured. logic_levels ((float, float) or None) Optional pair that indicates (low, high) logic levels of the sample stream. When present, auto level detection is disabled. This has no effect on edge streams. stream_type (streaming.StreamType) A StreamType value indicating that the stream parameter represents either Samples or Edges param_info (dict or None) An optional dictionary object that is used to monitor the results of automatic baud detection. Yields a series of LINStreamFrame objects. Raises AutoLevelError if stream_type = Samples and the logic levels cannot be determined. Raises AutoBaudError if auto-baud is active and the baud rate cannot be determined. ''' if stream_type == stream.StreamType.Samples: if logic_levels is None: samp_it, logic_levels = ripyl.decode.check_logic_levels(stream_data) else: samp_it = stream_data edges = ripyl.decode.find_edges(samp_it, logic_levels, hysteresis=0.4) else: # the stream is already a list of edges edges = stream_data bits = 8 parity = None stop_bits = 1 polarity = uart.UARTConfig.IdleHigh records_it = uart.uart_decode(edges, bits, parity, stop_bits, lsb_first=True, \ polarity=polarity, baud_rate=baud_rate, use_std_baud=False, logic_levels=logic_levels, \ stream_type=stream.StreamType.Edges, param_info=param_info) S_NEED_BREAK = 0 S_SYNC = 1 S_DATA = 2 state = S_NEED_BREAK raw_bytes = [] frame_start = 0.0 next_frame_start = 0.0 frame_complete = False for r in records_it: # Look for a break condition if state == S_NEED_BREAK: if r.data == 0 and r.status == uart.UARTStreamStatus.FramingError: frame_start = r.start_time state = S_SYNC elif state == S_SYNC: if r.data == 0x55: raw_bytes = [] state = S_DATA else: state = S_NEED_BREAK elif state == S_DATA: # Collect frame bytes until we see another break or we have 10 bytes (1 pid + 8 data + 1 checksum) if r.data == 0 and r.status == uart.UARTStreamStatus.FramingError: next_frame_start = r.start_time frame_complete = True state = S_SYNC else: raw_bytes.append(r) if len(raw_bytes) >= 10: frame_complete = True state = S_NEED_BREAK if frame_complete: sf = _make_lin_frame(raw_bytes, frame_start, enhanced_ids) frame_complete = False frame_start = next_frame_start raw_bytes = [] yield sf if len(raw_bytes) > 0: # Partial frame remains sf = _make_lin_frame(raw_bytes, frame_start, enhanced_ids) yield sf