예제 #1
0
    def _data_transfer_handler(self, msg):
        logger.debug("_data_transfer_handler:")
        msg_source = msg.arbitration_id.source_address
        pdu_specific = msg.arbitration_id.pgn.pdu_specific

        if msg_source in self._incomplete_received_pdus:

            logger.debug("in self._incomplete_received_pdus:")
            if pdu_specific in self._incomplete_received_pdus[msg_source]:
                logger.debug("in self._incomplete_received_pdus[msg_source]:")
                self._incomplete_received_pdus[msg_source][
                    pdu_specific].data.extend(msg.data[1:])
                total = self._incomplete_received_pdu_lengths[msg_source][
                    pdu_specific]["total"]
                if len(self._incomplete_received_pdus[msg_source]
                       [pdu_specific].data) >= total:
                    logger.debug(
                        "allReceived: %s" %
                        type(self._incomplete_received_pdus[msg_source]))
                    logger.debug("allReceived: %s" % pprint.pformat(
                        self._incomplete_received_pdus[msg_source]))
                    logger.debug(
                        "allReceived: %s from 0x%x" %
                        (type(self._incomplete_received_pdus[msg_source]
                              [pdu_specific]), pdu_specific))
                    logger.debug("allReceived: %s" %
                                 (self._incomplete_received_pdus[msg_source]
                                  [pdu_specific]))
                    if pdu_specific == DESTINATION_ADDRESS_GLOBAL:
                        logger.debug(
                            "pdu_specific == DESTINATION_ADDRESS_GLOBAL")
                        # Looks strange but makes sense - in the absence of explicit flow control,
                        # the last CAN packet in a long message *is* the end of message acknowledgement
                        return self._process_eom_ack(msg)

                    # Find a Node object so we can search its list of known node addresses for this node
                    # so we can find if we are responsible for sending the EOM ACK message
                    # TODO: Was self.j1939_notifier.listeners

                    send_ack = any(
                        True
                        for (_listener, l_notifier) in self.node_queue_list
                        if isinstance(_listener, Node) and (
                            _listener.address == pdu_specific
                            or pdu_specific in _listener.address_list))

                    #send_ack = any(True for l in self.can_notifier.listeners
                    #               if isinstance(l, Node) and (l.address == pdu_specific or
                    #                                           pdu_specific in l.address_list))
                    if send_ack:
                        arbitration_id = ArbitrationID()
                        arbitration_id.pgn.value = PGN_TP_CONNECTION_MANAGEMENT
                        arbitration_id.pgn.pdu_specific = msg_source
                        arbitration_id.source_address = pdu_specific
                        arbitration_id.destination_address = 0x17

                        total_length = self._incomplete_received_pdu_lengths[
                            msg_source][pdu_specific]["total"]
                        _num_packages = self._incomplete_received_pdu_lengths[
                            msg_source][pdu_specific]["num_packages"]
                        pgn = self._incomplete_received_pdus[msg_source][
                            pdu_specific].arbitration_id.pgn
                        pgn_msb = ((pgn.value & 0xFF0000) >> 16)
                        _pgn_middle = ((pgn.value & 0x00FF00) >> 8)
                        _pgn_lsb = 0

                        logger.debug(
                            "in send_ack: arbitration_id=[%s], can_id=[%x], destAdder=0x%0x"
                            % (arbitration_id, int(arbitration_id.can_id),
                               arbitration_id.destination_address))
                        logger.debug("in send_ack: " % ())
                        div, mod = divmod(total_length, 256)
                        can_message = Message(
                            arbitration_id=arbitration_id.can_id,
                            extended_id=True,
                            dlc=8,
                            data=[
                                CM_MSG_TYPE_EOM_ACK,
                                mod,  # total_length % 256,
                                div,  # total_length / 256,
                                _num_packages,
                                0xFF,
                                _pgn_lsb,
                                _pgn_middle,
                                pgn_msb
                            ])
                        try:
                            self.can_bus.send(can_message)
                        except CanError:
                            if self._ignore_can_send_error:
                                pass
                            raise

                    logger.debug("_data_transfer_handler: returning %s" %
                                 (msg))
                    return self._process_eom_ack(msg)
