Digging deeper into kvmlib

  • September 18, 2018
  • Magnus Carlsson

This is the third post in a 4-part series about configuring and reading logged data using a Kvaser Memorator 2nd Generation device through kvmlib:

In the first part we showed how to use kvmlib to configure a device and read the logged messages using Python. In this part we will be revisiting the configuring we did in the second part while showing some more things you can do with kvmlib, including saving and restoring your configuration on the Kvaser Memorator’s SD-card. There’s also a blog series about Setting Up CANlib for Visual Studio which might be useful.

3.1 Opening the device

Opening a device using kvmlib requires knowledge about more than just the EAN number. When connecting to a device using the Python canlib Device module, the code internally looks though all devices connected to our computer and returns the first one that match our search criteria, in our case the EAN number.

# 05_report_device.py
from canlib import Device, EAN


# Create an EAN object for our device by specifying the last six numbers
ean = EAN('00819-9')
print('Full EAN: {}\n'.format(ean))

# Find our Kvaser Memorator Pro 2xHS with EAN 00819-9
dev = Device.find(ean=ean, serial=None)

# Print information about the device
print(dev.probe_info())
Full EAN: 73-30130-00819-9

CANlib Channel: 0
Card Number   : 0
Device        : Kvaser Memorator Pro 2xHS v2 (channel 0)
Driver Name   : kcany0a
EAN           : 73-30130-00819-9
Firmware      : 3.11.0.557
Serial Number : 11573

Listing 8: Printing information about a connected Kvaser device.


Here we note that our device is connected to CANlib channel 0 , the CANlib channel number is used when opening the device from CANlib.1 If we had opened a second device, those numbers would be different on the second device.

When opening our device using kvmlib, beside specifying the CANlib channel, we may also specify a device type. The device type is used to decide what version of LIO data format the device is using.2 Firmware v3.0 uses device type kvmDEVICE_MHYDRA_EXT, which is the default in v1.7 of the python canlib module. The last argument to kvmlib.openDevice is mount, which indicates whether the Memorator log area should be mounted or not (default is False).

Let us take a look on how to set the device clock using kvmlib.

# 06_set_clock.py
from canlib import kvmlib
import datetime


# We know that our device is connected to CANlib channel number 0
channel = 0

# We also know that our device is of type kvmDEVICE_MHYDRA_EXT
with kvmlib.openDevice(
        channel_number=channel,
        device_type=kvmlib.Device.MHYDRA_EXT) as device:
    # Having obtained the device, we can now e.g. check the
    # serial number
    print("Serial number:", device.serial_number)

    # Read the device time
    print("Current device time is", device.rtc)

    # Set the real time clock of the device
    device.rtc = datetime.datetime.now()

    # Read the device time
    print("New device time is", device.rtc)

Listing 9: Setting the real time clock of a Kvaser device using kvmlib.

Serial number: 11573
Current device time is 2018-08-10 07:47:46
New device time is 2018-08-10 07:52:48

Running the above code gives the following output:

3.2 Initialize the SD card

As stated earlier, using the correct device type when opening a device is very important. If we open a device using the wrong LIO data format (as specified using the device type), we will not be able to see any log messages during reading. Using the correct device type when initializing the SD card is even more important since the firmware will not be able to access an SD card that has been initialized using an incorrect LIO data format.

In order to initialize the SD card, we first open the device using kvmlib.openDevice where we need to supply our device type, which on a Kvaser Memorator 2nd Generation device (running on fw v3.0) is kvmDEVICE_MHYDRA_EXT 3.

Then we initialize the SD card by calling format_disk. Most of the SD card is allocated for recording log messages during initialization, but there are two sizes that we can affect by passing two different arguments to the initialization command.

The first argument is specifying “space to reserve for user files”, which means that this amount of the SD card will be free for use by the user. We could have a tprogram running in the device that generates text files, or we may have other user files that we would like to copy to the SD card.

The second argument affects the size of a file called DATABASE.BIN which is used by the Kvaser Memorator Config Tool and may contain the configuration and database files that a user optionally can save to the SD card.

After mounting the Memorator’s newly formatted log area, we check that we got the expected LIO data format, and thus verify that we supplied the correct device type.

