python-can icon indicating copy to clipboard operation
python-can copied to clipboard

'ixxat' interface not detected

Open felixdivo opened this issue 2 years ago • 9 comments

The 'ixxat' interface is not detected with python-can 3.3.4 :

import can

can.interface.detect_available_configs()

Kvaser canlib is unavailable.
fcntl not available on this platform
libc is unavailable
failed to fetch opened can devices: [WinError 2] Le fichier spécifié est introuvable
Failed to load NI-CAN driver: [WinError 126] Le module spécifié est introuvable
Failed to load IS-CAN driver: [WinError 126] Le module spécifié est introuvable
Could not import vxlapi: [WinError 126] Le module spécifié est introuvable
Cannot load SYSTEC ucan library: [WinError 126] Le module spécifié est introuvable.
The SYSTEC ucan library has not been initialized.

[{'interface': 'virtual', 'channel': 'channel-3439'},
 {'interface': 'neovi', 'serial': '120216'}]

If I loop on all interfaces, I can detect it though :

# List possible CAN adapters (from 'python-can')
l_dict_valid = {}
l_list_cards = list(can.interfaces.BACKENDS.keys())
l_list_cards.sort()

# Drivers for supported cards :
# 'canalystii'	: http
# 'iscan'		: http
# 'ixxat'		: https://www.ixxat.com/docs/librariesprovider8/ixxat-english-new/pc-can-interfaces/windows-drivers/vci-v4-windows-10-8-7.zip?sfvrsn=9ceb48d7_75
# 'kvaser'		: http
# 'neovi'		: https://cdn.intrepidcs.net/updates/files/RP1210KitInstall.zip
# 	old driver	 (https://cdn.intrepidcs.net/updates/files/ICSDrivers.zip)
# 'nican'		: http
# 'pcan'		: http
# 'serial'		: http
# 'slcan'		: http
# 'socketcan'	: http
# 'systec'		: http
# 'usb2can'		: http
# 'vector'		: http
# 'virtual'		: http

# Virtual in an useless stub
l_list_cards.remove('virtual')

print(f"=== Loading CAN drivers ===")
for loop_str_card in l_list_cards:
	# Try all l_list_cards
	print(f"\n... Loading '{loop_str_card}' ...")
	for loop_int_chan in range(4):
		# Try only first 4 channels
		for loop_str_baud, loop_int_baud in dict_CANP_CARD__BAUD.items():
			# Try all bauds (1m, 500k, 250k, 125k)
			try:
				# Try connecting
				with can.interface.Bus(
							bustype = str(loop_str_card),
							channel = str(loop_int_chan),
							bitrate = int(loop_int_baud)
						) as l_obj_bus:
					# Register the combination as valid
					try:
						l_dict_valid[loop_str_card]
						# - except KeyError -
						try:
							l_dict_valid[loop_str_card][loop_int_chan]
							# - except KeyError -
							try:
								l_dict_valid[loop_str_card][loop_int_chan][loop_str_baud]
								# - except KeyError -
								# Register baudrate
								raise KeyError
							except KeyError:
								l_dict_valid[loop_str_card][loop_int_chan][loop_str_baud] = loop_int_baud
						except KeyError:
							l_dict_valid[loop_str_card][loop_int_chan] = {loop_str_baud: loop_int_baud}
					except KeyError:
						l_dict_valid[loop_str_card] = {loop_int_chan: {loop_str_baud: loop_int_baud}}
			except:
				# Connection failed
				pass
C:\Program Files\Spyder\Python>enaml-run "c:\Users\dkoch\Downloads\CAN\canp\canp_card_view.enaml"
=== Loading CAN drivers ===

... Loading 'canalystii' ...

... Loading 'iscan' ...
Failed to load IS-CAN driver: [WinError 126] Le module spécifié est introuvable

... Loading 'ixxat' ...

... Loading 'kvaser' ...
Kvaser canlib is unavailable.

... Loading 'neovi' ...
Error: set_bit_rate(): icsneoSetBitRate() Failed
Error: set_bit_rate(): icsneoSetBitRate() Failed
Error: set_bit_rate(): icsneoSetBitRate() Failed
Error: set_bit_rate(): icsneoSetBitRate() Failed
Error: set_bit_rate(): icsneoSetBitRate() Failed
Error: set_bit_rate(): icsneoSetBitRate() Failed
Error: set_bit_rate(): icsneoSetBitRate() Failed
Error: set_bit_rate(): icsneoSetBitRate() Failed

... Loading 'nican' ...
Failed to load NI-CAN driver: [WinError 126] Le module spécifié est introuvable

... Loading 'pcan' ...

... Loading 'serial' ...

... Loading 'slcan' ...

... Loading 'socketcan' ...
fcntl not available on this platform
libc is unavailable

... Loading 'systec' ...
Cannot load SYSTEC ucan library: [WinError 126] Le module spécifié est introuvable.

... Loading 'usb2can' ...

... Loading 'vector' ...
Could not import vxlapi: [WinError 126] Le module spécifié est introuvable

Yet trying all channels and all baud-rates pretty much hurts the CAN bus a lot (if not resilient to such invasion).

