This is an update of an older blog post and is now taking advantage of the Python canlib package v1.7.
Developer Blog
Converting to plain ASCII
This is the second post in a 3-part series about using the Converter Library (kvlclib) in CANlib SDK:
- Writer formats and properties (1 of 3)
- Converting to plain ASCII (2 of 3)
- Special converter conditions (3 of 3)
The first part of this blog series looked into converter formats and properties, we will now continue and convert events from a given log file.
Let us assume that we have a log file, mylog.kme50
, that we would like to convert to Plain text (.txt) format. The log file was created either by using the Kvaser Memorator Config Tool, or by using the kvmlib as described in an earlier blog post.1
Starting with the last code example we wrote in the previous blog article in this series, we now add setting up the name and format of our input file at the end.
# set up formats
out_fmt = kvlclib.WriterFormat(kvlclib.FileFormat.PLAIN_ASC)
in_fmt = kvlclib.ReaderFormat(kvlclib.FileFormat.KME50)
# set resulting output file name taking advantage of the extension
# defined in the format.
out_file = "myresult." + out_fmt.extension
print("Output filename is '%s'" % out_file)
# create converter
cnv = kvlclib.Converter(out_file, out_fmt)
# Set input file and format
cnv.setInputFile(INPUT_FILE, kvlclib.FileFormat.KME50)
Let us also add a loop that converts the events one by one until we reach the end of our input file. The last thing we do is to call Converter.flush()
in order to flush output to disk.
# Convert events from input file one by one until EOF is reached
while True:
try:
cnv.convertEvent()
except kvlclib.KvlcEndOfFile:
break
# Force a flush so that the resulting file is written to disk.
cnv.flush()
Our first try at writing a kme50 converter program now looks as follows.
# 04_first_try_converting.py
from canlib import kvlclib
INPUT_FILE = 'mylog.kme50'
# set up formats
out_fmt = kvlclib.WriterFormat(kvlclib.FileFormat.PLAIN_ASC)
in_fmt = kvlclib.ReaderFormat(kvlclib.FileFormat.KME50)
# set resulting output file name taking advantage of the extension
# defined in the format.
out_file = "myresult." + out_fmt.extension
print("Output filename is '%s'" % out_file)
# create converter
cnv = kvlclib.Converter(out_file, out_fmt)
# Set input file and format
cnv.setInputFile(INPUT_FILE, kvlclib.FileFormat.KME50)
# Convert events from input file one by one until EOF is reached
while True:
try:
cnv.convertEvent()
except kvlclib.KvlcEndOfFile:
break
# Force a flush so that the resulting file is written to disk.
cnv.flush()
Running the above code, assuming everything works as expected, the file myresult.txt
is created. But running the same code again results in an error:
canlib.kvlclib.exceptions.KvlcGeneralError: Output file already exists (-6)
Each converter has a number of properties that effect their inner workings. One of these properties is OVERWRITE
which defaults to โ0โ, and that is the reason the code failed when running the second time โ the resulting file already existed and the converter was not allowed to overwrite it.
As we saw in the previous blog post, we can ask if a property is supported by a specific format. So let us create a function that checks if a given property is supported. If the property is supported โ and a value was supplied to the function โ the function sets the property to the given value. We also take the opportunity to print the default value of the property to the console.
def trySetProperty(cnv, property, value=None):
# Check if the format supports the given property
if cnv.format.isPropertySupported(property):
# If a value is specified, set the property to this value
if value is not None:
cnv.setProperty(property, value)
# Get the property's default value
default = cnv.format.getPropertyDefault(property)
print(' %s is supported (Default: %s)' %
(property, default))
# Get the property's current value
value = cnv.getProperty(property)
print(' Current value: %s' % value)
else:
print(' %s is not supported' % property)
Now let us use the trySetProperty()
function and set the property OVERWRITE
to โ1โ, we also limit the output to only the first channel by setting the CHANNEL_MASK
property. Another useful property for the Plain text format is WRITE_HEADER
which adds a nice header to the output file, so let us set that property as well. The final property we set is LIMIT_DATA_BYTES
which controls how many data bytes to print. In the ASCII format this directly affects how wide our data table will be, and since we do not have any CAN FD2 messages in our input log, we set this property to 8 (bytes).
# allow output file to overwrite existing files
trySetProperty(cnv, kvlclib.Property.OVERWRITE, 1)
# we are only interested in the first channel
cnv.setProperty(kvlclib.Property.CHANNEL_MASK, 1)
# add nice header to the output file
trySetProperty(cnv, kvlclib.Property.WRITE_HEADER, 1)
# we are converting CAN traffic with max 8 bytes, so we can minimize
# the width of the data output to 8 bytes
trySetProperty(cnv, kvlclib.Property.LIMIT_DATA_BYTES, 8)
Collecting all our improvements so far, we end up with the following program.
# 05_convert_kme.py
from canlib import kvlclib
def trySetProperty(cnv, property, value=None):
# Check if the format supports the given property
if cnv.format.isPropertySupported(property):
# If a value is specified, set the property to this value
if value is not None:
cnv.setProperty(property, value)
# Get the property's default value
default = cnv.format.getPropertyDefault(property)
print(' %s is supported (Default: %s)' %
(property, default))
# Get the property's current value
value = cnv.getProperty(property)
print(' Current value: %s' % value)
else:
print(' %s is not supported' % property)
# set up formats
out_fmt = kvlclib.WriterFormat(kvlclib.FileFormat.PLAIN_ASC)
in_fmt = kvlclib.ReaderFormat(kvlclib.FileFormat.KME50)
# set resulting output file name taking advantage of the extension
# defined in the format.
out_file = "myresult." + out_fmt.extension
print("Output filename is '%s'" % out_file)
# create converter
cnv = kvlclib.Converter(out_file, out_fmt)
# Set input file and format
cnv.setInputFile(INPUT_FILE, kvlclib.FileFormat.KME50)
# allow output file to overwrite existing files
trySetProperty(cnv, kvlclib.Property.OVERWRITE, 1)
# we are only interested in the first channel
cnv.setProperty(kvlclib.Property.CHANNEL_MASK, 1)
# add nice header to the output file
trySetProperty(cnv, kvlclib.Property.WRITE_HEADER, 1)
# we are converting CAN traffic with max 8 bytes, so we can minimize
# the width of the data output to 8 bytes
trySetProperty(cnv, kvlclib.Property.LIMIT_DATA_BYTES, 8)
# Convert events from input file one by one until EOF is reached
while True:
try:
cnv.convertEvent()
except kvlclib.KvlcEndOfFile:
break
# Force a flush so that the resulting file is written to disk.
cnv.flush()
Running the full program results in the following output.
Kvaser Memorator Log
====================
Converted from Memorator Binary format at: 2018-08-14 07:47:10
Settings:
Format of data field: DEC
Format of id field: DEC
Timestamp Offset: 0.000000 s
CAN channel: 1
Time Chan Identifier Flags DLC Data Counter
====================================================================================
0.242162 Trigger (type=0x1, active=0x00, pre-trigger=0, post-trigger=-1)
32.003407 1 501 Rx 8 41 23 0 0 0 0 0 0 2
32.006923 1 501 Rx 8 234 0 0 0 0 0 0 0 4
32.007795 1 504 Rx 8 51 179 79 67 0 0 0 0 6
32.008373 1 402 Rx 8 51 51 134 66 0 0 0 0 8
32.009127 1 402 Rx 8 51 51 243 64 0 0 0 0 10
32.009925 1 504 Rx 8 0 0 56 66 0 0 0 0 12
32.010670 1 503 Rx 8 0 0 52 67 0 0 0 0 14
32.011413 1 504 Rx 8 154 25 90 67 0 0 0 0 16
32.012167 1 402 Rx 8 205 204 140 64 0 0 0 0 18
32.015623 1 504 Rx 8 205 204 68 65 0 0 0 0 20
This ends the second blog article in which we created a simple program that used the Kvaser Converter library, kvlclib, to convert a kme50 log file into a plain text file. In the last article of this series, we will look at some special conditions that can arise when converting a log file.
If you have any questions, comments or suggestion for future blog articles, you can contact us directly via mail at support@kvaser.com.