hardbyte / python-can

The can package provides controller area network support for Python developers
https://python-can.readthedocs.io
GNU Lesser General Public License v3.0
1.31k stars 604 forks source link

python-can doesn't appear to be using hardware timestamps with socketcan #1881

Open pevsonic opened 4 weeks ago

pevsonic commented 4 weeks ago

Describe the bug

To Reproduce

Run two captures at the same time, one using candump with hardware timestamps :

candump -ta -H can1

The other utilising python-can e.g. logger :

python -m can.logger -c can1

If you then dump the output into a spreadsheet and compare frames, the output is quite different. For example, on a cyclic message on our hardware, I can see the cycle with candump -H is stable +/- 5 microseconds. With the timestamps from python-can the variance seems to be +/- 900 microseconds.

Expected behavior

The python can docs say :

The timestamp field in a CAN message is a floating point number representing when the message was received since the epoch in seconds. Where possible this will be timestamped in hardware.

So I'd have expected the hardware timestamps to have been enabled as with candump -H.

Additional context

OS and version: Debian 12 (6.1.112-1) Python version: 3.11 python-can version: 4.4.2 python-can interface/s (if applicable): Peak PCAN-USB X6

We're using the standard kernel drivers not peak's custom drivers.

Traceback and logs
pevsonic commented 3 weeks ago

I've done some tests to illustrate better using a piece of hardware sending out a packet on a 1.95ms cycle. Timestamps imported into a spreadsheet and a scatter plotted of timestamp (x axis) vs milliseconds between current and last packet.

Plot of output from python-can logger. Note the jitter is around 2000 micro-seconds :

python-can-logger-timestamps

Plot of output from canutils candump. Note the jitter is also around 2000 micro-seconds :

candump-system-timestamp

Plot of output from canutils candump with hardware timestamping enabled (-H). Note the jitter is now around 20 micro-seconds :

candump-hardware-timestamp

pevsonic commented 3 weeks ago

Digging into the code it looks like socketcan uses SO_TIMESTAMPNS which is system timestamp only. Comparing to how candump implements hardware timestamps I can see that you need to use the SO_TIMESTAMPING interface in order to use hardware timestamps so I've taken a stab at hooking into this in the same way in a fork of python-can with appropriate changes to logger to allow easy demonstration. See my branch at :

https://github.com/pevsonic/python-can/commit/b1baa7a7433c4ea39d0650d7b15bb5fc8a118b58

Having done this, I can now plot the improvements as above when using hardware timestamps :

python-can-using-SO_TIMESTAMPING

I've made this change so it defaults to "no change" behaviour unless you set a param to enable so it should be a safe change to pull.

pevsonic commented 3 weeks ago

Pull request #1882 fixes this.