From e0ccfb0d4b3fef9fbed24c9a6e673e5199e35c52 Mon Sep 17 00:00:00 2001 From: jost Date: Mon, 31 Mar 2025 08:31:35 +0200 Subject: [PATCH 1/5] Handle timer overflow message and build timestamp according to the epoch --- can/interfaces/ixxat/canlib_vcinpl.py | 21 ++++++++++++++++----- can/interfaces/ixxat/canlib_vcinpl2.py | 21 +++++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/can/interfaces/ixxat/canlib_vcinpl.py b/can/interfaces/ixxat/canlib_vcinpl.py index 567dd0cd9..22ccf1dda 100644 --- a/can/interfaces/ixxat/canlib_vcinpl.py +++ b/can/interfaces/ixxat/canlib_vcinpl.py @@ -13,6 +13,7 @@ import functools import logging import sys +import time import warnings from typing import Callable, List, Optional, Sequence, Tuple, Union @@ -619,7 +620,15 @@ def __init__( log.info("Accepting ID: 0x%X MASK: 0x%X", code, mask) # Start the CAN controller. Messages will be forwarded to the channel + start_begin = time.time() _canlib.canControlStart(self._control_handle, constants.TRUE) + start_end = time.time() + + # Calculate an offset to make them relative to epoch + # Assume that the time offset is in the middle of the start command + self._timeoffset = start_begin + (start_end - start_begin / 2) + self._overrunticks = 0 + self._starttickoffset = 0 # For cyclic transmit list. Set when .send_periodic() is first called self._scheduler = None @@ -692,6 +701,9 @@ def _recv_internal(self, timeout): f"Unknown CAN info message code {self._message.abData[0]}", ) ) + # Handle CAN start info message + if self._message.abData[0] == constants.CAN_INFO_START: + self._starttickoffset = self._message.dwTime elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_ERROR: if self._message.uMsgInfo.Bytes.bFlags & constants.CAN_MSGFLAGS_OVR: log.warning("CAN error: data overrun") @@ -708,7 +720,8 @@ def _recv_internal(self, timeout): self._message.uMsgInfo.Bytes.bFlags, ) elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR: - pass + # Add the number of timestamp overruns to the high word + self._overrunticks += (self._message.dwMsgId << 32); else: log.warning( "Unexpected message info type 0x%X", @@ -740,11 +753,9 @@ def _recv_internal(self, timeout): # Timed out / can message type is not DATA return None, True - # The _message.dwTime is a 32bit tick value and will overrun, - # so expect to see the value restarting from 0 rx_msg = Message( - timestamp=self._message.dwTime - / self._tick_resolution, # Relative time in s + timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) + / self._tick_resolution) + self._timeoffset, is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_extended_id=bool(self._message.uMsgInfo.Bits.ext), arbitration_id=self._message.dwMsgId, diff --git a/can/interfaces/ixxat/canlib_vcinpl2.py b/can/interfaces/ixxat/canlib_vcinpl2.py index 79ad34c4f..2c723cdb6 100644 --- a/can/interfaces/ixxat/canlib_vcinpl2.py +++ b/can/interfaces/ixxat/canlib_vcinpl2.py @@ -726,7 +726,15 @@ def __init__( log.info("Accepting ID: 0x%X MASK: 0x%X", code, mask) # Start the CAN controller. Messages will be forwarded to the channel + start_begin = time.time() _canlib.canControlStart(self._control_handle, constants.TRUE) + start_end = time.time() + + # Calculate an offset to make them relative to epoch + # Assume that the time offset is in the middle of the start command + self._timeoffset = start_begin + (start_end - start_begin / 2) + self._overrunticks = 0 + self._starttickoffset = 0 # For cyclic transmit list. Set when .send_periodic() is first called self._scheduler = None @@ -831,7 +839,9 @@ def _recv_internal(self, timeout): f"Unknown CAN info message code {self._message.abData[0]}", ) ) - + # Handle CAN start info message + elif self._message.abData[0] == constants.CAN_INFO_START: + self._starttickoffset = self._message.dwTime elif ( self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_ERROR ): @@ -853,7 +863,8 @@ def _recv_internal(self, timeout): self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR ): - pass + # Add the number of timestamp overruns to the high word + self._overrunticks += (self._message.dwMsgId << 32); else: log.warning("Unexpected message info type") @@ -867,11 +878,9 @@ def _recv_internal(self, timeout): return None, True data_len = dlc2len(self._message.uMsgInfo.Bits.dlc) - # The _message.dwTime is a 32bit tick value and will overrun, - # so expect to see the value restarting from 0 rx_msg = Message( - timestamp=self._message.dwTime - / self._tick_resolution, # Relative time in s + timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) + / self._tick_resolution) + self._timeoffset, is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_fd=bool(self._message.uMsgInfo.Bits.edl), is_rx=True, From 6bc467d8ad6d0e9bea2000c2f854452aa3d4594b Mon Sep 17 00:00:00 2001 From: jost Date: Mon, 31 Mar 2025 08:36:05 +0200 Subject: [PATCH 2/5] Revert "Handle timer overflow message and build timestamp according to the epoch" This reverts commit e0ccfb0d4b3fef9fbed24c9a6e673e5199e35c52. --- can/interfaces/ixxat/canlib_vcinpl.py | 21 +++++---------------- can/interfaces/ixxat/canlib_vcinpl2.py | 21 ++++++--------------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/can/interfaces/ixxat/canlib_vcinpl.py b/can/interfaces/ixxat/canlib_vcinpl.py index 22ccf1dda..567dd0cd9 100644 --- a/can/interfaces/ixxat/canlib_vcinpl.py +++ b/can/interfaces/ixxat/canlib_vcinpl.py @@ -13,7 +13,6 @@ import functools import logging import sys -import time import warnings from typing import Callable, List, Optional, Sequence, Tuple, Union @@ -620,15 +619,7 @@ def __init__( log.info("Accepting ID: 0x%X MASK: 0x%X", code, mask) # Start the CAN controller. Messages will be forwarded to the channel - start_begin = time.time() _canlib.canControlStart(self._control_handle, constants.TRUE) - start_end = time.time() - - # Calculate an offset to make them relative to epoch - # Assume that the time offset is in the middle of the start command - self._timeoffset = start_begin + (start_end - start_begin / 2) - self._overrunticks = 0 - self._starttickoffset = 0 # For cyclic transmit list. Set when .send_periodic() is first called self._scheduler = None @@ -701,9 +692,6 @@ def _recv_internal(self, timeout): f"Unknown CAN info message code {self._message.abData[0]}", ) ) - # Handle CAN start info message - if self._message.abData[0] == constants.CAN_INFO_START: - self._starttickoffset = self._message.dwTime elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_ERROR: if self._message.uMsgInfo.Bytes.bFlags & constants.CAN_MSGFLAGS_OVR: log.warning("CAN error: data overrun") @@ -720,8 +708,7 @@ def _recv_internal(self, timeout): self._message.uMsgInfo.Bytes.bFlags, ) elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR: - # Add the number of timestamp overruns to the high word - self._overrunticks += (self._message.dwMsgId << 32); + pass else: log.warning( "Unexpected message info type 0x%X", @@ -753,9 +740,11 @@ def _recv_internal(self, timeout): # Timed out / can message type is not DATA return None, True + # The _message.dwTime is a 32bit tick value and will overrun, + # so expect to see the value restarting from 0 rx_msg = Message( - timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) - / self._tick_resolution) + self._timeoffset, + timestamp=self._message.dwTime + / self._tick_resolution, # Relative time in s is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_extended_id=bool(self._message.uMsgInfo.Bits.ext), arbitration_id=self._message.dwMsgId, diff --git a/can/interfaces/ixxat/canlib_vcinpl2.py b/can/interfaces/ixxat/canlib_vcinpl2.py index 2c723cdb6..79ad34c4f 100644 --- a/can/interfaces/ixxat/canlib_vcinpl2.py +++ b/can/interfaces/ixxat/canlib_vcinpl2.py @@ -726,15 +726,7 @@ def __init__( log.info("Accepting ID: 0x%X MASK: 0x%X", code, mask) # Start the CAN controller. Messages will be forwarded to the channel - start_begin = time.time() _canlib.canControlStart(self._control_handle, constants.TRUE) - start_end = time.time() - - # Calculate an offset to make them relative to epoch - # Assume that the time offset is in the middle of the start command - self._timeoffset = start_begin + (start_end - start_begin / 2) - self._overrunticks = 0 - self._starttickoffset = 0 # For cyclic transmit list. Set when .send_periodic() is first called self._scheduler = None @@ -839,9 +831,7 @@ def _recv_internal(self, timeout): f"Unknown CAN info message code {self._message.abData[0]}", ) ) - # Handle CAN start info message - elif self._message.abData[0] == constants.CAN_INFO_START: - self._starttickoffset = self._message.dwTime + elif ( self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_ERROR ): @@ -863,8 +853,7 @@ def _recv_internal(self, timeout): self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR ): - # Add the number of timestamp overruns to the high word - self._overrunticks += (self._message.dwMsgId << 32); + pass else: log.warning("Unexpected message info type") @@ -878,9 +867,11 @@ def _recv_internal(self, timeout): return None, True data_len = dlc2len(self._message.uMsgInfo.Bits.dlc) + # The _message.dwTime is a 32bit tick value and will overrun, + # so expect to see the value restarting from 0 rx_msg = Message( - timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) - / self._tick_resolution) + self._timeoffset, + timestamp=self._message.dwTime + / self._tick_resolution, # Relative time in s is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_fd=bool(self._message.uMsgInfo.Bits.edl), is_rx=True, From 97f100479b4badab00a7d594a4c59d8eabb18756 Mon Sep 17 00:00:00 2001 From: jost Date: Mon, 31 Mar 2025 08:42:53 +0200 Subject: [PATCH 3/5] Handle timer overflow message and build timestamp according to the epoch --- can/interfaces/ixxat/canlib_vcinpl.py | 21 ++++++++++++++++----- can/interfaces/ixxat/canlib_vcinpl2.py | 21 +++++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/can/interfaces/ixxat/canlib_vcinpl.py b/can/interfaces/ixxat/canlib_vcinpl.py index 567dd0cd9..22ccf1dda 100644 --- a/can/interfaces/ixxat/canlib_vcinpl.py +++ b/can/interfaces/ixxat/canlib_vcinpl.py @@ -13,6 +13,7 @@ import functools import logging import sys +import time import warnings from typing import Callable, List, Optional, Sequence, Tuple, Union @@ -619,7 +620,15 @@ def __init__( log.info("Accepting ID: 0x%X MASK: 0x%X", code, mask) # Start the CAN controller. Messages will be forwarded to the channel + start_begin = time.time() _canlib.canControlStart(self._control_handle, constants.TRUE) + start_end = time.time() + + # Calculate an offset to make them relative to epoch + # Assume that the time offset is in the middle of the start command + self._timeoffset = start_begin + (start_end - start_begin / 2) + self._overrunticks = 0 + self._starttickoffset = 0 # For cyclic transmit list. Set when .send_periodic() is first called self._scheduler = None @@ -692,6 +701,9 @@ def _recv_internal(self, timeout): f"Unknown CAN info message code {self._message.abData[0]}", ) ) + # Handle CAN start info message + if self._message.abData[0] == constants.CAN_INFO_START: + self._starttickoffset = self._message.dwTime elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_ERROR: if self._message.uMsgInfo.Bytes.bFlags & constants.CAN_MSGFLAGS_OVR: log.warning("CAN error: data overrun") @@ -708,7 +720,8 @@ def _recv_internal(self, timeout): self._message.uMsgInfo.Bytes.bFlags, ) elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR: - pass + # Add the number of timestamp overruns to the high word + self._overrunticks += (self._message.dwMsgId << 32); else: log.warning( "Unexpected message info type 0x%X", @@ -740,11 +753,9 @@ def _recv_internal(self, timeout): # Timed out / can message type is not DATA return None, True - # The _message.dwTime is a 32bit tick value and will overrun, - # so expect to see the value restarting from 0 rx_msg = Message( - timestamp=self._message.dwTime - / self._tick_resolution, # Relative time in s + timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) + / self._tick_resolution) + self._timeoffset, is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_extended_id=bool(self._message.uMsgInfo.Bits.ext), arbitration_id=self._message.dwMsgId, diff --git a/can/interfaces/ixxat/canlib_vcinpl2.py b/can/interfaces/ixxat/canlib_vcinpl2.py index 79ad34c4f..2c723cdb6 100644 --- a/can/interfaces/ixxat/canlib_vcinpl2.py +++ b/can/interfaces/ixxat/canlib_vcinpl2.py @@ -726,7 +726,15 @@ def __init__( log.info("Accepting ID: 0x%X MASK: 0x%X", code, mask) # Start the CAN controller. Messages will be forwarded to the channel + start_begin = time.time() _canlib.canControlStart(self._control_handle, constants.TRUE) + start_end = time.time() + + # Calculate an offset to make them relative to epoch + # Assume that the time offset is in the middle of the start command + self._timeoffset = start_begin + (start_end - start_begin / 2) + self._overrunticks = 0 + self._starttickoffset = 0 # For cyclic transmit list. Set when .send_periodic() is first called self._scheduler = None @@ -831,7 +839,9 @@ def _recv_internal(self, timeout): f"Unknown CAN info message code {self._message.abData[0]}", ) ) - + # Handle CAN start info message + elif self._message.abData[0] == constants.CAN_INFO_START: + self._starttickoffset = self._message.dwTime elif ( self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_ERROR ): @@ -853,7 +863,8 @@ def _recv_internal(self, timeout): self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR ): - pass + # Add the number of timestamp overruns to the high word + self._overrunticks += (self._message.dwMsgId << 32); else: log.warning("Unexpected message info type") @@ -867,11 +878,9 @@ def _recv_internal(self, timeout): return None, True data_len = dlc2len(self._message.uMsgInfo.Bits.dlc) - # The _message.dwTime is a 32bit tick value and will overrun, - # so expect to see the value restarting from 0 rx_msg = Message( - timestamp=self._message.dwTime - / self._tick_resolution, # Relative time in s + timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) + / self._tick_resolution) + self._timeoffset, is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_fd=bool(self._message.uMsgInfo.Bits.edl), is_rx=True, From 843d5e4b60d4660e67b3ff87a1fec107b2e86a2e Mon Sep 17 00:00:00 2001 From: jost Date: Tue, 22 Apr 2025 09:40:24 +0200 Subject: [PATCH 4/5] Fix formating issues --- can/interfaces/ixxat/canlib_vcinpl.py | 2 +- can/interfaces/ixxat/canlib_vcinpl2.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/can/interfaces/ixxat/canlib_vcinpl.py b/can/interfaces/ixxat/canlib_vcinpl.py index 22ccf1dda..220039719 100644 --- a/can/interfaces/ixxat/canlib_vcinpl.py +++ b/can/interfaces/ixxat/canlib_vcinpl.py @@ -721,7 +721,7 @@ def _recv_internal(self, timeout): ) elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR: # Add the number of timestamp overruns to the high word - self._overrunticks += (self._message.dwMsgId << 32); + self._overrunticks += (self._message.dwMsgId << 32) else: log.warning( "Unexpected message info type 0x%X", diff --git a/can/interfaces/ixxat/canlib_vcinpl2.py b/can/interfaces/ixxat/canlib_vcinpl2.py index 2c723cdb6..44a5b9dbf 100644 --- a/can/interfaces/ixxat/canlib_vcinpl2.py +++ b/can/interfaces/ixxat/canlib_vcinpl2.py @@ -839,7 +839,7 @@ def _recv_internal(self, timeout): f"Unknown CAN info message code {self._message.abData[0]}", ) ) - # Handle CAN start info message + # Handle CAN start info message elif self._message.abData[0] == constants.CAN_INFO_START: self._starttickoffset = self._message.dwTime elif ( @@ -864,7 +864,7 @@ def _recv_internal(self, timeout): == constants.CAN_MSGTYPE_TIMEOVR ): # Add the number of timestamp overruns to the high word - self._overrunticks += (self._message.dwMsgId << 32); + self._overrunticks += (self._message.dwMsgId << 32) else: log.warning("Unexpected message info type") From f614aae432cdc4c502f64004c9edb3b640a84be6 Mon Sep 17 00:00:00 2001 From: jost Date: Tue, 22 Apr 2025 10:06:44 +0200 Subject: [PATCH 5/5] Format with black --- can/interfaces/ixxat/canlib_vcinpl.py | 9 ++++++--- can/interfaces/ixxat/canlib_vcinpl2.py | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/can/interfaces/ixxat/canlib_vcinpl.py b/can/interfaces/ixxat/canlib_vcinpl.py index 220039719..18d99c588 100644 --- a/can/interfaces/ixxat/canlib_vcinpl.py +++ b/can/interfaces/ixxat/canlib_vcinpl.py @@ -721,7 +721,7 @@ def _recv_internal(self, timeout): ) elif self._message.uMsgInfo.Bits.type == constants.CAN_MSGTYPE_TIMEOVR: # Add the number of timestamp overruns to the high word - self._overrunticks += (self._message.dwMsgId << 32) + self._overrunticks += self._message.dwMsgId << 32 else: log.warning( "Unexpected message info type 0x%X", @@ -754,8 +754,11 @@ def _recv_internal(self, timeout): return None, True rx_msg = Message( - timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) - / self._tick_resolution) + self._timeoffset, + timestamp=( + (self._message.dwTime + self._overrunticks - self._starttickoffset) + / self._tick_resolution + ) + + self._timeoffset, is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_extended_id=bool(self._message.uMsgInfo.Bits.ext), arbitration_id=self._message.dwMsgId, diff --git a/can/interfaces/ixxat/canlib_vcinpl2.py b/can/interfaces/ixxat/canlib_vcinpl2.py index 44a5b9dbf..90031dc8e 100644 --- a/can/interfaces/ixxat/canlib_vcinpl2.py +++ b/can/interfaces/ixxat/canlib_vcinpl2.py @@ -864,7 +864,7 @@ def _recv_internal(self, timeout): == constants.CAN_MSGTYPE_TIMEOVR ): # Add the number of timestamp overruns to the high word - self._overrunticks += (self._message.dwMsgId << 32) + self._overrunticks += self._message.dwMsgId << 32 else: log.warning("Unexpected message info type") @@ -879,8 +879,11 @@ def _recv_internal(self, timeout): data_len = dlc2len(self._message.uMsgInfo.Bits.dlc) rx_msg = Message( - timestamp=((self._message.dwTime + self._overrunticks - self._starttickoffset) - / self._tick_resolution) + self._timeoffset, + timestamp=( + (self._message.dwTime + self._overrunticks - self._starttickoffset) + / self._tick_resolution + ) + + self._timeoffset, is_remote_frame=bool(self._message.uMsgInfo.Bits.rtr), is_fd=bool(self._message.uMsgInfo.Bits.edl), is_rx=True,