mdabrowski1990 / uds

Python package for communication via UDS (Unified Diagnostic Services) protocol. The package supports typical buses (i.e. CAN, Ethernet, LIN, FlexRay, K-Line) with possible extensions to any bus.
https://uds.readthedocs.io/
MIT License
78 stars 10 forks source link

Transmission Time is not accurate when python-can with Kvaser is used. #228

Open mdabrowski1990 opened 11 months ago

mdabrowski1990 commented 11 months ago

When python-can is used as a CAN bus manager, then timestamps of message are not accurate (not synchronized with local time) therefore attribute transmission_time of CanPacketRecord is not accurate.

Affects:

mdabrowski1990 commented 11 months ago

Issue reported in python-can repository - https://github.com/hardbyte/python-can/issues/1676

mdabrowski1990 commented 11 months ago

Response from Kvaser as issue was reported in their system:

There are a couple of misconceptions in your program.

  • That Timer and the timestamps returned with a CAN frame are related.
  • That the time checked on completion of a canWrite call is the time when the CAN frame has been placed on the CAN bus.

The timestamps generated by the Kvaser Hybrid Pro CAN/LIN are based on a counter clock within the unit. This counter is incremented based on a timer function and can drift based on the quality of the oscillator. We do use high quality oscillators to ensure proper bit timing. But no two clocks are exactly the same. This counter is used to increment a time domain associated with a handle to the channel. Each handle by default gets a unique time domain that is reset to zero when the handle goes bus on. The resulting time is the returned time stamp on a frame. Again, has nothing to do with a computer’s system clock or any timer within the PC. So, any clock in the PC can drift independent of the drift in the clock used for the timestamps.

With that said, if you used our direct API you do have the ability to place handles to channels on the same device or handles to channels on multiple Kvaser USB devices that support MagiSync in the same time domain. MagiSync guarantees that a tick on one Kvaser unit’s clock is synchronized with the tick on another Kvaser unit’s clock. Then by placing the handles in the same time domain, the time stamps represent the same moment in time (still not linked to any computer provided clock).

As for checking the time after a canWrite call completes, this does not take into consideration that the canWrite call just places the frame in a transmit buffer of our API. How long the frame sits in the transmit buffer will be dependent on the number of frames being written and received and other calls being placed to the unit. All such commands must be passed over the USB communication before the frame is actually transmitted. The Kvaser Hybrid does have the ability to receive an echo of frames transmitted on a handle in the handle’s receive buffer. The time stamp on this frame would be a better representation of when the frame was actually placed on the CAN bus.

However, you can still get inversion (on a much lower level). If I have two channels that support MagiSync connected to the same CAN bus and their handles are placed in the same time domain, the transmit echo for a sent frame channel 1 may still have a timestamp greater than the same frame received on channel 2. This usually only happens on a CAN bus that has extreme bursts of traffic or is heavily loaded. The reason for this inversion is receive interrupts are given a higher priority than transmit interrupts in our devices. The transmit echo placed in the receive buffer is timestamped when the frame has been successfully placed on the CAN bus causing an interrupt to notify us that we can place the next frame. But if a receive interrupt occurs at the same time, the receive interrupt gets priority and is handled first slowing down the application of a timestamp on the echo.

mdabrowski1990 commented 11 months ago

Python file for reprocuding the problem is located in examples

mdabrowski1990 commented 1 day ago

Proposed a solution on python-can side to solve the problem: https://github.com/hardbyte/python-can/issues/1861