예제 #2
0
    def _process_rts(self, msg):
        logger.debug("process_rts, source=0x%x" %
                     (msg.arbitration_id.source_address))
        if msg.arbitration_id.source_address not in self._incomplete_received_pdus:
            self._incomplete_received_pdus[
                msg.arbitration_id.source_address] = {}
            self._incomplete_received_pdu_lengths[
                msg.arbitration_id.source_address] = {}

        # Delete any previous messages that were not finished correctly
        if msg.arbitration_id.pgn.pdu_specific in self._incomplete_received_pdus[
                msg.arbitration_id.source_address]:
            del self._incomplete_received_pdus[
                msg.arbitration_id.source_address][
                    msg.arbitration_id.pgn.pdu_specific]
            del self._incomplete_received_pdu_lengths[
                msg.arbitration_id.source_address][
                    msg.arbitration_id.pgn.pdu_specific]

        if msg.data[0] == CM_MSG_TYPE_BAM:
            logger.debug("CM_MSG_TYPE_BAM")
            self._incomplete_received_pdus[
                msg.arbitration_id.source_address][0xFF] = self._pdu_type()
            self._incomplete_received_pdus[msg.arbitration_id.source_address][
                0xFF].arbitration_id.pgn.value = int(
                    ("%.2X%.2X%.2X" % (msg.data[7], msg.data[6], msg.data[5])),
                    16)
            if self._incomplete_received_pdus[
                    msg.arbitration_id.source_address][
                        0xFF].arbitration_id.pgn.is_destination_specific:
                self._incomplete_received_pdus[msg.arbitration_id.source_address][
                    0xFF].arbitration_id.pgn.pdu_specific = msg.arbitration_id.pgn.pdu_specific
            self._incomplete_received_pdus[msg.arbitration_id.source_address][
                0xFF].arbitration_id.source_address = msg.arbitration_id.source_address
            self._incomplete_received_pdus[
                msg.arbitration_id.source_address][0xFF].data = []
            _message_size = int("%.2X%.2X" % (msg.data[2], msg.data[1]), 16)
            self._incomplete_received_pdu_lengths[
                msg.arbitration_id.source_address][0xFF] = {
                    "total": _message_size,
                    "chunk": 255,
                    "num_packages": msg.data[3],
                }
        else:
            logger.debug("not CM_MSG_TYPE_BAM, source=0x%x" %
                         (msg.arbitration_id.source_address))
            self._incomplete_received_pdus[msg.arbitration_id.source_address][
                msg.arbitration_id.pgn.pdu_specific] = self._pdu_type()
            self._incomplete_received_pdus[msg.arbitration_id.source_address][
                msg.arbitration_id.pgn.
                pdu_specific].arbitration_id.pgn.value = int(
                    ("%.2X%.2X%.2X" % (msg.data[7], msg.data[6], msg.data[5])),
                    16)
            if self._incomplete_received_pdus[msg.arbitration_id.source_address][
                    msg.arbitration_id.pgn.
                    pdu_specific].arbitration_id.pgn.is_destination_specific:
                self._incomplete_received_pdus[msg.arbitration_id.source_address][
                    msg.arbitration_id.pgn.
                    pdu_specific].arbitration_id.pgn.pdu_specific = msg.arbitration_id.pgn.pdu_specific
            self._incomplete_received_pdus[msg.arbitration_id.source_address][
                msg.arbitration_id.pgn.
                pdu_specific].arbitration_id.source_address = msg.arbitration_id.source_address
            self._incomplete_received_pdus[msg.arbitration_id.source_address][
                msg.arbitration_id.pgn.pdu_specific].data = []
        _message_size = int("%.2X%.2X" % (msg.data[2], msg.data[1]), 16)
        self._incomplete_received_pdu_lengths[
            msg.arbitration_id.source_address][
                msg.arbitration_id.pgn.pdu_specific] = {
                    "total": _message_size,
                    "chunk": 255,
                    "num_packages": msg.data[3],
                }

        if msg.data[0] != CM_MSG_TYPE_BAM:
            logger.debug("not CM_MSG_TYPE_BAM--2")
            logger.debug("self.can_notifier.listeners = %s" %
                         self.can_notifier.listeners)
            logger.debug("self.node_queue_list = %s" % self.node_queue_list)

            #for _listener in self.can_notifier.listeners:
            for (_listener, l_notifier) in self.node_queue_list:
                logger.debug("MIL2: _listner/l_notifier = %s/%s" %
                             (_listener, l_notifier))
                if isinstance(_listener, Node):
                    logger.debug("6, dest=0x%x" %
                                 (msg.arbitration_id.source_address))
                    # find a Node object so we can search its list of known node addresses
                    # for this node - if we find it we are responsible for sending the CTS message
                    logger.debug("MIL3: Node: %s" % (Node))
                    logger.debug("MIL3: _listener.address: %s" %
                                 (_listener.address))
                    logger.debug(
                        "MIL3: msg.arbitration_id.pgn.pdu_specific: %s" %
                        (msg.arbitration_id.pgn.pdu_specific))
                    logger.debug("MIL3: _listener.address_list: %s" %
                                 (_listener.address_list))
                    if _listener.address == msg.arbitration_id.pgn.pdu_specific or \
                            msg.arbitration_id.pgn.pdu_specific in _listener.address_list:
                        _cts_arbitration_id = ArbitrationID(
                            source_address=msg.arbitration_id.pgn.pdu_specific)
                        _cts_arbitration_id.pgn.value = PGN_TP_CONNECTION_MANAGEMENT
                        _cts_arbitration_id.pgn.pdu_specific = msg.arbitration_id.source_address
                        _cts_arbitration_id.destination_address = msg.arbitration_id.source_address
                        _data = [0x11, msg.data[4], 0x01, 0xFF, 0xFF]
                        _data.extend(msg.data[5:])
                        logger.debug("send CTS: AID: %s" % _cts_arbitration_id)
                        cts_msg = Message(
                            extended_id=True,
                            arbitration_id=_cts_arbitration_id.can_id,
                            data=_data,
                            dlc=8)

                        # send clear to send
                        logger.debug("send CTS: %s" % cts_msg)
                        try:
                            self.can_bus.send(cts_msg)
                        except CanError:
                            if self._ignore_can_send_error:
                                pass
                            raise
                        return
