2121 Any ,
2222 Dict ,
2323 Callable ,
24+ cast ,
2425)
2526
2627WaitForSingleObject : Optional [Callable [[int , int ], int ]]
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