Regards.

Originally posted by @Kochise in https://github.com/hardbyte/python-can/issues/303#issuecomment-964886754

felixdivo avatar Nov 10 '21 13:11 felixdivo

Hmm. We're using the ixxat usb interfaces a lot at work. Let me have a look onto this tomorrow. My guess is that you don't have the driver installed and there is an issue with loading the module. Could you please print the exception that you currently ignore (The pass statement under the comment Connection failed)? This might help with the other backends too.

marcel-kanter avatar Nov 11 '21 16:11 marcel-kanter

Just to make it clear, this was

Originally posted by @Kochise in #303 (comment)

Thanks @marcel-kanter for having a look!

felixdivo avatar Nov 11 '21 16:11 felixdivo

Thanks for opening this issue. I don't have access to the hardware anymore, but I'll ask somebody that do.

The drivers were perfectly installed because I could use both adapters and my "discovery" loop worked fine for both of them.

BTW, is there a way to get more infos about an interface ? For instance, the neovi have two channels (ch1 and ch2) while the ixxat only have one (ch0). It would be great to have something like :

import can

can.interface.detect_available_configs()

[...]

[{'interface': 'virtual', 'channel': 'channel-3439'},
 {'interface': 'neovi', 'serial': '120216', 'channels': {'1': [1000000, 500000, 250000, 125000], '2': [1000000, 500000, 250000, 125000]}},
 {'interface': 'ixxat', 'serial': 'abcdef', 'channels': {'0': [1000000, 500000, 250000, 125000]}}]

Hence that would help to know what's possible without having to try all combinations.

Regards.

Kochise avatar Nov 13 '21 16:11 Kochise

First the code:

import can
import logging

logging.basicConfig(level = logging.DEBUG)

can.interface.detect_available_configs(['ixxat'])

Then the output:

pydev debugger: starting (pid: 6296)
DEBUG:can.ctypesutil:Wrapped function "vciInitialize", result type: <class '_ctypes.PyCSimpleType'>, error_check <function __check_status at 0x0000029043D0A9D0>
DEBUG:can.ctypesutil:Wrapped function "vciFormatError", result type: <class 'NoneType'>, error_check None
DEBUG:can.ctypesutil:Wrapped function "vciEnumDeviceOpen", result type: <class '_ctypes.PyCSimpleType'>, error_check <function __check_status at 0x0000029043D0A9D0>
DEBUG:can.ctypesutil:Wrapped function "vciEnumDeviceClose", result type: <class '_ctypes.PyCSimpleType'>, error_check <function __check_status at 0x0000029043D0A9D0>
DEBUG:can.ctypesutil:Wrapped function "vciEnumDeviceNext", result type: <class '_ctypes.PyCSimpleType'>, error_check <function __check_status at 0x0000029043D0A9D0>

...

DEBUG:can.ctypesutil:Wrapped function "canSchedulerStopMessage", result type: <class '_ctypes.PyCSimpleType'>, error_check <function __check_status at 0x0000029043D0A9D0>
DEBUG:can.interface.detect_available_configs:interface "ixxat" does not support detection of available configurations

Now the explanation:

I know for sure, there are adapters made by ixxat that have one or two interfaces. I use some of them and maybe there are some with more channels.

Back to the problem: detect_available_configs does not simply open the interface and tries all combinations. It forwards the work to the backends. Each bus interface needs to implement a method called '_detect_available_configs'. The function _detect_available_configs is not implemented for ixxat interface. So it falls back to the BusABC implementation, which raises the NotImplementedError. The logger used by detect_available_configs logs on level debug, so you don't see it normally.