예제 #3
0
    def send(self, msg, timeout=None):
        logger.info("j1939.send: msg=%s" % msg)
        messages = []
        if len(msg.data) > 8:
            logger.info("j1939.send: message is > than 8 bytes")
            # Making a copy of the PDU so that the original
            # is not altered by the data padding.
            pdu = copy.deepcopy(msg)
            pdu.data = bytearray(pdu.data)

            logger.info("j1939.send: Copied msg = %s" % pdu)
            pdu_length_lsb, pdu_length_msb = divmod(len(pdu.data), 256)

            while len(pdu.data) % 7 != 0:
                pdu.data += b'\xFF'

            logger.info("j1939.send: padded msg (mod 7) = %s" % pdu)
            logger.info("MIL8:---------------------")

            #
            # segment the longer message into 7 byte segments.  We need to prefix each
            # data[0] with a sequence number for the transfer
            #
            for i, segment in enumerate(pdu.data_segments(segment_length=7)):
                arbitration_id = copy.deepcopy(pdu.arbitration_id)
                arbitration_id.pgn.value = PGN_TP_DATA_TRANSFER

                logger.info(
                    "MIL8: j1939.send: i=%d, pdu.arbitration_id.pgn.is_destination_specific=%d, data=%s"
                    % (i, pdu.arbitration_id.pgn.is_destination_specific,
                       segment))

                if pdu.arbitration_id.pgn.is_destination_specific and \
                   pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL:

                    arbitration_id.pgn.pdu_specific = pdu.arbitration_id.pgn.pdu_specific
                else:
                    arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL
                    arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL

                logger.info("MIL8: j1939.send: segment=%d, arb = %s" %
                            (i, arbitration_id))
                message = Message(arbitration_id=arbitration_id.can_id,
                                  extended_id=True,
                                  dlc=(len(segment) + 1),
                                  data=(bytearray([i + 1]) + segment))
                messages.append(message)

            #
            # At this point we have the queued messages sequenced in 'messages'
            #
            logger.info(
                "MIL8: j1939.send: is_destination_specific=%d, destAddr=%s" %
                (pdu.arbitration_id.pgn.is_destination_specific,
                 pdu.arbitration_id.destination_address))
            logger.info("MIL8: j1939.send: messages=%s" % messages)

            if pdu.arbitration_id.pgn.is_destination_specific and \
               pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL:

                destination_address = pdu.arbitration_id.pgn.pdu_specific

                if pdu.arbitration_id.source_address in self._incomplete_transmitted_pdus:
                    if destination_address in self._incomplete_transmitted_pdus[
                            pdu.arbitration_id.source_address]:
                        logger.warning(
                            "Duplicate transmission of PDU:\n{}".format(pdu))
                else:
                    self._incomplete_transmitted_pdus[
                        pdu.arbitration_id.source_address] = {}

                # append the messages to the 'incomplete' list
                self._incomplete_transmitted_pdus[
                    pdu.arbitration_id.
                    source_address][destination_address] = messages

            else:
                destination_address = DESTINATION_ADDRESS_GLOBAL

            logger.debug("MIL8: rts arbitration id: src=%s, dest=%s" %
                         (pdu.source, destination_address))
            rts_arbitration_id = ArbitrationID(
                pgn=PGN_TP_CONNECTION_MANAGEMENT,
                source_address=pdu.source,
                destination_address=destination_address)
            rts_arbitration_id.pgn.pdu_specific = pdu.arbitration_id.pgn.pdu_specific

            temp_pgn = copy.deepcopy(pdu.arbitration_id.pgn)
            if temp_pgn.is_destination_specific:
                temp_pgn.value -= temp_pgn.pdu_specific

            pgn_msb = ((temp_pgn.value & 0xFF0000) >> 16)
            pgn_middle = ((temp_pgn.value & 0x00FF00) >> 8)
            pgn_lsb = (temp_pgn.value & 0x0000FF)

            if pdu.arbitration_id.pgn.is_destination_specific and \
               pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL:
                # send request to send
                logger.debug("MIL8: rts to specific dest: src=%s, dest=%s" %
                             (pdu.source, destination_address))
                rts_msg = Message(extended_id=True,
                                  arbitration_id=rts_arbitration_id.can_id,
                                  data=[
                                      CM_MSG_TYPE_RTS, pdu_length_msb,
                                      pdu_length_lsb,
                                      len(messages), 0xFF, pgn_lsb, pgn_middle,
                                      pgn_msb
                                  ],
                                  dlc=8)
                try:
                    logger.info("MIL08: j1939.send: sending TP.RTS to %s: %s" %
                                (destination_address, rts_msg))
                    self.can_bus.send(rts_msg)
                except CanError:
                    if self._ignore_can_send_error:
                        pass
                    raise
            else:
                rts_arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL
                rts_arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL
                logger.debug("MIL8: rts to Global dest: src=%s, dest=%s" %
                             (pdu.source, destination_address))
                bam_msg = Message(
                    extended_id=True,
                    arbitration_id=rts_arbitration_id.can_id | pdu.source,
                    data=[
                        CM_MSG_TYPE_BAM, pdu_length_msb, pdu_length_lsb,
                        len(messages), 0xFF, pgn_lsb, pgn_middle, pgn_msb
                    ],
                    dlc=8)
                bam_msg.destination_address = DESTINATION_ADDRESS_GLOBAL
                # bam_msg.arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL
                # send BAM
                try:
                    logger.info("j1939.send: sending TP.BAM to %s: %s" %
                                (destination_address, bam_msg))
                    self.can_bus.send(bam_msg)
                    time.sleep(0.05)
                except CanError:
                    if self._ignore_can_send_error:
                        pass
                    raise

                for message in messages:
                    # send data messages - no flow control, so no need to wait
                    # for receiving devices to acknowledge
                    logger.info("j1939.send: queue TP.BAM data to %s: %s" %
                                (destination_address, message))
                    self._long_message_segment_queue.put_nowait(message)
        else:
            msg.display_radix = 'hex'
            logger.debug("j1939.send: calling can_bus_send: j1939-msg: %s" %
                         (msg))
            can_message = Message(arbitration_id=msg.arbitration_id.can_id,
                                  extended_id=True,
                                  dlc=len(msg.data),
                                  data=msg.data)

            logger.debug("j1939.send: calling can_bus_send: can-msg: %s" %
                         can_message)
            try:
                self.can_bus.send(can_message)
            except CanError:
                if self._ignore_can_send_error:
                    pass
                raise