技术博客

19/09/2018 作者 Magnus Carlsson

用kvmlib配置SD卡

本文是共包括4部分的技术博客的最后一部分。此博客介绍通过kvmlib,使用第二代Kvaser Memorator数据记录仪,配置和读取已记录的数据:

在本系列博客的前几部分,我们介绍了用kvmlib配置一个设备,和获取该配置和已记录的数据,以做进一步分析。现在,我们来看一下,如果我们只能访问将要插入设备的SD卡,那么需要进行哪些不同的操作。此假设场景是,SD卡还未插入设备。

为了这个练习,我们将使用一个在Windows中格式化的16 GB SD卡,初始化并配置此SD卡,以便之后将它插入运行固件版本3.11的Kvaser Memorator Pro 2xHS (EAN 00819-9)。在运行我们的数据记录后,我们将从设备中取出SD卡,读取并重置记录文件。

4.1 初始化SD 卡

即使我们手里没有设备,仍然可以使用Windows电脑和 mhydraformat.exe程序,初始化SD卡。但是,这比直接使用设备要花费更多的时间,因为初始化16 GB卡大约需要3分钟。

mhydraformat.exe 程序位于在 Kvaser Memorator Config Tool.1 的安装目录下。你可以用 --help变量运行这个格式化程序,来查看使用帮助部分。

[C:\]mhydraformat.exe --help
Disk formatting program for Kvaser Memorator (2nd generation) devices.

-h       --help            | Print this information.
-d=DRIVE --drive=DRIVE     | The drive to format, e.g. F:
-r=X     --reserve=X       | The number of MB to reserve for user files.
-c=X     --config=X        | The number of MB to reserve for configurations.
         --fat16           | Format the disk with FAT16. Default is FAT32.
-i       --interactive     | Require the user to confirm before format.
-q       --quiet           | Stop all outputs. Overrides -i.
         --bin5            | Use the older, smaller version 5 of PARAM.LIF.
         --lio3            | Use the older LIO data format 3 for KMF files.

Example:
         mhydraformat -d=F: -r=100 -c=10 --interactive

将SD卡连接到电脑并记下驱动器代码字母。对于我来说,SD卡被分配给了J:盘。现在我们运行 mhydraformat.exe 来初始化卡。请注意,用于指定分配给DATABASE.BIN 空间的命令行改换为 --config。在初始化之后,我们还使用Windows dir命令查看此卡的内容。

C:> mhydraformat.exe -d=J: -r=10000 -c=10
Formatting...done.

C:> dir j:

 Volume in drive J has no label.
 Directory of  J:\

2018-08-10  10:39      10 010 624  DATABASE.BIN
2018-08-10  10:39   1 073 741 824  LOG00000.KMF
2018-08-10  10:39   1 073 741 824  LOG00001.KMF
2018-08-10  10:39   1 073 741 824  LOG00002.KMF
2018-08-10  10:39   1 073 741 824  LOG00003.KMF
2018-08-10  10:39   1 073 741 824  LOG00004.KMF
2018-08-10  10:39     514 785 280  LOG00005.KMF
2018-08-10  10:39      10 485 760  PARAM.LIF
               8 File(s)  5 903 990 784 bytes
               0 Dir(s)  10 004 455 424 bytes free

在这里我们看到二进制的配置文件(PARAM.LIF),此记录文件容器(LOG00000.KMF 到 LOG00005.KMF)和为Kvaser Memorator Config Tool (10MB DATABASE.BIN)保留的配置文件。我们还看到了我们要求的10000 MB空闲区。

4.2 把配置存储到卡上

要把此配置直接下载到SD卡,我们需要打开文件系统,而不是像在此博客前几部分所说的那样打开设备。我们还需要通知kvmlib我们的SD卡装在哪里。这是通过调用函数 kmfOpen() 和提供去文件LOG00000.KMF的完整路径来完成的,该文件总是在一个已正确初始化的SD卡2上。

我们现在用kvamemolibxml将二进制配置文件直接写入SD卡。

像之前介绍的那样,我们需要提供正确的设备类型。

# 12_设置Sd.py
from canlib import kvamemolibxml

print('kvamemolib version: ', kvamemolibxml.dllversion())

