Skip to content

Commit fabcdf7

Browse files
authored
Vector: Check sample point instead of tseg & sjw (#1486)
* check sample point instead of tseg & sjw * improve error message
1 parent c4c396b commit fabcdf7

File tree

2 files changed

+196
-118
lines changed

2 files changed

+196
-118
lines changed

can/interfaces/vector/canlib.py

Lines changed: 194 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ def __init__(
148148
If the bus could not be set up.
149149
This may or may not be a :class:`~can.interfaces.vector.VectorInitializationError`.
150150
"""
151-
if os.name != "nt" and not kwargs.get("_testing", False):
151+
self.__testing = kwargs.get("_testing", False)
152+
if os.name != "nt" and not self.__testing:
152153
raise CanInterfaceNotImplementedError(
153154
f"The Vector interface is only supported on Windows, "
154155
f'but you are running "{os.name}"'
@@ -232,66 +233,20 @@ def __init__(
232233

233234
# set CAN settings
234235
for channel in self.channels:
235-
if self._has_init_access(channel):
236-
if fd:
237-
self._set_bitrate_canfd(
238-
channel=channel,
239-
bitrate=bitrate,
240-
data_bitrate=data_bitrate,
241-
sjw_abr=sjw_abr,
242-
tseg1_abr=tseg1_abr,
243-
tseg2_abr=tseg2_abr,
244-
sjw_dbr=sjw_dbr,
245-
tseg1_dbr=tseg1_dbr,
246-
tseg2_dbr=tseg2_dbr,
247-
)
248-
elif bitrate:
249-
self._set_bitrate_can(channel=channel, bitrate=bitrate)
250-
251-
# Check CAN settings
252-
for channel in self.channels:
253-
if kwargs.get("_testing", False):
254-
# avoid check if xldriver is mocked for testing
255-
break
256-
257-
bus_params = self._read_bus_params(channel)
258236
if fd:
259-
_canfd = bus_params.canfd
260-
if not all(
261-
[
262-
bus_params.bus_type is xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
263-
_canfd.can_op_mode
264-
& xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CANFD,
265-
_canfd.bitrate == bitrate if bitrate else True,
266-
_canfd.sjw_abr == sjw_abr if bitrate else True,
267-
_canfd.tseg1_abr == tseg1_abr if bitrate else True,
268-
_canfd.tseg2_abr == tseg2_abr if bitrate else True,
269-
_canfd.data_bitrate == data_bitrate if data_bitrate else True,
270-
_canfd.sjw_dbr == sjw_dbr if data_bitrate else True,
271-
_canfd.tseg1_dbr == tseg1_dbr if data_bitrate else True,
272-
_canfd.tseg2_dbr == tseg2_dbr if data_bitrate else True,
273-
]
274-
):
275-
raise CanInitializationError(
276-
f"The requested CAN FD settings could not be set for channel {channel}. "
277-
f"Another application might have set incompatible settings. "
278-
f"These are the currently active settings: {_canfd._asdict()}"
279-
)
280-
else:
281-
_can = bus_params.can
282-
if not all(
283-
[
284-
bus_params.bus_type is xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
285-
_can.can_op_mode
286-
& xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CAN20,
287-
_can.bitrate == bitrate if bitrate else True,
288-
]
289-
):
290-
raise CanInitializationError(
291-
f"The requested CAN settings could not be set for channel {channel}. "
292-
f"Another application might have set incompatible settings. "
293-
f"These are the currently active settings: {_can._asdict()}"
294-
)
237+
self._set_bitrate_canfd(
238+
channel=channel,
239+
bitrate=bitrate,
240+
data_bitrate=data_bitrate,
241+
sjw_abr=sjw_abr,
242+
tseg1_abr=tseg1_abr,
243+
tseg2_abr=tseg2_abr,
244+
sjw_dbr=sjw_dbr,
245+
tseg1_dbr=tseg1_dbr,
246+
tseg2_dbr=tseg2_dbr,
247+
)
248+
elif bitrate:
249+
self._set_bitrate_can(channel=channel, bitrate=bitrate)
295250

296251
# Enable/disable TX receipts
297252
tx_receipts = 1 if receive_own_messages else 0
@@ -422,32 +377,85 @@ def _set_bitrate_can(
422377
)
423378

424379
# set parameters if channel has init access
425-
if any(kwargs):
426-
chip_params = xlclass.XLchipParams()
427-
chip_params.bitRate = bitrate
428-
chip_params.sjw = sjw
429-
chip_params.tseg1 = tseg1
430-
chip_params.tseg2 = tseg2
431-
chip_params.sam = sam
432-
self.xldriver.xlCanSetChannelParams(
433-
self.port_handle,
434-
self.channel_masks[channel],
435-
chip_params,
380+
if self._has_init_access(channel):
381+
if any(kwargs):
382+
chip_params = xlclass.XLchipParams()
383+
chip_params.bitRate = bitrate
384+
chip_params.sjw = sjw
385+
chip_params.tseg1 = tseg1
386+
chip_params.tseg2 = tseg2
387+
chip_params.sam = sam
388+
self.xldriver.xlCanSetChannelParams(
389+
self.port_handle,
390+
self.channel_masks[channel],
391+
chip_params,
392+
)
393+
LOG.info(
394+
"xlCanSetChannelParams: baudr.=%u, sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
395+
chip_params.bitRate,
396+
chip_params.sjw,
397+
chip_params.tseg1,
398+
chip_params.tseg2,
399+
)
400+
else:
401+
self.xldriver.xlCanSetChannelBitrate(
402+
self.port_handle,
403+
self.channel_masks[channel],
404+
bitrate,
405+
)
406+
LOG.info("xlCanSetChannelBitrate: baudr.=%u", bitrate)
407+
408+
if self.__testing:
409+
return
410+
411+
# Compare requested CAN settings to active settings
412+
bus_params = self._read_bus_params(channel)
413+
settings_acceptable = True
414+
415+
# check bus type
416+
settings_acceptable &= (
417+
bus_params.bus_type is xldefine.XL_BusTypes.XL_BUS_TYPE_CAN
418+
)
419+
420+
# check CAN operation mode. For CANcaseXL can_op_mode remains 0
421+
if bus_params.can.can_op_mode != 0:
422+
settings_acceptable &= bool(
423+
bus_params.can.can_op_mode
424+
& xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CAN20
436425
)
437-
LOG.info(
438-
"xlCanSetChannelParams: baudr.=%u, sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
439-
chip_params.bitRate,
440-
chip_params.sjw,
441-
chip_params.tseg1,
442-
chip_params.tseg2,
426+
427+
# check bitrate
428+
settings_acceptable &= abs(bus_params.can.bitrate - bitrate) < bitrate / 256
429+
430+
# check sample point
431+
if all(kwargs):
432+
requested_sample_point = (
433+
100
434+
* (1 + tseg1) # type: ignore[operator]
435+
/ (1 + tseg1 + tseg2) # type: ignore[operator]
443436
)
444-
else:
445-
self.xldriver.xlCanSetChannelBitrate(
446-
self.port_handle,
447-
self.channel_masks[channel],
448-
bitrate,
437+
actual_sample_point = (
438+
100
439+
* (1 + bus_params.can.tseg1)
440+
/ (1 + bus_params.can.tseg1 + bus_params.can.tseg2)
441+
)
442+
settings_acceptable &= (
443+
abs(actual_sample_point - requested_sample_point)
444+
< 1.0 # 1 percent threshold
445+
)
446+
447+
if not settings_acceptable:
448+
active_settings = ", ".join(
449+
[
450+
f"{key}: {getattr(val, 'name', val)}" # print int or Enum/Flag name
451+
for key, val in bus_params.can._asdict().items()
452+
]
453+
)
454+
raise CanInitializationError(
455+
f"The requested CAN settings could not be set for channel {channel}. "
456+
f"Another application might have set incompatible settings. "
457+
f"These are the currently active settings: {active_settings}"
449458
)
450-
LOG.info("xlCanSetChannelBitrate: baudr.=%u", bitrate)
451459

452460
def _set_bitrate_canfd(
453461
self,
@@ -462,42 +470,112 @@ def _set_bitrate_canfd(
462470
tseg2_dbr: int = 3,
463471
) -> None:
464472
# set parameters if channel has init access
465-
canfd_conf = xlclass.XLcanFdConf()
466-
if bitrate:
467-
canfd_conf.arbitrationBitRate = int(bitrate)
468-
else:
469-
canfd_conf.arbitrationBitRate = 500_000
470-
canfd_conf.sjwAbr = int(sjw_abr)
471-
canfd_conf.tseg1Abr = int(tseg1_abr)
472-
canfd_conf.tseg2Abr = int(tseg2_abr)
473-
if data_bitrate:
474-
canfd_conf.dataBitRate = int(data_bitrate)
475-
else:
476-
canfd_conf.dataBitRate = int(canfd_conf.arbitrationBitRate)
477-
canfd_conf.sjwDbr = int(sjw_dbr)
478-
canfd_conf.tseg1Dbr = int(tseg1_dbr)
479-
canfd_conf.tseg2Dbr = int(tseg2_dbr)
480-
self.xldriver.xlCanFdSetConfiguration(
481-
self.port_handle, self.channel_masks[channel], canfd_conf
482-
)
483-
LOG.info(
484-
"xlCanFdSetConfiguration.: ABaudr.=%u, DBaudr.=%u",
485-
canfd_conf.arbitrationBitRate,
486-
canfd_conf.dataBitRate,
487-
)
488-
LOG.info(
489-
"xlCanFdSetConfiguration.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
490-
canfd_conf.sjwAbr,
491-
canfd_conf.tseg1Abr,
492-
canfd_conf.tseg2Abr,
473+
if self._has_init_access(channel):
474+
canfd_conf = xlclass.XLcanFdConf()
475+
if bitrate:
476+
canfd_conf.arbitrationBitRate = int(bitrate)
477+
else:
478+
canfd_conf.arbitrationBitRate = 500_000
479+
canfd_conf.sjwAbr = int(sjw_abr)
480+
canfd_conf.tseg1Abr = int(tseg1_abr)
481+
canfd_conf.tseg2Abr = int(tseg2_abr)
482+
if data_bitrate:
483+
canfd_conf.dataBitRate = int(data_bitrate)
484+
else:
485+
canfd_conf.dataBitRate = int(canfd_conf.arbitrationBitRate)
486+
canfd_conf.sjwDbr = int(sjw_dbr)
487+
canfd_conf.tseg1Dbr = int(tseg1_dbr)
488+
canfd_conf.tseg2Dbr = int(tseg2_dbr)
489+
self.xldriver.xlCanFdSetConfiguration(
490+
self.port_handle, self.channel_masks[channel], canfd_conf
491+
)
492+
LOG.info(
493+
"xlCanFdSetConfiguration.: ABaudr.=%u, DBaudr.=%u",
494+
canfd_conf.arbitrationBitRate,
495+
canfd_conf.dataBitRate,
496+
)
497+
LOG.info(
498+
"xlCanFdSetConfiguration.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
499+
canfd_conf.sjwAbr,
500+
canfd_conf.tseg1Abr,
501+
canfd_conf.tseg2Abr,
502+
)
503+
LOG.info(
504+
"xlCanFdSetConfiguration.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u",
505+
canfd_conf.sjwDbr,
506+
canfd_conf.tseg1Dbr,
507+
canfd_conf.tseg2Dbr,
508+
)
509+
510+
if self.__testing:
511+
return
512+
513+
# Compare requested CAN settings to active settings
514+
bus_params = self._read_bus_params(channel)
515+
settings_acceptable = True
516+
517+
# check bus type
518+
settings_acceptable &= (
519+
bus_params.bus_type is xldefine.XL_BusTypes.XL_BUS_TYPE_CAN
493520
)
494-
LOG.info(
495-
"xlCanFdSetConfiguration.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u",
496-
canfd_conf.sjwDbr,
497-
canfd_conf.tseg1Dbr,
498-
canfd_conf.tseg2Dbr,
521+
522+
# check CAN operation mode
523+
settings_acceptable &= bool(
524+
bus_params.canfd.can_op_mode
525+
& xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CANFD
499526
)
500527

528+
# check bitrates
529+
if bitrate:
530+
settings_acceptable &= (
531+
abs(bus_params.canfd.bitrate - bitrate) < bitrate / 256
532+
)
533+
if data_bitrate:
534+
settings_acceptable &= (
535+
abs(bus_params.canfd.data_bitrate - data_bitrate) < data_bitrate / 256
536+
)
537+
538+
# check sample points
539+
if bitrate:
540+
requested_nom_sample_point = (
541+
100 * (1 + tseg1_abr) / (1 + tseg1_abr + tseg2_abr)
542+
)
543+
actual_nom_sample_point = (
544+
100
545+
* (1 + bus_params.canfd.tseg1_abr)
546+
/ (1 + bus_params.canfd.tseg1_abr + bus_params.canfd.tseg2_abr)
547+
)
548+
settings_acceptable &= (
549+
abs(actual_nom_sample_point - requested_nom_sample_point)
550+
< 1.0 # 1 percent threshold
551+
)
552+
if data_bitrate:
553+
requested_data_sample_point = (
554+
100 * (1 + tseg1_dbr) / (1 + tseg1_dbr + tseg2_dbr)
555+
)
556+
actual_data_sample_point = (
557+
100
558+
* (1 + bus_params.canfd.tseg1_dbr)
559+
/ (1 + bus_params.canfd.tseg1_dbr + bus_params.canfd.tseg2_dbr)
560+
)
561+
settings_acceptable &= (
562+
abs(actual_data_sample_point - requested_data_sample_point)
563+
< 1.0 # 1 percent threshold
564+
)
565+
566+
if not settings_acceptable:
567+
active_settings = ", ".join(
568+
[
569+
f"{key}: {getattr(val, 'name', val)}" # print int or Enum/Flag name
570+
for key, val in bus_params.canfd._asdict().items()
571+
]
572+
)
573+
raise CanInitializationError(
574+
f"The requested CAN FD settings could not be set for channel {channel}. "
575+
f"Another application might have set incompatible settings. "
576+
f"These are the currently active settings: {active_settings}."
577+
)
578+
501579
def _apply_filters(self, filters: Optional[CanFilters]) -> None:
502580
if filters:
503581
# Only up to one filter per ID type allowed

test/test_vector.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ def test_reset_mocked(mock_xldriver) -> None:
459459

460460

461461
@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable")
462-
def test_reset_mocked() -> None:
462+
def test_reset() -> None:
463463
bus = canlib.VectorBus(
464464
channel=0, serial=_find_virtual_can_serial(), interface="vector"
465465
)
@@ -696,7 +696,7 @@ def _find_virtual_can_serial() -> int:
696696
for i in range(xl_driver_config.channelCount):
697697
xl_channel_config: xlclass.XLchannelConfig = xl_driver_config.channel[i]
698698

699-
if xl_channel_config.transceiverName.decode() == "Virtual CAN":
699+
if "Virtual CAN" in xl_channel_config.transceiverName.decode():
700700
return xl_channel_config.serialNumber
701701

702702
raise LookupError("Vector virtual CAN not found")

0 commit comments

Comments
 (0)