From my point of view some working points arise:

  1. _detect_available_configs should not have the leading underscore
  2. detect_available_configs need to be implemented for the ixxat interface The function vciEnumDeviceNext may be used for this. It gets data about the interface (adapter) into an struct. I think this structure contains info about the serial and channel count.
  3. a fall-back to "open an try" may be implemented in the detect_available_configs. Reason: The methods listed above are available for linux too, but the implementation is a mess. There is an driver for each type of adapter, and the methods are named all differently (with suffix). In the past I wanted to talk to ixxat about this, but then we used the internal can interface with (socket can) under linux. Additionally how to implement the detectino functionality with socket can?
  4. the logger level maybe increased
  5. Listing all available baudrates would blow up the list. Especially with CAN-FD (many arbitration-bitrate and data-bitrate combinations lead to a long list). Maybe test and include the standard baudrates only? E.g. 10, 20, 50, 100, 125, 250, 500, 800 1000 kbaud ? For can-fd I think we should go for the 250, 500, 1000 kBaud with a multiplier of 2, 4, 8, 10 (I don't list all the commonly used ones here). The standard may include some recommended combos.

marcel-kanter avatar Nov 14 '21 09:11 marcel-kanter

import can
import logging

log = logging.getLogger('can.interface')
log_autodetect = log.getChild('detect_available_configs')

log_autodetect.setLevel(logging.DEBUG)

can.interface.detect_available_configs()

Can be used to get info about which interface implements the detection:

DEBUG:can.interface.detect_available_configs:interface "usb2can" can not be loaded for detection of available configurations
DEBUG:can.interface.detect_available_configs:interface "ixxat" does not support detection of available configurations
ERROR:can.interfaces.nican:Failed to load NI-CAN driver: Could not find module 'nican' (or one of its dependencies). Try using the full path with constructor syntax.
DEBUG:can.interface.detect_available_configs:interface "nican" does not support detection of available configurations
WARNING:can.interfaces.iscan:Failed to load IS-CAN driver: Could not find module 'iscandrv' (or one of its dependencies). Try using the full path with constructor syntax.
DEBUG:can.interface.detect_available_configs:interface "iscan" does not support detection of available configurations
DEBUG:can.interface.detect_available_configs:interface "virtual" detected 1 available configurations
WARNING:can.interfaces.ics_neovi.neovi_bus:You won't be able to use the ICS NeoVi can backend without the python-ics module installed!: No module named 'ics'
WARNING:can.interfaces.ics_neovi.neovi_bus:Using ICS NeoVi can backend without the filelock module installed may cause some issues!: No module named 'filelock'
DEBUG:can.interface.detect_available_configs:interface "neovi" detected 0 available configurations
WARNING:can.interfaces.vector.canlib:Could not import vxlapi: Could not find module 'vxlapi64' (or one of its dependencies). Try using the full path with constructor syntax.
DEBUG:can.interface.detect_available_configs:interface "vector" detected 0 available configurations
WARNING:can.interfaces.slcan:You won't be able to use the slcan can backend without the serial module installed!
DEBUG:can.interface.detect_available_configs:interface "slcan" does not support detection of available configurations
DEBUG:can.interface.detect_available_configs:interface "canalystii" does not support detection of available configurations
WARNING:can.systec:Cannot load SYSTEC ucan library: Could not find module 'usbcan64.dll' (or one of its dependencies). Try using the full path with constructor syntax..
WARNING:can.systec:The SYSTEC ucan library has not been initialized.
DEBUG:can.interface.detect_available_configs:interface "systec" detected 0 available configurations

marcel-kanter avatar Nov 14 '21 09:11 marcel-kanter

Better than nothing, yet doesn't nicely solve my problem, though.

Having some interfaces not being fully supported jeopardize their use unless we know for sure what they can do before connecting them to the bus. The CAN interface being live, trying combinations blindly kills the bus.

Better stick to known channels' identifier and compatible baud-rates. I'll have to store known working combinations locally.

Thank.

Kochise avatar Nov 14 '21 15:11 Kochise

5. Listing all available baudrates would blow up the list. Especially with CAN-FD (many arbitration-bitrate and data-bitrate combinations lead to a long list). Maybe test and include the standard baudrates only? E.g. 10, 20, 50, 100, 125, 250, 500, 800 1000 kbaud ? For can-fd I think we should go for the 250, 500, 1000 kBaud with a multiplier of 2, 4, 8, 10 (I don't list all the commonly used ones here). The standard may include some recommended combos.

I understand that there may be many baudrates available, it was mostly to feed a combobox with "standard" rates. Yet some can adapters do not support 1M hence it would be pointless to pretend the user can select that speed if in fact it cannot.

I also reiterate

It would be great to have something like :

import can

can.interface.detect_available_configs()

[...]

[{'interface': 'virtual', 'channel': 'channel-3439'},
 {'interface': 'neovi', 'serial': '120216', 'channels': {'1': [1000000, 500000, 250000, 125000], '2': [1000000, 500000, 250000, 125000]}},
 {'interface': 'ixxat', 'serial': 'abcdef', 'channels': {'0': [1000000, 500000, 250000, 125000]}}]

Because as you can see, not all adapters count the channels the same way, and again, it would be super handy to know in advance what an adapter can do without having to trash the can bus trying every combination.

Don't the adapters' driver have a declarative interface you can probe their capabilities with ?

Regards.

Kochise avatar Nov 26 '21 11:11 Kochise

OK. I'm working on this. And I made an generalized addition to the BusABC which should be rolled out to all interfaces. The term serial in the example above is a bit too specific, but the idea is good. I changed it to adapter - this can be used for tree structures (like the port in USB tree oder PCI too and does not imply that there is something like an serializing number for the actual interface device. For serial ports you might use the com-port number or the place in device tree (windows has adopted this concept from linux many years ago but hides it).

Current state is that it is possible to list all adapters.

>>> from can.interfaces.ixxat import IXXATBus
>>> for hwid in IXXATBus.list_adapters():
...     print("Found IXXAT adapter with hardware id '%s'." % hwid)
Found IXXAT adapter with hardware id 'HW441489'.
Found IXXAT adapter with hardware id 'HW107422'.

Generating the the configurations will be the next step.

marcel-kanter avatar Dec 02 '21 21:12 marcel-kanter

Looks promising...

Yeah, 'serial' is more 'sn', which the adapters are often identified with a sticker on them. Helps to identify them apart when you have several attached on your computer.

Kochise avatar Dec 03 '21 08:12 Kochise