# 我们的SD卡装在J:驱动器里, 所以我们的二进制配置应该在那里。
filename = 'J:/PARAM.LIF'

# 转换之前验证的XML配置文件
# 并将此结果二进制配置写入SD卡
kvamemolibxml.kvaXmlToFile("config.xml", filename)
View sourceCopy to clipboard
列表 15:将二进制配置写入SD卡。
要以明确文字形式下载配置,我们完全像在前一部分博客中那样操作,但是通过Windows挂载点直接将该zip文件写入SD卡。
# 13_复制_文件_到_卡上.py
import zipfile

# 我们的SD卡装在J:驱动
filename = 'J:/config.zip'

# 生成zip文档
with zipfile.ZipFile(filename, mode='w',
                     compression=zipfile.ZIP_DEFLATED) as zipf:
    # 把文件添加到zip 文档里
    zipf.write('config.xml')
    zipf.write('myCanGenerator.txe')

列表 15:将二进制配置写入SD卡。

要以明确文字形式下载配置,我们完全像在前一部分博客中那样操作,但是通过Windows挂载点直接将该zip文件写入SD卡。

# 13_复制_文件_到_卡上.py
import zipfile

# 我们的SD卡装在J:驱动
filename = 'J:/config.zip'

# 生成zip文档
with zipfile.ZipFile(filename, mode='w',
                     compression=zipfile.ZIP_DEFLATED) as zipf:
    # 把文件添加到zip 文档里
    zipf.write('config.xml')
    zipf.write('myCanGenerator.txe')
View sourceCopy to clipboard
列表 16: 用压缩文档写下明确文字配置。
现在如果你查看我们的SD卡,它的内容如下所示。
C:>dir J:
 Volume in drive J has no label.
 Directory of J:\

2018-08-10  11:16            40 604 PARAM.LIF
2018-08-10  10:39     1 073 741 824 LOG00000.KMF
2018-08-10  10:39     1 073 741 824 LOG00001.KMF
2018-08-10  10:39     1 073 741 824 LOG00002.KMF
2018-08-10  10:39     1 073 741 824 LOG00003.KMF
2018-08-10  10:39     1 073 741 824 LOG00004.KMF
2018-08-10  10:39       514 785 280 LOG00005.KMF
2018-08-10  10:39        10 010 624 DATABASE.BIN
2018-08-10  11:21             2 516 config.zip
               9 File(s)  5 893 548 144 bytes
               0 Dir(s)  10 014 892 032 bytes free

列表 16: 用压缩文档写下明确文字配置。

现在如果你查看我们的SD卡,它的内容如下所示。

C:>dir J:
 Volume in drive J has no label.
 Directory of J:\

2018-08-10  11:16            40 604 PARAM.LIF
2018-08-10  10:39     1 073 741 824 LOG00000.KMF
2018-08-10  10:39     1 073 741 824 LOG00001.KMF
2018-08-10  10:39     1 073 741 824 LOG00002.KMF
2018-08-10  10:39     1 073 741 824 LOG00003.KMF
2018-08-10  10:39     1 073 741 824 LOG00004.KMF
2018-08-10  10:39       514 785 280 LOG00005.KMF
2018-08-10  10:39        10 010 624 DATABASE.BIN
2018-08-10  11:21             2 516 config.zip
               9 File(s)  5 893 548 144 bytes
               0 Dir(s)  10 014 892 032 bytes free

4.3 从SD卡读取结果

当我们从现场取回SD卡,将SD卡重新接到我们的电脑上,并开始验证SD卡上的LIO数据格式版本。

# 14_验证Lio格式Sd.py
from canlib import kvmlib

# 我们的SD卡装在J:驱动, 所以我们的 LOG00000.KMF can可以在这里打开
filename = 'J:/LOG00000.KMF'

# 打开SD卡并读取LIO数据格式版本
# 我们设备的固件版本是3.0 ,此SD卡将插入此设备, 这意味着FW在使用Lio数据格式v5.0,我们应使用kvmDEVICE_MHYDRA_EXT作为设备类型deviceType
with kvmlib.openKmf(
        filename,
        device_type=kvmlib.Device.MHYDRA_EXT) as kmf:
    ldf_version = kmf.log.ldf_version

