Improved API in Python canlib v1.5

  • March 27, 2018
  • Magnus Carlsson

In version 1.5 of the Python wrapper, a lot of improvements were made. Two new libraries were wrapped; LINlib, which holds the LIN bus API, and kvaDbLib which contains the Database API (and there will be some blog on how to use those in the future).

The biggest change was however under the hood were the code has been restructured to make it more maintainable and easier to use. The ‘old’ way is still available but is deprecated and will be removed in the future. This is an example of how it used to look in v1.4:

import canlib.canlib as canlib


def setUpChannel(channel=0,
                 openFlags=canlib.canOPEN_ACCEPT_VIRTUAL,
                 bitrate=canlib.canBITRATE_500K,
                 bitrateFlags=canlib.canDRIVER_NORMAL):
    cl = canlib.canlib() # deprecated in v1.5
    ch = cl.openChannel(channel, openFlags)
    print("Using channel: %s, EAN: %s" % (ch.getChannelData_Name(), # deprecated in v1.5
                                          ch.getChannelData_EAN())) # deprecated in v1.5
    ch.setBusOutputControl(bitrateFlags)
    ch.setBusParams(bitrate)
    ch.busOn()
    return ch


def tearDownChannel(ch):
    ch.busOff()
    ch.close()


cl = canlib.canlib() # deprecated in v1.5
print("canlib version: %s" % cl.getVersion())

ch0 = setUpChannel(channel=0)
ch1 = setUpChannel(channel=1)

msgId = 100
msg = [1, 2, 3, 4]
flg = canlib.canMSG_EXT
ch1.write(msgId, msg, flg)
# deprecated in v1.5

while True:
    try:
        (msgId, msg, dlc, flg, time) = ch0.read() # deprecated in v1.5
        data = ''.join(format(x, '02x') for x in msg)
        print("time:%9d id:%9d flag:0x%02x dlc:%d data:%s" %
              (time, msgId, flg, dlc, data))
        break
    except (canlib.canNoMsg) as ex:
        pass
    except (canlib.canError) as ex:
        print(ex)

tearDownChannel(ch0)
tearDownChannel(ch1)

Listing 1: Code to send single frame


Running the above now gives a note that we are using deprecated functions.

canlib\deprecation.py:240: KvDeprecatedUsage: A deprecated function was
 called! Run python with -Wd flag for more information.
  "Run python with -Wd flag for more information."))
canlib version: 8.22
Using channel: Kvaser USBcan Pro 2xHS v2 (channel 0), EAN: 73-30130-00752-9
Using channel: Kvaser USBcan Pro 2xHS v2 (channel 1), EAN: 73-30130-00752-9
time:        9 id:      100  flag:0x04  dlc:4  data:01020304

Let us run the same code using the warning control flag -Wd as suggested:

canlib\deprecation.py:238: KvDeprecatedUsage: A deprecated function was called! Run
     python with -Wd flag for more information.
  "Run python with -Wd flag for more information."))
send_single_frame_v1.4.py:23: KvDeprecationWarning: Creating CANLib objects is
     deprecated, all functionality has been moved to the canlib module itself.
  cl = canlib.canlib() # deprecated in v1.5
send_single_frame_v1.4.py:24: KvDeprecationWarning: getVersion has been deprecated,
     use dllversion instead!
  print("canlib version: %s" % cl.getVersion())
canlib version: 8.21
send_single_frame_v1.4.py:8: KvDeprecationWarning: Creating CANLib objects is
     deprecated, all functionality has been moved to the canlib module itself.
  cl = canlib.canlib() # deprecated in v1.5
