Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions can/interfaces/kvaser/canlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from can import CanError, BusABC
from can import Message
from . import constants as canstat
from . import structures

log = logging.getLogger('can.kvaser')

Expand Down Expand Up @@ -248,6 +249,18 @@ def __check_bus_handle_validity(handle, function, arguments):
restype=canstat.c_canStatus,
errcheck=__check_status)

canRequestBusStatistics = __get_canlib_function("canRequestBusStatistics",
argtypes=[c_canHandle],
restype=canstat.c_canStatus,
errcheck=__check_status)

canGetBusStatistics = __get_canlib_function("canGetBusStatistics",
argtypes=[c_canHandle,
ctypes.POINTER(structures.BusStatistics),
ctypes.c_size_t],
restype=canstat.c_canStatus,
errcheck=__check_status)


def init_kvaser_library():
if __canlib is not None:
Expand Down Expand Up @@ -572,6 +585,25 @@ def shutdown(self):
canBusOff(self._write_handle)
canClose(self._write_handle)

def get_stats(self):
"""Retrieves the bus statistics.

Use like so:

>>> stats = bus.get_stats()
>>> print(stats)
std_data: 0, std_remote: 0, ext_data: 0, ext_remote: 0, err_frame: 0, bus_load: 0.0%, overruns: 0

:returns: bus statistics.
:rtype: can.interfaces.kvaser.structures.BusStatistics
"""
canRequestBusStatistics(self._write_handle)
stats = structures.BusStatistics()
canGetBusStatistics(self._write_handle,
ctypes.pointer(stats),
ctypes.sizeof(stats))
return stats

@staticmethod
def _detect_available_configs():
num_channels = ctypes.c_int(0)
Expand Down
73 changes: 73 additions & 0 deletions can/interfaces/kvaser/structures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# coding: utf-8

"""
Contains Python equivalents of the structures in CANLIB's canlib.h,
with some supporting functionality specific to Python.
"""

import ctypes


class BusStatistics(ctypes.Structure):
"""
This structure is used with the method :meth:`KvaserBus.get_stats`.

.. seealso:: :meth:`KvaserBus.get_stats`

"""
_fields_ = [
("m_stdData", ctypes.c_ulong),
("m_stdRemote", ctypes.c_ulong),
("m_extData", ctypes.c_ulong),
("m_extRemote", ctypes.c_ulong),
("m_errFrame", ctypes.c_ulong),
("m_busLoad", ctypes.c_ulong),
("m_overruns", ctypes.c_ulong)
]

def __str__(self):
return ("std_data: {}, std_remote: {}, ext_data: {}, ext_remote: {}, "
"err_frame: {}, bus_load: {:.1f}%, overruns: {}").format(
self.std_data,
self.std_remote,
self.ext_data,
self.ext_remote,
self.err_frame,
self.bus_load / 100.0,
self.overruns,
)

@property
def std_data(self):
"""Number of received standard (11-bit identifiers) data frames."""
return self.m_stdData

@property
def std_remote(self):
"""Number of received standard (11-bit identifiers) remote frames."""
return self.m_stdRemote

@property
def ext_data(self):
"""Number of received extended (29-bit identifiers) data frames."""
return self.m_extData

@property
def ext_remote(self):
"""Number of received extended (29-bit identifiers) remote frames."""
return self.m_extRemote

@property
def err_frame(self):
"""Number of error frames."""
return self.m_errFrame

@property
def bus_load(self):
"""The bus load, expressed as an integer in the interval 0 - 10000 representing 0.00% - 100.00% bus load."""
return self.m_busLoad

@property
def overruns(self):
"""Number of overruns."""
return self.m_overruns
11 changes: 11 additions & 0 deletions doc/interfaces/kvaser.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Bus
---

.. autoclass:: can.interfaces.kvaser.canlib.KvaserBus
:members:
:exclude-members: get_stats


Internals
Expand All @@ -35,3 +37,12 @@ If one filter is requested, this is will be handled by the Kvaser driver.
If more than one filter is needed, these will be handled in Python code
in the ``recv`` method. If a message does not match any of the filters,
``recv()`` will return None.


Custom methods
~~~~~~~~~~~~~~~~~

This section contains Kvaser driver specific methods.


.. automethod:: can.interfaces.kvaser.canlib.KvaserBus.get_stats
8 changes: 8 additions & 0 deletions test/test_kvaser.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ def setUp(self):
canlib.canWriteSync = Mock()
canlib.canWrite = self.canWrite
canlib.canReadWait = self.canReadWait
canlib.canGetBusStatistics = Mock()
canlib.canRequestBusStatistics = Mock()

self.msg = {}
self.msg_in_cue = None
Expand Down Expand Up @@ -191,6 +193,12 @@ def test_canfd_custom_data_bitrate(self):
canlib.canSetBusParamsFd.assert_called_once_with(
0, data_bitrate, 0, 0, 0)

def test_bus_get_stats(self):
stats = self.bus.get_stats()
self.assertTrue(canlib.canRequestBusStatistics.called)
self.assertTrue(canlib.canGetBusStatistics.called)
self.assertIsInstance(stats, canlib.structures.BusStatistics)

@staticmethod
def canGetNumberOfChannels(count):
count._obj.value = 2
Expand Down