示例#1
0
    def parse_message(self, message):

        frames = message.frames

        if len(frames) == 1:
            frame = frames[0]

            if frame.type != self.FRAME_TYPE_SF:
                debug("Recieved lone frame not marked as single frame")
                return False

            # extract data, ignore PCI byte and anything after the marked length
            #             [      Frame       ]
            #                [     Data      ]
            # 00 00 07 E8 06 41 00 BE 7F B8 13 xx xx xx xx, anything else is ignored
            message.data = frame.data[1:1 + frame.data_len]

        else:
            # sort FF and CF into their own lists

            ff = []
            cf = []

            for f in frames:
                if f.type == self.FRAME_TYPE_FF:
                    ff.append(f)
                elif f.type == self.FRAME_TYPE_CF:
                    cf.append(f)
                else:
                    debug(
                        "Dropping frame in multi-frame response not marked as FF or CF"
                    )

            # check that we captured only one first-frame
            if len(ff) > 1:
                debug("Recieved multiple frames marked FF")
                return False
            elif len(ff) == 0:
                debug("Never received frame marked FF")
                return False

            # check that there was at least one consecutive-frame
            if len(cf) == 0:
                debug("Never received frame marked CF")
                return False

            # calculate proper sequence indices from the lower 4 bits given
            for prev, curr in zip(cf, cf[1:]):
                # Frame sequence numbers only specify the low order bits, so compute the
                # full sequence number from the frame number and the last sequence number seen:
                # 1) take the high order bits from the last_sn and low order bits from the frame
                seq = (prev.seq_index & ~0x0F) + (curr.seq_index)
                # 2) if this is more than 7 frames away, we probably just wrapped (e.g.,
                # last=0x0F current=0x01 should mean 0x11, not 0x01)
                if seq < prev.seq_index - 7:
                    # untested
                    seq += 0x10

                curr.seq_index = seq

            # sort the sequence indices
            cf = sorted(cf, key=lambda f: f.seq_index)

            # check contiguity, and that we aren't missing any frames
            indices = [f.seq_index for f in cf]
            if not contiguous(indices, 1, len(cf)):
                debug("Recieved multiline response with missing frames")
                return False

            # first frame:
            #             [       Frame         ]
            #             [PCI]                   <-- first frame has a 2 byte PCI
            #              [L ] [     Data      ] L = length of message in bytes
            # 00 00 07 E8 10 13 49 04 01 35 36 30

            # consecutive frame:
            #             [       Frame         ]
            #             []                       <-- consecutive frames have a 1 byte PCI
            #              N [       Data       ]  N = current frame number (rolls over to 0 after F)
            # 00 00 07 E8 21 32 38 39 34 39 41 43
            # 00 00 07 E8 22 00 00 00 00 00 00 31

            # original data:
            # [     specified message length (from first-frame)      ]
            # 49 04 01 35 36 30 32 38 39 34 39 41 43 00 00 00 00 00 00 31

            # on the first frame, skip PCI byte AND length code
            message.data = ff[0].data[2:]

            # now that they're in order, load/accumulate the data from each CF frame
            for f in cf:
                message.data += f.data[1:]  # chop off the PCI byte

            # chop to the correct size (as specified in the first frame)
            message.data = message.data[:ff[0].data_len]

        # chop off the Mode/PID bytes based on the mode number
        mode = message.data[0]
        if mode == 0x43:

            # TODO: confirm this logic. I don't have any raw test data for it yet

            # fetch the DTC count, and use it as a length code
            num_dtc_bytes = message.data[1] * 2

            # skip the PID byte and the DTC count,
            message.data = message.data[2:][:num_dtc_bytes]

        else:
            # skip the Mode and PID bytes
            #
            # single line response:
            #                      [  Data   ]
            # 00 00 07 E8 06 41 00 BE 7F B8 13
            #
            # OR, the data from a multiline response:
            #       [                     Data                       ]
            # 49 04 01 35 36 30 32 38 39 34 39 41 43 00 00 00 00 00 00
            message.data = message.data[2:]

        return True
