예제 #1
0
    def get_application_config(
            app_name: str,
            app_channel: int) -> Tuple[xldefine.XL_HardwareType, int, int]:
        """Retrieve information for an application in Vector Hardware Configuration.

        :param app_name:
            The name of the application.
        :param app_channel:
            The channel of the application.
        :return:
            Returns a tuple of the hardware type, the hardware index and the
            hardware channel.

        :raises can.interfaces.vector.VectorInitializationError:
            If the application name does not exist in the Vector hardware configuration.
        """
        if xldriver is None:
            raise CanInterfaceNotImplementedError(
                "The Vector API has not been loaded")

        hw_type = ctypes.c_uint()
        hw_index = ctypes.c_uint()
        hw_channel = ctypes.c_uint()
        _app_channel = ctypes.c_uint(app_channel)

        xldriver.xlGetApplConfig(
            app_name.encode(),
            _app_channel,
            hw_type,
            hw_index,
            hw_channel,
            xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
        )
        return xldefine.XL_HardwareType(
            hw_type.value), hw_index.value, hw_channel.value
예제 #2
0
    def __init__(
        self,
        channel: Union[str, int],
        bitrate: int = 500000,
        poll_interval: float = 0.01,
        **kwargs,
    ) -> None:
        """
        :param channel:
            Device number
        :param bitrate:
            Bitrate in bits/s
        :param poll_interval:
            Poll interval in seconds when reading messages
        """
        if iscan is None:
            raise CanInterfaceNotImplementedError(
                "Could not load isCAN driver")

        self.channel = ctypes.c_ubyte(int(channel))
        self.channel_info = f"IS-CAN: {self.channel}"

        if bitrate not in self.BAUDRATES:
            raise ValueError(
                f"Invalid bitrate, choose one of {set(self.BAUDRATES)}")

        self.poll_interval = poll_interval
        iscan.isCAN_DeviceInitEx(self.channel, self.BAUDRATES[bitrate])

        super().__init__(channel=channel,
                         bitrate=bitrate,
                         poll_interval=poll_interval,
                         **kwargs)
예제 #3
0
    def popup_vector_hw_configuration(wait_for_finish: int = 0) -> None:
        """Open vector hardware configuration window.

        :param wait_for_finish:
            Time to wait for user input in milliseconds.
        """
        if xldriver is None:
            raise CanInterfaceNotImplementedError(
                "The Vector API has not been loaded")

        xldriver.xlPopupHwConfig(ctypes.c_char_p(),
                                 ctypes.c_uint(wait_for_finish))
예제 #4
0
    def __init__(
        self,
        channel: str,
        baudrate: int = 115200,
        timeout: float = 0.1,
        rtscts: bool = False,
        *args,
        **kwargs,
    ) -> None:
        """
        :param channel:
            The serial device to open. For example "/dev/ttyS1" or
            "/dev/ttyUSB0" on Linux or "COM1" on Windows systems.

        :param baudrate:
            Baud rate of the serial device in bit/s (default 115200).

            .. warning::
                Some serial port implementations don't care about the baudrate.

        :param timeout:
            Timeout for the serial device in seconds (default 0.1).

        :param rtscts:
            turn hardware handshake (RTS/CTS) on and off

        :raises can.CanInitializationError: If the given parameters are invalid.
        :raises can.CanInterfaceNotImplementedError: If the serial module is not installed.
        """

        if not serial:
            raise CanInterfaceNotImplementedError(
                "the serial module is not installed")

        if not channel:
            raise TypeError("Must specify a serial port.")

        self.channel_info = f"Serial interface: {channel}"

        try:
            self._ser = serial.serial_for_url(channel,
                                              baudrate=baudrate,
                                              timeout=timeout,
                                              rtscts=rtscts)
        except ValueError as error:
            raise CanInitializationError(
                "could not create the serial device") from error

        super().__init__(channel, *args, **kwargs)
예제 #5
0
    def set_application_config(
        app_name: str,
        app_channel: int,
        hw_type: xldefine.XL_HardwareType,
        hw_index: int,
        hw_channel: int,
        **kwargs: Any,
    ) -> None:
        """Modify the application settings in Vector Hardware Configuration.

        This method can also be used with a channel config dictionary::

            import can
            from can.interfaces.vector import VectorBus

            configs = can.detect_available_configs(interfaces=['vector'])
            cfg = configs[0]
            VectorBus.set_application_config(app_name="MyApplication", app_channel=0, **cfg)

        :param app_name:
            The name of the application. Creates a new application if it does
            not exist yet.
        :param app_channel:
            The channel of the application.
        :param hw_type:
            The hardware type of the interface.
            E.g XL_HardwareType.XL_HWTYPE_VIRTUAL
        :param hw_index:
            The index of the interface if multiple interface with the same
            hardware type are present.
        :param hw_channel:
            The channel index of the interface.

        :raises can.interfaces.vector.VectorInitializationError:
            If the application name does not exist in the Vector hardware configuration.
        """
        if xldriver is None:
            raise CanInterfaceNotImplementedError(
                "The Vector API has not been loaded")

        xldriver.xlSetApplConfig(
            app_name.encode(),
            app_channel,
            hw_type,
            hw_index,
            hw_channel,
            xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
        )