print('Lio Data Format version:', ldf_version)

# 验证SD卡的此 LIO数据格式版本,和我们用来打开此设备的设备版本匹配

if ldf_version != (5, 0):
    print('Unexpected Lio Data Format:', ldf_version)
    if ldf_version == (3, 0):
        print("This log file can be read if you reopen the"
              " device as kvmDEVICE_MHYDRA.")
View sourceCopy to clipboard
列表 17: 验证SD卡上的LIO数据格式。
下一步是读取记录下来的数据。和我们的上一部分博客唯一不同的是,我们现在打开此SD卡,而不是打开已连接的设备。我们回到上一部分,更详细地说明这里的状况。
# 15_从Sd读取结果.py
import glob
import os

from canlib import EAN, VersionNumber
from canlib import kvmlib

#我们的SD卡装在J:驱动, 所以我们的 LOG00000.KMF can可以在这里打开
filename = 'J:/LOG00000.KMF'

# 用来存放结果文件的目录
resultDir = "result"

# 确定结果文件的目录存在并且空闲
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)

# 打开SD卡
# 我们之前已经验证此SD卡是使用Lio 数据格式 v5.0,而且我们应该用
kvmDEVICE_MHYDRA_EXT 作为设备类型deviceType
with kvmlib.openKmf(filename) as kmf:
    ldf_version = kmf.log.ldf_version
    #验证SD卡的此LIO数据格式版本,和我们用来打开此设备的设备版本匹配

    if ldf_version != VersionNumber(major=5, minor=0):
        if ldf_version == 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(ldf_version))

    # 读取已记录下来的文件数量
    num_log_files = len(kmf.log)
    print("Found {num} file on card: ".format(num=num_log_files))

    # 选择所有记录文件并把它们的内容写入.kme50文件
    for i, log_file in enumerate(kmf.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()))
        # 第一个记录事件包含设备信息
        event_iterator = iter(log_file)
        first_event = next(event_iterator)
        ean = EAN.from_hilo([first_event.eanHi, first_event.eanLo])
        serial = first_event.serialNumber
        # 把EAN和系列号添加到文件名上
        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:
                # 把事件书写到stdout
                print(event)
                kme.write_event(event)

    # 删除所有记录文件
    # kmf.log.删除_所有()

列表 17: 验证SD卡上的LIO数据格式。

下一步是读取记录下来的数据。和我们的上一部分博客唯一不同的是,我们现在打开此SD卡,而不是打开已连接的设备。我们回到上一部分,更详细地说明这里的状况。

# 15_从Sd读取结果.py
import glob
import os

from canlib import EAN, VersionNumber
from canlib import kvmlib

#我们的SD卡装在J:驱动, 所以我们的 LOG00000.KMF can可以在这里打开
filename = 'J:/LOG00000.KMF'

# 用来存放结果文件的目录
resultDir = "result"

# 确定结果文件的目录存在并且空闲
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)

# 打开SD卡
# 我们之前已经验证此SD卡是使用Lio 数据格式 v5.0,而且我们应该用
kvmDEVICE_MHYDRA_EXT 作为设备类型deviceType
with kvmlib.openKmf(filename) as kmf:
    ldf_version = kmf.log.ldf_version
    #验证SD卡的此LIO数据格式版本,和我们用来打开此设备的设备版本匹配

    if ldf_version != VersionNumber(major=5, minor=0):
        if ldf_version == 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(ldf_version))

    # 读取已记录下来的文件数量
    num_log_files = len(kmf.log)
    print("Found {num} file on card: ".format(num=num_log_files))

    # 选择所有记录文件并把它们的内容写入.kme50文件
    for i, log_file in enumerate(kmf.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()))
        # 第一个记录事件包含设备信息
        event_iterator = iter(log_file)
        first_event = next(event_iterator)
        ean = EAN.from_hilo([first_event.eanHi, first_event.eanLo])
        serial = first_event.serialNumber
        # 把EAN和系列号添加到文件名上
        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:
                # 把事件书写到stdout
                print(event)
                kme.write_event(event)

    # 删除所有记录文件
    # kmf.log.删除_所有()