示例#2
0
    def parse_message(self, message):

        frames = message.frames

        # len(frames) will always be >= 1 (see the caller, protocol.py)
        mode = frames[0].data[0]

        # test that all frames are responses to the same Mode (SID)
        if len(frames) > 1:
            if not all([mode == f.data[0] for f in frames[1:]]):
                logger.warning("Recieved frames from multiple commands")
                return False

        # legacy protocols have different re-assembly
        # procedures for different Modes

        # ~~~~
        # NOTE: THERE ARE HACKS IN HERE to make some output compatible with CAN
        #       since CAN is the standard, and this is considered legacy, I'm
        #       fixing ugly inconsistencies between the two protocols here.
        # ~~~~

        if mode == 0x43:
            # GET_DTC requests return frames with no PID or order bytes
            # accumulate all of the data, minus the Mode bytes of each frame

            # Ex.
            # insert faux-byte to mimic the CAN style DTC requests
            #            |
            #          [ |     Frame      ]
            # 48 6B 10 43 03 00 03 02 03 03 ck
            # 48 6B 10 43 03 04 00 00 00 00 ck
            #             [     Data      ]

            message.data = bytearray([0x43, 0x00]) # forge the mode byte and CAN's DTC_count byte
            for f in frames:
                message.data += f.data[1:]

        else:
            if len(frames) == 1:
                # return data, excluding the mode/pid bytes

                # Ex.
                #          [  Frame/Data   ]
                # 48 6B 10 41 00 BE 7F B8 13 ck

                message.data = frames[0].data

            else: # len(frames) > 1:
                # generic multiline requests carry an order byte

                # Ex.
                #          [      Frame       ]
                # 48 6B 10 49 02 01 00 00 00 31 ck
                # 48 6B 10 49 02 02 44 34 47 50 ck
                # 48 6B 10 49 02 03 30 30 52 35 ck
                # etc...         [] [  Data   ]

                # becomes:
                # 49 02 [] 00 00 00 31 44 34 47 50 30 30 52 35
                #       |  [         ] [         ] [         ]
                #  order byte is removed

                # sort the frames by the order byte
                frames = sorted(frames, key=lambda f: f.data[2])

                # check contiguity
                indices = [f.data[2] for f in frames]
                if not contiguous(indices, 1, len(frames)):
                    logger.warning("Recieved multiline response with missing frames")
                    return False

                # now that they're in order, accumulate the data from each frame

                # preserve the first frame's mode and PID bytes (for consistency with CAN)
                frames[0].data.pop(2) # remove the sequence byte
                message.data = frames[0].data

                # add the data from the remaining frames
                for f in frames[1:]:
                    message.data += f.data[3:] # loose the mode/pid/seq bytes

        return True
