예제 #1
0
    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')
예제 #2
0
    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))
예제 #3
0
    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))
예제 #4
0
    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')
예제 #5
0
 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))
예제 #6
0
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
예제 #7
0
    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
예제 #9
0
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