Skip to content

Commit

Permalink
Vector: use global channel_index if provided (#1681)
Browse files Browse the repository at this point in the history
* fix XL_ERR_INVALID_CHANNEL_MASK for multiple devices with the same serial

* add CHANGELOG.md entry
  • Loading branch information
zariiii9003 authored Oct 19, 2023
1 parent 61ee42b commit 38c4dc4
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Bug Fixes
* Fix BLFReader error for incomplete or truncated stream (#1662)
* PCAN: remove Windows registry check to fix 32bit compatibility (#1672)
* Vector: Skip the `can_op_mode check` if the device reports `can_op_mode=0` (#1678)
* Vector: using the config from `detect_available_configs` might raise XL_ERR_INVALID_CHANNEL_MASK error (#1681)

Features
--------
Expand Down
21 changes: 15 additions & 6 deletions can/interfaces/vector/canlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,20 @@ def __init__(
self._can_protocol = CanProtocol.CAN_FD if is_fd else CanProtocol.CAN_20

for channel in self.channels:
channel_index = self._find_global_channel_idx(
channel=channel,
serial=serial,
app_name=app_name,
channel_configs=channel_configs,
)
if (_channel_index := kwargs.get("channel_index", None)) is not None:
# VectorBus._detect_available_configs() might return multiple
# devices with the same serial number, e.g. if a VN8900 is connected via both USB and Ethernet
# at the same time. If the VectorBus is instantiated with a config, that was returned from
# VectorBus._detect_available_configs(), then use the contained global channel_index
# to avoid any ambiguities.
channel_index = cast(int, _channel_index)
else:
channel_index = self._find_global_channel_idx(
channel=channel,
serial=serial,
app_name=app_name,
channel_configs=channel_configs,
)
LOG.debug("Channel index %d found", channel)

channel_mask = 1 << channel_index
Expand Down Expand Up @@ -950,6 +958,7 @@ def _detect_available_configs() -> List[AutoDetectedConfig]:
"interface": "vector",
"channel": channel_config.hw_channel,
"serial": channel_config.serial_number,
"channel_index": channel_config.channel_index,
# data for use in VectorBus.set_application_config():
"hw_type": channel_config.hw_type,
"hw_index": channel_config.hw_index,
Expand Down
41 changes: 41 additions & 0 deletions test/test_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,22 @@ def test_bus_creation() -> None:
bus.shutdown()


@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable")
def test_bus_creation_channel_index() -> None:
channel_index = 3
bus = can.Bus(
channel=0,
serial=_find_virtual_can_serial(),
channel_index=channel_index,
interface="vector",
)
assert isinstance(bus, canlib.VectorBus)
assert bus.protocol == can.CanProtocol.CAN_20
assert bus.channel_masks[0] == 1 << channel_index

bus.shutdown()


def test_bus_creation_bitrate_mocked(mock_xldriver) -> None:
bus = can.Bus(channel=0, interface="vector", bitrate=200_000, _testing=True)
assert isinstance(bus, canlib.VectorBus)
Expand Down Expand Up @@ -833,6 +849,31 @@ def test_get_channel_configs() -> None:
canlib._get_xl_driver_config = _original_func


@pytest.mark.skipif(
sys.byteorder != "little", reason="Test relies on little endian data."
)
def test_detect_available_configs() -> None:
_original_func = canlib._get_xl_driver_config
canlib._get_xl_driver_config = _get_predefined_xl_driver_config

available_configs = canlib.VectorBus._detect_available_configs()

assert len(available_configs) == 5

assert available_configs[0]["interface"] == "vector"
assert available_configs[0]["channel"] == 2
assert available_configs[0]["serial"] == 1001
assert available_configs[0]["channel_index"] == 2
assert available_configs[0]["hw_type"] == xldefine.XL_HardwareType.XL_HWTYPE_VN8900
assert available_configs[0]["hw_index"] == 0
assert available_configs[0]["supports_fd"] is True
assert isinstance(
available_configs[0]["vector_channel_config"], VectorChannelConfig
)

canlib._get_xl_driver_config = _original_func


@pytest.mark.skipif(not IS_WINDOWS, reason="Windows specific test")
def test_winapi_availability() -> None:
assert canlib.WaitForSingleObject is not None
Expand Down

0 comments on commit 38c4dc4

Please sign in to comment.