# 07_verify_lio_init_sdcard.py
from canlib import kvmlib
from canlib import VersionNumber

# We saw earlier that our device is connected to CANlib channel number 0
channel = 0

# We also know that our device is of type kvmDEVICE_MHYDRA_EXT
device_type = kvmlib.kvmDEVICE_MHYDRA_EXT

# Open the device
with kvmlib.openDevice(channel_number=channel,
                       device_type=device_type,
                       mount=False) as memorator:

    # Format the SD Card and reserve 10 MB for configuration files
    # (i.e. DATABASE.BIN) and 1000 MB for our own files.
    print('Initializing SD card...')
    memorator.format_disk(reserved_space=10000,
                          database_space=10)

    # Mount the log area
    memorator.mount()

    # Read LIO data format version
    lio_data_format = memorator.log.ldf_version

    # Verify that the LIO data format of the card corresponds to
    # the device type we used when opening the device
    if lio_data_format != VersionNumber(major=5, minor=0):
        if lio_data_format == VersionNumber(major=3, minor=0):
            raise ValueError('This log file can be read if you reopen the'
                             ' device as kvmDEVICE_MHYDRA.')
        raise ValueError('Unexpected Lio Data Format: ' +
                         str(lio_data_format))

    # Report info about the disk area allocated for logging
    print('Disk size: {disk:.0f} MB\n'
          '  Log size: {log:.0f} MB. Used: {used:.0f} MB'.
          format(disk=memorator.disk_size,
                 log=memorator.disk_usage.total,
                 used=memorator.disk_usage.used))

Listing 10: Verify LIO data format and initialize disk of a Kvaser device.

Initializing SD card...
Disk size: 15932 MB
  Log size: 5895 MB. Used: 0 MB

Our Kvaser Memorator device has a 16 GB SD card, and when we now reserved 10 MB for DATABASE.BIN and 10 GB as free space we are left with 5895 MB for logging data. Since we have just initialized the SD card, we also have 0 MB (used) logged data.

The device and it’s SD card is now initialized and ready to be configured.


3.3 Save configuration

To save the configuration to the device’s SD-card, we convert the validated XML configuration to a binary configuration and download this binary configuration to the device (just as we did in the first post of this blog series).

# 08_save_config.py
from canlib import kvamemolibxml
from canlib import kvmlib


# We saw earlier that our device is connected to CANlib channel number 0
channel = 0
# Read in the XML configuration file
with open("config.xml", 'r') as myfile:
    print('Reading xml')
    config_xml = myfile.read()

# Convert the XML configuration to a binary configuration
config_lif = kvamemolibxml.kvaXmlToBuffer(config_xml)

# Open the memorator device and write the configuration
# Device type kvmDEVICE_MHYDRA_EXT is default
with kvmlib.openDevice(channel_number=channel) as memorator:
    print('Writing config')
    memorator.write_config(config_lif)

Listing 11: Converting and downloading the configuration to a Kvaser device.

In order to later be able to retrieve the configuration in clear text, we create a zip file (config.zip) of the files we have used and download onto the device.4 Since we earlier used the argument -addsrc when we compiled the t program5, we only need the compiled .txe file and our XML configuration. If we had used any databases, we would add those to the zip archive as well.

# 09_copy_files_to_device.py
import zipfile
from canlib import canlib

# Create Zip archive
with zipfile.ZipFile("config.zip", mode='w',
                     compression=zipfile.ZIP_DEFLATED) as zipf:
    # Adding files to zip archive
    zipf.write("config.xml")
    zipf.write("myCanGenerator.txe")

# We know that our device was connected to CANlib channel number 0
channel = 0

# Open the device and write the zip archive
with canlib.openChannel(channel=channel) as ch:
    # Since the SD card is formated using FAT, we should use
    # a 8.3 formated filename as the target filename
    ch.fileCopyToDevice("config.zip", "config.zip")

Listing 12: Downloading clear text configurations using a zip archive.


3.4 Read result and save to file

After the device has been out in the field (i.e. we have applied power through the CAN connector and let the script run), we can once again connect our device to our computer and read out the logged data.6 In order to save the data for the future, we now write the data to a file using the kme50 format. This format can later be converted to a number of formats using the converter that is included in the Kvaser Memorator Config Tool.