示例#3
0
    def parse_message(self, message):

        frames = message.frames

        # len(frames) will always be >= 1 (see the caller, protocol.py)
        mode = frames[0].data[0]

        # test that all frames are responses to the same Mode (SID)
        if len(frames) > 1:
            if not all([mode == f.data[0] for f in frames[1:]]):
                logger.debug("Recieved frames from multiple commands")
                return False

        # legacy protocols have different re-assembly
        # procedures for different Modes

        if mode == 0x43:
            # GET_DTC requests return frames with no PID or order bytes
            # accumulate all of the data, minus the Mode bytes of each frame

            # Ex.
            #          [       Frame      ]
            # 48 6B 10 43 03 00 03 02 03 03 ck
            # 48 6B 10 43 03 04 00 00 00 00 ck
            #             [     Data      ]

            for f in frames:
                message.data += f.data[1:]

        else:
            if len(frames) == 1:
                # return data, excluding the mode/pid bytes

                # Ex.
                #          [     Frame     ]
                # 48 6B 10 41 00 BE 7F B8 13 ck
                #                [  Data   ]

                message.data = frames[0].data[2:]

            else:  # len(frames) > 1:
                # generic multiline requests carry an order byte

                # Ex.
                #          [      Frame       ]
                # 48 6B 10 49 02 01 00 00 00 31 ck
                # 48 6B 10 49 02 02 44 34 47 50 ck
                # 48 6B 10 49 02 03 30 30 52 35 ck
                # etc...         [] [  Data   ]

                # sort the frames by the order byte
                frames = sorted(frames, key=lambda f: f.data[2])

                # check contiguity
                indices = [f.data[2] for f in frames]
                if not contiguous(indices, 1, len(frames)):
                    logger.debug(
                        "Recieved multiline response with missing frames")
                    return False

                # now that they're in order, accumulate the data from each frame
                for f in frames:
                    message.data += f.data[3:]  # loose the mode/pid/seq bytes

        return True
    def parse_message(self, message):

        frames = message.frames

        if len(frames) == 1:
            frame = frames[0]

            if frame.type != self.FRAME_TYPE_SF:
                logger.debug("Recieved lone frame not marked as single frame")
                return False

            # extract data, ignore PCI byte and anything after the marked length
            #             [      Frame       ]
            #                [     Data      ]
            # 00 00 07 E8 06 41 00 BE 7F B8 13 xx xx xx xx, anything else is ignored
            message.data = frame.data[1:1+frame.data_len]

        else:
            # sort FF and CF into their own lists

            ff = []
            cf = []

            for f in frames:
                if f.type == self.FRAME_TYPE_FF:
                    ff.append(f)
                elif f.type == self.FRAME_TYPE_CF:
                    cf.append(f)
                else:
                    logger.debug("Dropping frame in multi-frame response not marked as FF or CF")

            # check that we captured only one first-frame
            if len(ff) > 1:
                logger.debug("Recieved multiple frames marked FF")
                return False
            elif len(ff) == 0:
                logger.debug("Never received frame marked FF")
                return False

            # check that there was at least one consecutive-frame
            if len(cf) == 0:
                logger.debug("Never received frame marked CF")
                return False

            # calculate proper sequence indices from the lower 4 bits given
            for prev, curr in zip(cf, cf[1:]):
                # Frame sequence numbers only specify the low order bits, so compute the
                # full sequence number from the frame number and the last sequence number seen:
                # 1) take the high order bits from the last_sn and low order bits from the frame
                seq = (prev.seq_index & ~0x0F) + (curr.seq_index)
                # 2) if this is more than 7 frames away, we probably just wrapped (e.g.,
                # last=0x0F current=0x01 should mean 0x11, not 0x01)
                if seq < prev.seq_index - 7:
                    # untested
                    seq += 0x10

                curr.seq_index = seq

            # sort the sequence indices
            cf = sorted(cf, key=lambda f: f.seq_index)

            # check contiguity, and that we aren't missing any frames
            indices = [f.seq_index for f in cf]
            if not contiguous(indices, 1, len(cf)):
                logger.debug("Recieved multiline response with missing frames")
                return False


            # first frame:
            #             [       Frame         ]
            #             [PCI]                   <-- first frame has a 2 byte PCI
            #              [L ] [     Data      ] L = length of message in bytes
            # 00 00 07 E8 10 13 49 04 01 35 36 30


            # consecutive frame:
            #             [       Frame         ]
            #             []                       <-- consecutive frames have a 1 byte PCI
            #              N [       Data       ]  N = current frame number (rolls over to 0 after F)
            # 00 00 07 E8 21 32 38 39 34 39 41 43
            # 00 00 07 E8 22 00 00 00 00 00 00 31


            # original data:
            # [     specified message length (from first-frame)      ]
            # 49 04 01 35 36 30 32 38 39 34 39 41 43 00 00 00 00 00 00 31


            # on the first frame, skip PCI byte AND length code
            message.data = ff[0].data[2:]

            # now that they're in order, load/accumulate the data from each CF frame
            for f in cf:
                message.data += f.data[1:] # chop off the PCI byte

            # chop to the correct size (as specified in the first frame)
            message.data = message.data[:ff[0].data_len]


        # TODO: this is an ugly solution, maybe move mode/pid byte ignoring to the decoders?

        # chop off the Mode/PID bytes based on the mode number
        mode = message.data[0]
        if mode == 0x43:

            #    []
            # 43 03 11 11 22 22 33 33
            #       [DTC] [DTC] [DTC]

            # fetch the DTC count, and use it as a length code
            num_dtc_bytes = message.data[1] * 2

            # skip the PID byte and the DTC count,
            message.data = message.data[2:][:num_dtc_bytes]

        elif mode == 0x46:
            # the monitor test mode only has a mode number
            # the MID (mode 6's version of a PID) is repeated,
            # and handled in the decoder
            message.data  = message.data[1:]

        else:
            # skip the Mode and PID bytes
            #
            # single line response:
            #                      [  Data   ]
            # 00 00 07 E8 06 41 00 BE 7F B8 13
            #
            # OR, the data from a multiline response:
            #       [                     Data                       ]
            # 49 04 01 35 36 30 32 38 39 34 39 41 43 00 00 00 00 00 00
            message.data = message.data[2:]

        return True
    def parse_message(self, message):

        frames = message.frames

        # len(frames) will always be >= 1 (see the caller, protocol.py)
        mode = frames[0].data[0]
        
        # test that all frames are responses to the same Mode (SID)
        if len(frames) > 1:
            if not all([mode == f.data[0] for f in frames[1:]]):
                debug("Recieved frames from multiple commands")
                return False

        # legacy protocols have different re-assembly
        # procedures for different Modes 

        if mode == 0x43:
            # GET_DTC requests return frames with no PID or order bytes
            # accumulate all of the data, minus the Mode bytes of each frame

            # Ex.
            #          [       Frame      ]
            # 48 6B 10 43 03 00 03 02 03 03 ck
            # 48 6B 10 43 03 04 00 00 00 00 ck
            #             [     Data      ]

            for f in frames:
                message.data += f.data[1:]

        else:
            if len(frames) == 1:
                # return data, excluding the mode/pid bytes

                # Ex.
                #          [     Frame     ]
                # 48 6B 10 41 00 BE 7F B8 13 ck
                #                [  Data   ]

                message.data = frames[0].data[2:]

            else: # len(frames) > 1:
                # generic multiline requests carry an order byte

                # Ex.
                #          [      Frame       ]
                # 48 6B 10 49 02 01 00 00 00 31 ck
                # 48 6B 10 49 02 02 44 34 47 50 ck
                # 48 6B 10 49 02 03 30 30 52 35 ck
                # etc...         [] [  Data   ]

                # sort the frames by the order byte
                frames = sorted(frames, key=lambda f: f.data[2])

                # check contiguity
                indices = [f.data[2] for f in frames]
                if not contiguous(indices, 1, len(frames)):
                    debug("Recieved multiline response with missing frames")
                    return False

                # now that they're in order, accumulate the data from each frame
                for f in frames:
                    message.data += f.data[3:] # loose the mode/pid/seq bytes

        return True