예제 #6
0
def check_msgpack_installed() -> None:
    """Raises a :class:`can.CanInterfaceNotImplementedError` if `msgpack` is not installed."""
    if msgpack is None:
        raise CanInterfaceNotImplementedError("msgpack not installed")
예제 #7
0
    def __init__(
        self,
        channel: Union[int, Sequence[int], str],
        can_filters: Optional[CanFilters] = None,
        poll_interval: float = 0.01,
        receive_own_messages: bool = False,
        bitrate: Optional[int] = None,
        rx_queue_size: int = 2**14,
        app_name: Optional[str] = "CANalyzer",
        serial: Optional[int] = None,
        fd: bool = False,
        data_bitrate: Optional[int] = None,
        sjw_abr: int = 2,
        tseg1_abr: int = 6,
        tseg2_abr: int = 3,
        sjw_dbr: int = 2,
        tseg1_dbr: int = 6,
        tseg2_dbr: int = 3,
        **kwargs: Any,
    ) -> None:
        """
        :param channel:
            The channel indexes to create this bus with.
            Can also be a single integer or a comma separated string.
        :param can_filters:
            See :class:`can.BusABC`.
        :param receive_own_messages:
            See :class:`can.BusABC`.
        :param poll_interval:
            Poll interval in seconds.
        :param bitrate:
            Bitrate in bits/s.
        :param rx_queue_size:
            Number of messages in receive queue (power of 2).
            CAN: range `16…32768`
            CAN-FD: range `8192…524288`
        :param app_name:
            Name of application in *Vector Hardware Config*.
            If set to `None`, the channel should be a global channel index.
        :param serial:
            Serial number of the hardware to be used.
            If set, the channel parameter refers to the channels ONLY on the specified hardware.
            If set, the `app_name` does not have to be previously defined in
            *Vector Hardware Config*.
        :param fd:
            If CAN-FD frames should be supported.
        :param data_bitrate:
            Which bitrate to use for data phase in CAN FD.
            Defaults to arbitration bitrate.
        :param sjw_abr:
            Bus timing value sample jump width (arbitration).
        :param tseg1_abr:
            Bus timing value tseg1 (arbitration)
        :param tseg2_abr:
            Bus timing value tseg2 (arbitration)
        :param sjw_dbr:
            Bus timing value sample jump width (data)
        :param tseg1_dbr:
            Bus timing value tseg1 (data)
        :param tseg2_dbr:
            Bus timing value tseg2 (data)

        :raise can.CanInterfaceNotImplementedError:
            If the current operating system is not supported or the driver could not be loaded.
        :raise can.CanInitializationError:
            If the bus could not be set up.
            This may or may not be a :class:`can.interfaces.vector.VectorInitializationError`.
        """
        if os.name != "nt" and not kwargs.get("_testing", False):
            raise CanInterfaceNotImplementedError(
                f"The Vector interface is only supported on Windows, "
                f'but you are running "{os.name}"')

        if xldriver is None:
            raise CanInterfaceNotImplementedError(
                "The Vector API has not been loaded")
        self.xldriver = xldriver  # keep reference so mypy knows it is not None

        self.poll_interval = poll_interval

        self.channels: Sequence[int]
        if isinstance(channel, int):
            self.channels = [channel]
        elif isinstance(channel,
                        str):  # must be checked before generic Sequence
            # Assume comma separated string of channels
            self.channels = [int(ch.strip()) for ch in channel.split(",")]
        elif isinstance(channel, Sequence):
            self.channels = [int(ch) for ch in channel]
        else:
            raise TypeError(
                f"Invalid type for channels parameter: {type(channel).__name__}"
            )

        self._app_name = app_name.encode() if app_name is not None else b""
        self.channel_info = "Application %s: %s" % (
            app_name,
            ", ".join(f"CAN {ch + 1}" for ch in self.channels),
        )

        if serial is not None:
            app_name = None
            channel_index = []
            channel_configs = get_channel_configs()
            for channel_config in channel_configs:
                if channel_config.serialNumber == serial:
                    if channel_config.hwChannel in self.channels:
                        channel_index.append(channel_config.channelIndex)
            if channel_index:
                if len(channel_index) != len(self.channels):
                    LOG.info(
                        "At least one defined channel wasn't found on the specified hardware."
                    )
                self.channels = channel_index
            else:
                # Is there any better way to raise the error?
                raise CanInitializationError(
                    "None of the configured channels could be found on the specified hardware."
                )

        self.xldriver.xlOpenDriver()
        self.port_handle = xlclass.XLportHandle(xldefine.XL_INVALID_PORTHANDLE)
        self.mask = 0
        self.fd = fd
        # Get channels masks
        self.channel_masks: Dict[Optional[Channel], int] = {}
        self.index_to_channel = {}

        for channel in self.channels:
            if app_name:
                # Get global channel index from application channel
                hw_type, hw_index, hw_channel = self.get_application_config(
                    app_name, channel)
                LOG.debug("Channel index %d found", channel)
                idx = self.xldriver.xlGetChannelIndex(hw_type, hw_index,
                                                      hw_channel)
                if idx < 0:
                    # Undocumented behavior! See issue #353.
                    # If hardware is unavailable, this function returns -1.
                    # Raise an exception as if the driver
                    # would have signalled XL_ERR_HW_NOT_PRESENT.
                    raise VectorInitializationError(
                        xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT,
                        xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT.name,
                        "xlGetChannelIndex",
                    )
            else:
                # Channel already given as global channel
                idx = channel
            mask = 1 << idx
            self.channel_masks[channel] = mask
            self.index_to_channel[idx] = channel
            self.mask |= mask

        permission_mask = xlclass.XLaccess()
        # Set mask to request channel init permission if needed
        if bitrate or fd:
            permission_mask.value = self.mask
        if fd:
            self.xldriver.xlOpenPort(
                self.port_handle,
                self._app_name,
                self.mask,
                permission_mask,
                rx_queue_size,
                xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4,
                xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
            )
        else:
            self.xldriver.xlOpenPort(
                self.port_handle,
                self._app_name,
                self.mask,
                permission_mask,
                rx_queue_size,
                xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION,
                xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
            )
        LOG.debug(
            "Open Port: PortHandle: %d, PermissionMask: 0x%X",
            self.port_handle.value,
            permission_mask.value,
        )

        if permission_mask.value == self.mask:
            if fd:
                self.canFdConf = xlclass.XLcanFdConf()
                if bitrate:
                    self.canFdConf.arbitrationBitRate = int(bitrate)
                else:
                    self.canFdConf.arbitrationBitRate = 500000
                self.canFdConf.sjwAbr = int(sjw_abr)
                self.canFdConf.tseg1Abr = int(tseg1_abr)
                self.canFdConf.tseg2Abr = int(tseg2_abr)
                if data_bitrate:
                    self.canFdConf.dataBitRate = int(data_bitrate)
                else:
                    self.canFdConf.dataBitRate = self.canFdConf.arbitrationBitRate
                self.canFdConf.sjwDbr = int(sjw_dbr)
                self.canFdConf.tseg1Dbr = int(tseg1_dbr)
                self.canFdConf.tseg2Dbr = int(tseg2_dbr)

                self.xldriver.xlCanFdSetConfiguration(self.port_handle,
                                                      self.mask,
                                                      self.canFdConf)
                LOG.info(
                    "SetFdConfig.: ABaudr.=%u, DBaudr.=%u",
                    self.canFdConf.arbitrationBitRate,
                    self.canFdConf.dataBitRate,
                )
                LOG.info(
                    "SetFdConfig.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
                    self.canFdConf.sjwAbr,
                    self.canFdConf.tseg1Abr,
                    self.canFdConf.tseg2Abr,
                )
                LOG.info(
                    "SetFdConfig.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u",
                    self.canFdConf.sjwDbr,
                    self.canFdConf.tseg1Dbr,
                    self.canFdConf.tseg2Dbr,
                )
            else:
                if bitrate:
                    self.xldriver.xlCanSetChannelBitrate(
                        self.port_handle, permission_mask, bitrate)
                    LOG.info("SetChannelBitrate: baudr.=%u", bitrate)
        else:
            LOG.info("No init access!")

        # Enable/disable TX receipts
        tx_receipts = 1 if receive_own_messages else 0
        self.xldriver.xlCanSetChannelMode(self.port_handle, self.mask,
                                          tx_receipts, 0)

        if HAS_EVENTS:
            self.event_handle = xlclass.XLhandle()
            self.xldriver.xlSetNotification(self.port_handle,
                                            self.event_handle, 1)
        else:
            LOG.info("Install pywin32 to avoid polling")

        try:
            self.xldriver.xlActivateChannel(
                self.port_handle, self.mask,
                xldefine.XL_BusTypes.XL_BUS_TYPE_CAN, 0)
        except VectorOperationError as error:
            self.shutdown()
            raise VectorInitializationError.from_generic(error) from None

        # Calculate time offset for absolute timestamps
        offset = xlclass.XLuint64()
        try:
            if time.get_clock_info("time").resolution > 1e-5:
                ts, perfcounter = time_perfcounter_correlation()
                try:
                    self.xldriver.xlGetSyncTime(self.port_handle, offset)
                except VectorInitializationError:
                    self.xldriver.xlGetChannelTime(self.port_handle, self.mask,
                                                   offset)
                current_perfcounter = time.perf_counter()
                now = ts + (current_perfcounter - perfcounter)
                self._time_offset = now - offset.value * 1e-9
            else:
                try:
                    self.xldriver.xlGetSyncTime(self.port_handle, offset)
                except VectorInitializationError:
                    self.xldriver.xlGetChannelTime(self.port_handle, self.mask,
                                                   offset)
                self._time_offset = time.time() - offset.value * 1e-9

        except VectorInitializationError:
            self._time_offset = 0.0

        self._is_filtered = False
        super().__init__(channel=channel, can_filters=can_filters, **kwargs)