The first entry in all log files contain information about the logged device. We take advantage of this here and place part of the EAN and serial number in the name of the resulting .kme50 files.

When all log files have been read from the device, we delete the log files on the device in order to be ready for a new logging run (reusing the same configuration).

# 10_read_logged_data.py
import glob
import os

from canlib import EAN, VersionNumber
from canlib import kvmlib

# We saw earlier that our device is connected to CANlib channel number 0
channel = 0

# Directory to put the resulting files in
resultDir = "result"

# Make sure the result directory exists and is empty
if os.path.isdir(resultDir):
    files = glob.glob(os.path.join(resultDir, "*"))
    for f in files:
        os.remove(f)
else:
    os.mkdir(resultDir)
os.chdir(resultDir)

# Open the device and mount the log area
# Device type kvmDEVICE_MHYDRA_EXT is default
# Note that openDevice() may raise KvmDiskNotFormated
with kvmlib.openDevice(channel_number=channel, mount=True) as memorator:
    lio_data_format = memorator.log.ldf_version
    # Verify that the LIO data format of the card corresponds to
    # the device type we used when opening the device
    if lio_data_format != VersionNumber(major=5, minor=0):
        if lio_data_format == VersionNumber(major=3, minor=0):
            raise ValueError('This log file can be read if you reopen the'
                             ' device as kvmDEVICE_MHYDRA.')
        raise ValueError('Unexpected Lio Data Format: ' + str(lio_data_format))

    # Read number of recorded logfiles
    num_log_files = len(memorator.log)
    print("Found {num} file(s) on card: ".format(num=num_log_files))

    # Loop through all logfiles and write their contents to .kme50 files
    for i, log_file in enumerate(memorator.log):
        print("\n==== File {index}: {start} - {end}, approx {num} events".
              format(index=i,
                     start=log_file.start_time,
                     end=log_file.end_time,
                     num=log_file.event_count_estimation()))
        # The first logEvent contains device information
        event_iterator = iter(log_file)
        first_event = next(event_iterator)
        ean = EAN.from_hilo([first_event.eanHi, first_event.eanLo])
        serial = first_event.serialNumber
        # Add EAN and serial number info to filename
        logfile_name = ('log_{ean}_{sn}_{index:03}.kme50'.
                        format(ean=str(ean), sn=serial, index=i))
        print('Saving to:', logfile_name)
        with kvmlib.createKme(logfile_name) as kme:
            print(first_event)
            kme.write_event(first_event)
            for event in event_iterator:
                # Write event to stdout
                print(event)
                kme.write_event(event)

    # Delete all logfiles
    # memorator.log.delete_all()

Listing 13: Read logged data and save to .kme50 files.

Running the above code we can see that six messages from each channel turns up inside the log.

Found 1 file on card: 

==== File 0: 2018-08-09 15:19:45 - 2018-08-09 15:19:51, approx 20 events
Saving to: log_73-30130-00819-9_11573_000.kme50
*t:             - EAN:73-30130-00819-9  s/n:11573  FW:v3.11.557  LIO:v5.0
 t:   2.824746112  DateTime: 2018-08-09 15:19:45
 t:   2.824746112 Log Trigger Event (type: 0x2, trigno: 0x01, pre-trigger: 0, post-trigger: 0)

 t:   2.824746112  ch:1 f:    2 id:   3 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   2.824746137 Log Trigger Event (type: 0x2, trigno: 0x01, pre-trigger: 0, post-trigger: 0)

 t:   2.824746137  ch:0 f:   42 id:   3 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   3.824770237  ch:1 f:    2 id:   4 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   3.824770262  ch:0 f:   42 id:   4 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   4.824788362  ch:1 f:    2 id:   5 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   4.824788387  ch:0 f:   42 id:   5 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   5.824810487 Log Trigger Event (type: 0x2, trigno: 0x01, pre-trigger: 0, post-trigger: 2500)

 t:   5.824810487  ch:1 f:    2 id:   6 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   5.824810512  ch:0 f:   42 id:   6 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   6.824826612  ch:1 f:    2 id:   7 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   6.824826637  ch:0 f:   42 id:   7 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   7.824851737  ch:1 f:    2 id:   8 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   7.824851762  ch:0 f:   42 id:   8 dlc: 8 d:12 21 13 31 22 34 41 15