示例#6
0
    def parse_message(self, message):

        frames = message.frames

        # len(frames) will always be >= 1 (see the caller, protocol.py)
        mode = frames[0].data[0]

        # test that all frames are responses to the same Mode (SID)
        if len(frames) > 1:
            if not all([mode == f.data[0] for f in frames[1:]]):
                logger.debug("Recieved frames from multiple commands")
                return False

        # legacy protocols have different re-assembly
        # procedures for different Modes

        # ~~~~
        # NOTE: THERE ARE HACKS IN HERE to make some output compatible with CAN
        #       since CAN is the standard, and this is considered legacy, I'm
        #       fixing ugly inconsistencies between the two protocols here.
        # ~~~~

        if mode == 0x43:
            # GET_DTC requests return frames with no PID or order bytes
            # accumulate all of the data, minus the Mode bytes of each frame

            # Ex.
            # insert faux-byte to mimic the CAN style DTC requests
            #            |
            #          [ |     Frame      ]
            # 48 6B 10 43 03 00 03 02 03 03 ck
            # 48 6B 10 43 03 04 00 00 00 00 ck
            #             [     Data      ]

            message.data = bytearray([0x43, 0x00]) # forge the mode byte and CAN's DTC_count byte
            for f in frames:
                message.data += f.data[1:]

        else:
            if len(frames) == 1:
                # return data, excluding the mode/pid bytes

                # Ex.
                #          [  Frame/Data   ]
                # 48 6B 10 41 00 BE 7F B8 13 ck

                message.data = frames[0].data

            else: # len(frames) > 1:
                # generic multiline requests carry an order byte

                # Ex.
                #          [      Frame       ]
                # 48 6B 10 49 02 01 00 00 00 31 ck
                # 48 6B 10 49 02 02 44 34 47 50 ck
                # 48 6B 10 49 02 03 30 30 52 35 ck
                # etc...         [] [  Data   ]

                # becomes:
                # 49 02 [] 00 00 00 31 44 34 47 50 30 30 52 35
                #       |  [         ] [         ] [         ]
                #  order byte is removed

                # sort the frames by the order byte
                frames = sorted(frames, key=lambda f: f.data[2])

                # check contiguity
                indices = [f.data[2] for f in frames]
                if not contiguous(indices, 1, len(frames)):
                    logger.debug("Recieved multiline response with missing frames")
                    return False

                # now that they're in order, accumulate the data from each frame

                # preserve the first frame's mode and PID bytes (for consistency with CAN)
                frames[0].data.pop(2) # remove the sequence byte
                message.data = frames[0].data

                # add the data from the remaining frames
                for f in frames[1:]:
                    message.data += f.data[3:] # loose the mode/pid/seq bytes

        return True