列表 18: 从SD卡读取已记录的数据并保存到.kme50文件上。

运行上面的程序,在此记录里出现的每个通道上,我们能看到6个报文。

Found 1 file on card:

==== File 0: 2018-08-10 12:26:38 - 2018-08-10 12:26:44, 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.701738275  DateTime: 2018-08-10 12:26:38
 t:   2.701738275 Log Trigger Event (type: 0x2, trigno: 0x01, pre-trigger: 0, post-trigger: 0)

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

 t:   2.701738337  ch:0 f:   42 id:   3 dlc: 8 d:12 21 13 31 22 34 41 15
 t:     3.7017584  ch:1 f:    2 id:   4 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   3.701758462  ch:0 f:   42 id:   4 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   4.701774525  ch:1 f:    2 id:   5 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   4.701774587  ch:0 f:   42 id:   5 dlc: 8 d:12 21 13 31 22 34 41 15
 t:    5.70179165 Log Trigger Event (type: 0x2, trigno: 0x01, pre-trigger: 0, post-trigger: 2500)

 t:    5.70179165  ch:1 f:    2 id:   6 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   5.701791712  ch:0 f:   42 id:   6 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   6.701809775  ch:1 f:    2 id:   7 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   6.701809837  ch:0 f:   42 id:   7 dlc: 8 d:12 21 13 31 22 34 41 15
 t:     7.7018359  ch:1 f:    2 id:   8 dlc: 8 d:12 21 13 31 22 34 41 15
 t:   7.701835962  ch:0 f:   42 id:   8 dlc: 8 d:12 21 13 31 22 34 41 15

4.4从SD卡读取配置

为了操作完整,我们还需要说明,怎样读取我们之前通过Windows挂载点放在SD卡上的压缩配置。

# 16_从Sd读取配置.py
import glob
import os
import shutil

#我们的SD卡装在J:驱动, 所以我们的 LOG00000.KMF can可以在这里打开
filename = 'J:/LOG00000.KMF'

for file in glob.glob(os.path.join(os.path.dirname(filename), "*.*")):
    if(os.path.splitext(file)[1].lower() == '.kmf'
       or file.lower() == 'param.lif'
       or file.lower() == 'database.bin'):
        print('Skipping:', file)
    else:
        print('Copying:', file)
        shutil.copy(file, ".")
View sourceCopy to clipboard
列表 19:从SD卡复制所有用户文件。
现在,此运行的所有内容都放到了结果目录中。
C:> dir result

 Directory of result

2018-08-10  13:28             2 516 config.zip
2018-08-10  13:28        10 010 624 DATABASE.BIN
2018-08-10  13:16               452 log_73-30130-00819-9_11573_000.kme50
2018-08-10  13:28            40 604 PARAM.LIF
               4 File(s)     10 054 196 bytes
               2 Dir(s)  786 525 990 912 bytes free

列表 19:从SD卡复制所有用户文件。

现在,此运行的所有内容都放到了结果目录中。

C:> dir result

 Directory of result

2018-08-10  13:28             2 516 config.zip
2018-08-10  13:28        10 010 624 DATABASE.BIN
2018-08-10  13:16               452 log_73-30130-00819-9_11573_000.kme50
2018-08-10  13:28            40 604 PARAM.LIF
               4 File(s)     10 054 196 bytes
               2 Dir(s)  786 525 990 912 bytes free

我们就谈到这里,希望这个博客系列能帮助你对kvmlib有更多了解,并展示了kvmlib在管理Kvaser记录设备方面可以为你做些什么。

注释

1Kvaser Memorator Config Tool的缺省安装位置在

C:\Program Files (x86)\Kvaser\MemoratorConfigTool\mhydraformat.exe

2我们仅提供记录文件容器文件的第一个文件名,在该第一个文件记录到卡上之后,其他文件会马上跟进。



本文已更新。 要查看原件,请单击下面的框。

Author Image

Magnus Carlsson

Margus Carlsson是Kvaser AB公司的软件开发人员,从2007年以来深度参与了Kvaser固件和软件的开发。他还为Kvaser的技术博客撰写了许多用流行的Python语言编写应用程序的文章。