Example #1
0
    def send(self, msg, timeout=None):
        log.debug("Sending message: %s", msg)

        # This system is not designed to be very efficient
        message = structures.CANMSG()
        message.uMsgInfo.Bits.type = constants.CAN_MSGTYPE_DATA
        message.uMsgInfo.Bits.rtr = 1 if msg.is_remote_frame else 0
        message.uMsgInfo.Bits.ext = 1 if msg.id_type else 0
        message.dwMsgId = msg.arbitration_id
        if msg.dlc:
            message.uMsgInfo.Bits.dlc = msg.dlc
            adapter = (ctypes.c_uint8 * msg.dlc).from_buffer(msg.data)
            ctypes.memmove(message.abData, adapter, msg.dlc)

        if timeout:
            _canlib.canChannelSendMessage(self._channel_handle,
                                          int(timeout * 1000), message)
        else:
            _canlib.canChannelPostMessage(self._channel_handle, message)
Example #2
0
    def __init__(self, channel, can_filters=None, **config):
        """
        :param int channel:
            The Channel id to create this bus with.

        :param list can_filters:
            A list of dictionaries each containing a "can_id" and a "can_mask".

            >>> [{"can_id": 0x11, "can_mask": 0x21}]

        :param int UniqueHardwareId:
            UniqueHardwareId to connect (optional, will use the first found if not supplied)

        :param int bitrate:
            Channel bitrate in bit/s
        """
        if _canlib is None:
            raise ImportError(
                "The IXXAT VCI library has not been initialized. Check the logs for more details."
            )
        log.info("CAN Filters: %s", can_filters)
        log.info("Got configuration of: %s", config)
        # Configuration options
        bitrate = config.get('bitrate', 500000)
        UniqueHardwareId = config.get('UniqueHardwareId', None)
        rxFifoSize = config.get('rxFifoSize', 16)
        txFifoSize = config.get('txFifoSize', 16)
        # Usually comes as a string from the config file
        channel = int(channel)

        if (bitrate not in self.CHANNEL_BITRATES[0]):
            raise ValueError("Invalid bitrate {}".format(bitrate))

        self._device_handle = HANDLE()
        self._device_info = structures.VCIDEVICEINFO()
        self._control_handle = HANDLE()
        self._channel_handle = HANDLE()
        self._channel_capabilities = structures.CANCAPABILITIES()
        self._message = structures.CANMSG()
        self._payload = (ctypes.c_byte * 8)()

        # Search for supplied device
        if UniqueHardwareId is None:
            log.info("Searching for first available device")
        else:
            log.info("Searching for unique HW ID %s", UniqueHardwareId)
        _canlib.vciEnumDeviceOpen(ctypes.byref(self._device_handle))
        while True:
            try:
                _canlib.vciEnumDeviceNext(self._device_handle,
                                          ctypes.byref(self._device_info))
            except StopIteration:
                if (UniqueHardwareId is None):
                    raise VCIDeviceNotFoundError(
                        "No IXXAT device(s) connected or device(s) in use by other process(es)."
                    )
                else:
                    raise VCIDeviceNotFoundError(
                        "Unique HW ID {} not connected or not available.".
                        format(UniqueHardwareId))
            else:
                if (UniqueHardwareId is
                        None) or (self._device_info.UniqueHardwareId.AsChar
                                  == bytes(UniqueHardwareId, 'ascii')):
                    break
        _canlib.vciEnumDeviceClose(self._device_handle)
        _canlib.vciDeviceOpen(ctypes.byref(self._device_info.VciObjectId),
                              ctypes.byref(self._device_handle))
        log.info("Using unique HW ID %s",
                 self._device_info.UniqueHardwareId.AsChar)

        log.info(
            "Initializing channel %d in shared mode, %d rx buffers, %d tx buffers",
            channel, rxFifoSize, txFifoSize)
        _canlib.canChannelOpen(self._device_handle, channel, constants.FALSE,
                               ctypes.byref(self._channel_handle))
        # Signal TX/RX events when at least one frame has been handled
        _canlib.canChannelInitialize(self._channel_handle, rxFifoSize, 1,
                                     txFifoSize, 1)
        _canlib.canChannelActivate(self._channel_handle, constants.TRUE)

        log.info("Initializing control %d bitrate %d", channel, bitrate)
        _canlib.canControlOpen(self._device_handle, channel,
                               ctypes.byref(self._control_handle))
        _canlib.canControlInitialize(
            self._control_handle,
            constants.CAN_OPMODE_STANDARD | constants.CAN_OPMODE_EXTENDED
            | constants.CAN_OPMODE_ERRFRAME if extended else
            constants.CAN_OPMODE_STANDARD | constants.CAN_OPMODE_ERRFRAME,
            self.CHANNEL_BITRATES[0][bitrate],
            self.CHANNEL_BITRATES[1][bitrate])
        _canlib.canControlGetCaps(self._control_handle,
                                  ctypes.byref(self._channel_capabilities))

        # With receive messages, this field contains the relative reception time of
        # the message in ticks. The resolution of a tick can be calculated from the fields
        # dwClockFreq and dwTscDivisor of the structure  CANCAPABILITIES in accordance with the following formula:
        # frequency [1/s] = dwClockFreq / dwTscDivisor
        # We explicitly cast to float for Python 2.x users
        self._tick_resolution = float(self._channel_capabilities.dwClockFreq /
                                      self._channel_capabilities.dwTscDivisor)

        # Setup filters before starting the channel
        if can_filters is not None and len(can_filters):
            log.info("The IXXAT VCI backend is filtering messages")
            # Disable every message coming in
            for extended in (0, 1):
                _canlib.canControlSetAccFilter(self._control_handle, extended,
                                               constants.CAN_ACC_CODE_NONE,
                                               constants.CAN_ACC_MASK_NONE)
            for can_filter in can_filters:
                # Whitelist
                code = int(can_filter['can_id'])
                mask = int(can_filter['can_mask'])
                extended = can_filter.get('extended', False)
                _canlib.canControlAddFilterIds(self._control_handle,
                                               1 if extended else 0, code,
                                               mask)
                rtr = (code & 0x01) and (mask & 0x01)
                log.info("Accepting ID:%d  MASK:%d RTR:%s", code >> 1,
                         mask >> 1, "YES" if rtr else "NO")

        # Start the CAN controller. Messages will be forwarded to the channel
        _canlib.canControlStart(self._control_handle, constants.TRUE)

        # Usually you get back 3 messages like "CAN initialized" ecc...
        # Filter them out with low timeout
        while True:
            try:
                _canlib.canChannelWaitRxEvent(self._channel_handle, 0)
            except VCITimeout:
                break
            else:
                _canlib.canChannelReadMessage(self._channel_handle, 0,
                                              ctypes.byref(self._message))

        super(IXXATBus, self).__init__()