Read the blog post Examining logged data with kvmlib and Python for another example on how to read data from a device using kvmlib.


3.5 Read configurations from device.

Earlier we put a copy of our configuration in a config.zip file on the SD card, we may now read all the user files back using CANlib. The resulting file may then be opened using e.g. 7-zip.7

# 11_read_config_from_device.py
import os

from canlib import canlib

# Our device is connected to CANlib channel number 0
channel = 0

# Open the device
with canlib.openChannel(channel=channel) as ch:
    # List files on device
    numFiles = ch.fileGetCount()

    if numFiles:
        for i in range(numFiles):
            name = ch.fileGetName(i)
            # Skip known system files
            if (os.path.splitext(name)[1].lower() == '.kmf'
                    or name.lower() == 'param.lif'
                    or name.lower() == 'database.bin'):
                print('Skipping', name)
            else:
                # Copy user files to PC
                print('Copying: ', name)
                ch.fileCopyFromDevice(name, name)

Listing 14: Copy user files from Kvaser device.

Thus ends this post about kvmlib calls to set time and configure our Kvaser Memorator device. We will in the next, and last, part of this series take a look at what steps that needs to be done if we only have access to the bare SD card that later will be inserted into the Kvaser Memorator device.


Footnotes

1 Read more in the post Was that the CANlib channel number or Card Number?

2 The LIO data format is the specification on how to store data on the SD card. The latest LIO data format, v5.0, is capable of handling the larger data frames that can be generated by CAN FD.

3 Firmware earlier than 3.0 should use device type kvmDEVICE.MHYDRA.

4 This is similar to what the Kvaser Memorator Config Tool does when you tick “Save Configuration and Databases on the Disk”. The tool will then insert the used configuration and database files into the file DATABASE.BIN.

5 In the previous post, Adding script and triggers to a configuration.

6 We should probably check the LIO data format version here as well, refer to our earlier initialization code on how to do that.

7 7-zip is an open source Windows utility for manipulating archives, see www.7-zip.org for more information.



This article has been updated. To view the original, click on the box below.

Original Article

Original article published April 12, 2016.

This blog uses now deprecated functions, see blog “Improved API in Python canlib v1.5” for more information.

1 Getting started with kvmlib

2 Adding script and triggers to a configuration

3 Digging deeper into kvmlib

4 Configure an SD card using kvmlib

In the first part we showed how to use kvmlib to configure a device and read the logged messages using Python. In this part we will be revisiting the configuring we did in the first part while using the low level functions. These low level functions share their names with the native C API, so you should not have any problem using the C API instead of Python. There’s also a blog series about Setting Up CANlib for Visual Studio which might be useful. Full program listings are available on GitHub.

Update 2017-03-21: Updated sample code to work with Python 3 as well as using the Python canlib package introduced in CANlib SDK v5.17.

3.1 Opening the device

Opening a device using CANlib requires knowledge about more than just the EAN number. When connecting to a device using Pythons kvDevice module, the code internally looks though all devices connected to our computer and returns the first one that match our search criteria, in our case the EAN number.

import canlib.kvDevice as kvDevice

# Connect to our Kvaser Memorator Pro 5xHS with EAN 00778-9
dev = kvDevice.kvDevice(ean="73-30130-00778-9")
print(dev)

Listing 11: Printing information about a connected Kvaser device.

 >>> Device: Kvaser Memorator Pro 5xHS (channel 0)
EAN : 73-30130-00778-9
S/N : 1023
FW : v3.0.546
Card : 0
Drv : kcany0a
Card channel : 0
Canlib channel: 0

Here we note that our device is connected to CANlib channel 0 and Card channel number 0. The CANlib channel number is used when opening the device from CANlib and the Card number is used in the corresponding way when opening the device in kvmlib.1 If we had opened a second device, those numbers would be different on the second device.

