Skip to content

Commit 1e11f21

Browse files
authored
VectorBus init refactoring (hardbyte#1389)
* refactor VectorBus.__init__() * move bitrate methods below __init__(), fix typo * refactor channel index search into method '_find_global_channel_idx', improve error messages
1 parent 40f6cce commit 1e11f21

File tree

1 file changed

+200
-116
lines changed

1 file changed

+200
-116
lines changed

can/interfaces/vector/canlib.py

Lines changed: 200 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
Any,
2222
Dict,
2323
Callable,
24+
cast,
2425
)
2526

2627
WaitForSingleObject: Optional[Callable[[int, int], int]]
@@ -43,7 +44,7 @@
4344
deprecated_args_alias,
4445
time_perfcounter_correlation,
4546
)
46-
from can.typechecking import AutoDetectedConfig, CanFilters, Channel
47+
from can.typechecking import AutoDetectedConfig, CanFilters
4748

4849
# Define Module Logger
4950
# ====================
@@ -152,6 +153,7 @@ def __init__(
152153
if xldriver is None:
153154
raise CanInterfaceNotImplementedError("The Vector API has not been loaded")
154155
self.xldriver = xldriver # keep reference so mypy knows it is not None
156+
self.xldriver.xlOpenDriver()
155157

156158
self.poll_interval = poll_interval
157159

@@ -165,7 +167,7 @@ def __init__(
165167
self.channels = [int(ch) for ch in channel]
166168
else:
167169
raise TypeError(
168-
f"Invalid type for channels parameter: {type(channel).__name__}"
170+
f"Invalid type for parameter 'channel': {type(channel).__name__}"
169171
)
170172

171173
self._app_name = app_name.encode() if app_name is not None else b""
@@ -174,136 +176,71 @@ def __init__(
174176
", ".join(f"CAN {ch + 1}" for ch in self.channels),
175177
)
176178

177-
if serial is not None:
178-
app_name = None
179-
channel_index = []
180-
channel_configs = get_channel_configs()
181-
for channel_config in channel_configs:
182-
if channel_config.serialNumber == serial:
183-
if channel_config.hwChannel in self.channels:
184-
channel_index.append(channel_config.channelIndex)
185-
if channel_index:
186-
if len(channel_index) != len(self.channels):
187-
LOG.info(
188-
"At least one defined channel wasn't found on the specified hardware."
189-
)
190-
self.channels = channel_index
191-
else:
192-
# Is there any better way to raise the error?
193-
raise CanInitializationError(
194-
"None of the configured channels could be found on the specified hardware."
195-
)
179+
channel_configs = get_channel_configs()
196180

197-
self.xldriver.xlOpenDriver()
198-
self.port_handle = xlclass.XLportHandle(xldefine.XL_INVALID_PORTHANDLE)
199181
self.mask = 0
200182
self.fd = fd
201-
# Get channels masks
202-
self.channel_masks: Dict[Optional[Channel], int] = {}
203-
self.index_to_channel = {}
183+
self.channel_masks: Dict[int, int] = {}
184+
self.index_to_channel: Dict[int, int] = {}
204185

205186
for channel in self.channels:
206-
if app_name:
207-
# Get global channel index from application channel
208-
hw_type, hw_index, hw_channel = self.get_application_config(
209-
app_name, channel
210-
)
211-
LOG.debug("Channel index %d found", channel)
212-
idx = self.xldriver.xlGetChannelIndex(hw_type, hw_index, hw_channel)
213-
if idx < 0:
214-
# Undocumented behavior! See issue #353.
215-
# If hardware is unavailable, this function returns -1.
216-
# Raise an exception as if the driver
217-
# would have signalled XL_ERR_HW_NOT_PRESENT.
218-
raise VectorInitializationError(
219-
xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT,
220-
xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT.name,
221-
"xlGetChannelIndex",
222-
)
223-
else:
224-
# Channel already given as global channel
225-
idx = channel
226-
mask = 1 << idx
227-
self.channel_masks[channel] = mask
228-
self.index_to_channel[idx] = channel
229-
self.mask |= mask
187+
channel_index = self._find_global_channel_idx(
188+
channel=channel,
189+
serial=serial,
190+
app_name=app_name,
191+
channel_configs=channel_configs,
192+
)
193+
LOG.debug("Channel index %d found", channel)
194+
195+
channel_mask = 1 << channel_index
196+
self.channel_masks[channel] = channel_mask
197+
self.index_to_channel[channel_index] = channel
198+
self.mask |= channel_mask
230199

231200
permission_mask = xlclass.XLaccess()
232201
# Set mask to request channel init permission if needed
233202
if bitrate or fd:
234203
permission_mask.value = self.mask
235-
if fd:
236-
self.xldriver.xlOpenPort(
237-
self.port_handle,
238-
self._app_name,
239-
self.mask,
240-
permission_mask,
241-
rx_queue_size,
242-
xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4,
243-
xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
244-
)
245-
else:
246-
self.xldriver.xlOpenPort(
247-
self.port_handle,
248-
self._app_name,
249-
self.mask,
250-
permission_mask,
251-
rx_queue_size,
252-
xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION,
253-
xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
254-
)
204+
205+
interface_version = (
206+
xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4
207+
if fd
208+
else xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION
209+
)
210+
211+
self.port_handle = xlclass.XLportHandle(xldefine.XL_INVALID_PORTHANDLE)
212+
self.xldriver.xlOpenPort(
213+
self.port_handle,
214+
self._app_name,
215+
self.mask,
216+
permission_mask,
217+
rx_queue_size,
218+
interface_version,
219+
xldefine.XL_BusTypes.XL_BUS_TYPE_CAN,
220+
)
221+
255222
LOG.debug(
256223
"Open Port: PortHandle: %d, PermissionMask: 0x%X",
257224
self.port_handle.value,
258225
permission_mask.value,
259226
)
260227

261-
if permission_mask.value == self.mask:
262-
if fd:
263-
self.canFdConf = xlclass.XLcanFdConf()
264-
if bitrate:
265-
self.canFdConf.arbitrationBitRate = int(bitrate)
266-
else:
267-
self.canFdConf.arbitrationBitRate = 500000
268-
self.canFdConf.sjwAbr = int(sjw_abr)
269-
self.canFdConf.tseg1Abr = int(tseg1_abr)
270-
self.canFdConf.tseg2Abr = int(tseg2_abr)
271-
if data_bitrate:
272-
self.canFdConf.dataBitRate = int(data_bitrate)
273-
else:
274-
self.canFdConf.dataBitRate = self.canFdConf.arbitrationBitRate
275-
self.canFdConf.sjwDbr = int(sjw_dbr)
276-
self.canFdConf.tseg1Dbr = int(tseg1_dbr)
277-
self.canFdConf.tseg2Dbr = int(tseg2_dbr)
278-
279-
self.xldriver.xlCanFdSetConfiguration(
280-
self.port_handle, self.mask, self.canFdConf
281-
)
282-
LOG.info(
283-
"SetFdConfig.: ABaudr.=%u, DBaudr.=%u",
284-
self.canFdConf.arbitrationBitRate,
285-
self.canFdConf.dataBitRate,
286-
)
287-
LOG.info(
288-
"SetFdConfig.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
289-
self.canFdConf.sjwAbr,
290-
self.canFdConf.tseg1Abr,
291-
self.canFdConf.tseg2Abr,
292-
)
293-
LOG.info(
294-
"SetFdConfig.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u",
295-
self.canFdConf.sjwDbr,
296-
self.canFdConf.tseg1Dbr,
297-
self.canFdConf.tseg2Dbr,
298-
)
299-
else:
300-
if bitrate:
301-
self.xldriver.xlCanSetChannelBitrate(
302-
self.port_handle, permission_mask, bitrate
228+
for channel in self.channels:
229+
if permission_mask.value & self.channel_masks[channel]:
230+
if fd:
231+
self._set_bitrate_canfd(
232+
channel=channel,
233+
bitrate=bitrate,
234+
data_bitrate=data_bitrate,
235+
sjw_abr=sjw_abr,
236+
tseg1_abr=tseg1_abr,
237+
tseg2_abr=tseg2_abr,
238+
sjw_dbr=sjw_dbr,
239+
tseg1_dbr=tseg1_dbr,
240+
tseg2_dbr=tseg2_dbr,
303241
)
304-
LOG.info("SetChannelBitrate: baudr.=%u", bitrate)
305-
else:
306-
LOG.info("No init access!")
242+
elif bitrate:
243+
self._set_bitrate_can(channel=channel, bitrate=bitrate)
307244

308245
# Enable/disable TX receipts
309246
tx_receipts = 1 if receive_own_messages else 0
@@ -348,6 +285,153 @@ def __init__(
348285
self._is_filtered = False
349286
super().__init__(channel=channel, can_filters=can_filters, **kwargs)
350287

288+
def _find_global_channel_idx(
289+
self,
290+
channel: int,
291+
serial: Optional[int],
292+
app_name: Optional[str],
293+
channel_configs: List["VectorChannelConfig"],
294+
) -> int:
295+
if serial is not None:
296+
hw_type: Optional[xldefine.XL_HardwareType] = None
297+
for channel_config in channel_configs:
298+
if channel_config.serialNumber != serial:
299+
continue
300+
301+
hw_type = xldefine.XL_HardwareType(channel_config.hwType)
302+
if channel_config.hwChannel == channel:
303+
return channel_config.channelIndex
304+
305+
if hw_type is None:
306+
err_msg = f"No interface with serial {serial} found."
307+
else:
308+
err_msg = f"Channel {channel} not found on interface {hw_type.name} ({serial})."
309+
raise CanInitializationError(
310+
err_msg, error_code=xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT
311+
)
312+
313+
if app_name:
314+
hw_type, hw_index, hw_channel = self.get_application_config(
315+
app_name, channel
316+
)
317+
idx = cast(
318+
int, self.xldriver.xlGetChannelIndex(hw_type, hw_index, hw_channel)
319+
)
320+
if idx < 0:
321+
# Undocumented behavior! See issue #353.
322+
# If hardware is unavailable, this function returns -1.
323+
# Raise an exception as if the driver
324+
# would have signalled XL_ERR_HW_NOT_PRESENT.
325+
raise VectorInitializationError(
326+
xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT,
327+
xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT.name,
328+
"xlGetChannelIndex",
329+
)
330+
return idx
331+
332+
# check if channel is a valid global channel index
333+
for channel_config in channel_configs:
334+
if channel == channel_config.channelIndex:
335+
return channel
336+
337+
raise CanInitializationError(
338+
f"Channel {channel} not found. The 'channel' parameter must be "
339+
f"a valid global channel index if neither 'app_name' nor 'serial' were given.",
340+
error_code=xldefine.XL_Status.XL_ERR_HW_NOT_PRESENT,
341+
)
342+
343+
def _set_bitrate_can(
344+
self,
345+
channel: int,
346+
bitrate: int,
347+
sjw: Optional[int] = None,
348+
tseg1: Optional[int] = None,
349+
tseg2: Optional[int] = None,
350+
sam: int = 1,
351+
) -> None:
352+
kwargs = [sjw, tseg1, tseg2]
353+
if any(kwargs) and not all(kwargs):
354+
raise ValueError(
355+
f"Either all of sjw, tseg1, tseg2 must be set or none of them."
356+
)
357+
358+
# set parameters if channel has init access
359+
if any(kwargs):
360+
chip_params = xlclass.XLchipParams()
361+
chip_params.bitRate = bitrate
362+
chip_params.sjw = sjw
363+
chip_params.tseg1 = tseg1
364+
chip_params.tseg2 = tseg2
365+
chip_params.sam = sam
366+
self.xldriver.xlCanSetChannelParams(
367+
self.port_handle,
368+
self.channel_masks[channel],
369+
chip_params,
370+
)
371+
LOG.info(
372+
"xlCanSetChannelParams: baudr.=%u, sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
373+
chip_params.bitRate,
374+
chip_params.sjw,
375+
chip_params.tseg1,
376+
chip_params.tseg2,
377+
)
378+
else:
379+
self.xldriver.xlCanSetChannelBitrate(
380+
self.port_handle,
381+
self.channel_masks[channel],
382+
bitrate,
383+
)
384+
LOG.info("xlCanSetChannelBitrate: baudr.=%u", bitrate)
385+
386+
def _set_bitrate_canfd(
387+
self,
388+
channel: int,
389+
bitrate: Optional[int] = None,
390+
data_bitrate: Optional[int] = None,
391+
sjw_abr: int = 2,
392+
tseg1_abr: int = 6,
393+
tseg2_abr: int = 3,
394+
sjw_dbr: int = 2,
395+
tseg1_dbr: int = 6,
396+
tseg2_dbr: int = 3,
397+
) -> None:
398+
# set parameters if channel has init access
399+
canfd_conf = xlclass.XLcanFdConf()
400+
if bitrate:
401+
canfd_conf.arbitrationBitRate = int(bitrate)
402+
else:
403+
canfd_conf.arbitrationBitRate = 500_000
404+
canfd_conf.sjwAbr = int(sjw_abr)
405+
canfd_conf.tseg1Abr = int(tseg1_abr)
406+
canfd_conf.tseg2Abr = int(tseg2_abr)
407+
if data_bitrate:
408+
canfd_conf.dataBitRate = int(data_bitrate)
409+
else:
410+
canfd_conf.dataBitRate = int(canfd_conf.arbitrationBitRate)
411+
canfd_conf.sjwDbr = int(sjw_dbr)
412+
canfd_conf.tseg1Dbr = int(tseg1_dbr)
413+
canfd_conf.tseg2Dbr = int(tseg2_dbr)
414+
self.xldriver.xlCanFdSetConfiguration(
415+
self.port_handle, self.channel_masks[channel], canfd_conf
416+
)
417+
LOG.info(
418+
"xlCanFdSetConfiguration.: ABaudr.=%u, DBaudr.=%u",
419+
canfd_conf.arbitrationBitRate,
420+
canfd_conf.dataBitRate,
421+
)
422+
LOG.info(
423+
"xlCanFdSetConfiguration.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u",
424+
canfd_conf.sjwAbr,
425+
canfd_conf.tseg1Abr,
426+
canfd_conf.tseg2Abr,
427+
)
428+
LOG.info(
429+
"xlCanFdSetConfiguration.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u",
430+
canfd_conf.sjwDbr,
431+
canfd_conf.tseg1Dbr,
432+
canfd_conf.tseg2Dbr,
433+
)
434+
351435
def _apply_filters(self, filters: Optional[CanFilters]) -> None:
352436
if filters:
353437
# Only up to one filter per ID type allowed
@@ -544,7 +628,7 @@ def _send_sequence(self, msgs: Sequence[Message]) -> int:
544628

545629
def _get_tx_channel_mask(self, msgs: Sequence[Message]) -> int:
546630
if len(msgs) == 1:
547-
return self.channel_masks.get(msgs[0].channel, self.mask)
631+
return self.channel_masks.get(msgs[0].channel, self.mask) # type: ignore[arg-type]
548632
else:
549633
return self.mask
550634

0 commit comments

Comments
 (0)