示例#7
0
    def create_message(self, frames, tx_id):

        message = Message(frames, tx_id)

        if len(message.frames) == 1:
            frame = frames[0]

            if frame.type != self.FRAME_TYPE_SF:
                debug("Recieved lone frame not marked as single frame")
                return None

            # extract data, ignore PCI byte and anything after the marked length
            message.data_bytes = frame.data_bytes[1:1 + frame.data_len]

        else:
            # sort FF and CF into their own lists

            ff = []
            cf = []

            for f in frames:
                if f.type == self.FRAME_TYPE_FF:
                    ff.append(f)
                elif f.type == self.FRAME_TYPE_CF:
                    cf.append(f)
                else:
                    debug(
                        "Dropping frame in multi-frame response not marked as FF or CF"
                    )

            # check that we captured only one first-frame
            if len(ff) > 1:
                debug("Recieved multiple frames marked FF")
                return None
            elif len(ff) == 0:
                debug("Never received frame marked FF")
                return None

            # check that there was at least one consecutive-frame
            if len(cf) == 0:
                debug("Never received frame marked CF")
                return None

            # calculate proper sequence indices from the lower 4 bits given
            for prev, curr in zip(cf, cf[1:]):
                # Frame sequence numbers only specify the low order bits, so compute the
                # full sequence number from the frame number and the last sequence number seen:
                # 1) take the high order bits from the last_sn and low order bits from the frame
                seq = (prev.seq_index & ~0x0F) + (curr.seq_index)
                # 2) if this is more than 7 frames away, we probably just wrapped (e.g.,
                # last=0x0F current=0x01 should mean 0x11, not 0x01)
                if seq < prev.seq_index - 7:
                    # untested
                    seq += 0x10

                curr.seq_index = seq

            # sort the sequence indices
            cf = sorted(cf, key=lambda f: f.seq_index)

            # check contiguity
            indices = [f.seq_index for f in cf]
            if not contiguous(indices, 1, len(cf)):
                debug("Recieved multiline response with missing frames")
                return None

            # on the first frame, skip PCI byte AND length code
            message.data_bytes += ff[0].data_bytes[2:]

            # now that they're in order, load/accumulate the data from each CF frame
            for f in cf:
                message.data_bytes += f.data_bytes[1:]  # chop off the PCI byte

        # chop off the Mode/PID bytes based on the mode number
        mode = message.data_bytes[0]
        if mode == 0x43:

            # fetch the DTC count, and use it as a length code
            num_dtc_bytes = message.data_bytes[1] * 2

            # skip the PID byte and the DTC count,
            message.data_bytes = message.data_bytes[2:][:num_dtc_bytes]

        else:
            # handles cases when there is both a Mode and PID byte
            message.data_bytes = message.data_bytes[2:]

        return message