When opening our device using kvmlib, beside specifying the device with Card channel, we also need to specify a device type. The device type is used to decide what version of LIO data format the device is using.2 Firmware v3.0 uses device type `kvmDEVICE_MHYDRA_EXT’.

Let us take a look on how to set the device clock using kvmlib directly, which corresponds to how you would do the same thing using the C API.

import canlib.kvmlib as kvmlib

ml = kvmlib.kvmlib()

# Since our firmware is v3.0 we should be using kvmDEVICE_MHYDRA_EXT
# as the device type.
deviceType = kvmlib.kvmDEVICE_MHYDRA_EXT

# We know that our device is connected to Card channel number 0
cardChannel = 0
 
# We have firmware version 3.0 in our device, this means that
# the FW is using Lio Data Format v5.0 and we should use
# kvmDEVICE_MHYDRA_EXT as the deviceType
ml.deviceOpen(memoNr=cardChannel, devicetype=deviceType)

# Having obtained a kvmHandle, we can now e.g. check the
# device serial number
print("Serial number:%d" % ml.deviceGetSerialNumber())

# Set the real time clock of the device
ml.deviceSetRTC(datetime.datetime.now())

# Read the device time
print("Current device time is %s" % ml.deviceGetRTC())

# Close device
ml.close()

Listing 12: Setting the real time clock of a Kvaser device using kvmlib.

Serial number:1023
Current time is 2016-02-11 13:01:00.509000
Setting time...
Current device time is 2016-02-11 13:01:00

3.2 Initialize the SD card

As stated earlier, using the correct device type when opening a device is very important. If we open a device using the wrong LIO data format (as specified using the device type), we will not be able to see any log messages during reading. Using the correct device type when initializing the SD card is even more important since the firmware will not be able to access an SD card that has been initialized using an incorrect LIO data format.

In order to initialize the SD card, we open a kvmHandle using kvmlib where we need to supply our device type, which on a Kvaser Memorator 2nd Generation device (running on fw v3.0) is kvmDEVICE_MHYDRA_EXT.3

The call to deviceMountKmf() returns the LIO data format, so we can conveniently check that we supplied the correct device type. In the code below, we also take the opportunity to catch the case were the SD card was not already initialized.

Most of the SD card is allocated for recording log messages during initialization, but there are two sizes that we can affect by passing two different arguments to the initialization command.

The first argument is specifying “space to reserve for user files”, which means that this amount of the SD card will be free for use by the user. We could have a /t/ program running in the device that generates text files, or we may have other user files that we would
like to copy to the SD card.

The second argument affects the size of a file called DATABASE.BIN which is used by the Kvaser Memorator Config Tool and may contain the configuration and database files that a user optionally can save to the SD card.

import canlib.kvmlib as kvmlib

ml = kvmlib.kvmlib()

# Since our firmware is v3.0 we should be using kvmDEVICE_MHYDRA_EXT
# as the device type.
deviceType = kvmlib.kvmDEVICE_MHYDRA_EXT

# We saw earlier that our device is connected to Card channel number 0
cardChannel = 0

# Open the device
ml.deviceOpen(memoNr=cardChannel, devicetype=deviceType)

try:
    # Mount the log area
    lioDataFormat = ml.deviceMountKmf()
    print("Lio Data Format v%s" % lioDataFormat)
    # Verify that the LIO data format of the card corresponds to
    # the device type we used when opening the device
    if lioDataFormat != '5.0':
        print("Unexpected Lio Data Format:", lioDataFormat)
        if lioDataFormat == '3.0':
            print("This log file can be read if you reopen the"
                  " device as kvmDEVICE_MHYDRA.")
        exit(1)
except kvmlib.kvmDiskNotFormated:
    print("SD card is not initialized...")
    exit(1)

# Format the SD Card and reserve 10 MB for configuration files
# (i.e. DATABASE.BIN) and 1000 MB for our own files.
print("Initializing SD card...")
ml.deviceFormatDisk(reserveSpace=10000, dbaseSpace=10)

# Report info about the disk area allocated for logging
(diskSize, usedDiskSize) = ml.kmfGetUsage()
print("Log size: %d MB\nUsed: %d MB" % (diskSize, usedDiskSize))

# Close the device
ml.close()

Listing 13: Verify LIO data format and initialize disk of a Kvaser device.

Lio Data Format v5.0
 Initializing SD card...
 Log size: 6112 MB
 Used: 0 MB

Our device has a 16 GB SD card, and when we now reserved 10 MB for DATABASE.BIN and 10 GB as free space we are left with 6112 MB for logging data. Since we have just initialized the SD card, we also have 0 MB (used) logged data.

The device SD card is now initialized and ready to be configured.

3.3 Save configuration

To configure the device, we convert the validated XML configuration to a binary configuration and download this binary configuration to the device. This is just as we did in the first post in this blog series, but here we call kvmlib directly and thus needs to expose the usage of deviceType and cardChannel.

import canlib.kvmlib as kvmlib
import canlib.kvaMemoLibXml as kvaMemoLibXml

ml = kvmlib.kvmlib()
xl = kvaMemoLibXml.kvaMemoLibXml()

# Since our firmware is v3.0 we should be using kvmDEVICE_MHYDRA_EXT
# as the device type.
deviceType = kvmlib.kvmDEVICE_MHYDRA_EXT

# We saw earlier that our device is connected to Card channel number 0
cardChannel = 0

# Read in the XML configuration file
with open("config.xml", 'r') as myfile:
    config_xml = myfile.read()

# Convert the XML configuration to a binary configuration
config_lif = xl.kvaXmlToBuffer(config_xml)

# Open the device and write the configuration
ml.deviceOpen(memoNr=cardChannel, devicetype=deviceType)
ml.kmfWriteConfig(config_lif)

# Close the device
ml.close()

Listing 14: Converting and downloading the configuration to a Kvaser device.

In order to later be able to retrieve the configuration in clear text, we create a zip file (config.zip) of the files we have used and download onto the device.4 Since we earlier used the argument -addsrc when we compiled the t program, we only need the compiled .txe file and our XML configuration.5 If we had used any databases, we would add those to the zip archive as well.

import zipfile
import canlib.canlib as canlib

# Create Zip archive
with zipfile.ZipFile("config.zip", mode='w',
                     compression=zipfile.ZIP_DEFLATED) as zipf:
    # Adding files to zip archive
    zipf.write("config.xml")
    zipf.write("myCanGenerator.txe")

cl = canlib.canlib()

# We know that our device was connected to CANlib channel number 0
canlibChannel = 0

# Open the device and write the zip archive
ch = cl.openChannel(channel=canlibChannel)
# Since the SD card is formated using FAT, we should use
# a 8.3 filename as the target filename
ch.fileCopyToDevice("config.zip", "config.zip")
 
ch.close()

Listing 15: Downloading clear text configurations using a zip archive.

3.4 Read result and save to file

After the device has been out in the field (i.e. we have applied power through the CAN connector and let the script run), we can once again connect our device to our computer and read out the logged data.6 In order to save the data for the future, we now write the data to a file using the kme50 format. This format can later be converted to a number of formats using the converter that is included in the Kvaser Memorator Config Tool.

The first entry in all log files contain information about the logged device. We take advantage of this here and place part of the EAN and serial number in the name of the resulting .kme50 files.

When all log files have been read from the device, we delete the log files on the device in order to be ready for a new logging run (reusing the same configuration).

import glob
import os

import canlib.kvmlib as kvmlib

ml = kvmlib.kvmlib()

# Since our firmware is v3.0 we should be using kvmDEVICE_MHYDRA_EXT
# as the device type.
deviceType = kvmlib.kvmDEVICE_MHYDRA_EXT

# We saw earlier that our device is connected to Card channel number 0
cardChannel = 0

# Directory to put the resulting files in
resultDir = "result"

# Make sure the result directory exists and is empty
if os.path.isdir(resultDir):
    files = glob.glob(os.path.join(resultDir, "*"))
    for f in files:
        os.remove(f)
else:
    os.mkdir(resultDir)
os.chdir(resultDir)

# Open the device
ml.deviceOpen(memoNr=cardChannel, devicetype=deviceType)

try:
    # Mount the log area
    lioDataFormat = ml.deviceMountKmf()
    print("Lio Data Format v%s" % lioDataFormat)
    # Verify that the LIO data format of the card corresponds to
    # the device type we used when opening the device
    if lioDataFormat != '5.0':
        print("Unexpected Lio Data Format:", lioDataFormat)
        if lioDataFormat == '3.0':
            print("This log file can be read if you reopen the"
                  " device as kvmDEVICE_MHYDRA.")
        exit(1)
except kvmlib.kvmDiskNotFormated:
    print("SD card is not initialized...")
    exit(1)

# Read number of recorded logfiles
fileCount = ml.logFileGetCount()
print("Found %d file%s on card:" % (fileCount,
                                    "s" if fileCount > 1 else ""))

# Loop through all logfiles and write their contents to .kme50 files
for fileIndx in range(fileCount):
    eventCount = ml.logFileMount(fileIndx)
    print("\tFile %3d: %10d events" % (fileIndx, eventCount))
    logEvent = ml.logFileReadEventLogFormat()
    #
    # The first logEvent contains device information
    memoEvent = logEvent.createMemoEvent()
    sn = memoEvent.serialNumber
    ean_lo = memoEvent.eanLo
    ean_sn = "%05x-%x_%d" % ((ean_lo >> 4) & 0xfffff, ean_lo & 0xf, sn)
    # Add EAN and serial number info to filename
    logfileName = "log_%s_%d.kme50" % (ean_sn, fileIndx)
    ml.kmeCreateFile(logfileName, kvmlib.kvmFILE_KME50)
    while logEvent is not None:
        # Write event to stdout
        print(logEvent)
        ml.kmeWriteEvent(logEvent)
        # Read next event
        logEvent = ml.logFileReadEventLogFormat()
    ml.kmeCloseFile()

# Delete all logfiles
ml.logFileDeleteAll()

# Close device
ml.close()

Listing 16: Read logged data and save to .kme50 files.

Read the blog post Examining logged data with kvmlib and Python for another example on how to read data from a device using kvmlib.

3.5 Read configurations from device.

Earlier we put a copy of our configuration in a config.zip file on the SD card, we may now read all the user files back using CANlib. The resulting file may then be opened using e.g. 7-zip.7

import os

import canlib.canlib as canlib

cl = canlib.canlib()

# We already knew that our device was connected to CANlib channel number 0
canlibChannel = 0
# Open the device
ch = cl.openChannel(channel=canlibChannel)

# List files on device
numFiles = ch.fileGetCount()

if numFiles:
    for i in range(numFiles):
        name = ch.fileGetName(i)
        # Skip known system files
        if (os.path.splitext(name)[1].lower() == '.kmf'
                or name.lower() == 'param.lif'
                or name.lower() == 'database.bin'):
            print("Skipping %s" % name)
        else:
            # Copy user files to PC
            print("Copying %s" % name)
            ch.fileCopyFromDevice(name, name)

ch.close()

Listing 17: Copy user files from Kvaser device.

Skipping PARAM.LIF
Skipping LOG00000.KMF
Skipping LOG00001.KMF
Skipping LOG00002.KMF
Skipping LOG00003.KMF
Skipping LOG00004.KMF
Skipping LOG00005.KMF
Skipping DATABASE.BIN
Copying CONFIG.ZIP

Thus ends this post about using low level kvmlib calls to configure our Kvaser Memorator device. We will in the next, and last, part of this series take a look at what steps that needs to be done if we only have access to the SD card that will be inserted into the device.

Footnotes

1 Read more in the post Was that the CANlib channel number or Card Number?

2 The LIO data format is the specification on how to store data on the SD card. The latest LIO data format, v5.0, is capable of handling the larger data frames that can be generated by CAN FD.

3 Firmware earlier than 3.0 should use device type kvmDEVICE.MHYDRA.

4 This is similar to what the Kvaser Memorator Config Tool does when you tick “Save
Configuration and Databases on the Disk”. The tool will then insert the used configuration and database files into the file DATABASE.BIN.

5 In the previous post, Adding script and triggers to a configuration.

6 We should probably check the LIO data format version here as well, refer to our earlier initialization code on how to do that.

7 7-zip is an open source Windows utility for manipulating archives, see www.7-zip.org for more information.

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.