send_single_frame_v1.4.py:10: KvDeprecationWarning: getChannelData_Name has been
     deprecated, use ChannelData(Channel.index).device_name instead!
  print("Using channel: %s, EAN: %s" % (ch.getChannelData_Name(), # deprecated in v1
       .5
canlib\canlib\channel.py:537: KvDeprecationWarning: getChannelData_Name has been
     deprecated, use ChannelData(channel).device_name instead!
  return wrapper.getChannelData_Name(self.index)
send_single_frame_v1.4.py:11: KvDeprecationWarning: getChannelData_EAN has been
     deprecated, use ChannelData(Channel.index).card_upc_no instead!
  ch.getChannelData_EAN())) # deprecated in v1.5
canlib\canlib\channel.py:558: KvDeprecationWarning: getChannelData_EAN has been
     deprecated, use ChannelData(channel).card_upc_no instead!
  return wrapper.getChannelData_EAN(self.index)
Using channel: Kvaser USBcan Pro 2xHS v2 (channel 0), EAN: 73-30130-00752-9
Using channel: Kvaser USBcan Pro 2xHS v2 (channel 1), EAN: 73-30130-00752-9
send_single_frame_v1.4.py:32: KvDeprecationWarning: Calling Channel.write() with
     individual arguments is deprecated, please use a Frame object or Channel.
     write_raw()
  ch1.write(msgId, msg, flg) # deprecated in v1.5
time:       14 id:      100 flag:0x04  dlc:4  data:01020304

This time we get a detailed notification that creating CANlib objects on line 8 and line 23 is deprecated, and that all functionality has been moved to the canlib module. The getChannelData_EAN on line 11 is also deprecated and should be replaced by ChannelData(channel).card_upc_no . We should also use the Frame object instead of individual arguments in our call to write on line 32 and, even though we do not get a deprecation warning, the Frame object should also be used in our read function on line 36 as well. The Frame object can then be printed directly. Let us adjust our code accordingly:

from canlib import canlib, Frame
from canlib.canlib import ChannelData


def setUpChannel(channel=0,
                 openFlags=canlib.canOPEN_ACCEPT_VIRTUAL,
                 bitrate=canlib.canBITRATE_500K,
                 bitrateFlags=canlib.canDRIVER_NORMAL):
    ch = canlib.openChannel(channel, openFlags)
    print("Using channel: %s, EAN: %s" % (ChannelData(channel).device_name,
                                          ChannelData(channel).card_upc_no)
                                              )
    ch.setBusOutputControl(bitrateFlags)
    ch.setBusParams(bitrate)
    ch.busOn()
    return ch


def tearDownChannel(ch):
    ch.busOff()
    ch.close()


print("canlib version:", canlib.dllversion())

ch0 = setUpChannel(channel=0)
ch1 = setUpChannel(channel=1)

frame = Frame(id_=100, data=[1, 2, 3, 4], flags=canlib.canMSG_EXT)
ch1.write(frame)

while True:
    try:
        frame = ch0.read()
        print(frame)
        break
    except (canlib.canNoMsg) as ex:
        pass
    except (canlib.canError) as ex:
        print(ex)

tearDownChannel(ch0)
tearDownChannel(ch1)

Listing 2: Code to send single frame using Python canlib v1.5


When we added Frame and ChannelData to the import line, we also took the opportunity to transform the import statement into a slightly more readable format. Running the new code shows a clean output:

canlib version: 8.22
Using channel: Kvaser USBcan Pro 2xHS v2 (channel 0), EAN: 73-30130-00752-9
Using channel: Kvaser USBcan Pro 2xHS v2 (channel 1), EAN: 73-30130-00752-9
Frame(id=100, data=bytearray(b'\x01\x02\x03\x04'), dlc=4, flags=4, timestamp=10)

Take a look through the release notes to get an overview of what has changed, and use the Python warning control flag -Wd to make sure that your code is up-to-date. This new way of doing things will really increase the maintainability of the library, and hopefully will also make it easier to get going with controlling Kvaser devices using Python.

Author Image

Magnus Carlsson

Magnus Carlsson is a Software Developer for Kvaser AB and has developed firmware and software for Kvaser products since 2007. He has also written a number of articles for Kvaser’s Developer Blog dealing with the popular Python language.