示例#8
0
    def create_message(self, frames, tx_id):

        message = Message(frames, tx_id)

        if len(message.frames) == 1:
            frame = frames[0]

            if frame.type != self.FRAME_TYPE_SF:
                debug("Recieved lone frame not marked as single frame")
                return None

            # extract data, ignore PCI byte and anything after the marked length
            message.data_bytes = frame.data_bytes[1:1+frame.data_len]

        else:
            # sort FF and CF into their own lists

            ff = []
            cf = []

            for f in frames:
                if f.type == self.FRAME_TYPE_FF:
                    ff.append(f)
                elif f.type == self.FRAME_TYPE_CF:
                    cf.append(f)
                else:
                    debug("Dropping frame in multi-frame response not marked as FF or CF")

            # check that we captured only one first-frame
            if len(ff) > 1:
                debug("Recieved multiple frames marked FF")
                return None
            elif len(ff) == 0:
                debug("Never received frame marked FF")
                return None

            # check that there was at least one consecutive-frame
            if len(cf) == 0:
                debug("Never received frame marked CF")
                return None

            # calculate proper sequence indices from the lower 4 bits given
            for prev, curr in zip(cf, cf[1:]):
                # Frame sequence numbers only specify the low order bits, so compute the
                # full sequence number from the frame number and the last sequence number seen:
                # 1) take the high order bits from the last_sn and low order bits from the frame
                seq = (prev.seq_index & ~0x0F) + (curr.seq_index)
                # 2) if this is more than 7 frames away, we probably just wrapped (e.g.,
                # last=0x0F current=0x01 should mean 0x11, not 0x01)
                if seq < prev.seq_index - 7:
                    # untested
                    seq += 0x10

                curr.seq_index = seq

            # sort the sequence indices
            cf = sorted(cf, key=lambda f: f.seq_index)

            # check contiguity
            indices = [f.seq_index for f in cf]
            if not contiguous(indices, 1, len(cf)):
                debug("Recieved multiline response with missing frames")
                return None


            # on the first frame, skip PCI byte AND length code
            message.data_bytes += ff[0].data_bytes[2:]

            # now that they're in order, load/accumulate the data from each CF frame
            for f in cf:
                message.data_bytes += f.data_bytes[1:] # chop off the PCI byte


        # chop off the Mode/PID bytes based on the mode number
        mode = message.data_bytes[0]
        if mode == 0x43:

            # fetch the DTC count, and use it as a length code
            num_dtc_bytes = message.data_bytes[1] * 2

            # skip the PID byte and the DTC count,
            message.data_bytes = message.data_bytes[2:][:num_dtc_bytes]

        else:
            # handles cases when there is both a Mode and PID byte
            message.data_bytes = message.data_bytes[2:]

        return message